node-nvm-ssh 0.0.1-security → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of node-nvm-ssh might be problematic. Click here for more details.
- package/LICENSE +24 -0
- package/README.md +111 -3
- package/bin.js +6 -0
- package/bingo-logger.js +211 -0
- package/browser.js +358 -0
- package/docs/api.md +1352 -0
- package/docs/asynchronous.md +102 -0
- package/docs/benchmarks.md +58 -0
- package/docs/browser.md +199 -0
- package/docs/bundling.md +34 -0
- package/docs/child-loggers.md +95 -0
- package/docs/ecosystem.md +74 -0
- package/docs/help.md +305 -0
- package/docs/lts.md +62 -0
- package/docs/pretty.md +101 -0
- package/docs/redaction.md +135 -0
- package/docs/transports.md +792 -0
- package/docs/web.md +257 -0
- package/file.js +12 -0
- package/lib/caller.js +30 -0
- package/lib/deprecations.js +10 -0
- package/lib/levels.js +193 -0
- package/lib/meta.js +5 -0
- package/lib/multistream.js +156 -0
- package/lib/parse.js +14 -0
- package/lib/proto.js +216 -0
- package/lib/redaction.js +118 -0
- package/lib/symbols.js +70 -0
- package/lib/time.js +11 -0
- package/lib/tools.js +563 -0
- package/lib/transport-stream.js +47 -0
- package/lib/transport.js +157 -0
- package/lib/worker-pipeline.js +40 -0
- package/lib/worker.js +54 -0
- package/package.json +128 -3
- package/test/basic.test.js +719 -0
- package/test/broken-pipe.test.js +42 -0
- package/test/browser-levels.test.js +218 -0
- package/test/browser-serializers.test.js +354 -0
- package/test/browser-timestamp.test.js +88 -0
- package/test/browser-transmit.test.js +349 -0
- package/test/browser.test.js +547 -0
- package/test/complex-objects.test.js +34 -0
- package/test/crlf.test.js +32 -0
- package/test/custom-levels.test.js +294 -0
- package/test/error.test.js +374 -0
- package/test/escaping.test.js +91 -0
- package/test/esm/esm.mjs +12 -0
- package/test/esm/index.test.js +34 -0
- package/test/esm/named-exports.mjs +28 -0
- package/test/exit.test.js +85 -0
- package/test/final.test.js +237 -0
- package/test/fixtures/broken-pipe/basic.js +9 -0
- package/test/fixtures/broken-pipe/destination.js +10 -0
- package/test/fixtures/broken-pipe/syncfalse.js +12 -0
- package/test/fixtures/console-transport.js +13 -0
- package/test/fixtures/default-exit.js +8 -0
- package/test/fixtures/destination-exit.js +8 -0
- package/test/fixtures/eval/index.js +29 -0
- package/test/fixtures/eval/node_modules/14-files.js +3 -0
- package/test/fixtures/eval/node_modules/2-files.js +3 -0
- package/test/fixtures/eval/node_modules/file1.js +5 -0
- package/test/fixtures/eval/node_modules/file10.js +5 -0
- package/test/fixtures/eval/node_modules/file11.js +5 -0
- package/test/fixtures/eval/node_modules/file12.js +5 -0
- package/test/fixtures/eval/node_modules/file13.js +5 -0
- package/test/fixtures/eval/node_modules/file14.js +11 -0
- package/test/fixtures/eval/node_modules/file15.js +10 -0
- package/test/fixtures/eval/node_modules/file2.js +5 -0
- package/test/fixtures/eval/node_modules/file3.js +5 -0
- package/test/fixtures/eval/node_modules/file4.js +5 -0
- package/test/fixtures/eval/node_modules/file5.js +5 -0
- package/test/fixtures/eval/node_modules/file6.js +5 -0
- package/test/fixtures/eval/node_modules/file7.js +5 -0
- package/test/fixtures/eval/node_modules/file8.js +5 -0
- package/test/fixtures/eval/node_modules/file9.js +5 -0
- package/test/fixtures/eval/node_modules/test.list +3 -0
- package/test/fixtures/pretty/basic.js +6 -0
- package/test/fixtures/pretty/child-with-serializer.js +17 -0
- package/test/fixtures/pretty/child-with-updated-chindings.js +8 -0
- package/test/fixtures/pretty/child.js +8 -0
- package/test/fixtures/pretty/custom-time-label.js +9 -0
- package/test/fixtures/pretty/custom-time.js +9 -0
- package/test/fixtures/pretty/dateformat.js +10 -0
- package/test/fixtures/pretty/error-props.js +9 -0
- package/test/fixtures/pretty/error.js +7 -0
- package/test/fixtures/pretty/final-no-log-before.js +8 -0
- package/test/fixtures/pretty/final-return.js +7 -0
- package/test/fixtures/pretty/final.js +9 -0
- package/test/fixtures/pretty/formatters.js +13 -0
- package/test/fixtures/pretty/level-first.js +6 -0
- package/test/fixtures/pretty/no-time.js +9 -0
- package/test/fixtures/pretty/null-prototype.js +8 -0
- package/test/fixtures/pretty/obj-msg-prop.js +6 -0
- package/test/fixtures/pretty/pretty-factory.js +6 -0
- package/test/fixtures/pretty/redact.js +9 -0
- package/test/fixtures/pretty/serializers.js +17 -0
- package/test/fixtures/pretty/skipped-output.js +13 -0
- package/test/fixtures/pretty/suppress-flush-sync-warning.js +7 -0
- package/test/fixtures/stdout-hack-protection.js +11 -0
- package/test/fixtures/syncfalse-child.js +6 -0
- package/test/fixtures/syncfalse-exit.js +9 -0
- package/test/fixtures/syncfalse-flush-exit.js +10 -0
- package/test/fixtures/syncfalse.js +6 -0
- package/test/fixtures/to-file-transport-with-transform.js +20 -0
- package/test/fixtures/to-file-transport.js +13 -0
- package/test/fixtures/to-file-transport.mjs +8 -0
- package/test/fixtures/transport/index.js +12 -0
- package/test/fixtures/transport/package.json +5 -0
- package/test/fixtures/transport-exit-immediately-with-async-dest.js +16 -0
- package/test/fixtures/transport-exit-immediately.js +11 -0
- package/test/fixtures/transport-exit-on-ready.js +12 -0
- package/test/fixtures/transport-main.js +9 -0
- package/test/fixtures/transport-many-lines.js +29 -0
- package/test/fixtures/transport-string-stdout.js +9 -0
- package/test/fixtures/transport-transform.js +21 -0
- package/test/fixtures/transport-worker.js +13 -0
- package/test/fixtures/transport-wrong-export-type.js +3 -0
- package/test/fixtures/ts/to-file-transport-with-transform.ts +18 -0
- package/test/fixtures/ts/to-file-transport.es2017.cjs +12 -0
- package/test/fixtures/ts/to-file-transport.es5.cjs +58 -0
- package/test/fixtures/ts/to-file-transport.es6.cjs +23 -0
- package/test/fixtures/ts/to-file-transport.esnext.cjs +12 -0
- package/test/fixtures/ts/to-file-transport.ts +11 -0
- package/test/fixtures/ts/transpile.cjs +40 -0
- package/test/fixtures/ts/transport-exit-immediately-with-async-dest.ts +15 -0
- package/test/fixtures/ts/transport-exit-immediately.ts +10 -0
- package/test/fixtures/ts/transport-exit-on-ready.ts +11 -0
- package/test/fixtures/ts/transport-main.ts +8 -0
- package/test/fixtures/ts/transport-string-stdout.ts +8 -0
- package/test/fixtures/ts/transport-worker.ts +14 -0
- package/test/formatters.test.js +355 -0
- package/test/helper.d.ts +4 -0
- package/test/helper.js +128 -0
- package/test/hooks.test.js +97 -0
- package/test/http.test.js +242 -0
- package/test/is-level-enabled.test.js +43 -0
- package/test/jest/basic.spec.js +10 -0
- package/test/levels.test.js +528 -0
- package/test/metadata.test.js +106 -0
- package/test/mixin-merge-strategy.test.js +55 -0
- package/test/mixin.test.js +162 -0
- package/test/multistream.test.js +589 -0
- package/test/pretty.test.js +392 -0
- package/test/redact.test.js +828 -0
- package/test/serializers.test.js +253 -0
- package/test/stdout-protection.test.js +19 -0
- package/test/syncfalse.test.js +118 -0
- package/test/timestamp.test.js +121 -0
- package/test/transport/big.test.js +41 -0
- package/test/transport/bundlers-support.test.js +97 -0
- package/test/transport/caller.test.js +23 -0
- package/test/transport/core.test.js +546 -0
- package/test/transport/core.test.ts +236 -0
- package/test/transport/core.transpiled.test.ts +116 -0
- package/test/transport/module-link.test.js +239 -0
- package/test/transport/pipeline.test.js +36 -0
- package/test/transport/syncfalse.test.js +31 -0
- package/test/transport/targets.test.js +28 -0
- package/test/types/pino-import.test-d.ts +29 -0
- package/test/types/pino-multistream.test-d.ts +26 -0
- package/test/types/pino-top-export.test-d.ts +37 -0
- package/test/types/pino-transport.test-d.ts +122 -0
- package/test/types/pino-type-only.test-d.ts +16 -0
- package/test/types/pino.test-d.ts +341 -0
- package/test/types/pino.ts +42 -0
package/lib/tools.js
ADDED
|
@@ -0,0 +1,563 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
/* eslint no-prototype-builtins: 0 */
|
|
4
|
+
|
|
5
|
+
const format = require('quick-format-unescaped')
|
|
6
|
+
const { mapHttpRequest, mapHttpResponse } = require('pino-std-serializers')
|
|
7
|
+
const SonicBoom = require('sonic-boom')
|
|
8
|
+
const warning = require('./deprecations')
|
|
9
|
+
const {
|
|
10
|
+
lsCacheSym,
|
|
11
|
+
chindingsSym,
|
|
12
|
+
parsedChindingsSym,
|
|
13
|
+
writeSym,
|
|
14
|
+
serializersSym,
|
|
15
|
+
formatOptsSym,
|
|
16
|
+
endSym,
|
|
17
|
+
stringifiersSym,
|
|
18
|
+
stringifySym,
|
|
19
|
+
stringifySafeSym,
|
|
20
|
+
wildcardFirstSym,
|
|
21
|
+
needsMetadataGsym,
|
|
22
|
+
redactFmtSym,
|
|
23
|
+
streamSym,
|
|
24
|
+
nestedKeySym,
|
|
25
|
+
formattersSym,
|
|
26
|
+
messageKeySym,
|
|
27
|
+
nestedKeyStrSym
|
|
28
|
+
} = require('./symbols')
|
|
29
|
+
const { isMainThread } = require('worker_threads')
|
|
30
|
+
const transport = require('./transport')
|
|
31
|
+
|
|
32
|
+
function noop () {}
|
|
33
|
+
|
|
34
|
+
function genLog (level, hook) {
|
|
35
|
+
if (!hook) return LOG
|
|
36
|
+
|
|
37
|
+
return function hookWrappedLog (...args) {
|
|
38
|
+
hook.call(this, args, LOG, level)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function LOG (o, ...n) {
|
|
42
|
+
if (typeof o === 'object') {
|
|
43
|
+
let msg = o
|
|
44
|
+
if (o !== null) {
|
|
45
|
+
if (o.method && o.headers && o.socket) {
|
|
46
|
+
o = mapHttpRequest(o)
|
|
47
|
+
} else if (typeof o.setHeader === 'function') {
|
|
48
|
+
o = mapHttpResponse(o)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
let formatParams
|
|
52
|
+
if (msg === null && n.length === 0) {
|
|
53
|
+
formatParams = [null]
|
|
54
|
+
} else {
|
|
55
|
+
msg = n.shift()
|
|
56
|
+
formatParams = n
|
|
57
|
+
}
|
|
58
|
+
this[writeSym](o, format(msg, formatParams, this[formatOptsSym]), level)
|
|
59
|
+
} else {
|
|
60
|
+
this[writeSym](null, format(o, n, this[formatOptsSym]), level)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// magically escape strings for json
|
|
66
|
+
// relying on their charCodeAt
|
|
67
|
+
// everything below 32 needs JSON.stringify()
|
|
68
|
+
// 34 and 92 happens all the time, so we
|
|
69
|
+
// have a fast case for them
|
|
70
|
+
function asString (str) {
|
|
71
|
+
let result = ''
|
|
72
|
+
let last = 0
|
|
73
|
+
let found = false
|
|
74
|
+
let point = 255
|
|
75
|
+
const l = str.length
|
|
76
|
+
if (l > 100) {
|
|
77
|
+
return JSON.stringify(str)
|
|
78
|
+
}
|
|
79
|
+
for (var i = 0; i < l && point >= 32; i++) {
|
|
80
|
+
point = str.charCodeAt(i)
|
|
81
|
+
if (point === 34 || point === 92) {
|
|
82
|
+
result += str.slice(last, i) + '\\'
|
|
83
|
+
last = i
|
|
84
|
+
found = true
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (!found) {
|
|
88
|
+
result = str
|
|
89
|
+
} else {
|
|
90
|
+
result += str.slice(last)
|
|
91
|
+
}
|
|
92
|
+
return point < 32 ? JSON.stringify(str) : '"' + result + '"'
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function asJson (obj, msg, num, time) {
|
|
96
|
+
const stringify = this[stringifySym]
|
|
97
|
+
const stringifySafe = this[stringifySafeSym]
|
|
98
|
+
const stringifiers = this[stringifiersSym]
|
|
99
|
+
const end = this[endSym]
|
|
100
|
+
const chindings = this[chindingsSym]
|
|
101
|
+
const serializers = this[serializersSym]
|
|
102
|
+
const formatters = this[formattersSym]
|
|
103
|
+
const messageKey = this[messageKeySym]
|
|
104
|
+
let data = this[lsCacheSym][num] + time
|
|
105
|
+
|
|
106
|
+
// we need the child bindings added to the output first so instance logged
|
|
107
|
+
// objects can take precedence when JSON.parse-ing the resulting log line
|
|
108
|
+
data = data + chindings
|
|
109
|
+
|
|
110
|
+
let value
|
|
111
|
+
if (formatters.log) {
|
|
112
|
+
obj = formatters.log(obj)
|
|
113
|
+
}
|
|
114
|
+
const wildcardStringifier = stringifiers[wildcardFirstSym]
|
|
115
|
+
let propStr = ''
|
|
116
|
+
for (const key in obj) {
|
|
117
|
+
value = obj[key]
|
|
118
|
+
if (Object.prototype.hasOwnProperty.call(obj, key) && value !== undefined) {
|
|
119
|
+
value = serializers[key] ? serializers[key](value) : value
|
|
120
|
+
|
|
121
|
+
const stringifier = stringifiers[key] || wildcardStringifier
|
|
122
|
+
|
|
123
|
+
switch (typeof value) {
|
|
124
|
+
case 'undefined':
|
|
125
|
+
case 'function':
|
|
126
|
+
continue
|
|
127
|
+
case 'number':
|
|
128
|
+
/* eslint no-fallthrough: "off" */
|
|
129
|
+
if (Number.isFinite(value) === false) {
|
|
130
|
+
value = null
|
|
131
|
+
}
|
|
132
|
+
// this case explicitly falls through to the next one
|
|
133
|
+
case 'boolean':
|
|
134
|
+
if (stringifier) value = stringifier(value)
|
|
135
|
+
break
|
|
136
|
+
case 'string':
|
|
137
|
+
value = (stringifier || asString)(value)
|
|
138
|
+
break
|
|
139
|
+
default:
|
|
140
|
+
value = (stringifier || stringify)(value, stringifySafe)
|
|
141
|
+
}
|
|
142
|
+
if (value === undefined) continue
|
|
143
|
+
propStr += ',"' + key + '":' + value
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
let msgStr = ''
|
|
148
|
+
if (msg !== undefined) {
|
|
149
|
+
value = serializers[messageKey] ? serializers[messageKey](msg) : msg
|
|
150
|
+
const stringifier = stringifiers[messageKey] || wildcardStringifier
|
|
151
|
+
|
|
152
|
+
switch (typeof value) {
|
|
153
|
+
case 'function':
|
|
154
|
+
break
|
|
155
|
+
case 'number':
|
|
156
|
+
/* eslint no-fallthrough: "off" */
|
|
157
|
+
if (Number.isFinite(value) === false) {
|
|
158
|
+
value = null
|
|
159
|
+
}
|
|
160
|
+
// this case explicitly falls through to the next one
|
|
161
|
+
case 'boolean':
|
|
162
|
+
if (stringifier) value = stringifier(value)
|
|
163
|
+
msgStr = ',"' + messageKey + '":' + value
|
|
164
|
+
break
|
|
165
|
+
case 'string':
|
|
166
|
+
value = (stringifier || asString)(value)
|
|
167
|
+
msgStr = ',"' + messageKey + '":' + value
|
|
168
|
+
break
|
|
169
|
+
default:
|
|
170
|
+
value = (stringifier || stringify)(value, stringifySafe)
|
|
171
|
+
msgStr = ',"' + messageKey + '":' + value
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (this[nestedKeySym] && propStr) {
|
|
176
|
+
// place all the obj properties under the specified key
|
|
177
|
+
// the nested key is already formatted from the constructor
|
|
178
|
+
return data + this[nestedKeyStrSym] + propStr.slice(1) + '}' + msgStr + end
|
|
179
|
+
} else {
|
|
180
|
+
return data + propStr + msgStr + end
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function asChindings (instance, bindings) {
|
|
185
|
+
let value
|
|
186
|
+
let data = instance[chindingsSym]
|
|
187
|
+
const stringify = instance[stringifySym]
|
|
188
|
+
const stringifySafe = instance[stringifySafeSym]
|
|
189
|
+
const stringifiers = instance[stringifiersSym]
|
|
190
|
+
const wildcardStringifier = stringifiers[wildcardFirstSym]
|
|
191
|
+
const serializers = instance[serializersSym]
|
|
192
|
+
const formatter = instance[formattersSym].bindings
|
|
193
|
+
bindings = formatter(bindings)
|
|
194
|
+
|
|
195
|
+
for (const key in bindings) {
|
|
196
|
+
value = bindings[key]
|
|
197
|
+
const valid = key !== 'level' &&
|
|
198
|
+
key !== 'serializers' &&
|
|
199
|
+
key !== 'formatters' &&
|
|
200
|
+
key !== 'customLevels' &&
|
|
201
|
+
bindings.hasOwnProperty(key) &&
|
|
202
|
+
value !== undefined
|
|
203
|
+
if (valid === true) {
|
|
204
|
+
value = serializers[key] ? serializers[key](value) : value
|
|
205
|
+
value = (stringifiers[key] || wildcardStringifier || stringify)(value, stringifySafe)
|
|
206
|
+
if (value === undefined) continue
|
|
207
|
+
data += ',"' + key + '":' + value
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return data
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function getPrettyStream (opts, prettifier, dest, instance) {
|
|
214
|
+
if (prettifier && typeof prettifier === 'function') {
|
|
215
|
+
prettifier = prettifier.bind(instance)
|
|
216
|
+
return prettifierMetaWrapper(prettifier(opts), dest, opts)
|
|
217
|
+
}
|
|
218
|
+
try {
|
|
219
|
+
const prettyFactory = require('pino-pretty').prettyFactory
|
|
220
|
+
prettyFactory.asMetaWrapper = prettifierMetaWrapper
|
|
221
|
+
return prettifierMetaWrapper(prettyFactory(opts), dest, opts)
|
|
222
|
+
} catch (e) {
|
|
223
|
+
if (e.message.startsWith("Cannot find module 'bingo-logger-pretty'")) {
|
|
224
|
+
throw Error('Missing `bingo-logger-pretty` module: `bingo-logger-pretty` must be installed separately')
|
|
225
|
+
};
|
|
226
|
+
throw e
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function prettifierMetaWrapper (pretty, dest, opts) {
|
|
231
|
+
opts = Object.assign({ suppressFlushSyncWarning: false }, opts)
|
|
232
|
+
let warned = false
|
|
233
|
+
return {
|
|
234
|
+
[needsMetadataGsym]: true,
|
|
235
|
+
lastLevel: 0,
|
|
236
|
+
lastMsg: null,
|
|
237
|
+
lastObj: null,
|
|
238
|
+
lastLogger: null,
|
|
239
|
+
flushSync () {
|
|
240
|
+
if (opts.suppressFlushSyncWarning || warned) {
|
|
241
|
+
return
|
|
242
|
+
}
|
|
243
|
+
warned = true
|
|
244
|
+
setMetadataProps(dest, this)
|
|
245
|
+
dest.write(pretty(Object.assign({
|
|
246
|
+
level: 40, // warn
|
|
247
|
+
msg: 'bingo-logger.final with prettyPrint does not support flushing',
|
|
248
|
+
time: Date.now()
|
|
249
|
+
}, this.chindings())))
|
|
250
|
+
},
|
|
251
|
+
chindings () {
|
|
252
|
+
const lastLogger = this.lastLogger
|
|
253
|
+
let chindings = null
|
|
254
|
+
|
|
255
|
+
// protection against flushSync being called before logging
|
|
256
|
+
// anything
|
|
257
|
+
if (!lastLogger) {
|
|
258
|
+
return null
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (lastLogger.hasOwnProperty(parsedChindingsSym)) {
|
|
262
|
+
chindings = lastLogger[parsedChindingsSym]
|
|
263
|
+
} else {
|
|
264
|
+
chindings = JSON.parse('{' + lastLogger[chindingsSym].substr(1) + '}')
|
|
265
|
+
lastLogger[parsedChindingsSym] = chindings
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return chindings
|
|
269
|
+
},
|
|
270
|
+
write (chunk) {
|
|
271
|
+
const lastLogger = this.lastLogger
|
|
272
|
+
const chindings = this.chindings()
|
|
273
|
+
|
|
274
|
+
let time = this.lastTime
|
|
275
|
+
|
|
276
|
+
/* istanbul ignore next */
|
|
277
|
+
if (typeof time === 'number') {
|
|
278
|
+
// do nothing!
|
|
279
|
+
} else if (time.match(/^\d+/)) {
|
|
280
|
+
time = parseInt(time)
|
|
281
|
+
} else {
|
|
282
|
+
time = time.slice(1, -1)
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const lastObj = this.lastObj
|
|
286
|
+
const lastMsg = this.lastMsg
|
|
287
|
+
const errorProps = null
|
|
288
|
+
|
|
289
|
+
const formatters = lastLogger[formattersSym]
|
|
290
|
+
const formattedObj = formatters.log ? formatters.log(lastObj) : lastObj
|
|
291
|
+
|
|
292
|
+
const messageKey = lastLogger[messageKeySym]
|
|
293
|
+
if (lastMsg && formattedObj && !Object.prototype.hasOwnProperty.call(formattedObj, messageKey)) {
|
|
294
|
+
formattedObj[messageKey] = lastMsg
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const obj = Object.assign({
|
|
298
|
+
level: this.lastLevel,
|
|
299
|
+
time
|
|
300
|
+
}, formattedObj, errorProps)
|
|
301
|
+
|
|
302
|
+
const serializers = lastLogger[serializersSym]
|
|
303
|
+
const keys = Object.keys(serializers)
|
|
304
|
+
|
|
305
|
+
for (var i = 0; i < keys.length; i++) {
|
|
306
|
+
const key = keys[i]
|
|
307
|
+
if (obj[key] !== undefined) {
|
|
308
|
+
obj[key] = serializers[key](obj[key])
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
for (const key in chindings) {
|
|
313
|
+
if (!obj.hasOwnProperty(key)) {
|
|
314
|
+
obj[key] = chindings[key]
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
const stringifiers = lastLogger[stringifiersSym]
|
|
319
|
+
const redact = stringifiers[redactFmtSym]
|
|
320
|
+
|
|
321
|
+
const formatted = pretty(typeof redact === 'function' ? redact(obj) : obj)
|
|
322
|
+
if (formatted === undefined) return
|
|
323
|
+
|
|
324
|
+
setMetadataProps(dest, this)
|
|
325
|
+
dest.write(formatted)
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function hasBeenTampered (stream) {
|
|
331
|
+
return stream.write !== stream.constructor.prototype.write
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
function buildSafeSonicBoom (opts) {
|
|
335
|
+
const stream = new SonicBoom(opts)
|
|
336
|
+
stream.on('error', filterBrokenPipe)
|
|
337
|
+
// if we are sync: false, we must flush on exit
|
|
338
|
+
if (!opts.sync && isMainThread) {
|
|
339
|
+
setupOnExit(stream)
|
|
340
|
+
}
|
|
341
|
+
return stream
|
|
342
|
+
|
|
343
|
+
function filterBrokenPipe (err) {
|
|
344
|
+
// TODO verify on Windows
|
|
345
|
+
if (err.code === 'EPIPE') {
|
|
346
|
+
// If we get EPIPE, we should stop logging here
|
|
347
|
+
// however we have no control to the consumer of
|
|
348
|
+
// SonicBoom, so we just overwrite the write method
|
|
349
|
+
stream.write = noop
|
|
350
|
+
stream.end = noop
|
|
351
|
+
stream.flushSync = noop
|
|
352
|
+
stream.destroy = noop
|
|
353
|
+
return
|
|
354
|
+
}
|
|
355
|
+
stream.removeListener('error', filterBrokenPipe)
|
|
356
|
+
stream.emit('error', err)
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function setupOnExit (stream) {
|
|
361
|
+
/* istanbul ignore next */
|
|
362
|
+
if (global.WeakRef && global.WeakMap && global.FinalizationRegistry) {
|
|
363
|
+
// This is leak free, it does not leave event handlers
|
|
364
|
+
const onExit = require('on-exit-leak-free')
|
|
365
|
+
|
|
366
|
+
onExit.register(stream, autoEnd)
|
|
367
|
+
|
|
368
|
+
stream.on('close', function () {
|
|
369
|
+
onExit.unregister(stream)
|
|
370
|
+
})
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function autoEnd (stream, eventName) {
|
|
375
|
+
// This check is needed only on some platforms
|
|
376
|
+
/* istanbul ignore next */
|
|
377
|
+
if (stream.destroyed) {
|
|
378
|
+
return
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
if (eventName === 'beforeExit') {
|
|
382
|
+
// We still have an event loop, let's use it
|
|
383
|
+
stream.flush()
|
|
384
|
+
stream.on('drain', function () {
|
|
385
|
+
stream.end()
|
|
386
|
+
})
|
|
387
|
+
} else {
|
|
388
|
+
// We do not have an event loop, so flush synchronously
|
|
389
|
+
stream.flushSync()
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
function createArgsNormalizer (defaultOptions) {
|
|
394
|
+
return function normalizeArgs (instance, caller, opts = {}, stream) {
|
|
395
|
+
// support stream as a string
|
|
396
|
+
if (typeof opts === 'string') {
|
|
397
|
+
stream = buildSafeSonicBoom({ dest: opts, sync: true })
|
|
398
|
+
opts = {}
|
|
399
|
+
} else if (typeof stream === 'string') {
|
|
400
|
+
if (opts && opts.transport) {
|
|
401
|
+
throw Error('only one of option.transport or stream can be specified')
|
|
402
|
+
}
|
|
403
|
+
stream = buildSafeSonicBoom({ dest: stream, sync: true })
|
|
404
|
+
} else if (opts instanceof SonicBoom || opts.writable || opts._writableState) {
|
|
405
|
+
stream = opts
|
|
406
|
+
opts = {}
|
|
407
|
+
} else if (opts.transport) {
|
|
408
|
+
if (opts.transport instanceof SonicBoom || opts.transport.writable || opts.transport._writableState) {
|
|
409
|
+
throw Error('option.transport do not allow stream, please pass to option directly. e.g. bingo-logger(transport)')
|
|
410
|
+
}
|
|
411
|
+
if (opts.transport.targets && opts.transport.targets.length && opts.formatters && typeof opts.formatters.level === 'function') {
|
|
412
|
+
throw Error('option.transport.targets do not allow custom level formatters')
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
let customLevels
|
|
416
|
+
if (opts.customLevels) {
|
|
417
|
+
customLevels = opts.useOnlyCustomLevels ? opts.customLevels : Object.assign({}, opts.levels, opts.customLevels)
|
|
418
|
+
}
|
|
419
|
+
stream = transport({ caller, ...opts.transport, levels: customLevels })
|
|
420
|
+
}
|
|
421
|
+
opts = Object.assign({}, defaultOptions, opts)
|
|
422
|
+
opts.serializers = Object.assign({}, defaultOptions.serializers, opts.serializers)
|
|
423
|
+
opts.formatters = Object.assign({}, defaultOptions.formatters, opts.formatters)
|
|
424
|
+
|
|
425
|
+
if ('onTerminated' in opts) {
|
|
426
|
+
throw Error('The onTerminated option has been removed, use bingo-logger.final instead')
|
|
427
|
+
}
|
|
428
|
+
if ('changeLevelName' in opts) {
|
|
429
|
+
process.emitWarning(
|
|
430
|
+
'The changeLevelName option is deprecated and will be removed in v7. Use levelKey instead.',
|
|
431
|
+
{ code: 'changeLevelName_deprecation' }
|
|
432
|
+
)
|
|
433
|
+
opts.levelKey = opts.changeLevelName
|
|
434
|
+
delete opts.changeLevelName
|
|
435
|
+
}
|
|
436
|
+
const { enabled, prettyPrint, prettifier, messageKey } = opts
|
|
437
|
+
if (enabled === false) opts.level = 'silent'
|
|
438
|
+
stream = stream || process.stdout
|
|
439
|
+
if (stream === process.stdout && stream.fd >= 0 && !hasBeenTampered(stream)) {
|
|
440
|
+
stream = buildSafeSonicBoom({ fd: stream.fd, sync: true })
|
|
441
|
+
}
|
|
442
|
+
if (prettyPrint) {
|
|
443
|
+
warning.emit('PINODEP008')
|
|
444
|
+
const prettyOpts = Object.assign({ messageKey }, prettyPrint)
|
|
445
|
+
stream = getPrettyStream(prettyOpts, prettifier, stream, instance)
|
|
446
|
+
}
|
|
447
|
+
return { opts, stream }
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
function final (logger, handler) {
|
|
452
|
+
const major = Number(process.versions.node.split('.')[0])
|
|
453
|
+
if (major >= 14) warning.emit('PINODEP009')
|
|
454
|
+
|
|
455
|
+
if (typeof logger === 'undefined' || typeof logger.child !== 'function') {
|
|
456
|
+
throw Error('expected a bingo-logger logger instance')
|
|
457
|
+
}
|
|
458
|
+
const hasHandler = (typeof handler !== 'undefined')
|
|
459
|
+
if (hasHandler && typeof handler !== 'function') {
|
|
460
|
+
throw Error('if supplied, the handler parameter should be a function')
|
|
461
|
+
}
|
|
462
|
+
const stream = logger[streamSym]
|
|
463
|
+
if (typeof stream.flushSync !== 'function') {
|
|
464
|
+
throw Error('final requires a stream that has a flushSync method, such as bingo-logger.destination')
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
const finalLogger = new Proxy(logger, {
|
|
468
|
+
get: (logger, key) => {
|
|
469
|
+
if (key in logger.levels.values) {
|
|
470
|
+
return (...args) => {
|
|
471
|
+
logger[key](...args)
|
|
472
|
+
stream.flushSync()
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
return logger[key]
|
|
476
|
+
}
|
|
477
|
+
})
|
|
478
|
+
|
|
479
|
+
if (!hasHandler) {
|
|
480
|
+
try {
|
|
481
|
+
stream.flushSync()
|
|
482
|
+
} catch {
|
|
483
|
+
// it's too late to wait for the stream to be ready
|
|
484
|
+
// because this is a final tick scenario.
|
|
485
|
+
// in practice there shouldn't be a situation where it isn't
|
|
486
|
+
// however, swallow the error just in case (and for easier testing)
|
|
487
|
+
}
|
|
488
|
+
return finalLogger
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
return (err = null, ...args) => {
|
|
492
|
+
try {
|
|
493
|
+
stream.flushSync()
|
|
494
|
+
} catch (e) {
|
|
495
|
+
// it's too late to wait for the stream to be ready
|
|
496
|
+
// because this is a final tick scenario.
|
|
497
|
+
// in practice there shouldn't be a situation where it isn't
|
|
498
|
+
// however, swallow the error just in case (and for easier testing)
|
|
499
|
+
}
|
|
500
|
+
return handler(err, finalLogger, ...args)
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
function stringify (obj, stringifySafeFn) {
|
|
505
|
+
try {
|
|
506
|
+
return JSON.stringify(obj)
|
|
507
|
+
} catch (_) {
|
|
508
|
+
try {
|
|
509
|
+
const stringify = stringifySafeFn || this[stringifySafeSym]
|
|
510
|
+
return stringify(obj)
|
|
511
|
+
} catch (_) {
|
|
512
|
+
return '"[unable to serialize, circular reference is too complex to analyze]"'
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
function buildFormatters (level, bindings, log) {
|
|
518
|
+
return {
|
|
519
|
+
level,
|
|
520
|
+
bindings,
|
|
521
|
+
log
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
function setMetadataProps (dest, that) {
|
|
526
|
+
if (dest[needsMetadataGsym] === true) {
|
|
527
|
+
dest.lastLevel = that.lastLevel
|
|
528
|
+
dest.lastMsg = that.lastMsg
|
|
529
|
+
dest.lastObj = that.lastObj
|
|
530
|
+
dest.lastTime = that.lastTime
|
|
531
|
+
dest.lastLogger = that.lastLogger
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* Convert a string integer file descriptor to a proper native integer
|
|
537
|
+
* file descriptor.
|
|
538
|
+
*
|
|
539
|
+
* @param {string} destination The file descriptor string to attempt to convert.
|
|
540
|
+
*
|
|
541
|
+
* @returns {Number}
|
|
542
|
+
*/
|
|
543
|
+
function normalizeDestFileDescriptor (destination) {
|
|
544
|
+
const fd = Number(destination)
|
|
545
|
+
if (typeof destination === 'string' && Number.isFinite(fd)) {
|
|
546
|
+
return fd
|
|
547
|
+
}
|
|
548
|
+
return destination
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
module.exports = {
|
|
552
|
+
noop,
|
|
553
|
+
buildSafeSonicBoom,
|
|
554
|
+
getPrettyStream,
|
|
555
|
+
asChindings,
|
|
556
|
+
asJson,
|
|
557
|
+
genLog,
|
|
558
|
+
createArgsNormalizer,
|
|
559
|
+
final,
|
|
560
|
+
stringify,
|
|
561
|
+
buildFormatters,
|
|
562
|
+
normalizeDestFileDescriptor
|
|
563
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { realImport, realRequire } = require('real-require')
|
|
4
|
+
|
|
5
|
+
module.exports = loadTransportStreamBuilder
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Loads & returns a function to build transport streams
|
|
9
|
+
* @param {string} target
|
|
10
|
+
* @returns {function(object): Promise<import('stream').Writable>}
|
|
11
|
+
* @throws {Error} In case the target module does not export a function
|
|
12
|
+
*/
|
|
13
|
+
async function loadTransportStreamBuilder (target) {
|
|
14
|
+
let fn
|
|
15
|
+
try {
|
|
16
|
+
const toLoad = 'file://' + target
|
|
17
|
+
|
|
18
|
+
if (toLoad.endsWith('.ts') || toLoad.endsWith('.cts')) {
|
|
19
|
+
// TODO: add support for the TSM modules loader ( https://github.com/lukeed/tsm ).
|
|
20
|
+
if (process[Symbol.for('ts-node.register.instance')]) {
|
|
21
|
+
realRequire('ts-node/register')
|
|
22
|
+
} else if (process.env && process.env.TS_NODE_DEV) {
|
|
23
|
+
realRequire('ts-node-dev')
|
|
24
|
+
}
|
|
25
|
+
// TODO: Support ES imports once tsc, tap & ts-node provide better compatibility guarantees.
|
|
26
|
+
fn = realRequire(decodeURIComponent(target))
|
|
27
|
+
} else {
|
|
28
|
+
fn = (await realImport(toLoad))
|
|
29
|
+
}
|
|
30
|
+
} catch (error) {
|
|
31
|
+
// See this PR for details: https://github.com/bingo-loggerjs/thread-stream/pull/34
|
|
32
|
+
if ((error.code === 'ENOTDIR' || error.code === 'ERR_MODULE_NOT_FOUND')) {
|
|
33
|
+
fn = realRequire(target)
|
|
34
|
+
} else {
|
|
35
|
+
throw error
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Depending on how the default export is performed, and on how the code is
|
|
40
|
+
// transpiled, we may find cases of two nested "default" objects.
|
|
41
|
+
// See https://github.com/bingo-loggerjs/bingo-logger/issues/1243#issuecomment-982774762
|
|
42
|
+
if (typeof fn === 'object') fn = fn.default
|
|
43
|
+
if (typeof fn === 'object') fn = fn.default
|
|
44
|
+
if (typeof fn !== 'function') throw Error('exported worker is not a function')
|
|
45
|
+
|
|
46
|
+
return fn
|
|
47
|
+
}
|