OpenTelemetry#

Distributed tracing with per-request spans following HTTP semantic conventions. All telemetry dependencies are lazily imported — zero startup cost until the plugin is installed.

Installation#

bash
bun add @opentelemetry/api

Quick Start#

typescript
import { otelPlugin } from "@buntok/core/plugins/opentelemetry";

app.plugin(otelPlugin({
  serviceName: "my-api",
  exporter: "console",  // logs traces to console
}));

Options#

OptionTypeDefaultDescription
serviceNamestringRequired. Service name for trace identification.
serviceVersionstringService version.
exporter"console" | "otlp""console"Trace exporter.
otlpEndpointstring"http://localhost:4318"OTLP endpoint URL (only for "otlp").
sampler"alwaysOn" | "alwaysOff" | "traceIdRatioBased""alwaysOn"Sampling strategy.
sampleRatenumber1Sample ratio (0–1), only for "traceIdRatioBased".

What It Does#

  1. Initializes OpenTelemetry SDK with your service name
  2. Registers global middleware that creates a span per request
  3. Records HTTP semantic attributes:
    • http.request.method (GET, POST, etc.)
    • url.full (full request URL)
    • http.response.status_code (200, 404, etc.)
  4. Sets span status OK/Error based on response status (2xx = OK, 4xx/5xx = ERROR)
  5. Records exceptions on error (stack trace captured)
  6. Graceful shutdown on SIGTERM/SIGINT — flushes remaining spans

OTLP Exporter (Production)#

For production, send traces to a collector (Jaeger, Grafana Tempo, Honeycomb, etc.):

typescript
app.plugin(otelPlugin({
  serviceName: "my-api",
  exporter: "otlp",
  otlpEndpoint: "http://localhost:4318",
  sampler: "traceIdRatioBased",
  sampleRate: 0.1,  // sample 10% of requests
}));

Console Exporter (Development)#

Logs traces to console — useful for debugging:

typescript
app.plugin(otelPlugin({
  serviceName: "my-api",
  exporter: "console",
}));

Sampling Strategies#

StrategyDescriptionUse Case
"alwaysOn"Record all requestsDevelopment, low traffic
"alwaysOff"Record no requestsDisable tracing
"traceIdRatioBased"Sample sampleRate % of requestsProduction (reduce overhead)

Span Lifecycle#

typescript
Request arrives
  → span starts (method, url)
  → handler runs
  → response sent
  → span ends (status code, duration)
  → span exported to collector

What Gets Traced#

  • Every HTTP request to any route
  • Request method and URL
  • Response status code
  • Duration (start → end)
  • Errors and exceptions
Info
Dependencies are lazily imported. No @opentelemetry/api code runs until the plugin is installed via app.plugin().