UNPKG

7.66 kBJavaScriptView Raw
1'use strict'
2
3const Writable = require('stream').Writable
4const os = require('os')
5const test = require('tap').test
6const pino = require('pino')
7const serializers = pino.stdSerializers
8const prettyFactory = require('../')
9
10// All dates are computed from 'Fri, 30 Mar 2018 17:35:28 GMT'
11const epoch = 1522431328992
12const pid = process.pid
13const hostname = os.hostname()
14
15test('error like objects tests', (t) => {
16 t.beforeEach((done) => {
17 Date.originalNow = Date.now
18 Date.now = () => epoch
19
20 done()
21 })
22 t.afterEach((done) => {
23 Date.now = Date.originalNow
24 delete Date.originalNow
25
26 done()
27 })
28
29 t.test('pino transform prettifies Error', (t) => {
30 t.plan(2)
31 const pretty = prettyFactory()
32 const err = Error('hello world')
33 const expected = err.stack.split('\n')
34 expected.unshift(err.message)
35
36 const log = pino({}, new Writable({
37 write (chunk, enc, cb) {
38 const formatted = pretty(chunk.toString())
39 const lines = formatted.split('\n')
40 t.is(lines.length, expected.length + 1)
41 t.is(lines[0], `[${epoch}] INFO (${pid} on ${hostname}): hello world`)
42 cb()
43 }
44 }))
45
46 log.info(err)
47 })
48
49 t.test('errorProps recognizes user specified properties', (t) => {
50 t.plan(3)
51 const pretty = prettyFactory({ errorProps: 'statusCode,originalStack' })
52 const log = pino({}, new Writable({
53 write (chunk, enc, cb) {
54 const formatted = pretty(chunk.toString())
55 t.match(formatted, /\s{4}error stack/)
56 t.match(formatted, /statusCode: 500/)
57 t.match(formatted, /originalStack: original stack/)
58 cb()
59 }
60 }))
61
62 const error = Error('error message')
63 error.stack = 'error stack'
64 error.statusCode = 500
65 error.originalStack = 'original stack'
66
67 log.error(error)
68 })
69
70 t.test('prettifies ignores undefined errorLikeObject', (t) => {
71 const pretty = prettyFactory()
72 pretty({ err: undefined })
73 pretty({ error: undefined })
74 t.end()
75 })
76
77 t.test('prettifies Error in property within errorLikeObjectKeys', (t) => {
78 t.plan(8)
79 const pretty = prettyFactory({
80 errorLikeObjectKeys: ['err']
81 })
82
83 const err = Error('hello world')
84 const expected = err.stack.split('\n')
85 expected.unshift(err.message)
86
87 const log = pino({ serializers: { err: serializers.err } }, new Writable({
88 write (chunk, enc, cb) {
89 const formatted = pretty(chunk.toString())
90 const lines = formatted.split('\n')
91 t.is(lines.length, expected.length + 6)
92 t.is(lines[0], `[${epoch}] INFO (${pid} on ${hostname}):`)
93 t.match(lines[1], /\s{4}err: {/)
94 t.match(lines[2], /\s{6}"type": "Error",/)
95 t.match(lines[3], /\s{6}"message": "hello world",/)
96 t.match(lines[4], /\s{6}"stack":/)
97 t.match(lines[5], /\s{6}Error: hello world/)
98 // Node 12 labels the test `<anonymous>`
99 t.match(lines[6], /\s{10}(at Test.t.test|at Test.<anonymous>)/)
100 cb()
101 }
102 }))
103
104 log.info({ err })
105 })
106
107 t.test('prettifies Error in property within errorLikeObjectKeys when stack has escaped characters', (t) => {
108 t.plan(8)
109 const pretty = prettyFactory({
110 errorLikeObjectKeys: ['err']
111 })
112
113 const err = Error('hello world')
114 err.stack = 'Error: hello world\n at anonymous (C:\\project\\node_modules\\example\\index.js)'
115 const expected = err.stack.split('\n')
116 expected.unshift(err.message)
117
118 const log = pino({ serializers: { err: serializers.err } }, new Writable({
119 write (chunk, enc, cb) {
120 const formatted = pretty(chunk.toString())
121 const lines = formatted.split('\n')
122 t.is(lines.length, expected.length + 6)
123 t.is(lines[0], `[${epoch}] INFO (${pid} on ${hostname}):`)
124 t.match(lines[1], /\s{4}err: {$/)
125 t.match(lines[2], /\s{6}"type": "Error",$/)
126 t.match(lines[3], /\s{6}"message": "hello world",$/)
127 t.match(lines[4], /\s{6}"stack":$/)
128 t.match(lines[5], /\s{10}Error: hello world$/)
129 t.match(lines[6], /\s{10}at anonymous \(C:\\project\\node_modules\\example\\index.js\)$/)
130 cb()
131 }
132 }))
133
134 log.info({ err })
135 })
136
137 t.test('prettifies Error in property within errorLikeObjectKeys when stack is not the last property', (t) => {
138 t.plan(9)
139 const pretty = prettyFactory({
140 errorLikeObjectKeys: ['err']
141 })
142
143 const err = Error('hello world')
144 err.anotherField = 'dummy value'
145 const expected = err.stack.split('\n')
146 expected.unshift(err.message)
147
148 const log = pino({ serializers: { err: serializers.err } }, new Writable({
149 write (chunk, enc, cb) {
150 const formatted = pretty(chunk.toString())
151 const lines = formatted.split('\n')
152 t.is(lines.length, expected.length + 7)
153 t.is(lines[0], `[${epoch}] INFO (${pid} on ${hostname}):`)
154 t.match(lines[1], /\s{4}err: {/)
155 t.match(lines[2], /\s{6}"type": "Error",/)
156 t.match(lines[3], /\s{6}"message": "hello world",/)
157 t.match(lines[4], /\s{6}"stack":/)
158 t.match(lines[5], /\s{6}Error: hello world/)
159 // Node 12 labels the test `<anonymous>`
160 t.match(lines[6], /\s{10}(at Test.t.test|at Test.<anonymous>)/)
161 t.match(lines[lines.length - 3], /\s{6}"anotherField": "dummy value"/)
162 cb()
163 }
164 }))
165
166 log.info({ err })
167 })
168
169 t.test('errorProps flag with "*" (print all nested props)', function (t) {
170 t.plan(9)
171 const pretty = prettyFactory({ errorProps: '*' })
172 const expectedLines = [
173 ' error stack',
174 'statusCode: 500',
175 'originalStack: original stack',
176 'dataBaseSpecificError: {',
177 ' erroMessage: "some database error message"',
178 ' evenMoreSpecificStuff: {',
179 ' "someErrorRelatedObject": "error"',
180 ' }',
181 '}'
182 ]
183 const log = pino({}, new Writable({
184 write (chunk, enc, cb) {
185 const formatted = pretty(chunk.toString())
186 const lines = formatted.split('\n')
187 lines.shift(); lines.pop()
188 for (var i = 0; i < lines.length; i += 1) {
189 t.is(lines[i], expectedLines[i])
190 }
191 cb()
192 }
193 }))
194
195 const error = Error('error message')
196 error.stack = 'error stack'
197 error.statusCode = 500
198 error.originalStack = 'original stack'
199 error.dataBaseSpecificError = {
200 erroMessage: 'some database error message',
201 evenMoreSpecificStuff: {
202 someErrorRelatedObject: 'error'
203 }
204 }
205
206 log.error(error)
207 })
208
209 t.test('handles errors with a null stack', (t) => {
210 t.plan(2)
211 const pretty = prettyFactory()
212 const log = pino({}, new Writable({
213 write (chunk, enc, cb) {
214 const formatted = pretty(chunk.toString())
215 t.match(formatted, /\s{4}message: "foo"/)
216 t.match(formatted, /\s{4}stack: null/)
217 cb()
218 }
219 }))
220
221 const error = { message: 'foo', stack: null }
222 log.error(error)
223 })
224
225 t.test('handles errors with a null stack for Error object', (t) => {
226 t.plan(3)
227 const pretty = prettyFactory()
228 const expectedLines = [
229 ' some: "property"',
230 ' stack: null',
231 ' type: "Error"'
232 ]
233 const log = pino({}, new Writable({
234 write (chunk, enc, cb) {
235 const formatted = pretty(chunk.toString())
236 const lines = formatted.split('\n')
237 lines.shift(); lines.pop()
238 for (var i = 0; i < lines.length; i += 1) {
239 t.true(expectedLines.includes(lines[i]))
240 }
241 cb()
242 }
243 }))
244
245 const error = Error('error message')
246 error.stack = null
247 error.some = 'property'
248
249 log.error(error)
250 })
251
252 t.end()
253})