diff --git a/packages/logger/src/LogAttributesStore.ts b/packages/logger/src/LogAttributesStore.ts index 649e8d0c12..f4cf61854d 100644 --- a/packages/logger/src/LogAttributesStore.ts +++ b/packages/logger/src/LogAttributesStore.ts @@ -1,5 +1,6 @@ import '@aws/lambda-invoke-store'; import { shouldUseInvokeStore } from '@aws-lambda-powertools/commons/utils/env'; +import merge from 'lodash.merge'; import type { LogAttributes } from './types/logKeys.js'; /** @@ -62,11 +63,11 @@ class LogAttributesStore { public appendTemporaryKeys(attributes: LogAttributes): void { const tempAttrs = this.#getTemporaryAttributes(); - const keys = this.#getKeys(); + merge(tempAttrs, attributes); - for (const [key, value] of Object.entries(attributes)) { - tempAttrs[key] = value; - keys.set(key, 'temp'); + const keysMap = this.#getKeys(); + for (const key of Object.keys(attributes)) { + keysMap.set(key, 'temp'); } } diff --git a/packages/logger/tests/unit/workingWithkeys.test.ts b/packages/logger/tests/unit/workingWithkeys.test.ts index 1bf67e7a93..d346b6c34c 100644 --- a/packages/logger/tests/unit/workingWithkeys.test.ts +++ b/packages/logger/tests/unit/workingWithkeys.test.ts @@ -185,6 +185,38 @@ describe('Working with keys', () => { ); }); + it('merges temporary keys with object values when the same key is added', () => { + // Prepare + const logger = new Logger(); + + // Act + logger.appendKeys({ + foo: { key1: 'bar' }, + }); + logger.info('Hello, world!'); + logger.appendKeys({ + foo: { key2: 'baz' }, + }); + logger.info('Hello, world!'); + + // Assess + expect(console.info).toHaveBeenCalledTimes(2); + expect(console.info).toHaveLoggedNth( + 1, + expect.objectContaining({ + message: 'Hello, world!', + foo: { key1: 'bar' }, + }) + ); + expect(console.info).toHaveLoggedNth( + 2, + expect.objectContaining({ + message: 'Hello, world!', + foo: { key1: 'bar', key2: 'baz' }, + }) + ); + }); + it('adds the temporary keys and clears them when calling resetKeys()', () => { // Prepare const logger = new Logger(); @@ -283,6 +315,31 @@ describe('Working with keys', () => { ); }); + it('merges persistent keys with object values when the same key is added', () => { + // Prepare + const logger = new Logger({ + persistentKeys: { + foo: { key1: 'bar' }, + }, + }); + + // Act + logger.appendPersistentKeys({ + foo: { key2: 'baz' }, + }); + logger.info('Hello, world!'); + + // Assess + expect(console.info).toHaveBeenCalledTimes(1); + expect(console.info).toHaveLoggedNth( + 1, + expect.objectContaining({ + message: 'Hello, world!', + foo: { key1: 'bar', key2: 'baz' }, + }) + ); + }); + it('overrides temporary keys when the same key is added as persistent key', () => { // Prepare const logger = new Logger(); @@ -806,25 +863,27 @@ describe('Working with keys', () => { ); }); - it.each([{ value: null }, { value: undefined }])( - 'handles null and undefined values when passing them to the log method ($value)', - ({ value }) => { - // Prepare - const logger = new Logger(); + it.each([ + { value: null }, + { value: undefined }, + ])('handles null and undefined values when passing them to the log method ($value)', ({ + value, + }) => { + // Prepare + const logger = new Logger(); - // Act - // @ts-expect-error - these values are already forbidden by TypeScript, but JavaScript-only customers might pass them - logger.info('foo', value); + // Act + // @ts-expect-error - these values are already forbidden by TypeScript, but JavaScript-only customers might pass them + logger.info('foo', value); - // Assess - expect(console.info).toHaveLoggedNth( - 1, - expect.objectContaining({ - message: 'foo', - }) - ); - } - ); + // Assess + expect(console.info).toHaveLoggedNth( + 1, + expect.objectContaining({ + message: 'foo', + }) + ); + }); describe('deprecated persistentLogAttributes usage', () => { it('sets #attributesStore on the logger', () => {