@stdiolabs/provenance-otel-exporter
v0.1.0
Published
OpenTelemetry SpanExporter that ships spans to Provenance as interactions — workflow correlation, reactive automation, and AI-ready operational history
Readme
Use alongside your existing exporters (Datadog, Jaeger, etc.) to add operational intelligence, workflow correlation, and reactive automation on top of your trace data.
Installation
npm install @stdiolabs/provenance-otel-exporterPeer dependencies (install if not already present):
npm install @opentelemetry/api @opentelemetry/sdk-trace-baseQuick Start
import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-base";
import { ProvenanceSpanExporter } from "@stdiolabs/provenance-otel-exporter";
const provider = new NodeTracerProvider();
const provenanceExporter = new ProvenanceSpanExporter({
apiKey: "your-provenance-api-key",
platformUrl: "https://api.provenance.io",
});
provider.addSpanProcessor(new BatchSpanProcessor(provenanceExporter));
provider.register();Configuration Reference
| Option | Type | Default | Description |
| ------------------ | ---------------------------------------------- | -------------- | ------------------------------------------------------------------------------ |
| apiKey | string | — | Required. API key for authenticating with the Provenance API. |
| platformUrl | string | — | Required. Base URL of the Provenance platform API. |
| origin | string | service.name | Optional origin override. Falls back to the service.name resource attribute. |
| headers | Record<string, string> | undefined | Additional HTTP headers to include in requests. |
| filter | (span: ReadableSpan) => boolean | undefined | Predicate to control which spans are exported. |
| mapper | (span: ReadableSpan) => Partial<SpanMapping> | undefined | Custom mapper to derive resourceType, action, resourceId from a span. |
| userIdAttribute | string | "enduser.id" | Span attribute name to extract userId from. |
| maxBatchSize | number | 512 | Maximum number of interactions per HTTP request. |
| concurrencyLimit | number | 5 | Maximum number of concurrent HTTP requests. |
| timeoutMs | number | 30000 | HTTP request timeout in milliseconds. |
Span Filtering
Use the filter option to control which spans are sent to Provenance:
const exporter = new ProvenanceSpanExporter({
apiKey: "your-api-key",
platformUrl: "https://api.provenance.io",
filter: (span) => {
// Only export server spans
return span.kind === SpanKind.SERVER;
},
});const exporter = new ProvenanceSpanExporter({
apiKey: "your-api-key",
platformUrl: "https://api.provenance.io",
filter: (span) => {
// Skip health check endpoints
const route = span.attributes["http.route"];
return route !== "/health" && route !== "/ready";
},
});If the filter function throws, the span is skipped and a warning is logged — the rest of the batch continues processing.
Custom Mapping
Use the mapper option to control how spans map to Provenance interaction fields:
const exporter = new ProvenanceSpanExporter({
apiKey: "your-api-key",
platformUrl: "https://api.provenance.io",
mapper: (span) => ({
resourceType: "ORDER",
action: span.attributes["app.action"] as string,
resourceId: span.attributes["app.order_id"] as string,
}),
});Custom Interaction Payload
Return an interaction field from the mapper to replace the default telemetry dump with a custom payload:
const exporter = new ProvenanceSpanExporter({
apiKey: "your-api-key",
platformUrl: "https://api.provenance.io",
mapper: (span) => ({
resourceType: "PAYMENT",
action: "process",
resourceId: span.attributes["payment.id"] as string,
interaction: {
amount: span.attributes["payment.amount"],
currency: span.attributes["payment.currency"],
status: span.attributes["payment.status"],
customerId: span.attributes["customer.id"],
},
}),
});If the mapper throws or returns partial results, the built-in semantic convention mapper fills in the missing fields.
Semantic Conventions
The exporter automatically maps well-known OTel semantic convention attributes to Provenance fields:
| Span Attributes | resourceType | action | resourceId |
| ---------------------------- | ------------- | ---------------------------------- | ------------------------ |
| http.method + http.route | "HTTP" | span name | http.route |
| db.system | "DATABASE" | db.operation or span name | db.name or db.system |
| rpc.system | "RPC" | rpc.method or span name | rpc.service |
| messaging.system | "MESSAGING" | messaging.operation or span name | messaging.destination |
| (fallback) | SpanKind name | span name | span name |
Multi-Exporter Setup
The Provenance exporter works alongside other exporters. Each processor operates independently:
import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-base";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
import { ProvenanceSpanExporter } from "@stdiolabs/provenance-otel-exporter";
const provider = new NodeTracerProvider();
// Send traces to Jaeger/Datadog via OTLP
const otlpExporter = new OTLPTraceExporter({
url: "http://localhost:4318/v1/traces",
});
provider.addSpanProcessor(new BatchSpanProcessor(otlpExporter));
// Also send traces to Provenance for business context
const provenanceExporter = new ProvenanceSpanExporter({
apiKey: process.env.PROVENANCE_API_KEY!,
platformUrl: "https://api.provenance.io",
});
provider.addSpanProcessor(new BatchSpanProcessor(provenanceExporter));
provider.register();Environment Variables
The exporter supports configuration via environment variables as a fallback when programmatic config is not provided:
| Variable | Maps to | Description |
| ----------------------------------- | ------------- | -------------------------------------- |
| OTEL_EXPORTER_PROVENANCE_API_KEY | apiKey | API key for Provenance authentication. |
| OTEL_EXPORTER_PROVENANCE_ENDPOINT | platformUrl | Base URL of the Provenance API. |
Programmatic configuration always takes precedence over environment variables.
License
MIT — see LICENSE for details.
