Add global error handler and logging interceptor.
- Global error handler allows catching errors and parsing them to appropriate logging handler. - Logging interceptor allows logging of request information and status.
This commit is contained in:
parent
d7dcece7fe
commit
c96ebec1d2
7
src/app/_helpers/global-error-handler.spec.ts
Normal file
7
src/app/_helpers/global-error-handler.spec.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { GlobalErrorHandler } from './global-error-handler';
|
||||||
|
|
||||||
|
describe('GlobalErrorHandler', () => {
|
||||||
|
it('should create an instance', () => {
|
||||||
|
expect(new GlobalErrorHandler()).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
61
src/app/_helpers/global-error-handler.ts
Normal file
61
src/app/_helpers/global-error-handler.ts
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import {ErrorHandler, Injectable} from '@angular/core';
|
||||||
|
import {LoggingService} from '@app/_services';
|
||||||
|
import {HttpErrorResponse} from '@angular/common/http';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class GlobalErrorHandler extends ErrorHandler {
|
||||||
|
private sentencesForWarningLogging: string[] = [];
|
||||||
|
private loggingService: LoggingService;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
handleError(error: any): void {
|
||||||
|
this.logError(error);
|
||||||
|
const message = error.message ? error.message : error.toString();
|
||||||
|
|
||||||
|
if (error.status) {
|
||||||
|
error = new Error(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
const errorTraceString = `Error message:\n${message}.\nStack trace: ${error.stack}`;
|
||||||
|
|
||||||
|
const isWarning = this.isWarning(errorTraceString);
|
||||||
|
if (isWarning) {
|
||||||
|
this.loggingService.sendWarnLevelMessage(errorTraceString, {error});
|
||||||
|
} else {
|
||||||
|
this.loggingService.sendErrorLevelMessage(errorTraceString, this, {error});
|
||||||
|
}
|
||||||
|
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
logError(error: any): void {
|
||||||
|
if (error instanceof HttpErrorResponse) {
|
||||||
|
this.loggingService.sendErrorLevelMessage(
|
||||||
|
`There was an HTTP error. ${error.message}, Status code: ${(error as HttpErrorResponse).status}`, this, {error});
|
||||||
|
} else if (error instanceof TypeError) {
|
||||||
|
this.loggingService.sendErrorLevelMessage(`There was a Type error. ${error.message}`, this, {error});
|
||||||
|
} else if (error instanceof Error) {
|
||||||
|
this.loggingService.sendErrorLevelMessage(`There was a general error. ${error.message}`, this, {error});
|
||||||
|
} else {
|
||||||
|
this.loggingService.sendErrorLevelMessage('Nobody threw an error but something happened!', this, {error});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private isWarning(errorTraceString: string): boolean {
|
||||||
|
let isWarning = true;
|
||||||
|
if (errorTraceString.includes('/src/app/')) {
|
||||||
|
isWarning = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sentencesForWarningLogging.forEach((whiteListSentence) => {
|
||||||
|
if (errorTraceString.includes(whiteListSentence)) {
|
||||||
|
isWarning = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return isWarning;
|
||||||
|
}
|
||||||
|
}
|
@ -9,3 +9,5 @@ export * from '@app/_helpers/http-getter';
|
|||||||
export * from '@app/_helpers/pgp-signer';
|
export * from '@app/_helpers/pgp-signer';
|
||||||
export * from '@app/_helpers/registry';
|
export * from '@app/_helpers/registry';
|
||||||
export * from '@app/_helpers/token-registry';
|
export * from '@app/_helpers/token-registry';
|
||||||
|
export * from '@app/_helpers/logging.interceptor';
|
||||||
|
export * from '@app/_helpers/global-error-handler';
|
||||||
|
16
src/app/_helpers/logging.interceptor.spec.ts
Normal file
16
src/app/_helpers/logging.interceptor.spec.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { LoggingInterceptor } from './logging.interceptor';
|
||||||
|
|
||||||
|
describe('LoggingInterceptor', () => {
|
||||||
|
beforeEach(() => TestBed.configureTestingModule({
|
||||||
|
providers: [
|
||||||
|
LoggingInterceptor
|
||||||
|
]
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
const interceptor: LoggingInterceptor = TestBed.inject(LoggingInterceptor);
|
||||||
|
expect(interceptor).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
35
src/app/_helpers/logging.interceptor.ts
Normal file
35
src/app/_helpers/logging.interceptor.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import {
|
||||||
|
HttpRequest,
|
||||||
|
HttpHandler,
|
||||||
|
HttpEvent,
|
||||||
|
HttpInterceptor, HttpResponse
|
||||||
|
} from '@angular/common/http';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import {LoggingService} from '@app/_services/logging.service';
|
||||||
|
import {finalize, tap} from 'rxjs/operators';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class LoggingInterceptor implements HttpInterceptor {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private loggingService: LoggingService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
|
||||||
|
this.loggingService.sendInfoLevelMessage(request);
|
||||||
|
const startTime = Date.now();
|
||||||
|
let status: string;
|
||||||
|
|
||||||
|
return next.handle(request).pipe(tap(event => {
|
||||||
|
status = '';
|
||||||
|
if (event instanceof HttpResponse) {
|
||||||
|
status = 'succeeded';
|
||||||
|
}
|
||||||
|
}, error => status = 'failed'), finalize(() => {
|
||||||
|
const elapsedTime = Date.now() - startTime;
|
||||||
|
const message = `${request.method} ${request.urlWithParams} ${status} in ${elapsedTime} ms`;
|
||||||
|
this.loggingService.sendInfoLevelMessage(message);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
import {MutableKeyStore} from '@app/_helpers/pgp-key-store';
|
import {MutableKeyStore} from '@app/_helpers/pgp-key-store';
|
||||||
|
import {LoggingService} from '@app/_services/logging.service';
|
||||||
|
|
||||||
const openpgp = require('openpgp');
|
const openpgp = require('openpgp');
|
||||||
|
|
||||||
@ -31,6 +32,7 @@ class PGPSigner implements Signer {
|
|||||||
keyStore: MutableKeyStore;
|
keyStore: MutableKeyStore;
|
||||||
onsign: (signature: Signature) => void;
|
onsign: (signature: Signature) => void;
|
||||||
onverify: (flag: boolean) => void;
|
onverify: (flag: boolean) => void;
|
||||||
|
loggingService: LoggingService;
|
||||||
|
|
||||||
constructor(keyStore: MutableKeyStore) {
|
constructor(keyStore: MutableKeyStore) {
|
||||||
this.keyStore = keyStore;
|
this.keyStore = keyStore;
|
||||||
@ -63,11 +65,11 @@ class PGPSigner implements Signer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.error('checked ' + i + ' signature(s) but none valid');
|
this.loggingService.sendErrorLevelMessage(`Checked ${i} signature(s) but none valid`, this, {error: '404 Not found!'});
|
||||||
this.onverify(false);
|
this.onverify(false);
|
||||||
});
|
});
|
||||||
}).catch((e) => {
|
}).catch((e) => {
|
||||||
console.error(e);
|
this.loggingService.sendErrorLevelMessage(e.message, this, {error: e});
|
||||||
this.onverify(false);
|
this.onverify(false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -94,7 +96,7 @@ class PGPSigner implements Signer {
|
|||||||
};
|
};
|
||||||
this.onsign(this.signature);
|
this.onsign(this.signature);
|
||||||
}).catch((e) => {
|
}).catch((e) => {
|
||||||
console.error(e);
|
this.loggingService.sendErrorLevelMessage(e.message, this, {error: e});
|
||||||
this.onsign(undefined);
|
this.onsign(undefined);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user