Files
skills/docs/devtools/tooling/profiler/src/otel/otel.md
2026-05-29 08:20:56 +01:00

3.1 KiB

otel

(no submodules)

Purpose

OtelExporter converts ProfileEntry records to OTLP-compatible spans and optionally exports them to a collector endpoint over HTTP. Both the fetch implementation and the random-bytes producer used for trace/span IDs are injectable so test runs can assert exact payloads and produce deterministic IDs.

Features

  • Zod-validated config (endpoint MUST be a valid URL when supplied; serviceName non-empty; batchSize > 0).
  • Defaults: http://localhost:4318/v1/traces, serviceName: "profiler", batchSize: 100.
  • entryToSpan(entry, traceId?, parentSpanId?) — single conversion; defaults trace/span IDs from the injected RNG.
  • convertEntries(entries, traceId?) — batch conversion under a single shared trace.
  • addToBatch(spans) / flush() / getPendingCount() — pending-batch buffer.
  • export(spans) — POSTs an OTLP JSON payload; returns true on response.ok, false on non-ok responses or thrown errors (no exceptions escape).
  • exportBatch() — drains pending in batchSize slices, returning the count of successfully exported spans.
  • Attribute encoding: strings → stringValue, integers → intValue, non-integer numbers → doubleValue, booleans → boolValue.

Usage: Basic

import { OtelExporter } from "@suaveplan/profiler";

const exporter = new OtelExporter({ serviceName: "my-app" });
const spans = exporter.convertEntries(profiler.getEntries());
await exporter.export(spans);

Usage: Advanced

import { OtelExporter } from "@suaveplan/profiler";

const seed = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
let cursor = 0;
const exporter = new OtelExporter({
    endpoint: "https://collector.internal/v1/traces",
    headers: { "x-api-key": process.env.OTLP_KEY ?? "" },
    batchSize: 25,
    randomBytes: (n) => seed.slice(cursor, (cursor += n)),
    fetchFn: async (url, init) => {
        const res = await myInstrumentedFetch(url, init);
        return { ok: res.ok };
    },
});

exporter.addToBatch(exporter.convertEntries(profiler.getEntries()));
const ok = await exporter.exportBatch();

API Reference

  • class OtelExporter — new OtelExporter(config?: OtelExporterConfig).
  • interface OtelExporterConfig { endpoint?, serviceName?, batchSize?, headers?, fetchFn?, randomBytes? }.
  • Methods: generateTraceId, generateSpanId, entryToSpan, convertEntries, addToBatch, getPendingCount, flush, export, exportBatch.
  • Errors: ProfilerError with PROFILER.INVALID_OPTIONS on bad config.

Implementation Notes

The payload structure follows the OTLP/HTTP JSON encoding: a single resourceSpans entry with one scopeSpans group, and per-span attributes encoded as { key, value } records where value is a discriminated union by primitive type. metadata fields that are objects/arrays are silently dropped — OTLP only allows primitive attribute values, and reshaping nested metadata is the caller's responsibility. Export failures are swallowed and surfaced via the boolean return so exporters can be used inside fire-and-forget profiling loops without crashing the host.