Skip to content

Commit d1284bf

Browse files
authored
docs(logger): rework working with keys doc sections (#2696)
1 parent f1cdb15 commit d1284bf

16 files changed

+420
-220
lines changed

Diff for: docs/core/logger.md

+152-102
Original file line numberDiff line numberDiff line change
@@ -181,93 +181,199 @@ When debugging in non-production environments, you can instruct Logger to log th
181181

182182
Use `POWERTOOLS_LOGGER_LOG_EVENT` environment variable to enable or disable (`true`/`false`) this feature.
183183

184-
### Appending persistent additional log keys and values
184+
### Appending additional keys
185185

186-
You can append additional persistent keys and values in the logs generated during a Lambda invocation using either mechanism:
186+
You can append additional keys using either machanism:
187187

188-
* Via the Logger's `appendKeys` method, for all log items generated after calling this method
189-
* Passing them in the Logger's constructor
188+
* Add **extra keys** to a single log message by passing them to the log method directly
189+
* Append **temporary keys** to all future log messages via the `appendKeys()` method until `resetKeys()` is called
190+
* Set **Persistent keys** for the logger instance via the `persistentKeys` constructor option or the `appendPersistentKeys()` method
190191

191-
To remove the keys you added, you can use the `removeKeys` method.
192+
#### Extra keys
193+
194+
You can append additional data to a single log item by passing objects as additional parameters.
195+
196+
* Pass a simple string for logging it with default key name `extra`
197+
* 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 }`
198+
* If you already have an object containing a `message` key and an additional property, you can pass this object directly
192199

193200
=== "handler.ts"
194201

195-
```typescript hl_lines="5-13 17-25 32"
196-
--8<-- "examples/snippets/logger/appendKeys.ts"
202+
```typescript hl_lines="16-18 23-25 37"
203+
--8<-- "examples/snippets/logger/extraData.ts"
197204
```
198205
=== "Example CloudWatch Logs excerpt"
199206

