forked from angular/angular
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(core): introduce Logger service
Closes angular#5458
- Loading branch information
1 parent
d3f174a
commit a3279d9
Showing
9 changed files
with
394 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
/** | ||
* @license | ||
* Copyright Google Inc. All Rights Reserved. | ||
* | ||
* Use of this source code is governed by an MIT-style license that can be | ||
* found in the LICENSE file at https://angular.io/license | ||
*/ | ||
|
||
import {InjectionToken} from './di/injection_token'; | ||
|
||
/** @experimental */ | ||
export interface LoggerOptions { | ||
enabled?: boolean; | ||
debug?: boolean; | ||
} | ||
|
||
/** | ||
* @whatItDoes Is used in DI to configure the {@link Logger}. | ||
* @experimental | ||
*/ | ||
export const LOGGER_OPTIONS = new InjectionToken<LoggerOptions>('Logger Options'); | ||
|
||
/** | ||
* Simple service for logging. | ||
* | ||
* @experimental | ||
*/ | ||
export abstract class Logger { | ||
/** Write a log message. */ | ||
abstract log(...args: any[]): void; | ||
|
||
/** Write an information message. */ | ||
abstract info(...args: any[]): void; | ||
|
||
/** Write a warning message. */ | ||
abstract warn(...args: any[]): void; | ||
|
||
/** Write an error message. */ | ||
abstract error(...args: any[]): void; | ||
|
||
/** Write a debug message. */ | ||
abstract debug(...args: any[]): void; | ||
|
||
/** Create a new inline group. */ | ||
abstract group(groupTitle?: string): void; | ||
|
||
/** Exit the current inline group. */ | ||
abstract groupEnd(): void; | ||
} | ||
|
||
const noop = (): any => undefined; | ||
|
||
/** | ||
* Default implementation of {@link Logger} that safely writes the message into the console. | ||
* | ||
* @experimental | ||
*/ | ||
export class ConsoleLogger implements Logger { | ||
constructor(private _console: Console, private _debugEnabled: boolean = true) {} | ||
|
||
log(...args: any[]): void { this._invokeConsoleMethod('log', args); } | ||
|
||
info(...args: any[]): void { this._invokeConsoleMethod('info', args); } | ||
|
||
warn(...args: any[]): void { this._invokeConsoleMethod('warn', args); } | ||
|
||
error(...args: any[]): void { this._invokeConsoleMethod('error', args); } | ||
|
||
debug(...args: any[]): void { | ||
if (this._debugEnabled) this._invokeConsoleMethod('debug', args); | ||
} | ||
|
||
group(groupTitle?: string): void { | ||
const args = groupTitle != null ? [groupTitle] : []; | ||
this._invokeConsoleMethod('group', args); | ||
} | ||
|
||
groupEnd(): void { this._invokeConsoleMethod('groupEnd'); } | ||
|
||
private _invokeConsoleMethod(type: string, args?: any[]): void { | ||
let logFn: Function = (<any>this._console)[type] || this._console.log || noop; | ||
|
||
// console methods in IE9 don't have 'apply' method, polyfill it | ||
if (!logFn.apply) { | ||
logFn = Function.prototype.bind.call(logFn, this._console); | ||
} | ||
|
||
logFn.apply(this._console, args); | ||
} | ||
} | ||
|
||
/** | ||
* No op implementation of {@link Logger}. | ||
* | ||
* @experimental | ||
*/ | ||
export class NoOpLogger implements Logger { | ||
log(): void {} | ||
|
||
info(): void {} | ||
|
||
warn(): void {} | ||
|
||
error(): void {} | ||
|
||
debug(): void {} | ||
|
||
group(): void {} | ||
|
||
groupEnd(): void {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
/** | ||
* @license | ||
* Copyright Google Inc. All Rights Reserved. | ||
* | ||
* Use of this source code is governed by an MIT-style license that can be | ||
* found in the LICENSE file at https://angular.io/license | ||
*/ | ||
|
||
import {ConsoleLogger, Logger, NoOpLogger} from '../src/logger'; | ||
|
||
interface TestConsole { | ||
log?: (arg?: any) => string; | ||
warn?: (arg?: any) => string; | ||
info?: (arg?: any) => string; | ||
error?: (arg?: any) => string; | ||
debug?: (arg?: any) => string; | ||
group?: (arg?: any) => string; | ||
groupEnd?: (arg?: any) => string; | ||
} | ||
|
||
export function main() { | ||
describe('Logger', () => { | ||
let logBuffer: string; | ||
let _console: TestConsole|any; | ||
|
||
beforeEach(() => { | ||
logBuffer = ''; | ||
_console = { | ||
log: (arg: any = '') => logBuffer += `log${arg};`, | ||
warn: (arg: any = '') => logBuffer += `warn${arg};`, | ||
info: (arg: any = '') => logBuffer += `info${arg};`, | ||
error: (arg: any = '') => logBuffer += `error${arg};`, | ||
debug: (arg: any = '') => logBuffer += `debug${arg};`, | ||
group: (arg: any = '') => logBuffer += `group${arg};`, | ||
groupEnd: () => logBuffer += 'groupEnd;', | ||
}; | ||
}); | ||
|
||
describe('No op', () => { | ||
it('should not log anything', () => { | ||
const logger: Logger = new NoOpLogger(); | ||
logger.info(); | ||
logger.log(); | ||
logger.debug(); | ||
logger.error(); | ||
logger.warn(); | ||
logger.group(); | ||
logger.groupEnd(); | ||
expect(logBuffer).toEqual(''); | ||
}); | ||
}); | ||
|
||
describe('Console', () => { | ||
it('should use console if present', () => { | ||
const logger: Logger = new ConsoleLogger(_console); | ||
logger.info('$'); | ||
logger.log('$'); | ||
logger.debug('$'); | ||
logger.error('$'); | ||
logger.warn('$'); | ||
logger.group('$'); | ||
logger.groupEnd(); | ||
expect(logBuffer).toEqual('info$;log$;debug$;error$;warn$;group$;groupEnd;'); | ||
}); | ||
|
||
it('should use console.log() if other not present', () => { | ||
const _console: any = {log: () => logBuffer += 'log;'}; | ||
const logger: Logger = new ConsoleLogger(_console); | ||
logger.info(); | ||
logger.log(); | ||
logger.debug(); | ||
logger.error(); | ||
logger.warn(); | ||
logger.group(); | ||
logger.groupEnd(); | ||
expect(logBuffer).toEqual('log;log;log;log;log;log;log;'); | ||
}); | ||
|
||
it('should use noop if no console', () => { | ||
const logger: Logger = new ConsoleLogger(<any>{}); | ||
logger.info(); | ||
logger.log(); | ||
logger.debug(); | ||
logger.error(); | ||
logger.warn(); | ||
logger.group(); | ||
logger.groupEnd(); | ||
expect(logBuffer).toEqual(''); | ||
}); | ||
|
||
describe('debug', () => { | ||
it('should skip debugging output if disabled', () => { | ||
const logger: Logger = new ConsoleLogger(_console, false); | ||
logger.info(); | ||
logger.log(); | ||
logger.debug(); | ||
logger.error(); | ||
logger.warn(); | ||
logger.group(); | ||
logger.groupEnd(); | ||
expect(logBuffer).toEqual('info;log;error;warn;group;groupEnd;'); | ||
}); | ||
}); | ||
|
||
describe('IE logging', () => { | ||
it(`should work in IE where console methods don't have 'apply' method`, () => { | ||
removeApplyFunctionForIE(_console); | ||
const logger: Logger = new ConsoleLogger(_console); | ||
logger.info('$'); | ||
logger.log('$'); | ||
logger.debug('$'); | ||
logger.error('$'); | ||
logger.warn('$'); | ||
logger.group('$'); | ||
logger.groupEnd(); | ||
expect(logBuffer).toEqual('info$;log$;debug$;error$;warn$;group$;groupEnd;'); | ||
}); | ||
|
||
function removeApplyFunctionForIE(console: TestConsole): void { | ||
console.log.apply = null; | ||
console.warn.apply = null; | ||
console.info.apply = null; | ||
console.error.apply = null; | ||
console.debug.apply = null; | ||
console.group.apply = null; | ||
console.groupEnd.apply = null; | ||
} | ||
}); | ||
}); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.