UNPKG

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