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
JavaScript
;
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