Skip to main content
The @orpc/otel package provides OpenTelemetry integration for oRPC. It uses the standard InstrumentationBase pattern from @opentelemetry/instrumentation, making it compatible with any OpenTelemetry SDK setup.

Installation

npm install @orpc/otel @opentelemetry/api @opentelemetry/instrumentation

ORPCInstrumentation

The main instrumentation class. Extend from InstrumentationBase and integrates with the OpenTelemetry SDK’s registerInstrumentations pattern.
import { ORPCInstrumentation } from '@orpc/otel'

Constructor

class ORPCInstrumentation extends InstrumentationBase {
  constructor(config?: ORPCInstrumentationConfig)
}

interface ORPCInstrumentationConfig extends InstrumentationConfig {}
ORPCInstrumentationConfig extends the standard InstrumentationConfig from @opentelemetry/instrumentation, which includes:
OptionTypeDefaultDescription
enabledbooleantrueWhether the instrumentation is active

enable()

Activates oRPC’s global OpenTelemetry integration, setting up the tracer, context propagation, and trace API:
instrumentation.enable()
Internally, this calls setGlobalOtelConfig() with the active tracer and propagation APIs from @opentelemetry/api.

disable()

Deactivates the integration:
instrumentation.disable()

Setup

import { NodeSDK } from '@opentelemetry/sdk-node'
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'
import { ORPCInstrumentation } from '@orpc/otel'

const sdk = new NodeSDK({
  traceExporter: new OTLPTraceExporter({
    url: 'http://localhost:4318/v1/traces',
  }),
  instrumentations: [
    new ORPCInstrumentation(),
  ],
})

sdk.start()

Manual setup

import { registerInstrumentations } from '@opentelemetry/instrumentation'
import { ORPCInstrumentation } from '@orpc/otel'

registerInstrumentations({
  instrumentations: [new ORPCInstrumentation()],
})
ORPCInstrumentation must be registered before your oRPC server or client code runs. The instrumentation hooks into oRPC’s global configuration at enable time.

What gets traced

Once instrumentation is enabled, oRPC automatically creates spans for:
  • Procedure execution — each procedure call creates a span named after the procedure path
  • Middleware pipeline — middleware execution is traced as child spans
  • Context propagation — trace context is propagated across requests using the W3C Trace Context standard

Span attributes

Spans include standard attributes such as:
AttributeValue
rpc.system'orpc'
rpc.methodProcedure path (e.g. planet.list)
rpc.grpc.status_codeStatus code on error
error.typeError code on failure

Example: full observability setup

// instrumentation.ts (loaded before all other code)
import { NodeSDK } from '@opentelemetry/sdk-node'
import { ConsoleSpanExporter } from '@opentelemetry/sdk-trace-node'
import { ORPCInstrumentation } from '@orpc/otel'

const sdk = new NodeSDK({
  spanProcessors: [new SimpleSpanProcessor(new ConsoleSpanExporter())],
  instrumentations: [new ORPCInstrumentation()],
})

sdk.start()
process.on('SIGTERM', () => sdk.shutdown())
// server.ts
import './instrumentation' // must be first
import { RPCHandler } from '@orpc/server/node'
import { router } from './router'

const handler = new RPCHandler(router)
// All procedure calls are now automatically traced

Compatibility

ORPCInstrumentation works with any OpenTelemetry-compatible backend:

Build docs developers (and LLMs) love