Skip to content

Commit 2e3e867

Browse files
kawaaaassvozza
andauthored
feat(logger): add tenantId to logger default properties (#4931)
Co-authored-by: Stefano Vozza <[email protected]>
1 parent 5544ce0 commit 2e3e867

9 files changed

Lines changed: 86 additions & 8 deletions

File tree

packages/logger/src/Logger.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@ class Logger extends Utility implements LoggerInterface {
282282
memoryLimitInMB: context.memoryLimitInMB,
283283
functionName: context.functionName,
284284
functionVersion: context.functionVersion,
285+
tenantId: context.tenantId,
285286
},
286287
});
287288
}

packages/logger/src/formatter/PowertoolsLogFormatter.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ class PowertoolsLogFormatter extends LogFormatter {
5555
function_request_id: attributes.lambdaContext?.awsRequestId,
5656
sampling_rate: attributes.sampleRateValue,
5757
xray_trace_id: attributes.xRayTraceId,
58+
tenant_id: attributes.lambdaContext?.tenantId,
5859
};
5960

6061
// If logRecordOrder is not set, return the log item with the attributes in the order they were added

packages/logger/src/types/logKeys.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,12 @@ type PowertoolsLambdaContextKeys = {
140140
* @example "899856cb-83d1-40d7-8611-9e78f15f32f4"
141141
*/
142142
function_request_id: string;
143+
/**
144+
* The tenant ID from AWS Lambda Tenant Isolation feature.
145+
*
146+
* @example "cff02b3a-0e12-4be2-b3e0-758b49c4cd9b"
147+
*/
148+
tenant_id?: string;
143149
};
144150

