a2efb537fd5e2eb0b00e4d72274f0567ce5488cc
4 const assert
= require('node:assert');
5 const sinon
= require('sinon'); // eslint-disable-line node/no-unpublished-require
6 const Logger
= require('../../lib/logger');
7 const http
= require('node:http');
8 const { AsyncLocalStorage
} = require('node:async_hooks');
9 const asyncLocalStorage
= new AsyncLocalStorage();
11 describe('Logger', function () {
12 let config
, logger
, commonObject
, scope
, message
;
14 beforeEach(function () {
17 nodeId: '3c100e84-9a7f-11ec-9b4e-0025905f714a',
19 logger
= new Logger(config
, commonObject
);
20 const logWrapper
= process
.env
['VERBOSE_TESTS'] ? sinon
.spy : sinon
.stub
;
21 Object
.keys(Logger
.nullLogger
).forEach((level
) => logWrapper(logger
.backend
, level
));
25 this.afterEach(function () {
29 it('logs a message', function () {
30 logger
.info(scope
, message
, { baz: 'quux' }, { foo: 1 }, 'more other');
31 assert(logger
.backend
.info
.called
);
32 assert(logger
.backend
.info
.args
[0][0].includes(message
));
35 it('stubs missing levels', function () {
39 logger
= new Logger(config
, commonObject
, undefined, backend
);
40 assert
.strictEqual(typeof logger
.info
, 'function');
43 it('logs BigInts', function () {
44 logger
.info(scope
, message
, { aBigInteger: BigInt(2) });
45 assert(logger
.backend
.info
.called
);
46 assert(logger
.backend
.info
.args
[0][0].includes('"2"'));
49 it('logs Errors', function () {
50 logger
.error(scope
, message
, { e: new Error('an error') });
51 assert(logger
.backend
.error
.called
);
52 assert(logger
.backend
.error
.args
[0][0].includes('an error'), logger
.backend
.error
.args
[0][0]);
55 it('covers config settings', function () {
56 config
.ignoreBelowLevel
= 'info';
57 logger
= new Logger(config
);
58 logger
.debug(scope
, message
, {});
59 assert(logger
.backend
.debug
.notCalled
);
62 it('covers config error', function () {
63 config
.ignoreBelowLevel
= 'not a level';
65 logger
= new Logger(config
);
66 assert
.fail('expected RangeError here');
68 assert(e
instanceof RangeError
);
72 it('covers empty fields', function () {
74 assert(logger
.backend
.info
.called
);
75 assert(logger
.backend
.info
.args
[0][0].includes('[unknown]'));
78 it('sanitizes', function () {
79 logger
.dataSanitizers
.push((data
, sanitize
= true) => {
81 const credentialLength
= data
?.ctx
?.parsedBody
?.credential
?.length
;
82 if (credentialLength
) {
85 if (unclean
&& sanitize
) {
86 data
.ctx
.parsedBody
.credential
= '*'.repeat(credentialLength
);
90 logger
.info(scope
, message
, {
97 assert(logger
.backend
.info
.called
);
98 assert(logger
.backend
.info
.args
[0][0].includes('******'));
101 it('logs http client requests', function () {
102 const incomingMessage
= new http
.IncomingMessage();
103 incomingMessage
.method
= 'GET';
104 incomingMessage
.url
= new URL('http://example.com/');
105 logger
.info(scope
, message
, { incomingMessage
});
106 assert(logger
.backend
.info
.called
);
107 assert(logger
.backend
.info
.args
[0][0].includes('GET'));
108 assert(logger
.backend
.info
.args
[0][0].includes('http://example.com/'));
111 it('logs http client requests with scrubbed auth', function () {
112 const incomingMessage
= Object
.create(http
.IncomingMessage
.prototype);
113 incomingMessage
.headers
= {
114 authorization: 'Basic eW8=',
116 logger
.info(scope
, message
, { incomingMessage
});
117 assert(logger
.backend
.info
.called
);
118 assert(logger
.backend
.info
.args
[0][0].includes('****'));
121 it('logs http server responses', function () {
122 const serverResponse
= Object
.create(http
.ServerResponse
.prototype);
123 logger
.info(scope
, message
, { serverResponse
});
124 assert(logger
.backend
.info
.args
[0][0].includes('"statusCode":200'));
127 it('follows expected level ordering', function () {
128 const levels
= Object
.keys(Logger
.nullLogger
);
129 const expected
= ['error', 'warn', 'info', 'log', 'debug'];
130 assert
.deepStrictEqual(levels
, expected
);
133 it('logs async storage data', async
function () {
134 logger
= new Logger(config
, commonObject
, asyncLocalStorage
);
135 const data
= { foo: 'bar' };
136 asyncLocalStorage
.run(data
, async () => {
137 logger
.info(scope
, message
, { baz: 3 });
139 assert(logger
.backend
.info
.called
);
140 assert(logger
.backend
.info
.args
[0][0].includes('"foo":"bar"'));
143 it('covers no async storage', function () {
144 logger
= new Logger(config
);
145 const data
= { foo: 'bar' };
146 asyncLocalStorage
.run(data
, async () => {
147 logger
.info(scope
, message
, { baz: 3 });
149 assert(logger
.backend
.info
.called
);
150 assert(!logger
.backend
.info
.args
[0][0].includes('"foo":"bar"'));
153 it('covers circular objects', function () {
154 const data
= { foo: 'bar' };
156 logger
.info(scope
, message
, data
);
157 assert(logger
.backend
.info
.called
);
158 assert(logger
.backend
.info
.args
[0][0].includes('[Circular]'));