UNPKG

apitally

Version:

Simple API monitoring & analytics for REST APIs built with Express, Fastify, NestJS, AdonisJS, Hono, H3, Elysia, Hapi, and Koa.

199 lines 6.8 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var spanCollector_exports = {}; __export(spanCollector_exports, { ApitallySpanProcessor: () => ApitallySpanProcessor, default: () => SpanCollector }); module.exports = __toCommonJS(spanCollector_exports); var import_api = require("@opentelemetry/api"); var import_client = require('./client.cjs'); const TRACE_MAX_AGE = 5 * 60 * 1e3; const _SpanCollector = class _SpanCollector { enabled; includedSpanIds = /* @__PURE__ */ new Map(); collectedSpans = /* @__PURE__ */ new Map(); traceStartTimes = /* @__PURE__ */ new Map(); maintainIntervalId; tracer; constructor(enabled) { this.enabled = enabled; if (enabled) { this.tracer = import_api.trace.getTracer("apitally"); this.maintainIntervalId = setInterval(() => { this.maintain(); }, 6e4); } } startSpan() { if (!this.enabled || !this.tracer) { return { setName: /* @__PURE__ */ __name(() => void 0, "setName"), runInContext: /* @__PURE__ */ __name((fn) => { return fn(); }, "runInContext"), enterContext: /* @__PURE__ */ __name(() => void 0, "enterContext"), end: /* @__PURE__ */ __name(() => void 0, "end") }; } const span = this.tracer.startSpan("root"); const spanCtx = span.spanContext(); const traceId = spanCtx.traceId; const ctx = import_api.trace.setSpan(import_api.context.active(), span); let ended = false; this.includedSpanIds.set(traceId, /* @__PURE__ */ new Set([ spanCtx.spanId ])); this.collectedSpans.set(traceId, []); this.traceStartTimes.set(traceId, Date.now()); return { traceId, setName: /* @__PURE__ */ __name((name) => { span.updateName(name); }, "setName"), runInContext: /* @__PURE__ */ __name((fn) => { return import_api.context.with(ctx, fn); }, "runInContext"), enterContext: /* @__PURE__ */ __name(() => { var _a, _b, _c; try { const contextManager = (_b = (_a = import_api.context)._getContextManager) == null ? void 0 : _b.call(_a); (_c = contextManager == null ? void 0 : contextManager._asyncLocalStorage) == null ? void 0 : _c.enterWith(ctx); } catch { } }, "enterContext"), end: /* @__PURE__ */ __name(() => { if (ended) return; span.end(); ended = true; return this.getAndClearSpans(traceId); }, "end") }; } getAndClearSpans(traceId) { const spans = this.collectedSpans.get(traceId) ?? []; this.collectedSpans.delete(traceId); this.includedSpanIds.delete(traceId); this.traceStartTimes.delete(traceId); return spans; } onStart(span) { var _a; if (!this.enabled) return; const ctx = span.spanContext(); const traceId = ctx.traceId; const spanId = ctx.spanId; const includedSpans = this.includedSpanIds.get(traceId); if (!includedSpans) return; const parentSpanId = (_a = span.parentSpanContext) == null ? void 0 : _a.spanId; if (parentSpanId && includedSpans.has(parentSpanId)) { includedSpans.add(spanId); } } onEnd(span) { if (!this.enabled) return; const ctx = span.spanContext(); const traceId = ctx.traceId; const spanId = ctx.spanId; const includedSpans = this.includedSpanIds.get(traceId); if (!includedSpans || !includedSpans.has(spanId)) return; const spans = this.collectedSpans.get(traceId); if (spans) { spans.push(this.serializeSpan(span)); } } serializeSpan(span) { var _a; const ctx = span.spanContext(); const data = { spanId: ctx.spanId, parentSpanId: ((_a = span.parentSpanContext) == null ? void 0 : _a.spanId) || null, name: span.name, kind: import_api.SpanKind[span.kind] ?? "INTERNAL", // HrTime is [seconds, nanoseconds], convert to nanoseconds as string to avoid precision loss startTime: (BigInt(span.startTime[0]) * 1000000000n + BigInt(span.startTime[1])).toString(), endTime: (BigInt(span.endTime[0]) * 1000000000n + BigInt(span.endTime[1])).toString() }; if (span.status.code !== import_api.SpanStatusCode.UNSET) { data.status = import_api.SpanStatusCode[span.status.code]; } if (span.attributes && Object.keys(span.attributes).length > 0) { data.attributes = { ...span.attributes }; } return data; } maintain() { const now = Date.now(); for (const [traceId, startTime] of this.traceStartTimes) { if (now - startTime > TRACE_MAX_AGE) { this.collectedSpans.delete(traceId); this.includedSpanIds.delete(traceId); this.traceStartTimes.delete(traceId); } } } async shutdown() { this.enabled = false; this.includedSpanIds.clear(); this.collectedSpans.clear(); this.traceStartTimes.clear(); if (this.maintainIntervalId) { clearInterval(this.maintainIntervalId); } } async forceFlush() { } }; __name(_SpanCollector, "SpanCollector"); let SpanCollector = _SpanCollector; const _ApitallySpanProcessor = class _ApitallySpanProcessor { getCollector() { try { return import_client.ApitallyClient.getInstance().spanCollector; } catch { return void 0; } } onStart(span) { var _a; (_a = this.getCollector()) == null ? void 0 : _a.onStart(span); } onEnd(span) { var _a; (_a = this.getCollector()) == null ? void 0 : _a.onEnd(span); } async shutdown() { var _a; (_a = this.getCollector()) == null ? void 0 : _a.shutdown(); } async forceFlush() { var _a; (_a = this.getCollector()) == null ? void 0 : _a.forceFlush(); } }; __name(_ApitallySpanProcessor, "ApitallySpanProcessor"); let ApitallySpanProcessor = _ApitallySpanProcessor; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { ApitallySpanProcessor }); //# sourceMappingURL=spanCollector.cjs.map