pino-testkit 10.4.5
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.
- package/.nojekyll +0 -0
- package/.prettierignore +1 -0
- package/CNAME +1 -0
- package/CONTRIBUTING.md +30 -0
- package/LICENSE +21 -0
- package/README.md +175 -0
- package/SECURITY.md +87 -0
- package/benchmarks/basic.bench.js +95 -0
- package/benchmarks/child-child.bench.js +52 -0
- package/benchmarks/child-creation.bench.js +73 -0
- package/benchmarks/child.bench.js +62 -0
- package/benchmarks/deep-object.bench.js +88 -0
- package/benchmarks/formatters.bench.js +50 -0
- package/benchmarks/internal/custom-levels.js +67 -0
- package/benchmarks/internal/just-pino-heavy.bench.js +76 -0
- package/benchmarks/internal/just-pino.bench.js +182 -0
- package/benchmarks/internal/parent-vs-child.bench.js +75 -0
- package/benchmarks/internal/redact.bench.js +86 -0
- package/benchmarks/long-string.bench.js +81 -0
- package/benchmarks/multi-arg.bench.js +193 -0
- package/benchmarks/multistream.js +98 -0
- package/benchmarks/object.bench.js +82 -0
- package/benchmarks/utils/generate-benchmark-doc.js +36 -0
- package/benchmarks/utils/runbench.js +138 -0
- package/benchmarks/utils/wrap-log-level.js +55 -0
- package/bin.js +6 -0
- package/browser.js +547 -0
- package/build/sync-version.js +25 -0
- package/docs/api.md +1593 -0
- package/docs/asynchronous.md +40 -0
- package/docs/benchmarks.md +55 -0
- package/docs/browser.md +278 -0
- package/docs/bundling.md +40 -0
- package/docs/child-loggers.md +95 -0
- package/docs/diagnostics.md +16 -0
- package/docs/ecosystem.md +86 -0
- package/docs/help.md +345 -0
- package/docs/lts.md +64 -0
- package/docs/pretty.md +35 -0
- package/docs/redaction.md +135 -0
- package/docs/transports.md +1376 -0
- package/docs/web.md +309 -0
- package/eslint.config.js +28 -0
- package/examples/basic.js +43 -0
- package/examples/transport.js +68 -0
- package/favicon.ico +0 -0
- package/file.js +12 -0
- package/inc-version.sh +42 -0
- package/index.html +55 -0
- package/lib/caller.js +30 -0
- package/lib/constants.js +28 -0
- package/lib/contract.js +8 -0
- package/lib/deprecations.js +8 -0
- package/lib/levels.js +241 -0
- package/lib/meta.js +3 -0
- package/lib/multistream.js +203 -0
- package/lib/proto.js +256 -0
- package/lib/redaction.js +114 -0
- package/lib/symbols.js +74 -0
- package/lib/time.js +39 -0
- package/lib/tools.js +427 -0
- package/lib/transport-stream.js +56 -0
- package/lib/transport.js +289 -0
- package/lib/worker.js +194 -0
- package/package.json +119 -0
- package/pino.d.ts +908 -0
- package/pino.js +240 -0
- package/test/basic.test.js +886 -0
- package/test/broken-pipe.test.js +59 -0
- package/test/browser-child.test.js +132 -0
- package/test/browser-disabled.test.js +87 -0
- package/test/browser-early-console-freeze.test.js +12 -0
- package/test/browser-is-level-enabled.test.js +101 -0
- package/test/browser-levels.test.js +241 -0
- package/test/browser-serializers.test.js +352 -0
- package/test/browser-timestamp.test.js +88 -0
- package/test/browser-transmit.test.js +417 -0
- package/test/browser.test.js +698 -0
- package/test/complex-objects.test.js +36 -0
- package/test/crlf.test.js +34 -0
- package/test/custom-levels.test.js +267 -0
- package/test/diagnostics.test.js +107 -0
- package/test/error-key.test.js +37 -0
- package/test/error.test.js +403 -0
- package/test/escaping.test.js +93 -0
- package/test/esm/esm.mjs +14 -0
- package/test/esm/index.test.js +21 -0
- package/test/esm/named-exports.mjs +29 -0
- package/test/exit.test.js +79 -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/crashing-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 +13 -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/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/noop-transport.js +10 -0
- package/test/fixtures/pretty/null-prototype.js +8 -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/syntax-error-esm.mjs +2 -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-invalid-node-options.js +26 -0
- package/test/fixtures/transport-main.js +9 -0
- package/test/fixtures/transport-many-lines.js +29 -0
- package/test/fixtures/transport-preload-main.mjs +13 -0
- package/test/fixtures/transport-preload.mjs +13 -0
- package/test/fixtures/transport-string-stdout.js +9 -0
- package/test/fixtures/transport-transform.js +21 -0
- package/test/fixtures/transport-uses-pino-config.js +33 -0
- package/test/fixtures/transport-with-on-exit.js +12 -0
- package/test/fixtures/transport-worker-data.js +19 -0
- package/test/fixtures/transport-worker-name.js +24 -0
- package/test/fixtures/transport-worker.js +15 -0
- package/test/fixtures/transport-wrong-export-type.js +3 -0
- package/test/fixtures/ts/to-file-transport-native.mts +15 -0
- package/test/fixtures/ts/to-file-transport-with-transform.ts +18 -0
- package/test/fixtures/ts/to-file-transport.ts +11 -0
- package/test/fixtures/ts/transpile.cjs +36 -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 +364 -0
- package/test/helper.d.ts +4 -0
- package/test/helper.js +155 -0
- package/test/hooks.test.js +114 -0
- package/test/http.test.js +214 -0
- package/test/internals/version.test.js +17 -0
- package/test/is-level-enabled.test.js +179 -0
- package/test/jest/basic.spec.js +10 -0
- package/test/levels.test.js +810 -0
- package/test/metadata.test.js +120 -0
- package/test/mixin-merge-strategy.test.js +57 -0
- package/test/mixin.test.js +241 -0
- package/test/multistream.test.js +729 -0
- package/test/redact.test.js +893 -0
- package/test/serializers.test.js +257 -0
- package/test/stdout-protection.test.js +41 -0
- package/test/syncfalse.test.js +186 -0
- package/test/timestamp-nano.test.js +37 -0
- package/test/timestamp.test.js +124 -0
- package/test/transport/big.test.js +42 -0
- package/test/transport/bundlers-support.test.js +99 -0
- package/test/transport/caller.test.js +24 -0
- package/test/transport/core.test.js +733 -0
- package/test/transport/core.transpiled.test.ts +114 -0
- package/test/transport/crash.test.js +36 -0
- package/test/transport/module-link.test.js +241 -0
- package/test/transport/native-type-stripping.test.mjs +151 -0
- package/test/transport/node-options.test.js +116 -0
- package/test/transport/pipeline.test.js +137 -0
- package/test/transport/preload.test.js +54 -0
- package/test/transport/repl.test.js +15 -0
- package/test/transport/sync-false.test.js +67 -0
- package/test/transport/sync-true.test.js +57 -0
- package/test/transport/targets.test.js +48 -0
- package/test/transport/uses-pino-config.test.js +166 -0
- package/test/transport-stream.test.js +40 -0
- package/test/types/pino-import.test-d.cts +30 -0
- package/test/types/pino-multistream.test-d.ts +28 -0
- package/test/types/pino-top-export.test-d.ts +34 -0
- package/test/types/pino-transport.test-d.ts +156 -0
- package/test/types/pino-type-only.test-d.ts +75 -0
- package/test/types/pino.test-d.ts +683 -0
- package/test/types/pino.ts +91 -0
- package/tsconfig.json +14 -0
|
@@ -0,0 +1,56 @@
|
|
|
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 {Promise<function(object): Promise<import('node: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 = target.startsWith('file://') ? target : '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/pinojs/thread-stream/pull/34
|
|
32
|
+
if ((error.code === 'ENOTDIR' || error.code === 'ERR_MODULE_NOT_FOUND')) {
|
|
33
|
+
fn = realRequire(target)
|
|
34
|
+
} else if (error.code === undefined || error.code === 'ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING') {
|
|
35
|
+
// When bundled with pkg, an undefined error is thrown when called with realImport
|
|
36
|
+
// When bundled with pkg and using node v20, an ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING error is thrown when called with realImport
|
|
37
|
+
// More info at: https://github.com/pinojs/thread-stream/issues/143
|
|
38
|
+
try {
|
|
39
|
+
fn = realRequire(decodeURIComponent(target))
|
|
40
|
+
} catch {
|
|
41
|
+
throw error
|
|
42
|
+
}
|
|
43
|
+
} else {
|
|
44
|
+
throw error
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Depending on how the default export is performed, and on how the code is
|
|
49
|
+
// transpiled, we may find cases of two nested "default" objects.
|
|
50
|
+
// See https://github.com/pinojs/pino/issues/1243#issuecomment-982774762
|
|
51
|
+
if (typeof fn === 'object') fn = fn.default
|
|
52
|
+
if (typeof fn === 'object') fn = fn.default
|
|
53
|
+
if (typeof fn !== 'function') throw Error('exported worker is not a function')
|
|
54
|
+
|
|
55
|
+
return fn
|
|
56
|
+
}
|
package/lib/transport.js
ADDED
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { createRequire } = require('module')
|
|
4
|
+
const { existsSync } = require('node:fs')
|
|
5
|
+
const getCallers = require('./caller')
|
|
6
|
+
const { join, isAbsolute, sep } = require('node:path')
|
|
7
|
+
const { fileURLToPath } = require('node:url')
|
|
8
|
+
const sleep = require('atomic-sleep')
|
|
9
|
+
const onExit = require('on-exit-leak-free')
|
|
10
|
+
const ThreadStream = require('thread-stream')
|
|
11
|
+
|
|
12
|
+
function setupOnExit (stream) {
|
|
13
|
+
// This is leak free, it does not leave event handlers
|
|
14
|
+
onExit.register(stream, autoEnd)
|
|
15
|
+
onExit.registerBeforeExit(stream, flush)
|
|
16
|
+
|
|
17
|
+
stream.on('close', function () {
|
|
18
|
+
onExit.unregister(stream)
|
|
19
|
+
})
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Check if preload flags exist in execArgv.
|
|
23
|
+
// During preload phase (require.main undefined), we pass empty execArgv to prevent infinite worker spawning.
|
|
24
|
+
// We don't try to filter and pass other flags because many (like --stack-trace-limit, --tls-cipher-list)
|
|
25
|
+
// aren't valid for worker threads and would cause ERR_WORKER_INVALID_EXEC_ARGV.
|
|
26
|
+
function hasPreloadFlags () {
|
|
27
|
+
const execArgv = process.execArgv
|
|
28
|
+
for (let i = 0; i < execArgv.length; i++) {
|
|
29
|
+
const arg = execArgv[i]
|
|
30
|
+
if (arg === '--import' || arg === '--require' || arg === '-r') {
|
|
31
|
+
return true
|
|
32
|
+
}
|
|
33
|
+
if (arg.startsWith('--import=') || arg.startsWith('--require=') || arg.startsWith('-r=')) {
|
|
34
|
+
return true
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return false
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function sanitizeNodeOptions (nodeOptions) {
|
|
41
|
+
const tokens = nodeOptions.match(/(?:[^\s"']+|"[^"]*"|'[^']*')+/g)
|
|
42
|
+
if (!tokens) {
|
|
43
|
+
return nodeOptions
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const sanitized = []
|
|
47
|
+
let changed = false
|
|
48
|
+
|
|
49
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
50
|
+
const token = tokens[i]
|
|
51
|
+
|
|
52
|
+
if (token === '--require' || token === '-r' || token === '--import') {
|
|
53
|
+
const next = tokens[i + 1]
|
|
54
|
+
if (next && shouldDropPreload(next)) {
|
|
55
|
+
changed = true
|
|
56
|
+
i++
|
|
57
|
+
continue
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
sanitized.push(token)
|
|
61
|
+
if (next) {
|
|
62
|
+
sanitized.push(next)
|
|
63
|
+
i++
|
|
64
|
+
}
|
|
65
|
+
continue
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (token.startsWith('--require=') || token.startsWith('-r=') || token.startsWith('--import=')) {
|
|
69
|
+
const value = token.slice(token.indexOf('=') + 1)
|
|
70
|
+
if (shouldDropPreload(value)) {
|
|
71
|
+
changed = true
|
|
72
|
+
continue
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
sanitized.push(token)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return changed ? sanitized.join(' ') : nodeOptions
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function shouldDropPreload (value) {
|
|
83
|
+
const unquoted = stripQuotes(value)
|
|
84
|
+
if (!unquoted) {
|
|
85
|
+
return false
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
let path = unquoted
|
|
89
|
+
if (path.startsWith('file://')) {
|
|
90
|
+
try {
|
|
91
|
+
path = fileURLToPath(path)
|
|
92
|
+
} catch {
|
|
93
|
+
return false
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return isAbsolute(path) && !existsSync(path)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function stripQuotes (value) {
|
|
101
|
+
const first = value[0]
|
|
102
|
+
const last = value[value.length - 1]
|
|
103
|
+
|
|
104
|
+
if ((first === '"' && last === '"') || (first === "'" && last === "'")) {
|
|
105
|
+
return value.slice(1, -1)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return value
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function buildStream (filename, workerData, workerOpts, sync, name) {
|
|
112
|
+
// When pino is loaded during a preload phase (via --import or --require),
|
|
113
|
+
// pass empty execArgv to prevent infinite spawning. Each worker would
|
|
114
|
+
// otherwise re-run the preload, creating another transport.
|
|
115
|
+
if (!workerOpts.execArgv && hasPreloadFlags() && require.main === undefined) {
|
|
116
|
+
workerOpts = {
|
|
117
|
+
...workerOpts,
|
|
118
|
+
execArgv: []
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (!workerOpts.env && process.env.NODE_OPTIONS) {
|
|
123
|
+
const nodeOptions = sanitizeNodeOptions(process.env.NODE_OPTIONS)
|
|
124
|
+
if (nodeOptions !== process.env.NODE_OPTIONS) {
|
|
125
|
+
workerOpts = {
|
|
126
|
+
...workerOpts,
|
|
127
|
+
env: {
|
|
128
|
+
...process.env,
|
|
129
|
+
NODE_OPTIONS: nodeOptions
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
workerOpts = { ...workerOpts, name }
|
|
136
|
+
|
|
137
|
+
const stream = new ThreadStream({
|
|
138
|
+
filename,
|
|
139
|
+
workerData,
|
|
140
|
+
workerOpts,
|
|
141
|
+
sync
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
stream.on('ready', onReady)
|
|
145
|
+
stream.on('close', function () {
|
|
146
|
+
process.removeListener('exit', onExit)
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
process.on('exit', onExit)
|
|
150
|
+
|
|
151
|
+
function onReady () {
|
|
152
|
+
process.removeListener('exit', onExit)
|
|
153
|
+
stream.unref()
|
|
154
|
+
|
|
155
|
+
if (workerOpts.autoEnd !== false) {
|
|
156
|
+
setupOnExit(stream)
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function onExit () {
|
|
161
|
+
/* istanbul ignore next */
|
|
162
|
+
if (stream.closed) {
|
|
163
|
+
return
|
|
164
|
+
}
|
|
165
|
+
stream.flushSync()
|
|
166
|
+
// Apparently there is a very sporadic race condition
|
|
167
|
+
// that in certain OS would prevent the messages to be flushed
|
|
168
|
+
// because the thread might not have been created still.
|
|
169
|
+
// Unfortunately we need to sleep(100) in this case.
|
|
170
|
+
sleep(100)
|
|
171
|
+
stream.end()
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return stream
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function autoEnd (stream) {
|
|
178
|
+
stream.ref()
|
|
179
|
+
stream.flushSync()
|
|
180
|
+
stream.end()
|
|
181
|
+
stream.once('close', function () {
|
|
182
|
+
stream.unref()
|
|
183
|
+
})
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function flush (stream) {
|
|
187
|
+
stream.flushSync()
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function transport (fullOptions) {
|
|
191
|
+
const { pipeline, targets, levels, dedupe, worker = {}, caller = getCallers(), sync = false } = fullOptions
|
|
192
|
+
|
|
193
|
+
const options = {
|
|
194
|
+
...fullOptions.options
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Backwards compatibility
|
|
198
|
+
const callers = typeof caller === 'string' ? [caller] : caller
|
|
199
|
+
|
|
200
|
+
// This will be eventually modified by bundlers
|
|
201
|
+
const bundlerOverrides = (typeof globalThis === 'object' &&
|
|
202
|
+
Object.prototype.hasOwnProperty.call(globalThis, '__bundlerPathsOverrides') &&
|
|
203
|
+
globalThis.__bundlerPathsOverrides &&
|
|
204
|
+
typeof globalThis.__bundlerPathsOverrides === 'object')
|
|
205
|
+
? globalThis.__bundlerPathsOverrides
|
|
206
|
+
: Object.create(null)
|
|
207
|
+
|
|
208
|
+
let target = fullOptions.target
|
|
209
|
+
|
|
210
|
+
if (target && targets) {
|
|
211
|
+
throw new Error('only one of target or targets can be specified')
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (targets) {
|
|
215
|
+
target = bundlerOverrides['pino-worker'] || join(__dirname, 'worker.js')
|
|
216
|
+
options.targets = targets.filter(dest => dest.target).map((dest) => {
|
|
217
|
+
return {
|
|
218
|
+
...dest,
|
|
219
|
+
target: fixTarget(dest.target)
|
|
220
|
+
}
|
|
221
|
+
})
|
|
222
|
+
options.pipelines = targets.filter(dest => dest.pipeline).map((dest) => {
|
|
223
|
+
return dest.pipeline.map((t) => {
|
|
224
|
+
return {
|
|
225
|
+
...t,
|
|
226
|
+
level: dest.level, // duplicate the pipeline `level` property defined in the upper level
|
|
227
|
+
target: fixTarget(t.target)
|
|
228
|
+
}
|
|
229
|
+
})
|
|
230
|
+
})
|
|
231
|
+
} else if (pipeline) {
|
|
232
|
+
target = bundlerOverrides['pino-worker'] || join(__dirname, 'worker.js')
|
|
233
|
+
options.pipelines = [pipeline.map((dest) => {
|
|
234
|
+
return {
|
|
235
|
+
...dest,
|
|
236
|
+
target: fixTarget(dest.target)
|
|
237
|
+
}
|
|
238
|
+
})]
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (levels) {
|
|
242
|
+
options.levels = levels
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (dedupe) {
|
|
246
|
+
options.dedupe = dedupe
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
options.pinoWillSendConfig = true
|
|
250
|
+
|
|
251
|
+
const name = (targets || pipeline) ? 'pino.transport' : target
|
|
252
|
+
return buildStream(fixTarget(target), options, worker, sync, name)
|
|
253
|
+
|
|
254
|
+
function fixTarget (origin) {
|
|
255
|
+
origin = bundlerOverrides[origin] || origin
|
|
256
|
+
|
|
257
|
+
if (isAbsolute(origin) || origin.indexOf('file://') === 0) {
|
|
258
|
+
return origin
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (origin === 'pino/file') {
|
|
262
|
+
return join(__dirname, '..', 'file.js')
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
let fixTarget
|
|
266
|
+
|
|
267
|
+
for (const filePath of callers) {
|
|
268
|
+
try {
|
|
269
|
+
const context = filePath === 'node:repl'
|
|
270
|
+
? process.cwd() + sep
|
|
271
|
+
: filePath
|
|
272
|
+
|
|
273
|
+
fixTarget = createRequire(context).resolve(origin)
|
|
274
|
+
break
|
|
275
|
+
} catch (err) {
|
|
276
|
+
// Silent catch
|
|
277
|
+
continue
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (!fixTarget) {
|
|
282
|
+
throw new Error(`unable to determine transport target for "${origin}"`)
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return fixTarget
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
module.exports = transport
|
package/lib/worker.js
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const EE = require('node:events')
|
|
4
|
+
const { pipeline, PassThrough } = require('node:stream')
|
|
5
|
+
const pino = require('../pino.js')
|
|
6
|
+
const build = require('pino-abstract-transport')
|
|
7
|
+
const loadTransportStreamBuilder = require('./transport-stream')
|
|
8
|
+
|
|
9
|
+
// This file is not checked by the code coverage tool,
|
|
10
|
+
// as it is not reliable.
|
|
11
|
+
|
|
12
|
+
/* istanbul ignore file */
|
|
13
|
+
|
|
14
|
+
/*
|
|
15
|
+
* > Multiple targets & pipelines
|
|
16
|
+
*
|
|
17
|
+
*
|
|
18
|
+
* ┌─────────────────────────────────────────────────┐ ┌─────┐
|
|
19
|
+
* │ │ │ p │
|
|
20
|
+
* │ │ │ i │
|
|
21
|
+
* │ target │ │ n │
|
|
22
|
+
* │ │ ────────────────────────────────┼────┤ o │
|
|
23
|
+
* │ targets │ target │ │ . │
|
|
24
|
+
* │ ────────────► │ ────────────────────────────────┼────┤ m │ source
|
|
25
|
+
* │ │ target │ │ u │ │
|
|
26
|
+
* │ │ ────────────────────────────────┼────┤ l │ │write
|
|
27
|
+
* │ │ │ │ t │ ▼
|
|
28
|
+
* │ │ pipeline ┌───────────────┐ │ │ i │ ┌────────┐
|
|
29
|
+
* │ │ ──────────► │ PassThrough ├───┼────┤ s ├──────┤ │
|
|
30
|
+
* │ │ └───────────────┘ │ │ t │ write│ Thread │
|
|
31
|
+
* │ │ │ │ r │◄─────┤ Stream │
|
|
32
|
+
* │ │ pipeline ┌───────────────┐ │ │ e │ │ │
|
|
33
|
+
* │ │ ──────────► │ PassThrough ├───┼────┤ a │ └────────┘
|
|
34
|
+
* │ └───────────────┘ │ │ m │
|
|
35
|
+
* │ │ │ │
|
|
36
|
+
* └─────────────────────────────────────────────────┘ └─────┘
|
|
37
|
+
*
|
|
38
|
+
*
|
|
39
|
+
*
|
|
40
|
+
* > One single pipeline or target
|
|
41
|
+
*
|
|
42
|
+
*
|
|
43
|
+
* source
|
|
44
|
+
* │
|
|
45
|
+
* ┌────────────────────────────────────────────────┐ │write
|
|
46
|
+
* │ │ ▼
|
|
47
|
+
* │ │ ┌────────┐
|
|
48
|
+
* │ targets │ target │ │ │
|
|
49
|
+
* │ ────────────► │ ──────────────────────────────┤ │ │
|
|
50
|
+
* │ │ │ │ │
|
|
51
|
+
* │ ├──────┤ │
|
|
52
|
+
* │ │ │ │
|
|
53
|
+
* │ │ │ │
|
|
54
|
+
* │ OR │ │ │
|
|
55
|
+
* │ │ │ │
|
|
56
|
+
* │ │ │ │
|
|
57
|
+
* │ ┌──────────────┐ │ │ │
|
|
58
|
+
* │ targets │ pipeline │ │ │ │ Thread │
|
|
59
|
+
* │ ────────────► │ ────────────►│ PassThrough ├─┤ │ Stream │
|
|
60
|
+
* │ │ │ │ │ │ │
|
|
61
|
+
* │ └──────────────┘ │ │ │
|
|
62
|
+
* │ │ │ │
|
|
63
|
+
* │ OR │ write│ │
|
|
64
|
+
* │ │◄─────┤ │
|
|
65
|
+
* │ │ │ │
|
|
66
|
+
* │ ┌──────────────┐ │ │ │
|
|
67
|
+
* │ pipeline │ │ │ │ │
|
|
68
|
+
* │ ──────────────►│ PassThrough ├────────────────┤ │ │
|
|
69
|
+
* │ │ │ │ │ │
|
|
70
|
+
* │ └──────────────┘ │ └────────┘
|
|
71
|
+
* │ │
|
|
72
|
+
* │ │
|
|
73
|
+
* └────────────────────────────────────────────────┘
|
|
74
|
+
*/
|
|
75
|
+
|
|
76
|
+
module.exports = async function ({ targets, pipelines, levels, dedupe }) {
|
|
77
|
+
const targetStreams = []
|
|
78
|
+
|
|
79
|
+
// Process targets
|
|
80
|
+
if (targets && targets.length) {
|
|
81
|
+
targets = await Promise.all(targets.map(async (t) => {
|
|
82
|
+
const fn = await loadTransportStreamBuilder(t.target)
|
|
83
|
+
const stream = await fn(t.options)
|
|
84
|
+
return {
|
|
85
|
+
level: t.level,
|
|
86
|
+
stream
|
|
87
|
+
}
|
|
88
|
+
}))
|
|
89
|
+
|
|
90
|
+
targetStreams.push(...targets)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Process pipelines
|
|
94
|
+
if (pipelines && pipelines.length) {
|
|
95
|
+
pipelines = await Promise.all(
|
|
96
|
+
pipelines.map(async (p) => {
|
|
97
|
+
let level
|
|
98
|
+
const pipeDests = await Promise.all(
|
|
99
|
+
p.map(async (t) => {
|
|
100
|
+
// level assigned to pipeline is duplicated over all its targets, just store it
|
|
101
|
+
level = t.level
|
|
102
|
+
const fn = await loadTransportStreamBuilder(t.target)
|
|
103
|
+
const stream = await fn(t.options)
|
|
104
|
+
return stream
|
|
105
|
+
}
|
|
106
|
+
))
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
level,
|
|
110
|
+
stream: createPipeline(pipeDests)
|
|
111
|
+
}
|
|
112
|
+
})
|
|
113
|
+
)
|
|
114
|
+
targetStreams.push(...pipelines)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Skip building the multistream step if either one single pipeline or target is defined and
|
|
118
|
+
// return directly the stream instance back to TreadStream.
|
|
119
|
+
// This is equivalent to define either:
|
|
120
|
+
//
|
|
121
|
+
// pino.transport({ target: ... })
|
|
122
|
+
//
|
|
123
|
+
// OR
|
|
124
|
+
//
|
|
125
|
+
// pino.transport({ pipeline: ... })
|
|
126
|
+
if (targetStreams.length === 1) {
|
|
127
|
+
return targetStreams[0].stream
|
|
128
|
+
} else {
|
|
129
|
+
return build(process, {
|
|
130
|
+
parse: 'lines',
|
|
131
|
+
metadata: true,
|
|
132
|
+
close (err, cb) {
|
|
133
|
+
let expected = 0
|
|
134
|
+
for (const transport of targetStreams) {
|
|
135
|
+
expected++
|
|
136
|
+
transport.stream.on('close', closeCb)
|
|
137
|
+
transport.stream.end()
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function closeCb () {
|
|
141
|
+
if (--expected === 0) {
|
|
142
|
+
cb(err)
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
})
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// TODO: Why split2 was not used for pipelines?
|
|
150
|
+
function process (stream) {
|
|
151
|
+
const multi = pino.multistream(targetStreams, { levels, dedupe })
|
|
152
|
+
// TODO manage backpressure
|
|
153
|
+
stream.on('data', function (chunk) {
|
|
154
|
+
const { lastTime, lastMsg, lastObj, lastLevel } = this
|
|
155
|
+
multi.lastLevel = lastLevel
|
|
156
|
+
multi.lastTime = lastTime
|
|
157
|
+
multi.lastMsg = lastMsg
|
|
158
|
+
multi.lastObj = lastObj
|
|
159
|
+
|
|
160
|
+
// TODO handle backpressure
|
|
161
|
+
multi.write(chunk + '\n')
|
|
162
|
+
})
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Creates a pipeline using the provided streams and return an instance of `PassThrough` stream
|
|
167
|
+
* as a source for the pipeline.
|
|
168
|
+
*
|
|
169
|
+
* @param {(TransformStream|WritableStream)[]} streams An array of streams.
|
|
170
|
+
* All intermediate streams in the array *MUST* be `Transform` streams and only the last one `Writable`.
|
|
171
|
+
* @returns A `PassThrough` stream instance representing the source stream of the pipeline
|
|
172
|
+
*/
|
|
173
|
+
function createPipeline (streams) {
|
|
174
|
+
const ee = new EE()
|
|
175
|
+
const stream = new PassThrough({
|
|
176
|
+
autoDestroy: true,
|
|
177
|
+
destroy (_, cb) {
|
|
178
|
+
ee.on('error', cb)
|
|
179
|
+
ee.on('closed', cb)
|
|
180
|
+
}
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
pipeline(stream, ...streams, function (err) {
|
|
184
|
+
if (err && err.code !== 'ERR_STREAM_PREMATURE_CLOSE') {
|
|
185
|
+
ee.emit('error', err)
|
|
186
|
+
return
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
ee.emit('closed')
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
return stream
|
|
193
|
+
}
|
|
194
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pino-testkit",
|
|
3
|
+
"version": "10.4.5",
|
|
4
|
+
"description": "super fast, all natural json logger",
|
|
5
|
+
"main": "pino.js",
|
|
6
|
+
"type": "commonjs",
|
|
7
|
+
"types": "pino.d.ts",
|
|
8
|
+
"browser": "./browser.js",
|
|
9
|
+
"scripts": {
|
|
10
|
+
"borp": "borp --timeout 60000 --coverage --check-coverage --lines 95 --functions 95 --branches 95 --statements 95",
|
|
11
|
+
"docs": "docsify serve",
|
|
12
|
+
"browser-test": "airtap --local 8080 test/browser*test.js",
|
|
13
|
+
"lint": "eslint .",
|
|
14
|
+
"test": "npm run lint && npm run transpile && npm run borp && jest test/jest && npm run test-types",
|
|
15
|
+
"test-ci": "npm run lint && npm run transpile && npm run borp && npm run test-types",
|
|
16
|
+
"test-ci-pnpm": "pnpm run lint && npm run transpile && borp --timeout 60000 && pnpm run test-types",
|
|
17
|
+
"test-ci-yarn-pnp": "yarn run lint && npm run transpile && borp --timeout 60000",
|
|
18
|
+
"test-types": "tsc && tsd && ts-node test/types/pino.ts && attw --pack .",
|
|
19
|
+
"test:smoke": "smoker smoke:pino && smoker smoke:browser && smoker smoke:file",
|
|
20
|
+
"smoke:pino": "node ./pino.js",
|
|
21
|
+
"smoke:browser": "node ./browser.js",
|
|
22
|
+
"smoke:file": "node ./file.js",
|
|
23
|
+
"transpile": "node ./test/fixtures/ts/transpile.cjs",
|
|
24
|
+
"cov-ui": "tap --ts --coverage-report=html",
|
|
25
|
+
"bench": "node benchmarks/utils/runbench all",
|
|
26
|
+
"bench-basic": "node benchmarks/utils/runbench basic",
|
|
27
|
+
"bench-object": "node benchmarks/utils/runbench object",
|
|
28
|
+
"bench-deep-object": "node benchmarks/utils/runbench deep-object",
|
|
29
|
+
"bench-multi-arg": "node benchmarks/utils/runbench multi-arg",
|
|
30
|
+
"bench-long-string": "node benchmarks/utils/runbench long-string",
|
|
31
|
+
"bench-child": "node benchmarks/utils/runbench child",
|
|
32
|
+
"bench-child-child": "node benchmarks/utils/runbench child-child",
|
|
33
|
+
"bench-child-creation": "node benchmarks/utils/runbench child-creation",
|
|
34
|
+
"bench-formatters": "node benchmarks/utils/runbench formatters",
|
|
35
|
+
"update-bench-doc": "node benchmarks/utils/generate-benchmark-doc > docs/benchmarks.md"
|
|
36
|
+
},
|
|
37
|
+
"bin": {
|
|
38
|
+
"pino": "./bin.js"
|
|
39
|
+
},
|
|
40
|
+
"precommit": "test",
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "git+https://github.com/pinojs/pino-testkit.git"
|
|
44
|
+
},
|
|
45
|
+
"keywords": [
|
|
46
|
+
"fast",
|
|
47
|
+
"logger",
|
|
48
|
+
"stream",
|
|
49
|
+
"json"
|
|
50
|
+
],
|
|
51
|
+
"author": "Matteo Collina <hello@matteocollina.com>",
|
|
52
|
+
"contributors": [
|
|
53
|
+
"David Mark Clements <huperekchuno@googlemail.com>",
|
|
54
|
+
"James Sumners <james.sumners@gmail.com>",
|
|
55
|
+
"Thomas Watson Steen <w@tson.dk> (https://twitter.com/wa7son)"
|
|
56
|
+
],
|
|
57
|
+
"license": "MIT",
|
|
58
|
+
"bugs": {
|
|
59
|
+
"url": "https://github.com/pinojs/pino-tookit/issues"
|
|
60
|
+
},
|
|
61
|
+
"homepage": "https://getpino.io",
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"@arethetypeswrong/cli": "^0.18.1",
|
|
64
|
+
"@matteo.collina/tspl": "^0.2.0",
|
|
65
|
+
"@types/flush-write-stream": "^1.0.0",
|
|
66
|
+
"@types/node": "^25.0.3",
|
|
67
|
+
"airtap": "5.0.0",
|
|
68
|
+
"bole": "^5.0.5",
|
|
69
|
+
"borp": "^0.21.0",
|
|
70
|
+
"bunyan": "^1.8.14",
|
|
71
|
+
"debug": "^4.3.4",
|
|
72
|
+
"docsify-cli": "^4.4.4",
|
|
73
|
+
"eslint": "^9.37.0",
|
|
74
|
+
"eslint-plugin-import": "^2.26.0",
|
|
75
|
+
"eslint-plugin-n": "17.23.2",
|
|
76
|
+
"eslint-plugin-node": "^11.1.0",
|
|
77
|
+
"eslint-plugin-promise": "^6.0.0",
|
|
78
|
+
"execa": "^5.0.0",
|
|
79
|
+
"fastbench": "^1.0.1",
|
|
80
|
+
"flush-write-stream": "^2.0.0",
|
|
81
|
+
"import-fresh": "^3.2.1",
|
|
82
|
+
"jest": "^30.0.3",
|
|
83
|
+
"log": "^6.0.0",
|
|
84
|
+
"loglevel": "^1.6.7",
|
|
85
|
+
"midnight-smoker": "1.1.1",
|
|
86
|
+
"neostandard": "^0.12.2",
|
|
87
|
+
"pino-pretty": "^13.0.0",
|
|
88
|
+
"pre-commit": "^1.2.2",
|
|
89
|
+
"proxyquire": "^2.1.3",
|
|
90
|
+
"pump": "^3.0.0",
|
|
91
|
+
"rimraf": "^6.0.1",
|
|
92
|
+
"semver": "^7.3.7",
|
|
93
|
+
"split2": "^4.0.0",
|
|
94
|
+
"steed": "^1.1.3",
|
|
95
|
+
"strip-ansi": "^6.0.0",
|
|
96
|
+
"tape": "^5.5.3",
|
|
97
|
+
"through2": "^4.0.0",
|
|
98
|
+
"ts-node": "^10.9.1",
|
|
99
|
+
"tsd": "^0.33.0",
|
|
100
|
+
"typescript": "~5.9.2",
|
|
101
|
+
"winston": "^3.7.2"
|
|
102
|
+
},
|
|
103
|
+
"dependencies": {
|
|
104
|
+
"atomic-sleep": "^1.0.0",
|
|
105
|
+
"on-exit-leak-free": "^2.1.0",
|
|
106
|
+
"pino-abstract-transport": "^3.0.0",
|
|
107
|
+
"pino-std-serializers": "^7.0.0",
|
|
108
|
+
"process-warning": "^5.0.0",
|
|
109
|
+
"quick-format-unescaped": "^4.0.3",
|
|
110
|
+
"real-require": "^0.2.0",
|
|
111
|
+
"safe-stable-stringify": "^2.3.1",
|
|
112
|
+
"@pinojs/redact": "^0.4.0",
|
|
113
|
+
"sonic-boom": "^4.0.1",
|
|
114
|
+
"thread-stream": "^4.0.0"
|
|
115
|
+
},
|
|
116
|
+
"tsd": {
|
|
117
|
+
"directory": "test/types"
|
|
118
|
+
}
|
|
119
|
+
}
|