OpenTelemetry
Use opentelemetry with the current published Askr packages.
@askrjs/otel0.0.2
How to use opentelemetry
Create the function-first telemetry bridge after installing an application-owned OpenTelemetry provider and wrap work at semantic boundaries.
- Import the published @askrjs/otel entrypoint.
- Keep opentelemetry configuration next to the component, route, or server composition root that owns it.
- Handle pending, unavailable, cancellation, and failure states, then verify the production path.
import { createTelemetry } from '@askrjs/otel';
const telemetry = createTelemetry({ tracerName: 'project-api' });
return telemetry.request({ requestId }, () => router.handle(request));Instrumentation boundary
`@askrjs/otel` only talks to the standard `@opentelemetry/api` peer dependency — it never bundles an SDK, span processor, exporter, or vendor backend. Call `createTelemetry(options)` once during app composition, and every span or log call routes through whatever provider your app registers; without one, the no-op implementation from the standard API absorbs the calls silently. That keeps this package usable in a test suite or a small app with zero telemetry infrastructure attached.
Spans and fields
The returned `Telemetry` object exposes one helper per lifecycle stage — `request`, `routeMatch`, `loader`, `action`, `apiOperation`, `queryPrefetch`, `ssrRender`, `viteDocument` — each wrapping a unit of work and recording it under a fixed `askr.*` `TelemetryOperation` name. `span(operation, fields, work)` is the general form underneath all of them if you need a custom operation. `TelemetryFields` is a narrow, typed shape — `requestId`, `traceId`, `route`, `action`, `status`, `durationMs` — so there's no open-ended bag of attributes to accidentally overload a span with.
Redaction
Because `TelemetryFields` is a closed interface rather than `Record<string, unknown>`, there's no field for request bodies, submitted form values, cookies, tokens, or arbitrary user attributes — you literally cannot pass them in through the typed API. The `route` field is meant to hold a route pattern like `/projects/:projectId`, not the raw, potentially sensitive URL a user actually requested. This is what keeps span data safe to forward to third-party backends by default, without a separate scrubbing pass.
Exporter setup
Choosing and configuring an actual OpenTelemetry SDK, processor, and exporter is application work, done in your composition root alongside `createTelemetry`. `TelemetryOptions` lets you customize the tracer's `tracerName`/`tracerVersion`, plug in a `logger` callback to mirror span-level events into your own structured logs, and override `now` for deterministic timing in tests. `extract`, `inject`, and `withContext` round out the object for propagating trace context across process or transport boundaries once a real exporter is wired up.