@with-jiko/next-logger-logtape 1.1.0
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/dist/index.cjs +180 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +35 -0
- package/dist/index.d.mts +35 -0
- package/dist/index.mjs +154 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +63 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region \0rolldown/runtime.js
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
11
|
+
key = keys[i];
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
13
|
+
get: ((k) => from[k]).bind(null, key),
|
|
14
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
|
|
20
|
+
value: mod,
|
|
21
|
+
enumerable: true
|
|
22
|
+
}) : target, mod));
|
|
23
|
+
//#endregion
|
|
24
|
+
let node_util = require("node:util");
|
|
25
|
+
let ansi_regex = require("ansi-regex");
|
|
26
|
+
ansi_regex = __toESM(ansi_regex, 1);
|
|
27
|
+
let node_module = require("node:module");
|
|
28
|
+
let _logtape_logtape = require("@logtape/logtape");
|
|
29
|
+
//#region src/next-logger.ts
|
|
30
|
+
const require$1 = (0, node_module.createRequire)(process.cwd() + "/");
|
|
31
|
+
const consoleMethods = [
|
|
32
|
+
["log", "info"],
|
|
33
|
+
["info", "info"],
|
|
34
|
+
["debug", "debug"],
|
|
35
|
+
["warn", "warn"],
|
|
36
|
+
["error", "error"],
|
|
37
|
+
["trace", "trace"]
|
|
38
|
+
];
|
|
39
|
+
const nextMethods = [
|
|
40
|
+
"bootstrap",
|
|
41
|
+
"error",
|
|
42
|
+
"event",
|
|
43
|
+
"info",
|
|
44
|
+
"ready",
|
|
45
|
+
"trace",
|
|
46
|
+
"wait",
|
|
47
|
+
"warn",
|
|
48
|
+
"warnOnce"
|
|
49
|
+
];
|
|
50
|
+
const nextLevels = {
|
|
51
|
+
error: "error",
|
|
52
|
+
warn: "warn",
|
|
53
|
+
trace: "trace"
|
|
54
|
+
};
|
|
55
|
+
function getBaseLogger(options) {
|
|
56
|
+
return options?.logger ?? (0, _logtape_logtape.getLogger)(options?.category ?? ["app"]);
|
|
57
|
+
}
|
|
58
|
+
function clean(value, stripAnsi) {
|
|
59
|
+
return stripAnsi && typeof value === "string" ? value.replace((0, ansi_regex.default)(), "") : value;
|
|
60
|
+
}
|
|
61
|
+
function isStructuredValue(value) {
|
|
62
|
+
return typeof value === "object" && value !== null;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Build a LogTape message template and structured `properties` from
|
|
66
|
+
* console-like arguments.
|
|
67
|
+
*/
|
|
68
|
+
function toLogTapeMessage(args, stripAnsi) {
|
|
69
|
+
const properties = {};
|
|
70
|
+
let argIndex = 0;
|
|
71
|
+
const formattedArgs = args.map((value) => {
|
|
72
|
+
const cleaned = clean(value, stripAnsi);
|
|
73
|
+
if (isStructuredValue(cleaned)) {
|
|
74
|
+
const key = `arg${argIndex}`;
|
|
75
|
+
properties[key] = cleaned;
|
|
76
|
+
argIndex++;
|
|
77
|
+
return `{${key}}`;
|
|
78
|
+
}
|
|
79
|
+
return cleaned;
|
|
80
|
+
});
|
|
81
|
+
return {
|
|
82
|
+
template: (0, node_util.format)(...formattedArgs),
|
|
83
|
+
properties
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function logAt(logger, level, args, stripAnsi, properties) {
|
|
87
|
+
const { template, properties: structured } = toLogTapeMessage(args, stripAnsi);
|
|
88
|
+
const record = {
|
|
89
|
+
...properties,
|
|
90
|
+
...structured
|
|
91
|
+
};
|
|
92
|
+
switch (level) {
|
|
93
|
+
case "debug":
|
|
94
|
+
logger.debug(template, record);
|
|
95
|
+
break;
|
|
96
|
+
case "warn":
|
|
97
|
+
logger.warn(template, record);
|
|
98
|
+
break;
|
|
99
|
+
case "error":
|
|
100
|
+
logger.error(template, record);
|
|
101
|
+
break;
|
|
102
|
+
case "trace":
|
|
103
|
+
logger.trace(template, record);
|
|
104
|
+
break;
|
|
105
|
+
default: logger.info(template, record);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Route `console.*` calls to a LogTape logger.
|
|
110
|
+
*
|
|
111
|
+
* @param options Patch options.
|
|
112
|
+
* @returns A function that restores the original `console` methods.
|
|
113
|
+
*/
|
|
114
|
+
function patchConsole(options = {}) {
|
|
115
|
+
const { stripAnsi = true } = options;
|
|
116
|
+
const consoleLogger = getBaseLogger(options).getChild("console");
|
|
117
|
+
const target = console;
|
|
118
|
+
const original = /* @__PURE__ */ new Map();
|
|
119
|
+
for (const [method, level] of consoleMethods) {
|
|
120
|
+
original.set(method, target[method]);
|
|
121
|
+
target[method] = (...args) => {
|
|
122
|
+
logAt(consoleLogger, level, args, stripAnsi);
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
return () => {
|
|
126
|
+
for (const [method, fn] of original) target[method] = fn;
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Route Next.js's internal logger (`next/dist/build/output/log`) to a LogTape
|
|
131
|
+
* logger.
|
|
132
|
+
*
|
|
133
|
+
* @param options Patch options.
|
|
134
|
+
* @returns A function that restores the original module exports.
|
|
135
|
+
*/
|
|
136
|
+
function patchNextLogging(options = {}) {
|
|
137
|
+
const { stripAnsi = true } = options;
|
|
138
|
+
try {
|
|
139
|
+
const logPath = require$1.resolve("next/dist/build/output/log");
|
|
140
|
+
require$1(logPath);
|
|
141
|
+
const mod = require$1.cache[logPath];
|
|
142
|
+
if (!mod) {
|
|
143
|
+
console.warn("[next-logger-logtape] Next.js log module not found");
|
|
144
|
+
return () => {};
|
|
145
|
+
}
|
|
146
|
+
const nextLogger = getBaseLogger(options).getChild("next");
|
|
147
|
+
const original = mod.exports;
|
|
148
|
+
const exports = { ...mod.exports };
|
|
149
|
+
for (const method of nextMethods) exports[method] = (...message) => {
|
|
150
|
+
logAt(nextLogger, nextLevels[method] ?? "info", message, stripAnsi, { prefix: method });
|
|
151
|
+
};
|
|
152
|
+
mod.exports = exports;
|
|
153
|
+
return () => {
|
|
154
|
+
mod.exports = original;
|
|
155
|
+
};
|
|
156
|
+
} catch (err) {
|
|
157
|
+
console.warn("[next-logger-logtape] Failed to patch Next.js logger:", err);
|
|
158
|
+
return () => {};
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Patch both the Next.js internal logger and `console`.
|
|
163
|
+
*
|
|
164
|
+
* @param options Patch options.
|
|
165
|
+
* @returns A function that restores both patches.
|
|
166
|
+
*/
|
|
167
|
+
function patchNextLogger(options = {}) {
|
|
168
|
+
const restoreConsole = patchConsole(options);
|
|
169
|
+
const restoreNext = patchNextLogging(options);
|
|
170
|
+
return () => {
|
|
171
|
+
restoreConsole();
|
|
172
|
+
restoreNext();
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
//#endregion
|
|
176
|
+
exports.patchConsole = patchConsole;
|
|
177
|
+
exports.patchNextLogger = patchNextLogger;
|
|
178
|
+
exports.patchNextLogging = patchNextLogging;
|
|
179
|
+
|
|
180
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["require","createRequire","getLogger","ansiRegex","format"],"sources":["../src/next-logger.ts"],"sourcesContent":["import { format } from \"node:util\";\nimport ansiRegex from \"ansi-regex\";\nimport { createRequire } from \"node:module\";\nimport { getLogger, type Logger } from \"@logtape/logtape\";\n\nconst require = createRequire(process.cwd() + \"/\");\n\nexport interface NextLoggerPatchOptions {\n /** The LogTape logger to route logs to. */\n logger?: Logger;\n /** The category used when no logger is provided. Defaults to `['app']`. */\n category?: string[];\n /** Strip ANSI escape codes from messages. Defaults to `true`. */\n stripAnsi?: boolean;\n}\n\nconst consoleMethods = [\n [\"log\", \"info\"],\n [\"info\", \"info\"],\n [\"debug\", \"debug\"],\n [\"warn\", \"warn\"],\n [\"error\", \"error\"],\n [\"trace\", \"trace\"],\n] as const;\n\nconst nextMethods = [\n \"bootstrap\",\n \"error\",\n \"event\",\n \"info\",\n \"ready\",\n \"trace\",\n \"wait\",\n \"warn\",\n \"warnOnce\",\n] as const;\n\nconst nextLevels: Record<string, \"error\" | \"warn\" | \"trace\" | \"info\"> = {\n error: \"error\",\n warn: \"warn\",\n trace: \"trace\",\n};\n\nfunction getBaseLogger(options?: NextLoggerPatchOptions): Logger {\n return options?.logger ?? getLogger(options?.category ?? [\"app\"]);\n}\n\nfunction clean(value: unknown, stripAnsi: boolean): unknown {\n return stripAnsi && typeof value === \"string\"\n ? value.replace(ansiRegex(), \"\")\n : value;\n}\n\nfunction isStructuredValue(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\n/**\n * Build a LogTape message template and structured `properties` from\n * console-like arguments.\n */\nfunction toLogTapeMessage(\n args: readonly unknown[],\n stripAnsi: boolean,\n): { template: string; properties: Record<string, unknown> } {\n const properties: Record<string, unknown> = {};\n let argIndex = 0;\n\n const formattedArgs = args.map((value) => {\n const cleaned = clean(value, stripAnsi);\n if (isStructuredValue(cleaned)) {\n const key = `arg${argIndex}`;\n properties[key] = cleaned;\n argIndex++;\n return `{${key}}`;\n }\n return cleaned;\n });\n\n return { template: format(...formattedArgs), properties };\n}\n\nfunction logAt(\n logger: Logger,\n level: \"info\" | \"debug\" | \"warn\" | \"error\" | \"trace\",\n args: readonly unknown[],\n stripAnsi: boolean,\n properties?: Record<string, unknown>,\n): void {\n const { template, properties: structured } = toLogTapeMessage(\n args,\n stripAnsi,\n );\n const record = { ...properties, ...structured };\n switch (level) {\n case \"debug\":\n logger.debug(template, record);\n break;\n case \"warn\":\n logger.warn(template, record);\n break;\n case \"error\":\n logger.error(template, record);\n break;\n case \"trace\":\n logger.trace(template, record);\n break;\n default:\n logger.info(template, record);\n }\n}\n\n/**\n * Route `console.*` calls to a LogTape logger.\n *\n * @param options Patch options.\n * @returns A function that restores the original `console` methods.\n */\nexport function patchConsole(options: NextLoggerPatchOptions = {}): () => void {\n const { stripAnsi = true } = options;\n const consoleLogger = getBaseLogger(options).getChild(\"console\");\n const target = console as unknown as Record<string, unknown>;\n const original = new Map<string, unknown>();\n\n for (const [method, level] of consoleMethods) {\n original.set(method, target[method]);\n target[method] = (...args: unknown[]) => {\n logAt(consoleLogger, level, args, stripAnsi);\n };\n }\n\n return () => {\n for (const [method, fn] of original) target[method] = fn;\n };\n}\n\n/**\n * Route Next.js's internal logger (`next/dist/build/output/log`) to a LogTape\n * logger.\n *\n * @param options Patch options.\n * @returns A function that restores the original module exports.\n */\nexport function patchNextLogging(\n options: NextLoggerPatchOptions = {},\n): () => void {\n const { stripAnsi = true } = options;\n try {\n const logPath = require.resolve(\"next/dist/build/output/log\");\n require(logPath);\n const mod = require.cache[logPath];\n if (!mod) {\n console.warn(\"[next-logger-logtape] Next.js log module not found\");\n return () => {};\n }\n\n const nextLogger = getBaseLogger(options).getChild(\"next\");\n const original = mod.exports;\n const exports = { ...(mod.exports as Record<string, unknown>) };\n\n for (const method of nextMethods) {\n exports[method] = (...message: unknown[]) => {\n logAt(nextLogger, nextLevels[method] ?? \"info\", message, stripAnsi, {\n prefix: method,\n });\n };\n }\n\n mod.exports = exports;\n return () => {\n mod.exports = original;\n };\n } catch (err) {\n console.warn(\"[next-logger-logtape] Failed to patch Next.js logger:\", err);\n return () => {};\n }\n}\n\n/**\n * Patch both the Next.js internal logger and `console`.\n *\n * @param options Patch options.\n * @returns A function that restores both patches.\n */\nexport function patchNextLogger(\n options: NextLoggerPatchOptions = {},\n): () => void {\n const restoreConsole = patchConsole(options);\n const restoreNext = patchNextLogging(options);\n return () => {\n restoreConsole();\n restoreNext();\n };\n}\n"],"mappings":"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"}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Logger } from "@logtape/logtape";
|
|
2
|
+
//#region src/next-logger.d.ts
|
|
3
|
+
interface NextLoggerPatchOptions {
|
|
4
|
+
/** The LogTape logger to route logs to. */
|
|
5
|
+
logger?: Logger;
|
|
6
|
+
/** The category used when no logger is provided. Defaults to `['app']`. */
|
|
7
|
+
category?: string[];
|
|
8
|
+
/** Strip ANSI escape codes from messages. Defaults to `true`. */
|
|
9
|
+
stripAnsi?: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Route `console.*` calls to a LogTape logger.
|
|
13
|
+
*
|
|
14
|
+
* @param options Patch options.
|
|
15
|
+
* @returns A function that restores the original `console` methods.
|
|
16
|
+
*/
|
|
17
|
+
declare function patchConsole(options?: NextLoggerPatchOptions): () => void;
|
|
18
|
+
/**
|
|
19
|
+
* Route Next.js's internal logger (`next/dist/build/output/log`) to a LogTape
|
|
20
|
+
* logger.
|
|
21
|
+
*
|
|
22
|
+
* @param options Patch options.
|
|
23
|
+
* @returns A function that restores the original module exports.
|
|
24
|
+
*/
|
|
25
|
+
declare function patchNextLogging(options?: NextLoggerPatchOptions): () => void;
|
|
26
|
+
/**
|
|
27
|
+
* Patch both the Next.js internal logger and `console`.
|
|
28
|
+
*
|
|
29
|
+
* @param options Patch options.
|
|
30
|
+
* @returns A function that restores both patches.
|
|
31
|
+
*/
|
|
32
|
+
declare function patchNextLogger(options?: NextLoggerPatchOptions): () => void;
|
|
33
|
+
//#endregion
|
|
34
|
+
export { type NextLoggerPatchOptions, patchConsole, patchNextLogger, patchNextLogging };
|
|
35
|
+
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Logger } from "@logtape/logtape";
|
|
2
|
+
//#region src/next-logger.d.ts
|
|
3
|
+
interface NextLoggerPatchOptions {
|
|
4
|
+
/** The LogTape logger to route logs to. */
|
|
5
|
+
logger?: Logger;
|
|
6
|
+
/** The category used when no logger is provided. Defaults to `['app']`. */
|
|
7
|
+
category?: string[];
|
|
8
|
+
/** Strip ANSI escape codes from messages. Defaults to `true`. */
|
|
9
|
+
stripAnsi?: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Route `console.*` calls to a LogTape logger.
|
|
13
|
+
*
|
|
14
|
+
* @param options Patch options.
|
|
15
|
+
* @returns A function that restores the original `console` methods.
|
|
16
|
+
*/
|
|
17
|
+
declare function patchConsole(options?: NextLoggerPatchOptions): () => void;
|
|
18
|
+
/**
|
|
19
|
+
* Route Next.js's internal logger (`next/dist/build/output/log`) to a LogTape
|
|
20
|
+
* logger.
|
|
21
|
+
*
|
|
22
|
+
* @param options Patch options.
|
|
23
|
+
* @returns A function that restores the original module exports.
|
|
24
|
+
*/
|
|
25
|
+
declare function patchNextLogging(options?: NextLoggerPatchOptions): () => void;
|
|
26
|
+
/**
|
|
27
|
+
* Patch both the Next.js internal logger and `console`.
|
|
28
|
+
*
|
|
29
|
+
* @param options Patch options.
|
|
30
|
+
* @returns A function that restores both patches.
|
|
31
|
+
*/
|
|
32
|
+
declare function patchNextLogger(options?: NextLoggerPatchOptions): () => void;
|
|
33
|
+
//#endregion
|
|
34
|
+
export { type NextLoggerPatchOptions, patchConsole, patchNextLogger, patchNextLogging };
|
|
35
|
+
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { format } from "node:util";
|
|
3
|
+
import ansiRegex from "ansi-regex";
|
|
4
|
+
import { getLogger } from "@logtape/logtape";
|
|
5
|
+
//#region src/next-logger.ts
|
|
6
|
+
const require = createRequire(process.cwd() + "/");
|
|
7
|
+
const consoleMethods = [
|
|
8
|
+
["log", "info"],
|
|
9
|
+
["info", "info"],
|
|
10
|
+
["debug", "debug"],
|
|
11
|
+
["warn", "warn"],
|
|
12
|
+
["error", "error"],
|
|
13
|
+
["trace", "trace"]
|
|
14
|
+
];
|
|
15
|
+
const nextMethods = [
|
|
16
|
+
"bootstrap",
|
|
17
|
+
"error",
|
|
18
|
+
"event",
|
|
19
|
+
"info",
|
|
20
|
+
"ready",
|
|
21
|
+
"trace",
|
|
22
|
+
"wait",
|
|
23
|
+
"warn",
|
|
24
|
+
"warnOnce"
|
|
25
|
+
];
|
|
26
|
+
const nextLevels = {
|
|
27
|
+
error: "error",
|
|
28
|
+
warn: "warn",
|
|
29
|
+
trace: "trace"
|
|
30
|
+
};
|
|
31
|
+
function getBaseLogger(options) {
|
|
32
|
+
return options?.logger ?? getLogger(options?.category ?? ["app"]);
|
|
33
|
+
}
|
|
34
|
+
function clean(value, stripAnsi) {
|
|
35
|
+
return stripAnsi && typeof value === "string" ? value.replace(ansiRegex(), "") : value;
|
|
36
|
+
}
|
|
37
|
+
function isStructuredValue(value) {
|
|
38
|
+
return typeof value === "object" && value !== null;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Build a LogTape message template and structured `properties` from
|
|
42
|
+
* console-like arguments.
|
|
43
|
+
*/
|
|
44
|
+
function toLogTapeMessage(args, stripAnsi) {
|
|
45
|
+
const properties = {};
|
|
46
|
+
let argIndex = 0;
|
|
47
|
+
const formattedArgs = args.map((value) => {
|
|
48
|
+
const cleaned = clean(value, stripAnsi);
|
|
49
|
+
if (isStructuredValue(cleaned)) {
|
|
50
|
+
const key = `arg${argIndex}`;
|
|
51
|
+
properties[key] = cleaned;
|
|
52
|
+
argIndex++;
|
|
53
|
+
return `{${key}}`;
|
|
54
|
+
}
|
|
55
|
+
return cleaned;
|
|
56
|
+
});
|
|
57
|
+
return {
|
|
58
|
+
template: format(...formattedArgs),
|
|
59
|
+
properties
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function logAt(logger, level, args, stripAnsi, properties) {
|
|
63
|
+
const { template, properties: structured } = toLogTapeMessage(args, stripAnsi);
|
|
64
|
+
const record = {
|
|
65
|
+
...properties,
|
|
66
|
+
...structured
|
|
67
|
+
};
|
|
68
|
+
switch (level) {
|
|
69
|
+
case "debug":
|
|
70
|
+
logger.debug(template, record);
|
|
71
|
+
break;
|
|
72
|
+
case "warn":
|
|
73
|
+
logger.warn(template, record);
|
|
74
|
+
break;
|
|
75
|
+
case "error":
|
|
76
|
+
logger.error(template, record);
|
|
77
|
+
break;
|
|
78
|
+
case "trace":
|
|
79
|
+
logger.trace(template, record);
|
|
80
|
+
break;
|
|
81
|
+
default: logger.info(template, record);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Route `console.*` calls to a LogTape logger.
|
|
86
|
+
*
|
|
87
|
+
* @param options Patch options.
|
|
88
|
+
* @returns A function that restores the original `console` methods.
|
|
89
|
+
*/
|
|
90
|
+
function patchConsole(options = {}) {
|
|
91
|
+
const { stripAnsi = true } = options;
|
|
92
|
+
const consoleLogger = getBaseLogger(options).getChild("console");
|
|
93
|
+
const target = console;
|
|
94
|
+
const original = /* @__PURE__ */ new Map();
|
|
95
|
+
for (const [method, level] of consoleMethods) {
|
|
96
|
+
original.set(method, target[method]);
|
|
97
|
+
target[method] = (...args) => {
|
|
98
|
+
logAt(consoleLogger, level, args, stripAnsi);
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
return () => {
|
|
102
|
+
for (const [method, fn] of original) target[method] = fn;
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Route Next.js's internal logger (`next/dist/build/output/log`) to a LogTape
|
|
107
|
+
* logger.
|
|
108
|
+
*
|
|
109
|
+
* @param options Patch options.
|
|
110
|
+
* @returns A function that restores the original module exports.
|
|
111
|
+
*/
|
|
112
|
+
function patchNextLogging(options = {}) {
|
|
113
|
+
const { stripAnsi = true } = options;
|
|
114
|
+
try {
|
|
115
|
+
const logPath = require.resolve("next/dist/build/output/log");
|
|
116
|
+
require(logPath);
|
|
117
|
+
const mod = require.cache[logPath];
|
|
118
|
+
if (!mod) {
|
|
119
|
+
console.warn("[next-logger-logtape] Next.js log module not found");
|
|
120
|
+
return () => {};
|
|
121
|
+
}
|
|
122
|
+
const nextLogger = getBaseLogger(options).getChild("next");
|
|
123
|
+
const original = mod.exports;
|
|
124
|
+
const exports = { ...mod.exports };
|
|
125
|
+
for (const method of nextMethods) exports[method] = (...message) => {
|
|
126
|
+
logAt(nextLogger, nextLevels[method] ?? "info", message, stripAnsi, { prefix: method });
|
|
127
|
+
};
|
|
128
|
+
mod.exports = exports;
|
|
129
|
+
return () => {
|
|
130
|
+
mod.exports = original;
|
|
131
|
+
};
|
|
132
|
+
} catch (err) {
|
|
133
|
+
console.warn("[next-logger-logtape] Failed to patch Next.js logger:", err);
|
|
134
|
+
return () => {};
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Patch both the Next.js internal logger and `console`.
|
|
139
|
+
*
|
|
140
|
+
* @param options Patch options.
|
|
141
|
+
* @returns A function that restores both patches.
|
|
142
|
+
*/
|
|
143
|
+
function patchNextLogger(options = {}) {
|
|
144
|
+
const restoreConsole = patchConsole(options);
|
|
145
|
+
const restoreNext = patchNextLogging(options);
|
|
146
|
+
return () => {
|
|
147
|
+
restoreConsole();
|
|
148
|
+
restoreNext();
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
//#endregion
|
|
152
|
+
export { patchConsole, patchNextLogger, patchNextLogging };
|
|
153
|
+
|
|
154
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/next-logger.ts"],"sourcesContent":["import { format } from \"node:util\";\nimport ansiRegex from \"ansi-regex\";\nimport { createRequire } from \"node:module\";\nimport { getLogger, type Logger } from \"@logtape/logtape\";\n\nconst require = createRequire(process.cwd() + \"/\");\n\nexport interface NextLoggerPatchOptions {\n /** The LogTape logger to route logs to. */\n logger?: Logger;\n /** The category used when no logger is provided. Defaults to `['app']`. */\n category?: string[];\n /** Strip ANSI escape codes from messages. Defaults to `true`. */\n stripAnsi?: boolean;\n}\n\nconst consoleMethods = [\n [\"log\", \"info\"],\n [\"info\", \"info\"],\n [\"debug\", \"debug\"],\n [\"warn\", \"warn\"],\n [\"error\", \"error\"],\n [\"trace\", \"trace\"],\n] as const;\n\nconst nextMethods = [\n \"bootstrap\",\n \"error\",\n \"event\",\n \"info\",\n \"ready\",\n \"trace\",\n \"wait\",\n \"warn\",\n \"warnOnce\",\n] as const;\n\nconst nextLevels: Record<string, \"error\" | \"warn\" | \"trace\" | \"info\"> = {\n error: \"error\",\n warn: \"warn\",\n trace: \"trace\",\n};\n\nfunction getBaseLogger(options?: NextLoggerPatchOptions): Logger {\n return options?.logger ?? getLogger(options?.category ?? [\"app\"]);\n}\n\nfunction clean(value: unknown, stripAnsi: boolean): unknown {\n return stripAnsi && typeof value === \"string\"\n ? value.replace(ansiRegex(), \"\")\n : value;\n}\n\nfunction isStructuredValue(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\n/**\n * Build a LogTape message template and structured `properties` from\n * console-like arguments.\n */\nfunction toLogTapeMessage(\n args: readonly unknown[],\n stripAnsi: boolean,\n): { template: string; properties: Record<string, unknown> } {\n const properties: Record<string, unknown> = {};\n let argIndex = 0;\n\n const formattedArgs = args.map((value) => {\n const cleaned = clean(value, stripAnsi);\n if (isStructuredValue(cleaned)) {\n const key = `arg${argIndex}`;\n properties[key] = cleaned;\n argIndex++;\n return `{${key}}`;\n }\n return cleaned;\n });\n\n return { template: format(...formattedArgs), properties };\n}\n\nfunction logAt(\n logger: Logger,\n level: \"info\" | \"debug\" | \"warn\" | \"error\" | \"trace\",\n args: readonly unknown[],\n stripAnsi: boolean,\n properties?: Record<string, unknown>,\n): void {\n const { template, properties: structured } = toLogTapeMessage(\n args,\n stripAnsi,\n );\n const record = { ...properties, ...structured };\n switch (level) {\n case \"debug\":\n logger.debug(template, record);\n break;\n case \"warn\":\n logger.warn(template, record);\n break;\n case \"error\":\n logger.error(template, record);\n break;\n case \"trace\":\n logger.trace(template, record);\n break;\n default:\n logger.info(template, record);\n }\n}\n\n/**\n * Route `console.*` calls to a LogTape logger.\n *\n * @param options Patch options.\n * @returns A function that restores the original `console` methods.\n */\nexport function patchConsole(options: NextLoggerPatchOptions = {}): () => void {\n const { stripAnsi = true } = options;\n const consoleLogger = getBaseLogger(options).getChild(\"console\");\n const target = console as unknown as Record<string, unknown>;\n const original = new Map<string, unknown>();\n\n for (const [method, level] of consoleMethods) {\n original.set(method, target[method]);\n target[method] = (...args: unknown[]) => {\n logAt(consoleLogger, level, args, stripAnsi);\n };\n }\n\n return () => {\n for (const [method, fn] of original) target[method] = fn;\n };\n}\n\n/**\n * Route Next.js's internal logger (`next/dist/build/output/log`) to a LogTape\n * logger.\n *\n * @param options Patch options.\n * @returns A function that restores the original module exports.\n */\nexport function patchNextLogging(\n options: NextLoggerPatchOptions = {},\n): () => void {\n const { stripAnsi = true } = options;\n try {\n const logPath = require.resolve(\"next/dist/build/output/log\");\n require(logPath);\n const mod = require.cache[logPath];\n if (!mod) {\n console.warn(\"[next-logger-logtape] Next.js log module not found\");\n return () => {};\n }\n\n const nextLogger = getBaseLogger(options).getChild(\"next\");\n const original = mod.exports;\n const exports = { ...(mod.exports as Record<string, unknown>) };\n\n for (const method of nextMethods) {\n exports[method] = (...message: unknown[]) => {\n logAt(nextLogger, nextLevels[method] ?? \"info\", message, stripAnsi, {\n prefix: method,\n });\n };\n }\n\n mod.exports = exports;\n return () => {\n mod.exports = original;\n };\n } catch (err) {\n console.warn(\"[next-logger-logtape] Failed to patch Next.js logger:\", err);\n return () => {};\n }\n}\n\n/**\n * Patch both the Next.js internal logger and `console`.\n *\n * @param options Patch options.\n * @returns A function that restores both patches.\n */\nexport function patchNextLogger(\n options: NextLoggerPatchOptions = {},\n): () => void {\n const restoreConsole = patchConsole(options);\n const restoreNext = patchNextLogging(options);\n return () => {\n restoreConsole();\n restoreNext();\n };\n}\n"],"mappings":";;;;;AAKA,MAAM,UAAU,cAAc,QAAQ,IAAI,IAAI,GAAG;AAWjD,MAAM,iBAAiB;CACrB,CAAC,OAAO,MAAM;CACd,CAAC,QAAQ,MAAM;CACf,CAAC,SAAS,OAAO;CACjB,CAAC,QAAQ,MAAM;CACf,CAAC,SAAS,OAAO;CACjB,CAAC,SAAS,OAAO;AACnB;AAEA,MAAM,cAAc;CAClB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAEA,MAAM,aAAkE;CACtE,OAAO;CACP,MAAM;CACN,OAAO;AACT;AAEA,SAAS,cAAc,SAA0C;CAC/D,OAAO,SAAS,UAAU,UAAU,SAAS,YAAY,CAAC,KAAK,CAAC;AAClE;AAEA,SAAS,MAAM,OAAgB,WAA6B;CAC1D,OAAO,aAAa,OAAO,UAAU,WACjC,MAAM,QAAQ,UAAU,GAAG,EAAE,IAC7B;AACN;AAEA,SAAS,kBAAkB,OAAkD;CAC3E,OAAO,OAAO,UAAU,YAAY,UAAU;AAChD;;;;;AAMA,SAAS,iBACP,MACA,WAC2D;CAC3D,MAAM,aAAsC,CAAC;CAC7C,IAAI,WAAW;CAEf,MAAM,gBAAgB,KAAK,KAAK,UAAU;EACxC,MAAM,UAAU,MAAM,OAAO,SAAS;EACtC,IAAI,kBAAkB,OAAO,GAAG;GAC9B,MAAM,MAAM,MAAM;GAClB,WAAW,OAAO;GAClB;GACA,OAAO,IAAI,IAAI;EACjB;EACA,OAAO;CACT,CAAC;CAED,OAAO;EAAE,UAAU,OAAO,GAAG,aAAa;EAAG;CAAW;AAC1D;AAEA,SAAS,MACP,QACA,OACA,MACA,WACA,YACM;CACN,MAAM,EAAE,UAAU,YAAY,eAAe,iBAC3C,MACA,SACF;CACA,MAAM,SAAS;EAAE,GAAG;EAAY,GAAG;CAAW;CAC9C,QAAQ,OAAR;EACE,KAAK;GACH,OAAO,MAAM,UAAU,MAAM;GAC7B;EACF,KAAK;GACH,OAAO,KAAK,UAAU,MAAM;GAC5B;EACF,KAAK;GACH,OAAO,MAAM,UAAU,MAAM;GAC7B;EACF,KAAK;GACH,OAAO,MAAM,UAAU,MAAM;GAC7B;EACF,SACE,OAAO,KAAK,UAAU,MAAM;CAChC;AACF;;;;;;;AAQA,SAAgB,aAAa,UAAkC,CAAC,GAAe;CAC7E,MAAM,EAAE,YAAY,SAAS;CAC7B,MAAM,gBAAgB,cAAc,OAAO,CAAC,CAAC,SAAS,SAAS;CAC/D,MAAM,SAAS;CACf,MAAM,2BAAW,IAAI,IAAqB;CAE1C,KAAK,MAAM,CAAC,QAAQ,UAAU,gBAAgB;EAC5C,SAAS,IAAI,QAAQ,OAAO,OAAO;EACnC,OAAO,WAAW,GAAG,SAAoB;GACvC,MAAM,eAAe,OAAO,MAAM,SAAS;EAC7C;CACF;CAEA,aAAa;EACX,KAAK,MAAM,CAAC,QAAQ,OAAO,UAAU,OAAO,UAAU;CACxD;AACF;;;;;;;;AASA,SAAgB,iBACd,UAAkC,CAAC,GACvB;CACZ,MAAM,EAAE,YAAY,SAAS;CAC7B,IAAI;EACF,MAAM,UAAU,QAAQ,QAAQ,4BAA4B;EAC5D,QAAQ,OAAO;EACf,MAAM,MAAM,QAAQ,MAAM;EAC1B,IAAI,CAAC,KAAK;GACR,QAAQ,KAAK,oDAAoD;GACjE,aAAa,CAAC;EAChB;EAEA,MAAM,aAAa,cAAc,OAAO,CAAC,CAAC,SAAS,MAAM;EACzD,MAAM,WAAW,IAAI;EACrB,MAAM,UAAU,EAAE,GAAI,IAAI,QAAoC;EAE9D,KAAK,MAAM,UAAU,aACnB,QAAQ,WAAW,GAAG,YAAuB;GAC3C,MAAM,YAAY,WAAW,WAAW,QAAQ,SAAS,WAAW,EAClE,QAAQ,OACV,CAAC;EACH;EAGF,IAAI,UAAU;EACd,aAAa;GACX,IAAI,UAAU;EAChB;CACF,SAAS,KAAK;EACZ,QAAQ,KAAK,yDAAyD,GAAG;EACzE,aAAa,CAAC;CAChB;AACF;;;;;;;AAQA,SAAgB,gBACd,UAAkC,CAAC,GACvB;CACZ,MAAM,iBAAiB,aAAa,OAAO;CAC3C,MAAM,cAAc,iBAAiB,OAAO;CAC5C,aAAa;EACX,eAAe;EACf,YAAY;CACd;AACF"}
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@with-jiko/next-logger-logtape",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"license": "Apache-2.0",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"type": "module",
|
|
9
|
+
"sideEffects": false,
|
|
10
|
+
"engines": {
|
|
11
|
+
"node": ">=18"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "https://github.com/semyonshap/jiko-packages.git",
|
|
16
|
+
"directory": "packages/next-logger-logtape"
|
|
17
|
+
},
|
|
18
|
+
"bugs": {
|
|
19
|
+
"url": "https://github.com/semyonshap/jiko-packages/issues"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"next",
|
|
23
|
+
"nextjs",
|
|
24
|
+
"logging",
|
|
25
|
+
"logtape",
|
|
26
|
+
"json"
|
|
27
|
+
],
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"import": "./dist/index.mjs",
|
|
32
|
+
"require": "./dist/index.js"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"dist"
|
|
37
|
+
],
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"@logtape/logtape": "^2.0.0",
|
|
40
|
+
"next": ">=13.1.0"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@logtape/logtape": "^2.0.0",
|
|
44
|
+
"@types/node": "^20",
|
|
45
|
+
"next": "^16.3.2",
|
|
46
|
+
"tsdown": "^0.22.0",
|
|
47
|
+
"typescript": "^5.5.0"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"ansi-regex": "^6.2.2"
|
|
51
|
+
},
|
|
52
|
+
"scripts": {
|
|
53
|
+
"dev": "tsdown --watch --logLevel warn",
|
|
54
|
+
"build": "tsdown",
|
|
55
|
+
"clean": "rimraf dist",
|
|
56
|
+
"lint": "eslint --fix .",
|
|
57
|
+
"typecheck": "tsc --noEmit",
|
|
58
|
+
"knip": "knip",
|
|
59
|
+
"test": "vitest run",
|
|
60
|
+
"test:integrations": "vitest run tests/integrations",
|
|
61
|
+
"test:demo": "vitest run tests/demo --disable-console-intercept"
|
|
62
|
+
}
|
|
63
|
+
}
|