@loggerjs/node 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,6 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  let _loggerjs_core = require("@loggerjs/core");
3
3
  let fs = require("fs");
4
+ let path = require("path");
4
5
  let node_zlib = require("node:zlib");
5
6
  let dgram = require("dgram");
6
7
  let net = require("net");
@@ -8,66 +9,116 @@ let os = require("os");
8
9
  let node_worker_threads = require("node:worker_threads");
9
10
  let node_async_hooks = require("node:async_hooks");
10
11
  let node_module = require("node:module");
11
- //#region src/stdout-transport.ts
12
+ //#region src/node-destination.ts
13
+ const encoder = new TextEncoder();
12
14
  const normalizeError = (error) => error instanceof Error ? error : new Error(String(error));
13
- function stdoutTransport(options = {}) {
14
- const codec = options.codec ?? (0, _loggerjs_core.ndjsonCodec)();
15
- const stream = options.stream ?? process.stdout;
16
- const transportName = options.name ?? "stdout";
15
+ function byteLength(payload) {
16
+ return typeof payload === "string" ? encoder.encode(payload).byteLength : payload.byteLength;
17
+ }
18
+ function coalescePayloads(payloads) {
19
+ if (payloads.every((payload) => typeof payload === "string")) return payloads.join("");
20
+ const buffers = payloads.map((payload) => typeof payload === "string" ? Buffer.from(payload) : Buffer.from(payload));
21
+ return Buffer.concat(buffers);
22
+ }
23
+ function isEpipe(error) {
24
+ return Boolean(error) && typeof error === "object" && error.code === "EPIPE";
25
+ }
26
+ function normalizeMinLength(value) {
27
+ if (value === void 0 || !Number.isFinite(value) || value <= 0) return 0;
28
+ return Math.floor(value);
29
+ }
30
+ function createNodeStreamDestination(options) {
31
+ const minLength = normalizeMinLength(options.minLength);
32
+ const ignoreEpipe = options.ignoreEpipe ?? false;
17
33
  const waiters = [];
34
+ const buffer = [];
35
+ const pendingPayloads = [];
36
+ let bufferedBytes = 0;
18
37
  let pendingWrites = 0;
19
38
  let pendingDrains = 0;
20
39
  let lastError;
21
40
  let lastContext;
41
+ let closed = false;
22
42
  const reportInternalError = (error, operation) => {
43
+ if (ignoreEpipe && isEpipe(error)) return;
23
44
  lastContext?.reportInternalError(error, {
24
45
  phase: "transport",
25
- transport: transportName,
46
+ transport: options.name,
26
47
  operation
27
48
  });
28
49
  };
29
50
  const settleWaitersIfIdle = () => {
30
51
  if (pendingWrites + pendingDrains > 0) return;
52
+ if (waiters.length === 0) return;
31
53
  const error = lastError;
32
54
  lastError = void 0;
33
55
  for (const waiter of waiters.splice(0)) if (error) waiter.reject(error);
34
56
  else waiter.resolve();
35
57
  };
36
58
  const recordError = (error, operation) => {
59
+ if (ignoreEpipe && isEpipe(error)) {
60
+ closed = true;
61
+ return;
62
+ }
37
63
  lastError = normalizeError(error);
38
64
  reportInternalError(lastError, operation);
39
65
  };
66
+ const onStreamError = (error) => {
67
+ recordError(error, "stream-error");
68
+ settleWaitersIfIdle();
69
+ };
70
+ const offError = () => options.stream.off?.("error", onStreamError);
71
+ options.stream.on?.("error", onStreamError);
40
72
  const waitForDrain = () => {
41
- if (!stream.once) return;
73
+ if (!options.stream.once) return;
42
74
  pendingDrains += 1;
43
- stream.once("drain", () => {
75
+ options.stream.once("drain", () => {
44
76
  pendingDrains -= 1;
45
77
  settleWaitersIfIdle();
46
78
  });
47
79
  };
48
- const writePayload = (payload) => {
80
+ const removePending = (payload) => {
81
+ const index = pendingPayloads.indexOf(payload);
82
+ if (index >= 0) pendingPayloads.splice(index, 1);
83
+ };
84
+ const writeNow = (payload) => {
85
+ if (closed) return;
86
+ pendingPayloads.push(payload);
49
87
  pendingWrites += 1;
50
88
  try {
51
- if (stream.write(payload, (error) => {
89
+ if (options.stream.write(payload, (error) => {
90
+ removePending(payload);
52
91
  pendingWrites -= 1;
53
- if (error) recordError(error, "write");
92
+ if (error) recordError(error, options.reportOperation ?? "write");
54
93
  settleWaitersIfIdle();
55
94
  }) === false) waitForDrain();
56
95
  } catch (error) {
96
+ removePending(payload);
57
97
  pendingWrites -= 1;
58
- recordError(error, "write");
98
+ recordError(error, options.reportOperation ?? "write");
59
99
  settleWaitersIfIdle();
60
100
  }
61
101
  };
62
- return {
63
- name: transportName,
64
- minLevel: options.minLevel,
65
- log(event, context) {
66
- if (options.minLevel !== void 0 && event.level < (0, _loggerjs_core.toLevelValue)(options.minLevel)) return;
102
+ const flushBuffered = () => {
103
+ if (buffer.length === 0) return;
104
+ const payload = coalescePayloads(buffer.splice(0));
105
+ bufferedBytes = 0;
106
+ writeNow(payload);
107
+ };
108
+ const destination = {
109
+ write(payload, context) {
110
+ if (closed) return;
67
111
  lastContext = context;
68
- writePayload(codec.encode(event));
112
+ if (minLength > 0) {
113
+ buffer.push(payload);
114
+ bufferedBytes += byteLength(payload);
115
+ if (bufferedBytes >= minLength) flushBuffered();
116
+ return;
117
+ }
118
+ writeNow(payload);
69
119
  },
70
120
  flush() {
121
+ flushBuffered();
71
122
  if (pendingWrites + pendingDrains === 0) {
72
123
  const error = lastError;
73
124
  lastError = void 0;
@@ -80,8 +131,133 @@ function stdoutTransport(options = {}) {
80
131
  reject
81
132
  });
82
133
  });
134
+ },
135
+ flushSync() {
136
+ if (!options.syncWrite) {
137
+ flushBuffered();
138
+ return;
139
+ }
140
+ for (const payload of buffer.splice(0)) options.syncWrite(payload);
141
+ bufferedBytes = 0;
142
+ for (const payload of pendingPayloads.splice(0)) options.syncWrite(payload);
143
+ },
144
+ close() {
145
+ return destination.flush().then(() => new Promise((resolve, reject) => {
146
+ if (!options.stream.end) {
147
+ closed = true;
148
+ offError();
149
+ resolve();
150
+ return;
151
+ }
152
+ options.stream.end((error) => {
153
+ closed = true;
154
+ offError();
155
+ if (error && !(ignoreEpipe && isEpipe(error))) reject(error);
156
+ else resolve();
157
+ });
158
+ }), (error) => {
159
+ offError();
160
+ return Promise.reject(error);
161
+ });
162
+ },
163
+ closeSync() {
164
+ destination.flushSync();
165
+ closed = true;
166
+ offError();
167
+ }
168
+ };
169
+ return destination;
170
+ }
171
+ function createNodeFileDestination(options) {
172
+ const flags = options.flags ?? (options.append === false ? "w" : "a");
173
+ if (options.mkdir) (0, fs.mkdirSync)((0, path.dirname)(options.path), { recursive: true });
174
+ let fd;
175
+ const getFd = () => {
176
+ fd ??= (0, fs.openSync)(options.path, flags);
177
+ return fd;
178
+ };
179
+ const syncWrite = (payload) => {
180
+ if (typeof payload === "string") (0, fs.writeSync)(getFd(), payload);
181
+ else (0, fs.writeSync)(getFd(), payload);
182
+ };
183
+ if (options.sync) {
184
+ let closed = false;
185
+ const releaseSync = () => {
186
+ if (fd !== void 0) {
187
+ (0, fs.closeSync)(fd);
188
+ fd = void 0;
189
+ }
190
+ };
191
+ return {
192
+ write(payload) {
193
+ if (closed) return;
194
+ syncWrite(payload);
195
+ },
196
+ flush() {
197
+ return Promise.resolve();
198
+ },
199
+ flushSync() {},
200
+ close() {
201
+ releaseSync();
202
+ closed = true;
203
+ return Promise.resolve();
204
+ },
205
+ closeSync() {
206
+ releaseSync();
207
+ closed = true;
208
+ },
209
+ releaseSync
210
+ };
211
+ }
212
+ const stream = (0, fs.createWriteStream)(options.path, { flags });
213
+ const destination = createNodeStreamDestination({
214
+ name: options.name,
215
+ stream,
216
+ minLength: options.minLength,
217
+ syncWrite
218
+ });
219
+ const releaseSync = () => {
220
+ if (fd !== void 0) {
221
+ (0, fs.closeSync)(fd);
222
+ fd = void 0;
83
223
  }
84
224
  };
225
+ return {
226
+ ...destination,
227
+ stream,
228
+ close() {
229
+ return destination.close().finally(releaseSync);
230
+ },
231
+ closeSync() {
232
+ destination.closeSync();
233
+ releaseSync();
234
+ },
235
+ releaseSync
236
+ };
237
+ }
238
+ //#endregion
239
+ //#region src/stdout-transport.ts
240
+ function stdoutTransport(options = {}) {
241
+ const codec = options.codec ?? (0, _loggerjs_core.ndjsonCodec)();
242
+ const stream = options.stream ?? process.stdout;
243
+ const transportName = options.name ?? "stdout";
244
+ const destination = createNodeStreamDestination({
245
+ name: transportName,
246
+ stream,
247
+ minLength: options.minLength,
248
+ ignoreEpipe: options.ignoreEpipe ?? true
249
+ });
250
+ return {
251
+ name: transportName,
252
+ minLevel: options.minLevel,
253
+ log(event, context) {
254
+ if (options.minLevel !== void 0 && event.level < (0, _loggerjs_core.toLevelValue)(options.minLevel)) return;
255
+ destination.write(codec.encode(event), context);
256
+ },
257
+ flush: destination.flush,
258
+ flushSync: destination.flushSync,
259
+ close: destination.close
260
+ };
85
261
  }
86
262
  function stderrTransport(options = {}) {
87
263
  return stdoutTransport({
@@ -94,60 +270,26 @@ function stderrTransport(options = {}) {
94
270
  //#region src/file-transport.ts
95
271
  function fileTransport(options) {
96
272
  const codec = options.codec ?? (0, _loggerjs_core.ndjsonCodec)();
97
- const flags = options.flags ?? "a";
98
- const stream = (0, fs.createWriteStream)(options.path, { flags });
99
- let syncFd;
100
- const pending = [];
101
- const removePending = (payload) => {
102
- const index = pending.indexOf(payload);
103
- if (index >= 0) pending.splice(index, 1);
104
- };
105
- const getSyncFd = () => {
106
- syncFd ??= (0, fs.openSync)(options.path, flags);
107
- return syncFd;
108
- };
273
+ const destination = createNodeFileDestination({
274
+ name: options.name ?? "file",
275
+ path: options.path,
276
+ flags: options.flags,
277
+ append: options.append,
278
+ mkdir: options.mkdir,
279
+ sync: options.sync,
280
+ minLength: options.minLength
281
+ });
109
282
  return {
110
283
  name: options.name ?? "file",
111
284
  minLevel: options.minLevel,
112
- stream,
113
- log(event) {
285
+ stream: destination.stream,
286
+ log(event, context) {
114
287
  if (options.minLevel !== void 0 && event.level < (0, _loggerjs_core.toLevelValue)(options.minLevel)) return;
115
- const payload = codec.encode(event);
116
- pending.push(payload);
117
- stream.write(payload, (error) => {
118
- if (!error) removePending(payload);
119
- });
288
+ destination.write(codec.encode(event), context);
120
289
  },
121
- flush() {
122
- return new Promise((resolve, reject) => {
123
- stream.write("", (error) => {
124
- if (error) {
125
- reject(error);
126
- return;
127
- }
128
- pending.splice(0, pending.length);
129
- resolve();
130
- });
131
- });
132
- },
133
- flushSync() {
134
- if (pending.length === 0) return;
135
- const fd = getSyncFd();
136
- for (const payload of pending.splice(0)) if (typeof payload === "string") (0, fs.writeSync)(fd, payload);
137
- else (0, fs.writeSync)(fd, payload);
138
- },
139
- close() {
140
- return new Promise((resolve, reject) => {
141
- stream.end?.((error) => {
142
- if (syncFd !== void 0) {
143
- (0, fs.closeSync)(syncFd);
144
- syncFd = void 0;
145
- }
146
- if (error) reject(error);
147
- else resolve();
148
- });
149
- });
150
- }
290
+ flush: destination.flush,
291
+ flushSync: destination.flushSync,
292
+ close: destination.close
151
293
  };
152
294
  }
153
295
  //#endregion
@@ -176,23 +318,20 @@ function fileSize(path) {
176
318
  }
177
319
  function rotatingFileTransport(options) {
178
320
  const codec = options.codec ?? (0, _loggerjs_core.ndjsonCodec)();
179
- const flags = options.flags ?? "a";
180
321
  const maxBytes = normalizePositiveInteger(options.maxBytes, 10 * 1024 * 1024);
181
322
  const maxFiles = normalizeNonNegativeInteger(options.maxFiles, 5);
182
323
  const archivePath = options.archivePath ?? defaultArchivePath;
183
- let fd;
324
+ const destination = createNodeFileDestination({
325
+ name: options.name ?? "rotating-file",
326
+ path: options.path,
327
+ flags: options.flags,
328
+ append: options.append,
329
+ mkdir: options.mkdir,
330
+ sync: true
331
+ });
184
332
  let bytes = fileSize(options.path);
185
- const closeFd = () => {
186
- if (fd === void 0) return;
187
- (0, fs.closeSync)(fd);
188
- fd = void 0;
189
- };
190
- const getFd = () => {
191
- fd ??= (0, fs.openSync)(options.path, flags);
192
- return fd;
193
- };
194
333
  const rotate = () => {
195
- closeFd();
334
+ destination.releaseSync?.();
196
335
  if (maxFiles === 0) {
197
336
  if ((0, fs.existsSync)(options.path)) (0, fs.unlinkSync)(options.path);
198
337
  bytes = 0;
@@ -210,8 +349,7 @@ function rotatingFileTransport(options) {
210
349
  const writePayload = (payload) => {
211
350
  const size = payloadBytes(payload);
212
351
  if (bytes > 0 && bytes + size > maxBytes) rotate();
213
- if (typeof payload === "string") (0, fs.writeSync)(getFd(), payload);
214
- else (0, fs.writeSync)(getFd(), payload);
352
+ destination.write(payload);
215
353
  bytes += size;
216
354
  };
217
355
  return {
@@ -228,12 +366,11 @@ function rotatingFileTransport(options) {
228
366
  }
229
367
  },
230
368
  flush() {
231
- return Promise.resolve();
369
+ return destination.flush();
232
370
  },
233
- flushSync() {},
371
+ flushSync: destination.flushSync,
234
372
  close() {
235
- closeFd();
236
- return Promise.resolve();
373
+ return destination.close();
237
374
  },
238
375
  rotate,
239
376
  currentBytes: () => bytes
@@ -455,13 +592,58 @@ function transferablePayload(payload) {
455
592
  transferList: [copy.buffer]
456
593
  };
457
594
  }
595
+ function normalizePositiveTimeout(value) {
596
+ if (value === void 0 || !Number.isFinite(value) || value <= 0) return 0;
597
+ return Math.floor(value);
598
+ }
599
+ function protocolMessage(value) {
600
+ if (!value || typeof value !== "object") return void 0;
601
+ const message = value;
602
+ if (message.type === "loggerjs:ready") return { type: "loggerjs:ready" };
603
+ if (message.type === "loggerjs:batch:ack") {
604
+ const id = value.id;
605
+ if (typeof id === "number") return {
606
+ type: "loggerjs:batch:ack",
607
+ id
608
+ };
609
+ }
610
+ if (message.type === "loggerjs:error") {
611
+ const item = value;
612
+ return {
613
+ type: "loggerjs:error",
614
+ error: item.error,
615
+ message: typeof item.message === "string" ? item.message : void 0
616
+ };
617
+ }
618
+ }
619
+ function dropBatch(events, reason) {
620
+ (0, _loggerjs_core.incrementLoggerMetaCounter)("transport.dropped", events.length);
621
+ (0, _loggerjs_core.incrementLoggerMetaCounter)(`transport.dropped.${reason}`, events.length);
622
+ }
458
623
  function workerTransport(options = {}) {
459
624
  const codec = options.codec ?? (0, _loggerjs_core.safeJsonCodec)();
460
625
  const transportName = options.name ?? "worker";
461
626
  const fallback = options.fallback;
627
+ const readyTimeoutMs = normalizePositiveTimeout(options.readyTimeoutMs);
628
+ const ackTimeoutMs = normalizePositiveTimeout(options.ackTimeoutMs);
629
+ const autoEnd = options.autoEnd ?? true;
462
630
  let worker;
463
631
  let failed = false;
632
+ let failedError;
464
633
  let lastContext;
634
+ let ready = readyTimeoutMs === 0;
635
+ let readyPromise;
636
+ let readyTimer;
637
+ let readyResolve;
638
+ let readyReject;
639
+ let nextBatchId = 1;
640
+ const pendingBatches = /* @__PURE__ */ new Map();
641
+ const setPendingGauge = () => {
642
+ (0, _loggerjs_core.setLoggerMetaGauge)(`transport.queue.depth.${transportName}`, pendingBatches.size);
643
+ };
644
+ const setReadyGauge = (value) => {
645
+ (0, _loggerjs_core.setLoggerMetaGauge)(`transport.ready.${transportName}`, value);
646
+ };
465
647
  const reportInternalError = (error, operation) => {
466
648
  lastContext?.reportInternalError(error, {
467
649
  phase: "transport",
@@ -470,14 +652,82 @@ function workerTransport(options = {}) {
470
652
  });
471
653
  };
472
654
  const markFailed = (error, operation) => {
655
+ if (failed) return;
473
656
  failed = true;
657
+ failedError = error instanceof Error ? error : new Error(String(error));
658
+ setReadyGauge(0);
474
659
  (0, _loggerjs_core.incrementLoggerMetaCounter)("transport.worker.failed");
660
+ (0, _loggerjs_core.emitLoggerDiagnostic)({
661
+ stage: "worker",
662
+ phase: "error",
663
+ transport: transportName,
664
+ operation,
665
+ error
666
+ });
475
667
  reportInternalError(error, operation);
668
+ readyReject?.(failedError);
669
+ failPendingBatches(operation);
476
670
  };
477
671
  const onWorkerError = (error) => markFailed(error, "worker-error");
478
672
  const onWorkerExit = (code) => {
479
673
  if (typeof code === "number" && code !== 0) markFailed(code, "worker-exit");
480
674
  };
675
+ const onWorkerMessage = (value) => {
676
+ const message = protocolMessage(value);
677
+ if (!message) return;
678
+ if (message.type === "loggerjs:ready") {
679
+ ready = true;
680
+ setReadyGauge(1);
681
+ (0, _loggerjs_core.emitLoggerDiagnostic)({
682
+ stage: "worker",
683
+ phase: "end",
684
+ transport: transportName,
685
+ operation: "ready"
686
+ });
687
+ if (readyTimer) clearTimeout(readyTimer);
688
+ readyResolve?.();
689
+ return;
690
+ }
691
+ if (message.type === "loggerjs:batch:ack") {
692
+ const pending = pendingBatches.get(message.id);
693
+ if (!pending) return;
694
+ pendingBatches.delete(message.id);
695
+ setPendingGauge();
696
+ if (pending.timer) clearTimeout(pending.timer);
697
+ pending.resolve();
698
+ (0, _loggerjs_core.incrementLoggerMetaCounter)("transport.worker.ack");
699
+ return;
700
+ }
701
+ markFailed(message.error ?? new Error(message.message ?? "Worker reported an error"), "worker-message");
702
+ };
703
+ const fallbackOrDropBatch = async (events, context, reason) => {
704
+ if (fallback) {
705
+ await fallbackBatch(events, context);
706
+ return;
707
+ }
708
+ dropBatch(events, reason);
709
+ };
710
+ const failPendingBatch = (pending, reason) => {
711
+ pendingBatches.delete(pending.id);
712
+ setPendingGauge();
713
+ if (pending.timer) clearTimeout(pending.timer);
714
+ (0, _loggerjs_core.incrementLoggerMetaCounter)("transport.worker.pending-dropped", pending.events.length);
715
+ fallbackOrDropBatch(pending.events, pending.context, reason).finally(pending.resolve);
716
+ };
717
+ function failPendingBatches(reason) {
718
+ for (const pending of Array.from(pendingBatches.values())) failPendingBatch(pending, reason);
719
+ }
720
+ const waitForReady = async () => {
721
+ if (ready) return;
722
+ readyPromise ??= new Promise((resolve, reject) => {
723
+ readyResolve = resolve;
724
+ readyReject = reject;
725
+ readyTimer = setTimeout(() => {
726
+ reject(/* @__PURE__ */ new Error(`workerTransport ready timeout after ${readyTimeoutMs}ms`));
727
+ }, readyTimeoutMs);
728
+ });
729
+ await readyPromise;
730
+ };
481
731
  const getWorker = () => {
482
732
  if (failed) return void 0;
483
733
  if (worker) return worker;
@@ -485,6 +735,8 @@ function workerTransport(options = {}) {
485
735
  worker = options.worker ?? options.workerFactory?.() ?? createDefaultWorker(options);
486
736
  worker.on?.("error", onWorkerError);
487
737
  worker.on?.("exit", onWorkerExit);
738
+ worker.on?.("message", onWorkerMessage);
739
+ if (ready) setReadyGauge(1);
488
740
  return worker;
489
741
  } catch (error) {
490
742
  markFailed(error, "create-worker");
@@ -502,7 +754,14 @@ function workerTransport(options = {}) {
502
754
  lastContext = context;
503
755
  const currentWorker = getWorker();
504
756
  if (!currentWorker) {
505
- await fallbackBatch(events, context);
757
+ await fallbackOrDropBatch(events, context, "worker-unavailable");
758
+ return;
759
+ }
760
+ try {
761
+ await waitForReady();
762
+ } catch (error) {
763
+ markFailed(error, "worker-ready-timeout");
764
+ await fallbackOrDropBatch(events, context, "worker-ready-timeout");
506
765
  return;
507
766
  }
508
767
  const encoded = payloadToBytes(codec.encode(events));
@@ -517,16 +776,53 @@ function workerTransport(options = {}) {
517
776
  count: events.length,
518
777
  payload: transferable.payload
519
778
  };
779
+ let pending;
780
+ if (ackTimeoutMs > 0) {
781
+ const id = nextBatchId;
782
+ nextBatchId += 1;
783
+ message.id = id;
784
+ pending = {
785
+ id,
786
+ events,
787
+ context,
788
+ resolve: () => {}
789
+ };
790
+ pending.timer = setTimeout(() => {
791
+ if (!pending) return;
792
+ markFailed(/* @__PURE__ */ new Error(`workerTransport ack timeout after ${ackTimeoutMs}ms`), "worker-ack-timeout");
793
+ }, ackTimeoutMs);
794
+ pendingBatches.set(id, pending);
795
+ setPendingGauge();
796
+ }
520
797
  try {
521
798
  currentWorker.postMessage(message, transferable.transferList);
522
799
  } catch (error) {
523
800
  markFailed(error, "post-message");
524
- await fallbackBatch(events, context);
801
+ if (!pending) await fallbackOrDropBatch(events, context, "worker-post-message");
525
802
  }
526
803
  };
527
- return {
804
+ const transport = {
528
805
  name: transportName,
529
806
  minLevel: options.minLevel,
807
+ async ready() {
808
+ if (!getWorker()) {
809
+ if (fallback) {
810
+ await fallback.ready?.();
811
+ return;
812
+ }
813
+ throw failedError ?? /* @__PURE__ */ new Error("workerTransport is unavailable");
814
+ }
815
+ try {
816
+ await waitForReady();
817
+ } catch (error) {
818
+ markFailed(error, "worker-ready-timeout");
819
+ if (fallback) {
820
+ await fallback.ready?.();
821
+ return;
822
+ }
823
+ throw error;
824
+ }
825
+ },
530
826
  log(event, context) {
531
827
  if (options.minLevel !== void 0 && event.level < (0, _loggerjs_core.toLevelValue)(options.minLevel)) return;
532
828
  return postBatch([event], context);
@@ -535,15 +831,28 @@ function workerTransport(options = {}) {
535
831
  return postBatch(events, context);
536
832
  },
537
833
  async flush() {
834
+ await Promise.all(Array.from(pendingBatches.values(), (pending) => new Promise((resolve) => {
835
+ const originalResolve = pending.resolve;
836
+ pending.resolve = () => {
837
+ originalResolve();
838
+ resolve();
839
+ };
840
+ })));
538
841
  await fallback?.flush?.();
539
842
  },
540
843
  async close() {
844
+ await transport.flush?.();
541
845
  worker?.off?.("error", onWorkerError);
542
846
  worker?.off?.("exit", onWorkerExit);
847
+ worker?.off?.("message", onWorkerMessage);
543
848
  await fallback?.close?.();
544
- await worker?.terminate?.();
849
+ if (autoEnd) await worker?.terminate?.();
850
+ if (readyTimer) clearTimeout(readyTimer);
851
+ readyReject = void 0;
852
+ readyResolve = void 0;
545
853
  }
546
854
  };
855
+ return transport;
547
856
  }
548
857
  //#endregion
549
858
  //#region src/context.ts
@@ -1441,16 +1750,16 @@ function nodeFetchIntegration(options = {}) {
1441
1750
  }
1442
1751
  //#endregion
1443
1752
  //#region src/node-http-client-integration.ts
1444
- const requireBuiltin$1 = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href);
1753
+ const requireBuiltin$2 = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href);
1445
1754
  const defaultRandom$1 = () => Math.random();
1446
1755
  let cachedHttpModule;
1447
1756
  let cachedHttpsModule;
1448
1757
  function loadBuiltin(name, fallback) {
1449
1758
  try {
1450
- return requireBuiltin$1(name);
1759
+ return requireBuiltin$2(name);
1451
1760
  } catch {
1452
1761
  try {
1453
- return requireBuiltin$1(fallback);
1762
+ return requireBuiltin$2(fallback);
1454
1763
  } catch {
1455
1764
  return null;
1456
1765
  }
@@ -1915,15 +2224,15 @@ const defaultChannels = [
1915
2224
  "undici:request:trailers",
1916
2225
  "undici:request:error"
1917
2226
  ];
1918
- const requireBuiltin = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href);
1919
- let cachedDiagnosticsChannel;
2227
+ const requireBuiltin$1 = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href);
2228
+ let cachedDiagnosticsChannel$1;
1920
2229
  function diagnosticsChannelIntegration(options = {}) {
1921
2230
  const channels = options.channels ?? defaultChannels;
1922
2231
  const captureMessage = options.captureMessage ?? false;
1923
2232
  return {
1924
2233
  name: "diagnostics-channel",
1925
2234
  setup(api) {
1926
- const diagnosticsChannel = options.diagnosticsChannel === void 0 ? loadDiagnosticsChannel() : options.diagnosticsChannel;
2235
+ const diagnosticsChannel = options.diagnosticsChannel === void 0 ? loadDiagnosticsChannel$1() : options.diagnosticsChannel;
1927
2236
  if (!diagnosticsChannel) return;
1928
2237
  const disposers = [];
1929
2238
  let disposed = false;
@@ -1950,6 +2259,23 @@ function diagnosticsChannelIntegration(options = {}) {
1950
2259
  }
1951
2260
  };
1952
2261
  }
2262
+ function loadDiagnosticsChannel$1() {
2263
+ if (cachedDiagnosticsChannel$1 !== void 0) return cachedDiagnosticsChannel$1;
2264
+ try {
2265
+ cachedDiagnosticsChannel$1 = requireBuiltin$1("node:diagnostics_channel");
2266
+ } catch {
2267
+ try {
2268
+ cachedDiagnosticsChannel$1 = requireBuiltin$1("diagnostics_channel");
2269
+ } catch {
2270
+ cachedDiagnosticsChannel$1 = null;
2271
+ }
2272
+ }
2273
+ return cachedDiagnosticsChannel$1;
2274
+ }
2275
+ //#endregion
2276
+ //#region src/logger-diagnostics.ts
2277
+ const requireBuiltin = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href);
2278
+ let cachedDiagnosticsChannel;
1953
2279
  function loadDiagnosticsChannel() {
1954
2280
  if (cachedDiagnosticsChannel !== void 0) return cachedDiagnosticsChannel;
1955
2281
  try {
@@ -1963,6 +2289,29 @@ function loadDiagnosticsChannel() {
1963
2289
  }
1964
2290
  return cachedDiagnosticsChannel;
1965
2291
  }
2292
+ function installLoggerDiagnosticsChannel(options = {}) {
2293
+ const diagnosticsChannel = options.diagnosticsChannel === void 0 ? loadDiagnosticsChannel() : options.diagnosticsChannel;
2294
+ if (!diagnosticsChannel) return () => {};
2295
+ const prefix = options.prefix ?? "loggerjs";
2296
+ const channels = /* @__PURE__ */ new Map();
2297
+ const channelFor = (stage) => {
2298
+ const name = `${prefix}.${stage}`;
2299
+ let channel = channels.get(name);
2300
+ if (!channel) {
2301
+ channel = diagnosticsChannel.channel(name);
2302
+ channels.set(name, channel);
2303
+ }
2304
+ return channel;
2305
+ };
2306
+ const sink = (event) => {
2307
+ channelFor(event.stage).publish(event);
2308
+ };
2309
+ sink.enabled = (stage) => channelFor(stage).hasSubscribers !== false;
2310
+ const previous = (0, _loggerjs_core.setLoggerDiagnosticSink)(sink);
2311
+ return () => {
2312
+ (0, _loggerjs_core.setLoggerDiagnosticSink)(previous);
2313
+ };
2314
+ }
1966
2315
  //#endregion
1967
2316
  exports.bullMqIntegration = bullMqIntegration;
1968
2317
  exports.captureCliIntegration = captureCliIntegration;
@@ -1976,6 +2325,7 @@ exports.fileTransport = fileTransport;
1976
2325
  exports.formatSyslogMessage = formatSyslogMessage;
1977
2326
  exports.hapiIntegration = hapiIntegration;
1978
2327
  exports.installAsyncLocalStorageContext = installAsyncLocalStorageContext;
2328
+ exports.installLoggerDiagnosticsChannel = installLoggerDiagnosticsChannel;
1979
2329
  exports.koaIntegration = koaIntegration;
1980
2330
  exports.nestMiddlewareIntegration = nestMiddlewareIntegration;
1981
2331
  exports.nodeCompressionPayloadTransform = nodeCompressionPayloadTransform;