@iii-dev/observability 0.19.6 → 0.19.7-alpha.1

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