UNPKG

4.78 kBJavaScriptView Raw
1'use strict'
2/* eslint no-prototype-builtins: 0 */
3const flatstr = require('flatstr')
4const {
5 lsCacheSym,
6 levelValSym,
7 useOnlyCustomLevelsSym,
8 streamSym,
9 formattersSym,
10 hooksSym
11} = require('./symbols')
12const { noop, genLog } = require('./tools')
13
14const levels = {
15 trace: 10,
16 debug: 20,
17 info: 30,
18 warn: 40,
19 error: 50,
20 fatal: 60
21}
22const levelMethods = {
23 fatal: (hook) => {
24 const logFatal = genLog(levels.fatal, hook)
25 return function (...args) {
26 const stream = this[streamSym]
27 logFatal.call(this, ...args)
28 if (typeof stream.flushSync === 'function') {
29 try {
30 stream.flushSync()
31 } catch (e) {
32 // https://github.com/pinojs/pino/pull/740#discussion_r346788313
33 }
34 }
35 }
36 },
37 error: (hook) => genLog(levels.error, hook),
38 warn: (hook) => genLog(levels.warn, hook),
39 info: (hook) => genLog(levels.info, hook),
40 debug: (hook) => genLog(levels.debug, hook),
41 trace: (hook) => genLog(levels.trace, hook)
42}
43
44const nums = Object.keys(levels).reduce((o, k) => {
45 o[levels[k]] = k
46 return o
47}, {})
48
49const initialLsCache = Object.keys(nums).reduce((o, k) => {
50 o[k] = flatstr('{"level":' + Number(k))
51 return o
52}, {})
53
54function genLsCache (instance) {
55 const formatter = instance[formattersSym].level
56 const { labels } = instance.levels
57 const cache = {}
58 for (const label in labels) {
59 const level = formatter(labels[label], Number(label))
60 cache[label] = JSON.stringify(level).slice(0, -1)
61 }
62 instance[lsCacheSym] = cache
63 return instance
64}
65
66function isStandardLevel (level, useOnlyCustomLevels) {
67 if (useOnlyCustomLevels) {
68 return false
69 }
70
71 switch (level) {
72 case 'fatal':
73 case 'error':
74 case 'warn':
75 case 'info':
76 case 'debug':
77 case 'trace':
78 return true
79 default:
80 return false
81 }
82}
83
84function setLevel (level) {
85 const { labels, values } = this.levels
86 if (typeof level === 'number') {
87 if (labels[level] === undefined) throw Error('unknown level value' + level)
88 level = labels[level]
89 }
90 if (values[level] === undefined) throw Error('unknown level ' + level)
91 const preLevelVal = this[levelValSym]
92 const levelVal = this[levelValSym] = values[level]
93 const useOnlyCustomLevelsVal = this[useOnlyCustomLevelsSym]
94 const hook = this[hooksSym].logMethod
95
96 for (var key in values) {
97 if (levelVal > values[key]) {
98 this[key] = noop
99 continue
100 }
101 this[key] = isStandardLevel(key, useOnlyCustomLevelsVal) ? levelMethods[key](hook) : genLog(values[key], hook)
102 }
103
104 this.emit(
105 'level-change',
106 level,
107 levelVal,
108 labels[preLevelVal],
109 preLevelVal
110 )
111}
112
113function getLevel (level) {
114 const { levels, levelVal } = this
115 return levels.labels[levelVal]
116}
117
118function isLevelEnabled (logLevel) {
119 const { values } = this.levels
120 const logLevelVal = values[logLevel]
121 return logLevelVal !== undefined && (logLevelVal >= this[levelValSym])
122}
123
124function mappings (customLevels = null, useOnlyCustomLevels = false) {
125 const customNums = customLevels ? Object.keys(customLevels).reduce((o, k) => {
126 o[customLevels[k]] = k
127 return o
128 }, {}) : null
129
130 const labels = Object.assign(
131 Object.create(Object.prototype, { Infinity: { value: 'silent' } }),
132 useOnlyCustomLevels ? null : nums,
133 customNums
134 )
135 const values = Object.assign(
136 Object.create(Object.prototype, { silent: { value: Infinity } }),
137 useOnlyCustomLevels ? null : levels,
138 customLevels
139 )
140 return { labels, values }
141}
142
143function assertDefaultLevelFound (defaultLevel, customLevels, useOnlyCustomLevels) {
144 if (typeof defaultLevel === 'number') {
145 const values = [].concat(
146 Object.keys(customLevels || {}).map(key => customLevels[key]),
147 useOnlyCustomLevels ? [] : Object.keys(nums).map(level => +level),
148 Infinity
149 )
150 if (!values.includes(defaultLevel)) {
151 throw Error(`default level:${defaultLevel} must be included in custom levels`)
152 }
153 return
154 }
155
156 const labels = Object.assign(
157 Object.create(Object.prototype, { silent: { value: Infinity } }),
158 useOnlyCustomLevels ? null : levels,
159 customLevels
160 )
161 if (!(defaultLevel in labels)) {
162 throw Error(`default level:${defaultLevel} must be included in custom levels`)
163 }
164}
165
166function assertNoLevelCollisions (levels, customLevels) {
167 const { labels, values } = levels
168 for (const k in customLevels) {
169 if (k in values) {
170 throw Error('levels cannot be overridden')
171 }
172 if (customLevels[k] in labels) {
173 throw Error('pre-existing level values cannot be used for new levels')
174 }
175 }
176}
177
178module.exports = {
179 initialLsCache,
180 genLsCache,
181 levelMethods,
182 getLevel,
183 setLevel,
184 isLevelEnabled,
185 mappings,
186 assertNoLevelCollisions,
187 assertDefaultLevelFound
188}