From d1284bf321bbab1a5124eab1598c9f97d2062604 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Thu, 27 Jun 2024 12:13:40 +0200 Subject: [PATCH] docs(logger): rework working with keys doc sections (#2696) --- docs/core/logger.md | 254 +++++++++++------- .../snippets/logger/appendAndRemoveKeys.ts | 30 +++ examples/snippets/logger/appendKeys.ts | 31 --- .../snippets/logger/clearStateDecorator.ts | 33 --- examples/snippets/logger/clearStateMiddy.ts | 32 --- examples/snippets/logger/persistentKeys.ts | 22 ++ .../logger/persistentKeysConstructor.ts | 18 ++ examples/snippets/logger/removeKeys.ts | 30 +++ .../snippets/logger/removePersistentKeys.ts | 24 ++ examples/snippets/logger/resetKeys.ts | 27 ++ .../snippets/logger/resetKeysDecorator.ts | 30 +++ examples/snippets/logger/resetKeysMiddy.ts | 24 ++ packages/logger/src/Logger.ts | 42 ++- packages/logger/src/middleware/middy.ts | 9 +- packages/logger/src/types/Logger.ts | 22 +- packages/logger/tests/unit/Logger.test.ts | 12 +- 16 files changed, 420 insertions(+), 220 deletions(-) create mode 100644 examples/snippets/logger/appendAndRemoveKeys.ts delete mode 100644 examples/snippets/logger/appendKeys.ts delete mode 100644 examples/snippets/logger/clearStateDecorator.ts delete mode 100644 examples/snippets/logger/clearStateMiddy.ts create mode 100644 examples/snippets/logger/persistentKeys.ts create mode 100644 examples/snippets/logger/persistentKeysConstructor.ts create mode 100644 examples/snippets/logger/removeKeys.ts create mode 100644 examples/snippets/logger/removePersistentKeys.ts create mode 100644 examples/snippets/logger/resetKeys.ts create mode 100644 examples/snippets/logger/resetKeysDecorator.ts create mode 100644 examples/snippets/logger/resetKeysMiddy.ts diff --git a/docs/core/logger.md b/docs/core/logger.md index c9b95b8b25..d98c647996 100644 --- a/docs/core/logger.md +++ b/docs/core/logger.md @@ -181,93 +181,199 @@ When debugging in non-production environments, you can instruct Logger to log th Use `POWERTOOLS_LOGGER_LOG_EVENT` environment variable to enable or disable (`true`/`false`) this feature. -### Appending persistent additional log keys and values +### Appending additional keys -You can append additional persistent keys and values in the logs generated during a Lambda invocation using either mechanism: +You can append additional keys using either machanism: -* Via the Logger's `appendKeys` method, for all log items generated after calling this method -* Passing them in the Logger's constructor +* Add **extra keys** to a single log message by passing them to the log method directly +* Append **temporary keys** to all future log messages via the `appendKeys()` method until `resetKeys()` is called +* Set **Persistent keys** for the logger instance via the `persistentKeys` constructor option or the `appendPersistentKeys()` method -To remove the keys you added, you can use the `removeKeys` method. +#### Extra keys + +You can append additional data to a single log item by passing objects as additional parameters. + +* Pass a simple string for logging it with default key name `extra` +* Pass one or multiple objects containing arbitrary data to be logged. Each data object should be placed in an enclosing object as a single property value, you can name this property as you need: `{ myData: arbitraryObjectToLog }` +* If you already have an object containing a `message` key and an additional property, you can pass this object directly === "handler.ts" - ```typescript hl_lines="5-13 17-25 32" - --8<-- "examples/snippets/logger/appendKeys.ts" + ```typescript hl_lines="16-18 23-25 37" + --8<-- "examples/snippets/logger/extraData.ts" ``` === "Example CloudWatch Logs excerpt" - ```json hl_lines="7-12 20-25" + ```json hl_lines="7 15-21 29 37" { "level": "INFO", - "message": "This is an INFO log", + "message": "This is a log with an extra variable", "service": "serverlessAirline", - "timestamp": "2021-12-12T21:49:58.084Z", + "timestamp": "2021-12-12T22:06:17.463Z", "xray_trace_id": "abcdef123456abcdef123456abcdef123456", - "aws_account_id": "123456789012", - "aws_region": "eu-west-1", - "logger": { - "name": "@aws-lambda-powertools/logger", - "version": "0.0.1" + "data": { "foo": "bar" } + } + { + "level": "INFO", + "message": "This is a log with 3 extra objects", + "service": "serverlessAirline", + "timestamp": "2021-12-12T22:06:17.466Z", + "xray_trace_id": "abcdef123456abcdef123456abcdef123456", + "data": { "foo": "bar" }, + "correlationIds": { "myCustomCorrelationId": "foo-bar-baz" }, + "lambdaEvent": { + "exampleEventData": { + "eventValue": 42 + } } } { "level": "INFO", - "message": "This is another INFO log", + "message": "This is a log with additional string value", + "service": "serverlessAirline", + "timestamp": "2021-12-12T22:06:17.463Z", + "xray_trace_id": "abcdef123456abcdef123456abcdef123456", + "extra": "string value" + } + { + "level": "INFO", + "message": "This is a log message", + "service": "serverlessAirline", + "timestamp": "2021-12-12T22:06:17.463Z", + "xray_trace_id": "abcdef123456abcdef123456abcdef123456", + "additionalValue": 42 + } + ``` + +#### Temporary keys + +You can append additional keys to all future log messages by using the `appendKeys()` method. + +???+ tip "When is this useful?" + This is helpful to contextualize log messages emitted during a specific function. + +=== "handler.ts" + + ```typescript hl_lines="9-11" + --8<-- "examples/snippets/logger/appendAndRemoveKeys.ts" + ``` + + 1. You can also remove specific keys by calling the `removeKeys()` method. + +=== "Example CloudWatch Logs excerpt" + + ```json hl_lines="7" + { + "level": "INFO", + "message": "transaction processed", + "service": "serverlessAirline", + "timestamp": "2021-12-12T21:49:58.084Z", + "xray_trace_id": "abcdef123456abcdef123456abcdef123456", + "customerId": "123456789012" + } + { + "level": "INFO", + "message": "other business logic processed", "service": "serverlessAirline", "timestamp": "2021-12-12T21:49:58.088Z", + "xray_trace_id": "abcdef123456abcdef123456abcdef123456" + } + ``` + +#### Persistent keys + +You can persist keys across Lambda invocations by using the `persistentKeys` constructor option or the `appendPersistentKeys()` method. These keys will persist even if you call the [`resetKeys()` method](#resetting-keys). + +A common use case is to set keys about your environment or application version, so that you can easily filter logs in CloudWatch Logs. + +=== "As constructor options" + + ```typescript hl_lines="5-8" + --8<-- "examples/snippets/logger/persistentKeysConstructor.ts" + ``` + +=== "Via dynamic method" + + ```typescript hl_lines="13" + --8<-- "examples/snippets/logger/persistentKeys.ts" + ``` + +=== "Example CloudWatch Logs excerpt" + + ```json hl_lines="7-8" + { + "level": "INFO", + "message": "processing transaction", + "service": "serverlessAirline", + "timestamp": "2021-12-12T21:49:58.084Z", "xray_trace_id": "abcdef123456abcdef123456abcdef123456", - "aws_account_id": "123456789012", - "aws_region": "eu-west-1", - "logger": { - "name": "@aws-lambda-powertools/logger", - "version": "0.0.1" - } + "environment": "prod", + "version": "1.2.0", } ``` -!!! tip "Logger will automatically ignore any key with an `undefined` value" +### Removing additional keys + +You can remove additional keys from the logger instance at any time: + +* Remove temporary keys added via the `appendKeys()` method by using the `removeKeys()` method +* Remove persistent keys added via the `persistentKeys` constructor option or the `appendPersistentKeys()` method by using the `removePersistentKeys()` method + +=== "Remove temporary keys" + + ```typescript hl_lines="17" + --8<-- "examples/snippets/logger/removeKeys.ts" + ``` + +=== "Remove persistent keys" -#### Clearing all state + ```typescript hl_lines="19" + --8<-- "examples/snippets/logger/removePersistentKeys.ts" + ``` + +#### Resetting keys + +Logger is commonly initialized in the global scope. Due to [Lambda Execution Context](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtime-environment.html){target="_blank"} reuse, this means that custom keys can be persisted across invocations. + +Resetting the state allows you to clear all the temporary keys you have added. + +???+ tip "Tip: When is this useful?" + This is useful when you add multiple custom keys conditionally or when you use canonical or wide logs. -The Logger utility is commonly initialized in the global scope, outside the handler function. -When you attach persistent log attributes through the `persistentLogAttributes` constructor option or via the `appendKeys`, `addPersistentLogAttributes` methods, this data is attached to the Logger instance. +=== "Clearing state manually" -Due to the [Lambda Execution Context reuse](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-context.html), this means those persistent log attributes may be reused across invocations. -If you want to make sure that persistent attributes added **inside the handler function** code are not persisted across invocations, you can set the parameter `clearState` as `true` in the `injectLambdaContext` middleware or decorator. + ```typescript hl_lines="25" + --8<-- "examples/snippets/logger/resetKeys.ts" + ``` === "Middy Middleware" - ```typescript hl_lines="31" - --8<-- "examples/snippets/logger/clearStateMiddy.ts" + ```typescript hl_lines="24" + --8<-- "examples/snippets/logger/resetKeysMiddy.ts" ``` === "Decorator" - ```typescript hl_lines="16" - --8<-- "examples/snippets/logger/clearStateDecorator.ts" + ```typescript hl_lines="13" + --8<-- "examples/snippets/logger/resetKeysDecorator.ts" ``` 1. Binding your handler method allows your handler to access `this` within the class methods. -In each case, the printed log will look like this: - === "First invocation" - ```json hl_lines="2 4-7" + ```json hl_lines="2 4" { - "biz": "baz", + "environment": "prod", "cold_start": true, - "details": { - "special_key": "123456", - }, + "userId": "123456789012", "foo": "bar", "function_arn": "arn:aws:lambda:eu-west-1:123456789012:function:foo-bar-function", "function_memory_size": 128, "function_name": "foo-bar-function", "function_request_id": "abcdef123456abcdef123456", - "level": "DEBUG", - "message": "This is a DEBUG log with the user_id", + "level": "INFO", + "message": "WIDE", "service": "hello-world", "timestamp": "2021-12-12T22:32:54.670Z", "xray_trace_id": "1-5759e988-bd862e3fe1be46a994272793" @@ -277,77 +383,21 @@ In each case, the printed log will look like this: ```json hl_lines="2 4" { - "biz": "baz", + "environment": "prod", "cold_start": false, - "foo": "bar", + "userId": "210987654321", "function_arn": "arn:aws:lambda:eu-west-1:123456789012:function:foo-bar-function", "function_memory_size": 128, "function_name": "foo-bar-function", "function_request_id": "abcdef123456abcdef123456", - "level": "DEBUG", - "message": "This is a DEBUG log with the user_id", + "level": "INFO", + "message": "WIDE", "service": "hello-world", "timestamp": "2021-12-12T22:40:23.120Z", "xray_trace_id": "1-5759e988-bd862e3fe1be46a994272793" } ``` -### Appending additional data to a single log item - -You can append additional data to a single log item by passing objects as additional parameters. - -* Pass a simple string for logging it with default key name `extra` -* Pass one or multiple objects containing arbitrary data to be logged. Each data object should be placed in an enclosing object as a single property value, you can name this property as you need: `{ myData: arbitraryObjectToLog }` -* If you already have an object containing a `message` key and an additional property, you can pass this object directly - -=== "handler.ts" - - ```typescript hl_lines="16-18 23-25 37" - --8<-- "examples/snippets/logger/extraData.ts" - ``` -=== "Example CloudWatch Logs excerpt" - - ```json hl_lines="7 15-21 29 37" - { - "level": "INFO", - "message": "This is a log with an extra variable", - "service": "serverlessAirline", - "timestamp": "2021-12-12T22:06:17.463Z", - "xray_trace_id": "abcdef123456abcdef123456abcdef123456", - "data": { "foo": "bar" } - } - { - "level": "INFO", - "message": "This is a log with 3 extra objects", - "service": "serverlessAirline", - "timestamp": "2021-12-12T22:06:17.466Z", - "xray_trace_id": "abcdef123456abcdef123456abcdef123456", - "data": { "foo": "bar" }, - "correlationIds": { "myCustomCorrelationId": "foo-bar-baz" }, - "lambdaEvent": { - "exampleEventData": { - "eventValue": 42 - } - } - } - { - "level": "INFO", - "message": "This is a log with additional string value", - "service": "serverlessAirline", - "timestamp": "2021-12-12T22:06:17.463Z", - "xray_trace_id": "abcdef123456abcdef123456abcdef123456", - "extra": "string value" - } - { - "level": "INFO", - "message": "This is a log message", - "service": "serverlessAirline", - "timestamp": "2021-12-12T22:06:17.463Z", - "xray_trace_id": "abcdef123456abcdef123456abcdef123456", - "additionalValue": 42 - } - ``` - ### Logging errors You can log errors by using the `error` method and pass the error object as parameter. @@ -471,7 +521,7 @@ In the event you have set a log level in Powertools to a level that is lower tha ### Using multiple Logger instances across your code -The `createChild` method allows you to create a child instance of the Logger, which inherits all of the attributes from its parent. You have the option to override any of the settings and attributes from the parent logger, including [its settings](#utility-settings), any [persistent attributes](#appending-persistent-additional-log-keys-and-values), and [the log formatter](#custom-log-formatter-bring-your-own-formatter). +The `createChild` method allows you to create a child instance of the Logger, which inherits all of the attributes from its parent. You have the option to override any of the settings and attributes from the parent logger, including [its settings](#utility-settings), any [extra keys](#appending-additional-keys), and [the log formatter](#custom-log-formatter-bring-your-own-formatter). Once a child logger is created, the logger and its parent will act as separate instances of the Logger class, and as such any change to one won't be applied to the other. diff --git a/examples/snippets/logger/appendAndRemoveKeys.ts b/examples/snippets/logger/appendAndRemoveKeys.ts new file mode 100644 index 0000000000..99605755e7 --- /dev/null +++ b/examples/snippets/logger/appendAndRemoveKeys.ts @@ -0,0 +1,30 @@ +import { Logger } from '@aws-lambda-powertools/logger'; + +const logger = new Logger({ + serviceName: 'serverlessAirline', +}); + +const processTransaction = async (customerId: string): Promise => { + try { + logger.appendKeys({ + customerId, + }); + + // ... your business logic + + logger.info('transaction processed'); + } finally { + logger.resetKeys(); // (1)! + } +}; + +export const handler = async ( + event: { customerId: string }, + _context: unknown +): Promise => { + await processTransaction(event.customerId); + + // .. other business logic + + logger.info('other business logic processed'); +}; diff --git a/examples/snippets/logger/appendKeys.ts b/examples/snippets/logger/appendKeys.ts deleted file mode 100644 index e99fc20cb2..0000000000 --- a/examples/snippets/logger/appendKeys.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Logger } from '@aws-lambda-powertools/logger'; - -// Add persistent log keys via the constructor -const logger = new Logger({ - persistentLogAttributes: { - aws_account_id: '123456789012', - aws_region: 'eu-west-1', - logger: { - name: '@aws-lambda-powertools/logger', - version: '0.0.1', - }, - extra_key: 'some-value', - }, -}); - -export const handler = async ( - _event: unknown, - _context: unknown -): Promise => { - // If you don't want to log the "extra_key" attribute in your logs, you can remove it - logger.removeKeys(['extra_key']); - - // This info log will print all extra custom attributes added above - // Extra attributes: logger object with name and version of the logger library, awsAccountId, awsRegion - logger.info('This is an INFO log'); - logger.info('This is another INFO log'); - - return { - foo: 'bar', - }; -}; diff --git a/examples/snippets/logger/clearStateDecorator.ts b/examples/snippets/logger/clearStateDecorator.ts deleted file mode 100644 index 0f4ec2b81f..0000000000 --- a/examples/snippets/logger/clearStateDecorator.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Logger } from '@aws-lambda-powertools/logger'; -import type { LambdaInterface } from '@aws-lambda-powertools/commons/types'; - -// Persistent attributes added outside the handler will be -// cached across invocations -const logger = new Logger({ - logLevel: 'DEBUG', - persistentLogAttributes: { - foo: 'bar', - biz: 'baz', - }, -}); - -class Lambda implements LambdaInterface { - // Enable the clear state flag - @logger.injectLambdaContext({ clearState: true }) - public async handler( - event: { specialKey: string }, - _context: unknown - ): Promise { - // Persistent attributes added inside the handler will NOT be cached - // across invocations - if (event['specialKey'] === '123456') { - logger.appendKeys({ - details: { specialKey: '123456' }, - }); - } - logger.debug('This is a DEBUG log'); - } -} - -const myFunction = new Lambda(); -export const handler = myFunction.handler.bind(myFunction); // (1) diff --git a/examples/snippets/logger/clearStateMiddy.ts b/examples/snippets/logger/clearStateMiddy.ts deleted file mode 100644 index 1c18e550a0..0000000000 --- a/examples/snippets/logger/clearStateMiddy.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Logger } from '@aws-lambda-powertools/logger'; -import { injectLambdaContext } from '@aws-lambda-powertools/logger/middleware'; -import middy from '@middy/core'; - -// Persistent attributes added outside the handler will be -// cached across invocations -const logger = new Logger({ - logLevel: 'DEBUG', - persistentLogAttributes: { - foo: 'bar', - biz: 'baz', - }, -}); - -const lambdaHandler = async ( - event: { specialKey: string }, - _context: unknown -): Promise => { - // Persistent attributes added inside the handler will NOT be cached - // across invocations - if (event['special_key'] === '123456') { - logger.appendKeys({ - details: { special_key: event['specialKey'] }, - }); - } - logger.debug('This is a DEBUG log'); -}; - -// Enable the clear state flag -export const handler = middy(lambdaHandler).use( - injectLambdaContext(logger, { clearState: true }) -); diff --git a/examples/snippets/logger/persistentKeys.ts b/examples/snippets/logger/persistentKeys.ts new file mode 100644 index 0000000000..9aedfe4dcd --- /dev/null +++ b/examples/snippets/logger/persistentKeys.ts @@ -0,0 +1,22 @@ +import { Logger } from '@aws-lambda-powertools/logger'; + +const logger = new Logger({ + serviceName: 'serverlessAirline', +}); + +declare const getRemoteConfig: (env: string) => { + environment: string; + version: string; +}; +const { environment, version } = getRemoteConfig('prod'); + +logger.appendPersistentKeys({ environment, version }); + +export const handler = async ( + _event: unknown, + _context: unknown +): Promise => { + logger.info('processing transaction'); + + // .. your business logic +}; diff --git a/examples/snippets/logger/persistentKeysConstructor.ts b/examples/snippets/logger/persistentKeysConstructor.ts new file mode 100644 index 0000000000..dc6d509bc3 --- /dev/null +++ b/examples/snippets/logger/persistentKeysConstructor.ts @@ -0,0 +1,18 @@ +import { Logger } from '@aws-lambda-powertools/logger'; + +const logger = new Logger({ + serviceName: 'serverlessAirline', + persistentKeys: { + environment: 'prod', + version: process.env.BUILD_VERSION, + }, +}); + +export const handler = async ( + _event: unknown, + _context: unknown +): Promise => { + logger.info('processing transaction'); + + // ... your business logic +}; diff --git a/examples/snippets/logger/removeKeys.ts b/examples/snippets/logger/removeKeys.ts new file mode 100644 index 0000000000..122181e5d0 --- /dev/null +++ b/examples/snippets/logger/removeKeys.ts @@ -0,0 +1,30 @@ +import { Logger } from '@aws-lambda-powertools/logger'; + +const logger = new Logger({ + serviceName: 'serverlessAirline', +}); + +const processTransaction = async (customerId: string): Promise => { + try { + logger.appendKeys({ + customerId, + }); + + // ... your business logic + + logger.info('transaction processed'); + } finally { + logger.removeKeys(['customerId']); + } +}; + +export const handler = async ( + event: { customerId: string }, + _context: unknown +): Promise => { + await processTransaction(event.customerId); + + // .. other business logic + + logger.info('other business logic processed'); +}; diff --git a/examples/snippets/logger/removePersistentKeys.ts b/examples/snippets/logger/removePersistentKeys.ts new file mode 100644 index 0000000000..f6cdb52051 --- /dev/null +++ b/examples/snippets/logger/removePersistentKeys.ts @@ -0,0 +1,24 @@ +import { Logger } from '@aws-lambda-powertools/logger'; + +const logger = new Logger({ + serviceName: 'serverlessAirline', + persistentKeys: { + foo: true, + }, +}); + +declare const getRemoteConfig: (env: string) => { + isFoo: boolean; +}; + +export const handler = async ( + _event: unknown, + _context: unknown +): Promise => { + const { isFoo } = getRemoteConfig('prod'); + if (isFoo) logger.removePersistentKeys(['foo']); + + logger.info('processing transaction'); + + // ... your business logic +}; diff --git a/examples/snippets/logger/resetKeys.ts b/examples/snippets/logger/resetKeys.ts new file mode 100644 index 0000000000..2c4c4fd09d --- /dev/null +++ b/examples/snippets/logger/resetKeys.ts @@ -0,0 +1,27 @@ +import { Logger } from '@aws-lambda-powertools/logger'; + +// Persistent attributes will be cached across invocations +const logger = new Logger({ + logLevel: 'info', + persistentKeys: { + environment: 'prod', + }, +}); + +// Enable the clear state flag +export const handler = async ( + event: { userId: string }, + _context: unknown +): Promise => { + try { + // This temporary key will be included in the log & cleared after the invocation + logger.appendKeys({ + details: { userId: event.userId }, + }); + + // ... your business logic + } finally { + logger.info('WIDE'); + logger.resetKeys(); + } +}; diff --git a/examples/snippets/logger/resetKeysDecorator.ts b/examples/snippets/logger/resetKeysDecorator.ts new file mode 100644 index 0000000000..4c4f702a94 --- /dev/null +++ b/examples/snippets/logger/resetKeysDecorator.ts @@ -0,0 +1,30 @@ +import { Logger } from '@aws-lambda-powertools/logger'; +import type { LambdaInterface } from '@aws-lambda-powertools/commons/types'; + +// Persistent attributes will be cached across invocations +const logger = new Logger({ + logLevel: 'info', + persistentKeys: { + environment: 'prod', + }, +}); + +class Lambda implements LambdaInterface { + @logger.injectLambdaContext({ resetKeys: true }) + public async handler( + event: { userId: string }, + _context: unknown + ): Promise { + // This temporary key will be included in the log & cleared after the invocation + logger.appendKeys({ + details: { userId: event.userId }, + }); + + // ... your business logic + + logger.info('WIDE'); + } +} + +const myFunction = new Lambda(); +export const handler = myFunction.handler.bind(myFunction); // (1)! diff --git a/examples/snippets/logger/resetKeysMiddy.ts b/examples/snippets/logger/resetKeysMiddy.ts new file mode 100644 index 0000000000..0601c47dca --- /dev/null +++ b/examples/snippets/logger/resetKeysMiddy.ts @@ -0,0 +1,24 @@ +import { Logger } from '@aws-lambda-powertools/logger'; +import { injectLambdaContext } from '@aws-lambda-powertools/logger/middleware'; +import middy from '@middy/core'; + +// Persistent attributes will be cached across invocations +const logger = new Logger({ + logLevel: 'info', + persistentKeys: { + environment: 'prod', + }, +}); + +export const handler = middy( + async (event: { userId: string }, _context: unknown): Promise => { + // This temporary key will be included in the log & cleared after the invocation + logger.appendKeys({ + details: { userId: event.userId }, + }); + + // ... your business logic + + logger.info('WIDE'); + } +).use(injectLambdaContext(logger, { resetKeys: true })); diff --git a/packages/logger/src/Logger.ts b/packages/logger/src/Logger.ts index 29a0c20fb4..d91b9ce39f 100644 --- a/packages/logger/src/Logger.ts +++ b/packages/logger/src/Logger.ts @@ -460,7 +460,7 @@ class Logger extends Utility implements LoggerInterface { } catch (error) { throw error; } finally { - if (options?.clearState) loggerRef.resetState(); + if (options?.clearState || options?.resetKeys) loggerRef.resetKeys(); } return result; @@ -469,7 +469,7 @@ class Logger extends Utility implements LoggerInterface { } /** - * @deprecated This method is deprecated and will be removed in the future major versions. Use {@link resetState()} instead. + * @deprecated This method is deprecated and will be removed in the future major versions. Use {@link resetKeys()} instead. */ /* istanbul ignore next */ public static injectLambdaContextAfterOrOnError( @@ -477,8 +477,8 @@ class Logger extends Utility implements LoggerInterface { _persistentAttributes: LogAttributes, options?: InjectLambdaContextOptions ): void { - if (options && options.clearState === true) { - logger.resetState(); + if (options && (options.clearState || options?.resetKeys)) { + logger.resetKeys(); } } @@ -539,12 +539,24 @@ class Logger extends Utility implements LoggerInterface { } /** - * It removes persistent attributes based on provided keys to all log items generated by this Logger instance. + * Remove the given keys from the persistent keys. * - * @param {string[]} keys - * @returns {void} + * @example + * ```typescript + * import { Logger } from '@aws-lambda-powertools/logger'; + * + * const logger = new Logger({ + * persistentKeys: { + * environment: 'prod', + * }, + * }); + * + * logger.removePersistentKeys(['environment']); + * ``` + * + * @param keys - The keys to remove from the persistent attributes. */ - public removePersistentLogAttributes(keys: string[]): void { + public removePersistentKeys(keys: string[]): void { for (const key of keys) { this.persistentLogAttributes[key] = undefined; @@ -557,9 +569,19 @@ class Logger extends Utility implements LoggerInterface { } /** - * It resets the state, by removing all temporary log attributes added with `appendKeys()` method. + * @deprecated This method is deprecated and will be removed in the future major versions. Use {@link removePersistentKeys()} instead. + * + * @param {string[]} keys + * @returns {void} + */ + public removePersistentLogAttributes(keys: string[]): void { + this.removePersistentKeys(keys); + } + + /** + * It removes all temporary log attributes added with `appendKeys()` method. */ - public resetState(): void { + public resetKeys(): void { for (const key of Object.keys(this.temporaryLogAttributes)) { if (this.persistentLogAttributes[key]) { this.#keys.set(key, 'persistent'); diff --git a/packages/logger/src/middleware/middy.ts b/packages/logger/src/middleware/middy.ts index 5b3a33dba2..2481060145 100644 --- a/packages/logger/src/middleware/middy.ts +++ b/packages/logger/src/middleware/middy.ts @@ -36,7 +36,8 @@ const injectLambdaContext = ( options?: InjectLambdaContextOptions ): MiddlewareLikeObj => { const loggers = target instanceof Array ? target : [target]; - const isClearState = options && options.clearState === true; + const isResetStateEnabled = + options && (options.clearState || options.resetKeys); /** * Set the cleanup function to be called in case other middlewares return early. @@ -54,7 +55,7 @@ const injectLambdaContext = ( request: MiddyLikeRequest ): Promise => { loggers.forEach((logger: Logger) => { - if (isClearState) { + if (isResetStateEnabled) { setCleanupFunction(request); } Logger.injectLambdaContextBefore( @@ -67,9 +68,9 @@ const injectLambdaContext = ( }; const injectLambdaContextAfterOrOnError = async (): Promise => { - if (isClearState) { + if (isResetStateEnabled) { loggers.forEach((logger: Logger) => { - logger.resetState(); + logger.resetKeys(); }); } }; diff --git a/packages/logger/src/types/Logger.ts b/packages/logger/src/types/Logger.ts index 258c468897..e662669fe3 100644 --- a/packages/logger/src/types/Logger.ts +++ b/packages/logger/src/types/Logger.ts @@ -18,7 +18,14 @@ type LogFunction = { type InjectLambdaContextOptions = { logEvent?: boolean; + /** + * @deprecated Use `resetKeys` instead. + */ clearState?: boolean; + /** + * If `true`, the logger will reset the keys added via {@link `appendKeys()`} + */ + resetKeys?: boolean; }; type BaseConstructorOptions = { @@ -31,12 +38,24 @@ type BaseConstructorOptions = { }; type PersistentKeysOption = { + /** + * Keys that will be added in all log items. + */ persistentKeys?: LogAttributes; + /** + * @deprecated Use `persistentKeys` instead. + */ persistentLogAttributes?: never; }; type DeprecatedOption = { + /** + * @deprecated Use `persistentKeys` instead. + */ persistentLogAttributes?: LogAttributes; + /** + * Keys that will be added in all log items. + */ persistentKeys?: never; }; @@ -50,8 +69,7 @@ type DeprecatedOption = { * @property {LogFormatterInterface} [logFormatter] - The custom log formatter. * @property {ConfigServiceInterface} [customConfigService] - The custom config service. * @property {Environment} [environment] - The environment. - * @property {LogAttributes} [persistentKeys] - The keys that will be persisted in all log items. - * @property {LogAttributes} [persistentLogAttributes] - **Deprecated!** Use `persistentKeys`. + * @property {LogAttributes} [persistentKeys] - Keys that will be added in all log items. */ type ConstructorOptions = BaseConstructorOptions & (PersistentKeysOption | DeprecatedOption); diff --git a/packages/logger/tests/unit/Logger.test.ts b/packages/logger/tests/unit/Logger.test.ts index 72dc761056..dd275a9be3 100644 --- a/packages/logger/tests/unit/Logger.test.ts +++ b/packages/logger/tests/unit/Logger.test.ts @@ -1665,7 +1665,7 @@ describe('Class: Logger', () => { }); }); - describe('Method: resetState', () => { + describe('Method: resetKeys', () => { test('when called, it removes all keys added with appendKeys() method', () => { // Prepare const logger = new Logger(); @@ -1679,7 +1679,7 @@ describe('Class: Logger', () => { }); // Act - logger.resetState(); + logger.resetKeys(); // Assess expect(logger).toEqual( @@ -1705,7 +1705,7 @@ describe('Class: Logger', () => { logger.appendKeys({ foo: 'bar' }); // Act - logger.resetState(); + logger.resetKeys(); // Assess expect(logger).toEqual( @@ -1736,7 +1736,7 @@ describe('Class: Logger', () => { }); // Act - logger.resetState(); + logger.resetKeys(); logger.info('foo'); // Assess @@ -2401,7 +2401,7 @@ describe('Class: Logger', () => { const logger = new Logger({ logLevel: 'DEBUG', }); - const resetStateSpy = jest.spyOn(logger, 'resetState'); + const resetKeysSpy = jest.spyOn(logger, 'resetKeys'); const consoleSpy = jest.spyOn(logger['console'], 'info'); class LambdaFunction implements LambdaInterface { @logger.injectLambdaContext({ clearState: true }) @@ -2431,7 +2431,7 @@ describe('Class: Logger', () => { // be called ONLY after the handler has returned. If logger.info is called after the cleanup function // it means the decorator is NOT awaiting the handler which would cause the test to fail. expect(consoleSpy.mock.invocationCallOrder[0]).toBeLessThan( - resetStateSpy.mock.invocationCallOrder[0] + resetKeysSpy.mock.invocationCallOrder[0] ); });