OpenTelemetry Integration
OpenTelemetry integration adds automatic instrumentation to oRPC applications, enabling distributed tracing and performance monitoring with minimal setup.

Installation
npm install @orpc/opentelemetry@betapnpm add @orpc/opentelemetry@betayarn add @orpc/opentelemetry@betabun add @orpc/opentelemetry@betaSetup
To integrate OpenTelemetry with oRPC, use ORPCInstrumentation. It automatically instruments both client and server for distributed tracing.
import { class NodeSDKA setup helper for the OpenTelemetry SDKs (logs, metrics, traces).
<p> After successful setup using
{@link
NodeSDK#start()
}
, use `@opentelemetry/api` to obtain the registered components.
<p> Use the shutdown handler
{@link
NodeSDK#shutdown()
}
to ensure your telemetry is exported before the process exits.NodeSDK } from '@opentelemetry/sdk-node'
import { class ORPCInstrumentationOpenTelemetry instrumentation for oRPC. Automatically instruments both
client and server for distributed tracing.ORPCInstrumentation } from '@orpc/opentelemetry'
const const sdk: NodeSDKsdk = new new NodeSDK(configuration?: Partial<NodeSDKConfiguration>): NodeSDKCreate a new NodeJS SDK instanceNodeSDK({
instrumentations?: (Instrumentation<InstrumentationConfig> | Instrumentation<InstrumentationConfig>[])[] | undefinedinstrumentations: [
new new ORPCInstrumentation(config?: ORPCInstrumentationConfig): ORPCInstrumentationOpenTelemetry instrumentation for oRPC. Automatically instruments both
client and server for distributed tracing.ORPCInstrumentation(),
],
})
const sdk: NodeSDKsdk.NodeSDK.start(): voidCall this method to construct SDK components and register them with the OpenTelemetry API.start()import { class WebTracerProviderThis class represents a web tracer with
{@link
StackContextManager
}WebTracerProvider } from '@opentelemetry/sdk-trace-web'
import { function registerInstrumentations(options: AutoLoaderOptions): () => voidIt will register instrumentations and pluginsregisterInstrumentations } from '@opentelemetry/instrumentation'
import { class ORPCInstrumentationOpenTelemetry instrumentation for oRPC. Automatically instruments both
client and server for distributed tracing.ORPCInstrumentation } from '@orpc/opentelemetry'
const const provider: WebTracerProviderprovider = new new WebTracerProvider(config?: WebTracerConfig): WebTracerProviderConstructs a new Tracer instance.WebTracerProvider()
const provider: WebTracerProviderprovider.WebTracerProvider.register(config?: SDKRegistrationConfig): voidRegister this TracerProvider for use with the OpenTelemetry API.
Undefined values may be replaced with defaults, and
null values will be skipped.register()
function registerInstrumentations(options: AutoLoaderOptions): () => voidIt will register instrumentations and pluginsregisterInstrumentations({
AutoLoaderOptions.instrumentations?: (Instrumentation<InstrumentationConfig> | Instrumentation<InstrumentationConfig>[])[] | undefinedinstrumentations: [
new new ORPCInstrumentation(config?: ORPCInstrumentationConfig): ORPCInstrumentationOpenTelemetry instrumentation for oRPC. Automatically instruments both
client and server for distributed tracing.ORPCInstrumentation(),
],
})Context Propagation
By default, ORPCInstrumentation enables context propagation between the client and server. You can disable it by setting propagationEnabled to false if you do not need it or if another instrumentation already handles it.
const instrumentation = new ORPCInstrumentation({
propagationEnabled: false,
})
Middleware Span
oRPC automatically creates spans for each middleware execution. You can access the active span to customize attributes, events, and other span data:
import { trace } from '@opentelemetry/api'
export const someMiddleware = os.middleware(async (ctx, next) => {
const span = trace.getActiveSpan()
span?.setAttribute('someAttribute', 'someValue')
span?.addEvent('someEvent')
return next()
})
Object.defineProperty(someMiddleware, 'name', {
value: 'someName',
})
Capture Abort Signals
If your application heavily uses AsyncIteratorObject or similar streaming patterns, we recommend capturing an event when the signal is aborted to properly track and detach unexpected long-running operations:
import { trace } from '@opentelemetry/api'
const handler = new RPCHandler(router, {
interceptors: [
({ request, next }) => {
const span = trace.getActiveSpan()
request.signal?.addEventListener('abort', () => {
span?.addEvent('aborted', { reason: String(request.signal?.reason) })
})
return next()
},
],
})