Skip to content

Commit ed79d8f

Browse files
author
Ramisa Alam
committed
feat: add tenant-id to structured log message
1 parent d45a5e0 commit ed79d8f

File tree

3 files changed

+68
-3
lines changed

3 files changed

+68
-3
lines changed

src/InvokeContext.js

+9-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
'use strict';
1010

1111
const assert = require('assert').strict;
12-
let { setCurrentRequestId } = require('./LogPatch');
12+
let { setCurrentRequestId, setCurrentTenantId } = require('./LogPatch');
1313

1414
const INVOKE_HEADER = {
1515
ClientContext: 'lambda-runtime-client-context',
@@ -35,11 +35,19 @@ module.exports = class InvokeContext {
3535
return id;
3636
}
3737

38+
/**
39+
* The tenantId for this request.
40+
*/
41+
get tenantId() {
42+
return this.headers[INVOKE_HEADER.TenantId];
43+
}
44+
3845
/**
3946
* Push relevant invoke data into the logging context.
4047
*/
4148
updateLoggingContext() {
4249
setCurrentRequestId(this.invokeId);
50+
setCurrentTenantId(this.tenantId);
4351
}
4452

4553
/**

src/LogPatch.js

+30-2
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,23 @@ const jsonErrorReplacer = (_, value) => {
2828
return value;
2929
};
3030

31-
function formatJsonMessage(requestId, timestamp, level, ...messageParams) {
31+
function formatJsonMessage(
32+
requestId,
33+
timestamp,
34+
level,
35+
tenantId,
36+
...messageParams
37+
) {
3238
let result = {
3339
timestamp: timestamp,
3440
level: level.name,
3541
requestId: requestId,
3642
};
3743

44+
if (tenantId != undefined && tenantId != null) {
45+
result.tenantId = tenantId;
46+
}
47+
3848
if (messageParams.length === 1) {
3949
result.message = messageParams[0];
4050
try {
@@ -65,6 +75,13 @@ let _currentRequestId = {
6575
set: (id) => (global[REQUEST_ID_SYMBOL] = id),
6676
};
6777

78+
/* Use a unique symbol to provide global access without risk of name clashes. */
79+
const TENANT_ID_SYMBOL = Symbol.for('aws.lambda.runtime.tenantId');
80+
let _currentTenantId = {
81+
get: () => global[TENANT_ID_SYMBOL],
82+
set: (id) => (global[TENANT_ID_SYMBOL] = id),
83+
};
84+
6885
/**
6986
* Write logs to stdout.
7087
*/
@@ -82,7 +99,15 @@ let logTextToStdout = (level, message, ...params) => {
8299
let logJsonToStdout = (level, message, ...params) => {
83100
let time = new Date().toISOString();
84101
let requestId = _currentRequestId.get();
85-
let line = formatJsonMessage(requestId, time, level, message, ...params);
102+
let tenantId = _currentTenantId.get();
103+
let line = formatJsonMessage(
104+
requestId,
105+
time,
106+
level,
107+
tenantId,
108+
message,
109+
...params,
110+
);
86111
line = line.replace(/\n/g, '\r');
87112
process.stdout.write(line + '\n');
88113
};
@@ -125,10 +150,12 @@ let logJsonToFd = function (logTarget) {
125150
let date = new Date();
126151
let time = date.toISOString();
127152
let requestId = _currentRequestId.get();
153+
let tenantId = _currentTenantId.get();
128154
let enrichedMessage = formatJsonMessage(
129155
requestId,
130156
time,
131157
level,
158+
tenantId,
132159
message,
133160
...params,
134161
);
@@ -239,6 +266,7 @@ let _patchConsole = () => {
239266

240267
module.exports = {
241268
setCurrentRequestId: _currentRequestId.set,
269+
setCurrentTenantId: _currentTenantId.set,
242270
patchConsole: _patchConsole,
243271
structuredConsole: structuredConsole,
244272
};

test/unit/LogPatchTest.js

+29
Original file line numberDiff line numberDiff line change
@@ -415,9 +415,38 @@ describe('The multiline log patch', () => {
415415
);
416416
receivedMessage.should.have.property('level', logFunctions[fIdx][1]);
417417
receivedMessage.should.have.property('requestId', EXPECTED_ID);
418+
receivedMessage.should.not.have.property('tenantId');
418419
}
419420
});
420421

422+
it('should format messages with tenant id as json correctly', () => {
423+
const EXPECTED_TENANT_ID = 'tenantId';
424+
LogPatch.setCurrentTenantId(EXPECTED_TENANT_ID);
425+
426+
for (let fIdx = 0; fIdx < logFunctions.length; fIdx++) {
427+
logFunctions[fIdx][0]('structured logging with tenant id');
428+
let receivedMessage = telemetryTarget.readLine(
429+
logFunctions[fIdx][1],
430+
'JSON',
431+
);
432+
receivedMessage = JSON.parse(receivedMessage);
433+
434+
receivedMessage.should.have.property('timestamp');
435+
let receivedTime = new Date(receivedMessage.timestamp);
436+
let now = new Date();
437+
assert(now >= receivedTime && now - receivedTime <= 1000);
438+
439+
receivedMessage.should.have.property(
440+
'message',
441+
'structured logging with tenant id',
442+
);
443+
receivedMessage.should.have.property('level', logFunctions[fIdx][1]);
444+
receivedMessage.should.have.property('requestId', EXPECTED_ID);
445+
receivedMessage.should.have.property('tenantId', EXPECTED_TENANT_ID);
446+
}
447+
LogPatch.setCurrentTenantId(undefined);
448+
});
449+
421450
it('should filter messages correctly', () => {
422451
const loglevelSettings = [
423452
undefined,

0 commit comments

Comments
 (0)