Pino Integration
Pino is a fast and lightweight JSON logger. This guide explains how to integrate oRPC with Pino to add structured logging, request tracking, and error monitoring to your applications.
WARNING
This guide assumes familiarity with Pino. Review the official documentation if needed.
Installation
npm install @orpc/experimental-pino@latest pino@latestyarn add @orpc/experimental-pino@latest pino@latestpnpm add @orpc/experimental-pino@latest pino@latestbun add @orpc/experimental-pino@latest pino@latestdeno add npm:@orpc/experimental-pino@latest npm:pino@latestSetup
To set up Pino with oRPC, use the LoggingHandlerPlugin class. This plugin automatically instruments your handler with structured logging, request tracking, and error monitoring.
import { LoggingHandlerPlugin } from '@orpc/experimental-pino'
import pino from 'pino'
const logger = pino()
const handler = new RPCHandler(router, {
plugins: [
new LoggingHandlerPlugin({
logger, // Custom logger instance
generateId: ({ request }) => crypto.randomUUID(), // Custom ID generator
logRequestResponse: true, // Log request start/end (disabled by default)
logRequestAbort: true, // Log when requests are aborted (disabled by default)
}),
],
})INFO
The handler can be any supported oRPC handler, such as RPCHandler, OpenAPIHandler, or another custom handler.
TIP
For improved log readability during development, consider using pino-pretty to format your logs in a human-friendly way.
npm run dev | npx pino-prettyUsing the Logger in Your Code
You can access the logger from the context object using the getLogger function:
import { getLogger } from '@orpc/experimental-pino'
const procedure = os.handler(({ context }) => {
const logger = getLogger(context)
logger?.info('Processing request')
logger?.debug({ userId: 123 }, 'User data')
return { success: true }
})Providing Custom Logger per Request
You can provide a custom logger instance for specific requests by passing it through the context. This is especially useful when integrating with pino-http for enhanced HTTP logging:
import {
CONTEXT_LOGGER_SYMBOL,
LoggerContext,
LoggingHandlerPlugin
} from '@orpc/experimental-pino'
const logger = pino()
const httpLogger = pinoHttp({ logger })
interface ORPCContext extends LoggerContext {}
const router = {
ping: os.$context<ORPCContext>().handler(() => 'pong')
}
const handler = new RPCHandler(router, {
plugins: [
new LoggingHandlerPlugin({ logger }),
],
})
const server = createServer(async (req, res) => {
httpLogger(req, res)
const { matched } = await handler.handle(req, res, {
prefix: '/api',
context: {
[CONTEXT_LOGGER_SYMBOL]: req.log,
},
})
if (!matched) {
res.statusCode = 404
res.end('Not Found')
}
})