diff --git a/README.md b/README.md index a1020a6..bd63f9c 100644 --- a/README.md +++ b/README.md @@ -234,6 +234,28 @@ headers['X-Log-Sampled'] ? logger.setDebugSamplingRate(100) : logger.setDebugSam ## Metadata +### One-time root-level enrichment + +If you want a one-time root-level enrichment, you can do: + +```typescript +const logger = MikroLog.start(); +logger.enrichNext({ someId: '123456789abcdefghi' }); +logger.info('Ping!'); // Enrichment is present on log +logger.info('Ping!'); // Enrichment is longer present +``` + +This works just as well on nested object: + +```typescript +const logger = MikroLog.start(); +logger.enrichNext({ myObject: { myValue: 'Something here', otherValue: 'Something else' } }); +logger.info('Ping!'); // Enrichment is present on log +logger.info('Ping!'); // Enrichment is longer present +``` + +Note that only object input is allowed for this method. + ### Static metadata _Static metadata_ is the metadata that you may provide at the time of instantiation. These fields will then be used automatically in all subsequent logs. diff --git a/package-lock.json b/package-lock.json index 088cfbf..fed5ea2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "mikrolog", - "version": "2.1.12", + "version": "2.1.13", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "mikrolog", - "version": "2.1.12", + "version": "2.1.13", "license": "MIT", "dependencies": { "aws-metadata-utils": "1" diff --git a/package.json b/package.json index a346059..22a426d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "mikrolog", "description": "The JSON logger you always wanted for Lambda.", - "version": "2.1.12", + "version": "2.1.13", "author": "Mikael Vesavuori", "license": "MIT", "main": "./lib/index.js", diff --git a/src/entities/MikroLog.ts b/src/entities/MikroLog.ts index 5b72204..3c72e76 100644 --- a/src/entities/MikroLog.ts +++ b/src/entities/MikroLog.ts @@ -42,6 +42,7 @@ export class MikroLog { private static debugSamplingLevel: number; private static isDebugLogSampled: boolean; private static isColdStart = true; + private nextLogEnrichment: Record; private constructor() { MikroLog.metadataConfig = {}; @@ -50,6 +51,7 @@ export class MikroLog { MikroLog.correlationId = ''; MikroLog.debugSamplingLevel = this.initDebugSampleLevel(); MikroLog.isDebugLogSampled = true; + this.nextLogEnrichment = {}; } /** @@ -105,6 +107,13 @@ export class MikroLog { MikroLog.correlationId = input?.correlationId || this.correlationId || ''; } + /** + * @description TODO + */ + public enrichNext(input: Record) { + this.nextLogEnrichment = input; + } + /** * @description Set correlation ID manually, for example for use in cross-boundary calls. * @@ -295,15 +304,24 @@ export class MikroLog { const dynamicMetadata = this.produceDynamicMetadata(); - const logOutput = { - ...dynamicMetadata, - ...staticMetadata, - message: log.message, - error: log.level === 'ERROR', - level: log.level, - httpStatusCode: log.httpStatusCode, - isColdStart: MikroLog.context.isColdStart - }; + const logOutput = (() => { + const output = { + ...dynamicMetadata, + ...staticMetadata, + message: log.message, + error: log.level === 'ERROR', + level: log.level, + httpStatusCode: log.httpStatusCode, + isColdStart: MikroLog.context.isColdStart + }; + + if (this.nextLogEnrichment && JSON.stringify(this.nextLogEnrichment) !== '{}') + return Object.assign(output, this.nextLogEnrichment); + + return output; + })(); + + this.nextLogEnrichment = {}; const filteredOutput = this.filterOutput(logOutput, redactedKeys, maskedValues); return this.sortOutput(filteredOutput); diff --git a/tests/MikroLog.test.ts b/tests/MikroLog.test.ts index 98d8b7c..b331610 100644 --- a/tests/MikroLog.test.ts +++ b/tests/MikroLog.test.ts @@ -570,3 +570,37 @@ test.serial('It should be able to enrich with correlation ID', (t) => { t.deepEqual(cleanedResponse, cleanedExpected); }); + +test.serial( + 'It should enrich a single-level log with a one-time root item and ensure it is not present in later calls', + (t) => { + MikroLog.reset(); + const message = 'Hello World'; + + const logger = MikroLog.start(); + logger.enrichNext({ myValue: 'abc123' }); + + const responseFirst: Record = logger.info(message); + const responseSecond: Record = logger.info(message); + + t.is(responseFirst.hasOwnProperty('myValue'), true); + t.is(responseSecond.hasOwnProperty('myValue'), false); + } +); + +test.serial( + 'It should enrich a multi-level log with a one-time root item and ensure it is not present in later calls', + (t) => { + MikroLog.reset(); + const message = 'Hello World'; + + const logger = MikroLog.start(); + logger.enrichNext({ dd: { trace_id: 'abc123' } }); + + const responseFirst: Record = logger.info(message); + const responseSecond: Record = logger.info(message); + + t.is(responseFirst['dd']['trace_id'], 'abc123'); + t.is(responseSecond.hasOwnProperty('dd'), false); + } +); diff --git a/tsconfig.json b/tsconfig.json index 6075020..3be905f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,7 +13,7 @@ "noFallthroughCasesInSwitch": true, "noUnusedLocals": true, "noUnusedParameters": true, - "removeComments": true, + "removeComments": false, "resolveJsonModule": true, "sourceMap": true, "strict": true,