@iii-dev/helpers 0.19.4-alpha.2 → 0.19.4-alpha.4
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-CEjPaG4S.d.cts +177 -0
- package/dist/index-KWqP5kbF.d.mts +177 -0
- package/dist/observability/index.cjs +490 -0
- package/dist/observability/index.cjs.map +1 -0
- package/dist/observability/index.d.cts +244 -0
- package/dist/observability/index.d.mts +244 -0
- package/dist/observability/index.mjs +455 -0
- package/dist/observability/index.mjs.map +1 -0
- package/dist/observability/internal.cjs +5 -0
- package/dist/observability/internal.d.cts +2 -0
- package/dist/observability/internal.d.mts +2 -0
- package/dist/observability/internal.mjs +3 -0
- package/dist/telemetry-system-CLZLK3nL.mjs +1126 -0
- package/dist/telemetry-system-CLZLK3nL.mjs.map +1 -0
- package/dist/telemetry-system-CY8_emop.cjs +1305 -0
- package/dist/telemetry-system-CY8_emop.cjs.map +1 -0
- package/dist/worker-connection-manager/index.d.cts +6 -6
- package/dist/worker-connection-manager/index.d.mts +6 -6
- package/package.json +36 -1
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
const require_telemetry_system = require('../telemetry-system-CY8_emop.cjs');
|
|
3
|
+
let _opentelemetry_api_logs = require("@opentelemetry/api-logs");
|
|
4
|
+
let _opentelemetry_api = require("@opentelemetry/api");
|
|
5
|
+
let node_perf_hooks = require("node:perf_hooks");
|
|
6
|
+
|
|
7
|
+
//#region src/observability/logger.ts
|
|
8
|
+
/**
|
|
9
|
+
* Structured logger that emits logs as OpenTelemetry LogRecords.
|
|
10
|
+
*
|
|
11
|
+
* Every log call automatically captures the active trace and span context,
|
|
12
|
+
* correlating your logs with distributed traces without any manual wiring.
|
|
13
|
+
* When OTel is not initialized, Logger gracefully falls back to `console.*`.
|
|
14
|
+
*
|
|
15
|
+
* Pass structured data as the second argument to any log method. Using an
|
|
16
|
+
* object of key-value pairs (instead of string interpolation) lets you
|
|
17
|
+
* filter, aggregate, and build dashboards in your observability backend.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* import { Logger } from 'iii-sdk'
|
|
22
|
+
*
|
|
23
|
+
* const logger = new Logger()
|
|
24
|
+
*
|
|
25
|
+
* // Basic logging — trace context is injected automatically
|
|
26
|
+
* logger.info('Worker connected')
|
|
27
|
+
*
|
|
28
|
+
* // Structured context for dashboards and alerting
|
|
29
|
+
* logger.info('Order processed', { orderId: 'ord_123', amount: 49.99, currency: 'USD' })
|
|
30
|
+
* logger.warn('Retry attempt', { attempt: 3, maxRetries: 5, endpoint: '/api/charge' })
|
|
31
|
+
* logger.error('Payment failed', { orderId: 'ord_123', gateway: 'stripe', errorCode: 'card_declined' })
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
var Logger = class {
|
|
35
|
+
_otelLogger = null;
|
|
36
|
+
get otelLogger() {
|
|
37
|
+
if (!this._otelLogger) this._otelLogger = require_telemetry_system.getLogger();
|
|
38
|
+
return this._otelLogger;
|
|
39
|
+
}
|
|
40
|
+
constructor(traceId, serviceName, spanId) {
|
|
41
|
+
this.traceId = traceId;
|
|
42
|
+
this.serviceName = serviceName;
|
|
43
|
+
this.spanId = spanId;
|
|
44
|
+
}
|
|
45
|
+
emit(message, severity, data) {
|
|
46
|
+
const attributes = {};
|
|
47
|
+
const traceId = this.traceId ?? require_telemetry_system.currentTraceId();
|
|
48
|
+
const spanId = this.spanId ?? require_telemetry_system.currentSpanId();
|
|
49
|
+
if (traceId) attributes.trace_id = traceId;
|
|
50
|
+
if (spanId) attributes.span_id = spanId;
|
|
51
|
+
if (this.serviceName) attributes["service.name"] = this.serviceName;
|
|
52
|
+
if (data !== void 0) attributes["log.data"] = data;
|
|
53
|
+
if (this.otelLogger) this.otelLogger.emit({
|
|
54
|
+
severityNumber: severity,
|
|
55
|
+
body: message,
|
|
56
|
+
attributes: Object.keys(attributes).length > 0 ? attributes : void 0
|
|
57
|
+
});
|
|
58
|
+
else switch (severity) {
|
|
59
|
+
case _opentelemetry_api_logs.SeverityNumber.DEBUG:
|
|
60
|
+
console.debug(message, data);
|
|
61
|
+
break;
|
|
62
|
+
case _opentelemetry_api_logs.SeverityNumber.INFO:
|
|
63
|
+
console.info(message, data);
|
|
64
|
+
break;
|
|
65
|
+
case _opentelemetry_api_logs.SeverityNumber.WARN:
|
|
66
|
+
console.warn(message, data);
|
|
67
|
+
break;
|
|
68
|
+
case _opentelemetry_api_logs.SeverityNumber.ERROR:
|
|
69
|
+
console.error(message, data);
|
|
70
|
+
break;
|
|
71
|
+
default: console.log(message, data);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Log an info-level message.
|
|
76
|
+
*
|
|
77
|
+
* @param message - Human-readable log message.
|
|
78
|
+
* @param data - Structured context attached as OTel log attributes.
|
|
79
|
+
* Use key-value objects to enable filtering and aggregation in your
|
|
80
|
+
* observability backend (e.g. Grafana, Datadog, New Relic).
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```typescript
|
|
84
|
+
* logger.info('Order processed', { orderId: 'ord_123', status: 'completed' })
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
info(message, data) {
|
|
88
|
+
this.emit(message, _opentelemetry_api_logs.SeverityNumber.INFO, data);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Log a warning-level message.
|
|
92
|
+
*
|
|
93
|
+
* @param message - Human-readable log message.
|
|
94
|
+
* @param data - Structured context attached as OTel log attributes.
|
|
95
|
+
* Use key-value objects to enable filtering and aggregation in your
|
|
96
|
+
* observability backend (e.g. Grafana, Datadog, New Relic).
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```typescript
|
|
100
|
+
* logger.warn('Retry attempt', { attempt: 3, maxRetries: 5, endpoint: '/api/charge' })
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
warn(message, data) {
|
|
104
|
+
this.emit(message, _opentelemetry_api_logs.SeverityNumber.WARN, data);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Log an error-level message.
|
|
108
|
+
*
|
|
109
|
+
* @param message - Human-readable log message.
|
|
110
|
+
* @param data - Structured context attached as OTel log attributes.
|
|
111
|
+
* Use key-value objects to enable filtering and aggregation in your
|
|
112
|
+
* observability backend (e.g. Grafana, Datadog, New Relic).
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```typescript
|
|
116
|
+
* logger.error('Payment failed', { orderId: 'ord_123', gateway: 'stripe', errorCode: 'card_declined' })
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
error(message, data) {
|
|
120
|
+
this.emit(message, _opentelemetry_api_logs.SeverityNumber.ERROR, data);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Log a debug-level message.
|
|
124
|
+
*
|
|
125
|
+
* @param message - Human-readable log message.
|
|
126
|
+
* @param data - Structured context attached as OTel log attributes.
|
|
127
|
+
* Use key-value objects to enable filtering and aggregation in your
|
|
128
|
+
* observability backend (e.g. Grafana, Datadog, New Relic).
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```typescript
|
|
132
|
+
* logger.debug('Cache lookup', { key: 'user:42', hit: false })
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
debug(message, data) {
|
|
136
|
+
this.emit(message, _opentelemetry_api_logs.SeverityNumber.DEBUG, data);
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
//#endregion
|
|
141
|
+
//#region src/observability/http-instrumentation.ts
|
|
142
|
+
const SAFE_REQUEST_HEADERS = ["content-type", "accept"];
|
|
143
|
+
const SAFE_RESPONSE_HEADERS = ["content-type"];
|
|
144
|
+
/**
|
|
145
|
+
* Execute a fetch request inside an OTel CLIENT span.
|
|
146
|
+
*
|
|
147
|
+
* Mirrors the Rust execute_traced_request shape: injects W3C traceparent into
|
|
148
|
+
* outgoing headers, records HTTP semantic-convention attributes, and sets
|
|
149
|
+
* ERROR span status for HTTP responses with status >= 400 or network errors.
|
|
150
|
+
*/
|
|
151
|
+
async function executeTracedRequest(input, init) {
|
|
152
|
+
const tracer = init?.tracer ?? _opentelemetry_api.trace.getTracer("iii-node-sdk");
|
|
153
|
+
const rawUrl = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
|
|
154
|
+
let url;
|
|
155
|
+
try {
|
|
156
|
+
url = new URL(rawUrl);
|
|
157
|
+
} catch {
|
|
158
|
+
url = null;
|
|
159
|
+
}
|
|
160
|
+
const method = (init?.method ?? (typeof input === "object" && "method" in input ? input.method : "GET") ?? "GET").toUpperCase();
|
|
161
|
+
const name = url?.pathname ? `${method} ${url.pathname}` : method;
|
|
162
|
+
return tracer.startActiveSpan(name, {
|
|
163
|
+
kind: _opentelemetry_api.SpanKind.CLIENT,
|
|
164
|
+
attributes: {
|
|
165
|
+
"http.request.method": method,
|
|
166
|
+
"url.full": url?.toString() ?? rawUrl,
|
|
167
|
+
"network.protocol.name": "http",
|
|
168
|
+
...url ? {
|
|
169
|
+
"server.address": url.hostname,
|
|
170
|
+
"url.scheme": url.protocol.replace(":", ""),
|
|
171
|
+
"url.path": url.pathname
|
|
172
|
+
} : {},
|
|
173
|
+
...url?.port ? { "server.port": Number(url.port) } : {},
|
|
174
|
+
...url?.search ? { "url.query": url.search.slice(1) } : {}
|
|
175
|
+
}
|
|
176
|
+
}, async (span) => {
|
|
177
|
+
try {
|
|
178
|
+
const baseHeaders = typeof input === "object" && "headers" in input ? input.headers : void 0;
|
|
179
|
+
const headers = new Headers(baseHeaders);
|
|
180
|
+
if (init?.headers) for (const [k, v] of new Headers(init.headers).entries()) headers.set(k, v);
|
|
181
|
+
const carrier = {};
|
|
182
|
+
_opentelemetry_api.propagation.inject(_opentelemetry_api.context.active(), carrier);
|
|
183
|
+
for (const [k, v] of Object.entries(carrier)) headers.set(k, v);
|
|
184
|
+
for (const h of SAFE_REQUEST_HEADERS) {
|
|
185
|
+
const v = headers.get(h);
|
|
186
|
+
if (v) span.setAttribute(`http.request.header.${h}`, v);
|
|
187
|
+
}
|
|
188
|
+
const response = await fetch(input, {
|
|
189
|
+
...init,
|
|
190
|
+
headers
|
|
191
|
+
});
|
|
192
|
+
span.setAttribute("http.response.status_code", response.status);
|
|
193
|
+
const cl = response.headers.get("content-length");
|
|
194
|
+
if (cl) span.setAttribute("http.response.body.size", Number(cl));
|
|
195
|
+
for (const h of SAFE_RESPONSE_HEADERS) {
|
|
196
|
+
const v = response.headers.get(h);
|
|
197
|
+
if (v) span.setAttribute(`http.response.header.${h}`, v);
|
|
198
|
+
}
|
|
199
|
+
if (response.status >= 400) {
|
|
200
|
+
span.setStatus({
|
|
201
|
+
code: _opentelemetry_api.SpanStatusCode.ERROR,
|
|
202
|
+
message: String(response.status)
|
|
203
|
+
});
|
|
204
|
+
span.setAttribute("error.type", String(response.status));
|
|
205
|
+
} else span.setStatus({ code: _opentelemetry_api.SpanStatusCode.OK });
|
|
206
|
+
return response;
|
|
207
|
+
} catch (err) {
|
|
208
|
+
const error = err;
|
|
209
|
+
span.recordException(error);
|
|
210
|
+
span.setStatus({
|
|
211
|
+
code: _opentelemetry_api.SpanStatusCode.ERROR,
|
|
212
|
+
message: error.message
|
|
213
|
+
});
|
|
214
|
+
span.setAttribute("error.type", error.name);
|
|
215
|
+
throw err;
|
|
216
|
+
} finally {
|
|
217
|
+
span.end();
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
//#endregion
|
|
223
|
+
//#region src/observability/worker-metrics.ts
|
|
224
|
+
/**
|
|
225
|
+
* Worker metrics collection for the III Node SDK.
|
|
226
|
+
*
|
|
227
|
+
* Collects CPU, memory, and event loop metrics for worker health monitoring.
|
|
228
|
+
* Uses the Node.js built-in `monitorEventLoopDelay` API for accurate
|
|
229
|
+
* event loop lag measurements.
|
|
230
|
+
*/
|
|
231
|
+
/**
|
|
232
|
+
* Collects worker resource metrics including CPU, memory, and event loop lag.
|
|
233
|
+
*
|
|
234
|
+
* Uses the Node.js `monitorEventLoopDelay` API for high-precision event loop
|
|
235
|
+
* delay measurements instead of manual `setImmediate` timing.
|
|
236
|
+
*
|
|
237
|
+
* @example
|
|
238
|
+
* ```typescript
|
|
239
|
+
* const collector = new WorkerMetricsCollector()
|
|
240
|
+
*
|
|
241
|
+
* // Collect metrics periodically
|
|
242
|
+
* setInterval(() => {
|
|
243
|
+
* const metrics = collector.collect()
|
|
244
|
+
* console.log('CPU:', metrics.cpu_percent, '%')
|
|
245
|
+
* console.log('Event Loop Lag:', metrics.event_loop_lag_ms, 'ms')
|
|
246
|
+
* }, 5000)
|
|
247
|
+
*
|
|
248
|
+
* // Clean up when done
|
|
249
|
+
* collector.stopMonitoring()
|
|
250
|
+
* ```
|
|
251
|
+
*/
|
|
252
|
+
var WorkerMetricsCollector = class {
|
|
253
|
+
startTime;
|
|
254
|
+
lastCpuUsage;
|
|
255
|
+
lastCpuTime;
|
|
256
|
+
eventLoopHistogram = null;
|
|
257
|
+
/**
|
|
258
|
+
* Creates a new WorkerMetricsCollector instance.
|
|
259
|
+
*
|
|
260
|
+
* @param options - Configuration options
|
|
261
|
+
*/
|
|
262
|
+
constructor(options = {}) {
|
|
263
|
+
this.startTime = Date.now();
|
|
264
|
+
this.lastCpuUsage = process.cpuUsage();
|
|
265
|
+
this.lastCpuTime = node_perf_hooks.performance.now();
|
|
266
|
+
this.startEventLoopMonitoring(options.eventLoopResolutionMs ?? 20);
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Starts the event loop delay histogram monitoring.
|
|
270
|
+
*
|
|
271
|
+
* @param resolutionMs - Histogram resolution in milliseconds
|
|
272
|
+
*/
|
|
273
|
+
startEventLoopMonitoring(resolutionMs) {
|
|
274
|
+
this.eventLoopHistogram = (0, node_perf_hooks.monitorEventLoopDelay)({ resolution: Number.isFinite(resolutionMs) && resolutionMs > 0 ? Math.max(1, Math.floor(resolutionMs)) : 20 });
|
|
275
|
+
this.eventLoopHistogram.enable();
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Stops the event loop monitoring and releases resources.
|
|
279
|
+
* Should be called when the collector is no longer needed.
|
|
280
|
+
*/
|
|
281
|
+
stopMonitoring() {
|
|
282
|
+
if (this.eventLoopHistogram) {
|
|
283
|
+
this.eventLoopHistogram.disable();
|
|
284
|
+
this.eventLoopHistogram = null;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Collects current worker metrics.
|
|
289
|
+
*
|
|
290
|
+
* This method calculates CPU usage since the last collection,
|
|
291
|
+
* reads memory usage, and gets event loop delay statistics.
|
|
292
|
+
* The event loop histogram is reset after each collection for
|
|
293
|
+
* accurate per-interval measurements.
|
|
294
|
+
*
|
|
295
|
+
* @returns Current worker metrics snapshot
|
|
296
|
+
*/
|
|
297
|
+
collect() {
|
|
298
|
+
const memoryUsage = process.memoryUsage();
|
|
299
|
+
const cpuUsage = process.cpuUsage();
|
|
300
|
+
const now = node_perf_hooks.performance.now();
|
|
301
|
+
const cpuDelta = {
|
|
302
|
+
user: cpuUsage.user - this.lastCpuUsage.user,
|
|
303
|
+
system: cpuUsage.system - this.lastCpuUsage.system
|
|
304
|
+
};
|
|
305
|
+
const timeDelta = (now - this.lastCpuTime) * 1e3;
|
|
306
|
+
const cpuPercent = timeDelta > 0 ? (cpuDelta.user + cpuDelta.system) / timeDelta * 100 : 0;
|
|
307
|
+
this.lastCpuUsage = cpuUsage;
|
|
308
|
+
this.lastCpuTime = now;
|
|
309
|
+
let eventLoopLagMs = 0;
|
|
310
|
+
if (this.eventLoopHistogram) {
|
|
311
|
+
eventLoopLagMs = this.eventLoopHistogram.mean / 1e6;
|
|
312
|
+
this.eventLoopHistogram.reset();
|
|
313
|
+
}
|
|
314
|
+
return {
|
|
315
|
+
memory_heap_used: memoryUsage.heapUsed,
|
|
316
|
+
memory_heap_total: memoryUsage.heapTotal,
|
|
317
|
+
memory_rss: memoryUsage.rss,
|
|
318
|
+
memory_external: memoryUsage.external,
|
|
319
|
+
cpu_user_micros: cpuUsage.user,
|
|
320
|
+
cpu_system_micros: cpuUsage.system,
|
|
321
|
+
cpu_percent: Math.min(cpuPercent, 100),
|
|
322
|
+
event_loop_lag_ms: eventLoopLagMs,
|
|
323
|
+
uptime_seconds: Math.floor((Date.now() - this.startTime) / 1e3),
|
|
324
|
+
timestamp_ms: Date.now(),
|
|
325
|
+
runtime: "node"
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
//#endregion
|
|
331
|
+
//#region src/observability/otel-worker-gauges.ts
|
|
332
|
+
let registeredGauges = false;
|
|
333
|
+
let metricsCollector = null;
|
|
334
|
+
let registeredMeter = null;
|
|
335
|
+
let registeredBatchCallback = null;
|
|
336
|
+
let registeredObservables = [];
|
|
337
|
+
function registerWorkerGauges(meter, options) {
|
|
338
|
+
if (registeredGauges) return;
|
|
339
|
+
const { workerId, workerName } = options;
|
|
340
|
+
const baseAttributes = {
|
|
341
|
+
"worker.id": workerId,
|
|
342
|
+
...workerName && { "worker.name": workerName }
|
|
343
|
+
};
|
|
344
|
+
metricsCollector = new WorkerMetricsCollector();
|
|
345
|
+
const memoryHeapUsed = meter.createObservableGauge("iii.worker.memory.heap_used", {
|
|
346
|
+
description: "Worker heap memory used in bytes",
|
|
347
|
+
unit: "bytes"
|
|
348
|
+
});
|
|
349
|
+
const memoryHeapTotal = meter.createObservableGauge("iii.worker.memory.heap_total", {
|
|
350
|
+
description: "Worker total heap memory in bytes",
|
|
351
|
+
unit: "bytes"
|
|
352
|
+
});
|
|
353
|
+
const memoryRss = meter.createObservableGauge("iii.worker.memory.rss", {
|
|
354
|
+
description: "Worker resident set size in bytes",
|
|
355
|
+
unit: "bytes"
|
|
356
|
+
});
|
|
357
|
+
const memoryExternal = meter.createObservableGauge("iii.worker.memory.external", {
|
|
358
|
+
description: "Worker external memory in bytes",
|
|
359
|
+
unit: "bytes"
|
|
360
|
+
});
|
|
361
|
+
const cpuPercent = meter.createObservableGauge("iii.worker.cpu.percent", {
|
|
362
|
+
description: "Worker CPU usage percentage",
|
|
363
|
+
unit: "%"
|
|
364
|
+
});
|
|
365
|
+
const cpuUserMicros = meter.createObservableGauge("iii.worker.cpu.user_micros", {
|
|
366
|
+
description: "Worker CPU user time in microseconds",
|
|
367
|
+
unit: "us"
|
|
368
|
+
});
|
|
369
|
+
const cpuSystemMicros = meter.createObservableGauge("iii.worker.cpu.system_micros", {
|
|
370
|
+
description: "Worker CPU system time in microseconds",
|
|
371
|
+
unit: "us"
|
|
372
|
+
});
|
|
373
|
+
const eventLoopLag = meter.createObservableGauge("iii.worker.event_loop.lag_ms", {
|
|
374
|
+
description: "Worker event loop lag in milliseconds",
|
|
375
|
+
unit: "ms"
|
|
376
|
+
});
|
|
377
|
+
const uptimeSeconds = meter.createObservableGauge("iii.worker.uptime_seconds", {
|
|
378
|
+
description: "Worker uptime in seconds",
|
|
379
|
+
unit: "s"
|
|
380
|
+
});
|
|
381
|
+
const batchCallback = (observableResult) => {
|
|
382
|
+
if (!metricsCollector) return;
|
|
383
|
+
const metrics = metricsCollector.collect();
|
|
384
|
+
if (metrics.memory_heap_used !== void 0) observableResult.observe(memoryHeapUsed, metrics.memory_heap_used, baseAttributes);
|
|
385
|
+
if (metrics.memory_heap_total !== void 0) observableResult.observe(memoryHeapTotal, metrics.memory_heap_total, baseAttributes);
|
|
386
|
+
if (metrics.memory_rss !== void 0) observableResult.observe(memoryRss, metrics.memory_rss, baseAttributes);
|
|
387
|
+
if (metrics.memory_external !== void 0) observableResult.observe(memoryExternal, metrics.memory_external, baseAttributes);
|
|
388
|
+
if (metrics.cpu_percent !== void 0) observableResult.observe(cpuPercent, metrics.cpu_percent, baseAttributes);
|
|
389
|
+
if (metrics.cpu_user_micros !== void 0) observableResult.observe(cpuUserMicros, metrics.cpu_user_micros, baseAttributes);
|
|
390
|
+
if (metrics.cpu_system_micros !== void 0) observableResult.observe(cpuSystemMicros, metrics.cpu_system_micros, baseAttributes);
|
|
391
|
+
if (metrics.event_loop_lag_ms !== void 0) observableResult.observe(eventLoopLag, metrics.event_loop_lag_ms, baseAttributes);
|
|
392
|
+
if (metrics.uptime_seconds !== void 0) observableResult.observe(uptimeSeconds, metrics.uptime_seconds, baseAttributes);
|
|
393
|
+
};
|
|
394
|
+
meter.addBatchObservableCallback(batchCallback, [
|
|
395
|
+
memoryHeapUsed,
|
|
396
|
+
memoryHeapTotal,
|
|
397
|
+
memoryRss,
|
|
398
|
+
memoryExternal,
|
|
399
|
+
cpuPercent,
|
|
400
|
+
cpuUserMicros,
|
|
401
|
+
cpuSystemMicros,
|
|
402
|
+
eventLoopLag,
|
|
403
|
+
uptimeSeconds
|
|
404
|
+
]);
|
|
405
|
+
registeredMeter = meter;
|
|
406
|
+
registeredBatchCallback = batchCallback;
|
|
407
|
+
registeredObservables = [
|
|
408
|
+
memoryHeapUsed,
|
|
409
|
+
memoryHeapTotal,
|
|
410
|
+
memoryRss,
|
|
411
|
+
memoryExternal,
|
|
412
|
+
cpuPercent,
|
|
413
|
+
cpuUserMicros,
|
|
414
|
+
cpuSystemMicros,
|
|
415
|
+
eventLoopLag,
|
|
416
|
+
uptimeSeconds
|
|
417
|
+
];
|
|
418
|
+
registeredGauges = true;
|
|
419
|
+
}
|
|
420
|
+
function stopWorkerGauges() {
|
|
421
|
+
if (registeredMeter && registeredBatchCallback) registeredMeter.removeBatchObservableCallback(registeredBatchCallback, registeredObservables);
|
|
422
|
+
if (metricsCollector) {
|
|
423
|
+
metricsCollector.stopMonitoring();
|
|
424
|
+
metricsCollector = null;
|
|
425
|
+
}
|
|
426
|
+
registeredMeter = null;
|
|
427
|
+
registeredBatchCallback = null;
|
|
428
|
+
registeredObservables = [];
|
|
429
|
+
registeredGauges = false;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
//#endregion
|
|
433
|
+
//#region src/observability/utils.ts
|
|
434
|
+
/**
|
|
435
|
+
* Safely stringify a value, handling circular references, BigInt, and other edge cases.
|
|
436
|
+
* Returns "[unserializable]" if serialization fails for any reason.
|
|
437
|
+
*/
|
|
438
|
+
function safeStringify(value) {
|
|
439
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
440
|
+
try {
|
|
441
|
+
return JSON.stringify(value, (_key, val) => {
|
|
442
|
+
if (typeof val === "bigint") return val.toString();
|
|
443
|
+
if (val !== null && typeof val === "object") {
|
|
444
|
+
if (seen.has(val)) return "[Circular]";
|
|
445
|
+
seen.add(val);
|
|
446
|
+
}
|
|
447
|
+
return val;
|
|
448
|
+
}) ?? "[unserializable]";
|
|
449
|
+
} catch {
|
|
450
|
+
return "[unserializable]";
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
//#endregion
|
|
455
|
+
exports.BaggageSpanProcessor = require_telemetry_system.BaggageSpanProcessor;
|
|
456
|
+
exports.DEFAULT_ALLOWLIST = require_telemetry_system.DEFAULT_ALLOWLIST;
|
|
457
|
+
exports.Logger = Logger;
|
|
458
|
+
exports.REDACTED_PLACEHOLDER = require_telemetry_system.REDACTED_PLACEHOLDER;
|
|
459
|
+
exports.SeverityNumber = _opentelemetry_api_logs.SeverityNumber;
|
|
460
|
+
exports.WorkerMetricsCollector = WorkerMetricsCollector;
|
|
461
|
+
exports.currentSpanId = require_telemetry_system.currentSpanId;
|
|
462
|
+
exports.currentSpanIsRecording = require_telemetry_system.currentSpanIsRecording;
|
|
463
|
+
exports.currentTraceId = require_telemetry_system.currentTraceId;
|
|
464
|
+
exports.executeTracedRequest = executeTracedRequest;
|
|
465
|
+
exports.extractBaggage = require_telemetry_system.extractBaggage;
|
|
466
|
+
exports.extractContext = require_telemetry_system.extractContext;
|
|
467
|
+
exports.extractTraceparent = require_telemetry_system.extractTraceparent;
|
|
468
|
+
exports.flushOtel = require_telemetry_system.flushOtel;
|
|
469
|
+
exports.getAllBaggage = require_telemetry_system.getAllBaggage;
|
|
470
|
+
exports.getBaggageEntry = require_telemetry_system.getBaggageEntry;
|
|
471
|
+
exports.getLogger = require_telemetry_system.getLogger;
|
|
472
|
+
exports.initOtel = require_telemetry_system.initOtel;
|
|
473
|
+
exports.injectBaggage = require_telemetry_system.injectBaggage;
|
|
474
|
+
exports.injectTraceparent = require_telemetry_system.injectTraceparent;
|
|
475
|
+
exports.patchGlobalFetch = require_telemetry_system.patchGlobalFetch;
|
|
476
|
+
exports.recordSpanEvent = require_telemetry_system.recordSpanEvent;
|
|
477
|
+
exports.redact = require_telemetry_system.redact;
|
|
478
|
+
exports.redactAndTruncate = require_telemetry_system.redactAndTruncate;
|
|
479
|
+
exports.registerWorkerGauges = registerWorkerGauges;
|
|
480
|
+
exports.removeBaggageEntry = require_telemetry_system.removeBaggageEntry;
|
|
481
|
+
exports.resolveMaxBytesFromEnv = require_telemetry_system.resolveMaxBytesFromEnv;
|
|
482
|
+
exports.safeStringify = safeStringify;
|
|
483
|
+
exports.setBaggageEntry = require_telemetry_system.setBaggageEntry;
|
|
484
|
+
exports.setCurrentSpanAttribute = require_telemetry_system.setCurrentSpanAttribute;
|
|
485
|
+
exports.setCurrentSpanError = require_telemetry_system.setCurrentSpanError;
|
|
486
|
+
exports.shutdownOtel = require_telemetry_system.shutdownOtel;
|
|
487
|
+
exports.stopWorkerGauges = stopWorkerGauges;
|
|
488
|
+
exports.unpatchGlobalFetch = require_telemetry_system.unpatchGlobalFetch;
|
|
489
|
+
exports.withSpan = require_telemetry_system.withSpan;
|
|
490
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["getOtelLogger","currentTraceId","currentSpanId","SeverityNumber","trace","SpanKind","otelContext","SpanStatusCode","performance"],"sources":["../../src/observability/logger.ts","../../src/observability/http-instrumentation.ts","../../src/observability/worker-metrics.ts","../../src/observability/otel-worker-gauges.ts","../../src/observability/utils.ts"],"sourcesContent":["import { AnyValue, AnyValueMap, SeverityNumber } from '@opentelemetry/api-logs'\nimport {\n currentSpanId,\n currentTraceId,\n getLogger as getOtelLogger,\n} from './telemetry-system'\n\n/** @internal */\nexport type LoggerParams = {\n message: string\n trace_id?: string\n span_id?: string\n service_name?: string\n data?: unknown\n /** @deprecated Use service_name instead */\n function_name?: string\n}\n\n/**\n * Structured logger that emits logs as OpenTelemetry LogRecords.\n *\n * Every log call automatically captures the active trace and span context,\n * correlating your logs with distributed traces without any manual wiring.\n * When OTel is not initialized, Logger gracefully falls back to `console.*`.\n *\n * Pass structured data as the second argument to any log method. Using an\n * object of key-value pairs (instead of string interpolation) lets you\n * filter, aggregate, and build dashboards in your observability backend.\n *\n * @example\n * ```typescript\n * import { Logger } from 'iii-sdk'\n *\n * const logger = new Logger()\n *\n * // Basic logging — trace context is injected automatically\n * logger.info('Worker connected')\n *\n * // Structured context for dashboards and alerting\n * logger.info('Order processed', { orderId: 'ord_123', amount: 49.99, currency: 'USD' })\n * logger.warn('Retry attempt', { attempt: 3, maxRetries: 5, endpoint: '/api/charge' })\n * logger.error('Payment failed', { orderId: 'ord_123', gateway: 'stripe', errorCode: 'card_declined' })\n * ```\n */\nexport class Logger {\n private _otelLogger: ReturnType<typeof getOtelLogger> | null = null\n\n private get otelLogger() {\n // Lazy initialization: re-fetch logger if not yet available\n if (!this._otelLogger) {\n this._otelLogger = getOtelLogger()\n }\n return this._otelLogger\n }\n\n constructor(\n private readonly traceId?: string,\n private readonly serviceName?: string,\n private readonly spanId?: string,\n ) {}\n\n private emit(message: string, severity: SeverityNumber, data?: unknown): void {\n const attributes: AnyValueMap = {}\n const traceId = this.traceId ?? currentTraceId()\n const spanId = this.spanId ?? currentSpanId()\n\n if (traceId) {\n attributes.trace_id = traceId\n }\n if (spanId) {\n attributes.span_id = spanId\n }\n if (this.serviceName) {\n attributes['service.name'] = this.serviceName\n }\n if (data !== undefined) {\n attributes['log.data'] = data as AnyValue\n }\n\n if (this.otelLogger) {\n this.otelLogger.emit({\n severityNumber: severity,\n body: message,\n attributes: Object.keys(attributes).length > 0 ? attributes : undefined,\n })\n } else {\n // Fallback to console when OTEL is not available\n switch (severity) {\n case SeverityNumber.DEBUG:\n console.debug(message, data)\n break\n case SeverityNumber.INFO:\n console.info(message, data)\n break\n case SeverityNumber.WARN:\n console.warn(message, data)\n break\n case SeverityNumber.ERROR:\n console.error(message, data)\n break\n default:\n console.log(message, data)\n }\n }\n }\n\n /**\n * Log an info-level message.\n *\n * @param message - Human-readable log message.\n * @param data - Structured context attached as OTel log attributes.\n * Use key-value objects to enable filtering and aggregation in your\n * observability backend (e.g. Grafana, Datadog, New Relic).\n *\n * @example\n * ```typescript\n * logger.info('Order processed', { orderId: 'ord_123', status: 'completed' })\n * ```\n */\n info(message: string, data?: unknown): void {\n this.emit(message, SeverityNumber.INFO, data)\n }\n\n /**\n * Log a warning-level message.\n *\n * @param message - Human-readable log message.\n * @param data - Structured context attached as OTel log attributes.\n * Use key-value objects to enable filtering and aggregation in your\n * observability backend (e.g. Grafana, Datadog, New Relic).\n *\n * @example\n * ```typescript\n * logger.warn('Retry attempt', { attempt: 3, maxRetries: 5, endpoint: '/api/charge' })\n * ```\n */\n warn(message: string, data?: unknown): void {\n this.emit(message, SeverityNumber.WARN, data)\n }\n\n /**\n * Log an error-level message.\n *\n * @param message - Human-readable log message.\n * @param data - Structured context attached as OTel log attributes.\n * Use key-value objects to enable filtering and aggregation in your\n * observability backend (e.g. Grafana, Datadog, New Relic).\n *\n * @example\n * ```typescript\n * logger.error('Payment failed', { orderId: 'ord_123', gateway: 'stripe', errorCode: 'card_declined' })\n * ```\n */\n error(message: string, data?: unknown): void {\n this.emit(message, SeverityNumber.ERROR, data)\n }\n\n /**\n * Log a debug-level message.\n *\n * @param message - Human-readable log message.\n * @param data - Structured context attached as OTel log attributes.\n * Use key-value objects to enable filtering and aggregation in your\n * observability backend (e.g. Grafana, Datadog, New Relic).\n *\n * @example\n * ```typescript\n * logger.debug('Cache lookup', { key: 'user:42', hit: false })\n * ```\n */\n debug(message: string, data?: unknown): void {\n this.emit(message, SeverityNumber.DEBUG, data)\n }\n}\n","import { context as otelContext, propagation, SpanKind, SpanStatusCode, trace, type Tracer } from '@opentelemetry/api'\n\nconst SAFE_REQUEST_HEADERS = ['content-type', 'accept'] as const\nconst SAFE_RESPONSE_HEADERS = ['content-type'] as const\n\nexport interface TracedFetchInit extends RequestInit {\n tracer?: Tracer\n}\n\n/**\n * Execute a fetch request inside an OTel CLIENT span.\n *\n * Mirrors the Rust execute_traced_request shape: injects W3C traceparent into\n * outgoing headers, records HTTP semantic-convention attributes, and sets\n * ERROR span status for HTTP responses with status >= 400 or network errors.\n */\nexport async function executeTracedRequest(\n input: RequestInfo | URL,\n init?: TracedFetchInit,\n): Promise<Response> {\n const tracer = init?.tracer ?? trace.getTracer('iii-node-sdk')\n const rawUrl = typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url\n let url: URL | null\n try {\n url = new URL(rawUrl)\n } catch {\n url = null\n }\n const method = (init?.method ?? (typeof input === 'object' && 'method' in input ? input.method : 'GET') ?? 'GET').toUpperCase()\n const name = url?.pathname ? `${method} ${url.pathname}` : method\n\n return tracer.startActiveSpan(\n name,\n {\n kind: SpanKind.CLIENT,\n attributes: {\n 'http.request.method': method,\n 'url.full': url?.toString() ?? rawUrl,\n 'network.protocol.name': 'http',\n ...(url\n ? {\n 'server.address': url.hostname,\n 'url.scheme': url.protocol.replace(':', ''),\n 'url.path': url.pathname,\n }\n : {}),\n ...(url?.port ? { 'server.port': Number(url.port) } : {}),\n ...(url?.search ? { 'url.query': url.search.slice(1) } : {}),\n },\n },\n async (span) => {\n try {\n // Seed with the Request's own headers so they survive when caller\n // passes a Request object; init.headers (if any) then overrides.\n const baseHeaders =\n typeof input === 'object' && 'headers' in input ? input.headers : undefined\n const headers = new Headers(baseHeaders)\n if (init?.headers) {\n for (const [k, v] of new Headers(init.headers).entries()) headers.set(k, v)\n }\n const carrier: Record<string, string> = {}\n propagation.inject(otelContext.active(), carrier)\n for (const [k, v] of Object.entries(carrier)) headers.set(k, v)\n\n for (const h of SAFE_REQUEST_HEADERS) {\n const v = headers.get(h)\n if (v) span.setAttribute(`http.request.header.${h}`, v)\n }\n\n const response = await fetch(input, { ...init, headers })\n span.setAttribute('http.response.status_code', response.status)\n const cl = response.headers.get('content-length')\n if (cl) span.setAttribute('http.response.body.size', Number(cl))\n for (const h of SAFE_RESPONSE_HEADERS) {\n const v = response.headers.get(h)\n if (v) span.setAttribute(`http.response.header.${h}`, v)\n }\n\n if (response.status >= 400) {\n span.setStatus({ code: SpanStatusCode.ERROR, message: String(response.status) })\n span.setAttribute('error.type', String(response.status))\n } else {\n span.setStatus({ code: SpanStatusCode.OK })\n }\n return response\n } catch (err) {\n const error = err as Error\n span.recordException(error)\n span.setStatus({ code: SpanStatusCode.ERROR, message: error.message })\n span.setAttribute('error.type', error.name)\n throw err\n } finally {\n span.end()\n }\n },\n )\n}\n","/**\n * Worker metrics collection for the III Node SDK.\n *\n * Collects CPU, memory, and event loop metrics for worker health monitoring.\n * Uses the Node.js built-in `monitorEventLoopDelay` API for accurate\n * event loop lag measurements.\n */\n\nimport { type IntervalHistogram, monitorEventLoopDelay, performance } from 'node:perf_hooks'\n\n/**\n * Worker metrics data structure used internally for OTEL metric collection.\n */\nexport type WorkerMetrics = {\n memory_heap_used?: number\n memory_heap_total?: number\n memory_rss?: number\n memory_external?: number\n cpu_user_micros?: number\n cpu_system_micros?: number\n cpu_percent?: number\n event_loop_lag_ms?: number\n uptime_seconds?: number\n timestamp_ms: number\n runtime: string\n}\n\n/**\n * Configuration options for the WorkerMetricsCollector.\n */\nexport interface WorkerMetricsCollectorOptions {\n /**\n * Event loop delay histogram resolution in milliseconds.\n * Lower values provide more accurate measurements but use more resources.\n * @default 20\n */\n eventLoopResolutionMs?: number\n}\n\n/**\n * Collects worker resource metrics including CPU, memory, and event loop lag.\n *\n * Uses the Node.js `monitorEventLoopDelay` API for high-precision event loop\n * delay measurements instead of manual `setImmediate` timing.\n *\n * @example\n * ```typescript\n * const collector = new WorkerMetricsCollector()\n *\n * // Collect metrics periodically\n * setInterval(() => {\n * const metrics = collector.collect()\n * console.log('CPU:', metrics.cpu_percent, '%')\n * console.log('Event Loop Lag:', metrics.event_loop_lag_ms, 'ms')\n * }, 5000)\n *\n * // Clean up when done\n * collector.stopMonitoring()\n * ```\n */\nexport class WorkerMetricsCollector {\n private readonly startTime: number\n private lastCpuUsage: NodeJS.CpuUsage\n private lastCpuTime: number\n private eventLoopHistogram: IntervalHistogram | null = null\n\n /**\n * Creates a new WorkerMetricsCollector instance.\n *\n * @param options - Configuration options\n */\n constructor(options: WorkerMetricsCollectorOptions = {}) {\n this.startTime = Date.now()\n this.lastCpuUsage = process.cpuUsage()\n this.lastCpuTime = performance.now()\n this.startEventLoopMonitoring(options.eventLoopResolutionMs ?? 20)\n }\n\n /**\n * Starts the event loop delay histogram monitoring.\n *\n * @param resolutionMs - Histogram resolution in milliseconds\n */\n private startEventLoopMonitoring(resolutionMs: number): void {\n // Sanitize resolution: must be a positive finite number, minimum 1ms\n const safeResolutionMs =\n Number.isFinite(resolutionMs) && resolutionMs > 0 ? Math.max(1, Math.floor(resolutionMs)) : 20 // Default fallback\n\n this.eventLoopHistogram = monitorEventLoopDelay({ resolution: safeResolutionMs })\n this.eventLoopHistogram.enable()\n }\n\n /**\n * Stops the event loop monitoring and releases resources.\n * Should be called when the collector is no longer needed.\n */\n public stopMonitoring(): void {\n if (this.eventLoopHistogram) {\n this.eventLoopHistogram.disable()\n this.eventLoopHistogram = null\n }\n }\n\n /**\n * Collects current worker metrics.\n *\n * This method calculates CPU usage since the last collection,\n * reads memory usage, and gets event loop delay statistics.\n * The event loop histogram is reset after each collection for\n * accurate per-interval measurements.\n *\n * @returns Current worker metrics snapshot\n */\n collect(): WorkerMetrics {\n const memoryUsage = process.memoryUsage()\n const cpuUsage = process.cpuUsage()\n const now = performance.now()\n\n // Calculate CPU percentage since last collection\n const cpuDelta = {\n user: cpuUsage.user - this.lastCpuUsage.user,\n system: cpuUsage.system - this.lastCpuUsage.system,\n }\n const timeDelta = (now - this.lastCpuTime) * 1000 // Convert ms to microseconds\n const cpuPercent = timeDelta > 0 ? ((cpuDelta.user + cpuDelta.system) / timeDelta) * 100 : 0\n\n // Update state for next collection\n this.lastCpuUsage = cpuUsage\n this.lastCpuTime = now\n\n // Get event loop lag from histogram (in nanoseconds, convert to ms)\n let eventLoopLagMs = 0\n if (this.eventLoopHistogram) {\n // Mean is in nanoseconds, convert to milliseconds\n eventLoopLagMs = this.eventLoopHistogram.mean / 1_000_000\n // Reset histogram for next collection interval\n this.eventLoopHistogram.reset()\n }\n\n return {\n memory_heap_used: memoryUsage.heapUsed,\n memory_heap_total: memoryUsage.heapTotal,\n memory_rss: memoryUsage.rss,\n memory_external: memoryUsage.external,\n cpu_user_micros: cpuUsage.user,\n cpu_system_micros: cpuUsage.system,\n cpu_percent: Math.min(cpuPercent, 100), // Cap at 100%\n event_loop_lag_ms: eventLoopLagMs,\n uptime_seconds: Math.floor((Date.now() - this.startTime) / 1000),\n timestamp_ms: Date.now(),\n runtime: 'node',\n }\n }\n}\n","import type { Meter, BatchObservableResult, Observable } from '@opentelemetry/api'\nimport { WorkerMetricsCollector } from './worker-metrics'\n\nexport interface WorkerGaugesOptions {\n workerId: string\n workerName?: string\n}\n\nlet registeredGauges = false\nlet metricsCollector: WorkerMetricsCollector | null = null\nlet registeredMeter: Meter | null = null\nlet registeredBatchCallback: ((observableResult: BatchObservableResult) => void) | null = null\nlet registeredObservables: Observable[] = []\n\nexport function registerWorkerGauges(meter: Meter, options: WorkerGaugesOptions): void {\n if (registeredGauges) {\n return\n }\n\n const { workerId, workerName } = options\n const baseAttributes = {\n 'worker.id': workerId,\n ...(workerName && { 'worker.name': workerName }),\n }\n\n metricsCollector = new WorkerMetricsCollector()\n\n const memoryHeapUsed = meter.createObservableGauge('iii.worker.memory.heap_used', {\n description: 'Worker heap memory used in bytes',\n unit: 'bytes',\n })\n\n const memoryHeapTotal = meter.createObservableGauge('iii.worker.memory.heap_total', {\n description: 'Worker total heap memory in bytes',\n unit: 'bytes',\n })\n\n const memoryRss = meter.createObservableGauge('iii.worker.memory.rss', {\n description: 'Worker resident set size in bytes',\n unit: 'bytes',\n })\n\n const memoryExternal = meter.createObservableGauge('iii.worker.memory.external', {\n description: 'Worker external memory in bytes',\n unit: 'bytes',\n })\n\n const cpuPercent = meter.createObservableGauge('iii.worker.cpu.percent', {\n description: 'Worker CPU usage percentage',\n unit: '%',\n })\n\n const cpuUserMicros = meter.createObservableGauge('iii.worker.cpu.user_micros', {\n description: 'Worker CPU user time in microseconds',\n unit: 'us',\n })\n\n const cpuSystemMicros = meter.createObservableGauge('iii.worker.cpu.system_micros', {\n description: 'Worker CPU system time in microseconds',\n unit: 'us',\n })\n\n const eventLoopLag = meter.createObservableGauge('iii.worker.event_loop.lag_ms', {\n description: 'Worker event loop lag in milliseconds',\n unit: 'ms',\n })\n\n const uptimeSeconds = meter.createObservableGauge('iii.worker.uptime_seconds', {\n description: 'Worker uptime in seconds',\n unit: 's',\n })\n\n const batchCallback = (observableResult: BatchObservableResult) => {\n if (!metricsCollector) return\n\n const metrics = metricsCollector.collect()\n\n if (metrics.memory_heap_used !== undefined) {\n observableResult.observe(memoryHeapUsed, metrics.memory_heap_used, baseAttributes)\n }\n if (metrics.memory_heap_total !== undefined) {\n observableResult.observe(memoryHeapTotal, metrics.memory_heap_total, baseAttributes)\n }\n if (metrics.memory_rss !== undefined) {\n observableResult.observe(memoryRss, metrics.memory_rss, baseAttributes)\n }\n if (metrics.memory_external !== undefined) {\n observableResult.observe(memoryExternal, metrics.memory_external, baseAttributes)\n }\n if (metrics.cpu_percent !== undefined) {\n observableResult.observe(cpuPercent, metrics.cpu_percent, baseAttributes)\n }\n if (metrics.cpu_user_micros !== undefined) {\n observableResult.observe(cpuUserMicros, metrics.cpu_user_micros, baseAttributes)\n }\n if (metrics.cpu_system_micros !== undefined) {\n observableResult.observe(cpuSystemMicros, metrics.cpu_system_micros, baseAttributes)\n }\n if (metrics.event_loop_lag_ms !== undefined) {\n observableResult.observe(eventLoopLag, metrics.event_loop_lag_ms, baseAttributes)\n }\n if (metrics.uptime_seconds !== undefined) {\n observableResult.observe(uptimeSeconds, metrics.uptime_seconds, baseAttributes)\n }\n }\n\n meter.addBatchObservableCallback(batchCallback, [\n memoryHeapUsed,\n memoryHeapTotal,\n memoryRss,\n memoryExternal,\n cpuPercent,\n cpuUserMicros,\n cpuSystemMicros,\n eventLoopLag,\n uptimeSeconds,\n ])\n\n registeredMeter = meter\n registeredBatchCallback = batchCallback\n registeredObservables = [\n memoryHeapUsed,\n memoryHeapTotal,\n memoryRss,\n memoryExternal,\n cpuPercent,\n cpuUserMicros,\n cpuSystemMicros,\n eventLoopLag,\n uptimeSeconds,\n ]\n\n registeredGauges = true\n}\n\nexport function stopWorkerGauges(): void {\n // Remove the batch observable callback before stopping\n if (registeredMeter && registeredBatchCallback) {\n registeredMeter.removeBatchObservableCallback(registeredBatchCallback, registeredObservables)\n }\n\n if (metricsCollector) {\n metricsCollector.stopMonitoring()\n metricsCollector = null\n }\n\n registeredMeter = null\n registeredBatchCallback = null\n registeredObservables = []\n registeredGauges = false\n}\n","/**\n * Safely stringify a value, handling circular references, BigInt, and other edge cases.\n * Returns \"[unserializable]\" if serialization fails for any reason.\n */\nexport function safeStringify(value: unknown): string {\n const seen = new WeakSet<object>()\n\n try {\n const result = JSON.stringify(value, (_key, val) => {\n // Handle BigInt\n if (typeof val === 'bigint') {\n return val.toString()\n }\n\n // Handle circular references\n if (val !== null && typeof val === 'object') {\n if (seen.has(val)) {\n return '[Circular]'\n }\n seen.add(val)\n }\n\n return val\n })\n return result ?? '[unserializable]'\n } catch {\n return '[unserializable]'\n }\n}\n"],"mappings":"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"}
|