oRPC OpenTelemetry Integration
Integrate oRPC with OpenTelemetry for distributed tracing.
SKILL.mdskills/orpc-opentelemetry/SKILL.md
GitHubOpenTelemetry Integration
OpenTelemetry provides observability APIs and instrumentation for applications.
Installation
npm install @orpc/otel@latest
Setup
// server
import { NodeSDK } from '@opentelemetry/sdk-node'
import { ORPCInstrumentation } from '@orpc/otel'
const sdk = new NodeSDK({
instrumentations: [
new ORPCInstrumentation(),
],
})
sdk.start()
// client
import { WebTracerProvider } from '@opentelemetry/sdk-trace-web'
import { registerInstrumentations } from '@opentelemetry/instrumentation'
import { ORPCInstrumentation } from '@orpc/otel'
const provider = new WebTracerProvider()
provider.register()
registerInstrumentations({
instrumentations: [new ORPCInstrumentation()],
})
Middleware Span
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',
})
Define
nameproperty on middleware to improve span naming.
Handling Uncaught Exceptions
import { SpanStatusCode, trace } from '@opentelemetry/api'
const tracer = trace.getTracer('uncaught-errors')
function recordError(eventName: string, reason: unknown) {
const span = tracer.startSpan(eventName)
const message = String(reason)
if (reason instanceof Error) {
span.recordException(reason)
} else {
span.recordException({ message })
}
span.setStatus({ code: SpanStatusCode.ERROR, message })
span.end()
}
process.on('uncaughtException', (reason) => {
recordError('uncaughtException', reason)
})
process.on('unhandledRejection', (reason) => {
recordError('unhandledRejection', reason)
})
Capture Abort Signals
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()
},
],
})
Context Propagation
When using HTTP/fetch adapters, set up HTTP instrumentation for context propagation on both client and server.