145151
/**
@@ -159,6 +165,7 @@ type LambdaFunctionContext = Pick<
159165
| 'functionVersion'
160166
| 'invokedFunctionArn'
161167
| 'awsRequestId'
168+
| 'tenantId'
162169
> & {
163170
coldStart: boolean;
164171
};

packages/logger/tests/unit/formatters.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ const unformattedAttributes: UnformattedAttributes = {
5858
invokedFunctionArn:
5959
'arn:aws:lambda:eu-west-1:123456789012:function:Example',
6060
awsRequestId: 'abcdefg123456789',
61+
tenantId: 'cff02b3a-0e12-4be2-b3e0-758b49c4cd9b',
6162
},
6263
};
6364

@@ -155,6 +156,7 @@ describe('Formatters', () => {
155156
service: 'hello-world',
156157
timestamp: '2016-06-20T12:08:10.000Z',
157158
xray_trace_id: '1-5759e988-bd862e3fe1be46a994272793',
159+
tenant_id: undefined,
158160
});
159161
expect(value).toBeInstanceOf(LogItem);
160162
});
@@ -184,6 +186,7 @@ describe('Formatters', () => {
184186
service: 'hello-world',
185187
timestamp: '2016-06-20T12:08:10.000Z',
186188
xray_trace_id: '1-5759e988-bd862e3fe1be46a994272793',
189+
tenant_id: 'cff02b3a-0e12-4be2-b3e0-758b49c4cd9b',
187190
});
188191
});
189192

@@ -215,6 +218,7 @@ describe('Formatters', () => {
215218
function_request_id: 'abcdefg123456789',
216219
sampling_rate: 0.25,
217220
xray_trace_id: '1-5759e988-bd862e3fe1be46a994272793',
221+
tenant_id: 'cff02b3a-0e12-4be2-b3e0-758b49c4cd9b',
218222
});
219223
});
220224

@@ -256,6 +260,7 @@ describe('Formatters', () => {
256260
function_request_id: 'abcdefg123456789',
257261
sampling_rate: 0.25,
258262
xray_trace_id: '1-5759e988-bd862e3fe1be46a994272793',
263+
tenant_id: 'cff02b3a-0e12-4be2-b3e0-758b49c4cd9b',
259264
another_key: 'another_value',
260265
});
261266
});
@@ -297,6 +302,7 @@ describe('Formatters', () => {
297302
function_request_id: 'abcdefg123456789',
298303
sampling_rate: 0.25,
299304
xray_trace_id: '1-5759e988-bd862e3fe1be46a994272793',
305+
tenant_id: 'cff02b3a-0e12-4be2-b3e0-758b49c4cd9b',
300306
});
301307
});
302308

@@ -328,6 +334,7 @@ describe('Formatters', () => {
328334
function_request_id: 'abcdefg123456789',
329335
sampling_rate: 0.25,
330336
xray_trace_id: '1-5759e988-bd862e3fe1be46a994272793',
337+
tenant_id: 'cff02b3a-0e12-4be2-b3e0-758b49c4cd9b',
331338
additional_key: 'additional_value',
332339
});
333340
});

packages/logger/tests/unit/injectLambdaContext.test.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const getContextLogEntries = (overrides?: Record<string, unknown>) => ({
1616
function_memory_size: context.memoryLimitInMB,
1717
function_name: context.functionName,
1818
function_request_id: context.awsRequestId,
19+
tenant_id: context.tenantId,
1920
cold_start: true,
2021
...overrides,
2122
});
@@ -76,6 +77,39 @@ describe('Inject Lambda Context', () => {
7677
);
7778
});
7879

80+
it('does not include tenant_id when context does not have tenantId', () => {
81+
// Prepare
82+
const logger = new Logger();
83+
const contextWithoutTenantId = {
84+
...context,
85+
tenantId: undefined,
86+
};
87+
88+
// Act
89+
logger.addContext(contextWithoutTenantId);
90+
logger.info('Hello, world!');
91+
92+
// Assess
93+
expect(console.info).toHaveBeenCalledTimes(1);
94+
expect(console.info).toHaveLoggedNth(
95+
1,
96+
expect.objectContaining({
97+
message: 'Hello, world!',
98+
function_arn: context.invokedFunctionArn,
99+
function_memory_size: context.memoryLimitInMB,
100+
function_name: context.functionName,
101+
function_request_id: context.awsRequestId,
102+
cold_start: true,
103+
})
104+
);
105+
expect(console.info).not.toHaveLoggedNth(
106+
1,
107+
expect.objectContaining({
108+
tenant_id: expect.anything(),
109+
})
110+
);
111+
});
112+
79113
it('adds the context to log messages when the feature is enabled in the Middy.js middleware', async () => {
80114
// Prepare
81115
const logger = new Logger();
@@ -97,6 +131,30 @@ describe('Inject Lambda Context', () => {
97131
);
98132
});
99133

134+
it('does not include tenant_id when using Middy.js middleware without tenantId in context', async () => {
135+
// Prepare
136+
const logger = new Logger();
137+
const contextWithoutTenantId = {
138+
...context,
139+
tenantId: undefined,
140+
};
141+
const handler = middy(() => {
142+
logger.info('Hello, world!');
143+
}).use(injectLambdaContext(logger));
144+
145+
// Act
146+
await handler(event, contextWithoutTenantId);
147+
148+
// Assess
149+
expect(console.info).toHaveBeenCalledTimes(1);
150+
expect(console.info).not.toHaveLoggedNth(
151+
1,
152+
expect.objectContaining({
153+
tenant_id: expect.anything(),
154+
})
155+
);
156+
});
157+
100158
it('adds the context to the messages of each logger instance', async () => {
101159
// Prepare
102160
const logger1 = new Logger({ serviceName: 'parent' });

packages/logger/tests/unit/logEvent.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ describe('Log event', () => {
7777
function_memory_size: '128',
7878
function_name: 'foo-bar-function',
7979
function_request_id: 'c6af9ac6-7b61-11e6-9a41-93e812345678',
80+
tenant_id: 'cff02b3a-0e12-4be2-b3e0-758b49c4cd9b'
8081
})
8182
);
8283
});
@@ -107,6 +108,7 @@ describe('Log event', () => {
107108
function_memory_size: '128',
108109
function_name: 'foo-bar-function',
109110
function_request_id: 'c6af9ac6-7b61-11e6-9a41-93e812345678',
111+
tenant_id: 'cff02b3a-0e12-4be2-b3e0-758b49c4cd9b'
110112
})
111113
);
112114
});

packages/testing/src/TestInvocationLogs.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ class TestInvocationLogs {
1919
* The first element is START, and the last two elements are END, and REPORT.
2020
* [
2121
* 'START RequestId: c6af9ac6-7b61-11e6-9a41-93e812345678 Version: $LATEST',
22-
* '{"cold_start":true,"function_arn":"arn:aws:lambda:eu-west-1:561912387782:function:loggerMiddyStandardFeatures-c555a2ec-1121-4586-9c04-185ab36ea34c","function_memory_size":128,"function_name":"loggerMiddyStandardFeatures-c555a2ec-1121-4586-9c04-185ab36ea34c","function_request_id":"7f586697-238a-4c3b-9250-a5f057c1119c","level":"INFO","message":"This is an INFO log with some context and persistent key","service":"logger-e2e-testing","timestamp":"2022-01-27T16:04:39.323Z","persistentKey":"works"}',
23-
* '{"cold_start":true,"function_arn":"arn:aws:lambda:eu-west-1:561912387782:function:loggerMiddyStandardFeatures-c555a2ec-1121-4586-9c04-185ab36ea34c","function_memory_size":128,"function_name":"loggerMiddyStandardFeatures-c555a2ec-1121-4586-9c04-185ab36ea34c","function_request_id":"7f586697-238a-4c3b-9250-a5f057c1119c","level":"INFO","message":"This is an INFO log with some context","service":"logger-e2e-testing","timestamp":"2022-01-27T16:04:39.323Z","persistentKey":"works","additionalKey":"additionalValue"}',
24-
* '{"cold_start":true,"function_arn":"arn:aws:lambda:eu-west-1:561912387782:function:loggerMiddyStandardFeatures-c555a2ec-1121-4586-9c04-185ab36ea34c","function_memory_size":128,"function_name":"loggerMiddyStandardFeatures-c555a2ec-1121-4586-9c04-185ab36ea34c","function_request_id":"7f586697-238a-4c3b-9250-a5f057c1119c","level":"ERROR","message":"There was an error","service":"logger-e2e-testing","timestamp":"2022-01-27T16:04:39.323Z","persistentKey":"works","error":{"name":"Error","location":"/var/task/index.js:2778","message":"you cannot prevent this","stack":"Error: you cannot prevent this\\n at testFunction (/var/task/index.js:2778:11)\\n at runRequest (/var/task/index.js:2314:36)"}}',
22+
* '{"cold_start":true,"function_arn":"arn:aws:lambda:eu-west-1:561912387782:function:loggerMiddyStandardFeatures-c555a2ec-1121-4586-9c04-185ab36ea34c","function_memory_size":128,"function_name":"loggerMiddyStandardFeatures-c555a2ec-1121-4586-9c04-185ab36ea34c","function_request_id":"7f586697-238a-4c3b-9250-a5f057c1119c","tenant_id":"cff02b3a-0e12-4be2-b3e0-758b49c4cd9b","level":"INFO","message":"This is an INFO log with some context and persistent key","service":"logger-e2e-testing","timestamp":"2022-01-27T16:04:39.323Z","persistentKey":"works"}',
23+
* '{"cold_start":true,"function_arn":"arn:aws:lambda:eu-west-1:561912387782:function:loggerMiddyStandardFeatures-c555a2ec-1121-4586-9c04-185ab36ea34c","function_memory_size":128,"function_name":"loggerMiddyStandardFeatures-c555a2ec-1121-4586-9c04-185ab36ea34c","function_request_id":"7f586697-238a-4c3b-9250-a5f057c1119c","tenant_id":"cff02b3a-0e12-4be2-b3e0-758b49c4cd9b","level":"INFO","message":"This is an INFO log with some context","service":"logger-e2e-testing","timestamp":"2022-01-27T16:04:39.323Z","persistentKey":"works","additionalKey":"additionalValue"}',
24+
* '{"cold_start":true,"function_arn":"arn:aws:lambda:eu-west-1:561912387782:function:loggerMiddyStandardFeatures-c555a2ec-1121-4586-9c04-185ab36ea34c","function_memory_size":128,"function_name":"loggerMiddyStandardFeatures-c555a2ec-1121-4586-9c04-185ab36ea34c","function_request_id":"7f586697-238a-4c3b-9250-a5f057c1119c","tenant_id":"cff02b3a-0e12-4be2-b3e0-758b49c4cd9b","level":"ERROR","message":"There was an error","service":"logger-e2e-testing","timestamp":"2022-01-27T16:04:39.323Z","persistentKey":"works","error":{"name":"Error","location":"/var/task/index.js:2778","message":"you cannot prevent this","stack":"Error: you cannot prevent this\\n at testFunction (/var/task/index.js:2778:11)\\n at runRequest (/var/task/index.js:2314:36)"}}',
2525
* 'END RequestId: c6af9ac6-7b61-11e6-9a41-93e812345678',
2626
* 'REPORT RequestId: c6af9ac6-7b61-11e6-9a41-93e812345678\tDuration: 2.16 ms\tBilled Duration: 3 ms\tMemory Size: 128 MB\tMax Memory Used: 57 MB\t',
2727
* ]

packages/testing/src/context.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export default {
1010
invokedFunctionArn:
1111
'arn:aws:lambda:eu-west-1:123456789012:function:foo-bar-function',
1212
awsRequestId: 'c6af9ac6-7b61-11e6-9a41-93e812345678',
13+
tenantId: 'cff02b3a-0e12-4be2-b3e0-758b49c4cd9b',
1314
getRemainingTimeInMillis: () => 1234,
1415
done: () => console.log('Done!'),
1516
fail: () => console.log('Failed!'),

packages/testing/tests/unit/TestInvocationLogs.test.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ import { beforeEach, describe, expect, it } from 'vitest';
22
import { TestInvocationLogs } from '../../src/TestInvocationLogs.js';
33

44
const exampleLogs = `START RequestId: c6af9ac6-7b61-11e6-9a41-93e812345678 Version: $LATEST
5-
{"cold_start":true,"function_arn":"arn:aws:lambda:eu-west-1:561912387782:function:loggerMiddyStandardFeatures-c555a2ec-1121-4586-9c04-185ab36ea34c","function_memory_size":128,"function_name":"loggerMiddyStandardFeatures-c555a2ec-1121-4586-9c04-185ab36ea34c","function_request_id":"7f586697-238a-4c3b-9250-a5f057c1119c","level":"DEBUG","message":"This is a DEBUG log but contains the word INFO some context and persistent key","service":"logger-e2e-testing","timestamp":"2022-01-27T16:04:39.323Z","persistentKey":"works"}
6-
{"cold_start":true,"function_arn":"arn:aws:lambda:eu-west-1:561912387782:function:loggerMiddyStandardFeatures-c555a2ec-1121-4586-9c04-185ab36ea34c","function_memory_size":128,"function_name":"loggerMiddyStandardFeatures-c555a2ec-1121-4586-9c04-185ab36ea34c","function_request_id":"7f586697-238a-4c3b-9250-a5f057c1119c","level":"INFO","message":"This is an INFO log with some context","service":"logger-e2e-testing","timestamp":"2022-01-27T16:04:39.323Z","persistentKey":"works","additionalKey":"additionalValue"}
7-
{"cold_start":true,"function_arn":"arn:aws:lambda:eu-west-1:561912387782:function:loggerMiddyStandardFeatures-c555a2ec-1121-4586-9c04-185ab36ea34c","function_memory_size":128,"function_name":"loggerMiddyStandardFeatures-c555a2ec-1121-4586-9c04-185ab36ea34c","function_request_id":"7f586697-238a-4c3b-9250-a5f057c1119c","level":"INFO","message":"This is a second INFO log with some context","service":"logger-e2e-testing","timestamp":"2022-01-27T16:04:39.323Z","persistentKey":"works","additionalKey":"additionalValue"}
8-
{"cold_start":true,"function_arn":"arn:aws:lambda:eu-west-1:561912387782:function:loggerMiddyStandardFeatures-c555a2ec-1121-4586-9c04-185ab36ea34c","function_memory_size":128,"function_name":"loggerMiddyStandardFeatures-c555a2ec-1121-4586-9c04-185ab36ea34c","function_request_id":"7f586697-238a-4c3b-9250-a5f057c1119c","level":"ERROR","message":"There was an error","service":"logger-e2e-testing","timestamp":"2022-01-27T16:04:39.323Z","persistentKey":"works","error":{"name":"Error","location":"/var/task/index.js:2778","message":"you cannot prevent this","stack":"Error: you cannot prevent this\\n at testFunction (/var/task/index.js:2778:11)\\n at runRequest (/var/task/index.js:2314:36)"}}
5+
{"cold_start":true,"function_arn":"arn:aws:lambda:eu-west-1:561912387782:function:loggerMiddyStandardFeatures-c555a2ec-1121-4586-9c04-185ab36ea34c","function_memory_size":128,"function_name":"loggerMiddyStandardFeatures-c555a2ec-1121-4586-9c04-185ab36ea34c","function_request_id":"7f586697-238a-4c3b-9250-a5f057c1119c","tenant_id":"cff02b3a-0e12-4be2-b3e0-758b49c4cd9b","level":"DEBUG","message":"This is a DEBUG log but contains the word INFO some context and persistent key","service":"logger-e2e-testing","timestamp":"2022-01-27T16:04:39.323Z","persistentKey":"works"}
6+
{"cold_start":true,"function_arn":"arn:aws:lambda:eu-west-1:561912387782:function:loggerMiddyStandardFeatures-c555a2ec-1121-4586-9c04-185ab36ea34c","function_memory_size":128,"function_name":"loggerMiddyStandardFeatures-c555a2ec-1121-4586-9c04-185ab36ea34c","function_request_id":"7f586697-238a-4c3b-9250-a5f057c1119c","tenant_id":"cff02b3a-0e12-4be2-b3e0-758b49c4cd9b","level":"INFO","message":"This is an INFO log with some context","service":"logger-e2e-testing","timestamp":"2022-01-27T16:04:39.323Z","persistentKey":"works","additionalKey":"additionalValue"}
7+
{"cold_start":true,"function_arn":"arn:aws:lambda:eu-west-1:561912387782:function:loggerMiddyStandardFeatures-c555a2ec-1121-4586-9c04-185ab36ea34c","function_memory_size":128,"function_name":"loggerMiddyStandardFeatures-c555a2ec-1121-4586-9c04-185ab36ea34c","function_request_id":"7f586697-238a-4c3b-9250-a5f057c1119c","tenant_id":"cff02b3a-0e12-4be2-b3e0-758b49c4cd9b","level":"INFO","message":"This is a second INFO log with some context","service":"logger-e2e-testing","timestamp":"2022-01-27T16:04:39.323Z","persistentKey":"works","additionalKey":"additionalValue"}
8+
{"cold_start":true,"function_arn":"arn:aws:lambda:eu-west-1:561912387782:function:loggerMiddyStandardFeatures-c555a2ec-1121-4586-9c04-185ab36ea34c","function_memory_size":128,"function_name":"loggerMiddyStandardFeatures-c555a2ec-1121-4586-9c04-185ab36ea34c","function_request_id":"7f586697-238a-4c3b-9250-a5f057c1119c","tenant_id":"cff02b3a-0e12-4be2-b3e0-758b49c4cd9b","level":"ERROR","message":"There was an error","service":"logger-e2e-testing","timestamp":"2022-01-27T16:04:39.323Z","persistentKey":"works","error":{"name":"Error","location":"/var/task/index.js:2778","message":"you cannot prevent this","stack":"Error: you cannot prevent this\\n at testFunction (/var/task/index.js:2778:11)\\n at runRequest (/var/task/index.js:2314:36)"}}
99
END RequestId: c6af9ac6-7b61-11e6-9a41-93e812345678
1010
REPORT RequestId: c6af9ac6-7b61-11e6-9a41-93e812345678\tDuration: 2.16 ms\tBilled Duration: 3 ms\tMemory Size: 128 MB\tMax Memory Used: 57 MB\t`;
1111

@@ -121,7 +121,7 @@ describe('getFunctionLogs()', () => {
121121
describe('parseFunctionLog()', () => {
122122
it('returns an object with the correct values based on the given log', () => {
123123
const rawLogStr =
124-
'{"cold_start":true,"function_arn":"arn:aws:lambda:eu-west-1:561912387782:function:loggerMiddyStandardFeatures-c555a2ec-1121-4586-9c04-185ab36ea34c","function_memory_size":128,"function_name":"loggerMiddyStandardFeatures-c555a2ec-1121-4586-9c04-185ab36ea34c","function_request_id":"7f586697-238a-4c3b-9250-a5f057c1119c","level":"DEBUG","message":"This is a DEBUG log but contains the word INFO some context and persistent key","service":"logger-e2e-testing","timestamp":"2022-01-27T16:04:39.323Z","persistentKey":"works"}';
124+
'{"cold_start":true,"function_arn":"arn:aws:lambda:eu-west-1:561912387782:function:loggerMiddyStandardFeatures-c555a2ec-1121-4586-9c04-185ab36ea34c","function_memory_size":128,"function_name":"loggerMiddyStandardFeatures-c555a2ec-1121-4586-9c04-185ab36ea34c","function_request_id":"7f586697-238a-4c3b-9250-a5f057c1119c","tenant_id":"cff02b3a-0e12-4be2-b3e0-758b49c4cd9b","level":"DEBUG","message":"This is a DEBUG log but contains the word INFO some context and persistent key","service":"logger-e2e-testing","timestamp":"2022-01-27T16:04:39.323Z","persistentKey":"works"}';
125125

126126
const logObj = TestInvocationLogs.parseFunctionLog(rawLogStr);
127127
expect(logObj).toStrictEqual({
@@ -132,6 +132,7 @@ describe('parseFunctionLog()', () => {
132132
function_name:
133133
'loggerMiddyStandardFeatures-c555a2ec-1121-4586-9c04-185ab36ea34c',
134134
function_request_id: '7f586697-238a-4c3b-9250-a5f057c1119c',
135+
tenant_id: 'cff02b3a-0e12-4be2-b3e0-758b49c4cd9b',
135136
level: 'DEBUG',
136137
message:
137138
'This is a DEBUG log but contains the word INFO some context and persistent key',

0 commit comments

Comments
 (0)