@loggerjs/node 0.5.6 → 0.7.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/README.md +18 -26
- package/dist/bullmq-integration.cjs +2 -145
- package/dist/bullmq-integration.cjs.map +1 -1
- package/dist/bullmq-integration.js +1 -144
- package/dist/bullmq-integration.js.map +1 -1
- package/dist/chunks/node-destination-DvP8jBvm.cjs +254 -0
- package/dist/chunks/node-destination-DvP8jBvm.cjs.map +1 -0
- package/dist/chunks/node-destination-YnpYbctz.js +243 -0
- package/dist/chunks/node-destination-YnpYbctz.js.map +1 -0
- package/dist/context.cjs +1 -1
- package/dist/context.js +1 -1
- package/dist/diagnostics-channel-integration.cjs +1 -1
- package/dist/file-transport.cjs +3 -231
- package/dist/file-transport.cjs.map +1 -1
- package/dist/file-transport.js +3 -231
- package/dist/file-transport.js.map +1 -1
- package/dist/http-transport.cjs +25 -4
- package/dist/http-transport.cjs.map +1 -1
- package/dist/http-transport.d.ts +15 -0
- package/dist/http-transport.d.ts.map +1 -1
- package/dist/http-transport.js +25 -4
- package/dist/http-transport.js.map +1 -1
- package/dist/index.cjs +54 -2355
- package/dist/index.d.ts +211 -19
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +25 -2327
- package/dist/internal-types.d.ts +1 -0
- package/dist/internal-types.d.ts.map +1 -1
- package/dist/logger-diagnostics.cjs +4 -5
- package/dist/logger-diagnostics.cjs.map +1 -1
- package/dist/logger-diagnostics.d.ts +1 -1
- package/dist/logger-diagnostics.d.ts.map +1 -1
- package/dist/logger-diagnostics.js +1 -1
- package/dist/logger-diagnostics.js.map +1 -1
- package/dist/nest-integration.cjs +2 -127
- package/dist/nest-integration.cjs.map +1 -1
- package/dist/nest-integration.js +1 -126
- package/dist/nest-integration.js.map +1 -1
- package/dist/node-destination.d.ts.map +1 -1
- package/dist/payload-transforms.cjs +2 -2
- package/dist/payload-transforms.cjs.map +1 -1
- package/dist/payload-transforms.d.ts.map +1 -1
- package/dist/payload-transforms.js +1 -1
- package/dist/payload-transforms.js.map +1 -1
- package/dist/prisma-integration.cjs +2 -125
- package/dist/prisma-integration.cjs.map +1 -1
- package/dist/prisma-integration.js +1 -124
- package/dist/prisma-integration.js.map +1 -1
- package/dist/process-integration.cjs +20 -1
- package/dist/process-integration.cjs.map +1 -1
- package/dist/process-integration.d.ts +7 -0
- package/dist/process-integration.d.ts.map +1 -1
- package/dist/process-integration.js +20 -1
- package/dist/process-integration.js.map +1 -1
- package/dist/redis-integration.cjs +2 -125
- package/dist/redis-integration.cjs.map +1 -1
- package/dist/redis-integration.js +1 -124
- package/dist/redis-integration.js.map +1 -1
- package/dist/rotating-file-transport.cjs +24 -238
- package/dist/rotating-file-transport.cjs.map +1 -1
- package/dist/rotating-file-transport.d.ts.map +1 -1
- package/dist/rotating-file-transport.js +24 -238
- package/dist/rotating-file-transport.js.map +1 -1
- package/dist/stdout-transport.cjs +3 -162
- package/dist/stdout-transport.cjs.map +1 -1
- package/dist/stdout-transport.js +3 -162
- package/dist/stdout-transport.js.map +1 -1
- package/dist/syslog-transport.cjs +1 -1
- package/dist/syslog-transport.js +1 -1
- package/dist/worker-transport.cjs +5 -4
- package/dist/worker-transport.cjs.map +1 -1
- package/dist/worker-transport.d.ts.map +1 -1
- package/dist/worker-transport.js +3 -2
- package/dist/worker-transport.js.map +1 -1
- package/package.json +5 -2
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
let fs = require("fs");
|
|
2
|
+
let path = require("path");
|
|
3
|
+
//#region src/node-destination.ts
|
|
4
|
+
const encoder = new TextEncoder();
|
|
5
|
+
const normalizeError = (error) => error instanceof Error ? error : new Error(String(error));
|
|
6
|
+
function byteLength(payload) {
|
|
7
|
+
return typeof payload === "string" ? encoder.encode(payload).byteLength : payload.byteLength;
|
|
8
|
+
}
|
|
9
|
+
function coalescePayloads(payloads) {
|
|
10
|
+
if (payloads.every((payload) => typeof payload === "string")) return payloads.join("");
|
|
11
|
+
const buffers = payloads.map((payload) => typeof payload === "string" ? Buffer.from(payload) : Buffer.from(payload));
|
|
12
|
+
return Buffer.concat(buffers);
|
|
13
|
+
}
|
|
14
|
+
function isEpipe(error) {
|
|
15
|
+
return Boolean(error) && typeof error === "object" && error.code === "EPIPE";
|
|
16
|
+
}
|
|
17
|
+
function normalizeMinLength(value) {
|
|
18
|
+
if (value === void 0 || !Number.isFinite(value) || value <= 0) return 0;
|
|
19
|
+
return Math.floor(value);
|
|
20
|
+
}
|
|
21
|
+
function createNodeStreamDestination(options) {
|
|
22
|
+
const minLength = normalizeMinLength(options.minLength);
|
|
23
|
+
const ignoreEpipe = options.ignoreEpipe ?? false;
|
|
24
|
+
const waiters = [];
|
|
25
|
+
const buffer = [];
|
|
26
|
+
const pendingPayloads = [];
|
|
27
|
+
let bufferedBytes = 0;
|
|
28
|
+
let pendingWrites = 0;
|
|
29
|
+
let pendingDrains = 0;
|
|
30
|
+
let lastError;
|
|
31
|
+
let lastContext;
|
|
32
|
+
let closed = false;
|
|
33
|
+
const reportInternalError = (error, operation) => {
|
|
34
|
+
if (ignoreEpipe && isEpipe(error)) return;
|
|
35
|
+
lastContext?.reportInternalError(error, {
|
|
36
|
+
phase: "transport",
|
|
37
|
+
transport: options.name,
|
|
38
|
+
operation
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
const settleWaitersIfIdle = () => {
|
|
42
|
+
if (pendingWrites + pendingDrains > 0) return;
|
|
43
|
+
if (waiters.length === 0) return;
|
|
44
|
+
const error = lastError;
|
|
45
|
+
lastError = void 0;
|
|
46
|
+
for (const waiter of waiters.splice(0)) if (error) waiter.reject(error);
|
|
47
|
+
else waiter.resolve();
|
|
48
|
+
};
|
|
49
|
+
const recordError = (error, operation) => {
|
|
50
|
+
if (ignoreEpipe && isEpipe(error)) {
|
|
51
|
+
closed = true;
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
lastError = normalizeError(error);
|
|
55
|
+
reportInternalError(lastError, operation);
|
|
56
|
+
};
|
|
57
|
+
const releaseDrainsIfDestroyed = () => {
|
|
58
|
+
if (options.stream.destroyed) pendingDrains = 0;
|
|
59
|
+
};
|
|
60
|
+
const onStreamError = (error) => {
|
|
61
|
+
recordError(error, "stream-error");
|
|
62
|
+
releaseDrainsIfDestroyed();
|
|
63
|
+
settleWaitersIfIdle();
|
|
64
|
+
};
|
|
65
|
+
const offError = () => options.stream.off?.("error", onStreamError);
|
|
66
|
+
options.stream.on?.("error", onStreamError);
|
|
67
|
+
const waitForDrain = () => {
|
|
68
|
+
if (!options.stream.once || options.stream.destroyed) return;
|
|
69
|
+
pendingDrains += 1;
|
|
70
|
+
options.stream.once("drain", () => {
|
|
71
|
+
pendingDrains -= 1;
|
|
72
|
+
settleWaitersIfIdle();
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
const removePending = (payload) => {
|
|
76
|
+
const index = pendingPayloads.indexOf(payload);
|
|
77
|
+
if (index >= 0) pendingPayloads.splice(index, 1);
|
|
78
|
+
};
|
|
79
|
+
const writeNow = (payload) => {
|
|
80
|
+
if (closed) return;
|
|
81
|
+
pendingPayloads.push(payload);
|
|
82
|
+
pendingWrites += 1;
|
|
83
|
+
try {
|
|
84
|
+
if (options.stream.write(payload, (error) => {
|
|
85
|
+
removePending(payload);
|
|
86
|
+
pendingWrites -= 1;
|
|
87
|
+
if (error) recordError(error, options.reportOperation ?? "write");
|
|
88
|
+
releaseDrainsIfDestroyed();
|
|
89
|
+
settleWaitersIfIdle();
|
|
90
|
+
}) === false) waitForDrain();
|
|
91
|
+
} catch (error) {
|
|
92
|
+
removePending(payload);
|
|
93
|
+
pendingWrites -= 1;
|
|
94
|
+
recordError(error, options.reportOperation ?? "write");
|
|
95
|
+
settleWaitersIfIdle();
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
const flushBuffered = () => {
|
|
99
|
+
if (buffer.length === 0) return;
|
|
100
|
+
const payload = coalescePayloads(buffer.splice(0));
|
|
101
|
+
bufferedBytes = 0;
|
|
102
|
+
writeNow(payload);
|
|
103
|
+
};
|
|
104
|
+
const destination = {
|
|
105
|
+
write(payload, context) {
|
|
106
|
+
if (closed) return;
|
|
107
|
+
lastContext = context;
|
|
108
|
+
if (minLength > 0) {
|
|
109
|
+
buffer.push(payload);
|
|
110
|
+
bufferedBytes += byteLength(payload);
|
|
111
|
+
if (bufferedBytes >= minLength) flushBuffered();
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
writeNow(payload);
|
|
115
|
+
},
|
|
116
|
+
flush() {
|
|
117
|
+
flushBuffered();
|
|
118
|
+
releaseDrainsIfDestroyed();
|
|
119
|
+
if (pendingWrites + pendingDrains === 0) {
|
|
120
|
+
const error = lastError;
|
|
121
|
+
lastError = void 0;
|
|
122
|
+
if (error) return Promise.reject(error);
|
|
123
|
+
return Promise.resolve();
|
|
124
|
+
}
|
|
125
|
+
return new Promise((resolve, reject) => {
|
|
126
|
+
waiters.push({
|
|
127
|
+
resolve,
|
|
128
|
+
reject
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
},
|
|
132
|
+
flushSync() {
|
|
133
|
+
if (!options.syncWrite) {
|
|
134
|
+
flushBuffered();
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
for (const payload of buffer.splice(0)) options.syncWrite(payload);
|
|
138
|
+
bufferedBytes = 0;
|
|
139
|
+
for (const payload of pendingPayloads.splice(0)) options.syncWrite(payload);
|
|
140
|
+
},
|
|
141
|
+
close() {
|
|
142
|
+
return destination.flush().then(() => new Promise((resolve, reject) => {
|
|
143
|
+
if (!options.stream.end) {
|
|
144
|
+
closed = true;
|
|
145
|
+
offError();
|
|
146
|
+
resolve();
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
options.stream.end((error) => {
|
|
150
|
+
closed = true;
|
|
151
|
+
offError();
|
|
152
|
+
if (error && !(ignoreEpipe && isEpipe(error))) reject(error);
|
|
153
|
+
else resolve();
|
|
154
|
+
});
|
|
155
|
+
}), (error) => {
|
|
156
|
+
offError();
|
|
157
|
+
return Promise.reject(error);
|
|
158
|
+
});
|
|
159
|
+
},
|
|
160
|
+
closeSync() {
|
|
161
|
+
destination.flushSync();
|
|
162
|
+
closed = true;
|
|
163
|
+
offError();
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
return destination;
|
|
167
|
+
}
|
|
168
|
+
function createNodeFileDestination(options) {
|
|
169
|
+
const flags = options.flags ?? (options.append === false ? "w" : "a");
|
|
170
|
+
if (options.mkdir) (0, fs.mkdirSync)((0, path.dirname)(options.path), { recursive: true });
|
|
171
|
+
let fd;
|
|
172
|
+
let syncFlags = options.sync ? flags : "a";
|
|
173
|
+
const getFd = () => {
|
|
174
|
+
if (fd === void 0) {
|
|
175
|
+
fd = (0, fs.openSync)(options.path, syncFlags);
|
|
176
|
+
syncFlags = "a";
|
|
177
|
+
}
|
|
178
|
+
return fd;
|
|
179
|
+
};
|
|
180
|
+
const syncWrite = (payload) => {
|
|
181
|
+
if (typeof payload === "string") (0, fs.writeSync)(getFd(), payload);
|
|
182
|
+
else (0, fs.writeSync)(getFd(), payload);
|
|
183
|
+
};
|
|
184
|
+
if (options.sync) {
|
|
185
|
+
let closed = false;
|
|
186
|
+
const releaseSync = () => {
|
|
187
|
+
if (fd !== void 0) {
|
|
188
|
+
(0, fs.closeSync)(fd);
|
|
189
|
+
fd = void 0;
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
return {
|
|
193
|
+
write(payload) {
|
|
194
|
+
if (closed) return;
|
|
195
|
+
syncWrite(payload);
|
|
196
|
+
},
|
|
197
|
+
flush() {
|
|
198
|
+
return Promise.resolve();
|
|
199
|
+
},
|
|
200
|
+
flushSync() {},
|
|
201
|
+
close() {
|
|
202
|
+
releaseSync();
|
|
203
|
+
closed = true;
|
|
204
|
+
return Promise.resolve();
|
|
205
|
+
},
|
|
206
|
+
closeSync() {
|
|
207
|
+
releaseSync();
|
|
208
|
+
closed = true;
|
|
209
|
+
},
|
|
210
|
+
releaseSync
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
const stream = (0, fs.createWriteStream)(options.path, { flags });
|
|
214
|
+
stream.on("error", () => {});
|
|
215
|
+
const destination = createNodeStreamDestination({
|
|
216
|
+
name: options.name,
|
|
217
|
+
stream,
|
|
218
|
+
minLength: options.minLength,
|
|
219
|
+
syncWrite
|
|
220
|
+
});
|
|
221
|
+
const releaseSync = () => {
|
|
222
|
+
if (fd !== void 0) {
|
|
223
|
+
(0, fs.closeSync)(fd);
|
|
224
|
+
fd = void 0;
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
return {
|
|
228
|
+
...destination,
|
|
229
|
+
stream,
|
|
230
|
+
close() {
|
|
231
|
+
return destination.close().finally(releaseSync);
|
|
232
|
+
},
|
|
233
|
+
closeSync() {
|
|
234
|
+
destination.closeSync();
|
|
235
|
+
releaseSync();
|
|
236
|
+
},
|
|
237
|
+
releaseSync
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
//#endregion
|
|
241
|
+
Object.defineProperty(exports, "createNodeFileDestination", {
|
|
242
|
+
enumerable: true,
|
|
243
|
+
get: function() {
|
|
244
|
+
return createNodeFileDestination;
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
Object.defineProperty(exports, "createNodeStreamDestination", {
|
|
248
|
+
enumerable: true,
|
|
249
|
+
get: function() {
|
|
250
|
+
return createNodeStreamDestination;
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
//# sourceMappingURL=node-destination-DvP8jBvm.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node-destination-DvP8jBvm.cjs","names":[],"sources":["../../src/node-destination.ts"],"sourcesContent":["import { closeSync, createWriteStream, mkdirSync, openSync, writeSync, type WriteStream } from \"fs\";\nimport { dirname } from \"path\";\nimport type { TransportContext } from \"@loggerjs/core\";\nimport type { WritableLike } from \"./internal-types\";\n\nexport interface NodeDestination {\n stream?: WriteStream;\n write: (payload: string | Uint8Array, context?: TransportContext) => void;\n flush: () => Promise<void>;\n flushSync: () => void;\n close: () => Promise<void>;\n closeSync: () => void;\n releaseSync?: () => void;\n}\n\nexport interface NodeStreamDestinationOptions {\n name: string;\n stream: WritableLike;\n minLength?: number;\n ignoreEpipe?: boolean;\n reportOperation?: string;\n syncWrite?: (payload: string | Uint8Array) => void;\n}\n\nexport interface NodeFileDestinationOptions {\n name: string;\n path: string;\n flags?: string;\n append?: boolean;\n mkdir?: boolean;\n sync?: boolean;\n minLength?: number;\n}\n\ninterface FlushWaiter {\n resolve: () => void;\n reject: (error: Error) => void;\n}\n\nconst encoder = new TextEncoder();\n\nconst normalizeError = (error: unknown): Error =>\n error instanceof Error ? error : new Error(String(error));\n\nfunction byteLength(payload: string | Uint8Array): number {\n return typeof payload === \"string\" ? encoder.encode(payload).byteLength : payload.byteLength;\n}\n\nfunction coalescePayloads(payloads: Array<string | Uint8Array>): string | Uint8Array {\n if (payloads.every((payload) => typeof payload === \"string\")) {\n return payloads.join(\"\");\n }\n const buffers = payloads.map((payload) =>\n typeof payload === \"string\" ? Buffer.from(payload) : Buffer.from(payload),\n );\n return Buffer.concat(buffers);\n}\n\nfunction isEpipe(error: unknown): boolean {\n return (\n Boolean(error) && typeof error === \"object\" && (error as { code?: unknown }).code === \"EPIPE\"\n );\n}\n\nfunction normalizeMinLength(value: number | undefined): number {\n if (value === undefined || !Number.isFinite(value) || value <= 0) return 0;\n return Math.floor(value);\n}\n\nexport function createNodeStreamDestination(\n options: NodeStreamDestinationOptions,\n): NodeDestination {\n const minLength = normalizeMinLength(options.minLength);\n const ignoreEpipe = options.ignoreEpipe ?? false;\n const waiters: FlushWaiter[] = [];\n const buffer: Array<string | Uint8Array> = [];\n const pendingPayloads: Array<string | Uint8Array> = [];\n let bufferedBytes = 0;\n let pendingWrites = 0;\n let pendingDrains = 0;\n let lastError: Error | undefined;\n let lastContext: TransportContext | undefined;\n let closed = false;\n\n const reportInternalError = (error: unknown, operation: string) => {\n if (ignoreEpipe && isEpipe(error)) return;\n lastContext?.reportInternalError(error, {\n phase: \"transport\",\n transport: options.name,\n operation,\n });\n };\n\n const settleWaitersIfIdle = () => {\n if (pendingWrites + pendingDrains > 0) return;\n if (waiters.length === 0) return;\n const error = lastError;\n lastError = undefined;\n for (const waiter of waiters.splice(0)) {\n if (error) waiter.reject(error);\n else waiter.resolve();\n }\n };\n\n const recordError = (error: unknown, operation: string) => {\n if (ignoreEpipe && isEpipe(error)) {\n closed = true;\n return;\n }\n lastError = normalizeError(error);\n reportInternalError(lastError, operation);\n };\n\n // A destroyed stream (for example after ENOSPC or EISDIR) never emits\n // drain, so waiting for one would leave flush() and close() pending forever.\n const releaseDrainsIfDestroyed = () => {\n if (options.stream.destroyed) pendingDrains = 0;\n };\n\n const onStreamError = (error: Error) => {\n recordError(error, \"stream-error\");\n releaseDrainsIfDestroyed();\n settleWaitersIfIdle();\n };\n const offError = () => options.stream.off?.(\"error\", onStreamError);\n options.stream.on?.(\"error\", onStreamError);\n\n const waitForDrain = () => {\n if (!options.stream.once || options.stream.destroyed) return;\n pendingDrains += 1;\n options.stream.once(\"drain\", () => {\n pendingDrains -= 1;\n settleWaitersIfIdle();\n });\n };\n\n const removePending = (payload: string | Uint8Array) => {\n const index = pendingPayloads.indexOf(payload);\n if (index >= 0) pendingPayloads.splice(index, 1);\n };\n\n const writeNow = (payload: string | Uint8Array) => {\n if (closed) return;\n pendingPayloads.push(payload);\n pendingWrites += 1;\n try {\n const result = options.stream.write(payload, (error?: Error | null) => {\n removePending(payload);\n pendingWrites -= 1;\n if (error) recordError(error, options.reportOperation ?? \"write\");\n releaseDrainsIfDestroyed();\n settleWaitersIfIdle();\n });\n if (result === false) waitForDrain();\n } catch (error) {\n removePending(payload);\n pendingWrites -= 1;\n recordError(error, options.reportOperation ?? \"write\");\n settleWaitersIfIdle();\n }\n };\n\n const flushBuffered = () => {\n if (buffer.length === 0) return;\n const payload = coalescePayloads(buffer.splice(0));\n bufferedBytes = 0;\n writeNow(payload);\n };\n\n const destination: NodeDestination = {\n write(payload, context) {\n if (closed) return;\n lastContext = context;\n if (minLength > 0) {\n buffer.push(payload);\n bufferedBytes += byteLength(payload);\n if (bufferedBytes >= minLength) flushBuffered();\n return;\n }\n writeNow(payload);\n },\n flush() {\n flushBuffered();\n releaseDrainsIfDestroyed();\n if (pendingWrites + pendingDrains === 0) {\n const error = lastError;\n lastError = undefined;\n if (error) return Promise.reject(error);\n return Promise.resolve();\n }\n return new Promise<void>((resolve, reject) => {\n waiters.push({ resolve, reject });\n });\n },\n flushSync() {\n if (!options.syncWrite) {\n flushBuffered();\n return;\n }\n for (const payload of buffer.splice(0)) options.syncWrite(payload);\n bufferedBytes = 0;\n for (const payload of pendingPayloads.splice(0)) options.syncWrite(payload);\n },\n close() {\n return destination.flush().then(\n () =>\n new Promise<void>((resolve, reject) => {\n if (!options.stream.end) {\n closed = true;\n offError();\n resolve();\n return;\n }\n options.stream.end((error?: Error | null) => {\n closed = true;\n offError();\n if (error && !(ignoreEpipe && isEpipe(error))) reject(error);\n else resolve();\n });\n }),\n (error: unknown) => {\n offError();\n return Promise.reject(error);\n },\n );\n },\n closeSync() {\n destination.flushSync();\n closed = true;\n offError();\n },\n };\n return destination;\n}\n\nexport function createNodeFileDestination(options: NodeFileDestinationOptions): NodeDestination {\n const flags = options.flags ?? (options.append === false ? \"w\" : \"a\");\n if (options.mkdir) mkdirSync(dirname(options.path), { recursive: true });\n\n let fd: number | undefined;\n // In sync mode this fd is the only writer, so it honors the configured flags.\n // In async stream mode the stream already opened (and, for \"w\", truncated)\n // the file; the crash-path fd must append or it would erase earlier logs.\n // Only the first open may truncate: the sync fd is reopened after a\n // rotation releases it, and if that rotation failed the file still holds\n // earlier logs that \"w\" would erase.\n let syncFlags = options.sync ? flags : \"a\";\n const getFd = () => {\n if (fd === undefined) {\n fd = openSync(options.path, syncFlags);\n syncFlags = \"a\";\n }\n return fd;\n };\n const syncWrite = (payload: string | Uint8Array) => {\n if (typeof payload === \"string\") writeSync(getFd(), payload);\n else writeSync(getFd(), payload);\n };\n\n if (options.sync) {\n let closed = false;\n const releaseSync = () => {\n if (fd !== undefined) {\n closeSync(fd);\n fd = undefined;\n }\n };\n return {\n write(payload) {\n if (closed) return;\n syncWrite(payload);\n },\n flush() {\n return Promise.resolve();\n },\n flushSync() {},\n close() {\n releaseSync();\n closed = true;\n return Promise.resolve();\n },\n closeSync() {\n releaseSync();\n closed = true;\n },\n releaseSync,\n };\n }\n\n const stream = createWriteStream(options.path, { flags });\n // This destination owns the stream, so keep an error listener on it for its\n // whole life. close() removes the reporting listener, and a write that fails\n // afterwards (for example ENOSPC while the last buffered chunk is flushed)\n // would otherwise be an unhandled 'error' event and crash the process.\n stream.on(\"error\", () => {});\n const destination = createNodeStreamDestination({\n name: options.name,\n stream,\n minLength: options.minLength,\n syncWrite,\n });\n const releaseSync = () => {\n if (fd !== undefined) {\n closeSync(fd);\n fd = undefined;\n }\n };\n return {\n ...destination,\n stream,\n close() {\n return destination.close().finally(releaseSync);\n },\n closeSync() {\n destination.closeSync();\n releaseSync();\n },\n releaseSync,\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import { closeSync, createWriteStream, mkdirSync, openSync, writeSync } from "fs";
|
|
2
|
+
import { dirname } from "path";
|
|
3
|
+
//#region src/node-destination.ts
|
|
4
|
+
const encoder = new TextEncoder();
|
|
5
|
+
const normalizeError = (error) => error instanceof Error ? error : new Error(String(error));
|
|
6
|
+
function byteLength(payload) {
|
|
7
|
+
return typeof payload === "string" ? encoder.encode(payload).byteLength : payload.byteLength;
|
|
8
|
+
}
|
|
9
|
+
function coalescePayloads(payloads) {
|
|
10
|
+
if (payloads.every((payload) => typeof payload === "string")) return payloads.join("");
|
|
11
|
+
const buffers = payloads.map((payload) => typeof payload === "string" ? Buffer.from(payload) : Buffer.from(payload));
|
|
12
|
+
return Buffer.concat(buffers);
|
|
13
|
+
}
|
|
14
|
+
function isEpipe(error) {
|
|
15
|
+
return Boolean(error) && typeof error === "object" && error.code === "EPIPE";
|
|
16
|
+
}
|
|
17
|
+
function normalizeMinLength(value) {
|
|
18
|
+
if (value === void 0 || !Number.isFinite(value) || value <= 0) return 0;
|
|
19
|
+
return Math.floor(value);
|
|
20
|
+
}
|
|
21
|
+
function createNodeStreamDestination(options) {
|
|
22
|
+
const minLength = normalizeMinLength(options.minLength);
|
|
23
|
+
const ignoreEpipe = options.ignoreEpipe ?? false;
|
|
24
|
+
const waiters = [];
|
|
25
|
+
const buffer = [];
|
|
26
|
+
const pendingPayloads = [];
|
|
27
|
+
let bufferedBytes = 0;
|
|
28
|
+
let pendingWrites = 0;
|
|
29
|
+
let pendingDrains = 0;
|
|
30
|
+
let lastError;
|
|
31
|
+
let lastContext;
|
|
32
|
+
let closed = false;
|
|
33
|
+
const reportInternalError = (error, operation) => {
|
|
34
|
+
if (ignoreEpipe && isEpipe(error)) return;
|
|
35
|
+
lastContext?.reportInternalError(error, {
|
|
36
|
+
phase: "transport",
|
|
37
|
+
transport: options.name,
|
|
38
|
+
operation
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
const settleWaitersIfIdle = () => {
|
|
42
|
+
if (pendingWrites + pendingDrains > 0) return;
|
|
43
|
+
if (waiters.length === 0) return;
|
|
44
|
+
const error = lastError;
|
|
45
|
+
lastError = void 0;
|
|
46
|
+
for (const waiter of waiters.splice(0)) if (error) waiter.reject(error);
|
|
47
|
+
else waiter.resolve();
|
|
48
|
+
};
|
|
49
|
+
const recordError = (error, operation) => {
|
|
50
|
+
if (ignoreEpipe && isEpipe(error)) {
|
|
51
|
+
closed = true;
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
lastError = normalizeError(error);
|
|
55
|
+
reportInternalError(lastError, operation);
|
|
56
|
+
};
|
|
57
|
+
const releaseDrainsIfDestroyed = () => {
|
|
58
|
+
if (options.stream.destroyed) pendingDrains = 0;
|
|
59
|
+
};
|
|
60
|
+
const onStreamError = (error) => {
|
|
61
|
+
recordError(error, "stream-error");
|
|
62
|
+
releaseDrainsIfDestroyed();
|
|
63
|
+
settleWaitersIfIdle();
|
|
64
|
+
};
|
|
65
|
+
const offError = () => options.stream.off?.("error", onStreamError);
|
|
66
|
+
options.stream.on?.("error", onStreamError);
|
|
67
|
+
const waitForDrain = () => {
|
|
68
|
+
if (!options.stream.once || options.stream.destroyed) return;
|
|
69
|
+
pendingDrains += 1;
|
|
70
|
+
options.stream.once("drain", () => {
|
|
71
|
+
pendingDrains -= 1;
|
|
72
|
+
settleWaitersIfIdle();
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
const removePending = (payload) => {
|
|
76
|
+
const index = pendingPayloads.indexOf(payload);
|
|
77
|
+
if (index >= 0) pendingPayloads.splice(index, 1);
|
|
78
|
+
};
|
|
79
|
+
const writeNow = (payload) => {
|
|
80
|
+
if (closed) return;
|
|
81
|
+
pendingPayloads.push(payload);
|
|
82
|
+
pendingWrites += 1;
|
|
83
|
+
try {
|
|
84
|
+
if (options.stream.write(payload, (error) => {
|
|
85
|
+
removePending(payload);
|
|
86
|
+
pendingWrites -= 1;
|
|
87
|
+
if (error) recordError(error, options.reportOperation ?? "write");
|
|
88
|
+
releaseDrainsIfDestroyed();
|
|
89
|
+
settleWaitersIfIdle();
|
|
90
|
+
}) === false) waitForDrain();
|
|
91
|
+
} catch (error) {
|
|
92
|
+
removePending(payload);
|
|
93
|
+
pendingWrites -= 1;
|
|
94
|
+
recordError(error, options.reportOperation ?? "write");
|
|
95
|
+
settleWaitersIfIdle();
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
const flushBuffered = () => {
|
|
99
|
+
if (buffer.length === 0) return;
|
|
100
|
+
const payload = coalescePayloads(buffer.splice(0));
|
|
101
|
+
bufferedBytes = 0;
|
|
102
|
+
writeNow(payload);
|
|
103
|
+
};
|
|
104
|
+
const destination = {
|
|
105
|
+
write(payload, context) {
|
|
106
|
+
if (closed) return;
|
|
107
|
+
lastContext = context;
|
|
108
|
+
if (minLength > 0) {
|
|
109
|
+
buffer.push(payload);
|
|
110
|
+
bufferedBytes += byteLength(payload);
|
|
111
|
+
if (bufferedBytes >= minLength) flushBuffered();
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
writeNow(payload);
|
|
115
|
+
},
|
|
116
|
+
flush() {
|
|
117
|
+
flushBuffered();
|
|
118
|
+
releaseDrainsIfDestroyed();
|
|
119
|
+
if (pendingWrites + pendingDrains === 0) {
|
|
120
|
+
const error = lastError;
|
|
121
|
+
lastError = void 0;
|
|
122
|
+
if (error) return Promise.reject(error);
|
|
123
|
+
return Promise.resolve();
|
|
124
|
+
}
|
|
125
|
+
return new Promise((resolve, reject) => {
|
|
126
|
+
waiters.push({
|
|
127
|
+
resolve,
|
|
128
|
+
reject
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
},
|
|
132
|
+
flushSync() {
|
|
133
|
+
if (!options.syncWrite) {
|
|
134
|
+
flushBuffered();
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
for (const payload of buffer.splice(0)) options.syncWrite(payload);
|
|
138
|
+
bufferedBytes = 0;
|
|
139
|
+
for (const payload of pendingPayloads.splice(0)) options.syncWrite(payload);
|
|
140
|
+
},
|
|
141
|
+
close() {
|
|
142
|
+
return destination.flush().then(() => new Promise((resolve, reject) => {
|
|
143
|
+
if (!options.stream.end) {
|
|
144
|
+
closed = true;
|
|
145
|
+
offError();
|
|
146
|
+
resolve();
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
options.stream.end((error) => {
|
|
150
|
+
closed = true;
|
|
151
|
+
offError();
|
|
152
|
+
if (error && !(ignoreEpipe && isEpipe(error))) reject(error);
|
|
153
|
+
else resolve();
|
|
154
|
+
});
|
|
155
|
+
}), (error) => {
|
|
156
|
+
offError();
|
|
157
|
+
return Promise.reject(error);
|
|
158
|
+
});
|
|
159
|
+
},
|
|
160
|
+
closeSync() {
|
|
161
|
+
destination.flushSync();
|
|
162
|
+
closed = true;
|
|
163
|
+
offError();
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
return destination;
|
|
167
|
+
}
|
|
168
|
+
function createNodeFileDestination(options) {
|
|
169
|
+
const flags = options.flags ?? (options.append === false ? "w" : "a");
|
|
170
|
+
if (options.mkdir) mkdirSync(dirname(options.path), { recursive: true });
|
|
171
|
+
let fd;
|
|
172
|
+
let syncFlags = options.sync ? flags : "a";
|
|
173
|
+
const getFd = () => {
|
|
174
|
+
if (fd === void 0) {
|
|
175
|
+
fd = openSync(options.path, syncFlags);
|
|
176
|
+
syncFlags = "a";
|
|
177
|
+
}
|
|
178
|
+
return fd;
|
|
179
|
+
};
|
|
180
|
+
const syncWrite = (payload) => {
|
|
181
|
+
if (typeof payload === "string") writeSync(getFd(), payload);
|
|
182
|
+
else writeSync(getFd(), payload);
|
|
183
|
+
};
|
|
184
|
+
if (options.sync) {
|
|
185
|
+
let closed = false;
|
|
186
|
+
const releaseSync = () => {
|
|
187
|
+
if (fd !== void 0) {
|
|
188
|
+
closeSync(fd);
|
|
189
|
+
fd = void 0;
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
return {
|
|
193
|
+
write(payload) {
|
|
194
|
+
if (closed) return;
|
|
195
|
+
syncWrite(payload);
|
|
196
|
+
},
|
|
197
|
+
flush() {
|
|
198
|
+
return Promise.resolve();
|
|
199
|
+
},
|
|
200
|
+
flushSync() {},
|
|
201
|
+
close() {
|
|
202
|
+
releaseSync();
|
|
203
|
+
closed = true;
|
|
204
|
+
return Promise.resolve();
|
|
205
|
+
},
|
|
206
|
+
closeSync() {
|
|
207
|
+
releaseSync();
|
|
208
|
+
closed = true;
|
|
209
|
+
},
|
|
210
|
+
releaseSync
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
const stream = createWriteStream(options.path, { flags });
|
|
214
|
+
stream.on("error", () => {});
|
|
215
|
+
const destination = createNodeStreamDestination({
|
|
216
|
+
name: options.name,
|
|
217
|
+
stream,
|
|
218
|
+
minLength: options.minLength,
|
|
219
|
+
syncWrite
|
|
220
|
+
});
|
|
221
|
+
const releaseSync = () => {
|
|
222
|
+
if (fd !== void 0) {
|
|
223
|
+
closeSync(fd);
|
|
224
|
+
fd = void 0;
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
return {
|
|
228
|
+
...destination,
|
|
229
|
+
stream,
|
|
230
|
+
close() {
|
|
231
|
+
return destination.close().finally(releaseSync);
|
|
232
|
+
},
|
|
233
|
+
closeSync() {
|
|
234
|
+
destination.closeSync();
|
|
235
|
+
releaseSync();
|
|
236
|
+
},
|
|
237
|
+
releaseSync
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
//#endregion
|
|
241
|
+
export { createNodeStreamDestination as n, createNodeFileDestination as t };
|
|
242
|
+
|
|
243
|
+
//# sourceMappingURL=node-destination-YnpYbctz.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node-destination-YnpYbctz.js","names":[],"sources":["../../src/node-destination.ts"],"sourcesContent":["import { closeSync, createWriteStream, mkdirSync, openSync, writeSync, type WriteStream } from \"fs\";\nimport { dirname } from \"path\";\nimport type { TransportContext } from \"@loggerjs/core\";\nimport type { WritableLike } from \"./internal-types\";\n\nexport interface NodeDestination {\n stream?: WriteStream;\n write: (payload: string | Uint8Array, context?: TransportContext) => void;\n flush: () => Promise<void>;\n flushSync: () => void;\n close: () => Promise<void>;\n closeSync: () => void;\n releaseSync?: () => void;\n}\n\nexport interface NodeStreamDestinationOptions {\n name: string;\n stream: WritableLike;\n minLength?: number;\n ignoreEpipe?: boolean;\n reportOperation?: string;\n syncWrite?: (payload: string | Uint8Array) => void;\n}\n\nexport interface NodeFileDestinationOptions {\n name: string;\n path: string;\n flags?: string;\n append?: boolean;\n mkdir?: boolean;\n sync?: boolean;\n minLength?: number;\n}\n\ninterface FlushWaiter {\n resolve: () => void;\n reject: (error: Error) => void;\n}\n\nconst encoder = new TextEncoder();\n\nconst normalizeError = (error: unknown): Error =>\n error instanceof Error ? error : new Error(String(error));\n\nfunction byteLength(payload: string | Uint8Array): number {\n return typeof payload === \"string\" ? encoder.encode(payload).byteLength : payload.byteLength;\n}\n\nfunction coalescePayloads(payloads: Array<string | Uint8Array>): string | Uint8Array {\n if (payloads.every((payload) => typeof payload === \"string\")) {\n return payloads.join(\"\");\n }\n const buffers = payloads.map((payload) =>\n typeof payload === \"string\" ? Buffer.from(payload) : Buffer.from(payload),\n );\n return Buffer.concat(buffers);\n}\n\nfunction isEpipe(error: unknown): boolean {\n return (\n Boolean(error) && typeof error === \"object\" && (error as { code?: unknown }).code === \"EPIPE\"\n );\n}\n\nfunction normalizeMinLength(value: number | undefined): number {\n if (value === undefined || !Number.isFinite(value) || value <= 0) return 0;\n return Math.floor(value);\n}\n\nexport function createNodeStreamDestination(\n options: NodeStreamDestinationOptions,\n): NodeDestination {\n const minLength = normalizeMinLength(options.minLength);\n const ignoreEpipe = options.ignoreEpipe ?? false;\n const waiters: FlushWaiter[] = [];\n const buffer: Array<string | Uint8Array> = [];\n const pendingPayloads: Array<string | Uint8Array> = [];\n let bufferedBytes = 0;\n let pendingWrites = 0;\n let pendingDrains = 0;\n let lastError: Error | undefined;\n let lastContext: TransportContext | undefined;\n let closed = false;\n\n const reportInternalError = (error: unknown, operation: string) => {\n if (ignoreEpipe && isEpipe(error)) return;\n lastContext?.reportInternalError(error, {\n phase: \"transport\",\n transport: options.name,\n operation,\n });\n };\n\n const settleWaitersIfIdle = () => {\n if (pendingWrites + pendingDrains > 0) return;\n if (waiters.length === 0) return;\n const error = lastError;\n lastError = undefined;\n for (const waiter of waiters.splice(0)) {\n if (error) waiter.reject(error);\n else waiter.resolve();\n }\n };\n\n const recordError = (error: unknown, operation: string) => {\n if (ignoreEpipe && isEpipe(error)) {\n closed = true;\n return;\n }\n lastError = normalizeError(error);\n reportInternalError(lastError, operation);\n };\n\n // A destroyed stream (for example after ENOSPC or EISDIR) never emits\n // drain, so waiting for one would leave flush() and close() pending forever.\n const releaseDrainsIfDestroyed = () => {\n if (options.stream.destroyed) pendingDrains = 0;\n };\n\n const onStreamError = (error: Error) => {\n recordError(error, \"stream-error\");\n releaseDrainsIfDestroyed();\n settleWaitersIfIdle();\n };\n const offError = () => options.stream.off?.(\"error\", onStreamError);\n options.stream.on?.(\"error\", onStreamError);\n\n const waitForDrain = () => {\n if (!options.stream.once || options.stream.destroyed) return;\n pendingDrains += 1;\n options.stream.once(\"drain\", () => {\n pendingDrains -= 1;\n settleWaitersIfIdle();\n });\n };\n\n const removePending = (payload: string | Uint8Array) => {\n const index = pendingPayloads.indexOf(payload);\n if (index >= 0) pendingPayloads.splice(index, 1);\n };\n\n const writeNow = (payload: string | Uint8Array) => {\n if (closed) return;\n pendingPayloads.push(payload);\n pendingWrites += 1;\n try {\n const result = options.stream.write(payload, (error?: Error | null) => {\n removePending(payload);\n pendingWrites -= 1;\n if (error) recordError(error, options.reportOperation ?? \"write\");\n releaseDrainsIfDestroyed();\n settleWaitersIfIdle();\n });\n if (result === false) waitForDrain();\n } catch (error) {\n removePending(payload);\n pendingWrites -= 1;\n recordError(error, options.reportOperation ?? \"write\");\n settleWaitersIfIdle();\n }\n };\n\n const flushBuffered = () => {\n if (buffer.length === 0) return;\n const payload = coalescePayloads(buffer.splice(0));\n bufferedBytes = 0;\n writeNow(payload);\n };\n\n const destination: NodeDestination = {\n write(payload, context) {\n if (closed) return;\n lastContext = context;\n if (minLength > 0) {\n buffer.push(payload);\n bufferedBytes += byteLength(payload);\n if (bufferedBytes >= minLength) flushBuffered();\n return;\n }\n writeNow(payload);\n },\n flush() {\n flushBuffered();\n releaseDrainsIfDestroyed();\n if (pendingWrites + pendingDrains === 0) {\n const error = lastError;\n lastError = undefined;\n if (error) return Promise.reject(error);\n return Promise.resolve();\n }\n return new Promise<void>((resolve, reject) => {\n waiters.push({ resolve, reject });\n });\n },\n flushSync() {\n if (!options.syncWrite) {\n flushBuffered();\n return;\n }\n for (const payload of buffer.splice(0)) options.syncWrite(payload);\n bufferedBytes = 0;\n for (const payload of pendingPayloads.splice(0)) options.syncWrite(payload);\n },\n close() {\n return destination.flush().then(\n () =>\n new Promise<void>((resolve, reject) => {\n if (!options.stream.end) {\n closed = true;\n offError();\n resolve();\n return;\n }\n options.stream.end((error?: Error | null) => {\n closed = true;\n offError();\n if (error && !(ignoreEpipe && isEpipe(error))) reject(error);\n else resolve();\n });\n }),\n (error: unknown) => {\n offError();\n return Promise.reject(error);\n },\n );\n },\n closeSync() {\n destination.flushSync();\n closed = true;\n offError();\n },\n };\n return destination;\n}\n\nexport function createNodeFileDestination(options: NodeFileDestinationOptions): NodeDestination {\n const flags = options.flags ?? (options.append === false ? \"w\" : \"a\");\n if (options.mkdir) mkdirSync(dirname(options.path), { recursive: true });\n\n let fd: number | undefined;\n // In sync mode this fd is the only writer, so it honors the configured flags.\n // In async stream mode the stream already opened (and, for \"w\", truncated)\n // the file; the crash-path fd must append or it would erase earlier logs.\n // Only the first open may truncate: the sync fd is reopened after a\n // rotation releases it, and if that rotation failed the file still holds\n // earlier logs that \"w\" would erase.\n let syncFlags = options.sync ? flags : \"a\";\n const getFd = () => {\n if (fd === undefined) {\n fd = openSync(options.path, syncFlags);\n syncFlags = \"a\";\n }\n return fd;\n };\n const syncWrite = (payload: string | Uint8Array) => {\n if (typeof payload === \"string\") writeSync(getFd(), payload);\n else writeSync(getFd(), payload);\n };\n\n if (options.sync) {\n let closed = false;\n const releaseSync = () => {\n if (fd !== undefined) {\n closeSync(fd);\n fd = undefined;\n }\n };\n return {\n write(payload) {\n if (closed) return;\n syncWrite(payload);\n },\n flush() {\n return Promise.resolve();\n },\n flushSync() {},\n close() {\n releaseSync();\n closed = true;\n return Promise.resolve();\n },\n closeSync() {\n releaseSync();\n closed = true;\n },\n releaseSync,\n };\n }\n\n const stream = createWriteStream(options.path, { flags });\n // This destination owns the stream, so keep an error listener on it for its\n // whole life. close() removes the reporting listener, and a write that fails\n // afterwards (for example ENOSPC while the last buffered chunk is flushed)\n // would otherwise be an unhandled 'error' event and crash the process.\n stream.on(\"error\", () => {});\n const destination = createNodeStreamDestination({\n name: options.name,\n stream,\n minLength: options.minLength,\n syncWrite,\n });\n const releaseSync = () => {\n if (fd !== undefined) {\n closeSync(fd);\n fd = undefined;\n }\n };\n return {\n ...destination,\n stream,\n close() {\n return destination.close().finally(releaseSync);\n },\n closeSync() {\n destination.closeSync();\n releaseSync();\n },\n releaseSync,\n };\n}\n"],"mappings":";;;AAuCA,MAAM,UAAU,IAAI,YAAY;AAEhC,MAAM,kBAAkB,UACtB,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AAE1D,SAAS,WAAW,SAAsC;CACxD,OAAO,OAAO,YAAY,WAAW,QAAQ,OAAO,OAAO,CAAC,CAAC,aAAa,QAAQ;AACpF;AAEA,SAAS,iBAAiB,UAA2D;CACnF,IAAI,SAAS,OAAO,YAAY,OAAO,YAAY,QAAQ,GACzD,OAAO,SAAS,KAAK,EAAE;CAEzB,MAAM,UAAU,SAAS,KAAK,YAC5B,OAAO,YAAY,WAAW,OAAO,KAAK,OAAO,IAAI,OAAO,KAAK,OAAO,CAC1E;CACA,OAAO,OAAO,OAAO,OAAO;AAC9B;AAEA,SAAS,QAAQ,OAAyB;CACxC,OACE,QAAQ,KAAK,KAAK,OAAO,UAAU,YAAa,MAA6B,SAAS;AAE1F;AAEA,SAAS,mBAAmB,OAAmC;CAC7D,IAAI,UAAU,KAAA,KAAa,CAAC,OAAO,SAAS,KAAK,KAAK,SAAS,GAAG,OAAO;CACzE,OAAO,KAAK,MAAM,KAAK;AACzB;AAEA,SAAgB,4BACd,SACiB;CACjB,MAAM,YAAY,mBAAmB,QAAQ,SAAS;CACtD,MAAM,cAAc,QAAQ,eAAe;CAC3C,MAAM,UAAyB,CAAC;CAChC,MAAM,SAAqC,CAAC;CAC5C,MAAM,kBAA8C,CAAC;CACrD,IAAI,gBAAgB;CACpB,IAAI,gBAAgB;CACpB,IAAI,gBAAgB;CACpB,IAAI;CACJ,IAAI;CACJ,IAAI,SAAS;CAEb,MAAM,uBAAuB,OAAgB,cAAsB;EACjE,IAAI,eAAe,QAAQ,KAAK,GAAG;EACnC,aAAa,oBAAoB,OAAO;GACtC,OAAO;GACP,WAAW,QAAQ;GACnB;EACF,CAAC;CACH;CAEA,MAAM,4BAA4B;EAChC,IAAI,gBAAgB,gBAAgB,GAAG;EACvC,IAAI,QAAQ,WAAW,GAAG;EAC1B,MAAM,QAAQ;EACd,YAAY,KAAA;EACZ,KAAK,MAAM,UAAU,QAAQ,OAAO,CAAC,GACnC,IAAI,OAAO,OAAO,OAAO,KAAK;OACzB,OAAO,QAAQ;CAExB;CAEA,MAAM,eAAe,OAAgB,cAAsB;EACzD,IAAI,eAAe,QAAQ,KAAK,GAAG;GACjC,SAAS;GACT;EACF;EACA,YAAY,eAAe,KAAK;EAChC,oBAAoB,WAAW,SAAS;CAC1C;CAIA,MAAM,iCAAiC;EACrC,IAAI,QAAQ,OAAO,WAAW,gBAAgB;CAChD;CAEA,MAAM,iBAAiB,UAAiB;EACtC,YAAY,OAAO,cAAc;EACjC,yBAAyB;EACzB,oBAAoB;CACtB;CACA,MAAM,iBAAiB,QAAQ,OAAO,MAAM,SAAS,aAAa;CAClE,QAAQ,OAAO,KAAK,SAAS,aAAa;CAE1C,MAAM,qBAAqB;EACzB,IAAI,CAAC,QAAQ,OAAO,QAAQ,QAAQ,OAAO,WAAW;EACtD,iBAAiB;EACjB,QAAQ,OAAO,KAAK,eAAe;GACjC,iBAAiB;GACjB,oBAAoB;EACtB,CAAC;CACH;CAEA,MAAM,iBAAiB,YAAiC;EACtD,MAAM,QAAQ,gBAAgB,QAAQ,OAAO;EAC7C,IAAI,SAAS,GAAG,gBAAgB,OAAO,OAAO,CAAC;CACjD;CAEA,MAAM,YAAY,YAAiC;EACjD,IAAI,QAAQ;EACZ,gBAAgB,KAAK,OAAO;EAC5B,iBAAiB;EACjB,IAAI;GAQF,IAPe,QAAQ,OAAO,MAAM,UAAU,UAAyB;IACrE,cAAc,OAAO;IACrB,iBAAiB;IACjB,IAAI,OAAO,YAAY,OAAO,QAAQ,mBAAmB,OAAO;IAChE,yBAAyB;IACzB,oBAAoB;GACtB,CACS,MAAM,OAAO,aAAa;EACrC,SAAS,OAAO;GACd,cAAc,OAAO;GACrB,iBAAiB;GACjB,YAAY,OAAO,QAAQ,mBAAmB,OAAO;GACrD,oBAAoB;EACtB;CACF;CAEA,MAAM,sBAAsB;EAC1B,IAAI,OAAO,WAAW,GAAG;EACzB,MAAM,UAAU,iBAAiB,OAAO,OAAO,CAAC,CAAC;EACjD,gBAAgB;EAChB,SAAS,OAAO;CAClB;CAEA,MAAM,cAA+B;EACnC,MAAM,SAAS,SAAS;GACtB,IAAI,QAAQ;GACZ,cAAc;GACd,IAAI,YAAY,GAAG;IACjB,OAAO,KAAK,OAAO;IACnB,iBAAiB,WAAW,OAAO;IACnC,IAAI,iBAAiB,WAAW,cAAc;IAC9C;GACF;GACA,SAAS,OAAO;EAClB;EACA,QAAQ;GACN,cAAc;GACd,yBAAyB;GACzB,IAAI,gBAAgB,kBAAkB,GAAG;IACvC,MAAM,QAAQ;IACd,YAAY,KAAA;IACZ,IAAI,OAAO,OAAO,QAAQ,OAAO,KAAK;IACtC,OAAO,QAAQ,QAAQ;GACzB;GACA,OAAO,IAAI,SAAe,SAAS,WAAW;IAC5C,QAAQ,KAAK;KAAE;KAAS;IAAO,CAAC;GAClC,CAAC;EACH;EACA,YAAY;GACV,IAAI,CAAC,QAAQ,WAAW;IACtB,cAAc;IACd;GACF;GACA,KAAK,MAAM,WAAW,OAAO,OAAO,CAAC,GAAG,QAAQ,UAAU,OAAO;GACjE,gBAAgB;GAChB,KAAK,MAAM,WAAW,gBAAgB,OAAO,CAAC,GAAG,QAAQ,UAAU,OAAO;EAC5E;EACA,QAAQ;GACN,OAAO,YAAY,MAAM,CAAC,CAAC,WAEvB,IAAI,SAAe,SAAS,WAAW;IACrC,IAAI,CAAC,QAAQ,OAAO,KAAK;KACvB,SAAS;KACT,SAAS;KACT,QAAQ;KACR;IACF;IACA,QAAQ,OAAO,KAAK,UAAyB;KAC3C,SAAS;KACT,SAAS;KACT,IAAI,SAAS,EAAE,eAAe,QAAQ,KAAK,IAAI,OAAO,KAAK;UACtD,QAAQ;IACf,CAAC;GACH,CAAC,IACF,UAAmB;IAClB,SAAS;IACT,OAAO,QAAQ,OAAO,KAAK;GAC7B,CACF;EACF;EACA,YAAY;GACV,YAAY,UAAU;GACtB,SAAS;GACT,SAAS;EACX;CACF;CACA,OAAO;AACT;AAEA,SAAgB,0BAA0B,SAAsD;CAC9F,MAAM,QAAQ,QAAQ,UAAU,QAAQ,WAAW,QAAQ,MAAM;CACjE,IAAI,QAAQ,OAAO,UAAU,QAAQ,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;CAEvE,IAAI;CAOJ,IAAI,YAAY,QAAQ,OAAO,QAAQ;CACvC,MAAM,cAAc;EAClB,IAAI,OAAO,KAAA,GAAW;GACpB,KAAK,SAAS,QAAQ,MAAM,SAAS;GACrC,YAAY;EACd;EACA,OAAO;CACT;CACA,MAAM,aAAa,YAAiC;EAClD,IAAI,OAAO,YAAY,UAAU,UAAU,MAAM,GAAG,OAAO;OACtD,UAAU,MAAM,GAAG,OAAO;CACjC;CAEA,IAAI,QAAQ,MAAM;EAChB,IAAI,SAAS;EACb,MAAM,oBAAoB;GACxB,IAAI,OAAO,KAAA,GAAW;IACpB,UAAU,EAAE;IACZ,KAAK,KAAA;GACP;EACF;EACA,OAAO;GACL,MAAM,SAAS;IACb,IAAI,QAAQ;IACZ,UAAU,OAAO;GACnB;GACA,QAAQ;IACN,OAAO,QAAQ,QAAQ;GACzB;GACA,YAAY,CAAC;GACb,QAAQ;IACN,YAAY;IACZ,SAAS;IACT,OAAO,QAAQ,QAAQ;GACzB;GACA,YAAY;IACV,YAAY;IACZ,SAAS;GACX;GACA;EACF;CACF;CAEA,MAAM,SAAS,kBAAkB,QAAQ,MAAM,EAAE,MAAM,CAAC;CAKxD,OAAO,GAAG,eAAe,CAAC,CAAC;CAC3B,MAAM,cAAc,4BAA4B;EAC9C,MAAM,QAAQ;EACd;EACA,WAAW,QAAQ;EACnB;CACF,CAAC;CACD,MAAM,oBAAoB;EACxB,IAAI,OAAO,KAAA,GAAW;GACpB,UAAU,EAAE;GACZ,KAAK,KAAA;EACP;CACF;CACA,OAAO;EACL,GAAG;EACH;EACA,QAAQ;GACN,OAAO,YAAY,MAAM,CAAC,CAAC,QAAQ,WAAW;EAChD;EACA,YAAY;GACV,YAAY,UAAU;GACtB,YAAY;EACd;EACA;CACF;AACF"}
|
package/dist/context.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
let node_async_hooks = require("node:async_hooks");
|
|
3
2
|
let _loggerjs_core = require("@loggerjs/core");
|
|
3
|
+
let node_async_hooks = require("node:async_hooks");
|
|
4
4
|
//#region src/context.ts
|
|
5
5
|
function mergeContext(...items) {
|
|
6
6
|
const out = {};
|
package/dist/context.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
1
|
import { createBoundContext, resetContextManager, setContextManager } from "@loggerjs/core";
|
|
2
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
3
3
|
//#region src/context.ts
|
|
4
4
|
function mergeContext(...items) {
|
|
5
5
|
const out = {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
let node_module = require("node:module");
|
|
3
2
|
let _loggerjs_core = require("@loggerjs/core");
|
|
3
|
+
let node_module = require("node:module");
|
|
4
4
|
//#region src/diagnostics-channel-integration.ts
|
|
5
5
|
const defaultChannels = [
|
|
6
6
|
"http.client.request.start",
|