Skip to content

Commit fa1dacb

Browse files
authored
feat(logger): add clear state functionality (#902)
* feat: add business logic for clear state * chore: removed temporary code * feat: business logic + unit tests for decorator and middleware * chore: format TS * chore: typo in logger docs * chore: lint fix quotes * chore: typo in logger docs * tests(logger): rename test scenario for clear state * chore: exclude non-null rule in decorator * build(deps): revert package-lock.json * test(logger): clear state e2e tests
1 parent c6622ad commit fa1dacb

File tree

12 files changed

+1542
-1248
lines changed

12 files changed

+1542
-1248
lines changed

Diff for: docs/core/logger.md

+120
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,125 @@ To remove the keys you added, you can use the `removeKeys` method.
282282

283283
!!! tip "Logger will automatically ignore any key with an `undefined` value"
284284

285+
#### Clearing all state
286+
287+
The Logger utility is commonly initialized in the global scope, outside the handler function.
288+
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.
289+
290+
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.
291+
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.
292+
293+
=== "Middy Middleware"
294+
295+
```typescript hl_lines="27"
296+
import { Logger, injectLambdaContext } from '@aws-lambda-powertools/logger';
297+
import middy from '@middy/core';
298+
299+
// Persistent attributes added outside the handler will be
300+
// cached across invocations
301+
const logger = new Logger({
302+
logLevel: 'DEBUG',
303+
persistentLogAttributes: {
304+
foo: "bar",
305+
biz: "baz"
306+
}
307+
});
308+
309+
const lambdaHandler = async (event: { special_key: string }, _context: any): Promise<void> => {
310+
// Persistent attributes added inside the handler will NOT be cached
311+
// across invocations
312+
if (event['special_key'] === '123456') {
313+
logger.appendKeys({
314+
details: { special_key: event['special_key'] }
315+
});
316+
}
317+
logger.debug('This is a DEBUG log');
318+
};
319+
320+
// Enable the clear state flag
321+
export const handler = middy(lambdaHandler)
322+
.use(injectLambdaContext(logger, { clearState: true }));
323+
```
324+
325+
=== "Decorator"
326+
327+
```typescript hl_lines="16"
328+
import { Logger } from '@aws-lambda-powertools/logger';
329+
import { LambdaInterface } from '@aws-lambda-powertools/commons';
330+
331+
// Persistent attributes added outside the handler will be
332+
// cached across invocations
333+
const logger = new Logger({
334+
logLevel: 'DEBUG',
335+
persistentLogAttributes: {
336+
foo: "bar",
337+
biz: "baz"
338+
}
339+
});
340+
341+
class Lambda implements LambdaInterface {
342+
// Enable the clear state flag
343+
@logger.injectLambdaContext({ clearState: true })
344+
public async handler(_event: any, _context: any): Promise<void> {
345+
// Persistent attributes added inside the handler will NOT be cached
346+
// across invocations
347+
if (event['special_key'] === '123456'){
348+
logger.appendKeys({
349+
details: { special_key: '123456' }
350+
});
351+
}
352+
logger.debug('This is a DEBUG log');
353+
}
354+
355+
}
356+
357+
export const myFunction = new Lambda();
358+
export const handler = myFunction.handler;
359+
```
360+
361+
In each case, the printed log will look like this:
362+
363+
=== "First invocation"
364+
365+
```json hl_lines="2 4-7"
366+
{
367+
"biz": "baz",
368+
"cold_start": true,
369+
"details": {
370+
"special_key": "123456",
371+
},
372+
"foo": "bar",
373+
"function_arn": "arn:aws:lambda:eu-west-1:123456789012:function:foo-bar-function",
374+
"function_memory_size": 128,
375+
"function_name": "foo-bar-function",
376+
"function_request_id": "abcdef123456abcdef123456",
377+
"level": "DEBUG",
378+
"message": "This is a DEBUG log with the user_id",
379+
"service": "hello-world",
380+
"timestamp": "2021-12-12T22:32:54.670Z",
381+
"xray_trace_id": "1-5759e988-bd862e3fe1be46a994272793"
382+
}
383+
```
384+
=== "Second invocation"
385+
386+
```json hl_lines="2 4"
387+
{
388+
"biz": "baz",
389+
"cold_start": false,
390+
"foo": "bar",
391+
"function_arn": "arn:aws:lambda:eu-west-1:123456789012:function:foo-bar-function",
392+
"function_memory_size": 128,
393+
"function_name": "foo-bar-function",
394+
"function_request_id": "abcdef123456abcdef123456",
395+
"level": "DEBUG",
396+
"message": "This is a DEBUG log with the user_id",
397+
"service": "hello-world",
398+
"timestamp": "2021-12-12T22:40:23.120Z",
399+
"xray_trace_id": "1-5759e988-bd862e3fe1be46a994272793"
400+
}
401+
```
402+
403+
285404
### Appending additional data to a single log item
286405

287406
You can append additional data to a single log item by passing objects as additional parameters.
@@ -440,6 +559,7 @@ The error will be logged with default key name `error`, but you can also pass yo
440559
!!! tip "Logging errors and log level"
441560
You can also log errors using the `warn`, `info`, and `debug` methods. Be aware of the log level though, you might miss those errors when analyzing the log later depending on the log level configuration.
442561

562+
443563
## Advanced
444564

445565
### Using multiple Logger instances across your code

0 commit comments

Comments
 (0)