Skip to content

Commit

Permalink
fix(logging): clean up and update LoggingService and its link to Sentry
Browse files Browse the repository at this point in the history
* update to latest sentry sdk and use LoggerService consistently
* do not log debug events to remote
* add Angular ErrorHandler to catch and log exceptions globally

see PR #384
  • Loading branch information
sleidig authored Dec 5, 2019
1 parent a3f8e20 commit 2d186d4
Show file tree
Hide file tree
Showing 9 changed files with 148 additions and 68 deletions.
62 changes: 57 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"@angular/pwa": "^0.803.0",
"@angular/router": "^8.2.2",
"@angular/service-worker": "^8.2.2",
"@sentry/browser": "^5.9.1",
"core-js": "^2.6.9",
"crypto-js": "~3.1.9-1",
"faker": "^4.1.0",
Expand All @@ -37,7 +38,6 @@
"ngx-papaparse": "^3.0.3",
"pouchdb-authentication": "^1.1.3",
"pouchdb-browser": "^7.1.1",
"raven-js": "^3.27.2",
"reflect-metadata": "^0.1.13",
"rxjs": "^6.5.2",
"uniqid": "^5.0.3",
Expand Down
3 changes: 0 additions & 3 deletions src/app/alerts/alert.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,16 +59,13 @@ export class AlertService {
switch (alert.type) {
case Alert.WARNING:
case Alert.DANGER:
console.warn(alert.message);
this.loggingService.warn(alert.message);
break;
case Alert.INFO:
case Alert.SUCCESS:
console.log(alert.message);
this.loggingService.info(alert.message);
break;
case Alert.DEBUG:
console.log(alert.message);
this.loggingService.debug(alert.message);
break;
}
Expand Down
4 changes: 3 additions & 1 deletion src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import {APP_INITIALIZER, NgModule} from '@angular/core';
import {APP_INITIALIZER, ErrorHandler, NgModule} from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpClientModule} from '@angular/common/http';

Expand Down Expand Up @@ -48,6 +48,7 @@ import {CookieService} from 'ngx-cookie-service';
import {HelpModule} from './help/help.module';
import {DemoDataModule} from './demo-data/demo-data.module';
import {MatNativeDateModule} from '@angular/material/core';
import {LoggingErrorHandler} from './logging/logging-error-handler';

