Skip to content

Commit 8aab299

Browse files
author
Dmitry Balabanov
authored
fix(logger): fix handling of additional log keys (#614)
* fix(logger): fix handling of additional log keys * fix(logger): add unit tests * chore(examples): extend logger example * docs: update docs about logging additional keys
1 parent cadbcb2 commit 8aab299

File tree

7 files changed

+63
-15
lines changed

7 files changed

+63
-15
lines changed

Diff for: docs/core/logger.md

+36-4
Original file line numberDiff line numberDiff line change
@@ -276,10 +276,12 @@ You can append additional persistent keys and values in the logs generated durin
276276
### Appending additional log keys and values to a single log item
277277

278278
You can append additional keys and values in a single log item passing them as parameters.
279+
Pass a string for logging it with default key name `extra`. Alternatively, pass one or multiple objects with custom keys.
280+
If you already have an object containing a `message` key and an additional property, you can pass this object directly.
279281

280282
=== "handler.ts"
281283

282-
```typescript hl_lines="14 18-19"
284+
```typescript hl_lines="14 18-19 23 31"
283285
import { Logger } from '@aws-lambda-powertools/logger';
284286

285287
const logger = new Logger();
@@ -300,6 +302,17 @@ You can append additional keys and values in a single log item passing them as p
300302
{ data: myImportantVariable },
301303
{ correlationIds: { myCustomCorrelationId: 'foo-bar-baz' } }
302304
);
305+
306+
// Simply pass a string for logging additional data
307+
logger.info('This is a log with additional string value', 'string value');
308+
309+
// Directly passing an object containing both the message and the additional info
310+
const logObject = {
311+
message: 'This is a log message',
312+
additionalValue: 42
313+
};
314+
315+
logger.info(logObject);
303316
304317
return {
305318
foo: 'bar'
@@ -309,7 +322,7 @@ You can append additional keys and values in a single log item passing them as p
309322
```
310323
=== "Example CloudWatch Logs excerpt"
311324

312-
```json hl_lines="7 15-16"
325+
```json hl_lines="7 15-16 24 32"
313326
{
314327
"level": "INFO",
315328
"message": "This is a log with an extra variable",
@@ -327,6 +340,22 @@ You can append additional keys and values in a single log item passing them as p
327340
"data": { "foo": "bar" },
328341
"correlationIds": { "myCustomCorrelationId": "foo-bar-baz" }
329342
}
343+
{
344+
"level": "INFO",
345+
"message": "This is a log with additional string value",
346+
"service": "serverlessAirline",
347+
"timestamp": "2021-12-12T22:06:17.463Z",
348+
"xray_trace_id": "abcdef123456abcdef123456abcdef123456",
349+
"extra": "string value"
350+
}
351+
{
352+
"level": "INFO",
353+
"message": "This is a log message",
354+
"service": "serverlessAirline",
355+
"timestamp": "2021-12-12T22:06:17.463Z",
356+
"xray_trace_id": "abcdef123456abcdef123456abcdef123456",
357+
"additionalValue": 42
358+
}
330359
```
331360

332361
### Logging errors
@@ -347,14 +376,14 @@ The error will be logged with default key name `error`, but you can also pass yo
347376
throw new Error('Unexpected error #1');
348377
} catch (error) {
349378
// Log information about the error using the default "error" key
350-
logger.error('This is the first error', error);
379+
logger.error('This is the first error', error as Error);
351380
}
352381

353382
try {
354383
throw new Error('Unexpected error #2');
355384
} catch (error) {
356385
// Log information about the error using a custom "myCustomErrorKey" key
357-
logger.error('This is the second error', { myCustomErrorKey: error } );
386+
logger.error('This is the second error', { myCustomErrorKey: error as Error } );
358387
}
359388

