Cuando tu app da error y se ejecuta en dispositivos en los que no tienes acceso a los logs, esta solución te puede solucionar parte del camino para resolver el error.
Primero creamos el servicio que enviara el error a un servidor o servicio externo, en este ejemplo yo hago una petición HTTP a una URL externa, pero puede ser todo lo complejo que quieras:
error-log-service.ts
import { Injectable } from '@angular/core'; import { HttpClient, HttpHeaders} from '@angular/common/http'; @Injectable({ providedIn: 'root' }) export class ErrorLogService { constructor( private http: HttpClient ){ } sendError(error) { const headers: HttpHeaders = new HttpHeaders({ 'Content-Type': 'application/json' }); const requestOptions = { headers }; const url = 'https://www.javray.com/log.php'; const body: any = {}; body.message = error.message || 'N/A'; body.stack = error.stack || 'N/A'; this.http.post(url, body, requestOptions).subscribe(); } }
Después definimos la clase que extenderá ErrorHandler y que hará uso de nuestro servicio:
my-error-handler.ts
import { Injectable, ErrorHandler } from '@angular/core'; import { ErrorLogService } from './error-log.service'; @Injectable({ providedIn: 'root' }) export class MyErrorHandler extends ErrorHandler { constructor(private errorLogService: ErrorLogService) { super(); } handleError(error) { super.handleError(error); this.errorLogService.sendError(error); } }
Y por ultimo añadimos MyErrorHandler como provider en la app:
app.module.ts
import { ErrorHandler, NgModule, Injectable } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { RouteReuseStrategy } from '@angular/router'; import { IonicModule, IonicRouteStrategy } from '@ionic/angular'; import { SplashScreen } from '@ionic-native/splash-screen/ngx'; import { StatusBar } from '@ionic-native/status-bar/ngx'; import { AppComponent } from './app.component'; import { AppRoutingModule } from './app-routing.module'; import { HttpClientModule } from '@angular/common/http'; import { MyErrorHandler } from './my-error-handler'; @NgModule({ declarations: [AppComponent], entryComponents: [], imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule, HttpClientModule], providers: [ StatusBar, SplashScreen, { provide: ErrorHandler, useClass: MyErrorHandler }, { provide: RouteReuseStrategy, useClass: IonicRouteStrategy } ], bootstrap: [AppComponent] }) export class AppModule {}
Una implementación sencilla del servicio que recibe los logs sería la siguiente:
log.php
header('Access-Control-Allow-Credentials: true'); header('Access-Control-Allow-Origin: *'); if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') { if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'])) header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS"); if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'])) header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}"); exit(0); } $params = json_decode(file_get_contents('php://input'), true); $fecha = date('Y-m-d H:m:s'); $log = '[' . $fecha . '] '; $log .= '"' . $params['message'] . '" '; $log .= $params['stack']; $fichero = '/var/www/html/logs/' . date('Ymd') . '.log'; file_put_contents($fichero, $log . "\n", FILE_APPEND); echo json_encode(array('estado' => 'OK'));