@NgModule({
declarations: [
Expand Down Expand Up @@ -82,6 +83,7 @@ import {MatNativeDateModule} from '@angular/material/core';
providers: [
AppConfig,
{ provide: APP_INITIALIZER, useFactory: initializeApp, deps: [AppConfig], multi: true },
{ provide: ErrorHandler, useClass: LoggingErrorHandler },
MatIconRegistry,
CookieService,
],
Expand Down
3 changes: 1 addition & 2 deletions src/app/entity/entity-mapper.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ describe('EntityMapperService', () => {
testDatabase = new MockDatabase();
entityMapper = new EntityMapperService(testDatabase, new EntitySchemaService());

return Promise.all([testDatabase.put(existingEntity), testDatabase.put(existingEntity2)])
.catch(err => console.log('Failed to insert entity: ' + err));
return Promise.all([testDatabase.put(existingEntity), testDatabase.put(existingEntity2)]);
});


Expand Down
10 changes: 6 additions & 4 deletions src/app/latest-changes/update-manager.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {SwUpdate} from '@angular/service-worker';
import {first} from 'rxjs/operators';
import {concat, interval} from 'rxjs';
import { MatSnackBar } from '@angular/material/snack-bar';
import {LoggingService} from '../logging/logging.service';

@Injectable()
export class UpdateManagerService {
Expand All @@ -29,12 +30,13 @@ export class UpdateManagerService {
constructor(
private appRef: ApplicationRef,
private updates: SwUpdate,
public snackBar: MatSnackBar) {

public snackBar: MatSnackBar,
private logger: LoggingService,
) {
}

public notifyUserWhenUpdateAvailable() {
this.updates.available.subscribe(event => {
this.updates.available.subscribe(() => {
this.showUpdateNotification();
});
}
Expand All @@ -49,7 +51,7 @@ export class UpdateManagerService {
try {
await this.updates.checkForUpdate();
} catch (err) {
console.log(err);
this.logger.error(err);
}
});
}
Expand Down
14 changes: 14 additions & 0 deletions src/app/logging/logging-error-handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {ErrorHandler, Injectable} from '@angular/core';
import {LoggingService} from './logging.service';

@Injectable()
export class LoggingErrorHandler implements ErrorHandler {
constructor(private logger: LoggingService) {}

handleError(error) {
this.logger.error(error);
// It is possible to show a feedback dialog to the user through Sentry:
// const eventId = Sentry.captureException(error.originalError || error);
// Sentry.showReportDialog({ eventId });
}
}
47 changes: 21 additions & 26 deletions src/app/logging/logging.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,17 @@
import {LoggingService} from './logging.service';
import * as Raven from 'raven-js';

class LoggingServiceRavenMock extends LoggingService {

public latestRavenCalls: Array<[string, Raven.RavenOptions]>;

constructor() {
super();
this.latestRavenCalls = [];
}

protected ravenCaptureMessage(message: string, options: Raven.RavenOptions): void {
this.latestRavenCalls.push([message, options]);
}
}
import {LogLevel} from './log-level';


describe('LoggingService', () => {
const testMessage = 'FANCY_TEST_MESSAGE';

let loggingService: LoggingServiceRavenMock;
let loggingService: LoggingService;
beforeEach(() => {
loggingService = new LoggingServiceRavenMock();
loggingService = new LoggingService();
spyOn<any>(loggingService, 'logToConsole');
spyOn<any>(loggingService, 'logToRemoteMonitoring');
});

function checkReceivedLogMessage(level: Raven.LogLevel) {
const receivedLogRequest = loggingService.latestRavenCalls.pop();
expect(receivedLogRequest[0]).toEqual(testMessage);
expect(receivedLogRequest[1].level).toEqual(level);
}

it('should be created', () => {
expect(loggingService).toBeTruthy();
Expand All @@ -37,25 +20,37 @@ describe('LoggingService', () => {
it('should log a debug message', function () {
loggingService.debug(testMessage);

checkReceivedLogMessage('debug');
expect(loggingService['logToConsole']).toHaveBeenCalledWith(testMessage, LogLevel.DEBUG);
expect(loggingService['logToRemoteMonitoring']).not.toHaveBeenCalled();
});

it('should log a info message', function () {
loggingService.info(testMessage);

checkReceivedLogMessage('info');
expect(loggingService['logToConsole']).toHaveBeenCalledWith(testMessage, LogLevel.INFO);
expect(loggingService['logToRemoteMonitoring']).not.toHaveBeenCalled();
});

it('should log a warn message', function () {
loggingService.warn(testMessage);

checkReceivedLogMessage('warn');
expect(loggingService['logToConsole']).toHaveBeenCalledWith(testMessage, LogLevel.WARN);
expect(loggingService['logToRemoteMonitoring']).toHaveBeenCalledWith(testMessage, LogLevel.WARN);
});


it('should log a error message', function () {
loggingService.error(testMessage);

checkReceivedLogMessage('error');
expect(loggingService['logToConsole']).toHaveBeenCalledWith(testMessage, LogLevel.ERROR);
expect(loggingService['logToRemoteMonitoring']).toHaveBeenCalledWith(testMessage, LogLevel.ERROR);
});


it('should log a message through the generic log method', function () {
loggingService.log(testMessage, LogLevel.WARN);

expect(loggingService['logToConsole']).toHaveBeenCalledWith(testMessage, LogLevel.WARN);
expect(loggingService['logToRemoteMonitoring']).toHaveBeenCalledWith(testMessage, LogLevel.WARN);
});
});
71 changes: 45 additions & 26 deletions src/app/logging/logging.service.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import {Injectable} from '@angular/core';
import * as Raven from 'raven-js';
import {LogLevel as RavenLogLevel, RavenOptions} from 'raven-js';
import {LogLevel} from './log-level';
import * as Sentry from '@sentry/browser';


Raven
.config('https://bd6aba79ca514d35bb06a4b4e0c2a21e@sentry.io/1242399')
.install();
Sentry.init({
dsn: 'https://bd6aba79ca514d35bb06a4b4e0c2a21e@sentry.io/1242399',
whitelistUrls: [
/https?:\/\/(.*)\.?aam-digital\.com/
]
});


/* tslint:disable:no-console */
@Injectable({
providedIn: 'root'
})
Expand All @@ -16,53 +20,68 @@ export class LoggingService {
constructor() {
}

public log(message: string, logLevel: LogLevel) {
let options: RavenOptions;
options = {};
options.level = this.translateLogLevel(logLevel);

this.ravenCaptureMessage(message, options);
}

public debug(message: string) {
public debug(message: any) {
this.log(message, LogLevel.DEBUG);
}

public info(message: string) {
public info(message: any) {
this.log(message, LogLevel.INFO);
}

public warn(message: string) {
public warn(message: any) {
this.log(message, LogLevel.WARN);
}

public error(message: string) {
public error(message: any) {
this.log(message, LogLevel.ERROR);
}

private translateLogLevel(logLevel: LogLevel): RavenLogLevel {

let retVal: RavenLogLevel;
public log(message: any, logLevel: LogLevel = LogLevel.INFO) {
this.logToConsole(message, logLevel);

if (logLevel !== LogLevel.DEBUG && logLevel !== LogLevel.INFO) {
this.logToRemoteMonitoring(message, logLevel);
}
}

private logToConsole(message: any, logLevel: LogLevel) {
switch (+logLevel) {
case LogLevel.DEBUG:
retVal = 'debug';
console.debug(message);
break;
case LogLevel.INFO:
retVal = 'info';
console.info(message);
break;
case LogLevel.WARN:
retVal = 'warn';
console.warn(message);
break;
case LogLevel.ERROR:
retVal = 'error';
console.error(message);
break;
default:
console.log(message);
break;
}
}

return retVal;
private logToRemoteMonitoring(message: any, logLevel: LogLevel) {
Sentry.captureMessage(message, this.translateLogLevel(logLevel));
}

protected ravenCaptureMessage(message: string,
options: RavenOptions) {
Raven.captureMessage(message, options);
private translateLogLevel(logLevel: LogLevel): Sentry.Severity {
switch (+logLevel) {
case LogLevel.DEBUG:
return Sentry.Severity.Debug;
case LogLevel.INFO:
return Sentry.Severity.Info;
case LogLevel.WARN:
return Sentry.Severity.Warning;
case LogLevel.ERROR:
return Sentry.Severity.Error;
default:
return Sentry.Severity.Info;
}
}
}

0 comments on commit 2d186d4

Please sign in to comment.