diff --git a/dist/README.md b/dist/README.md index cbcb8e9..872e89c 100644 --- a/dist/README.md +++ b/dist/README.md @@ -1,10 +1,28 @@ # NestLoggedDecorators + This package provides some decorations to make NestJS logging simpler. It only uses Logger provided by @nestjs/common package and some dependencies required for nestjs. +> TODO: Improve README, providing Quickstart section, add wiki to github + ## How to use +### Installation + +npm: + +```sh +npm i nestlogged +``` + +yarn: + +```sh +yarn add nestlogged +``` + ### Route Logging + ```ts import { Controller, Get } from "@nestjs/common"; import { LoggedRoute } from "nlogdec"; @@ -21,7 +39,7 @@ export class WhateverController { } ``` -``` +```md [Nest] 000000 - 00/00/0000, 00:00:00 AM LOG [WhateverController] HIT HTTP WhateverController//you/like (whateverYouLikeImpl) [Nest] 000000 - 00/00/0000, 00:00:00 AM LOG [WhateverController] RETURNED RESPONSE WhateverController//you/like (whateverYouLikeImpl) ``` @@ -46,7 +64,7 @@ export class WhateverController { } ``` -``` +```md [Nest] 000000 - 00/00/0000, 00:00:00 AM LOG [WhateverController] HIT HTTP WhateverController//you/like (whateverYouLikeImpl) [Nest] 000000 - 00/00/0000, 00:00:00 AM LOG [WhateverController] WHILE HTTP WhateverController//you/like (whateverYouLikeImpl) ERROR BadRequestException: I don't like this ``` @@ -71,7 +89,7 @@ export class WhateverController { } ``` -``` +```md [Nest] 000000 - 00/00/0000, 00:00:00 AM LOG [WhateverController] HIT HTTP WhateverController/you/like (whateverYouLikeImpl) [Nest] 000000 - 00/00/0000, 00:00:00 AM LOG [WhateverController] WHILE HTTP WhateverController/you/like (whateverYouLikeImpl) ERROR BadRequestException: I don't like this ``` @@ -81,6 +99,7 @@ You feel the change? Logged path is slightly changed from `WhateverController//you/like` to `WhateverController/you/like`. ### Function Logging + ```ts import { LoggedFunction } from "nlogdec"; @@ -92,7 +111,7 @@ export async function doILikeThis(stuff: "apple" | "banana"): "yes" | "no" { LoggedFunction decorator will log function calls and returns for you. -**Note: This decorator is expected to be used with a class method. You can't use this outside of class** +> Note: This decorator is expected to be used with a class method. You can't use this outside of class Like `LoggedRoute` decorator, it will automatically catch all exceptions, log it, and throw it again. @@ -111,7 +130,8 @@ export async function doILikeThis( doILikeThis("apple") ``` -``` + +```md HIT HTTP WhateverController//you/like (whateverYouLikeImpl) WITH stuff="apple" ``` @@ -121,6 +141,7 @@ The name of parameter is decided by the first parameter of LoggedParam decorator This decorator also can be used with `LoggedRoute`. ### Class Logging + You can make all method in injectable classes to logged function. ```ts diff --git a/dist/package.json b/dist/package.json index 1eef295..a494032 100644 --- a/dist/package.json +++ b/dist/package.json @@ -1,6 +1,6 @@ { - "name": "nlogdec", - "version": "1.2.3", + "name": "nestlogged", + "version": "1.0.0", "description": "A NestJS Logger Decorator Library", "main": "lib/index.js", "repository": "https://github.com/worplo/nestlogged", diff --git a/src/logged.ts b/src/logged.ts index 914b887..9d0db83 100644 --- a/src/logged.ts +++ b/src/logged.ts @@ -6,7 +6,12 @@ import { ScopeOptions, } from "@nestjs/common"; import { ScopedLogger } from "./logger"; -import { LoggedParamReflectData } from "./reflected"; +import { + LoggedParamReflectData, + ScopeKeyReflectData, + forceScopeKey, + scopeKey, +} from "./reflected"; import { loggedParam, scopedLogger } from "./reflected"; import objectContainedLogged from "./functions"; import { RequestMethod } from "@nestjs/common"; @@ -36,7 +41,9 @@ function loggerInit(_target: any) { } } -export function LoggedInjectable(options?: ScopeOptions) { +export function LoggedInjectable( + options?: ScopeOptions & { verbose?: boolean } +) { return (target: any) => { loggerInit(target.prototype); @@ -52,7 +59,8 @@ export function LoggedInjectable(options?: ScopeOptions) { const all = Reflect.getMetadataKeys(target.prototype[method]).map( (k) => [k, Reflect.getMetadata(k, target.prototype[method])] ); - logger.log(`LoggedFunction applied to ${method}`); + if (options && options.verbose) + logger.log(`LoggedFunction applied to ${method}`); LoggedFunction(target.prototype, method, { value: target.prototype[method], }); @@ -71,7 +79,7 @@ export function LoggedController( prefix: string | string[] ): (target: any) => void; export function LoggedController( - options: ControllerOptions + options: ControllerOptions & { verbose?: boolean } ): (target: any) => void; export function LoggedController(param?: any): (target: any) => void { @@ -82,6 +90,11 @@ export function LoggedController(param?: any): (target: any) => void { const methods = Object.getOwnPropertyNames(target.prototype); + let verbose = + typeof param === "object" && Object.keys(param).includes("verbose") + ? param.verbose + : false; + methods.forEach((method) => { if ( method !== "constructor" && @@ -95,9 +108,10 @@ export function LoggedController(param?: any): (target: any) => void { const all = Reflect.getMetadataKeys(target.prototype[method]).map( (k) => [k, Reflect.getMetadata(k, target.prototype[method])] ); - logger.log( - `LoggedRoute applied to ${method} (${RevRequestMethod[httpMethod]} ${path})` - ); + if (verbose) + logger.log( + `LoggedRoute applied to ${method} (${RevRequestMethod[httpMethod]} ${path})` + ); LoggedRoute()(target.prototype, method, { value: target.prototype[method], }); @@ -111,6 +125,126 @@ export function LoggedController(param?: any): (target: any) => void { }; } +interface FunctionMetadata { + scopedLoggerInjectableParam?: number; + scopeKeys?: ScopeKeyReflectData[]; + shouldScoped?: boolean; + loggedParams?: LoggedParamReflectData[]; +} + +function overrideBuild, R>( + originalFunction: (...args: F) => Promise, + baseLogger: Logger, + metadatas: FunctionMetadata, + key: string, + route?: { + fullRoute: string; + } +) { + return async function (...args: F) { + let injectedLogger: Logger = baseLogger; + if (typeof metadatas.scopedLoggerInjectableParam !== "undefined") { + if ( + args.length <= metadatas.scopedLoggerInjectableParam || + !(args[metadatas.scopedLoggerInjectableParam] instanceof ScopedLogger) + ) { + args[metadatas.scopedLoggerInjectableParam] = new ScopedLogger( + baseLogger, + key + ); + } else { + args[metadatas.scopedLoggerInjectableParam] = new ScopedLogger( + args[metadatas.scopedLoggerInjectableParam], + key + ); + } + + injectedLogger = args[metadatas.scopedLoggerInjectableParam]; + + if (Array.isArray(metadatas.scopeKeys)) { + const scopeKeyResults: { error: boolean; value: string }[] = + metadatas.scopeKeys.map((key) => { + const argsValue = args[key.index]; + if (!key.path) { + if (!metadatas.shouldScoped || argsValue) { + return { error: false, value: `${key.name}=${argsValue}` }; + } else { + return { + error: true, + value: `ScopeKey in ShouldScope cannot be falsy value (${argsValue})`, + }; + } + } + try { + const reduceResult = key.path.reduce((base, keyPath) => { + if ( + typeof base !== "object" || + !Object.keys(base).includes(keyPath) + ) + throw new Error( + `Cannot find key ${keyPath} in ${ + typeof base === "object" ? JSON.stringify(base) : base + }` + ); + return base[keyPath]; + }, argsValue); + return { error: false, value: `${key.name}=${reduceResult}` }; + } catch (e) { + return { error: true, value: e.message }; + } + }); + + const successResults = scopeKeyResults.filter((v) => v.error === false); + if (successResults.length === 0) { + if (metadatas.shouldScoped) { + scopeKeyResults.forEach((v) => injectedLogger.warn(v.value)); + } + } else { + (injectedLogger as ScopedLogger).addScope(successResults[0].value); + } + } + } + + injectedLogger.log( + `${route ? "HIT HTTP" : "CALL"} ${ + route ? `${route.fullRoute} (${key})` : key + } ${ + metadatas.loggedParams && metadatas.loggedParams.length > 0 + ? "WITH " + + ( + await Promise.all( + metadatas.loggedParams.map( + async ({ name, index, include, exclude }) => + name + + "=" + + (await objectContainedLogged(args[index], { + include, + exclude, + })) + ) + ) + ).join(", ") + : "" + }` + ); + + try { + const r: R = await originalFunction.call(this, ...args); + injectedLogger.log( + route + ? `RETURNED RESPONSE ${route.fullRoute} (${key})` + : `RETURNED ${key}` + ); + return r; + } catch (e) { + injectedLogger.error( + `WHILE ${route ? `HTTP ${route.fullRoute} (${key})` : key} ERROR ${e}` + ); + throw e; + } + }; +} + export function LoggedFunction, R>( _target: any, key: string, @@ -129,67 +263,40 @@ export function LoggedFunction, R>( return; } - _target[key] = async function (...args: F) { - const scopedLoggerInjectableParam: number = Reflect.getOwnMetadata( - scopedLogger, - _target, - key - ); + const scopedLoggerInjectableParam: number = Reflect.getOwnMetadata( + scopedLogger, + _target, + key + ); - if ( - typeof scopedLoggerInjectableParam !== "undefined" && - (args.length <= scopedLoggerInjectableParam || - !(args[scopedLoggerInjectableParam] instanceof ScopedLogger)) - ) { - args[scopedLoggerInjectableParam] = new ScopedLogger(logger, key); - } else if (typeof scopedLoggerInjectableParam !== "undefined") { - args[scopedLoggerInjectableParam] = new ScopedLogger( - args[scopedLoggerInjectableParam], - key - ); - } + const loggedParams: LoggedParamReflectData[] = Reflect.getOwnMetadata( + loggedParam, + _target, + key + ); - const injectedLogger = - typeof scopedLoggerInjectableParam !== "undefined" - ? args[scopedLoggerInjectableParam] - : logger; + const scopeKeys: ScopeKeyReflectData[] = Reflect.getOwnMetadata( + scopeKey, + _target, + key + ); - const loggedParams: LoggedParamReflectData[] = Reflect.getOwnMetadata( - loggedParam, - _target, - key - ); + const shouldScoped: boolean = Reflect.getOwnMetadata(forceScopeKey, fn); - injectedLogger.log( - `CALL ${key} ${ - loggedParams && loggedParams.length > 0 - ? "WITH " + - ( - await Promise.all( - loggedParams.map( - async ({ name, index, include, exclude }) => - name + - "=" + - (await objectContainedLogged(args[index], { - include, - exclude, - })) - ) - ) - ).join(", ") - : "" - }` - ); + const overrideFunction = overrideBuild( + fn, + logger, + { + scopedLoggerInjectableParam, + loggedParams, + scopeKeys, + shouldScoped, + }, + key + ); - try { - const r: R = await fn.call(this, ...args); - injectedLogger.log(`RETURNED ${key}`); - return r; - } catch (e) { - injectedLogger.error(`WHILE ${key} ERROR ${e}`); - throw e; - } - }; + _target[key] = overrideFunction; + descriptor.value = overrideFunction; } export function LoggedRoute, R>(route?: string) { @@ -204,13 +311,6 @@ export function LoggedRoute, R>(route?: string) { const fn = descriptor.value; - const httpPath: string = Reflect.getMetadata("path", fn); - const httpMethod: RequestMethod = Reflect.getMetadata("method", fn); - - const fullRoute = `${_target.constructor.name}::${route ?? httpPath}[${ - RevRequestMethod[httpMethod] - }]`; - if (!fn || typeof fn !== "function") { logger.warn( `LoggedRoute decorator applied to non-function property: ${key}` @@ -218,63 +318,46 @@ export function LoggedRoute, R>(route?: string) { return; } - _target[key] = async function (...args: F) { - const scopedLoggerInjectableParam: number = Reflect.getOwnMetadata( - scopedLogger, - _target, - key - ); + const httpPath: string = Reflect.getMetadata("path", fn); + const httpMethod: RequestMethod = Reflect.getMetadata("method", fn); - if ( - typeof scopedLoggerInjectableParam !== "undefined" && - (args.length <= scopedLoggerInjectableParam || - !(args[scopedLoggerInjectableParam] instanceof ScopedLogger)) - ) { - args[scopedLoggerInjectableParam] = new ScopedLogger(logger, fullRoute); + const fullRoute = `${_target.constructor.name}::${route ?? httpPath}[${ + RevRequestMethod[httpMethod] + }]`; + + const scopedLoggerInjectableParam: number = Reflect.getOwnMetadata( + scopedLogger, + _target, + key + ); + + const loggedParams: LoggedParamReflectData[] = Reflect.getOwnMetadata( + loggedParam, + _target, + key + ); + + const scopeKeys: ScopeKeyReflectData[] = Reflect.getOwnMetadata( + scopeKey, + _target, + key + ); + + const shouldScoped: boolean = Reflect.getOwnMetadata(forceScopeKey, fn); + + const overrideFunction = overrideBuild( + fn, + logger, + { + scopedLoggerInjectableParam, + loggedParams, + scopeKeys, + shouldScoped, + }, + key, + { + fullRoute, } - - const injectedLogger = - typeof scopedLoggerInjectableParam !== "undefined" - ? args[scopedLoggerInjectableParam] - : logger; - - const loggedParams: LoggedParamReflectData[] = Reflect.getOwnMetadata( - loggedParam, - _target, - key - ); - - injectedLogger.log( - `HIT HTTP ${fullRoute} (${key}) ${ - loggedParams && loggedParams.length > 0 - ? "WITH " + - ( - await Promise.all( - loggedParams.map( - async ({ name, index, include, exclude }) => - name + - "=" + - (await objectContainedLogged(args[index], { - include, - exclude, - })) - ) - ) - ).join(", ") - : "" - }` - ); - - try { - const r: R = await fn.call(this, ...args); - injectedLogger.log(`RETURNED RESPONSE ${fullRoute} (${key})`); - return r; - } catch (e) { - injectedLogger.error(`WHILE HTTP ${fullRoute} (${key}) ERROR ${e}`); - throw e; - } - }; - - return [httpPath, httpMethod]; + ); }; } diff --git a/src/logger.ts b/src/logger.ts index 485401e..0c28a1c 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -11,6 +11,10 @@ export class ScopedLogger extends Logger { super(); } + public addScope(scopeId: string) { + this.scopeId = scopeId; + } + private scopedLog(method: LogLevel) { return (message: string) => { this.logger[method]( diff --git a/src/reflected.ts b/src/reflected.ts index 8144e65..62327d2 100644 --- a/src/reflected.ts +++ b/src/reflected.ts @@ -5,8 +5,17 @@ export interface LoggedParamReflectData { exclude?: string[]; } -export const scopedLogger = Symbol("scopedLogger"); -export const loggedParam = Symbol("loggedParam"); +export interface ScopeKeyReflectData { + name: string; + index: number; + path?: string[]; + priority?: number; +} + +export const scopedLogger = Symbol("nlogdec-scopedLogger"); +export const loggedParam = Symbol("nlogdec-loggedParam"); +export const scopeKey = Symbol("nlogdec-scopeKey"); +export const forceScopeKey = Symbol("nlogdec-forceScopeKey"); export function InjectLogger( target: any, @@ -34,6 +43,7 @@ export function LoggedParam( existingLoggedParams.push({ name, index: parameterIndex, + // If path is provided in string[] type, convert it to string path because it is used in string type include: options && options.includePath && @@ -52,3 +62,38 @@ export function LoggedParam( ); }; } + +export function ScopeKey( + name: string, + options?: { path?: string | string[]; priority?: number } +) { + return ( + target: any, + propertyKey: string | symbol, + parameterIndex: number + ) => { + const existingScopeKeys: ScopeKeyReflectData[] = + Reflect.getOwnMetadata(scopeKey, target, propertyKey) || []; + + existingScopeKeys.push({ + name, + index: parameterIndex, + path: Array.isArray(options?.path) + ? options.path + : options?.path?.split("."), + priority: options?.priority, + }); + + existingScopeKeys.sort((a, b) => (b.priority ?? 1) - (a.priority ?? 1)); + + Reflect.defineMetadata(scopeKey, existingScopeKeys, target, propertyKey); + }; +} + +export function ShouldScoped( + _target: any, + _key: string, + descriptor: TypedPropertyDescriptor<(...args: any[]) => Promise> +) { + Reflect.defineMetadata(forceScopeKey, true, descriptor.value); +} diff --git a/src/test/index.ts b/src/test/index.ts index e69de29..68d556b 100644 --- a/src/test/index.ts +++ b/src/test/index.ts @@ -0,0 +1,313 @@ +import { LoggedFunction, LoggedInjectable } from "../logged"; +import { ScopedLogger } from "../logger"; +import { + InjectLogger, + LoggedParam, + ScopeKey, + ShouldScoped, +} from "../reflected"; + +type TestObject = { + a: string; + b: { c: string; f: number }; + d: [number, string]; + e: { p: string; g: number }; +}; + +const testObject: TestObject = { + a: "asdf", + b: { c: "zxcv", f: 1 }, + d: [2, "qwer"], + e: { p: "uiop", g: 3 }, +}; + +@LoggedInjectable() +class LoggedClass { + async testParameterLoggingWithoutInjection(@LoggedParam("key") key: number) { + console.log(key); + } + + async testMultiParameterLoggingWithoutInjection( + @LoggedParam("key") key: number, + @LoggedParam("key2") key2: string + ) { + console.log(key, key2); + } + + async testParameterLoggingWithInjection( + @LoggedParam("key") key: number, + @InjectLogger logger?: ScopedLogger + ) { + logger.log(key.toString()); + } + + async testMultiParameterLoggingWithInjection( + @LoggedParam("key") key: number, + @LoggedParam("key2") key2: string, + @InjectLogger logger?: ScopedLogger + ) { + logger.log(key.toString() + key2); + } + + async testObjectParameterLogging( + @LoggedParam("key") key: TestObject, + @InjectLogger logger?: ScopedLogger + ) { + logger.log(JSON.stringify(key)); + } + + async testObjectParameterDotIncludeLogging( + @LoggedParam("key", { includePath: ["a", "b.c", "d.0", "e"] }) + key: TestObject, + @InjectLogger logger?: ScopedLogger + ) { + logger.log(JSON.stringify(key)); + } + + async testObjectParameterArrayIncludeLogging( + @LoggedParam("key", { includePath: [["a"], ["b", "c"], ["d", "0"], ["e"]] }) + key: TestObject, + @InjectLogger logger?: ScopedLogger + ) { + logger.log(JSON.stringify(key)); + } + + async testObjectParameterDotExcludeLogging( + @LoggedParam("key", { excludePath: ["a", "b.c", "d.0", "e"] }) + key: TestObject, + @InjectLogger logger?: ScopedLogger + ) { + logger.log(JSON.stringify(key)); + } + + async testObjectParameterArrayExcludeLogging( + @LoggedParam("key", { excludePath: [["a"], ["b", "c"], ["d", "0"], ["e"]] }) + key: TestObject, + @InjectLogger logger?: ScopedLogger + ) { + logger.log(JSON.stringify(key)); + } + + async testScopedLogging( + @LoggedParam("key") @ScopeKey("scopekey") key: string, + @LoggedParam("key2") key2: number, + @InjectLogger logger?: ScopedLogger + ) { + logger.log(key + key2.toString()); + } + + async testPathScopedLogging( + @LoggedParam("key") @ScopeKey("scopekey", { path: "b.c" }) key: TestObject, + @InjectLogger logger?: ScopedLogger + ) { + logger.log(JSON.stringify(key)); + } + + async testOrScopedLogging( + @LoggedParam("key") + @ScopeKey("scopekey-a", { path: "a" }) + @ScopeKey("scopekey-b", { path: "b" }) + key: { a: string } | { b: string }, + @InjectLogger logger?: ScopedLogger + ) { + logger.log(JSON.stringify(key)); + } + + async testPriorityScopedLogging( + @LoggedParam("key") + @ScopeKey("scopekey-a", { path: "a", priority: 0.5 }) + @ScopeKey("scopekey-b", { path: "b" }) // default 1 + key: { a?: string; b?: string }, + // if both a and b are undefined, set scope to nothing + @InjectLogger logger?: ScopedLogger + ) { + logger.log(JSON.stringify(key)); + } + + async testOptionalScopedLogging( + @LoggedParam("key") + @ScopeKey("scopekey") + key?: string, + @InjectLogger logger?: ScopedLogger + ) { + logger.log(key); + } + + @ShouldScoped // Warn if there is no valid scopekey + async testShouldScopedLogging( + @LoggedParam("key") + @ScopeKey("scopekey") + key?: string, + @InjectLogger logger?: ScopedLogger + ) { + logger.log(key); + } +} + +class LoggedMethodsClass { + @LoggedFunction + async testParameterLoggingWithoutInjection(@LoggedParam("key") key: number) { + console.log(key); + } + + @LoggedFunction + async testMultiParameterLoggingWithoutInjection( + @LoggedParam("key") key: number, + @LoggedParam("key2") key2: string + ) { + console.log(key, key2); + } + + @LoggedFunction + async testParameterLoggingWithInjection( + @LoggedParam("key") key: number, + @InjectLogger logger?: ScopedLogger + ) { + logger.log(key.toString()); + } + + @LoggedFunction + async testMultiParameterLoggingWithInjection( + @LoggedParam("key") key: number, + @LoggedParam("key2") key2: string, + @InjectLogger logger?: ScopedLogger + ) { + logger.log(key.toString() + key2); + } + + @LoggedFunction + async testObjectParameterLogging( + @LoggedParam("key") key: TestObject, + @InjectLogger logger?: ScopedLogger + ) { + logger.log(JSON.stringify(key)); + } + + @LoggedFunction + async testObjectParameterDotIncludeLogging( + @LoggedParam("key", { includePath: ["a", "b.c", "d.0", "e"] }) + key: TestObject, + @InjectLogger logger?: ScopedLogger + ) { + logger.log(JSON.stringify(key)); + } + + @LoggedFunction + async testObjectParameterArrayIncludeLogging( + @LoggedParam("key", { includePath: [["a"], ["b", "c"], ["d", "0"], ["e"]] }) + key: TestObject, + @InjectLogger logger?: ScopedLogger + ) { + logger.log(JSON.stringify(key)); + } + + @LoggedFunction + async testObjectParameterDotExcludeLogging( + @LoggedParam("key", { excludePath: ["a", "b.c", "d.0", "e"] }) + key: TestObject, + @InjectLogger logger?: ScopedLogger + ) { + logger.log(JSON.stringify(key)); + } + + @LoggedFunction + async testObjectParameterArrayExcludeLogging( + @LoggedParam("key", { excludePath: [["a"], ["b", "c"], ["d", "0"], ["e"]] }) + key: TestObject, + @InjectLogger logger?: ScopedLogger + ) { + logger.log(JSON.stringify(key)); + } + + @LoggedFunction + async testScopedLogging( + @LoggedParam("key") @ScopeKey("scopekey") key: string, + @LoggedParam("key2") key2: number, + @InjectLogger logger?: ScopedLogger + ) { + logger.log(key + key2.toString()); + } + + @LoggedFunction + async testPathScopedLogging( + @LoggedParam("key") @ScopeKey("scopekey", { path: "b.c" }) key: TestObject, + @InjectLogger logger?: ScopedLogger + ) { + logger.log(JSON.stringify(key)); + } + + @LoggedFunction + async testOrScopedLogging( + @LoggedParam("key") + @ScopeKey("scopekey-a", { path: "a" }) + @ScopeKey("scopekey-b", { path: "b" }) + key: { a: string } | { b: string }, + @InjectLogger logger?: ScopedLogger + ) { + logger.log(JSON.stringify(key)); + } + + @LoggedFunction + async testPriorityScopedLogging( + @LoggedParam("key") + @ScopeKey("scopekey-a", { path: "a", priority: 0.5 }) + @ScopeKey("scopekey-b", { path: "b" }) // default 1 + key: { a?: string; b?: string }, + // if both a and b are undefined, set scope to nothing + @InjectLogger logger?: ScopedLogger + ) { + logger.log(JSON.stringify(key)); + } + + @LoggedFunction + async testOptionalScopedLogging( + @LoggedParam("key") + @ScopeKey("scopekey") + key?: string, + @InjectLogger logger?: ScopedLogger + ) { + logger.log(key); + } + + @LoggedFunction + @ShouldScoped // Warn if there is no valid scopekey + async testShouldScopedLogging( + @LoggedParam("key") + @ScopeKey("scopekey") + key?: string, + @InjectLogger logger?: ScopedLogger + ) { + logger.log(key); + } +} + +/** + * Choose Class to Test + */ +// const tester = new LoggedClass(); +const tester = new LoggedMethodsClass(); + +/** + * Choose Method to Test + */ +// tester.testParameterLoggingWithoutInjection(1); +// tester.testMultiParameterLoggingWithoutInjection(1, "asdf"); +// tester.testParameterLoggingWithInjection(1); +// tester.testMultiParameterLoggingWithInjection(1, "asdf"); +// tester.testObjectParameterLogging(testObject); +// tester.testObjectParameterDotIncludeLogging(testObject); +// tester.testObjectParameterArrayIncludeLogging(testObject); +// tester.testObjectParameterDotExcludeLogging(testObject); +// tester.testObjectParameterArrayExcludeLogging(testObject); +// tester.testScopedLogging("asdf", 2); +// tester.testPathScopedLogging(testObject); +// tester.testOrScopedLogging({ a: "asdf" }); +// tester.testOrScopedLogging({ b: "qwer" }); +// tester.testPriorityScopedLogging({ a: "asdf", b: "qwer" }); +// tester.testPriorityScopedLogging({ a: "asdf" }); +// tester.testPriorityScopedLogging({ b: "qwer" }); +// tester.testPriorityScopedLogging({}); +// tester.testOptionalScopedLogging("asdf"); +// tester.testOptionalScopedLogging(); +// tester.testShouldScopedLogging("asdf"); +tester.testShouldScopedLogging();