Frames

Untitled

0
1
2
1var prettyBytes = require('prettier-bytes')
2var jsonParse = require('fast-json-parse')
3var prettyMs = require('pretty-ms')
4var padLeft = require('pad-left')
5var indent = require('indent')
6var split = require('split2')
7var chalk = require('chalk')
8
9var nl = '\n'
10var emojiLog = {
11 warn: '⚠️',
12 info: '✨',
13 error: '🚨',
14 debug: '🐛',
15 fatal: '💀',
16 trace: '🔍'
17}
18var lineLimit = 100
19var pinoKeys = [
20 'level',
21 'time',
22 'msg',
23 'message',
24 'pid',
25 'hostname',
26 'name',
27 'ns',
28 'v',
29 'req',
30 'res',
31 'statusCode',
32 'responseTime',
33 'elapsed',
34 'method',
35 'contentLength',
36 'url'
37]
38var verbose = process.argv.includes('-v')
39
40module.exports = PinoGris
41
42function PinoGris () {
43 return split(parse)
44}
45
46function parse (line) {
47 var obj = jsonParse(line)
48 if (!obj.value || obj.err) return line + nl
49 obj = obj.value
50
51 if (!obj.level) return line + nl
52 if (typeof obj.level === 'number') convertLogNumber(obj)
53
54 return output(obj) + nl
55}
56
57function convertLogNumber (obj) {
58 if (!obj.message) obj.message = obj.msg
59 if (obj.level === 10) obj.level = 'trace'
60 if (obj.level === 20) obj.level = 'debug'
61 if (obj.level === 30) obj.level = 'info'
62 if (obj.level === 40) obj.level = 'warn'
63 if (obj.level === 50) obj.level = 'error'
64 if (obj.level === 60) obj.level = 'fatal'
65}
66
67function output (obj) {
68 var output = []
69
70 if (!obj.level) obj.level = 'userlvl'
71 if (!obj.name) obj.name = ''
72 if (!obj.ns) obj.ns = ''
73
74 output.push(formatDate())
75 output.push(formatLevel(obj.level))
76 output.push(formatNs(obj.ns))
77 output.push(formatName(obj.name))
78 output.push(formatMessage(obj))
79
80 var req = obj.req
81 var res = obj.res
82 var statusCode = (res) ? res.statusCode : obj.statusCode
83 var responseTime = obj.responseTime || obj.elapsed
84 var method = (req) ? req.method : obj.method
85 var contentLength = obj.contentLength
86 var url = (req) ? req.url : obj.url
87
88 if (method != null) {
89 output.push(formatMethod(method))
90 output.push(formatStatusCode(statusCode))
91 }
92 if (url != null) output.push(formatUrl(url))
93 if (contentLength != null) output.push(formatBundleSize(contentLength))
94 if (responseTime != null) output.push(formatLoadTime(responseTime))
95 output.push(formatExtra(obj))
96
97 return output.filter(noEmpty).join(' ')
98}
99
100function formatDate () {
101 var date = new Date()
102 var hours = padLeft(date.getHours().toString(), 2, '0')
103 var minutes = padLeft(date.getMinutes().toString(), 2, '0')
104 var seconds = padLeft(date.getSeconds().toString(), 2, '0')
105 var prettyDate = hours + ':' + minutes + ':' + seconds
106 return chalk.gray(prettyDate)
107}
108
109function formatLevel (level) {
110 const emoji = emojiLog[level]
111 const padding = isWideEmoji(emoji) ? '' : ' '
112 return emoji + padding
113}
114
115function formatNs (name) {
116 return chalk.cyan(name)
117}
118
119function formatName (name) {
120 return chalk.blue(name)
121}
122
123function formatMessage (obj) {
124 var msg = formatMessageName(obj.message)
125 if (obj.level === 'error') return chalk.red(msg)
126 if (obj.level === 'trace') return chalk.white(msg)
127 if (obj.level === 'warn') return chalk.magenta(msg)
128 if (obj.level === 'debug') return chalk.yellow(msg)
129 if (obj.level === 'info' || obj.level === 'userlvl') return chalk.green(msg)
130 if (obj.level === 'fatal') return chalk.white.bgRed(msg)
131}
132
133function formatUrl (url) {
134 return chalk.white(url)
135}
136
137function formatMethod (method) {
138 return chalk.white(method)
139}
140
141function formatStatusCode (statusCode) {
142 statusCode = statusCode || 'xxx'
143 return chalk.white(statusCode)
144}
145
146function formatLoadTime (elapsedTime) {
147 var elapsed = parseInt(elapsedTime, 10)
148 var time = prettyMs(elapsed)
149 return chalk.gray(time)
150}
151
152function formatBundleSize (bundle) {
153 var bytes = parseInt(bundle, 10)
154 var size = prettyBytes(bytes).replace(/ /, '')
155 return chalk.gray(size)
156}
157
158function formatMessageName (message) {
159 if (message === 'request') return '<--'
160 if (message === 'response') return '-->'
161 return message
162}
163
164function formatExtra (obj) {
165 const extra = Object.keys(obj)
166 .filter(key => {
167 if (verbose) return true
168 return !pinoKeys.includes(key)
169 })
170 .reduce((acc, key) => {
171 acc[key] = obj[key]
172 return acc
173 }, {})
174
175 const extraKeys = Object.keys(extra)
176
177 if (extraKeys.length === 0) return ''
178
179 const content = nl + nl + extraKeys.map(key => {
180 let val = extra[key]
181 if (isObject(val)) val = JSON.stringify(val, null, 2)
182
183 // limit very long string values
184 if (!verbose && typeof val === 'string' && val.split('\n').length > lineLimit) {
185 let arr = val.split('\n').slice(0, lineLimit)
186 arr.push(`(truncated at ${lineLimit} lines)`)
187 val = arr.join('\n')
188 }
189 return chalk.gray(`${key}: ${val}`)
190 }).join(nl) + nl
191
192 return indent(content, 2)
193}
194
195function isObject (val) {
196 return val != null && typeof val === 'object' && Array.isArray(val) === false
197}
198
199function isWideEmoji (character) {
200 return character !== '⚠️'
201}
202
203function noEmpty (val) {
204 return !!val
205}
206