loggily 0.7.0 → 0.8.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 +145 -54
- package/dist/context.mjs +1 -1
- package/dist/{core-Du3sIje6.mjs → core-B3pox577.mjs} +521 -347
- package/dist/core-B3pox577.mjs.map +1 -0
- package/dist/core-Dm2PQUoS.d.mts +191 -0
- package/dist/core-Dm2PQUoS.d.mts.map +1 -0
- package/dist/{index-Co4jC3mx.d.mts → file-writer-DtaY8Njt.d.mts} +60 -49
- package/dist/file-writer-DtaY8Njt.d.mts.map +1 -0
- package/dist/index.browser.d.mts +10 -0
- package/dist/index.browser.d.mts.map +1 -0
- package/dist/index.browser.mjs +10 -0
- package/dist/index.browser.mjs.map +1 -0
- package/dist/index.d.mts +4 -3
- package/dist/index.mjs +7 -2
- package/dist/index.mjs.map +1 -0
- package/dist/metrics.d.mts +2 -48
- package/dist/metrics.mjs +13 -43
- package/dist/metrics.mjs.map +1 -1
- package/dist/otel.d.mts +63 -0
- package/dist/otel.d.mts.map +1 -0
- package/dist/otel.mjs +82 -0
- package/dist/otel.mjs.map +1 -0
- package/dist/pipeline-Cl9-wCmt.d.mts +73 -0
- package/dist/pipeline-Cl9-wCmt.d.mts.map +1 -0
- package/dist/worker.d.mts +64 -94
- package/dist/worker.d.mts.map +1 -1
- package/dist/worker.mjs +107 -281
- package/dist/worker.mjs.map +1 -1
- package/package.json +22 -3
- package/dist/core-DAFH-huv.d.mts +0 -199
- package/dist/core-DAFH-huv.d.mts.map +0 -1
- package/dist/core-Du3sIje6.mjs.map +0 -1
- package/dist/index-Co4jC3mx.d.mts.map +0 -1
- package/dist/metrics.d.mts.map +0 -1
package/dist/worker.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker.d.mts","names":[],"sources":["../src/worker.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"worker.d.mts","names":[],"sources":["../src/worker.ts"],"mappings":";;;;;UA8CiB,oBAAA;EACf,IAAA;EACA,KAAA;EACA,SAAA;EACA,IAAA;EACA,SAAA;AAAA;;iBAMc,gBAAA,CAAiB,GAAA,YAAe,GAAA,IAAO,QAAA;AAyBvD;AAAA,iBApBgB,iBAAA,CAAkB,GAAA,YAAe,GAAA,IAAO,SAAA;;iBAKxC,aAAA,CAAc,GAAA,YAAe,GAAA,IAAO,KAAA;;iBAKpC,sBAAA,CAAuB,GAAA,YAAe,GAAA,IAAO,oBAAA;;iBAU7C,eAAA,CAAgB,GAAA,YAAe,GAAA,IAAO,oBAAA,GAAuB,KAAA;AAAA,KAMxE,aAAA,IAAiB,OAAA,EAAS,oBAAA;;AAJ9B;;;;;AAuBD;;;;;;;;iBAAgB,cAAA,CAAe,WAAA,EAAa,aAAA,EAAe,SAAA;AA8B3D;;;;AAAA,iBAAgB,cAAA,CAAA;AAiBhB;;;;;;;;AAAA,iBAAgB,oBAAA,CAAqB,WAAA,GAAc,GAAA,qBAAwB,KAAA;AA0C3E;;;;;;;;;;;;AAsBA;;;;;;;;;;;;AA4BA;;AAlDA,iBAAgB,kBAAA,CACd,WAAA,GAAc,GAAA,oBACd,SAAA,UACA,KAAA,GAAQ,MAAA,oBACP,iBAAA;;;AAwEH;;;;;;iBAtDgB,kBAAA,CACd,MAAA,EAAQ,iBAAA;EAAsB,QAAA,CAAS,KAAA,EAAO,KAAA;AAAA,KAC5C,GAAA;;;;AAwIJ;;;;;;;;;;;;;iBA9GgB,sBAAA,CAAA,IAA2B,OAAA;AAAA,UA0B1B,2BAAA;;EAEf,gBAAA;;EAEA,MAAA;IAAW,IAAA;IAAc,QAAA,CAAS,KAAA,EAAO,KAAA;EAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;iBAgF3B,0BAAA,CACd,OAAA,GAAS,2BAAA,IACP,OAAA,EAAS,oBAAA"}
|
package/dist/worker.mjs
CHANGED
|
@@ -1,22 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import "./index.mjs";
|
|
1
|
+
import { a as baseCreateLogger, j as withSpans, s as createLogger, v as pipe } from "./core-B3pox577.mjs";
|
|
3
2
|
//#region src/worker.ts
|
|
4
3
|
/**
|
|
5
4
|
* Worker Thread Logger/Console Forwarding
|
|
6
5
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* Pipeline-based worker logging: worker loggers use a postMessage transport
|
|
7
|
+
* so events flow through the main thread's pipeline for output.
|
|
9
8
|
*
|
|
10
|
-
* ##
|
|
9
|
+
* ## Structured Logger (Recommended)
|
|
11
10
|
*
|
|
12
11
|
* @example Worker side:
|
|
13
12
|
* ```typescript
|
|
14
13
|
* import { createWorkerLogger } from "loggily/worker"
|
|
15
14
|
* const log = createWorkerLogger(postMessage, "km:worker:parse")
|
|
16
15
|
*
|
|
17
|
-
* log.info("processing", { file: "test.md" })
|
|
16
|
+
* log.info?.("processing", { file: "test.md" })
|
|
18
17
|
* {
|
|
19
|
-
* using span = log.span("parse")
|
|
18
|
+
* using span = log.span?.("parse")
|
|
20
19
|
* // ... work ...
|
|
21
20
|
* span.spanData.lines = 100
|
|
22
21
|
* }
|
|
@@ -27,9 +26,7 @@ import "./index.mjs";
|
|
|
27
26
|
* import { createWorkerLogHandler } from "loggily/worker"
|
|
28
27
|
*
|
|
29
28
|
* const handleLog = createWorkerLogHandler()
|
|
30
|
-
* worker.onmessage = (e) =>
|
|
31
|
-
* if (e.data.type === "log" || e.data.type === "span") handleLog(e.data)
|
|
32
|
-
* }
|
|
29
|
+
* worker.onmessage = (e) => handleLog(e.data)
|
|
33
30
|
* ```
|
|
34
31
|
*
|
|
35
32
|
* ## Console Forwarding (Simple)
|
|
@@ -42,71 +39,40 @@ import "./index.mjs";
|
|
|
42
39
|
* console.log("message") // Forwarded to main thread
|
|
43
40
|
* ```
|
|
44
41
|
*/
|
|
42
|
+
/** Type guard for LogEvent (structured log from worker) */
|
|
43
|
+
function isWorkerLogEvent(msg) {
|
|
44
|
+
return typeof msg === "object" && msg?.kind === "log";
|
|
45
|
+
}
|
|
46
|
+
/** Type guard for SpanEvent (span from worker) */
|
|
47
|
+
function isWorkerSpanEvent(msg) {
|
|
48
|
+
return typeof msg === "object" && msg?.kind === "span";
|
|
49
|
+
}
|
|
50
|
+
/** Type guard for any pipeline Event (log or span) */
|
|
51
|
+
function isWorkerEvent(msg) {
|
|
52
|
+
return isWorkerLogEvent(msg) || isWorkerSpanEvent(msg);
|
|
53
|
+
}
|
|
45
54
|
/** Type guard for WorkerConsoleMessage */
|
|
46
55
|
function isWorkerConsoleMessage(msg) {
|
|
47
56
|
return typeof msg === "object" && msg?.type === "console" && typeof msg.level === "string" && Array.isArray(msg.args);
|
|
48
57
|
}
|
|
49
|
-
/** Type guard for
|
|
50
|
-
function isWorkerLogMessage(msg) {
|
|
51
|
-
return typeof msg === "object" && msg?.type === "log" && typeof msg.level === "string" && typeof msg.namespace === "string";
|
|
52
|
-
}
|
|
53
|
-
/** Type guard for WorkerSpanMessage */
|
|
54
|
-
function isWorkerSpanMessage(msg) {
|
|
55
|
-
return typeof msg === "object" && msg?.type === "span" && typeof msg.event === "string";
|
|
56
|
-
}
|
|
57
|
-
/** Type guard for any worker message */
|
|
58
|
+
/** Type guard for any worker message (console or pipeline event) */
|
|
58
59
|
function isWorkerMessage(msg) {
|
|
59
|
-
return isWorkerConsoleMessage(msg) ||
|
|
60
|
+
return isWorkerConsoleMessage(msg) || isWorkerEvent(msg);
|
|
60
61
|
}
|
|
61
62
|
/** Store original console methods for restoration */
|
|
62
63
|
let originalConsole = null;
|
|
63
64
|
/**
|
|
64
|
-
*
|
|
65
|
-
* Handles non-serializable values like functions and circular references.
|
|
66
|
-
*/
|
|
67
|
-
function serializeArg(arg, depth = 0) {
|
|
68
|
-
if (depth > 5) return "[max depth]";
|
|
69
|
-
if (arg === null || arg === void 0) return arg;
|
|
70
|
-
if (typeof arg === "function") return `[Function: ${arg.name || "anonymous"}]`;
|
|
71
|
-
if (typeof arg === "symbol") return arg.toString();
|
|
72
|
-
if (typeof arg === "bigint") return arg.toString() + "n";
|
|
73
|
-
if (arg instanceof Error) return {
|
|
74
|
-
name: arg.name,
|
|
75
|
-
message: arg.message,
|
|
76
|
-
stack: arg.stack
|
|
77
|
-
};
|
|
78
|
-
if (Array.isArray(arg)) return arg.map((v) => serializeArg(v, depth + 1));
|
|
79
|
-
if (typeof arg === "object") try {
|
|
80
|
-
structuredClone(arg);
|
|
81
|
-
return arg;
|
|
82
|
-
} catch {
|
|
83
|
-
const result = {};
|
|
84
|
-
const seen = /* @__PURE__ */ new Set();
|
|
85
|
-
seen.add(arg);
|
|
86
|
-
for (const [key, value] of Object.entries(arg)) if (typeof value === "object" && value !== null && seen.has(value)) result[key] = "[Circular]";
|
|
87
|
-
else result[key] = serializeArg(value, depth + 1);
|
|
88
|
-
return result;
|
|
89
|
-
}
|
|
90
|
-
return arg;
|
|
91
|
-
}
|
|
92
|
-
/**
|
|
93
|
-
* Forward console.* calls from worker to main thread.
|
|
94
|
-
*
|
|
95
|
-
* Monkey-patches console methods to send messages via postMessage.
|
|
96
|
-
* Call this at the start of your worker script.
|
|
65
|
+
* Forward console.* calls from worker to main thread via postMessage.
|
|
97
66
|
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
67
|
+
* Monkey-patches console methods. postMessage uses structuredClone,
|
|
68
|
+
* which handles most values natively. If cloning fails (functions,
|
|
69
|
+
* symbols), falls back to original console.
|
|
100
70
|
*
|
|
101
71
|
* @example
|
|
102
72
|
* ```typescript
|
|
103
|
-
* // At top of worker file:
|
|
104
73
|
* import { forwardConsole } from "loggily/worker"
|
|
105
74
|
* forwardConsole(postMessage, "km:worker:parse")
|
|
106
|
-
*
|
|
107
|
-
* // Now all console.* calls are forwarded:
|
|
108
75
|
* console.log("processing", { file: "test.md" })
|
|
109
|
-
* console.error(new Error("failed"))
|
|
110
76
|
* ```
|
|
111
77
|
*/
|
|
112
78
|
function forwardConsole(postMessage, namespace) {
|
|
@@ -119,13 +85,16 @@ function forwardConsole(postMessage, namespace) {
|
|
|
119
85
|
"error",
|
|
120
86
|
"trace"
|
|
121
87
|
]) console[level] = (...args) => {
|
|
122
|
-
const serializedArgs = args.map((arg) => serializeArg(arg));
|
|
123
88
|
try {
|
|
124
89
|
postMessage({
|
|
125
90
|
type: "console",
|
|
126
91
|
level,
|
|
127
92
|
namespace,
|
|
128
|
-
args:
|
|
93
|
+
args: args.map((a) => typeof a === "function" ? `[Function: ${a.name || "anonymous"}]` : typeof a === "symbol" ? a.toString() : a instanceof Error ? {
|
|
94
|
+
name: a.name,
|
|
95
|
+
message: a.message,
|
|
96
|
+
stack: a.stack
|
|
97
|
+
} : a),
|
|
129
98
|
timestamp: Date.now()
|
|
130
99
|
});
|
|
131
100
|
} catch {
|
|
@@ -143,29 +112,35 @@ function restoreConsole() {
|
|
|
143
112
|
originalConsole = null;
|
|
144
113
|
}
|
|
145
114
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
115
|
+
/**
|
|
116
|
+
* Create a pipeline stage that forwards events via postMessage.
|
|
117
|
+
*
|
|
118
|
+
* Events are plain JSON objects that survive structuredClone natively.
|
|
119
|
+
* The stage consumes events (returns null) so nothing is output locally.
|
|
120
|
+
* The main thread uses handleWorkerEvents() or createWorkerLogHandler()
|
|
121
|
+
* to dispatch them through a local logger pipeline.
|
|
122
|
+
*/
|
|
123
|
+
function workerTransportStage(postMessage) {
|
|
124
|
+
return (event) => {
|
|
125
|
+
try {
|
|
126
|
+
postMessage(event);
|
|
127
|
+
} catch {
|
|
128
|
+
try {
|
|
129
|
+
postMessage(JSON.parse(JSON.stringify(event)));
|
|
130
|
+
} catch {}
|
|
131
|
+
}
|
|
132
|
+
return null;
|
|
133
|
+
};
|
|
158
134
|
}
|
|
159
135
|
/**
|
|
160
|
-
* Create a logger
|
|
136
|
+
* Create a logger for use in a worker thread.
|
|
161
137
|
*
|
|
162
|
-
* All log
|
|
163
|
-
* The main thread should use createWorkerLogHandler to process these messages.
|
|
138
|
+
* All log and span events are forwarded to the main thread via postMessage.
|
|
139
|
+
* The main thread should use createWorkerLogHandler() to process these messages.
|
|
164
140
|
*
|
|
165
141
|
* @param postMessage - The worker's postMessage function
|
|
166
142
|
* @param namespace - Logger namespace (e.g., "km:worker:parse")
|
|
167
143
|
* @param props - Optional initial props
|
|
168
|
-
* @param options - Optional configuration
|
|
169
144
|
*
|
|
170
145
|
* @example
|
|
171
146
|
* ```typescript
|
|
@@ -173,168 +148,69 @@ function resetWorkerIds() {
|
|
|
173
148
|
*
|
|
174
149
|
* const log = createWorkerLogger(postMessage, "km:worker:parse")
|
|
175
150
|
*
|
|
176
|
-
* log.info("starting parse", { file: "test.md" })
|
|
151
|
+
* log.info?.("starting parse", { file: "test.md" })
|
|
177
152
|
*
|
|
178
153
|
* {
|
|
179
|
-
* using span = log.span("process")
|
|
180
|
-
* span.info("processing...")
|
|
181
|
-
* span.spanData.
|
|
154
|
+
* using span = log.span?.("process")
|
|
155
|
+
* span.info?.("processing...")
|
|
156
|
+
* span.spanData.count = 100
|
|
182
157
|
* }
|
|
183
158
|
* // Span end event automatically sent to main thread
|
|
184
159
|
* ```
|
|
185
160
|
*/
|
|
186
|
-
function createWorkerLogger(postMessage, namespace, props
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
161
|
+
function createWorkerLogger(postMessage, namespace, props) {
|
|
162
|
+
const config = [{ level: "trace" }, workerTransportStage(postMessage)];
|
|
163
|
+
const logger = pipe(baseCreateLogger, withSpans())(namespace, config);
|
|
164
|
+
return props ? logger.child(props) : logger;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Create a handler that dispatches worker events to a target logger.
|
|
168
|
+
*
|
|
169
|
+
* Use this when you have a specific logger to dispatch through.
|
|
170
|
+
*
|
|
171
|
+
* @param target - Logger or object with dispatch method
|
|
172
|
+
* @returns Handler function to call with worker messages
|
|
173
|
+
*/
|
|
174
|
+
function handleWorkerEvents(target) {
|
|
175
|
+
return (msg) => {
|
|
176
|
+
if (typeof msg !== "object" || msg === null) return;
|
|
177
|
+
const event = msg;
|
|
178
|
+
if (event.kind === "log" || event.kind === "span") target.dispatch(msg);
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Create a zero-config handler for worker logger messages.
|
|
183
|
+
*
|
|
184
|
+
* Automatically creates loggers per-namespace. For console messages,
|
|
185
|
+
* formats args and dispatches through a logger.
|
|
186
|
+
*
|
|
187
|
+
* @returns Handler function to call with any worker message
|
|
188
|
+
*
|
|
189
|
+
* @example
|
|
190
|
+
* ```typescript
|
|
191
|
+
* import { createWorkerLogHandler } from "loggily/worker"
|
|
192
|
+
*
|
|
193
|
+
* const handleLog = createWorkerLogHandler()
|
|
194
|
+
* worker.onmessage = (e) => handleLog(e.data)
|
|
195
|
+
* ```
|
|
196
|
+
*/
|
|
197
|
+
function createWorkerLogHandler() {
|
|
198
|
+
const loggers = /* @__PURE__ */ new Map();
|
|
199
|
+
function getLogger(namespace) {
|
|
200
|
+
let logger = loggers.get(namespace);
|
|
201
|
+
if (!logger) {
|
|
202
|
+
logger = createLogger(namespace);
|
|
203
|
+
loggers.set(namespace, logger);
|
|
212
204
|
}
|
|
205
|
+
return logger;
|
|
213
206
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
const spanId = generateWorkerSpanId();
|
|
221
|
-
const spanTraceId = traceId || generateWorkerTraceId();
|
|
222
|
-
const startTime = Date.now();
|
|
223
|
-
const customSpanData = {};
|
|
224
|
-
try {
|
|
225
|
-
postMessage({
|
|
226
|
-
type: "span",
|
|
227
|
-
event: "start",
|
|
228
|
-
namespace: fullNamespace,
|
|
229
|
-
spanId,
|
|
230
|
-
traceId: spanTraceId,
|
|
231
|
-
parentId: parentSpanId,
|
|
232
|
-
startTime,
|
|
233
|
-
props: mergedProps,
|
|
234
|
-
spanData: {},
|
|
235
|
-
timestamp: Date.now()
|
|
236
|
-
});
|
|
237
|
-
} catch (err) {
|
|
238
|
-
try {
|
|
239
|
-
postMessage({
|
|
240
|
-
type: "log",
|
|
241
|
-
level: "error",
|
|
242
|
-
namespace: fullNamespace,
|
|
243
|
-
message: `postMessage failed for span start "${fullNamespace}": ${err instanceof Error ? err.message : String(err)}`,
|
|
244
|
-
timestamp: Date.now()
|
|
245
|
-
});
|
|
246
|
-
} catch {}
|
|
247
|
-
}
|
|
248
|
-
let ended = false;
|
|
249
|
-
const spanData = createSpanDataProxy(() => ({
|
|
250
|
-
id: spanId,
|
|
251
|
-
traceId: spanTraceId,
|
|
252
|
-
parentId: parentSpanId,
|
|
253
|
-
startTime,
|
|
254
|
-
endTime: ended ? Date.now() : null,
|
|
255
|
-
duration: Date.now() - startTime
|
|
256
|
-
}), customSpanData);
|
|
257
|
-
function endSpan() {
|
|
258
|
-
if (ended) return;
|
|
259
|
-
ended = true;
|
|
260
|
-
const endTime = Date.now();
|
|
261
|
-
const duration = endTime - startTime;
|
|
262
|
-
try {
|
|
263
|
-
postMessage({
|
|
264
|
-
type: "span",
|
|
265
|
-
event: "end",
|
|
266
|
-
namespace: fullNamespace,
|
|
267
|
-
spanId,
|
|
268
|
-
traceId: spanTraceId,
|
|
269
|
-
parentId: parentSpanId,
|
|
270
|
-
startTime,
|
|
271
|
-
endTime,
|
|
272
|
-
duration,
|
|
273
|
-
props: mergedProps,
|
|
274
|
-
spanData: customSpanData,
|
|
275
|
-
timestamp: Date.now()
|
|
276
|
-
});
|
|
277
|
-
} catch (err) {
|
|
278
|
-
try {
|
|
279
|
-
postMessage({
|
|
280
|
-
type: "log",
|
|
281
|
-
level: "error",
|
|
282
|
-
namespace: fullNamespace,
|
|
283
|
-
message: `postMessage failed for span end "${fullNamespace}" (${duration}ms): ${err instanceof Error ? err.message : String(err)}`,
|
|
284
|
-
timestamp: Date.now()
|
|
285
|
-
});
|
|
286
|
-
} catch {}
|
|
287
|
-
}
|
|
207
|
+
return (message) => {
|
|
208
|
+
if (isWorkerEvent(message)) getLogger(message.namespace).dispatch(message);
|
|
209
|
+
else if (isWorkerConsoleMessage(message)) {
|
|
210
|
+
const logger = getLogger(message.namespace || "worker");
|
|
211
|
+
const { message: msg, data } = formatConsoleArgs(message.args);
|
|
212
|
+
dispatchToLogger(logger, message.level, msg, data);
|
|
288
213
|
}
|
|
289
|
-
return {
|
|
290
|
-
...createWorkerLogger(postMessage, fullNamespace, mergedProps, {
|
|
291
|
-
parentSpanId: spanId,
|
|
292
|
-
traceId: spanTraceId
|
|
293
|
-
}),
|
|
294
|
-
spanData,
|
|
295
|
-
end: endSpan,
|
|
296
|
-
[Symbol.dispose]: endSpan
|
|
297
|
-
};
|
|
298
|
-
}
|
|
299
|
-
return {
|
|
300
|
-
name: namespace,
|
|
301
|
-
props: Object.freeze({ ...props }),
|
|
302
|
-
spanData: null,
|
|
303
|
-
trace: (msg, data) => log("trace", msg, data),
|
|
304
|
-
debug: (msg, data) => log("debug", msg, data),
|
|
305
|
-
info: (msg, data) => log("info", msg, data),
|
|
306
|
-
warn: (msg, data) => log("warn", msg, data),
|
|
307
|
-
error: (msgOrError, dataOrMsg, extraData) => {
|
|
308
|
-
if (msgOrError instanceof Error) if (typeof dataOrMsg === "string") log("error", dataOrMsg, {
|
|
309
|
-
...extraData,
|
|
310
|
-
error_type: msgOrError.name,
|
|
311
|
-
error_message: msgOrError.message,
|
|
312
|
-
error_stack: msgOrError.stack,
|
|
313
|
-
error_code: msgOrError.code
|
|
314
|
-
});
|
|
315
|
-
else log("error", msgOrError.message, {
|
|
316
|
-
...dataOrMsg,
|
|
317
|
-
error_type: msgOrError.name,
|
|
318
|
-
error_stack: msgOrError.stack,
|
|
319
|
-
error_code: msgOrError.code
|
|
320
|
-
});
|
|
321
|
-
else log("error", msgOrError, dataOrMsg);
|
|
322
|
-
},
|
|
323
|
-
logger(childNamespace, childProps) {
|
|
324
|
-
return createWorkerLogger(postMessage, childNamespace ? `${namespace}:${childNamespace}` : namespace, {
|
|
325
|
-
...props,
|
|
326
|
-
...childProps
|
|
327
|
-
}, options);
|
|
328
|
-
},
|
|
329
|
-
span: createSpan,
|
|
330
|
-
child(context) {
|
|
331
|
-
if (typeof context === "string") return this.logger(context);
|
|
332
|
-
return createWorkerLogger(postMessage, namespace, {
|
|
333
|
-
...props,
|
|
334
|
-
...context
|
|
335
|
-
}, options);
|
|
336
|
-
},
|
|
337
|
-
end() {}
|
|
338
214
|
};
|
|
339
215
|
}
|
|
340
216
|
/** Safely stringify a value, handling circular refs and BigInt */
|
|
@@ -394,8 +270,6 @@ function dispatchToLogger(logger, level, message, data) {
|
|
|
394
270
|
* worker.onmessage = (e) => {
|
|
395
271
|
* if (e.data.type === "console") {
|
|
396
272
|
* handleConsole(e.data)
|
|
397
|
-
* } else {
|
|
398
|
-
* // Handle other message types
|
|
399
273
|
* }
|
|
400
274
|
* }
|
|
401
275
|
* ```
|
|
@@ -417,55 +291,7 @@ function createWorkerConsoleHandler(options = {}) {
|
|
|
417
291
|
dispatchToLogger(logger, message.level, msg, data);
|
|
418
292
|
};
|
|
419
293
|
}
|
|
420
|
-
/**
|
|
421
|
-
* Create a handler for worker logger messages (logs and spans).
|
|
422
|
-
*
|
|
423
|
-
* Use this on the main thread to receive and output messages from workers
|
|
424
|
-
* that use createWorkerLogger.
|
|
425
|
-
*
|
|
426
|
-
* @param options - Handler options
|
|
427
|
-
* @returns Handler function to call with worker messages
|
|
428
|
-
*
|
|
429
|
-
* @example
|
|
430
|
-
* ```typescript
|
|
431
|
-
* import { createWorkerLogHandler, isWorkerMessage } from "loggily/worker"
|
|
432
|
-
*
|
|
433
|
-
* const handleLog = createWorkerLogHandler()
|
|
434
|
-
*
|
|
435
|
-
* worker.onmessage = (e) => {
|
|
436
|
-
* if (isWorkerMessage(e.data)) {
|
|
437
|
-
* handleLog(e.data)
|
|
438
|
-
* } else {
|
|
439
|
-
* // Handle other message types
|
|
440
|
-
* }
|
|
441
|
-
* }
|
|
442
|
-
* ```
|
|
443
|
-
*/
|
|
444
|
-
function createWorkerLogHandler(options = {}) {
|
|
445
|
-
const loggers = /* @__PURE__ */ new Map();
|
|
446
|
-
function getLogger(namespace) {
|
|
447
|
-
let logger = loggers.get(namespace);
|
|
448
|
-
if (!logger) {
|
|
449
|
-
logger = createLogger(namespace);
|
|
450
|
-
loggers.set(namespace, logger);
|
|
451
|
-
}
|
|
452
|
-
return logger;
|
|
453
|
-
}
|
|
454
|
-
return (message) => {
|
|
455
|
-
if (isWorkerConsoleMessage(message)) {
|
|
456
|
-
const logger = getLogger(message.namespace || "worker");
|
|
457
|
-
const { message: msg, data } = formatConsoleArgs(message.args);
|
|
458
|
-
dispatchToLogger(logger, message.level, msg, data);
|
|
459
|
-
} else if (isWorkerLogMessage(message)) dispatchToLogger(getLogger(message.namespace), message.level, message.message, message.data);
|
|
460
|
-
else if (isWorkerSpanMessage(message)) {
|
|
461
|
-
if (message.event === "end") (getLogger(message.namespace).span?.(void 0, {
|
|
462
|
-
...message.props,
|
|
463
|
-
...message.spanData
|
|
464
|
-
}))?.end();
|
|
465
|
-
}
|
|
466
|
-
};
|
|
467
|
-
}
|
|
468
294
|
//#endregion
|
|
469
|
-
export { createWorkerConsoleHandler, createWorkerLogHandler, createWorkerLogger, forwardConsole, isWorkerConsoleMessage,
|
|
295
|
+
export { createWorkerConsoleHandler, createWorkerLogHandler, createWorkerLogger, forwardConsole, handleWorkerEvents, isWorkerConsoleMessage, isWorkerEvent, isWorkerLogEvent, isWorkerMessage, isWorkerSpanEvent, restoreConsole, workerTransportStage };
|
|
470
296
|
|
|
471
297
|
//# sourceMappingURL=worker.mjs.map
|
package/dist/worker.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker.mjs","names":[],"sources":["../src/worker.ts"],"sourcesContent":["/**\n * Worker Thread Logger/Console Forwarding\n *\n * Provides utilities to forward loggily and console.* output from worker threads\n * to the main thread, ensuring proper integration with DEBUG_LOG and log files.\n *\n * ## Full Logger Forwarding (Recommended)\n *\n * @example Worker side:\n * ```typescript\n * import { createWorkerLogger } from \"loggily/worker\"\n * const log = createWorkerLogger(postMessage, \"km:worker:parse\")\n *\n * log.info(\"processing\", { file: \"test.md\" })\n * {\n * using span = log.span(\"parse\")\n * // ... work ...\n * span.spanData.lines = 100\n * }\n * ```\n *\n * @example Main thread side:\n * ```typescript\n * import { createWorkerLogHandler } from \"loggily/worker\"\n *\n * const handleLog = createWorkerLogHandler()\n * worker.onmessage = (e) => {\n * if (e.data.type === \"log\" || e.data.type === \"span\") handleLog(e.data)\n * }\n * ```\n *\n * ## Console Forwarding (Simple)\n *\n * @example Worker side:\n * ```typescript\n * import { forwardConsole } from \"loggily/worker\"\n * forwardConsole(postMessage)\n *\n * console.log(\"message\") // Forwarded to main thread\n * ```\n */\n\nimport {\n createLogger,\n createSpanDataProxy,\n type ConditionalLogger,\n type LazyMessage,\n type Logger,\n type SpanLogger,\n type SpanData,\n} from \"./index.ts\"\n\n// ============ Message Protocol ============\n\n/** Message sent from worker to main thread for console output */\nexport interface WorkerConsoleMessage {\n type: \"console\"\n level: \"log\" | \"debug\" | \"info\" | \"warn\" | \"error\" | \"trace\"\n namespace?: string\n args: unknown[]\n timestamp: number\n}\n\n/** Message sent from worker to main thread for structured log output */\nexport interface WorkerLogMessage {\n type: \"log\"\n level: \"trace\" | \"debug\" | \"info\" | \"warn\" | \"error\"\n namespace: string\n message: string\n data?: Record<string, unknown>\n timestamp: number\n}\n\n/** Message sent from worker to main thread for span events */\nexport interface WorkerSpanMessage {\n type: \"span\"\n event: \"start\" | \"end\"\n namespace: string\n spanId: string\n traceId: string\n parentId: string | null\n startTime: number\n endTime?: number\n duration?: number\n props: Record<string, unknown>\n spanData: Record<string, unknown>\n timestamp: number\n}\n\n/** Union type for all worker messages */\nexport type WorkerMessage = WorkerConsoleMessage | WorkerLogMessage | WorkerSpanMessage\n\n/** Type guard for WorkerConsoleMessage */\nexport function isWorkerConsoleMessage(msg: unknown): msg is WorkerConsoleMessage {\n return (\n typeof msg === \"object\" &&\n (msg as WorkerConsoleMessage)?.type === \"console\" &&\n typeof (msg as WorkerConsoleMessage).level === \"string\" &&\n Array.isArray((msg as WorkerConsoleMessage).args)\n )\n}\n\n/** Type guard for WorkerLogMessage */\nexport function isWorkerLogMessage(msg: unknown): msg is WorkerLogMessage {\n return (\n typeof msg === \"object\" &&\n (msg as WorkerLogMessage)?.type === \"log\" &&\n typeof (msg as WorkerLogMessage).level === \"string\" &&\n typeof (msg as WorkerLogMessage).namespace === \"string\"\n )\n}\n\n/** Type guard for WorkerSpanMessage */\nexport function isWorkerSpanMessage(msg: unknown): msg is WorkerSpanMessage {\n return (\n typeof msg === \"object\" &&\n (msg as WorkerSpanMessage)?.type === \"span\" &&\n typeof (msg as WorkerSpanMessage).event === \"string\"\n )\n}\n\n/** Type guard for any worker message */\nexport function isWorkerMessage(msg: unknown): msg is WorkerMessage {\n return isWorkerConsoleMessage(msg) || isWorkerLogMessage(msg) || isWorkerSpanMessage(msg)\n}\n\n// ============ Worker Side ============\n\ntype PostMessageFn = (message: WorkerConsoleMessage) => void\n\n/** Store original console methods for restoration */\nlet originalConsole: typeof console | null = null\n\n/**\n * Serialize a value for transmission via postMessage.\n * Handles non-serializable values like functions and circular references.\n */\nfunction serializeArg(arg: unknown, depth = 0): unknown {\n // Prevent infinite recursion\n if (depth > 5) return \"[max depth]\"\n\n if (arg === null || arg === undefined) return arg\n if (typeof arg === \"function\") return `[Function: ${arg.name || \"anonymous\"}]`\n if (typeof arg === \"symbol\") return arg.toString()\n if (typeof arg === \"bigint\") return arg.toString() + \"n\"\n\n if (arg instanceof Error) {\n return {\n name: arg.name,\n message: arg.message,\n stack: arg.stack,\n }\n }\n\n if (Array.isArray(arg)) {\n return arg.map((v) => serializeArg(v, depth + 1))\n }\n\n if (typeof arg === \"object\") {\n try {\n // Try structured clone first (handles most cases)\n structuredClone(arg)\n return arg\n } catch {\n // Fall back to manual serialization\n const result: Record<string, unknown> = {}\n const seen = new Set<object>()\n seen.add(arg)\n\n for (const [key, value] of Object.entries(arg)) {\n if (typeof value === \"object\" && value !== null && seen.has(value)) {\n result[key] = \"[Circular]\"\n } else {\n result[key] = serializeArg(value, depth + 1)\n }\n }\n return result\n }\n }\n\n return arg\n}\n\n/**\n * Forward console.* calls from worker to main thread.\n *\n * Monkey-patches console methods to send messages via postMessage.\n * Call this at the start of your worker script.\n *\n * @param postMessage - The worker's postMessage function\n * @param namespace - Optional namespace for log messages (e.g., \"km:worker:parse\")\n *\n * @example\n * ```typescript\n * // At top of worker file:\n * import { forwardConsole } from \"loggily/worker\"\n * forwardConsole(postMessage, \"km:worker:parse\")\n *\n * // Now all console.* calls are forwarded:\n * console.log(\"processing\", { file: \"test.md\" })\n * console.error(new Error(\"failed\"))\n * ```\n */\nexport function forwardConsole(postMessage: PostMessageFn, namespace?: string): void {\n // Store original console for restoration\n if (!originalConsole) {\n originalConsole = { ...console }\n }\n\n const levels = [\"log\", \"debug\", \"info\", \"warn\", \"error\", \"trace\"] as const\n\n for (const level of levels) {\n console[level] = (...args: unknown[]) => {\n const serializedArgs = args.map((arg) => serializeArg(arg))\n\n try {\n postMessage({\n type: \"console\",\n level,\n namespace,\n args: serializedArgs,\n timestamp: Date.now(),\n })\n } catch {\n // postMessage might fail if worker is shutting down\n // Fall back to original console\n originalConsole?.[level](...args)\n }\n }\n }\n}\n\n/**\n * Restore original console methods.\n * Call this if you need to disable console forwarding.\n */\nexport function restoreConsole(): void {\n if (originalConsole) {\n Object.assign(console, originalConsole)\n originalConsole = null\n }\n}\n\n// ============ Worker Logger (Full API) ============\n\ntype PostMessageAnyFn = (message: WorkerMessage) => void\n\nlet workerSpanIdCounter = 0\nlet workerTraceIdCounter = 0\n\nfunction generateWorkerSpanId(): string {\n return `wsp_${(++workerSpanIdCounter).toString(36)}`\n}\n\nfunction generateWorkerTraceId(): string {\n return `wtr_${(++workerTraceIdCounter).toString(36)}`\n}\n\n/** Reset worker ID counters (for testing) */\nexport function resetWorkerIds(): void {\n workerSpanIdCounter = 0\n workerTraceIdCounter = 0\n}\n\ninterface WorkerLoggerOptions {\n /** Parent span ID for nested spans */\n parentSpanId?: string | null\n /** Trace ID for distributed tracing */\n traceId?: string | null\n}\n\n/**\n * Create a logger instance for use in a worker thread.\n *\n * All log calls and span events are forwarded to the main thread via postMessage.\n * The main thread should use createWorkerLogHandler to process these messages.\n *\n * @param postMessage - The worker's postMessage function\n * @param namespace - Logger namespace (e.g., \"km:worker:parse\")\n * @param props - Optional initial props\n * @param options - Optional configuration\n *\n * @example\n * ```typescript\n * import { createWorkerLogger } from \"loggily/worker\"\n *\n * const log = createWorkerLogger(postMessage, \"km:worker:parse\")\n *\n * log.info(\"starting parse\", { file: \"test.md\" })\n *\n * {\n * using span = log.span(\"process\")\n * span.info(\"processing...\")\n * span.spanData.lineCount = 100\n * }\n * // Span end event automatically sent to main thread\n * ```\n */\nexport function createWorkerLogger(\n postMessage: PostMessageAnyFn,\n namespace: string,\n props: Record<string, unknown> = {},\n options: WorkerLoggerOptions = {},\n): Logger {\n const { parentSpanId = null, traceId = null } = options\n\n function log(\n level: \"trace\" | \"debug\" | \"info\" | \"warn\" | \"error\",\n message: LazyMessage,\n data?: Record<string, unknown>,\n ): void {\n const resolved = typeof message === \"function\" ? message() : message\n try {\n postMessage({\n type: \"log\",\n level,\n namespace,\n message: resolved,\n data: data ? { ...props, ...data } : Object.keys(props).length > 0 ? props : undefined,\n timestamp: Date.now(),\n })\n } catch (err) {\n // postMessage failed (e.g. uncloneable data) — send a diagnostic fallback\n try {\n postMessage({\n type: \"log\",\n level: \"error\",\n namespace,\n message: `postMessage failed for ${level} \"${resolved}\": ${err instanceof Error ? err.message : String(err)}`,\n timestamp: Date.now(),\n })\n } catch {\n // Worker might be shutting down — truly nothing we can do\n }\n }\n }\n\n function createSpan(spanNamespace?: string, spanProps?: Record<string, unknown>): SpanLogger {\n const fullNamespace = spanNamespace ? `${namespace}:${spanNamespace}` : namespace\n const mergedProps = { ...props, ...spanProps }\n const spanId = generateWorkerSpanId()\n const spanTraceId = traceId || generateWorkerTraceId()\n const startTime = Date.now()\n\n // Mutable span data that can be set by the user\n const customSpanData: Record<string, unknown> = {}\n\n // Send span start event\n try {\n postMessage({\n type: \"span\",\n event: \"start\",\n namespace: fullNamespace,\n spanId,\n traceId: spanTraceId,\n parentId: parentSpanId,\n startTime,\n props: mergedProps,\n spanData: {},\n timestamp: Date.now(),\n })\n } catch (err) {\n // postMessage failed (e.g. uncloneable props) — send a diagnostic fallback\n try {\n postMessage({\n type: \"log\",\n level: \"error\",\n namespace: fullNamespace,\n message: `postMessage failed for span start \"${fullNamespace}\": ${err instanceof Error ? err.message : String(err)}`,\n timestamp: Date.now(),\n })\n } catch {\n // Worker might be shutting down\n }\n }\n\n let ended = false\n\n const spanData: SpanData = createSpanDataProxy(\n () => ({\n id: spanId,\n traceId: spanTraceId,\n parentId: parentSpanId,\n startTime,\n endTime: ended ? Date.now() : null,\n duration: Date.now() - startTime,\n }),\n customSpanData,\n )\n\n function endSpan(): void {\n if (ended) return\n ended = true\n\n const endTime = Date.now()\n const duration = endTime - startTime\n\n try {\n postMessage({\n type: \"span\",\n event: \"end\",\n namespace: fullNamespace,\n spanId,\n traceId: spanTraceId,\n parentId: parentSpanId,\n startTime,\n endTime,\n duration,\n props: mergedProps,\n spanData: customSpanData,\n timestamp: Date.now(),\n })\n } catch (err) {\n // postMessage failed (e.g. uncloneable spanData) — send a diagnostic fallback\n try {\n postMessage({\n type: \"log\",\n level: \"error\",\n namespace: fullNamespace,\n message: `postMessage failed for span end \"${fullNamespace}\" (${duration}ms): ${err instanceof Error ? err.message : String(err)}`,\n timestamp: Date.now(),\n })\n } catch {\n // Worker might be shutting down\n }\n }\n }\n\n // Create child logger for the span\n const childLogger = createWorkerLogger(postMessage, fullNamespace, mergedProps, {\n parentSpanId: spanId,\n traceId: spanTraceId,\n })\n\n const spanLogger: SpanLogger = {\n ...childLogger,\n spanData,\n end: endSpan,\n [Symbol.dispose]: endSpan,\n }\n\n return spanLogger\n }\n\n const logger: Logger = {\n name: namespace,\n props: Object.freeze({ ...props }),\n spanData: null,\n\n trace: (msg, data) => log(\"trace\", msg, data),\n debug: (msg, data) => log(\"debug\", msg, data),\n info: (msg, data) => log(\"info\", msg, data),\n warn: (msg, data) => log(\"warn\", msg, data),\n error: (\n msgOrError: LazyMessage | Error,\n dataOrMsg?: Record<string, unknown> | string,\n extraData?: Record<string, unknown>,\n ) => {\n if (msgOrError instanceof Error) {\n if (typeof dataOrMsg === \"string\") {\n log(\"error\", dataOrMsg, {\n ...extraData,\n error_type: msgOrError.name,\n error_message: msgOrError.message,\n error_stack: msgOrError.stack,\n error_code: (msgOrError as NodeJS.ErrnoException).code,\n })\n } else {\n log(\"error\", msgOrError.message, {\n ...(dataOrMsg as Record<string, unknown>),\n error_type: msgOrError.name,\n error_stack: msgOrError.stack,\n error_code: (msgOrError as NodeJS.ErrnoException).code,\n })\n }\n } else {\n log(\"error\", msgOrError, dataOrMsg as Record<string, unknown>)\n }\n },\n\n logger(childNamespace?: string, childProps?: Record<string, unknown>): ConditionalLogger {\n const fullNamespace = childNamespace ? `${namespace}:${childNamespace}` : namespace\n return createWorkerLogger(\n postMessage,\n fullNamespace,\n { ...props, ...childProps },\n options,\n ) as unknown as ConditionalLogger\n },\n\n span: createSpan,\n\n child(context: Record<string, unknown> | string): ConditionalLogger {\n if (typeof context === \"string\") {\n return this.logger(context)\n }\n return createWorkerLogger(\n postMessage,\n namespace,\n { ...props, ...context },\n options,\n ) as unknown as ConditionalLogger\n },\n\n end(): void {\n // No-op for non-span logger\n },\n }\n\n return logger\n}\n\n// ============ Main Thread Side ============\n\nexport interface WorkerConsoleHandlerOptions {\n /** Default namespace if message doesn't include one */\n defaultNamespace?: string\n /** Custom logger to use (defaults to creating one with the namespace) */\n logger?: Logger\n}\n\n/** Safely stringify a value, handling circular refs and BigInt */\nfunction safeStringify(value: unknown): string {\n try {\n return JSON.stringify(value)\n } catch {\n return String(value)\n }\n}\n\n/** Format console args into a message string and optional data object */\nfunction formatConsoleArgs(args: unknown[]): { message: string; data: Record<string, unknown> | undefined } {\n const message =\n args.length === 0\n ? \"\"\n : args.length === 1 && typeof args[0] === \"string\"\n ? args[0]\n : args.map((a) => (typeof a === \"string\" ? a : safeStringify(a))).join(\" \")\n\n const lastArg = args[args.length - 1]\n const data =\n args.length > 1 && typeof lastArg === \"object\" && lastArg !== null && !Array.isArray(lastArg)\n ? (lastArg as Record<string, unknown>)\n : undefined\n\n return { message, data }\n}\n\n/** Dispatch a message to a logger at the given console level */\nfunction dispatchToLogger(\n logger: ConditionalLogger,\n level: \"log\" | \"debug\" | \"info\" | \"warn\" | \"error\" | \"trace\",\n message: string,\n data?: Record<string, unknown>,\n): void {\n switch (level) {\n case \"trace\":\n logger.trace?.(message, data)\n break\n case \"debug\":\n logger.debug?.(message, data)\n break\n case \"info\":\n case \"log\":\n logger.info?.(message, data)\n break\n case \"warn\":\n logger.warn?.(message, data)\n break\n case \"error\":\n logger.error?.(message, data)\n break\n }\n}\n\n/**\n * Create a handler for worker console messages.\n *\n * Use this on the main thread to receive and output messages from workers.\n *\n * @param options - Handler options\n * @returns Handler function to call with worker messages\n *\n * @example\n * ```typescript\n * import { createWorkerConsoleHandler } from \"loggily/worker\"\n *\n * const handleConsole = createWorkerConsoleHandler({\n * defaultNamespace: \"km:worker:parse\"\n * })\n *\n * worker.onmessage = (e) => {\n * if (e.data.type === \"console\") {\n * handleConsole(e.data)\n * } else {\n * // Handle other message types\n * }\n * }\n * ```\n */\nexport function createWorkerConsoleHandler(\n options: WorkerConsoleHandlerOptions = {},\n): (message: WorkerConsoleMessage) => void {\n const loggers = new Map<string, ConditionalLogger>()\n\n function getLogger(namespace?: string): ConditionalLogger {\n const ns = namespace || options.defaultNamespace || \"worker\"\n\n let logger = loggers.get(ns)\n if (!logger) {\n logger = options.logger ? (options.logger as ConditionalLogger) : createLogger(ns)\n loggers.set(ns, logger)\n }\n return logger\n }\n\n return (message: WorkerConsoleMessage) => {\n const logger = getLogger(message.namespace)\n const { message: msg, data } = formatConsoleArgs(message.args)\n dispatchToLogger(logger, message.level, msg, data)\n }\n}\n\n// ============ Full Logger Handler ============\n\nexport interface WorkerLogHandlerOptions {\n /** @deprecated Span output is now controlled by TRACE env var */\n enableSpans?: boolean\n}\n\n/**\n * Create a handler for worker logger messages (logs and spans).\n *\n * Use this on the main thread to receive and output messages from workers\n * that use createWorkerLogger.\n *\n * @param options - Handler options\n * @returns Handler function to call with worker messages\n *\n * @example\n * ```typescript\n * import { createWorkerLogHandler, isWorkerMessage } from \"loggily/worker\"\n *\n * const handleLog = createWorkerLogHandler()\n *\n * worker.onmessage = (e) => {\n * if (isWorkerMessage(e.data)) {\n * handleLog(e.data)\n * } else {\n * // Handle other message types\n * }\n * }\n * ```\n */\nexport function createWorkerLogHandler(options: WorkerLogHandlerOptions = {}): (message: WorkerMessage) => void {\n const loggers = new Map<string, ConditionalLogger>()\n\n function getLogger(namespace: string): ConditionalLogger {\n let logger = loggers.get(namespace)\n if (!logger) {\n logger = createLogger(namespace)\n loggers.set(namespace, logger)\n }\n return logger\n }\n\n return (message: WorkerMessage) => {\n if (isWorkerConsoleMessage(message)) {\n const logger = getLogger(message.namespace || \"worker\")\n const { message: msg, data } = formatConsoleArgs(message.args)\n dispatchToLogger(logger, message.level, msg, data)\n } else if (isWorkerLogMessage(message)) {\n const logger = getLogger(message.namespace)\n dispatchToLogger(logger, message.level, message.message, message.data)\n } else if (isWorkerSpanMessage(message)) {\n if (message.event === \"end\") {\n const logger = getLogger(message.namespace)\n const span = logger.span?.(undefined, { ...message.props, ...message.spanData })\n span?.end()\n }\n // Start events are informational only on main thread\n // (the actual timing happens in the worker)\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"worker.mjs","names":[],"sources":["../src/worker.ts"],"sourcesContent":["/**\n * Worker Thread Logger/Console Forwarding\n *\n * Pipeline-based worker logging: worker loggers use a postMessage transport\n * so events flow through the main thread's pipeline for output.\n *\n * ## Structured Logger (Recommended)\n *\n * @example Worker side:\n * ```typescript\n * import { createWorkerLogger } from \"loggily/worker\"\n * const log = createWorkerLogger(postMessage, \"km:worker:parse\")\n *\n * log.info?.(\"processing\", { file: \"test.md\" })\n * {\n * using span = log.span?.(\"parse\")\n * // ... work ...\n * span.spanData.lines = 100\n * }\n * ```\n *\n * @example Main thread side:\n * ```typescript\n * import { createWorkerLogHandler } from \"loggily/worker\"\n *\n * const handleLog = createWorkerLogHandler()\n * worker.onmessage = (e) => handleLog(e.data)\n * ```\n *\n * ## Console Forwarding (Simple)\n *\n * @example Worker side:\n * ```typescript\n * import { forwardConsole } from \"loggily/worker\"\n * forwardConsole(postMessage)\n *\n * console.log(\"message\") // Forwarded to main thread\n * ```\n */\n\nimport { createLogger, baseCreateLogger, pipe, withSpans, type ConditionalLogger } from \"./core.js\"\nimport type { Event, LogEvent, SpanEvent, Stage, ConfigElement } from \"./pipeline.js\"\n\n// ============ Console Message Type ============\n\n/** Message sent from worker to main thread for console output */\nexport interface WorkerConsoleMessage {\n type: \"console\"\n level: \"log\" | \"debug\" | \"info\" | \"warn\" | \"error\" | \"trace\"\n namespace?: string\n args: unknown[]\n timestamp: number\n}\n\n// ============ Type Guards ============\n\n/** Type guard for LogEvent (structured log from worker) */\nexport function isWorkerLogEvent(msg: unknown): msg is LogEvent {\n return typeof msg === \"object\" && (msg as LogEvent)?.kind === \"log\"\n}\n\n/** Type guard for SpanEvent (span from worker) */\nexport function isWorkerSpanEvent(msg: unknown): msg is SpanEvent {\n return typeof msg === \"object\" && (msg as SpanEvent)?.kind === \"span\"\n}\n\n/** Type guard for any pipeline Event (log or span) */\nexport function isWorkerEvent(msg: unknown): msg is Event {\n return isWorkerLogEvent(msg) || isWorkerSpanEvent(msg)\n}\n\n/** Type guard for WorkerConsoleMessage */\nexport function isWorkerConsoleMessage(msg: unknown): msg is WorkerConsoleMessage {\n return (\n typeof msg === \"object\" &&\n (msg as WorkerConsoleMessage)?.type === \"console\" &&\n typeof (msg as WorkerConsoleMessage).level === \"string\" &&\n Array.isArray((msg as WorkerConsoleMessage).args)\n )\n}\n\n/** Type guard for any worker message (console or pipeline event) */\nexport function isWorkerMessage(msg: unknown): msg is WorkerConsoleMessage | Event {\n return isWorkerConsoleMessage(msg) || isWorkerEvent(msg)\n}\n\n// ============ Worker Side: Console Forwarding ============\n\ntype PostMessageFn = (message: WorkerConsoleMessage) => void\n\n/** Store original console methods for restoration */\nlet originalConsole: typeof console | null = null\n\n/**\n * Forward console.* calls from worker to main thread via postMessage.\n *\n * Monkey-patches console methods. postMessage uses structuredClone,\n * which handles most values natively. If cloning fails (functions,\n * symbols), falls back to original console.\n *\n * @example\n * ```typescript\n * import { forwardConsole } from \"loggily/worker\"\n * forwardConsole(postMessage, \"km:worker:parse\")\n * console.log(\"processing\", { file: \"test.md\" })\n * ```\n */\nexport function forwardConsole(postMessage: PostMessageFn, namespace?: string): void {\n if (!originalConsole) {\n originalConsole = { ...console }\n }\n\n for (const level of [\"log\", \"debug\", \"info\", \"warn\", \"error\", \"trace\"] as const) {\n console[level] = (...args: unknown[]) => {\n try {\n // Sanitize non-cloneable values before postMessage (structuredClone rejects them)\n const safe = args.map((a) =>\n typeof a === \"function\"\n ? `[Function: ${a.name || \"anonymous\"}]`\n : typeof a === \"symbol\"\n ? a.toString()\n : a instanceof Error\n ? { name: a.name, message: a.message, stack: a.stack }\n : a,\n )\n postMessage({ type: \"console\", level, namespace, args: safe, timestamp: Date.now() })\n } catch {\n originalConsole?.[level](...args)\n }\n }\n }\n}\n\n/**\n * Restore original console methods.\n * Call this if you need to disable console forwarding.\n */\nexport function restoreConsole(): void {\n if (originalConsole) {\n Object.assign(console, originalConsole)\n originalConsole = null\n }\n}\n\n// ============ Worker Side: Pipeline Transport ============\n\n/**\n * Create a pipeline stage that forwards events via postMessage.\n *\n * Events are plain JSON objects that survive structuredClone natively.\n * The stage consumes events (returns null) so nothing is output locally.\n * The main thread uses handleWorkerEvents() or createWorkerLogHandler()\n * to dispatch them through a local logger pipeline.\n */\nexport function workerTransportStage(postMessage: (msg: unknown) => void): Stage {\n return (event: Event): null => {\n try {\n postMessage(event)\n } catch {\n // If postMessage fails (non-cloneable), try with JSON round-trip\n try {\n postMessage(JSON.parse(JSON.stringify(event)))\n } catch {\n // Silently drop -- worker can't communicate\n }\n }\n return null // Consume the event (no local output)\n }\n}\n\n/**\n * Create a logger for use in a worker thread.\n *\n * All log and span events are forwarded to the main thread via postMessage.\n * The main thread should use createWorkerLogHandler() to process these messages.\n *\n * @param postMessage - The worker's postMessage function\n * @param namespace - Logger namespace (e.g., \"km:worker:parse\")\n * @param props - Optional initial props\n *\n * @example\n * ```typescript\n * import { createWorkerLogger } from \"loggily/worker\"\n *\n * const log = createWorkerLogger(postMessage, \"km:worker:parse\")\n *\n * log.info?.(\"starting parse\", { file: \"test.md\" })\n *\n * {\n * using span = log.span?.(\"process\")\n * span.info?.(\"processing...\")\n * span.spanData.count = 100\n * }\n * // Span end event automatically sent to main thread\n * ```\n */\nexport function createWorkerLogger(\n postMessage: (msg: unknown) => void,\n namespace: string,\n props?: Record<string, unknown>,\n): ConditionalLogger {\n const transport = workerTransportStage(postMessage)\n const config: ConfigElement[] = [{ level: \"trace\" as const }, transport]\n const factory = pipe(baseCreateLogger, withSpans())\n const logger = factory(namespace, config)\n return props ? logger.child(props) : logger\n}\n\n// ============ Main Thread Side: Event Handling ============\n\n/**\n * Create a handler that dispatches worker events to a target logger.\n *\n * Use this when you have a specific logger to dispatch through.\n *\n * @param target - Logger or object with dispatch method\n * @returns Handler function to call with worker messages\n */\nexport function handleWorkerEvents(\n target: ConditionalLogger | { dispatch(event: Event): void },\n): (msg: unknown) => void {\n return (msg: unknown) => {\n if (typeof msg !== \"object\" || msg === null) return\n const event = msg as Record<string, unknown>\n if (event.kind === \"log\" || event.kind === \"span\") {\n target.dispatch(msg as Event)\n }\n }\n}\n\n/**\n * Create a zero-config handler for worker logger messages.\n *\n * Automatically creates loggers per-namespace. For console messages,\n * formats args and dispatches through a logger.\n *\n * @returns Handler function to call with any worker message\n *\n * @example\n * ```typescript\n * import { createWorkerLogHandler } from \"loggily/worker\"\n *\n * const handleLog = createWorkerLogHandler()\n * worker.onmessage = (e) => handleLog(e.data)\n * ```\n */\nexport function createWorkerLogHandler(): (message: unknown) => void {\n const loggers = new Map<string, ConditionalLogger>()\n\n function getLogger(namespace: string): ConditionalLogger {\n let logger = loggers.get(namespace)\n if (!logger) {\n logger = createLogger(namespace)\n loggers.set(namespace, logger)\n }\n return logger\n }\n\n return (message: unknown) => {\n if (isWorkerEvent(message)) {\n const logger = getLogger(message.namespace)\n logger.dispatch(message)\n } else if (isWorkerConsoleMessage(message)) {\n const logger = getLogger(message.namespace || \"worker\")\n const { message: msg, data } = formatConsoleArgs(message.args)\n dispatchToLogger(logger, message.level, msg, data)\n }\n }\n}\n\n// ============ Main Thread Side: Console Handler ============\n\nexport interface WorkerConsoleHandlerOptions {\n /** Default namespace if message doesn't include one */\n defaultNamespace?: string\n /** Custom logger to use (defaults to creating one with the namespace) */\n logger?: { name: string; dispatch(event: Event): void }\n}\n\n/** Safely stringify a value, handling circular refs and BigInt */\nfunction safeStringify(value: unknown): string {\n try {\n return JSON.stringify(value)\n } catch {\n return String(value)\n }\n}\n\n/** Format console args into a message string and optional data object */\nfunction formatConsoleArgs(args: unknown[]): { message: string; data: Record<string, unknown> | undefined } {\n const message =\n args.length === 0\n ? \"\"\n : args.length === 1 && typeof args[0] === \"string\"\n ? args[0]\n : args.map((a) => (typeof a === \"string\" ? a : safeStringify(a))).join(\" \")\n\n const lastArg = args[args.length - 1]\n const data =\n args.length > 1 && typeof lastArg === \"object\" && lastArg !== null && !Array.isArray(lastArg)\n ? (lastArg as Record<string, unknown>)\n : undefined\n\n return { message, data }\n}\n\n/** Dispatch a message to a logger at the given console level */\nfunction dispatchToLogger(\n logger: ConditionalLogger,\n level: \"log\" | \"debug\" | \"info\" | \"warn\" | \"error\" | \"trace\",\n message: string,\n data?: Record<string, unknown>,\n): void {\n switch (level) {\n case \"trace\":\n logger.trace?.(message, data)\n break\n case \"debug\":\n logger.debug?.(message, data)\n break\n case \"info\":\n case \"log\":\n logger.info?.(message, data)\n break\n case \"warn\":\n logger.warn?.(message, data)\n break\n case \"error\":\n logger.error?.(message, data)\n break\n }\n}\n\n/**\n * Create a handler for worker console messages.\n *\n * Use this on the main thread to receive and output messages from workers.\n *\n * @param options - Handler options\n * @returns Handler function to call with worker messages\n *\n * @example\n * ```typescript\n * import { createWorkerConsoleHandler } from \"loggily/worker\"\n *\n * const handleConsole = createWorkerConsoleHandler({\n * defaultNamespace: \"km:worker:parse\"\n * })\n *\n * worker.onmessage = (e) => {\n * if (e.data.type === \"console\") {\n * handleConsole(e.data)\n * }\n * }\n * ```\n */\nexport function createWorkerConsoleHandler(\n options: WorkerConsoleHandlerOptions = {},\n): (message: WorkerConsoleMessage) => void {\n const loggers = new Map<string, ConditionalLogger>()\n\n function getLogger(namespace?: string): ConditionalLogger {\n const ns = namespace || options.defaultNamespace || \"worker\"\n\n let logger = loggers.get(ns)\n if (!logger) {\n logger = options.logger ? (options.logger as ConditionalLogger) : createLogger(ns)\n loggers.set(ns, logger)\n }\n return logger\n }\n\n return (message: WorkerConsoleMessage) => {\n const logger = getLogger(message.namespace)\n const { message: msg, data } = formatConsoleArgs(message.args)\n dispatchToLogger(logger, message.level, msg, data)\n }\n}\n"],"mappings":"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"}
|