@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
package/dist/file-transport.cjs
CHANGED
|
@@ -1,238 +1,10 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_node_destination = require("./chunks/node-destination-DvP8jBvm.cjs");
|
|
2
3
|
let _loggerjs_core = require("@loggerjs/core");
|
|
3
|
-
let fs = require("fs");
|
|
4
|
-
let path = require("path");
|
|
5
|
-
//#region src/node-destination.ts
|
|
6
|
-
const encoder = new TextEncoder();
|
|
7
|
-
const normalizeError = (error) => error instanceof Error ? error : new Error(String(error));
|
|
8
|
-
function byteLength(payload) {
|
|
9
|
-
return typeof payload === "string" ? encoder.encode(payload).byteLength : payload.byteLength;
|
|
10
|
-
}
|
|
11
|
-
function coalescePayloads(payloads) {
|
|
12
|
-
if (payloads.every((payload) => typeof payload === "string")) return payloads.join("");
|
|
13
|
-
const buffers = payloads.map((payload) => typeof payload === "string" ? Buffer.from(payload) : Buffer.from(payload));
|
|
14
|
-
return Buffer.concat(buffers);
|
|
15
|
-
}
|
|
16
|
-
function isEpipe(error) {
|
|
17
|
-
return Boolean(error) && typeof error === "object" && error.code === "EPIPE";
|
|
18
|
-
}
|
|
19
|
-
function normalizeMinLength(value) {
|
|
20
|
-
if (value === void 0 || !Number.isFinite(value) || value <= 0) return 0;
|
|
21
|
-
return Math.floor(value);
|
|
22
|
-
}
|
|
23
|
-
function createNodeStreamDestination(options) {
|
|
24
|
-
const minLength = normalizeMinLength(options.minLength);
|
|
25
|
-
const ignoreEpipe = options.ignoreEpipe ?? false;
|
|
26
|
-
const waiters = [];
|
|
27
|
-
const buffer = [];
|
|
28
|
-
const pendingPayloads = [];
|
|
29
|
-
let bufferedBytes = 0;
|
|
30
|
-
let pendingWrites = 0;
|
|
31
|
-
let pendingDrains = 0;
|
|
32
|
-
let lastError;
|
|
33
|
-
let lastContext;
|
|
34
|
-
let closed = false;
|
|
35
|
-
const reportInternalError = (error, operation) => {
|
|
36
|
-
if (ignoreEpipe && isEpipe(error)) return;
|
|
37
|
-
lastContext?.reportInternalError(error, {
|
|
38
|
-
phase: "transport",
|
|
39
|
-
transport: options.name,
|
|
40
|
-
operation
|
|
41
|
-
});
|
|
42
|
-
};
|
|
43
|
-
const settleWaitersIfIdle = () => {
|
|
44
|
-
if (pendingWrites + pendingDrains > 0) return;
|
|
45
|
-
if (waiters.length === 0) return;
|
|
46
|
-
const error = lastError;
|
|
47
|
-
lastError = void 0;
|
|
48
|
-
for (const waiter of waiters.splice(0)) if (error) waiter.reject(error);
|
|
49
|
-
else waiter.resolve();
|
|
50
|
-
};
|
|
51
|
-
const recordError = (error, operation) => {
|
|
52
|
-
if (ignoreEpipe && isEpipe(error)) {
|
|
53
|
-
closed = true;
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
lastError = normalizeError(error);
|
|
57
|
-
reportInternalError(lastError, operation);
|
|
58
|
-
};
|
|
59
|
-
const onStreamError = (error) => {
|
|
60
|
-
recordError(error, "stream-error");
|
|
61
|
-
settleWaitersIfIdle();
|
|
62
|
-
};
|
|
63
|
-
const offError = () => options.stream.off?.("error", onStreamError);
|
|
64
|
-
options.stream.on?.("error", onStreamError);
|
|
65
|
-
const waitForDrain = () => {
|
|
66
|
-
if (!options.stream.once) return;
|
|
67
|
-
pendingDrains += 1;
|
|
68
|
-
options.stream.once("drain", () => {
|
|
69
|
-
pendingDrains -= 1;
|
|
70
|
-
settleWaitersIfIdle();
|
|
71
|
-
});
|
|
72
|
-
};
|
|
73
|
-
const removePending = (payload) => {
|
|
74
|
-
const index = pendingPayloads.indexOf(payload);
|
|
75
|
-
if (index >= 0) pendingPayloads.splice(index, 1);
|
|
76
|
-
};
|
|
77
|
-
const writeNow = (payload) => {
|
|
78
|
-
if (closed) return;
|
|
79
|
-
pendingPayloads.push(payload);
|
|
80
|
-
pendingWrites += 1;
|
|
81
|
-
try {
|
|
82
|
-
if (options.stream.write(payload, (error) => {
|
|
83
|
-
removePending(payload);
|
|
84
|
-
pendingWrites -= 1;
|
|
85
|
-
if (error) recordError(error, options.reportOperation ?? "write");
|
|
86
|
-
settleWaitersIfIdle();
|
|
87
|
-
}) === false) waitForDrain();
|
|
88
|
-
} catch (error) {
|
|
89
|
-
removePending(payload);
|
|
90
|
-
pendingWrites -= 1;
|
|
91
|
-
recordError(error, options.reportOperation ?? "write");
|
|
92
|
-
settleWaitersIfIdle();
|
|
93
|
-
}
|
|
94
|
-
};
|
|
95
|
-
const flushBuffered = () => {
|
|
96
|
-
if (buffer.length === 0) return;
|
|
97
|
-
const payload = coalescePayloads(buffer.splice(0));
|
|
98
|
-
bufferedBytes = 0;
|
|
99
|
-
writeNow(payload);
|
|
100
|
-
};
|
|
101
|
-
const destination = {
|
|
102
|
-
write(payload, context) {
|
|
103
|
-
if (closed) return;
|
|
104
|
-
lastContext = context;
|
|
105
|
-
if (minLength > 0) {
|
|
106
|
-
buffer.push(payload);
|
|
107
|
-
bufferedBytes += byteLength(payload);
|
|
108
|
-
if (bufferedBytes >= minLength) flushBuffered();
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
writeNow(payload);
|
|
112
|
-
},
|
|
113
|
-
flush() {
|
|
114
|
-
flushBuffered();
|
|
115
|
-
if (pendingWrites + pendingDrains === 0) {
|
|
116
|
-
const error = lastError;
|
|
117
|
-
lastError = void 0;
|
|
118
|
-
if (error) return Promise.reject(error);
|
|
119
|
-
return Promise.resolve();
|
|
120
|
-
}
|
|
121
|
-
return new Promise((resolve, reject) => {
|
|
122
|
-
waiters.push({
|
|
123
|
-
resolve,
|
|
124
|
-
reject
|
|
125
|
-
});
|
|
126
|
-
});
|
|
127
|
-
},
|
|
128
|
-
flushSync() {
|
|
129
|
-
if (!options.syncWrite) {
|
|
130
|
-
flushBuffered();
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
for (const payload of buffer.splice(0)) options.syncWrite(payload);
|
|
134
|
-
bufferedBytes = 0;
|
|
135
|
-
for (const payload of pendingPayloads.splice(0)) options.syncWrite(payload);
|
|
136
|
-
},
|
|
137
|
-
close() {
|
|
138
|
-
return destination.flush().then(() => new Promise((resolve, reject) => {
|
|
139
|
-
if (!options.stream.end) {
|
|
140
|
-
closed = true;
|
|
141
|
-
offError();
|
|
142
|
-
resolve();
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
options.stream.end((error) => {
|
|
146
|
-
closed = true;
|
|
147
|
-
offError();
|
|
148
|
-
if (error && !(ignoreEpipe && isEpipe(error))) reject(error);
|
|
149
|
-
else resolve();
|
|
150
|
-
});
|
|
151
|
-
}), (error) => {
|
|
152
|
-
offError();
|
|
153
|
-
return Promise.reject(error);
|
|
154
|
-
});
|
|
155
|
-
},
|
|
156
|
-
closeSync() {
|
|
157
|
-
destination.flushSync();
|
|
158
|
-
closed = true;
|
|
159
|
-
offError();
|
|
160
|
-
}
|
|
161
|
-
};
|
|
162
|
-
return destination;
|
|
163
|
-
}
|
|
164
|
-
function createNodeFileDestination(options) {
|
|
165
|
-
const flags = options.flags ?? (options.append === false ? "w" : "a");
|
|
166
|
-
if (options.mkdir) (0, fs.mkdirSync)((0, path.dirname)(options.path), { recursive: true });
|
|
167
|
-
let fd;
|
|
168
|
-
const getFd = () => {
|
|
169
|
-
fd ??= (0, fs.openSync)(options.path, flags);
|
|
170
|
-
return fd;
|
|
171
|
-
};
|
|
172
|
-
const syncWrite = (payload) => {
|
|
173
|
-
if (typeof payload === "string") (0, fs.writeSync)(getFd(), payload);
|
|
174
|
-
else (0, fs.writeSync)(getFd(), payload);
|
|
175
|
-
};
|
|
176
|
-
if (options.sync) {
|
|
177
|
-
let closed = false;
|
|
178
|
-
const releaseSync = () => {
|
|
179
|
-
if (fd !== void 0) {
|
|
180
|
-
(0, fs.closeSync)(fd);
|
|
181
|
-
fd = void 0;
|
|
182
|
-
}
|
|
183
|
-
};
|
|
184
|
-
return {
|
|
185
|
-
write(payload) {
|
|
186
|
-
if (closed) return;
|
|
187
|
-
syncWrite(payload);
|
|
188
|
-
},
|
|
189
|
-
flush() {
|
|
190
|
-
return Promise.resolve();
|
|
191
|
-
},
|
|
192
|
-
flushSync() {},
|
|
193
|
-
close() {
|
|
194
|
-
releaseSync();
|
|
195
|
-
closed = true;
|
|
196
|
-
return Promise.resolve();
|
|
197
|
-
},
|
|
198
|
-
closeSync() {
|
|
199
|
-
releaseSync();
|
|
200
|
-
closed = true;
|
|
201
|
-
},
|
|
202
|
-
releaseSync
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
const stream = (0, fs.createWriteStream)(options.path, { flags });
|
|
206
|
-
const destination = createNodeStreamDestination({
|
|
207
|
-
name: options.name,
|
|
208
|
-
stream,
|
|
209
|
-
minLength: options.minLength,
|
|
210
|
-
syncWrite
|
|
211
|
-
});
|
|
212
|
-
const releaseSync = () => {
|
|
213
|
-
if (fd !== void 0) {
|
|
214
|
-
(0, fs.closeSync)(fd);
|
|
215
|
-
fd = void 0;
|
|
216
|
-
}
|
|
217
|
-
};
|
|
218
|
-
return {
|
|
219
|
-
...destination,
|
|
220
|
-
stream,
|
|
221
|
-
close() {
|
|
222
|
-
return destination.close().finally(releaseSync);
|
|
223
|
-
},
|
|
224
|
-
closeSync() {
|
|
225
|
-
destination.closeSync();
|
|
226
|
-
releaseSync();
|
|
227
|
-
},
|
|
228
|
-
releaseSync
|
|
229
|
-
};
|
|
230
|
-
}
|
|
231
|
-
//#endregion
|
|
232
4
|
//#region src/file-transport.ts
|
|
233
5
|
function fileTransport(options) {
|
|
234
|
-
const codec = options.codec ?? (0, _loggerjs_core.
|
|
235
|
-
const destination = createNodeFileDestination({
|
|
6
|
+
const codec = options.codec ?? (0, _loggerjs_core.ndjsonEncoder)();
|
|
7
|
+
const destination = require_node_destination.createNodeFileDestination({
|
|
236
8
|
name: options.name ?? "file",
|
|
237
9
|
path: options.path,
|
|
238
10
|
flags: options.flags,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-transport.cjs","names":[],"sources":["../src/node-destination.ts","../src/file-transport.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 const onStreamError = (error: Error) => {\n recordError(error, \"stream-error\");\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) 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 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 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 const getFd = () => {\n fd ??= openSync(options.path, flags);\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 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","import {\n ndjsonCodec,\n toLevelValue,\n type Codec,\n type LogEvent,\n type LoggerLevel,\n type Transport,\n} from \"@loggerjs/core\";\nimport type { WriteStream } from \"fs\";\nimport { createNodeFileDestination } from \"./node-destination\";\n\nexport interface FileTransportOptions {\n path: string;\n name?: string;\n codec?: Codec<string | Uint8Array>;\n minLevel?: LoggerLevel;\n flags?: string;\n append?: boolean;\n mkdir?: boolean;\n sync?: boolean;\n minLength?: number;\n}\n\nexport interface FileTransport extends Transport {\n stream?: WriteStream;\n flushSync: () => void;\n}\n\nexport function fileTransport(options: FileTransportOptions): FileTransport {\n const codec = options.codec ?? ndjsonCodec();\n const destination = createNodeFileDestination({\n name: options.name ?? \"file\",\n path: options.path,\n flags: options.flags,\n append: options.append,\n mkdir: options.mkdir,\n sync: options.sync,\n minLength: options.minLength,\n });\n\n return {\n name: options.name ?? \"file\",\n minLevel: options.minLevel,\n stream: destination.stream,\n log(event: LogEvent, context) {\n if (options.minLevel !== undefined && event.level < toLevelValue(options.minLevel)) return;\n destination.write(codec.encode(event), context);\n },\n flush: destination.flush,\n flushSync: destination.flushSync,\n close: destination.close,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"file-transport.cjs","names":["createNodeFileDestination"],"sources":["../src/file-transport.ts"],"sourcesContent":["import {\n ndjsonEncoder,\n toLevelValue,\n type Codec,\n type LogEvent,\n type LoggerLevel,\n type Transport,\n} from \"@loggerjs/core\";\nimport type { WriteStream } from \"fs\";\nimport { createNodeFileDestination } from \"./node-destination\";\n\nexport interface FileTransportOptions {\n path: string;\n name?: string;\n codec?: Codec<string | Uint8Array>;\n minLevel?: LoggerLevel;\n flags?: string;\n append?: boolean;\n mkdir?: boolean;\n sync?: boolean;\n minLength?: number;\n}\n\nexport interface FileTransport extends Transport {\n stream?: WriteStream;\n flushSync: () => void;\n}\n\nexport function fileTransport(options: FileTransportOptions): FileTransport {\n const codec = options.codec ?? ndjsonEncoder();\n const destination = createNodeFileDestination({\n name: options.name ?? \"file\",\n path: options.path,\n flags: options.flags,\n append: options.append,\n mkdir: options.mkdir,\n sync: options.sync,\n minLength: options.minLength,\n });\n\n return {\n name: options.name ?? \"file\",\n minLevel: options.minLevel,\n stream: destination.stream,\n log(event: LogEvent, context) {\n if (options.minLevel !== undefined && event.level < toLevelValue(options.minLevel)) return;\n destination.write(codec.encode(event), context);\n },\n flush: destination.flush,\n flushSync: destination.flushSync,\n close: destination.close,\n };\n}\n"],"mappings":";;;;AA4BA,SAAgB,cAAc,SAA8C;CAC1E,MAAM,QAAQ,QAAQ,UAAA,GAAA,eAAA,cAAA,CAAuB;CAC7C,MAAM,cAAcA,yBAAAA,0BAA0B;EAC5C,MAAM,QAAQ,QAAQ;EACtB,MAAM,QAAQ;EACd,OAAO,QAAQ;EACf,QAAQ,QAAQ;EAChB,OAAO,QAAQ;EACf,MAAM,QAAQ;EACd,WAAW,QAAQ;CACrB,CAAC;CAED,OAAO;EACL,MAAM,QAAQ,QAAQ;EACtB,UAAU,QAAQ;EAClB,QAAQ,YAAY;EACpB,IAAI,OAAiB,SAAS;GAC5B,IAAI,QAAQ,aAAa,KAAA,KAAa,MAAM,SAAA,GAAA,eAAA,aAAA,CAAqB,QAAQ,QAAQ,GAAG;GACpF,YAAY,MAAM,MAAM,OAAO,KAAK,GAAG,OAAO;EAChD;EACA,OAAO,YAAY;EACnB,WAAW,YAAY;EACvB,OAAO,YAAY;CACrB;AACF"}
|
package/dist/file-transport.js
CHANGED
|
@@ -1,236 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { dirname } from "path";
|
|
4
|
-
//#region src/node-destination.ts
|
|
5
|
-
const encoder = new TextEncoder();
|
|
6
|
-
const normalizeError = (error) => error instanceof Error ? error : new Error(String(error));
|
|
7
|
-
function byteLength(payload) {
|
|
8
|
-
return typeof payload === "string" ? encoder.encode(payload).byteLength : payload.byteLength;
|
|
9
|
-
}
|
|
10
|
-
function coalescePayloads(payloads) {
|
|
11
|
-
if (payloads.every((payload) => typeof payload === "string")) return payloads.join("");
|
|
12
|
-
const buffers = payloads.map((payload) => typeof payload === "string" ? Buffer.from(payload) : Buffer.from(payload));
|
|
13
|
-
return Buffer.concat(buffers);
|
|
14
|
-
}
|
|
15
|
-
function isEpipe(error) {
|
|
16
|
-
return Boolean(error) && typeof error === "object" && error.code === "EPIPE";
|
|
17
|
-
}
|
|
18
|
-
function normalizeMinLength(value) {
|
|
19
|
-
if (value === void 0 || !Number.isFinite(value) || value <= 0) return 0;
|
|
20
|
-
return Math.floor(value);
|
|
21
|
-
}
|
|
22
|
-
function createNodeStreamDestination(options) {
|
|
23
|
-
const minLength = normalizeMinLength(options.minLength);
|
|
24
|
-
const ignoreEpipe = options.ignoreEpipe ?? false;
|
|
25
|
-
const waiters = [];
|
|
26
|
-
const buffer = [];
|
|
27
|
-
const pendingPayloads = [];
|
|
28
|
-
let bufferedBytes = 0;
|
|
29
|
-
let pendingWrites = 0;
|
|
30
|
-
let pendingDrains = 0;
|
|
31
|
-
let lastError;
|
|
32
|
-
let lastContext;
|
|
33
|
-
let closed = false;
|
|
34
|
-
const reportInternalError = (error, operation) => {
|
|
35
|
-
if (ignoreEpipe && isEpipe(error)) return;
|
|
36
|
-
lastContext?.reportInternalError(error, {
|
|
37
|
-
phase: "transport",
|
|
38
|
-
transport: options.name,
|
|
39
|
-
operation
|
|
40
|
-
});
|
|
41
|
-
};
|
|
42
|
-
const settleWaitersIfIdle = () => {
|
|
43
|
-
if (pendingWrites + pendingDrains > 0) return;
|
|
44
|
-
if (waiters.length === 0) return;
|
|
45
|
-
const error = lastError;
|
|
46
|
-
lastError = void 0;
|
|
47
|
-
for (const waiter of waiters.splice(0)) if (error) waiter.reject(error);
|
|
48
|
-
else waiter.resolve();
|
|
49
|
-
};
|
|
50
|
-
const recordError = (error, operation) => {
|
|
51
|
-
if (ignoreEpipe && isEpipe(error)) {
|
|
52
|
-
closed = true;
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
lastError = normalizeError(error);
|
|
56
|
-
reportInternalError(lastError, operation);
|
|
57
|
-
};
|
|
58
|
-
const onStreamError = (error) => {
|
|
59
|
-
recordError(error, "stream-error");
|
|
60
|
-
settleWaitersIfIdle();
|
|
61
|
-
};
|
|
62
|
-
const offError = () => options.stream.off?.("error", onStreamError);
|
|
63
|
-
options.stream.on?.("error", onStreamError);
|
|
64
|
-
const waitForDrain = () => {
|
|
65
|
-
if (!options.stream.once) return;
|
|
66
|
-
pendingDrains += 1;
|
|
67
|
-
options.stream.once("drain", () => {
|
|
68
|
-
pendingDrains -= 1;
|
|
69
|
-
settleWaitersIfIdle();
|
|
70
|
-
});
|
|
71
|
-
};
|
|
72
|
-
const removePending = (payload) => {
|
|
73
|
-
const index = pendingPayloads.indexOf(payload);
|
|
74
|
-
if (index >= 0) pendingPayloads.splice(index, 1);
|
|
75
|
-
};
|
|
76
|
-
const writeNow = (payload) => {
|
|
77
|
-
if (closed) return;
|
|
78
|
-
pendingPayloads.push(payload);
|
|
79
|
-
pendingWrites += 1;
|
|
80
|
-
try {
|
|
81
|
-
if (options.stream.write(payload, (error) => {
|
|
82
|
-
removePending(payload);
|
|
83
|
-
pendingWrites -= 1;
|
|
84
|
-
if (error) recordError(error, options.reportOperation ?? "write");
|
|
85
|
-
settleWaitersIfIdle();
|
|
86
|
-
}) === false) waitForDrain();
|
|
87
|
-
} catch (error) {
|
|
88
|
-
removePending(payload);
|
|
89
|
-
pendingWrites -= 1;
|
|
90
|
-
recordError(error, options.reportOperation ?? "write");
|
|
91
|
-
settleWaitersIfIdle();
|
|
92
|
-
}
|
|
93
|
-
};
|
|
94
|
-
const flushBuffered = () => {
|
|
95
|
-
if (buffer.length === 0) return;
|
|
96
|
-
const payload = coalescePayloads(buffer.splice(0));
|
|
97
|
-
bufferedBytes = 0;
|
|
98
|
-
writeNow(payload);
|
|
99
|
-
};
|
|
100
|
-
const destination = {
|
|
101
|
-
write(payload, context) {
|
|
102
|
-
if (closed) return;
|
|
103
|
-
lastContext = context;
|
|
104
|
-
if (minLength > 0) {
|
|
105
|
-
buffer.push(payload);
|
|
106
|
-
bufferedBytes += byteLength(payload);
|
|
107
|
-
if (bufferedBytes >= minLength) flushBuffered();
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
writeNow(payload);
|
|
111
|
-
},
|
|
112
|
-
flush() {
|
|
113
|
-
flushBuffered();
|
|
114
|
-
if (pendingWrites + pendingDrains === 0) {
|
|
115
|
-
const error = lastError;
|
|
116
|
-
lastError = void 0;
|
|
117
|
-
if (error) return Promise.reject(error);
|
|
118
|
-
return Promise.resolve();
|
|
119
|
-
}
|
|
120
|
-
return new Promise((resolve, reject) => {
|
|
121
|
-
waiters.push({
|
|
122
|
-
resolve,
|
|
123
|
-
reject
|
|
124
|
-
});
|
|
125
|
-
});
|
|
126
|
-
},
|
|
127
|
-
flushSync() {
|
|
128
|
-
if (!options.syncWrite) {
|
|
129
|
-
flushBuffered();
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
for (const payload of buffer.splice(0)) options.syncWrite(payload);
|
|
133
|
-
bufferedBytes = 0;
|
|
134
|
-
for (const payload of pendingPayloads.splice(0)) options.syncWrite(payload);
|
|
135
|
-
},
|
|
136
|
-
close() {
|
|
137
|
-
return destination.flush().then(() => new Promise((resolve, reject) => {
|
|
138
|
-
if (!options.stream.end) {
|
|
139
|
-
closed = true;
|
|
140
|
-
offError();
|
|
141
|
-
resolve();
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
options.stream.end((error) => {
|
|
145
|
-
closed = true;
|
|
146
|
-
offError();
|
|
147
|
-
if (error && !(ignoreEpipe && isEpipe(error))) reject(error);
|
|
148
|
-
else resolve();
|
|
149
|
-
});
|
|
150
|
-
}), (error) => {
|
|
151
|
-
offError();
|
|
152
|
-
return Promise.reject(error);
|
|
153
|
-
});
|
|
154
|
-
},
|
|
155
|
-
closeSync() {
|
|
156
|
-
destination.flushSync();
|
|
157
|
-
closed = true;
|
|
158
|
-
offError();
|
|
159
|
-
}
|
|
160
|
-
};
|
|
161
|
-
return destination;
|
|
162
|
-
}
|
|
163
|
-
function createNodeFileDestination(options) {
|
|
164
|
-
const flags = options.flags ?? (options.append === false ? "w" : "a");
|
|
165
|
-
if (options.mkdir) mkdirSync(dirname(options.path), { recursive: true });
|
|
166
|
-
let fd;
|
|
167
|
-
const getFd = () => {
|
|
168
|
-
fd ??= openSync(options.path, flags);
|
|
169
|
-
return fd;
|
|
170
|
-
};
|
|
171
|
-
const syncWrite = (payload) => {
|
|
172
|
-
if (typeof payload === "string") writeSync(getFd(), payload);
|
|
173
|
-
else writeSync(getFd(), payload);
|
|
174
|
-
};
|
|
175
|
-
if (options.sync) {
|
|
176
|
-
let closed = false;
|
|
177
|
-
const releaseSync = () => {
|
|
178
|
-
if (fd !== void 0) {
|
|
179
|
-
closeSync(fd);
|
|
180
|
-
fd = void 0;
|
|
181
|
-
}
|
|
182
|
-
};
|
|
183
|
-
return {
|
|
184
|
-
write(payload) {
|
|
185
|
-
if (closed) return;
|
|
186
|
-
syncWrite(payload);
|
|
187
|
-
},
|
|
188
|
-
flush() {
|
|
189
|
-
return Promise.resolve();
|
|
190
|
-
},
|
|
191
|
-
flushSync() {},
|
|
192
|
-
close() {
|
|
193
|
-
releaseSync();
|
|
194
|
-
closed = true;
|
|
195
|
-
return Promise.resolve();
|
|
196
|
-
},
|
|
197
|
-
closeSync() {
|
|
198
|
-
releaseSync();
|
|
199
|
-
closed = true;
|
|
200
|
-
},
|
|
201
|
-
releaseSync
|
|
202
|
-
};
|
|
203
|
-
}
|
|
204
|
-
const stream = createWriteStream(options.path, { flags });
|
|
205
|
-
const destination = createNodeStreamDestination({
|
|
206
|
-
name: options.name,
|
|
207
|
-
stream,
|
|
208
|
-
minLength: options.minLength,
|
|
209
|
-
syncWrite
|
|
210
|
-
});
|
|
211
|
-
const releaseSync = () => {
|
|
212
|
-
if (fd !== void 0) {
|
|
213
|
-
closeSync(fd);
|
|
214
|
-
fd = void 0;
|
|
215
|
-
}
|
|
216
|
-
};
|
|
217
|
-
return {
|
|
218
|
-
...destination,
|
|
219
|
-
stream,
|
|
220
|
-
close() {
|
|
221
|
-
return destination.close().finally(releaseSync);
|
|
222
|
-
},
|
|
223
|
-
closeSync() {
|
|
224
|
-
destination.closeSync();
|
|
225
|
-
releaseSync();
|
|
226
|
-
},
|
|
227
|
-
releaseSync
|
|
228
|
-
};
|
|
229
|
-
}
|
|
230
|
-
//#endregion
|
|
1
|
+
import { t as createNodeFileDestination } from "./chunks/node-destination-YnpYbctz.js";
|
|
2
|
+
import { ndjsonEncoder, toLevelValue } from "@loggerjs/core";
|
|
231
3
|
//#region src/file-transport.ts
|
|
232
4
|
function fileTransport(options) {
|
|
233
|
-
const codec = options.codec ??
|
|
5
|
+
const codec = options.codec ?? ndjsonEncoder();
|
|
234
6
|
const destination = createNodeFileDestination({
|
|
235
7
|
name: options.name ?? "file",
|
|
236
8
|
path: options.path,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-transport.js","names":[],"sources":["../src/node-destination.ts","../src/file-transport.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 const onStreamError = (error: Error) => {\n recordError(error, \"stream-error\");\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) 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 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 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 const getFd = () => {\n fd ??= openSync(options.path, flags);\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 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","import {\n ndjsonCodec,\n toLevelValue,\n type Codec,\n type LogEvent,\n type LoggerLevel,\n type Transport,\n} from \"@loggerjs/core\";\nimport type { WriteStream } from \"fs\";\nimport { createNodeFileDestination } from \"./node-destination\";\n\nexport interface FileTransportOptions {\n path: string;\n name?: string;\n codec?: Codec<string | Uint8Array>;\n minLevel?: LoggerLevel;\n flags?: string;\n append?: boolean;\n mkdir?: boolean;\n sync?: boolean;\n minLength?: number;\n}\n\nexport interface FileTransport extends Transport {\n stream?: WriteStream;\n flushSync: () => void;\n}\n\nexport function fileTransport(options: FileTransportOptions): FileTransport {\n const codec = options.codec ?? ndjsonCodec();\n const destination = createNodeFileDestination({\n name: options.name ?? \"file\",\n path: options.path,\n flags: options.flags,\n append: options.append,\n mkdir: options.mkdir,\n sync: options.sync,\n minLength: options.minLength,\n });\n\n return {\n name: options.name ?? \"file\",\n minLevel: options.minLevel,\n stream: destination.stream,\n log(event: LogEvent, context) {\n if (options.minLevel !== undefined && event.level < toLevelValue(options.minLevel)) return;\n destination.write(codec.encode(event), context);\n },\n flush: destination.flush,\n flushSync: destination.flushSync,\n close: destination.close,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"file-transport.js","names":[],"sources":["../src/file-transport.ts"],"sourcesContent":["import {\n ndjsonEncoder,\n toLevelValue,\n type Codec,\n type LogEvent,\n type LoggerLevel,\n type Transport,\n} from \"@loggerjs/core\";\nimport type { WriteStream } from \"fs\";\nimport { createNodeFileDestination } from \"./node-destination\";\n\nexport interface FileTransportOptions {\n path: string;\n name?: string;\n codec?: Codec<string | Uint8Array>;\n minLevel?: LoggerLevel;\n flags?: string;\n append?: boolean;\n mkdir?: boolean;\n sync?: boolean;\n minLength?: number;\n}\n\nexport interface FileTransport extends Transport {\n stream?: WriteStream;\n flushSync: () => void;\n}\n\nexport function fileTransport(options: FileTransportOptions): FileTransport {\n const codec = options.codec ?? ndjsonEncoder();\n const destination = createNodeFileDestination({\n name: options.name ?? \"file\",\n path: options.path,\n flags: options.flags,\n append: options.append,\n mkdir: options.mkdir,\n sync: options.sync,\n minLength: options.minLength,\n });\n\n return {\n name: options.name ?? \"file\",\n minLevel: options.minLevel,\n stream: destination.stream,\n log(event: LogEvent, context) {\n if (options.minLevel !== undefined && event.level < toLevelValue(options.minLevel)) return;\n destination.write(codec.encode(event), context);\n },\n flush: destination.flush,\n flushSync: destination.flushSync,\n close: destination.close,\n };\n}\n"],"mappings":";;;AA4BA,SAAgB,cAAc,SAA8C;CAC1E,MAAM,QAAQ,QAAQ,SAAS,cAAc;CAC7C,MAAM,cAAc,0BAA0B;EAC5C,MAAM,QAAQ,QAAQ;EACtB,MAAM,QAAQ;EACd,OAAO,QAAQ;EACf,QAAQ,QAAQ;EAChB,OAAO,QAAQ;EACf,MAAM,QAAQ;EACd,WAAW,QAAQ;CACrB,CAAC;CAED,OAAO;EACL,MAAM,QAAQ,QAAQ;EACtB,UAAU,QAAQ;EAClB,QAAQ,YAAY;EACpB,IAAI,OAAiB,SAAS;GAC5B,IAAI,QAAQ,aAAa,KAAA,KAAa,MAAM,QAAQ,aAAa,QAAQ,QAAQ,GAAG;GACpF,YAAY,MAAM,MAAM,OAAO,KAAK,GAAG,OAAO;EAChD;EACA,OAAO,YAAY;EACnB,WAAW,YAAY;EACvB,OAAO,YAAY;CACrB;AACF"}
|
package/dist/http-transport.cjs
CHANGED
|
@@ -1,19 +1,38 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
let _loggerjs_core = require("@loggerjs/core");
|
|
3
|
+
let _loggerjs_core_payload_transforms = require("@loggerjs/core/payload-transforms");
|
|
3
4
|
//#region src/http-transport.ts
|
|
4
5
|
function payloadToBody(payload) {
|
|
5
6
|
if (typeof payload === "string") return payload;
|
|
6
7
|
return Uint8Array.from(payload);
|
|
7
8
|
}
|
|
9
|
+
function idempotencyKeyHeaders(header) {
|
|
10
|
+
if (!header) return () => void 0;
|
|
11
|
+
new Headers().append(header, "");
|
|
12
|
+
const prefix = Array.from(crypto.getRandomValues(new Uint32Array(2)), (word) => word.toString(36)).join("");
|
|
13
|
+
const keys = /* @__PURE__ */ new WeakMap();
|
|
14
|
+
let next = 0;
|
|
15
|
+
return (events) => {
|
|
16
|
+
const last = events[events.length - 1];
|
|
17
|
+
let key = keys.get(last);
|
|
18
|
+
if (key === void 0) {
|
|
19
|
+
key = `${prefix}-${(next++).toString(36)}`;
|
|
20
|
+
keys.set(last, key);
|
|
21
|
+
}
|
|
22
|
+
return { [header]: key };
|
|
23
|
+
};
|
|
24
|
+
}
|
|
8
25
|
function nodeHttpTransport(options) {
|
|
9
|
-
const codec = options.codec ?? (0, _loggerjs_core.
|
|
26
|
+
const codec = options.codec ?? (0, _loggerjs_core.safeJsonEncoder)();
|
|
10
27
|
const fetchFn = options.fetchFn ?? globalThis.fetch?.bind(globalThis);
|
|
28
|
+
const keyHeaders = idempotencyKeyHeaders(options.idempotencyKeyHeader);
|
|
29
|
+
const timeoutMs = options.timeoutMs ?? 1e4;
|
|
11
30
|
return (0, _loggerjs_core.batchTransport)({
|
|
12
31
|
name: options.name ?? "node-http-inner",
|
|
13
32
|
minLevel: options.minLevel,
|
|
14
33
|
async logBatch(events) {
|
|
15
34
|
if (!fetchFn) throw new Error("fetch is not available. Use Node.js 18+ or pass fetchFn.");
|
|
16
|
-
const transformed = await (0,
|
|
35
|
+
const transformed = await (0, _loggerjs_core_payload_transforms.applyPayloadTransforms)(codec.encode(events), {
|
|
17
36
|
contentType: codec.contentType,
|
|
18
37
|
events,
|
|
19
38
|
transport: options.name ?? "node-http"
|
|
@@ -23,11 +42,13 @@ function nodeHttpTransport(options) {
|
|
|
23
42
|
headers: {
|
|
24
43
|
"content-type": transformed.contentType,
|
|
25
44
|
...transformed.headers,
|
|
45
|
+
...keyHeaders(events),
|
|
26
46
|
...options.headers
|
|
27
47
|
},
|
|
28
|
-
body: payloadToBody(transformed.payload)
|
|
48
|
+
body: payloadToBody(transformed.payload),
|
|
49
|
+
signal: timeoutMs > 0 ? AbortSignal.timeout(timeoutMs) : void 0
|
|
29
50
|
});
|
|
30
|
-
if (!response.ok) throw
|
|
51
|
+
if (!response.ok) throw (0, _loggerjs_core.httpStatusError)("nodeHttpTransport", response);
|
|
31
52
|
}
|
|
32
53
|
}, {
|
|
33
54
|
name: options.name ?? "node-http",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-transport.cjs","names":[],"sources":["../src/http-transport.ts"],"sourcesContent":["import {\n
|
|
1
|
+
{"version":3,"file":"http-transport.cjs","names":[],"sources":["../src/http-transport.ts"],"sourcesContent":["import {\n httpStatusError,\n batchTransport,\n safeJsonEncoder,\n type BatchTransportOptions,\n type Codec,\n type EncodedPayload,\n type LogEvent,\n type LoggerLevel,\n type PayloadTransform,\n type Transport,\n} from \"@loggerjs/core\";\nimport { applyPayloadTransforms } from \"@loggerjs/core/payload-transforms\";\n\nexport interface NodeHttpTransportOptions extends BatchTransportOptions {\n url: string;\n name?: string;\n method?: \"POST\" | \"PUT\";\n headers?: Record<string, string>;\n codec?: Codec<string | Uint8Array>;\n minLevel?: LoggerLevel;\n fetchFn?: typeof fetch;\n transformPayload?: PayloadTransform | readonly PayloadTransform[];\n /**\n * Abort a delivery attempt after this many milliseconds so a collector that\n * accepts the connection but never answers cannot stall flush() and close().\n * A timed-out attempt fails like any other and follows the retry settings.\n * Set to 0 to disable. Defaults to 10000.\n */\n timeoutMs?: number;\n /**\n * Header that carries an idempotency key for each request, for example\n * \"Idempotency-Key\". Every resend of a batch repeats its key, so the\n * collector can drop the duplicate that a retry after a timeout may cause.\n * Keys start with a random per-transport prefix, so senders never share\n * one. Off by default.\n */\n idempotencyKeyHeader?: string;\n}\n\nfunction payloadToBody(payload: EncodedPayload): BodyInit {\n if (typeof payload === \"string\") return payload;\n return Uint8Array.from(payload);\n}\n\n// Keys are a random per-transport prefix, which keeps senders apart, and a\n// batch number. A batch's key is stored under its last event: retries and\n// resends of a batch handed back to the queue keep that event, because a full\n// queue only drops events from the front. Mirrors @loggerjs/browser.\nfunction idempotencyKeyHeaders(\n header: string | undefined,\n): (events: readonly LogEvent[]) => Record<string, string> | undefined {\n if (!header) return () => undefined;\n // Throws a TypeError for an invalid header name now instead of on every send.\n new Headers().append(header, \"\");\n const prefix = Array.from(crypto.getRandomValues(new Uint32Array(2)), (word) =>\n word.toString(36),\n ).join(\"\");\n const keys = new WeakMap<LogEvent, string>();\n let next = 0;\n return (events) => {\n const last = events[events.length - 1]!;\n let key = keys.get(last);\n if (key === undefined) {\n key = `${prefix}-${(next++).toString(36)}`;\n keys.set(last, key);\n }\n return { [header]: key };\n };\n}\n\nexport function nodeHttpTransport(options: NodeHttpTransportOptions): Transport {\n const codec = options.codec ?? safeJsonEncoder();\n const fetchFn = options.fetchFn ?? globalThis.fetch?.bind(globalThis);\n const keyHeaders = idempotencyKeyHeaders(options.idempotencyKeyHeader);\n const timeoutMs = options.timeoutMs ?? 10_000;\n const inner: Transport = {\n name: options.name ?? \"node-http-inner\",\n minLevel: options.minLevel,\n async logBatch(events: LogEvent[]) {\n if (!fetchFn) throw new Error(\"fetch is not available. Use Node.js 18+ or pass fetchFn.\");\n const encoded = codec.encode(events);\n const transformed = await applyPayloadTransforms(\n encoded,\n {\n contentType: codec.contentType,\n events,\n transport: options.name ?? \"node-http\",\n },\n options.transformPayload,\n );\n const response = await fetchFn(options.url, {\n method: options.method ?? \"POST\",\n headers: {\n \"content-type\": transformed.contentType,\n ...transformed.headers,\n ...keyHeaders(events),\n ...options.headers,\n },\n body: payloadToBody(transformed.payload),\n signal: timeoutMs > 0 ? AbortSignal.timeout(timeoutMs) : undefined,\n });\n if (!response.ok) throw httpStatusError(\"nodeHttpTransport\", response);\n },\n };\n return batchTransport(inner, {\n name: options.name ?? \"node-http\",\n maxRecords: options.maxRecords,\n maxBatchSize: options.maxBatchSize,\n maxBytes: options.maxBytes,\n maxWaitMs: options.maxWaitMs,\n flushIntervalMs: options.flushIntervalMs,\n concurrency: options.concurrency,\n maxQueueSize: options.maxQueueSize,\n dropPolicy: options.dropPolicy,\n estimateEventBytes: options.estimateEventBytes,\n maxRetries: options.maxRetries,\n retryBaseDelayMs: options.retryBaseDelayMs,\n retryMaxDelayMs: options.retryMaxDelayMs,\n random: options.random,\n circuitBreakerFailureThreshold: options.circuitBreakerFailureThreshold,\n circuitBreakerResetMs: options.circuitBreakerResetMs,\n onDrop: options.onDrop,\n });\n}\n"],"mappings":";;;;AAwCA,SAAS,cAAc,SAAmC;CACxD,IAAI,OAAO,YAAY,UAAU,OAAO;CACxC,OAAO,WAAW,KAAK,OAAO;AAChC;AAMA,SAAS,sBACP,QACqE;CACrE,IAAI,CAAC,QAAQ,aAAa,KAAA;CAE1B,IAAI,QAAQ,CAAC,CAAC,OAAO,QAAQ,EAAE;CAC/B,MAAM,SAAS,MAAM,KAAK,OAAO,gBAAgB,IAAI,YAAY,CAAC,CAAC,IAAI,SACrE,KAAK,SAAS,EAAE,CAClB,CAAC,CAAC,KAAK,EAAE;CACT,MAAM,uBAAO,IAAI,QAA0B;CAC3C,IAAI,OAAO;CACX,QAAQ,WAAW;EACjB,MAAM,OAAO,OAAO,OAAO,SAAS;EACpC,IAAI,MAAM,KAAK,IAAI,IAAI;EACvB,IAAI,QAAQ,KAAA,GAAW;GACrB,MAAM,GAAG,OAAO,IAAI,OAAA,CAAQ,SAAS,EAAE;GACvC,KAAK,IAAI,MAAM,GAAG;EACpB;EACA,OAAO,GAAG,SAAS,IAAI;CACzB;AACF;AAEA,SAAgB,kBAAkB,SAA8C;CAC9E,MAAM,QAAQ,QAAQ,UAAA,GAAA,eAAA,gBAAA,CAAyB;CAC/C,MAAM,UAAU,QAAQ,WAAW,WAAW,OAAO,KAAK,UAAU;CACpE,MAAM,aAAa,sBAAsB,QAAQ,oBAAoB;CACrE,MAAM,YAAY,QAAQ,aAAa;CA8BvC,QAAA,GAAA,eAAA,eAAA,CAAsB;EA5BpB,MAAM,QAAQ,QAAQ;EACtB,UAAU,QAAQ;EAClB,MAAM,SAAS,QAAoB;GACjC,IAAI,CAAC,SAAS,MAAM,IAAI,MAAM,0DAA0D;GAExF,MAAM,cAAc,OAAA,GAAA,kCAAA,uBAAA,CADJ,MAAM,OAAO,MAErB,GACN;IACE,aAAa,MAAM;IACnB;IACA,WAAW,QAAQ,QAAQ;GAC7B,GACA,QAAQ,gBACV;GACA,MAAM,WAAW,MAAM,QAAQ,QAAQ,KAAK;IAC1C,QAAQ,QAAQ,UAAU;IAC1B,SAAS;KACP,gBAAgB,YAAY;KAC5B,GAAG,YAAY;KACf,GAAG,WAAW,MAAM;KACpB,GAAG,QAAQ;IACb;IACA,MAAM,cAAc,YAAY,OAAO;IACvC,QAAQ,YAAY,IAAI,YAAY,QAAQ,SAAS,IAAI,KAAA;GAC3D,CAAC;GACD,IAAI,CAAC,SAAS,IAAI,OAAA,GAAA,eAAA,gBAAA,CAAsB,qBAAqB,QAAQ;EACvE;CAEwB,GAAG;EAC3B,MAAM,QAAQ,QAAQ;EACtB,YAAY,QAAQ;EACpB,cAAc,QAAQ;EACtB,UAAU,QAAQ;EAClB,WAAW,QAAQ;EACnB,iBAAiB,QAAQ;EACzB,aAAa,QAAQ;EACrB,cAAc,QAAQ;EACtB,YAAY,QAAQ;EACpB,oBAAoB,QAAQ;EAC5B,YAAY,QAAQ;EACpB,kBAAkB,QAAQ;EAC1B,iBAAiB,QAAQ;EACzB,QAAQ,QAAQ;EAChB,gCAAgC,QAAQ;EACxC,uBAAuB,QAAQ;EAC/B,QAAQ,QAAQ;CAClB,CAAC;AACH"}
|
package/dist/http-transport.d.ts
CHANGED
|
@@ -8,6 +8,21 @@ export interface NodeHttpTransportOptions extends BatchTransportOptions {
|
|
|
8
8
|
minLevel?: LoggerLevel;
|
|
9
9
|
fetchFn?: typeof fetch;
|
|
10
10
|
transformPayload?: PayloadTransform | readonly PayloadTransform[];
|
|
11
|
+
/**
|
|
12
|
+
* Abort a delivery attempt after this many milliseconds so a collector that
|
|
13
|
+
* accepts the connection but never answers cannot stall flush() and close().
|
|
14
|
+
* A timed-out attempt fails like any other and follows the retry settings.
|
|
15
|
+
* Set to 0 to disable. Defaults to 10000.
|
|
16
|
+
*/
|
|
17
|
+
timeoutMs?: number;
|
|
18
|
+
/**
|
|
19
|
+
* Header that carries an idempotency key for each request, for example
|
|
20
|
+
* "Idempotency-Key". Every resend of a batch repeats its key, so the
|
|
21
|
+
* collector can drop the duplicate that a retry after a timeout may cause.
|
|
22
|
+
* Keys start with a random per-transport prefix, so senders never share
|
|
23
|
+
* one. Off by default.
|
|
24
|
+
*/
|
|
25
|
+
idempotencyKeyHeader?: string;
|
|
11
26
|
}
|
|
12
27
|
export declare function nodeHttpTransport(options: NodeHttpTransportOptions): Transport;
|
|
13
28
|
//# sourceMappingURL=http-transport.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-transport.d.ts","sourceRoot":"","sources":["../src/http-transport.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,qBAAqB,EAC1B,KAAK,KAAK,EAGV,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACrB,KAAK,SAAS,EACf,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"http-transport.d.ts","sourceRoot":"","sources":["../src/http-transport.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,qBAAqB,EAC1B,KAAK,KAAK,EAGV,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACrB,KAAK,SAAS,EACf,MAAM,gBAAgB,CAAC;AAGxB,MAAM,WAAW,wBAAyB,SAAQ,qBAAqB;IACrE,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,KAAK,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,UAAU,CAAC,CAAC;IACnC,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;IACvB,gBAAgB,CAAC,EAAE,gBAAgB,GAAG,SAAS,gBAAgB,EAAE,CAAC;IAClE;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;OAMG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAiCD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,SAAS,CAqD9E"}
|