From ee0f0af4d31a1fd92c923131d851cd629303199d Mon Sep 17 00:00:00 2001 From: Bartlomiej Obecny Date: Fri, 7 May 2021 00:16:45 +0200 Subject: [PATCH 1/4] chore: adding component logger --- src/api/diag.ts | 19 ++++++++- src/diag/ComponentLogger.ts | 70 +++++++++++++++++++++++++++++++ src/diag/types.ts | 46 ++++++++++++++++++++ test/diag/ComponentLogger.test.ts | 63 ++++++++++++++++++++++++++++ 4 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 src/diag/ComponentLogger.ts create mode 100644 test/diag/ComponentLogger.test.ts diff --git a/src/api/diag.ts b/src/api/diag.ts index b3136c96..5b8886aa 100644 --- a/src/api/diag.ts +++ b/src/api/diag.ts @@ -14,8 +14,15 @@ * limitations under the License. */ +import { DiagComponentLogger } from '../diag/ComponentLogger'; import { createLogLevelDiagLogger } from '../diag/internal/logLevelLogger'; -import { DiagLogFunction, DiagLogger, DiagLogLevel } from '../diag/types'; +import { + ComponentLogger, + ComponentLoggerOptions, + DiagLogFunction, + DiagLogger, + DiagLogLevel, +} from '../diag/types'; import { getGlobal, registerGlobal, @@ -90,6 +97,10 @@ export class DiagAPI implements DiagLogger { unregisterGlobal(API_NAME); }; + self.createComponentLogger = (options: ComponentLoggerOptions) => { + return new DiagComponentLogger(options); + }; + self.verbose = _logProxy('verbose'); self.debug = _logProxy('debug'); self.info = _logProxy('info'); @@ -106,6 +117,12 @@ export class DiagAPI implements DiagLogger { * @returns true if the logger was successfully registered, else false */ public setLogger!: (logger: DiagLogger, logLevel?: DiagLogLevel) => boolean; + /** + * + */ + public createComponentLogger!: ( + options: ComponentLoggerOptions + ) => ComponentLogger; // DiagLogger implementation public verbose!: DiagLogFunction; diff --git a/src/diag/ComponentLogger.ts b/src/diag/ComponentLogger.ts new file mode 100644 index 00000000..7b365dc3 --- /dev/null +++ b/src/diag/ComponentLogger.ts @@ -0,0 +1,70 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { getGlobal } from '../internal/global-utils'; +import { ComponentLogger, ComponentLoggerOptions, DiagLogger } from './types'; + +/** + * Component Logger which is meant to be used as part of any component which + * will add automatically additional namespace in front of the log message. + * It will then forward all message to global diag logger + * @example + * const cLogger = diag.createComponentLogger({ namespace: '@opentelemetry/instrumentation-http' }); + * cLogger.debug('test'); + * // @opentelemetry/instrumentation-http test + */ +export class DiagComponentLogger implements ComponentLogger { + public namespace: string; + + constructor(props: ComponentLoggerOptions) { + this.namespace = props.namespace || 'DiagComponentLogger'; + } + + public debug(...args: any[]): void { + return logProxy('debug', this.namespace, args); + } + + public error(...args: any[]): void { + return logProxy('error', this.namespace, args); + } + + public info(...args: any[]): void { + return logProxy('info', this.namespace, args); + } + + public warn(...args: any[]): void { + return logProxy('warn', this.namespace, args); + } + + public verbose(...args: any[]): void { + return logProxy('verbose', this.namespace, args); + } +} + +function logProxy( + funcName: keyof DiagLogger, + nameSpace: string, + args: any +): void { + const logger = getGlobal('diag'); + // shortcut if logger not set + if (!logger) { + return; + } + + args.unshift(nameSpace); + return logger[funcName].apply(logger, args); +} diff --git a/src/diag/types.ts b/src/diag/types.ts index 3a633a5b..592e3914 100644 --- a/src/diag/types.ts +++ b/src/diag/types.ts @@ -89,3 +89,49 @@ export enum DiagLogLevel { /** Used to set the logging level to include all logging */ ALL = 9999, } + +/** + * Defines options for ComponentLogger + */ +export interface ComponentLogger { + namespace: string; + /** Log an error scenario that was not expected and caused the requested operation to fail. */ + error: (...args: any) => void; + + /** + * Log a warning scenario to inform the developer of an issues that should be investigated. + * The requested operation may or may not have succeeded or completed. + */ + warn: (...args: any) => void; + + /** + * Log a general informational message, this should not affect functionality. + * This is also the default logging level so this should NOT be used for logging + * debugging level information. + */ + info: (...args: any) => void; + + /** + * Log a general debug message that can be useful for identifying a failure. + * Information logged at this level may include diagnostic details that would + * help identify a failure scenario. + * For example: Logging the order of execution of async operations. + */ + debug: (...args: any) => void; + + /** + * Log a detailed (verbose) trace level logging that can be used to identify failures + * where debug level logging would be insufficient, this level of tracing can include + * input and output parameters and as such may include PII information passing through + * the API. As such it is recommended that this level of tracing should not be enabled + * in a production environment. + */ + verbose: (...args: any) => void; +} + +/** + * Defines options for ComponentLogger + */ +export interface ComponentLoggerOptions { + namespace?: string; +} diff --git a/test/diag/ComponentLogger.test.ts b/test/diag/ComponentLogger.test.ts new file mode 100644 index 00000000..bbc25b1e --- /dev/null +++ b/test/diag/ComponentLogger.test.ts @@ -0,0 +1,63 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as assert from 'assert'; +import * as sinon from 'sinon'; +import { diag, DiagLogger, DiagLogLevel } from '../../src'; + +class SpyLogger implements DiagLogger { + debug() {} + + error() {} + + info() {} + + warn() {} + + verbose() {} +} + +const loggerFunctions = ['verbose', 'debug', 'info', 'warn', 'error']; + +describe('ComponentLogger', () => { + let logger: DiagLogger; + + const sandbox = sinon.createSandbox(); + + beforeEach(() => { + logger = new SpyLogger(); + sandbox.spy(logger); + diag.setLogger(logger, DiagLogLevel.ALL); + }); + + afterEach(() => { + sandbox.restore(); + }); + + loggerFunctions.forEach(name => { + const fName = name as keyof SpyLogger; + it(`should call global logger function "${name}" with namespace as first param`, () => { + const componentLogger = diag.createComponentLogger({ namespace: 'foo' }); + componentLogger[fName]('test'); + + assert.strictEqual((logger[fName] as sinon.SinonSpy).callCount, 1); + assert.deepStrictEqual((logger[fName] as sinon.SinonSpy).args[0], [ + 'foo', + 'test', + ]); + }); + }); +}); From e8c15c108eb25e748717ece5e78e188e931d78bd Mon Sep 17 00:00:00 2001 From: Bartlomiej Obecny Date: Fri, 7 May 2021 18:43:08 +0200 Subject: [PATCH 2/4] chore: typo --- src/diag/ComponentLogger.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/diag/ComponentLogger.ts b/src/diag/ComponentLogger.ts index 7b365dc3..07b53f1d 100644 --- a/src/diag/ComponentLogger.ts +++ b/src/diag/ComponentLogger.ts @@ -56,7 +56,7 @@ export class DiagComponentLogger implements ComponentLogger { function logProxy( funcName: keyof DiagLogger, - nameSpace: string, + namespace: string, args: any ): void { const logger = getGlobal('diag'); @@ -65,6 +65,6 @@ function logProxy( return; } - args.unshift(nameSpace); + args.unshift(namespace); return logger[funcName].apply(logger, args); } From 0af8b414ff4d4261a03455888c399ebde1c55197 Mon Sep 17 00:00:00 2001 From: Bartlomiej Obecny Date: Fri, 7 May 2021 19:48:29 +0200 Subject: [PATCH 3/4] chore: namespace to be required --- src/diag/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/diag/types.ts b/src/diag/types.ts index 592e3914..00747eab 100644 --- a/src/diag/types.ts +++ b/src/diag/types.ts @@ -133,5 +133,5 @@ export interface ComponentLogger { * Defines options for ComponentLogger */ export interface ComponentLoggerOptions { - namespace?: string; + namespace: string; } From 3a26649b7a78c7105f14a7a14d619fd6257e0e9a Mon Sep 17 00:00:00 2001 From: Bartlomiej Obecny Date: Mon, 10 May 2021 18:21:15 +0200 Subject: [PATCH 4/4] chore: reviews --- src/api/diag.ts | 3 +-- src/diag/ComponentLogger.ts | 18 ++++++++--------- src/diag/types.ts | 39 ------------------------------------- 3 files changed, 10 insertions(+), 50 deletions(-) diff --git a/src/api/diag.ts b/src/api/diag.ts index 5b8886aa..768ad74c 100644 --- a/src/api/diag.ts +++ b/src/api/diag.ts @@ -17,7 +17,6 @@ import { DiagComponentLogger } from '../diag/ComponentLogger'; import { createLogLevelDiagLogger } from '../diag/internal/logLevelLogger'; import { - ComponentLogger, ComponentLoggerOptions, DiagLogFunction, DiagLogger, @@ -122,7 +121,7 @@ export class DiagAPI implements DiagLogger { */ public createComponentLogger!: ( options: ComponentLoggerOptions - ) => ComponentLogger; + ) => DiagLogger; // DiagLogger implementation public verbose!: DiagLogFunction; diff --git a/src/diag/ComponentLogger.ts b/src/diag/ComponentLogger.ts index 07b53f1d..aaddb9de 100644 --- a/src/diag/ComponentLogger.ts +++ b/src/diag/ComponentLogger.ts @@ -15,7 +15,7 @@ */ import { getGlobal } from '../internal/global-utils'; -import { ComponentLogger, ComponentLoggerOptions, DiagLogger } from './types'; +import { ComponentLoggerOptions, DiagLogger } from './types'; /** * Component Logger which is meant to be used as part of any component which @@ -26,31 +26,31 @@ import { ComponentLogger, ComponentLoggerOptions, DiagLogger } from './types'; * cLogger.debug('test'); * // @opentelemetry/instrumentation-http test */ -export class DiagComponentLogger implements ComponentLogger { - public namespace: string; +export class DiagComponentLogger implements DiagLogger { + private _namespace: string; constructor(props: ComponentLoggerOptions) { - this.namespace = props.namespace || 'DiagComponentLogger'; + this._namespace = props.namespace || 'DiagComponentLogger'; } public debug(...args: any[]): void { - return logProxy('debug', this.namespace, args); + return logProxy('debug', this._namespace, args); } public error(...args: any[]): void { - return logProxy('error', this.namespace, args); + return logProxy('error', this._namespace, args); } public info(...args: any[]): void { - return logProxy('info', this.namespace, args); + return logProxy('info', this._namespace, args); } public warn(...args: any[]): void { - return logProxy('warn', this.namespace, args); + return logProxy('warn', this._namespace, args); } public verbose(...args: any[]): void { - return logProxy('verbose', this.namespace, args); + return logProxy('verbose', this._namespace, args); } } diff --git a/src/diag/types.ts b/src/diag/types.ts index 00747eab..54bf398d 100644 --- a/src/diag/types.ts +++ b/src/diag/types.ts @@ -90,45 +90,6 @@ export enum DiagLogLevel { ALL = 9999, } -/** - * Defines options for ComponentLogger - */ -export interface ComponentLogger { - namespace: string; - /** Log an error scenario that was not expected and caused the requested operation to fail. */ - error: (...args: any) => void; - - /** - * Log a warning scenario to inform the developer of an issues that should be investigated. - * The requested operation may or may not have succeeded or completed. - */ - warn: (...args: any) => void; - - /** - * Log a general informational message, this should not affect functionality. - * This is also the default logging level so this should NOT be used for logging - * debugging level information. - */ - info: (...args: any) => void; - - /** - * Log a general debug message that can be useful for identifying a failure. - * Information logged at this level may include diagnostic details that would - * help identify a failure scenario. - * For example: Logging the order of execution of async operations. - */ - debug: (...args: any) => void; - - /** - * Log a detailed (verbose) trace level logging that can be used to identify failures - * where debug level logging would be insufficient, this level of tracing can include - * input and output parameters and as such may include PII information passing through - * the API. As such it is recommended that this level of tracing should not be enabled - * in a production environment. - */ - verbose: (...args: any) => void; -} - /** * Defines options for ComponentLogger */