@verdaccio/logger 9.0.0-next-9.30 → 9.0.0-next-9.32
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/CHANGELOG.md +33 -0
- package/build/logger.js +71 -5
- package/build/logger.js.map +1 -1
- package/build/logger.mjs +71 -5
- package/build/logger.mjs.map +1 -1
- package/build/prettify.js +1 -1
- package/build/prettify.mjs +1 -1
- package/build/transport.js +1 -2
- package/build/transport.js.map +1 -1
- package/build/transport.mjs +2 -3
- package/build/transport.mjs.map +1 -1
- package/package.json +5 -5
- package/src/colors.ts +0 -8
- package/src/formatter.ts +0 -90
- package/src/index.ts +0 -28
- package/src/levels.ts +0 -60
- package/src/logger.ts +0 -126
- package/src/prettify.ts +0 -120
- package/src/transport.ts +0 -36
- package/src/types.ts +0 -6
- package/src/utils.ts +0 -18
- package/test/__snapshots__/formatter.spec.ts.snap +0 -21
- package/test/createLogger.spec.ts +0 -22
- package/test/formatter.spec.ts +0 -214
- package/test/index.spec.ts +0 -49
- package/test/logger.spec.ts +0 -375
- package/test/prettify-onexit.spec.ts +0 -70
- package/test/prettify.spec.ts +0 -387
- package/test/transport.spec.ts +0 -108
- package/test/utils.test.ts +0 -19
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
# @verdaccio/logger
|
|
2
2
|
|
|
3
|
+
## 9.0.0-next-9.32
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 107c4d3: Avoid creating an unused stdout destination when pretty logging uses its own transport.
|
|
8
|
+
- f3f8976: chore: replace \_\_dirname with import.meta.dirname
|
|
9
|
+
- 89a7362: Prevent file logging failures from unexpectedly terminating the registry.
|
|
10
|
+
|
|
11
|
+
In the 9.x asynchronous file logging path, an unsuccessful initial open could leave a
|
|
12
|
+
destination registered for process exit and cause `sonic boom is not ready yet`. Setup
|
|
13
|
+
now reports the original error and removes only the destination that failed to open;
|
|
14
|
+
healthy destinations continue to flush when the process exits.
|
|
15
|
+
|
|
16
|
+
After a file opens successfully, write and reopen errors are reported as structured
|
|
17
|
+
JSON errors on standard error. Error handling remains active for repeated failures,
|
|
18
|
+
including synchronous reopen failures during log rotation. Logging can resume after
|
|
19
|
+
the destination becomes writable again, and configured redaction also applies to the
|
|
20
|
+
error reports. No configuration change is required.
|
|
21
|
+
- 107c4d3: Honor the configured `sync` option for JSON logs written to stdout or files, including in production. Keep asynchronous writes as the default.
|
|
22
|
+
- Updated dependencies [59f1350]
|
|
23
|
+
- @verdaccio/core@9.0.0-next-9.32
|
|
24
|
+
|
|
25
|
+
## 9.0.0-next-9.31
|
|
26
|
+
|
|
27
|
+
### Patch Changes
|
|
28
|
+
|
|
29
|
+
- Updated dependencies [c2b5897]
|
|
30
|
+
- Updated dependencies [68ab0d4]
|
|
31
|
+
- Updated dependencies [c52b632]
|
|
32
|
+
- Updated dependencies [7054084]
|
|
33
|
+
- Updated dependencies [cf15239]
|
|
34
|
+
- @verdaccio/core@9.0.0-next-9.31
|
|
35
|
+
|
|
3
36
|
## 9.0.0-next-9.30
|
|
4
37
|
|
|
5
38
|
### Patch Changes
|
package/build/logger.js
CHANGED
|
@@ -3,6 +3,7 @@ const require_formatter = require("./formatter.js");
|
|
|
3
3
|
const require_transport = require("./transport.js");
|
|
4
4
|
let debug = require("debug");
|
|
5
5
|
debug = require_runtime.__toESM(debug);
|
|
6
|
+
let on_exit_leak_free = require("on-exit-leak-free");
|
|
6
7
|
//#region src/logger.ts
|
|
7
8
|
var debug$1 = (0, debug.default)("verdaccio:logger");
|
|
8
9
|
function isProd() {
|
|
@@ -68,17 +69,82 @@ async function prepareSetup(options = DEFAULT_LOGGER_CONF, pino) {
|
|
|
68
69
|
if (loggerConfig.type === "file") {
|
|
69
70
|
debug$1("logging file enabled");
|
|
70
71
|
if (willUseTransport(loggerConfig.format)) return createLogger(loggerConfig, void 0, loggerConfig.format, pino);
|
|
71
|
-
const destination = pino.destination(
|
|
72
|
+
const destination = pino.destination({
|
|
73
|
+
dest: loggerConfig.path,
|
|
74
|
+
sync: loggerConfig.sync ?? false,
|
|
75
|
+
minLength: 0
|
|
76
|
+
});
|
|
77
|
+
let errorLogger;
|
|
78
|
+
let reopening = false;
|
|
79
|
+
let reopenListeners = [];
|
|
80
|
+
const onReopenReady = () => {
|
|
81
|
+
reopening = false;
|
|
82
|
+
reopenListeners = [];
|
|
83
|
+
};
|
|
84
|
+
const reportedErrors = /* @__PURE__ */ new WeakSet();
|
|
85
|
+
const onRuntimeError = (error) => {
|
|
86
|
+
if (reportedErrors.has(error)) return;
|
|
87
|
+
reportedErrors.add(error);
|
|
88
|
+
for (const listener of reopenListeners) destination.removeListener("ready", listener);
|
|
89
|
+
destination.removeListener("ready", onReopenReady);
|
|
90
|
+
reopening = false;
|
|
91
|
+
reopenListeners = [];
|
|
92
|
+
(errorLogger ??= createLogger({
|
|
93
|
+
level: "error",
|
|
94
|
+
redact: loggerConfig.redact
|
|
95
|
+
}, pino.destination({
|
|
96
|
+
dest: 2,
|
|
97
|
+
sync: true,
|
|
98
|
+
minLength: 0
|
|
99
|
+
}), "json", pino)).error({
|
|
100
|
+
err: error,
|
|
101
|
+
path: loggerConfig.path
|
|
102
|
+
}, "file log destination error");
|
|
103
|
+
};
|
|
72
104
|
await new Promise((resolve, reject) => {
|
|
73
|
-
|
|
74
|
-
|
|
105
|
+
const onReady = () => {
|
|
106
|
+
destination.removeListener("error", onError);
|
|
107
|
+
destination.on("error", onRuntimeError);
|
|
108
|
+
resolve();
|
|
109
|
+
};
|
|
110
|
+
const onError = (error) => {
|
|
111
|
+
destination.removeListener("ready", onReady);
|
|
112
|
+
(0, on_exit_leak_free.unregister)(destination);
|
|
113
|
+
reject(error);
|
|
114
|
+
};
|
|
115
|
+
destination.once("ready", onReady);
|
|
116
|
+
destination.once("error", onError);
|
|
75
117
|
});
|
|
76
118
|
debug$1("file destination ready: %s", loggerConfig.path);
|
|
77
|
-
|
|
119
|
+
const reopen = destination.reopen.bind(destination);
|
|
120
|
+
destination.reopen = (file) => {
|
|
121
|
+
if (!reopening) {
|
|
122
|
+
reopening = true;
|
|
123
|
+
destination.once("ready", onReopenReady);
|
|
124
|
+
}
|
|
125
|
+
const previousListeners = new Set(destination.rawListeners("ready"));
|
|
126
|
+
let reopenError;
|
|
127
|
+
try {
|
|
128
|
+
reopen(file);
|
|
129
|
+
} catch (error) {
|
|
130
|
+
reopenError = error;
|
|
131
|
+
} finally {
|
|
132
|
+
reopenListeners.push(...destination.rawListeners("ready").filter((listener) => !previousListeners.has(listener)));
|
|
133
|
+
}
|
|
134
|
+
if (reopenError) onRuntimeError(reopenError);
|
|
135
|
+
};
|
|
136
|
+
process.on("SIGUSR2", () => {
|
|
137
|
+
if (!reopening) destination.reopen();
|
|
138
|
+
});
|
|
78
139
|
return createLogger(loggerConfig, destination, loggerConfig.format, pino);
|
|
79
140
|
}
|
|
80
141
|
debug$1("logging stdout enabled");
|
|
81
|
-
|
|
142
|
+
const destination = willUseTransport(loggerConfig.format) ? void 0 : pino.destination({
|
|
143
|
+
dest: 1,
|
|
144
|
+
sync: loggerConfig.sync ?? false,
|
|
145
|
+
minLength: 0
|
|
146
|
+
});
|
|
147
|
+
return createLogger(loggerConfig, destination, loggerConfig.format, pino);
|
|
82
148
|
}
|
|
83
149
|
//#endregion
|
|
84
150
|
exports.createLogger = createLogger;
|
package/build/logger.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.js","names":[],"sources":["../src/logger.ts"],"sourcesContent":["// <reference types=\"node\" />\nimport buildDebug from 'debug';\nimport type { LoggerOptions } from 'pino';\n\nimport type { Logger, LoggerConfigItem, LoggerFormat } from '@verdaccio/types';\n\nimport { fillInMsgTemplate } from './formatter';\nimport { createPrettyTransport, isPrettyFormat } from './transport';\n\nconst debug = buildDebug('verdaccio:logger');\n\nfunction isProd() {\n return process.env.NODE_ENV === 'production';\n}\n\nconst DEFAULT_LOG_FORMAT = isProd() ? 'json' : 'pretty';\ndebug('default log format: %s', DEFAULT_LOG_FORMAT);\n\nexport type LogPlugin = {\n dest: string;\n options?: any[];\n};\n\nexport function createLogger(\n options: LoggerConfigItem = { level: 'http' },\n destination: NodeJS.WritableStream | undefined,\n format: LoggerFormat = DEFAULT_LOG_FORMAT,\n pino\n): any {\n debug('setup logger');\n let pinoConfig: LoggerOptions = {\n customLevels: {\n http: 25,\n },\n level: options.level,\n serializers: {\n err: pino.stdSerializers.err,\n req: pino.stdSerializers.req,\n res: pino.stdSerializers.res,\n },\n redact: options.redact,\n };\n\n debug('has prettifier? %o', !isProd());\n let logger;\n // pretty logs are not allowed in production for performance reasons\n if (isPrettyFormat(format) && isProd() === false) {\n const transport = createPrettyTransport(pino, options, format);\n logger = pino(pinoConfig, transport);\n } else {\n pinoConfig = {\n ...pinoConfig,\n // https://getpino.io/#/docs/api?id=hooks-object\n hooks: {\n logMethod(args: [obj: unknown, msg?: string, ...rest: unknown[]], method, _level) {\n const [templateObject, message, ...otherArgs] = args;\n const templateVars =\n !!templateObject && typeof templateObject === 'object'\n ? Object.getOwnPropertyNames(templateObject)\n : [];\n if (!message || !templateVars.length) return method.apply(this, args);\n const hydratedMessage = fillInMsgTemplate(message, templateObject as any, false);\n return method.apply(this, [templateObject, hydratedMessage, ...otherArgs] as any);\n },\n },\n };\n logger = pino(pinoConfig, destination);\n }\n\n if (process.env.DEBUG) {\n logger.on('level-change', (lvl, val, prevLvl, prevVal, instance) => {\n if (logger !== instance) {\n return;\n }\n debug('%s (%d) was changed to %s (%d)', lvl, val, prevLvl, prevVal);\n });\n }\n\n return logger;\n}\n\nconst DEFAULT_LOGGER_CONF: LoggerConfigItem = {\n type: 'stdout',\n format: 'pretty',\n level: 'http',\n};\n\nexport type LoggerConfig = LoggerConfigItem;\n\nexport function willUseTransport(format: LoggerFormat | undefined): boolean {\n const resolvedFormat = format ?? (isProd() ? 'json' : 'pretty');\n return isPrettyFormat(resolvedFormat) && isProd() === false;\n}\n\nexport async function prepareSetup(\n options: LoggerConfigItem = DEFAULT_LOGGER_CONF,\n pino\n): Promise<Logger> {\n let loggerConfig = options;\n if (!loggerConfig?.level) {\n loggerConfig = {\n ...loggerConfig,\n level: 'http',\n };\n }\n if (loggerConfig.type === 'file') {\n debug('logging file enabled');\n // Pretty format uses a pino transport that creates its own destination stream,\n // so no destination is needed here.\n if (willUseTransport(loggerConfig.format)) {\n return createLogger(loggerConfig, undefined, loggerConfig.format, pino);\n }\n // For file destinations (json format), wait for the fd to be ready\n // so we fail fast on bad paths / permissions instead of losing early logs\n const destination = pino.destination(loggerConfig.path);\n await new Promise<void>((resolve, reject) => {\n destination.once('ready', resolve);\n destination.once('error', reject);\n });\n debug('file destination ready: %s', loggerConfig.path);\n process.on('SIGUSR2', () => destination.reopen());\n return createLogger(loggerConfig, destination, loggerConfig.format, pino);\n }\n debug('logging stdout enabled');\n return createLogger(loggerConfig, pino.destination(1), loggerConfig.format, pino);\n}\n"],"mappings":";;;;;;AASA,IAAM,WAAA,GAAQ,MAAA,QAAA,CAAW,kBAAkB;AAE3C,SAAS,SAAS;CAChB,OAAA,QAAA,IAAA,aAAgC;AAClC;AAEA,IAAM,qBAAqB,OAAO,IAAI,SAAS;AAC/C,QAAM,0BAA0B,kBAAkB;AAOlD,SAAgB,aACd,UAA4B,EAAE,OAAO,OAAO,GAC5C,aACA,SAAuB,oBACvB,MACK;CACL,QAAM,cAAc;CACpB,IAAI,aAA4B;EAC9B,cAAc,EACZ,MAAM,GACR;EACA,OAAO,QAAQ;EACf,aAAa;GACX,KAAK,KAAK,eAAe;GACzB,KAAK,KAAK,eAAe;GACzB,KAAK,KAAK,eAAe;EAC3B;EACA,QAAQ,QAAQ;CAClB;CAEA,QAAM,sBAAsB,CAAC,OAAO,CAAC;CACrC,IAAI;CAEJ,IAAI,kBAAA,eAAe,MAAM,KAAK,OAAO,MAAM,OAAO;EAChD,MAAM,YAAY,kBAAA,sBAAsB,MAAM,SAAS,MAAM;EAC7D,SAAS,KAAK,YAAY,SAAS;CACrC,OAAO;EACL,aAAa;GACX,GAAG;GAEH,OAAO,EACL,UAAU,MAAwD,QAAQ,QAAQ;IAChF,MAAM,CAAC,gBAAgB,SAAS,GAAG,aAAa;IAChD,MAAM,eACJ,CAAC,CAAC,kBAAkB,OAAO,mBAAmB,WAC1C,OAAO,oBAAoB,cAAc,IACzC,CAAC;IACP,IAAI,CAAC,WAAW,CAAC,aAAa,QAAQ,OAAO,OAAO,MAAM,MAAM,IAAI;IACpE,MAAM,kBAAkB,kBAAA,kBAAkB,SAAS,gBAAuB,KAAK;IAC/E,OAAO,OAAO,MAAM,MAAM;KAAC;KAAgB;KAAiB,GAAG;IAAS,CAAQ;GAClF,EACF;EACF;EACA,SAAS,KAAK,YAAY,WAAW;CACvC;CAEA,IAAI,QAAQ,IAAI,OACd,OAAO,GAAG,iBAAiB,KAAK,KAAK,SAAS,SAAS,aAAa;EAClE,IAAI,WAAW,UACb;EAEF,QAAM,kCAAkC,KAAK,KAAK,SAAS,OAAO;CACpE,CAAC;CAGH,OAAO;AACT;AAEA,IAAM,sBAAwC;CAC5C,MAAM;CACN,QAAQ;CACR,OAAO;AACT;AAIA,SAAgB,iBAAiB,QAA2C;CAC1E,MAAM,iBAAiB,WAAW,OAAO,IAAI,SAAS;CACtD,OAAO,kBAAA,eAAe,cAAc,KAAK,OAAO,MAAM;AACxD;AAEA,eAAsB,aACpB,UAA4B,qBAC5B,MACiB;CACjB,IAAI,eAAe;CACnB,IAAI,CAAC,cAAc,OACjB,eAAe;EACb,GAAG;EACH,OAAO;CACT;CAEF,IAAI,aAAa,SAAS,QAAQ;EAChC,QAAM,sBAAsB;EAG5B,IAAI,iBAAiB,aAAa,MAAM,GACtC,OAAO,aAAa,cAAc,KAAA,GAAW,aAAa,QAAQ,IAAI;EAIxE,MAAM,cAAc,KAAK,YAAY,aAAa,IAAI;EACtD,MAAM,IAAI,SAAe,SAAS,WAAW;GAC3C,YAAY,KAAK,SAAS,OAAO;GACjC,YAAY,KAAK,SAAS,MAAM;EAClC,CAAC;EACD,QAAM,8BAA8B,aAAa,IAAI;EACrD,QAAQ,GAAG,iBAAiB,YAAY,OAAO,CAAC;EAChD,OAAO,aAAa,cAAc,aAAa,aAAa,QAAQ,IAAI;CAC1E;CACA,QAAM,wBAAwB;CAC9B,OAAO,aAAa,cAAc,KAAK,YAAY,CAAC,GAAG,aAAa,QAAQ,IAAI;AAClF"}
|
|
1
|
+
{"version":3,"file":"logger.js","names":[],"sources":["../src/logger.ts"],"sourcesContent":["// <reference types=\"node\" />\nimport buildDebug from 'debug';\nimport { unregister as onExitUnregister } from 'on-exit-leak-free';\nimport type { LoggerOptions } from 'pino';\n\nimport type { Logger, LoggerConfigItem, LoggerFormat } from '@verdaccio/types';\n\nimport { fillInMsgTemplate } from './formatter';\nimport { createPrettyTransport, isPrettyFormat } from './transport';\n\nconst debug = buildDebug('verdaccio:logger');\n\nfunction isProd() {\n return process.env.NODE_ENV === 'production';\n}\n\nconst DEFAULT_LOG_FORMAT = isProd() ? 'json' : 'pretty';\ndebug('default log format: %s', DEFAULT_LOG_FORMAT);\n\nexport type LogPlugin = {\n dest: string;\n options?: any[];\n};\n\nexport function createLogger(\n options: LoggerConfigItem = { level: 'http' },\n destination: NodeJS.WritableStream | undefined,\n format: LoggerFormat = DEFAULT_LOG_FORMAT,\n pino\n): any {\n debug('setup logger');\n let pinoConfig: LoggerOptions = {\n customLevels: {\n http: 25,\n },\n level: options.level,\n serializers: {\n err: pino.stdSerializers.err,\n req: pino.stdSerializers.req,\n res: pino.stdSerializers.res,\n },\n redact: options.redact,\n };\n\n debug('has prettifier? %o', !isProd());\n let logger;\n // pretty logs are not allowed in production for performance reasons\n if (isPrettyFormat(format) && isProd() === false) {\n const transport = createPrettyTransport(pino, options, format);\n logger = pino(pinoConfig, transport);\n } else {\n pinoConfig = {\n ...pinoConfig,\n // https://getpino.io/#/docs/api?id=hooks-object\n hooks: {\n logMethod(args: [obj: unknown, msg?: string, ...rest: unknown[]], method, _level) {\n const [templateObject, message, ...otherArgs] = args;\n const templateVars =\n !!templateObject && typeof templateObject === 'object'\n ? Object.getOwnPropertyNames(templateObject)\n : [];\n if (!message || !templateVars.length) return method.apply(this, args);\n const hydratedMessage = fillInMsgTemplate(message, templateObject as any, false);\n return method.apply(this, [templateObject, hydratedMessage, ...otherArgs] as any);\n },\n },\n };\n logger = pino(pinoConfig, destination);\n }\n\n if (process.env.DEBUG) {\n logger.on('level-change', (lvl, val, prevLvl, prevVal, instance) => {\n if (logger !== instance) {\n return;\n }\n debug('%s (%d) was changed to %s (%d)', lvl, val, prevLvl, prevVal);\n });\n }\n\n return logger;\n}\n\nconst DEFAULT_LOGGER_CONF: LoggerConfigItem = {\n type: 'stdout',\n format: 'pretty',\n level: 'http',\n};\n\nexport type LoggerConfig = LoggerConfigItem;\n\nexport function willUseTransport(format: LoggerFormat | undefined): boolean {\n const resolvedFormat = format ?? (isProd() ? 'json' : 'pretty');\n return isPrettyFormat(resolvedFormat) && isProd() === false;\n}\n\nexport async function prepareSetup(\n options: LoggerConfigItem = DEFAULT_LOGGER_CONF,\n pino\n): Promise<Logger> {\n let loggerConfig = options;\n if (!loggerConfig?.level) {\n loggerConfig = {\n ...loggerConfig,\n level: 'http',\n };\n }\n if (loggerConfig.type === 'file') {\n debug('logging file enabled');\n // Pretty format uses a pino transport that creates its own destination stream,\n // so no destination is needed here.\n if (willUseTransport(loggerConfig.format)) {\n return createLogger(loggerConfig, undefined, loggerConfig.format, pino);\n }\n // For file destinations (json format), wait for the fd to be ready\n // so we fail fast on bad paths / permissions instead of losing early logs\n const destination = pino.destination({\n dest: loggerConfig.path,\n sync: loggerConfig.sync ?? false,\n minLength: 0,\n });\n let errorLogger: Logger | undefined;\n let reopening = false;\n let reopenListeners: (() => void)[] = [];\n const onReopenReady = () => {\n reopening = false;\n reopenListeners = [];\n };\n const reportedErrors = new WeakSet<Error>();\n const onRuntimeError = (error: Error) => {\n // Pino re-emits errors; synchronous reopen failures also throw the same error.\n if (reportedErrors.has(error)) return;\n reportedErrors.add(error);\n // Failed reopens otherwise leave callbacks that close the old fd again on recovery.\n for (const listener of reopenListeners) destination.removeListener('ready', listener);\n destination.removeListener('ready', onReopenReady);\n reopening = false;\n reopenListeners = [];\n const reporter: Logger = (errorLogger ??= createLogger(\n { level: 'error', redact: loggerConfig.redact },\n pino.destination({ dest: 2, sync: true, minLength: 0 }),\n 'json',\n pino\n ));\n reporter.error({ err: error, path: loggerConfig.path }, 'file log destination error');\n };\n await new Promise<void>((resolve, reject) => {\n const onReady = () => {\n destination.removeListener('error', onError);\n destination.on('error', onRuntimeError);\n resolve();\n };\n const onError = (error: Error) => {\n destination.removeListener('ready', onReady);\n // A failed open leaves fd=-1, so Pino's exit flush would throw.\n // SonicBoom.destroy() waits for ready here; unregister the failed stream directly.\n onExitUnregister(destination);\n reject(error);\n };\n destination.once('ready', onReady);\n destination.once('error', onError);\n });\n debug('file destination ready: %s', loggerConfig.path);\n const reopen = destination.reopen.bind(destination);\n // SonicBoom can defer reopening until a pending write finishes.\n destination.reopen = (file?: string) => {\n if (!reopening) {\n reopening = true;\n destination.once('ready', onReopenReady);\n }\n const previousListeners = new Set(destination.rawListeners('ready'));\n let reopenError: Error | undefined;\n try {\n reopen(file);\n } catch (error) {\n reopenError = error as Error;\n } finally {\n reopenListeners.push(\n ...destination\n .rawListeners('ready')\n .filter((listener) => !previousListeners.has(listener))\n );\n }\n if (reopenError) onRuntimeError(reopenError);\n };\n process.on('SIGUSR2', () => {\n if (!reopening) destination.reopen();\n });\n return createLogger(loggerConfig, destination, loggerConfig.format, pino);\n }\n debug('logging stdout enabled');\n const destination = willUseTransport(loggerConfig.format)\n ? undefined\n : pino.destination({ dest: 1, sync: loggerConfig.sync ?? false, minLength: 0 });\n return createLogger(loggerConfig, destination, loggerConfig.format, pino);\n}\n"],"mappings":"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"}
|
package/build/logger.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { fillInMsgTemplate } from "./formatter.mjs";
|
|
2
2
|
import { createPrettyTransport, isPrettyFormat } from "./transport.mjs";
|
|
3
3
|
import buildDebug from "debug";
|
|
4
|
+
import { unregister } from "on-exit-leak-free";
|
|
4
5
|
//#region src/logger.ts
|
|
5
6
|
var debug = buildDebug("verdaccio:logger");
|
|
6
7
|
function isProd() {
|
|
@@ -66,17 +67,82 @@ async function prepareSetup(options = DEFAULT_LOGGER_CONF, pino) {
|
|
|
66
67
|
if (loggerConfig.type === "file") {
|
|
67
68
|
debug("logging file enabled");
|
|
68
69
|
if (willUseTransport(loggerConfig.format)) return createLogger(loggerConfig, void 0, loggerConfig.format, pino);
|
|
69
|
-
const destination = pino.destination(
|
|
70
|
+
const destination = pino.destination({
|
|
71
|
+
dest: loggerConfig.path,
|
|
72
|
+
sync: loggerConfig.sync ?? false,
|
|
73
|
+
minLength: 0
|
|
74
|
+
});
|
|
75
|
+
let errorLogger;
|
|
76
|
+
let reopening = false;
|
|
77
|
+
let reopenListeners = [];
|
|
78
|
+
const onReopenReady = () => {
|
|
79
|
+
reopening = false;
|
|
80
|
+
reopenListeners = [];
|
|
81
|
+
};
|
|
82
|
+
const reportedErrors = /* @__PURE__ */ new WeakSet();
|
|
83
|
+
const onRuntimeError = (error) => {
|
|
84
|
+
if (reportedErrors.has(error)) return;
|
|
85
|
+
reportedErrors.add(error);
|
|
86
|
+
for (const listener of reopenListeners) destination.removeListener("ready", listener);
|
|
87
|
+
destination.removeListener("ready", onReopenReady);
|
|
88
|
+
reopening = false;
|
|
89
|
+
reopenListeners = [];
|
|
90
|
+
(errorLogger ??= createLogger({
|
|
91
|
+
level: "error",
|
|
92
|
+
redact: loggerConfig.redact
|
|
93
|
+
}, pino.destination({
|
|
94
|
+
dest: 2,
|
|
95
|
+
sync: true,
|
|
96
|
+
minLength: 0
|
|
97
|
+
}), "json", pino)).error({
|
|
98
|
+
err: error,
|
|
99
|
+
path: loggerConfig.path
|
|
100
|
+
}, "file log destination error");
|
|
101
|
+
};
|
|
70
102
|
await new Promise((resolve, reject) => {
|
|
71
|
-
|
|
72
|
-
|
|
103
|
+
const onReady = () => {
|
|
104
|
+
destination.removeListener("error", onError);
|
|
105
|
+
destination.on("error", onRuntimeError);
|
|
106
|
+
resolve();
|
|
107
|
+
};
|
|
108
|
+
const onError = (error) => {
|
|
109
|
+
destination.removeListener("ready", onReady);
|
|
110
|
+
unregister(destination);
|
|
111
|
+
reject(error);
|
|
112
|
+
};
|
|
113
|
+
destination.once("ready", onReady);
|
|
114
|
+
destination.once("error", onError);
|
|
73
115
|
});
|
|
74
116
|
debug("file destination ready: %s", loggerConfig.path);
|
|
75
|
-
|
|
117
|
+
const reopen = destination.reopen.bind(destination);
|
|
118
|
+
destination.reopen = (file) => {
|
|
119
|
+
if (!reopening) {
|
|
120
|
+
reopening = true;
|
|
121
|
+
destination.once("ready", onReopenReady);
|
|
122
|
+
}
|
|
123
|
+
const previousListeners = new Set(destination.rawListeners("ready"));
|
|
124
|
+
let reopenError;
|
|
125
|
+
try {
|
|
126
|
+
reopen(file);
|
|
127
|
+
} catch (error) {
|
|
128
|
+
reopenError = error;
|
|
129
|
+
} finally {
|
|
130
|
+
reopenListeners.push(...destination.rawListeners("ready").filter((listener) => !previousListeners.has(listener)));
|
|
131
|
+
}
|
|
132
|
+
if (reopenError) onRuntimeError(reopenError);
|
|
133
|
+
};
|
|
134
|
+
process.on("SIGUSR2", () => {
|
|
135
|
+
if (!reopening) destination.reopen();
|
|
136
|
+
});
|
|
76
137
|
return createLogger(loggerConfig, destination, loggerConfig.format, pino);
|
|
77
138
|
}
|
|
78
139
|
debug("logging stdout enabled");
|
|
79
|
-
|
|
140
|
+
const destination = willUseTransport(loggerConfig.format) ? void 0 : pino.destination({
|
|
141
|
+
dest: 1,
|
|
142
|
+
sync: loggerConfig.sync ?? false,
|
|
143
|
+
minLength: 0
|
|
144
|
+
});
|
|
145
|
+
return createLogger(loggerConfig, destination, loggerConfig.format, pino);
|
|
80
146
|
}
|
|
81
147
|
//#endregion
|
|
82
148
|
export { createLogger, prepareSetup, willUseTransport };
|
package/build/logger.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.mjs","names":[],"sources":["../src/logger.ts"],"sourcesContent":["// <reference types=\"node\" />\nimport buildDebug from 'debug';\nimport type { LoggerOptions } from 'pino';\n\nimport type { Logger, LoggerConfigItem, LoggerFormat } from '@verdaccio/types';\n\nimport { fillInMsgTemplate } from './formatter';\nimport { createPrettyTransport, isPrettyFormat } from './transport';\n\nconst debug = buildDebug('verdaccio:logger');\n\nfunction isProd() {\n return process.env.NODE_ENV === 'production';\n}\n\nconst DEFAULT_LOG_FORMAT = isProd() ? 'json' : 'pretty';\ndebug('default log format: %s', DEFAULT_LOG_FORMAT);\n\nexport type LogPlugin = {\n dest: string;\n options?: any[];\n};\n\nexport function createLogger(\n options: LoggerConfigItem = { level: 'http' },\n destination: NodeJS.WritableStream | undefined,\n format: LoggerFormat = DEFAULT_LOG_FORMAT,\n pino\n): any {\n debug('setup logger');\n let pinoConfig: LoggerOptions = {\n customLevels: {\n http: 25,\n },\n level: options.level,\n serializers: {\n err: pino.stdSerializers.err,\n req: pino.stdSerializers.req,\n res: pino.stdSerializers.res,\n },\n redact: options.redact,\n };\n\n debug('has prettifier? %o', !isProd());\n let logger;\n // pretty logs are not allowed in production for performance reasons\n if (isPrettyFormat(format) && isProd() === false) {\n const transport = createPrettyTransport(pino, options, format);\n logger = pino(pinoConfig, transport);\n } else {\n pinoConfig = {\n ...pinoConfig,\n // https://getpino.io/#/docs/api?id=hooks-object\n hooks: {\n logMethod(args: [obj: unknown, msg?: string, ...rest: unknown[]], method, _level) {\n const [templateObject, message, ...otherArgs] = args;\n const templateVars =\n !!templateObject && typeof templateObject === 'object'\n ? Object.getOwnPropertyNames(templateObject)\n : [];\n if (!message || !templateVars.length) return method.apply(this, args);\n const hydratedMessage = fillInMsgTemplate(message, templateObject as any, false);\n return method.apply(this, [templateObject, hydratedMessage, ...otherArgs] as any);\n },\n },\n };\n logger = pino(pinoConfig, destination);\n }\n\n if (process.env.DEBUG) {\n logger.on('level-change', (lvl, val, prevLvl, prevVal, instance) => {\n if (logger !== instance) {\n return;\n }\n debug('%s (%d) was changed to %s (%d)', lvl, val, prevLvl, prevVal);\n });\n }\n\n return logger;\n}\n\nconst DEFAULT_LOGGER_CONF: LoggerConfigItem = {\n type: 'stdout',\n format: 'pretty',\n level: 'http',\n};\n\nexport type LoggerConfig = LoggerConfigItem;\n\nexport function willUseTransport(format: LoggerFormat | undefined): boolean {\n const resolvedFormat = format ?? (isProd() ? 'json' : 'pretty');\n return isPrettyFormat(resolvedFormat) && isProd() === false;\n}\n\nexport async function prepareSetup(\n options: LoggerConfigItem = DEFAULT_LOGGER_CONF,\n pino\n): Promise<Logger> {\n let loggerConfig = options;\n if (!loggerConfig?.level) {\n loggerConfig = {\n ...loggerConfig,\n level: 'http',\n };\n }\n if (loggerConfig.type === 'file') {\n debug('logging file enabled');\n // Pretty format uses a pino transport that creates its own destination stream,\n // so no destination is needed here.\n if (willUseTransport(loggerConfig.format)) {\n return createLogger(loggerConfig, undefined, loggerConfig.format, pino);\n }\n // For file destinations (json format), wait for the fd to be ready\n // so we fail fast on bad paths / permissions instead of losing early logs\n const destination = pino.destination(loggerConfig.path);\n await new Promise<void>((resolve, reject) => {\n destination.once('ready',
|
|
1
|
+
{"version":3,"file":"logger.mjs","names":[],"sources":["../src/logger.ts"],"sourcesContent":["// <reference types=\"node\" />\nimport buildDebug from 'debug';\nimport { unregister as onExitUnregister } from 'on-exit-leak-free';\nimport type { LoggerOptions } from 'pino';\n\nimport type { Logger, LoggerConfigItem, LoggerFormat } from '@verdaccio/types';\n\nimport { fillInMsgTemplate } from './formatter';\nimport { createPrettyTransport, isPrettyFormat } from './transport';\n\nconst debug = buildDebug('verdaccio:logger');\n\nfunction isProd() {\n return process.env.NODE_ENV === 'production';\n}\n\nconst DEFAULT_LOG_FORMAT = isProd() ? 'json' : 'pretty';\ndebug('default log format: %s', DEFAULT_LOG_FORMAT);\n\nexport type LogPlugin = {\n dest: string;\n options?: any[];\n};\n\nexport function createLogger(\n options: LoggerConfigItem = { level: 'http' },\n destination: NodeJS.WritableStream | undefined,\n format: LoggerFormat = DEFAULT_LOG_FORMAT,\n pino\n): any {\n debug('setup logger');\n let pinoConfig: LoggerOptions = {\n customLevels: {\n http: 25,\n },\n level: options.level,\n serializers: {\n err: pino.stdSerializers.err,\n req: pino.stdSerializers.req,\n res: pino.stdSerializers.res,\n },\n redact: options.redact,\n };\n\n debug('has prettifier? %o', !isProd());\n let logger;\n // pretty logs are not allowed in production for performance reasons\n if (isPrettyFormat(format) && isProd() === false) {\n const transport = createPrettyTransport(pino, options, format);\n logger = pino(pinoConfig, transport);\n } else {\n pinoConfig = {\n ...pinoConfig,\n // https://getpino.io/#/docs/api?id=hooks-object\n hooks: {\n logMethod(args: [obj: unknown, msg?: string, ...rest: unknown[]], method, _level) {\n const [templateObject, message, ...otherArgs] = args;\n const templateVars =\n !!templateObject && typeof templateObject === 'object'\n ? Object.getOwnPropertyNames(templateObject)\n : [];\n if (!message || !templateVars.length) return method.apply(this, args);\n const hydratedMessage = fillInMsgTemplate(message, templateObject as any, false);\n return method.apply(this, [templateObject, hydratedMessage, ...otherArgs] as any);\n },\n },\n };\n logger = pino(pinoConfig, destination);\n }\n\n if (process.env.DEBUG) {\n logger.on('level-change', (lvl, val, prevLvl, prevVal, instance) => {\n if (logger !== instance) {\n return;\n }\n debug('%s (%d) was changed to %s (%d)', lvl, val, prevLvl, prevVal);\n });\n }\n\n return logger;\n}\n\nconst DEFAULT_LOGGER_CONF: LoggerConfigItem = {\n type: 'stdout',\n format: 'pretty',\n level: 'http',\n};\n\nexport type LoggerConfig = LoggerConfigItem;\n\nexport function willUseTransport(format: LoggerFormat | undefined): boolean {\n const resolvedFormat = format ?? (isProd() ? 'json' : 'pretty');\n return isPrettyFormat(resolvedFormat) && isProd() === false;\n}\n\nexport async function prepareSetup(\n options: LoggerConfigItem = DEFAULT_LOGGER_CONF,\n pino\n): Promise<Logger> {\n let loggerConfig = options;\n if (!loggerConfig?.level) {\n loggerConfig = {\n ...loggerConfig,\n level: 'http',\n };\n }\n if (loggerConfig.type === 'file') {\n debug('logging file enabled');\n // Pretty format uses a pino transport that creates its own destination stream,\n // so no destination is needed here.\n if (willUseTransport(loggerConfig.format)) {\n return createLogger(loggerConfig, undefined, loggerConfig.format, pino);\n }\n // For file destinations (json format), wait for the fd to be ready\n // so we fail fast on bad paths / permissions instead of losing early logs\n const destination = pino.destination({\n dest: loggerConfig.path,\n sync: loggerConfig.sync ?? false,\n minLength: 0,\n });\n let errorLogger: Logger | undefined;\n let reopening = false;\n let reopenListeners: (() => void)[] = [];\n const onReopenReady = () => {\n reopening = false;\n reopenListeners = [];\n };\n const reportedErrors = new WeakSet<Error>();\n const onRuntimeError = (error: Error) => {\n // Pino re-emits errors; synchronous reopen failures also throw the same error.\n if (reportedErrors.has(error)) return;\n reportedErrors.add(error);\n // Failed reopens otherwise leave callbacks that close the old fd again on recovery.\n for (const listener of reopenListeners) destination.removeListener('ready', listener);\n destination.removeListener('ready', onReopenReady);\n reopening = false;\n reopenListeners = [];\n const reporter: Logger = (errorLogger ??= createLogger(\n { level: 'error', redact: loggerConfig.redact },\n pino.destination({ dest: 2, sync: true, minLength: 0 }),\n 'json',\n pino\n ));\n reporter.error({ err: error, path: loggerConfig.path }, 'file log destination error');\n };\n await new Promise<void>((resolve, reject) => {\n const onReady = () => {\n destination.removeListener('error', onError);\n destination.on('error', onRuntimeError);\n resolve();\n };\n const onError = (error: Error) => {\n destination.removeListener('ready', onReady);\n // A failed open leaves fd=-1, so Pino's exit flush would throw.\n // SonicBoom.destroy() waits for ready here; unregister the failed stream directly.\n onExitUnregister(destination);\n reject(error);\n };\n destination.once('ready', onReady);\n destination.once('error', onError);\n });\n debug('file destination ready: %s', loggerConfig.path);\n const reopen = destination.reopen.bind(destination);\n // SonicBoom can defer reopening until a pending write finishes.\n destination.reopen = (file?: string) => {\n if (!reopening) {\n reopening = true;\n destination.once('ready', onReopenReady);\n }\n const previousListeners = new Set(destination.rawListeners('ready'));\n let reopenError: Error | undefined;\n try {\n reopen(file);\n } catch (error) {\n reopenError = error as Error;\n } finally {\n reopenListeners.push(\n ...destination\n .rawListeners('ready')\n .filter((listener) => !previousListeners.has(listener))\n );\n }\n if (reopenError) onRuntimeError(reopenError);\n };\n process.on('SIGUSR2', () => {\n if (!reopening) destination.reopen();\n });\n return createLogger(loggerConfig, destination, loggerConfig.format, pino);\n }\n debug('logging stdout enabled');\n const destination = willUseTransport(loggerConfig.format)\n ? undefined\n : pino.destination({ dest: 1, sync: loggerConfig.sync ?? false, minLength: 0 });\n return createLogger(loggerConfig, destination, loggerConfig.format, pino);\n}\n"],"mappings":"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"}
|
package/build/prettify.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
const require_runtime = require("./_virtual/_rolldown/runtime.js");
|
|
2
2
|
const require_formatter = require("./formatter.js");
|
|
3
3
|
const require_colors = require("./colors.js");
|
|
4
|
+
let on_exit_leak_free = require("on-exit-leak-free");
|
|
4
5
|
let node_stream = require("node:stream");
|
|
5
6
|
let node_worker_threads = require("node:worker_threads");
|
|
6
|
-
let on_exit_leak_free = require("on-exit-leak-free");
|
|
7
7
|
let pino_abstract_transport = require("pino-abstract-transport");
|
|
8
8
|
pino_abstract_transport = require_runtime.__toESM(pino_abstract_transport);
|
|
9
9
|
let sonic_boom = require("sonic-boom");
|
package/build/prettify.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { printMessage } from "./formatter.mjs";
|
|
2
2
|
import { hasColors } from "./colors.mjs";
|
|
3
|
+
import { register, unregister } from "on-exit-leak-free";
|
|
3
4
|
import { Transform, pipeline } from "node:stream";
|
|
4
5
|
import { isMainThread } from "node:worker_threads";
|
|
5
|
-
import { register, unregister } from "on-exit-leak-free";
|
|
6
6
|
import build from "pino-abstract-transport";
|
|
7
7
|
import SonicBoom from "sonic-boom";
|
|
8
8
|
//#region src/prettify.ts
|
package/build/transport.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
const require_colors = require("./colors.js");
|
|
2
2
|
let node_path = require("node:path");
|
|
3
|
-
let node_url = require("node:url");
|
|
4
3
|
//#region src/transport.ts
|
|
5
|
-
var currentDir =
|
|
4
|
+
var currentDir = __dirname;
|
|
6
5
|
var prettifyPath = (0, node_path.join)(currentDir, "..", "build", "prettify.js");
|
|
7
6
|
function isPrettyFormat(format) {
|
|
8
7
|
return ["pretty-timestamped", "pretty"].includes(format ?? "pretty");
|
package/build/transport.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.js","names":[],"sources":["../src/transport.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"transport.js","names":[],"sources":["../src/transport.ts"],"sourcesContent":["import { join } from 'node:path';\n\nimport type { LoggerConfigItem, LoggerFormat } from '@verdaccio/types';\n\nimport { hasColors } from './colors';\n\n// Pino transports run in a worker thread via require(), so CJS output must work.\nconst currentDir = import.meta.dirname;\nconst prettifyPath = join(currentDir, '..', 'build', 'prettify.js');\n\nexport function isPrettyFormat(format: LoggerFormat | undefined): boolean {\n return ['pretty-timestamped', 'pretty'].includes(format ?? 'pretty');\n}\n\n/**\n * Create a pino pretty transport for non-production environments.\n */\nexport function createPrettyTransport(pino: any, options: LoggerConfigItem, format: LoggerFormat) {\n return pino.transport({\n target: prettifyPath,\n options: {\n destination: options.path || 1,\n colors: hasColors(options.colors),\n prettyStamp: format === 'pretty-timestamped',\n sync: options.sync ?? false,\n },\n worker: {\n name: 'verdaccio-logger-prettify',\n },\n });\n}\n"],"mappings":";;;AAOA,IAAM,aAAA;AACN,IAAM,gBAAA,GAAe,UAAA,KAAA,CAAK,YAAY,MAAM,SAAS,aAAa;AAElE,SAAgB,eAAe,QAA2C;CACxE,OAAO,CAAC,sBAAsB,QAAQ,CAAC,CAAC,SAAS,UAAU,QAAQ;AACrE;;;;AAKA,SAAgB,sBAAsB,MAAW,SAA2B,QAAsB;CAChG,OAAO,KAAK,UAAU;EACpB,QAAQ;EACR,SAAS;GACP,aAAa,QAAQ,QAAQ;GAC7B,QAAQ,eAAA,UAAU,QAAQ,MAAM;GAChC,aAAa,WAAW;GACxB,MAAM,QAAQ,QAAQ;EACxB;EACA,QAAQ,EACN,MAAM,4BACR;CACF,CAAC;AACH"}
|
package/build/transport.mjs
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { hasColors } from "./colors.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import { fileURLToPath } from "node:url";
|
|
2
|
+
import { join } from "node:path";
|
|
4
3
|
//#region src/transport.ts
|
|
5
|
-
var currentDir = import.meta.
|
|
4
|
+
var currentDir = import.meta.dirname;
|
|
6
5
|
var prettifyPath = join(currentDir, "..", "build", "prettify.js");
|
|
7
6
|
function isPrettyFormat(format) {
|
|
8
7
|
return ["pretty-timestamped", "pretty"].includes(format ?? "pretty");
|
package/build/transport.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.mjs","names":[],"sources":["../src/transport.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"transport.mjs","names":[],"sources":["../src/transport.ts"],"sourcesContent":["import { join } from 'node:path';\n\nimport type { LoggerConfigItem, LoggerFormat } from '@verdaccio/types';\n\nimport { hasColors } from './colors';\n\n// Pino transports run in a worker thread via require(), so CJS output must work.\nconst currentDir = import.meta.dirname;\nconst prettifyPath = join(currentDir, '..', 'build', 'prettify.js');\n\nexport function isPrettyFormat(format: LoggerFormat | undefined): boolean {\n return ['pretty-timestamped', 'pretty'].includes(format ?? 'pretty');\n}\n\n/**\n * Create a pino pretty transport for non-production environments.\n */\nexport function createPrettyTransport(pino: any, options: LoggerConfigItem, format: LoggerFormat) {\n return pino.transport({\n target: prettifyPath,\n options: {\n destination: options.path || 1,\n colors: hasColors(options.colors),\n prettyStamp: format === 'pretty-timestamped',\n sync: options.sync ?? false,\n },\n worker: {\n name: 'verdaccio-logger-prettify',\n },\n });\n}\n"],"mappings":";;;AAOA,IAAM,aAAa,YAAY;AAC/B,IAAM,eAAe,KAAK,YAAY,MAAM,SAAS,aAAa;AAElE,SAAgB,eAAe,QAA2C;CACxE,OAAO,CAAC,sBAAsB,QAAQ,CAAC,CAAC,SAAS,UAAU,QAAQ;AACrE;;;;AAKA,SAAgB,sBAAsB,MAAW,SAA2B,QAAsB;CAChG,OAAO,KAAK,UAAU;EACpB,QAAQ;EACR,SAAS;GACP,aAAa,QAAQ,QAAQ;GAC7B,QAAQ,UAAU,QAAQ,MAAM;GAChC,aAAa,WAAW;GACxB,MAAM,QAAQ,QAAQ;EACxB;EACA,QAAQ,EACN,MAAM,4BACR;CACF,CAAC;AACH"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@verdaccio/logger",
|
|
3
|
-
"version": "9.0.0-next-9.
|
|
3
|
+
"version": "9.0.0-next-9.32",
|
|
4
4
|
"description": "Verdaccio Logger",
|
|
5
5
|
"main": "./build/index.js",
|
|
6
6
|
"types": "./build/index.d.ts",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"node": ">=24"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@verdaccio/core": "9.0.0-next-9.
|
|
36
|
+
"@verdaccio/core": "9.0.0-next-9.32",
|
|
37
37
|
"colorette": "2.0.20",
|
|
38
38
|
"dayjs": "1.11.23",
|
|
39
39
|
"debug": "4.4.3",
|
|
@@ -43,11 +43,11 @@
|
|
|
43
43
|
"sonic-boom": "4.2.1"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@verdaccio/types": "14.0.0-next-9.
|
|
46
|
+
"@verdaccio/types": "14.0.0-next-9.15",
|
|
47
47
|
"cross-env": "10.1.0",
|
|
48
48
|
"rimraf": "6.1.3",
|
|
49
|
-
"vite": "8.2.
|
|
50
|
-
"vitest": "4.1.
|
|
49
|
+
"vite": "8.2.2",
|
|
50
|
+
"vitest": "4.1.11"
|
|
51
51
|
},
|
|
52
52
|
"funding": {
|
|
53
53
|
"type": "opencollective",
|
package/src/colors.ts
DELETED
package/src/formatter.ts
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { green, red, white } from 'colorette';
|
|
2
|
-
import { inspect } from 'node:util';
|
|
3
|
-
|
|
4
|
-
import type { LevelCode } from './levels';
|
|
5
|
-
import { calculateLevel, levelsColors, subSystemLevels } from './levels';
|
|
6
|
-
import type { PrettyOptionsExtended } from './types';
|
|
7
|
-
import { formatLoggingDate, isObject, padRight } from './utils';
|
|
8
|
-
|
|
9
|
-
let LEVEL_VALUE_MAX = 0;
|
|
10
|
-
for (const l of Object.keys(levelsColors)) {
|
|
11
|
-
LEVEL_VALUE_MAX = Math.max(LEVEL_VALUE_MAX, l.length);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const ERROR_FLAG = '!';
|
|
15
|
-
|
|
16
|
-
export interface ObjectTemplate {
|
|
17
|
-
level: LevelCode;
|
|
18
|
-
msg: string;
|
|
19
|
-
sub?: string;
|
|
20
|
-
[key: string]: string | number | object | null | void;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function fillInMsgTemplate(
|
|
24
|
-
msg: string,
|
|
25
|
-
templateOptions: ObjectTemplate,
|
|
26
|
-
colors: boolean
|
|
27
|
-
): string {
|
|
28
|
-
const templateRegex = /@{(!?[$A-Za-z_][$0-9A-Za-z\._]*)}/g;
|
|
29
|
-
|
|
30
|
-
return msg.replace(templateRegex, (_, name): string => {
|
|
31
|
-
let str = templateOptions;
|
|
32
|
-
let isError;
|
|
33
|
-
if (name[0] === ERROR_FLAG) {
|
|
34
|
-
name = name.slice(1);
|
|
35
|
-
isError = true;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// object can be @{foo.bar.}
|
|
39
|
-
const listAccessors = name.split('.');
|
|
40
|
-
for (let property = 0; property < listAccessors.length; property++) {
|
|
41
|
-
const id = listAccessors[property];
|
|
42
|
-
if (isObject(str)) {
|
|
43
|
-
str = (str as object)[id];
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if (typeof str === 'string') {
|
|
48
|
-
if (colors === false || (str as string).includes('\n')) {
|
|
49
|
-
return str;
|
|
50
|
-
} else if (isError) {
|
|
51
|
-
return red(str);
|
|
52
|
-
}
|
|
53
|
-
return green(str);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// object, showHidden, depth, colors
|
|
57
|
-
return inspect(str, undefined, null, colors);
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function getMessage(debugLevel, msg, sub, templateObjects, hasColors: boolean) {
|
|
62
|
-
const finalMessage = fillInMsgTemplate(msg, templateObjects, hasColors);
|
|
63
|
-
|
|
64
|
-
const subSystemType = hasColors
|
|
65
|
-
? subSystemLevels.color[sub ?? 'default']
|
|
66
|
-
: subSystemLevels.white[sub ?? 'default'];
|
|
67
|
-
if (hasColors) {
|
|
68
|
-
const logString = `${levelsColors[debugLevel](padRight(debugLevel, LEVEL_VALUE_MAX))}${white(
|
|
69
|
-
`${subSystemType} ${finalMessage}`
|
|
70
|
-
)}`;
|
|
71
|
-
|
|
72
|
-
return logString;
|
|
73
|
-
}
|
|
74
|
-
const logString = `${padRight(debugLevel, LEVEL_VALUE_MAX)}${subSystemType} ${finalMessage}`;
|
|
75
|
-
|
|
76
|
-
return logString;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export function printMessage(
|
|
80
|
-
templateObjects: ObjectTemplate,
|
|
81
|
-
options: Pick<PrettyOptionsExtended, 'prettyStamp'>,
|
|
82
|
-
hasColors: boolean
|
|
83
|
-
): string {
|
|
84
|
-
const { prettyStamp } = options;
|
|
85
|
-
const { level, msg, sub } = templateObjects;
|
|
86
|
-
const debugLevel = calculateLevel(level);
|
|
87
|
-
const logMessage = getMessage(debugLevel, msg, sub, templateObjects, hasColors);
|
|
88
|
-
|
|
89
|
-
return prettyStamp ? formatLoggingDate(templateObjects.time as number, logMessage) : logMessage;
|
|
90
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import pino from 'pino';
|
|
2
|
-
|
|
3
|
-
import type { Logger, LoggerConfigItem } from '@verdaccio/types';
|
|
4
|
-
|
|
5
|
-
import { prepareSetup } from './logger';
|
|
6
|
-
|
|
7
|
-
export { createLogger, prepareSetup, willUseTransport } from './logger';
|
|
8
|
-
export type { LogPlugin, LoggerConfig } from './logger';
|
|
9
|
-
export { default as prettifyTransport, autoEnd, buildPretty, buildSafeSonicBoom } from './prettify';
|
|
10
|
-
export { hasColors } from './colors';
|
|
11
|
-
export { fillInMsgTemplate, printMessage } from './formatter';
|
|
12
|
-
export { createPrettyTransport, isPrettyFormat } from './transport';
|
|
13
|
-
export type { LevelCode } from './levels';
|
|
14
|
-
export { formatLoggingDate, padRight } from './utils';
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Initialize the logger singleton.
|
|
18
|
-
*/
|
|
19
|
-
export async function setup(options: LoggerConfigItem): Promise<Logger> {
|
|
20
|
-
if (typeof logger !== 'undefined') {
|
|
21
|
-
return logger;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
logger = await prepareSetup(options, pino);
|
|
25
|
-
return logger;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export let logger: Logger;
|
package/src/levels.ts
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { black, blue, cyan, green, magenta, red, white, yellow } from 'colorette';
|
|
2
|
-
|
|
3
|
-
export type LogLevel = 'trace' | 'debug' | 'info' | 'http' | 'warn' | 'error' | 'fatal';
|
|
4
|
-
|
|
5
|
-
export type LevelCode = number;
|
|
6
|
-
|
|
7
|
-
export function calculateLevel(levelCode: LevelCode): LogLevel {
|
|
8
|
-
switch (true) {
|
|
9
|
-
case levelCode === 10:
|
|
10
|
-
return 'trace';
|
|
11
|
-
case levelCode === 20:
|
|
12
|
-
return 'debug';
|
|
13
|
-
case levelCode === 25:
|
|
14
|
-
return 'http';
|
|
15
|
-
case levelCode === 30:
|
|
16
|
-
return 'info';
|
|
17
|
-
case levelCode === 40:
|
|
18
|
-
return 'warn';
|
|
19
|
-
case levelCode === 50:
|
|
20
|
-
return 'error';
|
|
21
|
-
case levelCode === 60:
|
|
22
|
-
return 'fatal';
|
|
23
|
-
default:
|
|
24
|
-
return 'fatal';
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export const levelsColors = {
|
|
29
|
-
fatal: red,
|
|
30
|
-
error: red,
|
|
31
|
-
warn: yellow,
|
|
32
|
-
http: magenta,
|
|
33
|
-
info: cyan,
|
|
34
|
-
debug: green,
|
|
35
|
-
trace: white,
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
enum ARROWS {
|
|
39
|
-
LEFT = '<--',
|
|
40
|
-
RIGHT = '-->',
|
|
41
|
-
EQUAL = '-=-',
|
|
42
|
-
NEUTRAL = '---',
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export const subSystemLevels = {
|
|
46
|
-
color: {
|
|
47
|
-
in: green(ARROWS.LEFT),
|
|
48
|
-
out: yellow(ARROWS.RIGHT),
|
|
49
|
-
auth: blue(ARROWS.NEUTRAL),
|
|
50
|
-
fs: black(ARROWS.EQUAL),
|
|
51
|
-
default: blue(ARROWS.NEUTRAL),
|
|
52
|
-
},
|
|
53
|
-
white: {
|
|
54
|
-
in: ARROWS.LEFT,
|
|
55
|
-
out: ARROWS.RIGHT,
|
|
56
|
-
auth: ARROWS.NEUTRAL,
|
|
57
|
-
fs: ARROWS.EQUAL,
|
|
58
|
-
default: ARROWS.NEUTRAL,
|
|
59
|
-
},
|
|
60
|
-
};
|