logbin-nodejs 0.0.1-security → 2.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of logbin-nodejs might be problematic. Click here for more details.
- package/.eslintrc.js +28 -0
- package/.github/ISSUE_TEMPLATE/bug.yaml +55 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +32 -0
- package/.github/ISSUE_TEMPLATE/documentation.yaml +22 -0
- package/.github/ISSUE_TEMPLATE/feature.yaml +24 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- package/.github/ISSUE_TEMPLATE/question.yaml +16 -0
- package/.github/ISSUE_TEMPLATE/security.yaml +13 -0
- package/.github/dependabot.yml +17 -0
- package/.github/pull_request_template.md +23 -0
- package/.github/workflows/npm-publish.yml +16 -0
- package/.github/workflows/test-nodejs.yml +25 -0
- package/.travis.yml +14 -0
- package/.vscode/settings.json +5 -0
- package/.whitesource +13 -0
- package/CONTRIBUTING.md +63 -0
- package/LICENSE +201 -0
- package/README.md +239 -5
- package/Serverless/lambda-async.md +40 -0
- package/Serverless/lambda-sync.md +32 -0
- package/example.js +25 -0
- package/index.js +2 -0
- package/lib/axiosInstance.js +5 -0
- package/lib/logbin-nodejs.js +21 -0
- package/lib/logzio-nodejs.d.ts +30 -0
- package/lib/logzio-nodejs.js +380 -0
- package/logzio-nodejs.iml +215 -0
- package/package.json +83 -6
- package/test/.eslintrc.js +5 -0
- package/test/logger.test.js +669 -0
- package/test/udp.test.js +94 -0
@@ -0,0 +1,669 @@
|
|
1
|
+
const { networkInterfaces } = require('os');
|
2
|
+
const sinon = require('sinon');
|
3
|
+
const nock = require('nock');
|
4
|
+
const assert = require('assert');
|
5
|
+
const moment = require('moment');
|
6
|
+
const zlib = require('zlib');
|
7
|
+
const logzioLogger = require('../lib/logzio-nodejs.js');
|
8
|
+
const hrtimemock = require('hrtimemock');
|
9
|
+
const axiosInstance = require('../lib/axiosInstance.js');
|
10
|
+
const prop = require('../package.json');
|
11
|
+
axiosInstance.defaults.adapter = 'http';
|
12
|
+
const { trace, context } = require('@opentelemetry/api');
|
13
|
+
const { NodeTracerProvider } = require('@opentelemetry/sdk-trace-node');
|
14
|
+
|
15
|
+
|
16
|
+
const dummyHost = 'logz.io';
|
17
|
+
const nockHttpAddress = `http://${dummyHost}:8070`;
|
18
|
+
|
19
|
+
const createLogger = function createLogger(options) {
|
20
|
+
const myOptions = options;
|
21
|
+
myOptions.token = 'testToken';
|
22
|
+
myOptions.type = 'test-node';
|
23
|
+
myOptions.debug = options.debug??true;
|
24
|
+
myOptions.host = dummyHost;
|
25
|
+
myOptions.sendIntervalMs = options.sendIntervalMs || 1000;
|
26
|
+
return logzioLogger.createLogger(myOptions);
|
27
|
+
};
|
28
|
+
|
29
|
+
const sendLogs = (logger, count = 1, message = 'hello there from test') => {
|
30
|
+
Array(count).fill().forEach((item, i) => {
|
31
|
+
logger.log({
|
32
|
+
message: `${message} #${i}`,
|
33
|
+
id: i,
|
34
|
+
});
|
35
|
+
});
|
36
|
+
};
|
37
|
+
|
38
|
+
const provider = new NodeTracerProvider();
|
39
|
+
provider.register();
|
40
|
+
const tracer = trace.getTracer('test-tracer');
|
41
|
+
|
42
|
+
|
43
|
+
describe('logger', () => {
|
44
|
+
describe('_addOpentelemetryContext', () => {
|
45
|
+
it('should attach traceId and spanId when a span is active', () => {
|
46
|
+
let logger = createLogger({
|
47
|
+
bufferSize: 1,
|
48
|
+
});
|
49
|
+
sinon.spy(logger, '_createBulk');
|
50
|
+
|
51
|
+
let logMessage;
|
52
|
+
|
53
|
+
tracer.startActiveSpan('test-span', (span) => {
|
54
|
+
logMessage = {
|
55
|
+
message: 'test message with active span'
|
56
|
+
};
|
57
|
+
logger.log(logMessage);
|
58
|
+
span.end();
|
59
|
+
});
|
60
|
+
|
61
|
+
const loggedMessage = logger._createBulk.getCall(0).args[0][0];
|
62
|
+
assert(loggedMessage.trace_id, 'trace_id should exist');
|
63
|
+
assert(loggedMessage.span_id, 'span_id should exist');
|
64
|
+
});
|
65
|
+
|
66
|
+
it('should not attach traceId or spanId when no span is active', () => {
|
67
|
+
let logger = createLogger({
|
68
|
+
bufferSize: 1,
|
69
|
+
});
|
70
|
+
sinon.spy(logger, '_createBulk');
|
71
|
+
let logMessage = {
|
72
|
+
message: 'test message without active span'
|
73
|
+
};
|
74
|
+
|
75
|
+
logger.log(logMessage);
|
76
|
+
|
77
|
+
const loggedMessage = logger._createBulk.getCall(0).args[0][0];
|
78
|
+
assert.strictEqual(loggedMessage.trace_id, undefined, 'trace_id should not exist');
|
79
|
+
assert.strictEqual(loggedMessage.span_id, undefined, 'span_id should not exist');
|
80
|
+
});
|
81
|
+
});
|
82
|
+
describe('logs a single line', () => {
|
83
|
+
beforeAll((done) => {
|
84
|
+
sinon
|
85
|
+
.stub(axiosInstance, 'post')
|
86
|
+
.resolves({
|
87
|
+
statusCode: 200,
|
88
|
+
});
|
89
|
+
done();
|
90
|
+
});
|
91
|
+
|
92
|
+
afterAll((done) => {
|
93
|
+
axiosInstance.post.restore();
|
94
|
+
done();
|
95
|
+
});
|
96
|
+
|
97
|
+
it('sends log as a string', (done) => {
|
98
|
+
const logger = createLogger({
|
99
|
+
bufferSize: 1,
|
100
|
+
callback: done,
|
101
|
+
});
|
102
|
+
sinon.spy(logger, '_createBulk');
|
103
|
+
|
104
|
+
const logMsg = 'hello there from test';
|
105
|
+
logger.log(logMsg);
|
106
|
+
assert.equal(logger._createBulk.getCall(0).args[0][0].message, logMsg);
|
107
|
+
logger._createBulk.restore();
|
108
|
+
logger.close();
|
109
|
+
});
|
110
|
+
|
111
|
+
it('sends log with user-agent header', (done) => {
|
112
|
+
const logger = createLogger({
|
113
|
+
bufferSize: 1,
|
114
|
+
callback: onDone
|
115
|
+
});
|
116
|
+
sinon.spy(logger, '_tryToSend');
|
117
|
+
|
118
|
+
const logMsg = 'hello there from test';
|
119
|
+
logger.log(logMsg);
|
120
|
+
|
121
|
+
function onDone() {
|
122
|
+
assert.equal(axiosInstance.defaults.headers.post['user-agent'], `NodeJS/${prop.version} logs`);
|
123
|
+
logger._tryToSend.restore();
|
124
|
+
logger.close();
|
125
|
+
done();
|
126
|
+
}
|
127
|
+
});
|
128
|
+
|
129
|
+
it('should send a log with an object as additional param', (done) => {
|
130
|
+
const logger = createLogger({
|
131
|
+
bufferSize: 1,
|
132
|
+
callback: done,
|
133
|
+
});
|
134
|
+
sinon.spy(logger, '_createBulk');
|
135
|
+
const obj = { key1: "val1", key2: "val2"};
|
136
|
+
const strMsg = 'message: ';
|
137
|
+
const expectedLog = strMsg + JSON.stringify(obj);
|
138
|
+
logger.log(strMsg, obj);
|
139
|
+
|
140
|
+
assert.equal(logger._createBulk.getCall(0).args[0][0].message, expectedLog);
|
141
|
+
logger._createBulk.restore();
|
142
|
+
logger.close();
|
143
|
+
});
|
144
|
+
it('log with sourceIP', (done) => {
|
145
|
+
const logger = createLogger({
|
146
|
+
bufferSize: 1,
|
147
|
+
callback: done,
|
148
|
+
});
|
149
|
+
sinon.spy(logger, '_createBulk');
|
150
|
+
const { en0 } = networkInterfaces();
|
151
|
+
let sourceIP;
|
152
|
+
if (en0 && en0.length > 0) {
|
153
|
+
en0.forEach((ip) => {
|
154
|
+
// Skip over non-IPv4 and internal (i.e. 127.0.0.1) addresses
|
155
|
+
// 'IPv4' is in Node <= 17, from 18 it's a number 4 or 6
|
156
|
+
const familyV4Value = typeof ip.family === 'string' ? 'IPv4' : 4;
|
157
|
+
if (ip.family === familyV4Value && !ip.internal) {
|
158
|
+
sourceIP = ip.address;
|
159
|
+
}
|
160
|
+
});
|
161
|
+
}
|
162
|
+
logger.log({ message: 'sourceIp' });
|
163
|
+
|
164
|
+
assert.equal(logger._createBulk.getCall(0).args[0][0].sourceIP, sourceIP);
|
165
|
+
logger._createBulk.restore();
|
166
|
+
logger.close();
|
167
|
+
});
|
168
|
+
it('sends log as a string with extra fields', (done) => {
|
169
|
+
const logger = createLogger({
|
170
|
+
bufferSize: 1,
|
171
|
+
callback: done,
|
172
|
+
extraFields: {
|
173
|
+
extraField1: 'val1',
|
174
|
+
extraField2: 'val2',
|
175
|
+
},
|
176
|
+
});
|
177
|
+
sinon.spy(logger, '_createBulk');
|
178
|
+
|
179
|
+
const logMsg = 'hello there from test';
|
180
|
+
logger.log(logMsg);
|
181
|
+
assert.equal(logger._createBulk.getCall(0).args[0][0].extraField1, 'val1');
|
182
|
+
assert.equal(logger._createBulk.getCall(0).args[0][0].extraField2, 'val2');
|
183
|
+
|
184
|
+
logger._createBulk.restore();
|
185
|
+
logger.close();
|
186
|
+
});
|
187
|
+
|
188
|
+
it('sends log as an object', (done) => {
|
189
|
+
const logger = createLogger({
|
190
|
+
bufferSize: 1,
|
191
|
+
callback: done,
|
192
|
+
});
|
193
|
+
sinon.spy(logger, '_createBulk');
|
194
|
+
|
195
|
+
const logMsg = {
|
196
|
+
message: 'hello there from test',
|
197
|
+
};
|
198
|
+
logger.log(logMsg);
|
199
|
+
assert.equal(logger._createBulk.getCall(0).args[0][0].message, logMsg.message);
|
200
|
+
|
201
|
+
logger._createBulk.restore();
|
202
|
+
logger.close();
|
203
|
+
});
|
204
|
+
|
205
|
+
it('sends log as an object with extra fields', (done) => {
|
206
|
+
const logger = createLogger({
|
207
|
+
bufferSize: 1,
|
208
|
+
callback: done,
|
209
|
+
extraFields: {
|
210
|
+
extraField1: 'val1',
|
211
|
+
extraField2: 'val2',
|
212
|
+
},
|
213
|
+
});
|
214
|
+
sinon.spy(logger, '_createBulk');
|
215
|
+
|
216
|
+
const logMsg = {
|
217
|
+
message: 'hello there from test',
|
218
|
+
};
|
219
|
+
logger.log(logMsg);
|
220
|
+
assert.equal(logger._createBulk.getCall(0).args[0][0].extraField1, 'val1');
|
221
|
+
assert.equal(logger._createBulk.getCall(0).args[0][0].extraField2, 'val2');
|
222
|
+
|
223
|
+
logger._createBulk.restore();
|
224
|
+
logger.close();
|
225
|
+
});
|
226
|
+
|
227
|
+
it('sends compressed log as an object with extra fields', (done) => {
|
228
|
+
const extraField1 = 'val1';
|
229
|
+
const extraField2 = 'val2';
|
230
|
+
const logger = createLogger({
|
231
|
+
bufferSize: 1,
|
232
|
+
callback: onDone,
|
233
|
+
extraFields: {
|
234
|
+
extraField1,
|
235
|
+
extraField2,
|
236
|
+
},
|
237
|
+
compress: true,
|
238
|
+
});
|
239
|
+
|
240
|
+
sinon.spy(logger, '_tryToSend');
|
241
|
+
const logMsg = {
|
242
|
+
message: 'hello there from test',
|
243
|
+
};
|
244
|
+
|
245
|
+
logger.log(logMsg);
|
246
|
+
|
247
|
+
function onDone() {
|
248
|
+
assert.equal(axiosInstance.defaults.headers.post['content-encoding'], 'gzip');
|
249
|
+
const unzipBody = JSON.parse(zlib.gunzipSync(logger._tryToSend.getCall(0).args[0]));
|
250
|
+
assert.equal(unzipBody.message, logMsg.message);
|
251
|
+
assert.equal(unzipBody.extraField1, extraField1);
|
252
|
+
assert.equal(unzipBody.extraField2, extraField2);
|
253
|
+
logger._tryToSend.restore();
|
254
|
+
logger.close();
|
255
|
+
done();
|
256
|
+
}
|
257
|
+
});
|
258
|
+
|
259
|
+
it('sends log as an object with type', (done) => {
|
260
|
+
const logger = createLogger({
|
261
|
+
bufferSize: 1,
|
262
|
+
callback: done,
|
263
|
+
});
|
264
|
+
sinon.spy(logger, '_createBulk');
|
265
|
+
|
266
|
+
const logMsg = {
|
267
|
+
message: 'hello there from test',
|
268
|
+
type: 'myTestType',
|
269
|
+
};
|
270
|
+
|
271
|
+
logger.log(logMsg);
|
272
|
+
assert.equal(logger._createBulk.getCall(0).args[0][0].message, logMsg.message);
|
273
|
+
assert.equal(logger._createBulk.getCall(0).args[0][0].type, logMsg.type);
|
274
|
+
|
275
|
+
logger._createBulk.restore();
|
276
|
+
logger.close();
|
277
|
+
});
|
278
|
+
|
279
|
+
it('should not include nano timestamp by default', (done) => {
|
280
|
+
let logger = createLogger({
|
281
|
+
bufferSize: 1,
|
282
|
+
callback: done
|
283
|
+
});
|
284
|
+
sinon.spy(logger, '_createBulk');
|
285
|
+
|
286
|
+
logger.log({
|
287
|
+
message: 'hello there from test',
|
288
|
+
});
|
289
|
+
assert.equal(logger._createBulk.getCall(0).args[0][0].hasOwnProperty('@timestamp_nano_secs'), false);
|
290
|
+
|
291
|
+
logger._createBulk.restore();
|
292
|
+
logger.close();
|
293
|
+
});
|
294
|
+
|
295
|
+
it('should add a valid nano-sec timestamp to the log', (done) => {
|
296
|
+
var mockTime = 0.123456;
|
297
|
+
var expectedLogTime = '000123456';
|
298
|
+
|
299
|
+
logger = createLogger({
|
300
|
+
bufferSize: 1,
|
301
|
+
callback: done,
|
302
|
+
addTimestampWithNanoSecs: true,
|
303
|
+
});
|
304
|
+
sinon.spy(logger, '_createBulk');
|
305
|
+
hrtimemock(mockTime);
|
306
|
+
process.hrtime();
|
307
|
+
logger.log({
|
308
|
+
message: 'hello there from test'
|
309
|
+
})
|
310
|
+
const mockLogCall = logger._createBulk.getCall(0).args[0][0];
|
311
|
+
assert.equal(mockLogCall['@timestamp_nano'].endsWith(expectedLogTime), true);
|
312
|
+
|
313
|
+
logger._createBulk.restore();
|
314
|
+
logger.close();
|
315
|
+
});
|
316
|
+
|
317
|
+
it('writes a log message without @timestamp', (done) => {
|
318
|
+
const logger = createLogger({
|
319
|
+
// buffer is 2 so we could access the log before we send it, to analyze it
|
320
|
+
bufferSize: 2,
|
321
|
+
callback: done,
|
322
|
+
});
|
323
|
+
|
324
|
+
const fakeTime = moment('2011-09-01').valueOf();
|
325
|
+
|
326
|
+
// Fake the current time, so we could test on it
|
327
|
+
const clock = sinon.useFakeTimers(fakeTime);
|
328
|
+
logger.log({
|
329
|
+
message: 'hello there from test',
|
330
|
+
});
|
331
|
+
clock.restore();
|
332
|
+
|
333
|
+
assert.equal(fakeTime, moment(logger.messages[logger.messages.length - 1]['@timestamp'].valueOf()));
|
334
|
+
logger.close();
|
335
|
+
});
|
336
|
+
|
337
|
+
it('writes a log message with a custom @timestamp', (done) => {
|
338
|
+
const logger = createLogger({
|
339
|
+
// buffer is 2 so we could access the log before we send it, to analyze it
|
340
|
+
bufferSize: 2,
|
341
|
+
callback: done,
|
342
|
+
});
|
343
|
+
|
344
|
+
const fakeTime = moment('2011-09-01');
|
345
|
+
|
346
|
+
logger.log({
|
347
|
+
message: 'hello there from test',
|
348
|
+
'@timestamp': fakeTime.format(),
|
349
|
+
});
|
350
|
+
|
351
|
+
assert.equal(fakeTime.format(), logger.messages[logger.messages.length - 1]['@timestamp']);
|
352
|
+
logger.close();
|
353
|
+
});
|
354
|
+
});
|
355
|
+
|
356
|
+
describe('logs multiple lines', () => {
|
357
|
+
beforeAll((done) => {
|
358
|
+
sinon
|
359
|
+
.stub(axiosInstance, 'post')
|
360
|
+
.resolves({
|
361
|
+
statusCode: 200,
|
362
|
+
});
|
363
|
+
done();
|
364
|
+
});
|
365
|
+
|
366
|
+
afterAll((done) => {
|
367
|
+
axiosInstance.post.restore();
|
368
|
+
done();
|
369
|
+
});
|
370
|
+
|
371
|
+
it('Send multiple lines', (done) => {
|
372
|
+
const logger = createLogger({
|
373
|
+
bufferSize: 3,
|
374
|
+
callback: done,
|
375
|
+
});
|
376
|
+
|
377
|
+
sendLogs(logger, 3);
|
378
|
+
|
379
|
+
logger.close();
|
380
|
+
});
|
381
|
+
|
382
|
+
it('Send multiple bulks', (done) => {
|
383
|
+
let timesCalled = 0;
|
384
|
+
const bufferSize = 3;
|
385
|
+
const logCount = 6;
|
386
|
+
const expectedTimes = logCount / bufferSize;
|
387
|
+
|
388
|
+
function assertCalled() {
|
389
|
+
timesCalled += 1;
|
390
|
+
|
391
|
+
if (expectedTimes === timesCalled) {
|
392
|
+
done();
|
393
|
+
} else if (timesCalled > expectedTimes) {
|
394
|
+
throw new Error('called more than expected');
|
395
|
+
}
|
396
|
+
}
|
397
|
+
|
398
|
+
const logger = createLogger({
|
399
|
+
bufferSize,
|
400
|
+
callback: assertCalled,
|
401
|
+
});
|
402
|
+
|
403
|
+
sendLogs(logger, logCount);
|
404
|
+
|
405
|
+
logger.close();
|
406
|
+
});
|
407
|
+
});
|
408
|
+
|
409
|
+
describe('#log-closing', () => {
|
410
|
+
beforeAll((done) => {
|
411
|
+
sinon
|
412
|
+
.stub(axiosInstance, 'post')
|
413
|
+
.resolves({
|
414
|
+
statusCode: 200,
|
415
|
+
});
|
416
|
+
done();
|
417
|
+
});
|
418
|
+
|
419
|
+
afterAll((done) => {
|
420
|
+
axiosInstance.post.restore();
|
421
|
+
done();
|
422
|
+
});
|
423
|
+
|
424
|
+
it('Don\'t allow logs after closing', (done) => {
|
425
|
+
const logger = createLogger({
|
426
|
+
bufferSize: 1,
|
427
|
+
});
|
428
|
+
logger.close();
|
429
|
+
try {
|
430
|
+
logger.log({
|
431
|
+
messge: 'hello there from test',
|
432
|
+
});
|
433
|
+
done('Expected an error when logging into a closed log!');
|
434
|
+
} catch (ex) {
|
435
|
+
done();
|
436
|
+
}
|
437
|
+
});
|
438
|
+
});
|
439
|
+
|
440
|
+
describe('timers', () => {
|
441
|
+
beforeAll((done) => {
|
442
|
+
sinon
|
443
|
+
.stub(axiosInstance, 'post')
|
444
|
+
.resolves({
|
445
|
+
statusCode: 200,
|
446
|
+
});
|
447
|
+
done();
|
448
|
+
});
|
449
|
+
|
450
|
+
afterAll((done) => {
|
451
|
+
axiosInstance.post.restore();
|
452
|
+
done();
|
453
|
+
});
|
454
|
+
|
455
|
+
it('timer send test', (done) => {
|
456
|
+
const bufferSize = 100;
|
457
|
+
let timesCalled = 0;
|
458
|
+
const expectedTimes = 2;
|
459
|
+
|
460
|
+
function assertCalled() {
|
461
|
+
timesCalled += 1;
|
462
|
+
if (expectedTimes === timesCalled) done();
|
463
|
+
}
|
464
|
+
|
465
|
+
const logger = createLogger({
|
466
|
+
bufferSize,
|
467
|
+
callback: assertCalled,
|
468
|
+
sendIntervalMs: 10,
|
469
|
+
});
|
470
|
+
|
471
|
+
// These messages should be sent in 1 bulk 10 seconds from now (due to sendIntervalMs)
|
472
|
+
sendLogs(logger, 3);
|
473
|
+
// Schedule 100 msgs (buffer size)
|
474
|
+
// which should be sent in one bulk 11 seconds from start
|
475
|
+
setTimeout(() => {
|
476
|
+
sendLogs(logger, bufferSize);
|
477
|
+
logger.close();
|
478
|
+
}, 30);
|
479
|
+
}, 5000);
|
480
|
+
});
|
481
|
+
|
482
|
+
describe('recovers after server fails one time', () => {
|
483
|
+
let errorAndThenSuccessScope;
|
484
|
+
let extraRequestScope;
|
485
|
+
const socketDelay = 20;
|
486
|
+
|
487
|
+
beforeAll((done) => {
|
488
|
+
nock.cleanAll();
|
489
|
+
errorAndThenSuccessScope = nock(nockHttpAddress)
|
490
|
+
.post('/')
|
491
|
+
.socketDelay(socketDelay)
|
492
|
+
.query(true)
|
493
|
+
.once()
|
494
|
+
.reply(200, '')
|
495
|
+
|
496
|
+
// success
|
497
|
+
.post('/')
|
498
|
+
.socketDelay(0)
|
499
|
+
.query(true)
|
500
|
+
.once()
|
501
|
+
.reply(200, '');
|
502
|
+
|
503
|
+
extraRequestScope = nock(nockHttpAddress)
|
504
|
+
.filteringPath(() => '/')
|
505
|
+
.post('/')
|
506
|
+
.once()
|
507
|
+
.reply(200, '');
|
508
|
+
|
509
|
+
done();
|
510
|
+
});
|
511
|
+
|
512
|
+
afterAll((done) => {
|
513
|
+
nock.restore();
|
514
|
+
nock.cleanAll();
|
515
|
+
done();
|
516
|
+
});
|
517
|
+
|
518
|
+
it('Msgs are only sent once', (done) => {
|
519
|
+
// very small timeout so the first request will fail (nock setup this way above) and
|
520
|
+
// then second attempt will succeed
|
521
|
+
const logger = createLogger({
|
522
|
+
bufferSize: 1,
|
523
|
+
sendIntervalMs: 50000,
|
524
|
+
timeout: socketDelay / 2,
|
525
|
+
sleepUntilNextRetry: socketDelay * 2,
|
526
|
+
});
|
527
|
+
|
528
|
+
sendLogs(logger);
|
529
|
+
logger.close();
|
530
|
+
|
531
|
+
setTimeout(() => {
|
532
|
+
if (!errorAndThenSuccessScope.isDone()) {
|
533
|
+
done(new Error(`pending mocks: ${errorAndThenSuccessScope.pendingMocks()}`));
|
534
|
+
} else if (extraRequestScope.isDone()) {
|
535
|
+
done(new Error('We don\'t expect another request'));
|
536
|
+
} else {
|
537
|
+
done();
|
538
|
+
}
|
539
|
+
}, socketDelay * 5);
|
540
|
+
}, 10000);
|
541
|
+
});
|
542
|
+
|
543
|
+
describe('bad request', () => {
|
544
|
+
afterEach((done) => {
|
545
|
+
axiosInstance.post.restore();
|
546
|
+
done();
|
547
|
+
});
|
548
|
+
|
549
|
+
it('bad request with code', (done) => {
|
550
|
+
sinon
|
551
|
+
.stub(axiosInstance, 'post')
|
552
|
+
.rejects({
|
553
|
+
statusCode: 400,
|
554
|
+
cause: { code: 'BAD_REQUEST' },
|
555
|
+
messge: 'bad',
|
556
|
+
});
|
557
|
+
|
558
|
+
const logger = createLogger({
|
559
|
+
bufferSize: 3,
|
560
|
+
callback(err) {
|
561
|
+
if (err) {
|
562
|
+
done();
|
563
|
+
return;
|
564
|
+
}
|
565
|
+
|
566
|
+
done(new Error('Expected an error'));
|
567
|
+
},
|
568
|
+
});
|
569
|
+
|
570
|
+
sendLogs(logger, 3);
|
571
|
+
|
572
|
+
logger.close();
|
573
|
+
});
|
574
|
+
|
575
|
+
it('bad request with no cause nor code', (done) => {
|
576
|
+
sinon
|
577
|
+
.stub(axiosInstance, 'post')
|
578
|
+
.rejects({
|
579
|
+
statusCode: 400,
|
580
|
+
message: 'bad',
|
581
|
+
});
|
582
|
+
|
583
|
+
const logger = createLogger({
|
584
|
+
bufferSize: 3,
|
585
|
+
callback(err) {
|
586
|
+
if (err) {
|
587
|
+
done();
|
588
|
+
return;
|
589
|
+
}
|
590
|
+
|
591
|
+
done(new Error('Expected an error'));
|
592
|
+
},
|
593
|
+
});
|
594
|
+
|
595
|
+
sendLogs(logger, 3);
|
596
|
+
|
597
|
+
logger.close();
|
598
|
+
});
|
599
|
+
});
|
600
|
+
|
601
|
+
describe('Logger callback', () => {
|
602
|
+
it('should execute external logger', (done) => {
|
603
|
+
const internalLogger = {
|
604
|
+
log: () => {
|
605
|
+
done();
|
606
|
+
},
|
607
|
+
};
|
608
|
+
|
609
|
+
const logger = createLogger({
|
610
|
+
bufferSize: 1,
|
611
|
+
internalLogger,
|
612
|
+
debug: false,
|
613
|
+
numberOfRetries: 0,
|
614
|
+
});
|
615
|
+
|
616
|
+
sendLogs(logger);
|
617
|
+
logger.close();
|
618
|
+
});
|
619
|
+
});
|
620
|
+
|
621
|
+
describe('Flush log messages', () => {
|
622
|
+
|
623
|
+
afterAll((done) => {
|
624
|
+
axiosInstance.post.restore();
|
625
|
+
done();
|
626
|
+
});
|
627
|
+
|
628
|
+
beforeAll((done) => {
|
629
|
+
sinon
|
630
|
+
.stub(axiosInstance, 'post')
|
631
|
+
.resolves({
|
632
|
+
statusCode: 200,
|
633
|
+
});
|
634
|
+
done();
|
635
|
+
});
|
636
|
+
|
637
|
+
it('should send one log at a time', (done) => {
|
638
|
+
let timesCalled = 0;
|
639
|
+
const bufferSize = 3;
|
640
|
+
const logCount = 3;
|
641
|
+
const expectedTimes = 3;
|
642
|
+
|
643
|
+
function assertCalled() {
|
644
|
+
timesCalled += 1;
|
645
|
+
|
646
|
+
if (logCount === timesCalled) {
|
647
|
+
done();
|
648
|
+
} else if (timesCalled > expectedTimes) {
|
649
|
+
throw new Error('called less times than expected');
|
650
|
+
}
|
651
|
+
}
|
652
|
+
|
653
|
+
const logger = createLogger({
|
654
|
+
bufferSize,
|
655
|
+
});
|
656
|
+
|
657
|
+
Array(logCount).fill().forEach((item, i) => {
|
658
|
+
logger.log({
|
659
|
+
message: `hello there from test #${i}`,
|
660
|
+
id: i,
|
661
|
+
});
|
662
|
+
|
663
|
+
logger.flush(assertCalled);
|
664
|
+
});
|
665
|
+
|
666
|
+
logger.close();
|
667
|
+
});
|
668
|
+
});
|
669
|
+
});
|