Skip to content

Commit 3a5da9e

Browse files
akapagergaczd
andcommitted
feat(ecs): use ecs format fields by default for logging
AUT-2249 BREAKING CHANGE: after this change, ecs formatting will be used for logging, you need to definitely set that you need the legacy format if necessary (see README) Co-authored-by: Daniel Gergacz <[email protected]>
1 parent 11b9b58 commit 3a5da9e

File tree

2 files changed

+183
-85
lines changed

2 files changed

+183
-85
lines changed

src/logger/logger.spec.ts

Lines changed: 112 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,13 @@ describe('Logger', () => {
2121
formatter: jsonFormatter,
2222
output: consoleOutput,
2323
transformers: [],
24+
outputFormat: 'ecs',
2425
});
2526
clock.restore();
2627
});
2728

28-
it('should call log info method when enabled', () => {
29+
it('should call log info method when enabled (legacy format)', () => {
30+
Logger.configure({ outputFormat: 'legacy' });
2931
logger.info('wedidit', { details: 'forever' });
3032

3133
const logArguments = JSON.parse(outputStub.args[0][0]);
@@ -35,13 +37,24 @@ describe('Logger', () => {
3537
expect(logArguments.details).to.eql('forever');
3638
});
3739

40+
it('should call log info method when enabled (ecs format)', () => {
41+
Logger.configure({ outputFormat: 'ecs' });
42+
logger.info('wedidit', { details: 'forever' });
43+
44+
const logArguments = JSON.parse(outputStub.args[0][0]);
45+
expect(logArguments.event.action).to.eql('wedidit');
46+
expect(logArguments.log.logger).to.eql('mongo');
47+
expect(logArguments.log.level).to.eql(30);
48+
expect(logArguments.details).to.eql('forever');
49+
});
50+
3851
it('should be callable without the data object', () => {
3952
logger.info('wedidit');
4053

4154
const logArguments = JSON.parse(outputStub.args[0][0]);
42-
expect(logArguments.name).to.eql('mongo');
43-
expect(logArguments.action).to.eql('wedidit');
44-
expect(logArguments.level).to.eql(30);
55+
expect(logArguments.event.action).to.eql('wedidit');
56+
expect(logArguments.log.logger).to.eql('mongo');
57+
expect(logArguments.log.level).to.eql(30);
4558
});
4659

4760
it('should not call log info method when disabled', () => {
@@ -63,7 +76,9 @@ describe('Logger', () => {
6376
expect(infoStub).to.have.been.calledWith('hi', { duration: 100 });
6477
});
6578

66-
it('should log error with action', () => {
79+
it('should log error with action (legacy format)', () => {
80+
Logger.configure({ outputFormat: 'legacy' });
81+
6782
const error: Error & { data?: any } = new Error('failed');
6883
error.data = { test: 'data' };
6984

@@ -81,22 +96,42 @@ describe('Logger', () => {
8196
expect(logArguments.error_data).to.eql(JSON.stringify(error.data));
8297
});
8398

99+
it('should log error with action (ecs format)', () => {
100+
Logger.configure({ outputFormat: 'ecs' });
101+
102+
const error: Error & { data?: any } = new Error('failed');
103+
error.data = { test: 'data' };
104+
105+
logger.fromError('hi', error, { details: 'here' });
106+
107+
const logArguments = JSON.parse(outputStub.args[0][0]);
108+
expect(logArguments.event.action).to.eql('hi');
109+
expect(logArguments.log.logger).to.eql('mongo');
110+
expect(logArguments.log.level).to.eql(50);
111+
expect(logArguments.details).to.eql('here');
112+
113+
expect(logArguments.error.type).to.eql(error.name);
114+
expect(logArguments.error.stack_trace).to.eql(error.stack);
115+
expect(logArguments.error.message).to.eql(error.message);
116+
expect(logArguments.error.context).to.eql(JSON.stringify(error.data));
117+
});
118+
84119
it('should log error as warning with action', () => {
85120
const error: Error & { data?: any } = new Error('failed');
86121
error.data = { test: 'data' };
87122

88123
logger.warnFromError('hi', error, { details: 'here' });
89124

90125
const logArguments = JSON.parse(outputStub.args[0][0]);
91-
expect(logArguments.name).to.eql('mongo');
92-
expect(logArguments.action).to.eql('hi');
93-
expect(logArguments.level).to.eql(40);
126+
expect(logArguments.event.action).to.eql('hi');
127+
expect(logArguments.log.logger).to.eql('mongo');
128+
expect(logArguments.log.level).to.eql(40);
94129
expect(logArguments.details).to.eql('here');
95130

96-
expect(logArguments.error_name).to.eql(error.name);
97-
expect(logArguments.error_stack).to.eql(error.stack);
98-
expect(logArguments.error_message).to.eql(error.message);
99-
expect(logArguments.error_data).to.eql(JSON.stringify(error.data));
131+
expect(logArguments.error.type).to.eql(error.name);
132+
expect(logArguments.error.stack_trace).to.eql(error.stack);
133+
expect(logArguments.error.message).to.eql(error.message);
134+
expect(logArguments.error.context).to.eql(JSON.stringify(error.data));
100135
});
101136

102137
it('should not log error data when it is undefined', () => {
@@ -105,15 +140,7 @@ describe('Logger', () => {
105140
logger.warnFromError('hi', error, { details: 'here' });
106141

107142
const logArguments = JSON.parse(outputStub.args[0][0]);
108-
expect(logArguments.name).to.eql('mongo');
109-
expect(logArguments.action).to.eql('hi');
110-
expect(logArguments.level).to.eql(40);
111-
expect(logArguments.details).to.eql('here');
112-
113-
expect(logArguments.error_name).to.eql(error.name);
114-
expect(logArguments.error_stack).to.eql(error.stack);
115-
expect(logArguments.error_message).to.eql(error.message);
116-
expect(logArguments).to.not.have.any.keys('error_data');
143+
expect(logArguments.error).to.not.have.any.keys('context');
117144
});
118145

119146
it('should log only 3000 character of data', () => {
@@ -123,18 +150,12 @@ describe('Logger', () => {
123150
logger.warnFromError('hi', error, { details: 'here' });
124151

125152
const logArguments = JSON.parse(outputStub.args[0][0]);
126-
expect(logArguments.name).to.eql('mongo');
127-
expect(logArguments.action).to.eql('hi');
128-
expect(logArguments.level).to.eql(40);
129-
expect(logArguments.details).to.eql('here');
130-
131-
expect(logArguments.error_name).to.eql(error.name);
132-
expect(logArguments.error_stack).to.eql(error.stack);
133-
expect(logArguments.error_message).to.eql(error.message);
134-
expect(logArguments.error_data.length).to.eql(3004);
153+
expect(logArguments.error.context.length).to.eql(3004);
135154
});
136155

137-
it('should log request/response details for Axios-like error objects', () => {
156+
it('should log request/response details for Axios-like error objects (legacy format)', () => {
157+
Logger.configure({ outputFormat: 'legacy' });
158+
138159
const error = new AxiosError('Request failed with status code 500');
139160
error.response = {
140161
status: 500,
@@ -165,6 +186,38 @@ describe('Logger', () => {
165186
expect(logArguments.response_data).to.eql(JSON.stringify(error.response.data));
166187
});
167188

189+
it('should log request/response details for Axios-like error objects (ecs format)', () => {
190+
Logger.configure({ outputFormat: 'ecs' });
191+
192+
const error = new AxiosError('Request failed with status code 500');
193+
error.response = {
194+
status: 500,
195+
statusText: 'Something horrible happened',
196+
data: { useful_detail: 'important info' },
197+
headers: {},
198+
config: {},
199+
};
200+
error.config = {
201+
url: 'http://amazinghost.com/beautiful-path',
202+
method: 'get',
203+
};
204+
205+
logger.fromError('hi', error, { details: 'here' });
206+
207+
const logArguments = JSON.parse(outputStub.args[0][0]);
208+
expect(logArguments.log.logger).to.eql('mongo');
209+
expect(logArguments.event.action).to.eql('hi');
210+
expect(logArguments.log.level).to.eql(50);
211+
212+
expect(logArguments.error.type).to.eql(error.name);
213+
expect(logArguments.error.stack_trace).to.eql(error.stack);
214+
expect(logArguments.error.message).to.eql(error.message);
215+
expect(logArguments.http.request.method).to.eql(error.config.method);
216+
expect(logArguments.url.full).to.eql(error.config.url);
217+
expect(logArguments.http.response.status_code).to.eql(error.response.status);
218+
expect(logArguments.http.response.body.content).to.eql(JSON.stringify(error.response.data));
219+
});
220+
168221
describe('#customError', () => {
169222
it('should log error as the given severity with action', () => {
170223
const error: Error & { data?: any } = new Error('failed');
@@ -173,15 +226,15 @@ describe('Logger', () => {
173226
logger.customError('info', 'hi', error, { details: 'here' });
174227

175228
const logArguments = JSON.parse(outputStub.args[0][0]);
176-
expect(logArguments.name).to.eql('mongo');
177-
expect(logArguments.action).to.eql('hi');
178-
expect(logArguments.level).to.eql(30);
229+
expect(logArguments.event.action).to.eql('hi');
230+
expect(logArguments.log.logger).to.eql('mongo');
231+
expect(logArguments.log.level).to.eql(30);
179232
expect(logArguments.details).to.eql('here');
180233

181-
expect(logArguments.error_name).to.eql(error.name);
182-
expect(logArguments.error_stack).to.eql(error.stack);
183-
expect(logArguments.error_message).to.eql(error.message);
184-
expect(logArguments.error_data).to.eql(JSON.stringify(error.data));
234+
expect(logArguments.error.type).to.eql(error.name);
235+
expect(logArguments.error.stack_trace).to.eql(error.stack);
236+
expect(logArguments.error.message).to.eql(error.message);
237+
expect(logArguments.error.context).to.eql(JSON.stringify(error.data));
185238
});
186239

187240
it('should not log error data when it is undefined', () => {
@@ -190,15 +243,7 @@ describe('Logger', () => {
190243
logger.customError('warn', 'hi', error, { details: 'here' });
191244

192245
const logArguments = JSON.parse(outputStub.args[0][0]);
193-
expect(logArguments.name).to.eql('mongo');
194-
expect(logArguments.action).to.eql('hi');
195-
expect(logArguments.level).to.eql(40);
196-
expect(logArguments.details).to.eql('here');
197-
198-
expect(logArguments.error_name).to.eql(error.name);
199-
expect(logArguments.error_stack).to.eql(error.stack);
200-
expect(logArguments.error_message).to.eql(error.message);
201-
expect(logArguments).to.not.have.any.keys('error_data');
246+
expect(logArguments.error).to.not.have.any.keys('context');
202247
});
203248

204249
it('should log only 3000 character of data', () => {
@@ -208,15 +253,7 @@ describe('Logger', () => {
208253
logger.customError('error', 'hi', error, { details: 'here' });
209254

210255
const logArguments = JSON.parse(outputStub.args[0][0]);
211-
expect(logArguments.name).to.eql('mongo');
212-
expect(logArguments.action).to.eql('hi');
213-
expect(logArguments.level).to.eql(50);
214-
expect(logArguments.details).to.eql('here');
215-
216-
expect(logArguments.error_name).to.eql(error.name);
217-
expect(logArguments.error_stack).to.eql(error.stack);
218-
expect(logArguments.error_message).to.eql(error.message);
219-
expect(logArguments.error_data.length).to.eql(3004);
256+
expect(logArguments.error.context.length).to.eql(3004);
220257
});
221258

222259
describe('when not an Error instance is passed as error', () => {
@@ -239,10 +276,10 @@ describe('Logger', () => {
239276

240277
const logArguments = JSON.parse(outputStub.args[0][0]);
241278

242-
expect(logArguments.error_name).to.eql(errorObject.name);
243-
expect(logArguments.error_stack).to.eql(errorObject.stack);
244-
expect(logArguments.error_message).to.eql(errorObject.message);
245-
expect(logArguments.error_data).to.eql(JSON.stringify(errorObject.data));
279+
expect(logArguments.error.type).to.eql(errorObject.name);
280+
expect(logArguments.error.stack_trace).to.eql(errorObject.stack);
281+
expect(logArguments.error.message).to.eql(errorObject.message);
282+
expect(logArguments.error.context).to.eql(JSON.stringify(errorObject.data));
246283
});
247284

248285
it('should not log additional or missing error properties from custom error object', () => {
@@ -284,6 +321,17 @@ describe('Logger', () => {
284321
expect(outputStub).to.have.been.called;
285322
});
286323

324+
it('should change output format', () => {
325+
Logger.configure({
326+
outputFormat: 'legacy',
327+
});
328+
logger.info('hi');
329+
330+
const logArguments = JSON.parse(outputStub.args[0][0]);
331+
expect(logArguments.action).to.eql('hi');
332+
expect(logArguments.event).to.be.undefined;
333+
});
334+
287335
it('should throw error on invalid config', () => {
288336
try {
289337
Logger.configure({
@@ -292,7 +340,9 @@ describe('Logger', () => {
292340
});
293341
throw new Error('should throw');
294342
} catch (e) {
295-
expect((e as Error).message).to.eql('Only the following keys are allowed: formatter, output');
343+
expect((e as Error).message).to.eql(
344+
'Only the following keys are allowed: output,formatter,transformers,outputFormat',
345+
);
296346
}
297347
});
298348

@@ -304,7 +354,7 @@ describe('Logger', () => {
304354
logger.info('hi');
305355

306356
const logArguments = JSON.parse(outputStub.args[0][0]);
307-
expect(logArguments.action).to.eql('hi');
357+
expect(logArguments.event.action).to.eql('hi');
308358
expect(logArguments.debug).to.eql(true);
309359
});
310360
});

0 commit comments

Comments
 (0)