200-
```json hl_lines="7-12 20-25"
207+
```json hl_lines="7 15-21 29 37"
201208
{
202209
"level": "INFO",
203-
"message": "This is an INFO log",
210+
"message": "This is a log with an extra variable",
204211
"service": "serverlessAirline",
205-
"timestamp": "2021-12-12T21:49:58.084Z",
212+
"timestamp": "2021-12-12T22:06:17.463Z",
206213
"xray_trace_id": "abcdef123456abcdef123456abcdef123456",
207-
"aws_account_id": "123456789012",
208-
"aws_region": "eu-west-1",
209-
"logger": {
210-
"name": "@aws-lambda-powertools/logger",
211-
"version": "0.0.1"
214+
"data": { "foo": "bar" }
215+
}
216+
{
217+
"level": "INFO",
218+
"message": "This is a log with 3 extra objects",
219+
"service": "serverlessAirline",
220+
"timestamp": "2021-12-12T22:06:17.466Z",
221+
"xray_trace_id": "abcdef123456abcdef123456abcdef123456",
222+
"data": { "foo": "bar" },
223+
"correlationIds": { "myCustomCorrelationId": "foo-bar-baz" },
224+
"lambdaEvent": {
225+
"exampleEventData": {
226+
"eventValue": 42
227+
}
212228
}
213229
}
214230
{
215231
"level": "INFO",
216-
"message": "This is another INFO log",
232+
"message": "This is a log with additional string value",
233+
"service": "serverlessAirline",
234+
"timestamp": "2021-12-12T22:06:17.463Z",
235+
"xray_trace_id": "abcdef123456abcdef123456abcdef123456",
236+
"extra": "string value"
237+
}
238+
{
239+
"level": "INFO",
240+
"message": "This is a log message",
241+
"service": "serverlessAirline",
242+
"timestamp": "2021-12-12T22:06:17.463Z",
243+
"xray_trace_id": "abcdef123456abcdef123456abcdef123456",
244+
"additionalValue": 42
245+
}
246+
```
247+
248+
#### Temporary keys
249+
250+
You can append additional keys to all future log messages by using the `appendKeys()` method.
251+
252+
???+ tip "When is this useful?"
253+
This is helpful to contextualize log messages emitted during a specific function.
254+
255+
=== "handler.ts"
256+
257+
```typescript hl_lines="9-11"
258+
--8<-- "examples/snippets/logger/appendAndRemoveKeys.ts"
259+
```
260+
261+
1. You can also remove specific keys by calling the `removeKeys()` method.
262+
263+
=== "Example CloudWatch Logs excerpt"
264+
265+
```json hl_lines="7"
266+
{
267+
"level": "INFO",
268+
"message": "transaction processed",
269+
"service": "serverlessAirline",
270+
"timestamp": "2021-12-12T21:49:58.084Z",
271+
"xray_trace_id": "abcdef123456abcdef123456abcdef123456",
272+
"customerId": "123456789012"
273+
}
274+
{
275+
"level": "INFO",
276+
"message": "other business logic processed",
217277
"service": "serverlessAirline",
218278
"timestamp": "2021-12-12T21:49:58.088Z",
279+
"xray_trace_id": "abcdef123456abcdef123456abcdef123456"
280+
}
281+
```
282+
283+
#### Persistent keys
284+
285+
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).
286+
287+
A common use case is to set keys about your environment or application version, so that you can easily filter logs in CloudWatch Logs.
288+
289+
=== "As constructor options"
290+
291+
```typescript hl_lines="5-8"
292+
--8<-- "examples/snippets/logger/persistentKeysConstructor.ts"
293+
```
294+
295+
=== "Via dynamic method"
296+
297+
```typescript hl_lines="13"
298+
--8<-- "examples/snippets/logger/persistentKeys.ts"
299+
```
300+
301+
=== "Example CloudWatch Logs excerpt"
302+
303+
```json hl_lines="7-8"
304+
{
305+
"level": "INFO",
306+
"message": "processing transaction",
307+
"service": "serverlessAirline",
308+
"timestamp": "2021-12-12T21:49:58.084Z",
219309
"xray_trace_id": "abcdef123456abcdef123456abcdef123456",
220-
"aws_account_id": "123456789012",
221-
"aws_region": "eu-west-1",
222-
"logger": {
223-
"name": "@aws-lambda-powertools/logger",
224-
"version": "0.0.1"
225-
}
310+
"environment": "prod",
311+
"version": "1.2.0",
226312
}
227313
```
228314

229-
!!! tip "Logger will automatically ignore any key with an `undefined` value"
315+
### Removing additional keys
316+
317+
You can remove additional keys from the logger instance at any time:
318+
319+
* Remove temporary keys added via the `appendKeys()` method by using the `removeKeys()` method
320+
* Remove persistent keys added via the `persistentKeys` constructor option or the `appendPersistentKeys()` method by using the `removePersistentKeys()` method
321+
322+
=== "Remove temporary keys"
323+
324+
```typescript hl_lines="17"
325+
--8<-- "examples/snippets/logger/removeKeys.ts"
326+
```
327+
328+
=== "Remove persistent keys"
230329

231-
#### Clearing all state
330+
```typescript hl_lines="19"
331+
--8<-- "examples/snippets/logger/removePersistentKeys.ts"
332+
```
333+
334+
#### Resetting keys
335+
336+
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.
337+
338+
Resetting the state allows you to clear all the temporary keys you have added.
339+
340+
???+ tip "Tip: When is this useful?"
341+
This is useful when you add multiple custom keys conditionally or when you use canonical or wide logs.
232342

233-
The Logger utility is commonly initialized in the global scope, outside the handler function.
234-
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.
343+
=== "Clearing state manually"
235344

236-
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.
237-
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.
345+
```typescript hl_lines="25"
346+
--8<-- "examples/snippets/logger/resetKeys.ts"
347+
```
238348

239349
=== "Middy Middleware"
240350

241-
```typescript hl_lines="31"
242-
--8<-- "examples/snippets/logger/clearStateMiddy.ts"
351+
```typescript hl_lines="24"
352+
--8<-- "examples/snippets/logger/resetKeysMiddy.ts"
243353
```
244354

245355
=== "Decorator"
246356

247-
```typescript hl_lines="16"
248-
--8<-- "examples/snippets/logger/clearStateDecorator.ts"
357+
```typescript hl_lines="13"
358+
--8<-- "examples/snippets/logger/resetKeysDecorator.ts"
249359
```
250360

251361
1. Binding your handler method allows your handler to access `this` within the class methods.
252362

253-
In each case, the printed log will look like this:
254-
255363
=== "First invocation"
256364

257-
```json hl_lines="2 4-7"
365+
```json hl_lines="2 4"
258366
{
259-
"biz": "baz",
367+
"environment": "prod",
260368
"cold_start": true,
261-
"details": {
262-
"special_key": "123456",
263-
},
369+
"userId": "123456789012",
264370
"foo": "bar",
265371
"function_arn": "arn:aws:lambda:eu-west-1:123456789012:function:foo-bar-function",
266372
"function_memory_size": 128,
267373
"function_name": "foo-bar-function",
268374
"function_request_id": "abcdef123456abcdef123456",
269-
"level": "DEBUG",
270-
"message": "This is a DEBUG log with the user_id",
375+
"level": "INFO",
376+
"message": "WIDE",
271377
"service": "hello-world",
272378
"timestamp": "2021-12-12T22:32:54.670Z",
273379
"xray_trace_id": "1-5759e988-bd862e3fe1be46a994272793"
@@ -277,77 +383,21 @@ In each case, the printed log will look like this:
277383

278384
```json hl_lines="2 4"
279385
{
280-
"biz": "baz",
386+
"environment": "prod",
281387
"cold_start": false,
282-
"foo": "bar",
388+
"userId": "210987654321",
283389
"function_arn": "arn:aws:lambda:eu-west-1:123456789012:function:foo-bar-function",
284390
"function_memory_size": 128,
285391
"function_name": "foo-bar-function",
286392
"function_request_id": "abcdef123456abcdef123456",
287-
"level": "DEBUG",
288-
"message": "This is a DEBUG log with the user_id",
393+
"level": "INFO",
394+
"message": "WIDE",
289395
"service": "hello-world",
290396
"timestamp": "2021-12-12T22:40:23.120Z",
291397
"xray_trace_id": "1-5759e988-bd862e3fe1be46a994272793"
292398
}
293399
```
294400

295-
### Appending additional data to a single log item
296-
297-
You can append additional data to a single log item by passing objects as additional parameters.
298-
299-
* Pass a simple string for logging it with default key name `extra`
300-
* 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 }`
301-
* If you already have an object containing a `message` key and an additional property, you can pass this object directly
302-
303-
=== "handler.ts"
304-
305-
```typescript hl_lines="16-18 23-25 37"
306-
--8<-- "examples/snippets/logger/extraData.ts"
307-
```
308-
=== "Example CloudWatch Logs excerpt"
309-
310-
```json hl_lines="7 15-21 29 37"
311-
{
312-
"level": "INFO",
313-
"message": "This is a log with an extra variable",
314-
"service": "serverlessAirline",
315-
"timestamp": "2021-12-12T22:06:17.463Z",
316-
"xray_trace_id": "abcdef123456abcdef123456abcdef123456",
317-
"data": { "foo": "bar" }
318-
}
319-
{
320-
"level": "INFO",
321-
"message": "This is a log with 3 extra objects",
322-
"service": "serverlessAirline",
323-
"timestamp": "2021-12-12T22:06:17.466Z",
324-
"xray_trace_id": "abcdef123456abcdef123456abcdef123456",
325-
"data": { "foo": "bar" },
326-
"correlationIds": { "myCustomCorrelationId": "foo-bar-baz" },
327-
"lambdaEvent": {
328-
"exampleEventData": {
329-
"eventValue": 42
330-
}
331-
}
332-
}
333-
{
334-
"level": "INFO",
335-
"message": "This is a log with additional string value",
336-
"service": "serverlessAirline",
337-
"timestamp": "2021-12-12T22:06:17.463Z",
338-
"xray_trace_id": "abcdef123456abcdef123456abcdef123456",
339-
"extra": "string value"
340-
}
341-
{
342-
"level": "INFO",
343-
"message": "This is a log message",
344-
"service": "serverlessAirline",
345-
"timestamp": "2021-12-12T22:06:17.463Z",
346-
"xray_trace_id": "abcdef123456abcdef123456abcdef123456",
347-
"additionalValue": 42
348-
}
349-
```
350-
351401
### Logging errors
352402

353403
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
471521

472522
### Using multiple Logger instances across your code
473523

474-
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).
524+
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).
475525

476526
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.
477527

Diff for: examples/snippets/logger/appendAndRemoveKeys.ts

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { Logger } from '@aws-lambda-powertools/logger';
2+
3+
const logger = new Logger({
4+
serviceName: 'serverlessAirline',
5+
});
6+
7+
const processTransaction = async (customerId: string): Promise<void> => {
8+
try {
9+
logger.appendKeys({
10+
customerId,
11+
});
12+
13+
// ... your business logic
14+
15+
logger.info('transaction processed');
16+
} finally {
17+
logger.resetKeys(); // (1)!
18+
}
19+
};
20+
21+
export const handler = async (
22+
event: { customerId: string },
23+
_context: unknown
24+
): Promise<void> => {
25+
await processTransaction(event.customerId);
26+
27+
// .. other business logic
28+
29+
logger.info('other business logic processed');
30+
};

Diff for: examples/snippets/logger/appendKeys.ts

-31
This file was deleted.

0 commit comments

Comments
 (0)