From 7a406a389635262904d1cc243c4543760af221de Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin Date: Tue, 6 Feb 2018 10:50:59 +0000 Subject: [PATCH] feat(aio): report `logger.error` calls to Google Analytics (#22011) We have a number of observables that have `catch` handlers to recover from errors without causing the stream to close, and breaking the app. We also have some `try ... catch` blocks for synchronous code for a similar reason. In these cases we conventionally then call `logger.error` in the catch handler. We are interested in these errors so we are going to capture them by reporting them to Google Analytics via the new `ReportingErrorHandler`. PR Close #22011 --- aio/src/app/shared/logger.service.spec.ts | 46 +++++++++++++++++++++++ aio/src/app/shared/logger.service.ts | 7 +++- 2 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 aio/src/app/shared/logger.service.spec.ts diff --git a/aio/src/app/shared/logger.service.spec.ts b/aio/src/app/shared/logger.service.spec.ts new file mode 100644 index 0000000000..7094bd3297 --- /dev/null +++ b/aio/src/app/shared/logger.service.spec.ts @@ -0,0 +1,46 @@ +import { ErrorHandler, ReflectiveInjector } from '@angular/core'; +import { Logger } from './logger.service'; + +describe('logger service', () => { + let logSpy: jasmine.Spy; + let warnSpy: jasmine.Spy; + let logger: Logger; + let errorHandler: ErrorHandler; + + beforeEach(() => { + logSpy = spyOn(console, 'log'); + warnSpy = spyOn(console, 'warn'); + const injector = ReflectiveInjector.resolveAndCreate([ + Logger, + { provide: ErrorHandler, useClass: MockErrorHandler } + ]); + logger = injector.get(Logger); + errorHandler = injector.get(ErrorHandler); + }); + + describe('log', () => { + it('should delegate to console.log', () => { + logger.log('param1', 'param2', 'param3'); + expect(console.log).toHaveBeenCalledWith('param1', 'param2', 'param3'); + }); + }); + + describe('warn', () => { + it('should delegate to console.warn', () => { + logger.warn('param1', 'param2', 'param3'); + expect(console.warn).toHaveBeenCalledWith('param1', 'param2', 'param3'); + }); + }); + + describe('error', () => { + it('should delegate to ErrorHandler', () => { + logger.error('param1', 'param2', 'param3'); + expect(errorHandler.handleError).toHaveBeenCalledWith('param1 param2 param3'); + }); + }); +}); + + +class MockErrorHandler implements ErrorHandler { + handleError = jasmine.createSpy('handleError'); +} diff --git a/aio/src/app/shared/logger.service.ts b/aio/src/app/shared/logger.service.ts index cf7c3479d3..6b6207a41d 100644 --- a/aio/src/app/shared/logger.service.ts +++ b/aio/src/app/shared/logger.service.ts @@ -1,10 +1,12 @@ -import { Injectable } from '@angular/core'; +import { ErrorHandler, Injectable } from '@angular/core'; import { environment } from '../../environments/environment'; @Injectable() export class Logger { + constructor(private errorHandler: ErrorHandler) {} + log(value: any, ...rest: any[]) { if (!environment.production) { console.log(value, ...rest); @@ -12,7 +14,8 @@ export class Logger { } error(value: any, ...rest: any[]) { - console.error(value, ...rest); + const message = [value, ...rest].join(' '); + this.errorHandler.handleError(message); } warn(value: any, ...rest: any[]) {