forked from hapijs/hapi-pino
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
182 lines (152 loc) · 5.29 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
'use strict'
const Hoek = require('hoek')
const pino = require('pino')
const { stdSerializers } = pino
const { serializersSym } = pino.symbols
const nullLogger = require('abstract-logging')
const levels = ['trace', 'debug', 'info', 'warn', 'error']
const levelTags = {
trace: 'trace',
debug: 'debug',
info: 'info',
warn: 'warn',
error: 'error'
}
async function register (server, options) {
// clone all user options to account for internal mutations, except for existing stream and pino instances
options = Object.assign(Hoek.clone(options), { stream: options.stream, instance: options.instance })
options.serializers = options.serializers || {}
options.serializers.req = stdSerializers.wrapRequestSerializer(options.serializers.req || stdSerializers.req)
options.serializers.res = stdSerializers.wrapResponseSerializer(options.serializers.res || stdSerializers.res)
options.serializers.err = options.serializers.err || pino.stdSerializers.err
if (options.logEvents === undefined) {
options.logEvents = ['onPostStart', 'onPostStop', 'response', 'request-error']
}
var logger
if (options.instance) {
logger = options.instance
const overrideDefaultErrorSerializer = (typeof options.serializers.err === 'function') &&
logger[serializersSym].err === stdSerializers.err
logger[serializersSym] = Object.assign({}, options.serializers, logger[serializersSym])
if (overrideDefaultErrorSerializer) {
logger[serializersSym].err = options.serializers.err
}
} else {
options.stream = options.stream || process.stdout
var stream = options.stream || process.stdout
logger = pino(options, stream)
}
const tagToLevels = Object.assign({}, levelTags, options.tags)
const allTags = options.allTags || 'info'
const validTags = Object.keys(tagToLevels).filter((key) => levels.indexOf(tagToLevels[key]) < 0).length === 0
if (!validTags || levels.indexOf(allTags) < 0) {
throw new Error('invalid tag levels')
}
const tagToLevelValue = {}
for (let tag in tagToLevels) {
tagToLevelValue[tag] = logger.levels.values[tagToLevels[tag]]
}
var ignoreTable = {}
if (options.ignorePaths) {
for (let i = 0; i < options.ignorePaths.length; i++) {
ignoreTable[options.ignorePaths[i]] = true
}
}
const mergeHapiLogData = options.mergeHapiLogData
// expose logger as 'server.logger()'
server.decorate('server', 'logger', () => logger)
// set a logger for each request
server.ext('onRequest', (request, h) => {
if (options.ignorePaths && ignoreTable[request.url.path]) {
request.logger = nullLogger
return h.continue
}
request.logger = logger.child({ req: request })
return h.continue
})
server.events.on('log', function (event) {
if (event.error) {
logger.warn({ err: event.error })
} else {
logEvent(logger, event)
}
})
// log via `request.log()` and optionally when an internal `accept-encoding`
// error occurs or request completes with an error
server.events.on('request', function (request, event, tags) {
if (event.channel === 'internal' && !tags['accept-encoding']) {
return
}
request.logger = request.logger || logger.child({ req: request })
if (event.error && isEnabledLogEvent(options, 'request-error')) {
request.logger.warn({
err: event.error
}, 'request error')
} else if (event.channel === 'app') {
logEvent(request.logger, event)
}
})
// log when a request completes
tryAddEvent(server, options, 'on', 'response', function (request) {
if (options.ignorePaths && ignoreTable[request.url.path]) {
return
}
const info = request.info
request.logger.info({
payload: options.logPayload ? request.payload : undefined,
tags: options.logRouteTags ? request.route.settings.tags : undefined,
res: request.raw.res,
responseTime: info.responded - info.received
}, 'request completed')
})
tryAddEvent(server, options, 'ext', 'onPostStart', async function (s) {
logger.info(server.info, 'server started')
})
tryAddEvent(server, options, 'ext', 'onPostStop', async function (s) {
logger.info(server.info, 'server stopped')
})
function isEnabledLogEvent (options, name) {
return options.logEvents && options.logEvents.indexOf(name) !== -1
}
function tryAddEvent (server, options, type, event, cb) {
var name = typeof event === 'string' ? event : event.name
if (isEnabledLogEvent(options, name)) {
if (type === 'on') {
server.events.on(event, cb)
} else if (type === 'ext') {
server.ext(event, cb)
} else {
throw new Error(`unsupported type ${type}`)
}
}
}
function logEvent (current, event) {
var tags = event.tags
var data = event.data
var logObject
if (mergeHapiLogData) {
if (typeof data === 'string') {
data = { msg: data }
}
logObject = Object.assign({ tags }, data)
} else {
logObject = { tags, data }
}
let highest = 0
for (let tag of tags) {
const level = tagToLevelValue[tag]
if (level && level > highest) {
highest = level
}
}
if (highest > 0) {
current[current.levels.labels[highest]](logObject)
} else {
current[allTags](logObject)
}
}
}
module.exports = {
register,
name: 'hapi-pino'
}