360389
};
@@ -391,6 +420,9 @@ The error will be logged with default key name `error`, but you can also pass yo
391420
}
392421
```
393422

423+
!!! tip "Logging errors and log level"
424+
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.
425+
394426
## Advanced
395427

396428
### Using multiple Logger instances across your code

Diff for: packages/logger/examples/additional-keys.ts

+3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ const lambdaHandler: Handler = async () => {
2020
// Pass an error that occurred
2121
logger.error('This is an ERROR log', new Error('Something bad happened!'));
2222

23+
// Pass a simple string as additional data
24+
logger.info('This is an INFO log', 'Extra log data');
25+
2326
return {
2427
foo: 'bar'
2528
};

Diff for: packages/logger/examples/errors.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@ const lambdaHandler: Handler = async () => {
1717
try {
1818
throw new Error('Unexpected error #1');
1919
} catch (error) {
20-
logger.error('This is an ERROR log #1', error);
20+
logger.error('This is an ERROR log #1', error as Error);
2121
}
2222

2323
try {
2424
throw new Error('Unexpected error #2');
2525
} catch (error) {
26-
logger.error('This is an ERROR log #2', { myCustomErrorKey: error } );
26+
logger.error('This is an ERROR log #2', { myCustomErrorKey: error as Error } );
2727
}
2828

2929
return {

Diff for: packages/logger/src/Logger.ts

+11-7
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ class Logger extends Utility implements ClassThatLogs {
200200
* It prints a log item with level DEBUG.
201201
*
202202
* @param {LogItemMessage} input
203-
* @param {Error | LogAttributes | unknown} extraInput
203+
* @param {Error | LogAttributes | string} extraInput
204204
* @returns {void}
205205
*/
206206
public debug(input: LogItemMessage, ...extraInput: LogItemExtraInput): void {
@@ -211,7 +211,7 @@ class Logger extends Utility implements ClassThatLogs {
211211
* It prints a log item with level ERROR.
212212
*
213213
* @param {LogItemMessage} input
214-
* @param {Error | LogAttributes | unknown} extraInput
214+
* @param {Error | LogAttributes | string} extraInput
215215
* @returns {void}
216216
*/
217217
public error(input: LogItemMessage, ...extraInput: LogItemExtraInput): void {
@@ -231,7 +231,7 @@ class Logger extends Utility implements ClassThatLogs {
231231
* It prints a log item with level INFO.
232232
*
233233
* @param {LogItemMessage} input
234-
* @param {Error | LogAttributes | unknown} extraInput
234+
* @param {Error | LogAttributes | string} extraInput
235235
* @returns {void}
236236
*/
237237
public info(input: LogItemMessage, ...extraInput: LogItemExtraInput): void {
@@ -288,7 +288,7 @@ class Logger extends Utility implements ClassThatLogs {
288288
* It prints a log item with level WARN.
289289
*
290290
* @param {LogItemMessage} input
291-
* @param {Error | LogAttributes | unknown} extraInput
291+
* @param {Error | LogAttributes | string} extraInput
292292
* @returns {void}
293293
*/
294294
public warn(input: LogItemMessage, ...extraInput: LogItemExtraInput): void {
@@ -336,9 +336,13 @@ class Logger extends Utility implements ClassThatLogs {
336336
if (typeof input !== 'string') {
337337
logItem.addAttributes(input);
338338
}
339-
extraInput.forEach((item: Error | LogAttributes | unknown) => {
340-
const attributes = item instanceof Error ? { error: item } : item;
341-
logItem.addAttributes(<LogAttributes>attributes);
339+
extraInput.forEach((item: Error | LogAttributes | string) => {
340+
const attributes: LogAttributes =
341+
item instanceof Error ? { error: item } :
342+
typeof item === 'string' ? { extra: item } :
343+
item;
344+
345+
logItem.addAttributes(attributes);
342346
});
343347

344348
return logItem;

Diff for: packages/logger/src/types/Logger.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ type UnformattedAttributes = {
5050
};
5151

5252
type LogItemMessage = string | LogAttributesWithMessage;
53-
type LogItemExtraInput = Array<Error | LogAttributes | unknown>;
53+
type LogItemExtraInput = [Error | string] | LogAttributes[];
5454

5555
type HandlerMethodDecorator = (
5656
target: LambdaInterface,

Diff for: packages/logger/tests/e2e/basicFeatures.middy.test.FunctionCode.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ const testFunction = async (event: APIGatewayProxyEvent, context: Context): Prom
3030
try {
3131
throw new Error(ERROR_MSG);
3232
} catch (e) {
33-
logger.error(ERROR_MSG, e);
33+
logger.error(ERROR_MSG, e as Error);
3434
}
3535

3636
return {

Diff for: packages/logger/tests/unit/Logger.test.ts

+9
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@ describe('Class: Logger', () => {
288288
logger[methodOfLogger]( { message: 'A log item with an object as first parameters', extra: 'parameter' });
289289
logger[methodOfLogger]('A log item with a string as first parameter, and an error as second parameter', new Error('Something happened!') );
290290
logger[methodOfLogger]('A log item with a string as first parameter, and an error with custom key as second parameter', { myCustomErrorKey: new Error('Something happened!') });
291+
logger[methodOfLogger]('A log item with a string as first parameter, and a string as second parameter', 'parameter');
291292
}
292293

293294
// Assess
@@ -351,6 +352,14 @@ describe('Class: Logger', () => {
351352
stack: expect.stringMatching(/Logger.test.ts:[0-9]+:[0-9]+/),
352353
},
353354
}));
355+
expect(console[methodOfConsole]).toHaveBeenNthCalledWith(7, JSON.stringify({
356+
level: method.toUpperCase(),
357+
message: 'A log item with a string as first parameter, and a string as second parameter',
358+
service: 'hello-world',
359+
timestamp: '2016-06-20T12:08:10.000Z',
360+
xray_trace_id: 'abcdef123456abcdef123456abcdef123456',
361+
extra: 'parameter',
362+
}));
354363
});
355364
});
356365

0 commit comments

Comments
 (0)