@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 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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAKA,MAAMA,aAAAA,GAAUC,YAAAA,cAAAA,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,WAAA,GAAUC,iBAAAA,UAAAA,CAAU,SAAS,YAAY,CAAC,KAAK,CAAC;AAClE;AAEA,SAAS,MAAM,OAAgB,WAA6B;CAC1D,OAAO,aAAa,OAAO,UAAU,WACjC,MAAM,SAAA,GAAQC,WAAAA,QAAAA,CAAU,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,WAAA,GAAUC,UAAAA,OAAAA,CAAO,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,UAAUJ,UAAQ,QAAQ,4BAA4B;EAC5D,UAAQ,OAAO;EACf,MAAM,MAAMA,UAAQ,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"}
@@ -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
@@ -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":"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"}
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
+ }