UNPKG

37.1 kBJavaScriptView Raw
1'use strict'
2
3const { test, tearDown } = require('tap')
4const http = require('http')
5const stream = require('stream')
6const split = require('split2')
7const Fastify = require('..')
8const pino = require('pino')
9const path = require('path')
10const os = require('os')
11const fs = require('fs')
12const sget = require('simple-get').concat
13
14const files = []
15let count = 0
16
17function file () {
18 const file = path.join(os.tmpdir(), `sonic-boom-${process.pid}-${process.hrtime().toString()}-${count++}`)
19 files.push(file)
20 return file
21}
22
23tearDown(() => {
24 files.forEach((file) => {
25 try {
26 fs.unlinkSync(file)
27 } catch (e) {
28 console.log(e)
29 }
30 })
31})
32
33test('defaults to info level', t => {
34 t.plan(13)
35 var fastify = null
36 var stream = split(JSON.parse)
37 try {
38 fastify = Fastify({
39 logger: {
40 stream: stream
41 }
42 })
43 } catch (e) {
44 t.fail()
45 }
46
47 fastify.get('/', function (req, reply) {
48 t.ok(req.log)
49 reply.send({ hello: 'world' })
50 })
51
52 stream.once('data', listenAtLogLine => {
53 t.ok(listenAtLogLine, 'listen at log message is ok')
54
55 stream.once('data', line => {
56 const id = line.reqId
57 t.ok(line.reqId, 'reqId is defined')
58 t.ok(line.req, 'req is defined')
59 t.equal(line.msg, 'incoming request', 'message is set')
60 t.equal(line.req.method, 'GET', 'method is get')
61
62 stream.once('data', line => {
63 t.equal(line.reqId, id)
64 t.ok(line.reqId, 'reqId is defined')
65 t.ok(line.res, 'res is defined')
66 t.equal(line.msg, 'request completed', 'message is set')
67 t.equal(line.res.statusCode, 200, 'statusCode is 200')
68 t.ok(line.responseTime, 'responseTime is defined')
69 })
70 })
71 })
72
73 fastify.listen(0, err => {
74 t.error(err)
75 fastify.server.unref()
76
77 http.get('http://localhost:' + fastify.server.address().port)
78 })
79})
80
81test('test log stream', t => {
82 t.plan(12)
83 var fastify = null
84 var stream = split(JSON.parse)
85 try {
86 fastify = Fastify({
87 logger: {
88 stream: stream,
89 level: 'info'
90 }
91 })
92 } catch (e) {
93 t.fail()
94 }
95
96 fastify.get('/', function (req, reply) {
97 t.ok(req.log)
98 reply.send({ hello: 'world' })
99 })
100
101 fastify.listen(0, err => {
102 t.error(err)
103 fastify.server.unref()
104
105 http.get('http://localhost:' + fastify.server.address().port)
106 stream.once('data', listenAtLogLine => {
107 t.ok(listenAtLogLine, 'listen at log message is ok')
108
109 stream.once('data', line => {
110 const id = line.reqId
111 t.ok(line.reqId, 'reqId is defined')
112 t.ok(line.req, 'req is defined')
113 t.equal(line.msg, 'incoming request', 'message is set')
114 t.equal(line.req.method, 'GET', 'method is get')
115
116 stream.once('data', line => {
117 t.equal(line.reqId, id)
118 t.ok(line.reqId, 'reqId is defined')
119 t.ok(line.res, 'res is defined')
120 t.equal(line.msg, 'request completed', 'message is set')
121 t.equal(line.res.statusCode, 200, 'statusCode is 200')
122 })
123 })
124 })
125 })
126})
127
128test('test error log stream', t => {
129 t.plan(11)
130 var fastify = null
131 var stream = split(JSON.parse)
132 try {
133 fastify = Fastify({
134 logger: {
135 stream: stream,
136 level: 'info'
137 }
138 })
139 } catch (e) {
140 t.fail()
141 }
142
143 fastify.get('/error', function (req, reply) {
144 t.ok(req.log)
145 reply.send(new Error('kaboom'))
146 })
147
148 fastify.listen(0, err => {
149 t.error(err)
150 fastify.server.unref()
151
152 http.get('http://localhost:' + fastify.server.address().port + '/error')
153 stream.once('data', listenAtLogLine => {
154 t.ok(listenAtLogLine, 'listen at log message is ok')
155
156 stream.once('data', line => {
157 t.ok(line.reqId, 'reqId is defined')
158 t.ok(line.req, 'req is defined')
159 t.equal(line.msg, 'incoming request', 'message is set')
160 t.equal(line.req.method, 'GET', 'method is get')
161
162 stream.once('data', line => {
163 t.ok(line.reqId, 'reqId is defined')
164 t.ok(line.res, 'res is defined')
165 t.equal(line.msg, 'kaboom', 'message is set')
166 t.equal(line.res.statusCode, 500, 'statusCode is 500')
167 })
168 })
169 })
170 })
171})
172
173test('can use external logger instance', t => {
174 const lines = [/^Server listening at /, /^incoming request$/, /^log success$/, /^request completed$/]
175 t.plan(lines.length + 2)
176
177 const splitStream = split(JSON.parse)
178 splitStream.on('data', (line) => {
179 const regex = lines.shift()
180 t.ok(regex.test(line.msg), '"' + line.msg + '" dont match "' + regex + '"')
181 })
182
183 const logger = require('pino')(splitStream)
184
185 const localFastify = Fastify({ logger: logger })
186
187 localFastify.get('/foo', function (req, reply) {
188 t.ok(req.log)
189 req.log.info('log success')
190 reply.send({ hello: 'world' })
191 })
192
193 localFastify.listen(0, err => {
194 t.error(err)
195 http.get('http://localhost:' + localFastify.server.address().port + '/foo', (res) => {
196 res.resume()
197 res.on('end', () => {
198 localFastify.server.close()
199 })
200 })
201 })
202})
203
204test('can use external logger instance with custom serializer', t => {
205 const lines = [['level', 30], ['req', { url: '/foo' }], ['level', 30], ['res', { statusCode: 200 }]]
206 t.plan(lines.length + 2)
207
208 const splitStream = split(JSON.parse)
209 splitStream.on('data', (line) => {
210 const check = lines.shift()
211 const key = check[0]
212 const value = check[1]
213
214 t.deepEqual(line[key], value)
215 })
216
217 const logger = require('pino')({
218 level: 'info',
219 serializers: {
220 req: function (req) {
221 return {
222 url: req.url
223 }
224 }
225 }
226 }, splitStream)
227
228 const localFastify = Fastify({
229 logger: logger
230 })
231
232 localFastify.get('/foo', function (req, reply) {
233 t.ok(req.log)
234 req.log.info('log success')
235 reply.send({ hello: 'world' })
236 })
237
238 localFastify.listen(0, err => {
239 t.error(err)
240 http.get('http://localhost:' + localFastify.server.address().port + '/foo', (res) => {
241 res.resume()
242 res.on('end', () => {
243 localFastify.server.close()
244 })
245 })
246 })
247})
248
249test('expose the logger', t => {
250 t.plan(2)
251 var fastify = null
252 var stream = split(JSON.parse)
253 try {
254 fastify = Fastify({
255 logger: {
256 stream: stream,
257 level: 'info'
258 }
259 })
260 } catch (e) {
261 t.fail()
262 }
263
264 t.ok(fastify.log)
265 t.is(typeof fastify.log, 'object')
266})
267
268test('The request id header key can be customized', t => {
269 t.plan(9)
270 const REQUEST_ID = '42'
271
272 const stream = split(JSON.parse)
273 const fastify = Fastify({
274 logger: { stream: stream, level: 'info' },
275 requestIdHeader: 'my-custom-request-id'
276 })
277 t.tearDown(() => fastify.close())
278
279 fastify.get('/', (req, reply) => {
280 t.equal(req.raw.id, REQUEST_ID)
281 req.log.info('some log message')
282 reply.send({ id: req.raw.id })
283 })
284
285 fastify.inject({
286 method: 'GET',
287 url: '/',
288 headers: {
289 'my-custom-request-id': REQUEST_ID
290 }
291 }, (err, res) => {
292 t.error(err)
293 const payload = JSON.parse(res.payload)
294 t.equal(payload.id, REQUEST_ID)
295
296 stream.once('data', line => {
297 t.equal(line.reqId, REQUEST_ID)
298 t.equal(line.msg, 'incoming request', 'message is set')
299
300 stream.once('data', line => {
301 t.equal(line.reqId, REQUEST_ID)
302 t.equal(line.msg, 'some log message', 'message is set')
303
304 stream.once('data', line => {
305 t.equal(line.reqId, REQUEST_ID)
306 t.equal(line.msg, 'request completed', 'message is set')
307 })
308 })
309 })
310 })
311})
312
313test('The request id header key can be customized along with a custom id generator', t => {
314 t.plan(12)
315 const REQUEST_ID = '42'
316
317 const stream = split(JSON.parse)
318 const fastify = Fastify({
319 logger: { stream: stream, level: 'info' },
320 requestIdHeader: 'my-custom-request-id',
321 genReqId (req) {
322 return 'foo'
323 }
324 })
325 t.tearDown(() => fastify.close())
326
327 fastify.get('/one', (req, reply) => {
328 t.equal(req.id, REQUEST_ID)
329 req.log.info('some log message')
330 reply.send({ id: req.id })
331 })
332
333 fastify.get('/two', (req, reply) => {
334 t.equal(req.id, 'foo')
335 req.log.info('some log message 2')
336 reply.send({ id: req.id })
337 })
338
339 const matches = [
340 { reqId: REQUEST_ID, msg: /incoming request/ },
341 { reqId: REQUEST_ID, msg: /some log message/ },
342 { reqId: REQUEST_ID, msg: /request completed/ },
343 { reqId: 'foo', msg: /incoming request/ },
344 { reqId: 'foo', msg: /some log message 2/ },
345 { reqId: 'foo', msg: /request completed/ }
346 ]
347
348 let i = 0
349 stream.on('data', line => {
350 t.match(line, matches[i])
351 i += 1
352 })
353
354 fastify.inject({
355 method: 'GET',
356 url: '/one',
357 headers: {
358 'my-custom-request-id': REQUEST_ID
359 }
360 }, (err, res) => {
361 t.error(err)
362 const payload = JSON.parse(res.payload)
363 t.equal(payload.id, REQUEST_ID)
364 })
365
366 fastify.inject({
367 method: 'GET',
368 url: '/two'
369 }, (err, res) => {
370 t.error(err)
371 const payload = JSON.parse(res.payload)
372 t.equal(payload.id, 'foo')
373 })
374})
375
376test('The request id log label can be changed', t => {
377 t.plan(6)
378 const REQUEST_ID = '42'
379
380 const stream = split(JSON.parse)
381 const fastify = Fastify({
382 logger: { stream: stream, level: 'info' },
383 requestIdHeader: 'my-custom-request-id',
384 requestIdLogLabel: 'traceId'
385 })
386 t.tearDown(() => fastify.close())
387
388 fastify.get('/one', (req, reply) => {
389 t.equal(req.id, REQUEST_ID)
390 req.log.info('some log message')
391 reply.send({ id: req.id })
392 })
393
394 const matches = [
395 { traceId: REQUEST_ID, msg: /incoming request/ },
396 { traceId: REQUEST_ID, msg: /some log message/ },
397 { traceId: REQUEST_ID, msg: /request completed/ }
398 ]
399
400 let i = 0
401 stream.on('data', line => {
402 t.match(line, matches[i])
403 i += 1
404 })
405
406 fastify.inject({
407 method: 'GET',
408 url: '/one',
409 headers: {
410 'my-custom-request-id': REQUEST_ID
411 }
412 }, (err, res) => {
413 t.error(err)
414 const payload = JSON.parse(res.payload)
415 t.equal(payload.id, REQUEST_ID)
416 })
417})
418
419test('The logger should accept custom serializer', t => {
420 t.plan(9)
421
422 const stream = split(JSON.parse)
423 const fastify = Fastify({
424 logger: {
425 stream: stream,
426 level: 'info',
427 serializers: {
428 req: function (req) {
429 return {
430 url: req.url
431 }
432 }
433 }
434 }
435 })
436
437 fastify.get('/custom', function (req, reply) {
438 t.ok(req.log)
439 reply.send(new Error('kaboom'))
440 })
441
442 fastify.listen(0, err => {
443 t.error(err)
444 fastify.server.unref()
445
446 http.get('http://localhost:' + fastify.server.address().port + '/custom')
447 stream.once('data', listenAtLogLine => {
448 t.ok(listenAtLogLine, 'listen at log message is ok')
449
450 stream.once('data', line => {
451 t.ok(line.req, 'req is defined')
452 t.equal(line.msg, 'incoming request', 'message is set')
453 t.deepEqual(line.req, { url: '/custom' }, 'custom req serialiser is use')
454
455 stream.once('data', line => {
456 t.ok(line.res, 'res is defined')
457 t.equal(line.msg, 'kaboom', 'message is set')
458 t.deepEqual(line.res, { statusCode: 500 }, 'default res serialiser is use')
459 })
460 })
461 })
462 })
463})
464
465test('reply.send logs an error if called twice in a row', t => {
466 const lines = ['incoming request', 'request completed', 'Reply already sent', 'Reply already sent']
467 t.plan(lines.length + 2)
468
469 const splitStream = split(JSON.parse)
470 splitStream.on('data', (line) => {
471 t.is(line.msg, lines.shift())
472 })
473
474 const logger = pino(splitStream)
475
476 const fastify = Fastify({
477 logger
478 })
479
480 fastify.get('/', (req, reply) => {
481 reply.send({ hello: 'world' })
482 reply.send({ hello: 'world2' })
483 reply.send({ hello: 'world3' })
484 })
485
486 fastify.inject({
487 method: 'GET',
488 url: '/'
489 }, (err, res) => {
490 t.error(err)
491 const payload = JSON.parse(res.payload)
492 t.deepEqual(payload, { hello: 'world' })
493 })
494})
495
496test('logger can be silented', t => {
497 t.plan(17)
498 const fastify = Fastify({
499 logger: false
500 })
501 t.ok(fastify.log)
502 t.is(typeof fastify.log, 'object')
503 t.is(typeof fastify.log.fatal, 'function')
504 t.is(typeof fastify.log.error, 'function')
505 t.is(typeof fastify.log.warn, 'function')
506 t.is(typeof fastify.log.info, 'function')
507 t.is(typeof fastify.log.debug, 'function')
508 t.is(typeof fastify.log.trace, 'function')
509 t.is(typeof fastify.log.child, 'function')
510
511 const childLog = fastify.log.child()
512
513 t.is(typeof childLog, 'object')
514 t.is(typeof childLog.fatal, 'function')
515 t.is(typeof childLog.error, 'function')
516 t.is(typeof childLog.warn, 'function')
517 t.is(typeof childLog.info, 'function')
518 t.is(typeof childLog.debug, 'function')
519 t.is(typeof childLog.trace, 'function')
520 t.is(typeof childLog.child, 'function')
521})
522
523test('Should set a custom logLevel for a plugin', t => {
524 const lines = ['incoming request', 'Hello', 'request completed']
525 t.plan(7)
526
527 const splitStream = split(JSON.parse)
528 splitStream.on('data', (line) => {
529 t.is(line.msg, lines.shift())
530 })
531
532 const logger = pino({ level: 'error' }, splitStream)
533
534 const fastify = Fastify({
535 logger
536 })
537
538 fastify.get('/', (req, reply) => {
539 req.log.info('Hello') // we should not see this log
540 reply.send({ hello: 'world' })
541 })
542
543 fastify.register(function (instance, opts, next) {
544 instance.get('/plugin', (req, reply) => {
545 req.log.info('Hello') // we should see this log
546 reply.send({ hello: 'world' })
547 })
548 next()
549 }, { logLevel: 'info' })
550
551 fastify.inject({
552 method: 'GET',
553 url: '/'
554 }, (err, res) => {
555 t.error(err)
556 const payload = JSON.parse(res.payload)
557 t.deepEqual(payload, { hello: 'world' })
558 })
559
560 fastify.inject({
561 method: 'GET',
562 url: '/plugin'
563 }, (err, res) => {
564 t.error(err)
565 const payload = JSON.parse(res.payload)
566 t.deepEqual(payload, { hello: 'world' })
567 })
568})
569
570test('Should set a custom logSerializers for a plugin', t => {
571 t.plan(3)
572
573 const splitStream = split(JSON.parse)
574 splitStream.on('data', (line) => {
575 if (line.test) {
576 t.is(line.test, 'XHello')
577 }
578 })
579
580 const logger = pino({ level: 'error' }, splitStream)
581
582 const fastify = Fastify({
583 logger
584 })
585
586 fastify.register(function (instance, opts, next) {
587 instance.get('/plugin', (req, reply) => {
588 req.log.info({ test: 'Hello' }) // we should see this log
589 reply.send({ hello: 'world' })
590 })
591 next()
592 }, { logLevel: 'info', logSerializers: { test: value => 'X' + value } })
593
594 fastify.inject({
595 method: 'GET',
596 url: '/plugin'
597 }, (err, res) => {
598 t.error(err)
599 const payload = JSON.parse(res.payload)
600 t.deepEqual(payload, { hello: 'world' })
601 })
602})
603
604test('Should set a custom logLevel for every plugin', t => {
605 const lines = ['incoming request', 'request completed', 'info', 'debug']
606 t.plan(18)
607
608 const splitStream = split(JSON.parse)
609 splitStream.on('data', (line) => {
610 t.ok(line.level === 30 || line.level === 20)
611 t.ok(lines.indexOf(line.msg) > -1)
612 })
613
614 const logger = pino({ level: 'error' }, splitStream)
615
616 const fastify = Fastify({
617 logger
618 })
619
620 fastify.get('/', (req, reply) => {
621 req.log.warn('Hello') // we should not see this log
622 reply.send({ hello: 'world' })
623 })
624
625 fastify.register(function (instance, opts, next) {
626 instance.get('/info', (req, reply) => {
627 req.log.info('info') // we should see this log
628 req.log.debug('hidden log')
629 reply.send({ hello: 'world' })
630 })
631 next()
632 }, { logLevel: 'info' })
633
634 fastify.register(function (instance, opts, next) {
635 instance.get('/debug', (req, reply) => {
636 req.log.debug('debug') // we should see this log
637 req.log.trace('hidden log')
638 reply.send({ hello: 'world' })
639 })
640 next()
641 }, { logLevel: 'debug' })
642
643 fastify.inject({
644 method: 'GET',
645 url: '/'
646 }, (err, res) => {
647 t.error(err)
648 const payload = JSON.parse(res.payload)
649 t.deepEqual(payload, { hello: 'world' })
650 })
651
652 fastify.inject({
653 method: 'GET',
654 url: '/info'
655 }, (err, res) => {
656 t.error(err)
657 const payload = JSON.parse(res.payload)
658 t.deepEqual(payload, { hello: 'world' })
659 })
660
661 fastify.inject({
662 method: 'GET',
663 url: '/debug'
664 }, (err, res) => {
665 t.error(err)
666 const payload = JSON.parse(res.payload)
667 t.deepEqual(payload, { hello: 'world' })
668 })
669})
670
671test('Should set a custom logSerializers for every plugin', t => {
672 const lines = ['Hello', 'XHello', 'ZHello']
673 t.plan(9)
674
675 const splitStream = split(JSON.parse)
676 splitStream.on('data', (line) => {
677 if (line.test) {
678 t.is(line.test, lines.shift())
679 }
680 })
681
682 const logger = pino({ level: 'info' }, splitStream)
683 const fastify = Fastify({
684 logger
685 })
686
687 fastify.get('/', (req, reply) => {
688 req.log.warn({ test: 'Hello' })
689 reply.send({ hello: 'world' })
690 })
691
692 fastify.register(function (instance, opts, next) {
693 instance.get('/test1', (req, reply) => {
694 req.log.info({ test: 'Hello' })
695 reply.send({ hello: 'world' })
696 })
697 next()
698 }, { logSerializers: { test: value => 'X' + value } })
699
700 fastify.register(function (instance, opts, next) {
701 instance.get('/test2', (req, reply) => {
702 req.log.info({ test: 'Hello' })
703 reply.send({ hello: 'world' })
704 })
705 next()
706 }, { logSerializers: { test: value => 'Z' + value } })
707
708 fastify.inject({
709 method: 'GET',
710 url: '/'
711 }, (err, res) => {
712 t.error(err)
713 const payload = JSON.parse(res.payload)
714 t.deepEqual(payload, { hello: 'world' })
715 })
716
717 fastify.inject({
718 method: 'GET',
719 url: '/test1'
720 }, (err, res) => {
721 t.error(err)
722 const payload = JSON.parse(res.payload)
723 t.deepEqual(payload, { hello: 'world' })
724 })
725
726 fastify.inject({
727 method: 'GET',
728 url: '/test2'
729 }, (err, res) => {
730 t.error(err)
731 const payload = JSON.parse(res.payload)
732 t.deepEqual(payload, { hello: 'world' })
733 })
734})
735
736test('Should override serializers from route', t => {
737 t.plan(3)
738
739 const splitStream = split(JSON.parse)
740 splitStream.on('data', (line) => {
741 if (line.test) {
742 t.is(line.test, 'ZHello')
743 }
744 })
745
746 const logger = pino({ level: 'info' }, splitStream)
747 const fastify = Fastify({
748 logger
749 })
750
751 fastify.register(function (instance, opts, next) {
752 instance.get('/', {
753 logSerializers: {
754 test: value => 'Z' + value // should override
755 }
756 }, (req, reply) => {
757 req.log.info({ test: 'Hello' })
758 reply.send({ hello: 'world' })
759 })
760 next()
761 }, { logSerializers: { test: value => 'X' + value } })
762
763 fastify.inject({
764 method: 'GET',
765 url: '/'
766 }, (err, res) => {
767 t.error(err)
768 const payload = JSON.parse(res.payload)
769 t.deepEqual(payload, { hello: 'world' })
770 })
771})
772
773test('Should override serializers from plugin', t => {
774 t.plan(3)
775
776 const splitStream = split(JSON.parse)
777 splitStream.on('data', (line) => {
778 if (line.test) {
779 t.is(line.test, 'ZHello')
780 }
781 })
782
783 const logger = pino({ level: 'info' }, splitStream)
784 const fastify = Fastify({
785 logger
786 })
787
788 fastify.register(function (instance, opts, next) {
789 instance.register(context1, {
790 logSerializers: {
791 test: value => 'Z' + value // should override
792 }
793 })
794 next()
795 }, { logSerializers: { test: value => 'X' + value } })
796
797 function context1 (instance, opts, next) {
798 instance.get('/', (req, reply) => {
799 req.log.info({ test: 'Hello' })
800 reply.send({ hello: 'world' })
801 })
802 next()
803 }
804
805 fastify.inject({
806 method: 'GET',
807 url: '/'
808 }, (err, res) => {
809 t.error(err)
810 const payload = JSON.parse(res.payload)
811 t.deepEqual(payload, { hello: 'world' })
812 })
813})
814
815test('Should use serializers from plugin and route', t => {
816 t.plan(4)
817
818 const splitStream = split(JSON.parse)
819 splitStream.on('data', (line) => {
820 if (line.test) {
821 t.is(line.test, 'XHello')
822 }
823 if (line.test2) {
824 t.is(line.test2, 'ZHello')
825 }
826 })
827
828 const logger = pino({ level: 'info' }, splitStream)
829 const fastify = Fastify({
830 logger
831 })
832
833 fastify.register(context1, {
834 logSerializers: { test: value => 'X' + value }
835 })
836
837 function context1 (instance, opts, next) {
838 instance.get('/', {
839 logSerializers: {
840 test2: value => 'Z' + value
841 }
842 }, (req, reply) => {
843 req.log.info({ test: 'Hello', test2: 'Hello' }) // { test: 'XHello', test2: 'ZHello' }
844 reply.send({ hello: 'world' })
845 })
846 next()
847 }
848
849 fastify.inject({
850 method: 'GET',
851 url: '/'
852 }, (err, res) => {
853 t.error(err)
854 const payload = JSON.parse(res.payload)
855 t.deepEqual(payload, { hello: 'world' })
856 })
857})
858
859test('Should use serializers from instance fastify and route', t => {
860 t.plan(4)
861
862 const splitStream = split(JSON.parse)
863 splitStream.on('data', (line) => {
864 if (line.test) {
865 t.is(line.test, 'XHello')
866 }
867 if (line.test2) {
868 t.is(line.test2, 'ZHello')
869 }
870 })
871
872 const logger = pino({
873 level: 'info',
874 serializers: {
875 test: value => 'X' + value,
876 test2: value => 'This should be override - ' + value
877 }
878 }, splitStream)
879 const fastify = Fastify({
880 logger
881 })
882
883 fastify.get('/', {
884 logSerializers: {
885 test2: value => 'Z' + value
886 }
887 }, (req, reply) => {
888 req.log.info({ test: 'Hello', test2: 'Hello' }) // { test: 'XHello', test2: 'ZHello' }
889 reply.send({ hello: 'world' })
890 })
891
892 fastify.inject({
893 method: 'GET',
894 url: '/'
895 }, (err, res) => {
896 t.error(err)
897 const payload = JSON.parse(res.payload)
898 t.deepEqual(payload, { hello: 'world' })
899 })
900})
901
902test('Should use serializers inherit from contexts', t => {
903 t.plan(5)
904
905 const splitStream = split(JSON.parse)
906 splitStream.on('data', (line) => {
907 if (line.test && line.test2 && line.test3) {
908 t.is(line.test, 'XHello')
909 t.is(line.test2, 'YHello')
910 t.is(line.test3, 'ZHello')
911 }
912 })
913
914 const logger = pino({
915 level: 'info',
916 serializers: {
917 test: value => 'X' + value
918 }
919 }, splitStream)
920
921 const fastify = Fastify({ logger })
922 fastify.register(context1, { logSerializers: { test2: value => 'Y' + value } })
923
924 function context1 (instance, opts, next) {
925 instance.get('/', {
926 logSerializers: {
927 test3: value => 'Z' + value
928 }
929 }, (req, reply) => {
930 req.log.info({ test: 'Hello', test2: 'Hello', test3: 'Hello' }) // { test: 'XHello', test2: 'YHello', test3: 'ZHello' }
931 reply.send({ hello: 'world' })
932 })
933 next()
934 }
935
936 fastify.inject({
937 method: 'GET',
938 url: '/'
939 }, (err, res) => {
940 t.error(err)
941 const payload = JSON.parse(res.payload)
942 t.deepEqual(payload, { hello: 'world' })
943 })
944})
945
946test('Should increase the log level for a specific plugin', t => {
947 t.plan(4)
948
949 const splitStream = split(JSON.parse)
950 splitStream.on('data', (line) => {
951 t.is(line.msg, 'Hello')
952 t.ok(line.level === 50)
953 })
954
955 const logger = pino({ level: 'info' }, splitStream)
956
957 const fastify = Fastify({
958 logger
959 })
960
961 fastify.register(function (instance, opts, next) {
962 instance.get('/', (req, reply) => {
963 req.log.error('Hello') // we should see this log
964 reply.send({ hello: 'world' })
965 })
966 next()
967 }, { logLevel: 'error' })
968
969 fastify.inject({
970 method: 'GET',
971 url: '/'
972 }, (err, res) => {
973 t.error(err)
974 const payload = JSON.parse(res.payload)
975 t.deepEqual(payload, { hello: 'world' })
976 })
977})
978
979test('Should set the log level for the customized 404 handler', t => {
980 t.plan(4)
981
982 const splitStream = split(JSON.parse)
983 splitStream.on('data', (line) => {
984 t.is(line.msg, 'Hello')
985 t.ok(line.level === 50)
986 })
987
988 const logger = pino({ level: 'warn' }, splitStream)
989
990 const fastify = Fastify({
991 logger
992 })
993
994 fastify.register(function (instance, opts, next) {
995 instance.setNotFoundHandler(function (req, reply) {
996 req.log.error('Hello')
997 reply.code(404).send()
998 })
999 next()
1000 }, { logLevel: 'error' })
1001
1002 fastify.inject({
1003 method: 'GET',
1004 url: '/'
1005 }, (err, res) => {
1006 t.error(err)
1007 t.strictEqual(res.statusCode, 404)
1008 })
1009})
1010
1011test('Should set the log level for the customized 500 handler', t => {
1012 t.plan(4)
1013
1014 const splitStream = split(JSON.parse)
1015 splitStream.on('data', (line) => {
1016 t.is(line.msg, 'Hello')
1017 t.ok(line.level === 60)
1018 })
1019
1020 const logger = pino({ level: 'warn' }, splitStream)
1021
1022 const fastify = Fastify({
1023 logger
1024 })
1025
1026 fastify.register(function (instance, opts, next) {
1027 instance.get('/', (req, reply) => {
1028 req.log.error('kaboom')
1029 reply.send(new Error('kaboom'))
1030 })
1031
1032 instance.setErrorHandler(function (e, request, reply) {
1033 reply.log.fatal('Hello')
1034 reply.code(500).send()
1035 })
1036 next()
1037 }, { logLevel: 'fatal' })
1038
1039 fastify.inject({
1040 method: 'GET',
1041 url: '/'
1042 }, (err, res) => {
1043 t.error(err)
1044 t.strictEqual(res.statusCode, 500)
1045 })
1046})
1047
1048test('Should set a custom log level for a specific route', t => {
1049 const lines = ['incoming request', 'Hello', 'request completed']
1050 t.plan(7)
1051
1052 const splitStream = split(JSON.parse)
1053 splitStream.on('data', (line) => {
1054 t.is(line.msg, lines.shift())
1055 })
1056
1057 const logger = pino({ level: 'error' }, splitStream)
1058
1059 const fastify = Fastify({
1060 logger
1061 })
1062
1063 fastify.get('/log', { logLevel: 'info' }, (req, reply) => {
1064 req.log.info('Hello')
1065 reply.send({ hello: 'world' })
1066 })
1067
1068 fastify.get('/no-log', (req, reply) => {
1069 req.log.info('Hello')
1070 reply.send({ hello: 'world' })
1071 })
1072
1073 fastify.inject({
1074 method: 'GET',
1075 url: '/log'
1076 }, (err, res) => {
1077 t.error(err)
1078 const payload = JSON.parse(res.payload)
1079 t.deepEqual(payload, { hello: 'world' })
1080 })
1081
1082 fastify.inject({
1083 method: 'GET',
1084 url: '/no-log'
1085 }, (err, res) => {
1086 t.error(err)
1087 const payload = JSON.parse(res.payload)
1088 t.deepEqual(payload, { hello: 'world' })
1089 })
1090})
1091
1092test('The default 404 handler logs the incoming request', t => {
1093 t.plan(5)
1094
1095 const expectedMessages = [
1096 'incoming request',
1097 'Route GET:/not-found not found',
1098 'request completed'
1099 ]
1100
1101 const splitStream = split(JSON.parse)
1102 splitStream.on('data', (line) => {
1103 t.is(line.msg, expectedMessages.shift())
1104 })
1105
1106 const logger = pino({ level: 'trace' }, splitStream)
1107
1108 const fastify = Fastify({
1109 logger
1110 })
1111
1112 fastify.inject({
1113 method: 'GET',
1114 url: '/not-found'
1115 }, (err, res) => {
1116 t.error(err)
1117 t.strictEqual(res.statusCode, 404)
1118 })
1119})
1120
1121test('should serialize request and response', t => {
1122 t.plan(3)
1123 const lines = []
1124 const dest = new stream.Writable({
1125 write: function (chunk, enc, cb) {
1126 lines.push(JSON.parse(chunk))
1127 cb()
1128 }
1129 })
1130 const fastify = Fastify({ logger: { level: 'info', stream: dest } })
1131
1132 fastify.get('/500', (req, reply) => {
1133 reply.code(500).send(Error('500 error'))
1134 })
1135
1136 fastify.inject({
1137 url: '/500',
1138 method: 'GET'
1139 }, (e, res) => {
1140 const l = lines.find((line) => line.res && line.res.statusCode === 500)
1141 t.ok(l.req)
1142 t.is(l.req.method, 'GET')
1143 t.is(l.req.url, '/500')
1144 })
1145})
1146
1147{
1148 const interfaces = os.networkInterfaces()
1149 const ipv6 = Object.keys(interfaces)
1150 .filter(name => name.substr(0, 2) === 'lo')
1151 .map(name => interfaces[name])
1152 .reduce((list, set) => list.concat(set), [])
1153 .filter(info => info.family === 'IPv6')
1154 .map(info => info.address)
1155 .shift()
1156
1157 if (ipv6 !== undefined) {
1158 test('Wrap IPv6 address in listening log message', t => {
1159 t.plan(2)
1160 const stream = split(JSON.parse)
1161 const fastify = Fastify({
1162 logger: {
1163 stream: stream,
1164 level: 'info'
1165 }
1166 })
1167 fastify.listen(0, ipv6, err => {
1168 t.error(err)
1169 stream.once('data', line => {
1170 const expected = 'Server listening at http://[' + ipv6 + ']:' +
1171 fastify.server.address().port
1172 t.is(line.msg, expected)
1173 fastify.close()
1174 })
1175 })
1176 })
1177 }
1178}
1179
1180test('Do not wrap IPv4 address', t => {
1181 t.plan(2)
1182 const stream = split(JSON.parse)
1183 const fastify = Fastify({
1184 logger: {
1185 stream: stream,
1186 level: 'info'
1187 }
1188 })
1189 fastify.listen(0, '127.0.0.1', err => {
1190 t.error(err)
1191 stream.once('data', line => {
1192 const expected = 'Server listening at http://127.0.0.1:' +
1193 fastify.server.address().port
1194 t.is(line.msg, expected)
1195 fastify.close()
1196 })
1197 })
1198})
1199
1200test('file option', t => {
1201 t.plan(13)
1202 var fastify = null
1203 var dest = file()
1204
1205 fastify = Fastify({
1206 logger: {
1207 file: dest
1208 }
1209 })
1210
1211 fastify.get('/', function (req, reply) {
1212 t.ok(req.log)
1213 reply.send({ hello: 'world' })
1214 })
1215
1216 fastify.listen(0, err => {
1217 t.error(err)
1218 fastify.server.unref()
1219
1220 http.get('http://localhost:' + fastify.server.address().port, () => {
1221 const stream = fs.createReadStream(dest).pipe(split(JSON.parse))
1222
1223 stream.once('data', listenAtLogLine => {
1224 t.ok(listenAtLogLine, 'listen at log message is ok')
1225
1226 stream.once('data', line => {
1227 const id = line.reqId
1228 t.ok(line.reqId, 'reqId is defined')
1229 t.ok(line.req, 'req is defined')
1230 t.equal(line.msg, 'incoming request', 'message is set')
1231 t.equal(line.req.method, 'GET', 'method is get')
1232
1233 stream.once('data', line => {
1234 t.equal(line.reqId, id)
1235 t.ok(line.reqId, 'reqId is defined')
1236 t.ok(line.res, 'res is defined')
1237 t.equal(line.msg, 'request completed', 'message is set')
1238 t.equal(line.res.statusCode, 200, 'statusCode is 200')
1239 t.ok(line.responseTime, 'responseTime is defined')
1240 stream.resume()
1241 })
1242 })
1243 })
1244 })
1245 })
1246})
1247
1248test('should log the error if no error handler is defined', t => {
1249 t.plan(8)
1250 const stream = split(JSON.parse)
1251 const fastify = Fastify({
1252 logger: {
1253 stream: stream,
1254 level: 'info'
1255 }
1256 })
1257 fastify.get('/error', function (req, reply) {
1258 t.ok(req.log)
1259 reply.send(new Error('a generic error'))
1260 })
1261 fastify.listen(0, err => {
1262 t.error(err)
1263 fastify.server.unref()
1264 http.get('http://localhost:' + fastify.server.address().port + '/error')
1265 stream.once('data', listenAtLogLine => {
1266 t.ok(listenAtLogLine, 'listen at log message is ok')
1267 stream.once('data', line => {
1268 t.equal(line.msg, 'incoming request', 'message is set')
1269 stream.once('data', line => {
1270 t.equal(line.level, 50, 'level is correct')
1271 t.equal(line.msg, 'a generic error', 'message is set')
1272 stream.once('data', line => {
1273 t.equal(line.msg, 'request completed', 'message is set')
1274 t.deepEqual(line.res, { statusCode: 500 }, 'status code is set')
1275 })
1276 })
1277 })
1278 })
1279 })
1280})
1281
1282test('should log as info if error status code >= 400 and < 500 if no error handler is defined', t => {
1283 t.plan(8)
1284 const stream = split(JSON.parse)
1285 const fastify = Fastify({
1286 logger: {
1287 stream: stream,
1288 level: 'info'
1289 }
1290 })
1291 fastify.get('/400', function (req, reply) {
1292 t.ok(req.log)
1293 reply.send(Object.assign(new Error('a 400 error'), { statusCode: 400 }))
1294 })
1295 fastify.get('/503', function (req, reply) {
1296 t.ok(req.log)
1297 reply.send(Object.assign(new Error('a 503 error'), { statusCode: 503 }))
1298 })
1299 fastify.listen(0, err => {
1300 t.error(err)
1301 fastify.server.unref()
1302 http.get('http://localhost:' + fastify.server.address().port + '/400')
1303 stream.once('data', listenAtLogLine => {
1304 t.ok(listenAtLogLine, 'listen at log message is ok')
1305 stream.once('data', line => {
1306 t.equal(line.msg, 'incoming request', 'message is set')
1307 stream.once('data', line => {
1308 t.equal(line.level, 30, 'level is correct')
1309 t.equal(line.msg, 'a 400 error', 'message is set')
1310 stream.once('data', line => {
1311 t.equal(line.msg, 'request completed', 'message is set')
1312 t.deepEqual(line.res, { statusCode: 400 }, 'status code is set')
1313 })
1314 })
1315 })
1316 })
1317 })
1318})
1319
1320test('should log as error if error status code >= 500 if no error handler is defined', t => {
1321 t.plan(8)
1322 const stream = split(JSON.parse)
1323 const fastify = Fastify({
1324 logger: {
1325 stream: stream,
1326 level: 'info'
1327 }
1328 })
1329 fastify.get('/503', function (req, reply) {
1330 t.ok(req.log)
1331 reply.send(Object.assign(new Error('a 503 error'), { statusCode: 503 }))
1332 })
1333 fastify.listen(0, err => {
1334 t.error(err)
1335 fastify.server.unref()
1336 http.get('http://localhost:' + fastify.server.address().port + '/503')
1337 stream.once('data', listenAtLogLine => {
1338 t.ok(listenAtLogLine, 'listen at log message is ok')
1339 stream.once('data', line => {
1340 t.equal(line.msg, 'incoming request', 'message is set')
1341 stream.once('data', line => {
1342 t.equal(line.level, 50, 'level is correct')
1343 t.equal(line.msg, 'a 503 error', 'message is set')
1344 stream.once('data', line => {
1345 t.equal(line.msg, 'request completed', 'message is set')
1346 t.deepEqual(line.res, { statusCode: 503 }, 'status code is set')
1347 })
1348 })
1349 })
1350 })
1351 })
1352})
1353
1354test('should not log the error if error handler is defined', t => {
1355 t.plan(7)
1356 const stream = split(JSON.parse)
1357 const fastify = Fastify({
1358 logger: {
1359 stream: stream,
1360 level: 'info'
1361 }
1362 })
1363 fastify.get('/error', function (req, reply) {
1364 t.ok(req.log)
1365 reply.send(new Error('something happened'))
1366 })
1367 fastify.setErrorHandler((err, req, reply) => {
1368 reply.send(err)
1369 })
1370 fastify.listen(0, err => {
1371 t.error(err)
1372 fastify.server.unref()
1373 http.get('http://localhost:' + fastify.server.address().port + '/error')
1374 stream.once('data', listenAtLogLine => {
1375 t.ok(listenAtLogLine, 'listen at log message is ok')
1376 stream.once('data', line => {
1377 t.equal(line.msg, 'incoming request', 'message is set')
1378 stream.once('data', line => {
1379 t.equal(line.level, 30, 'level is correct')
1380 t.equal(line.msg, 'request completed', 'message is set')
1381 t.deepEqual(line.res, { statusCode: 500 }, 'status code is set')
1382 })
1383 })
1384 })
1385 })
1386})
1387
1388test('should not rely on raw request to log errors', t => {
1389 t.plan(7)
1390 const stream = split(JSON.parse)
1391 const fastify = Fastify({
1392 modifyCoreObjects: false,
1393 logger: {
1394 stream: stream,
1395 level: 'info'
1396 }
1397 })
1398 fastify.get('/error', function (req, reply) {
1399 t.ok(req.log)
1400 reply.status(415).send(new Error('something happened'))
1401 })
1402 fastify.listen(0, err => {
1403 t.error(err)
1404 fastify.server.unref()
1405 http.get('http://localhost:' + fastify.server.address().port + '/error')
1406 stream.once('data', listenAtLogLine => {
1407 t.ok(listenAtLogLine, 'listen at log message is ok')
1408 stream.once('data', line => {
1409 t.equal(line.msg, 'incoming request', 'message is set')
1410 stream.once('data', line => {
1411 t.equal(line.level, 30, 'level is correct')
1412 t.equal(line.msg, 'something happened', 'message is set')
1413 t.deepEqual(line.res, { statusCode: 415 }, 'status code is set')
1414 })
1415 })
1416 })
1417 })
1418})
1419
1420test('should redact the authorization header if so specified', t => {
1421 t.plan(7)
1422 const stream = split(JSON.parse)
1423 const fastify = Fastify({
1424 logger: {
1425 stream: stream,
1426 redact: ['req.headers.authorization'],
1427 level: 'info',
1428 serializers: {
1429 req (req) {
1430 return {
1431 method: req.method,
1432 url: req.url,
1433 headers: req.headers,
1434 hostname: req.hostname,
1435 remoteAddress: req.ip,
1436 remotePort: req.connection.remotePort
1437 }
1438 }
1439 }
1440 }
1441 })
1442 fastify.get('/', function (req, reply) {
1443 t.is(req.headers.authorization, 'Bearer abcde')
1444 reply.send({ hello: 'world' })
1445 })
1446 stream.once('data', listenAtLogLine => {
1447 t.ok(listenAtLogLine, 'listen at log message is ok')
1448 stream.once('data', line => {
1449 t.equal(line.req.headers.authorization, '[Redacted]', 'authorization is redacted')
1450 })
1451 })
1452 fastify.listen(0, err => {
1453 t.error(err)
1454 fastify.server.unref()
1455 sget({
1456 method: 'GET',
1457 url: 'http://localhost:' + fastify.server.address().port,
1458 headers: {
1459 authorization: 'Bearer abcde'
1460 }
1461 }, (err, response, body) => {
1462 t.error(err)
1463 t.strictEqual(response.statusCode, 200)
1464 t.deepEqual(body.toString(), JSON.stringify({ hello: 'world' }))
1465 })
1466 })
1467})
1468
1469test('should not log incoming request and outgoing response when disabled', t => {
1470 t.plan(3)
1471 const lines = []
1472 const dest = new stream.Writable({
1473 write: function (chunk, enc, cb) {
1474 lines.push(JSON.parse(chunk))
1475 cb()
1476 }
1477 })
1478 const fastify = Fastify({ disableRequestLogging: true, logger: { level: 'info', stream: dest } })
1479
1480 fastify.get('/500', (req, reply) => {
1481 reply.code(500).send(Error('500 error'))
1482 })
1483
1484 fastify.inject({
1485 url: '/500',
1486 method: 'GET'
1487 }, (e, res) => {
1488 t.is(lines.length, 1)
1489 t.ok(lines[0].msg)
1490 t.is(lines[0].msg, '500 error')
1491 })
1492})