Pino Integration
Pino integration for oRPC provides structured logging capabilities, allowing you to easily track requests, monitor errors, and gain insights into your application’s behavior.
Installation
npm install @orpc/pino@beta pino@betapnpm add @orpc/pino@beta pino@betayarn add @orpc/pino@beta pino@betabun add @orpc/pino@beta pino@betaSetup
To set up Pino with oRPC, use the PinoHandlerPlugin class. This plugin automatically instruments your handler with structured logging, request tracking, and error monitoring.
import { class PinoHandlerPlugin<T extends Context>Instruments an oRPC handler with Pino structured logging, request tracking,
and error monitoring.PinoHandlerPlugin } from '@orpc/pino'
import function pino<CustomLevels extends string = never, UseOnlyCustomLevels extends boolean = boolean>(optionsOrStream?: pino.LoggerOptions<CustomLevels, UseOnlyCustomLevels> | pino.DestinationStream): pino.Logger<CustomLevels, UseOnlyCustomLevels> (+1 overload)pino from 'pino'
const const logger: pino.Logger<never, boolean>logger = pino<never, boolean>(optionsOrStream?: pino.DestinationStream | pino.LoggerOptions<never, boolean> | undefined): pino.Logger<never, boolean> (+1 overload)pino()
const const handler: RPCHandler<{
headers?: IncomingHttpHeaders;
} & object>
handler = new new RPCHandler<{
headers?: IncomingHttpHeaders;
} & object>(router: Router<{
headers?: IncomingHttpHeaders;
} & object>, options?: NoInfer<RPCHandlerOptions<{
headers?: IncomingHttpHeaders;
} & object>>): RPCHandler<{
headers?: IncomingHttpHeaders;
} & object>
Serves an oRPC router over the RPC protocol using the Fetch API
(Request/Response), supported by modern runtimes like Deno, Bun,
Cloudflare Workers, and browsers.RPCHandler(const router: {
planet: {
list: ImplementedProcedure<{
headers?: IncomingHttpHeaders;
} & object, object, ZodObject<{
limit: ZodOptional<ZodNumber>;
cursor: ZodDefault<ZodNumber>;
}, $strip>, ZodArray<ZodObject<{
id: ZodNumber;
name: ZodString;
description: ZodOptional<ZodString>;
}, $strip>>, object>;
find: ImplementedProcedure<{
headers?: IncomingHttpHeaders;
} & object, object, ZodObject<...>, ZodObject<...>, object>;
create: ImplementedProcedure<...>;
};
}
router, {
FetchHandlerOptions<{ headers?: IncomingHttpHeaders; } & object>.plugins?: FetchHandlerPlugin<{
headers?: IncomingHttpHeaders;
} & object>[] | undefined
plugins: [
new new PinoHandlerPlugin<{
headers?: IncomingHttpHeaders;
} & object>(options?: PinoHandlerPluginOptions<{
headers?: IncomingHttpHeaders;
} & object>): PinoHandlerPlugin<{
headers?: IncomingHttpHeaders;
} & object>
Instruments an oRPC handler with Pino structured logging, request tracking,
and error monitoring.PinoHandlerPlugin({
PinoHandlerPluginOptions<T extends Context>.logger?: pino.Logger | undefinedLogger instance to use for logging.logger, // <- custom logger instance
PinoHandlerPluginOptions<{ headers?: IncomingHttpHeaders; } & object>.generateRequestId?: ((options: StandardHandlerRoutingInterceptorOptions<{
headers?: IncomingHttpHeaders;
} & object>) => string) | undefined
Function to generate a unique ID for each request.generateRequestId: ({ request: StandardLazyRequestrequest }) => var crypto: Crypto[MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/crypto)crypto.Crypto.randomUUID(): `${string}-${string}-${string}-${string}-${string}`The **`randomUUID()`** method of the Crypto interface is used to generate a v4 UUID using a cryptographically secure random number generator.
Available only in secure contexts.
[MDN Reference](https://developer.mozilla.org/docs/Web/API/Crypto/randomUUID)randomUUID(), // <- custom request id generator
PinoHandlerPluginOptions<T extends Context>.logLifecycle?: boolean | undefinedIf true, this plugin will log information about request lifecycle,
including when a request is received, handled, or no matching procedure is found.logLifecycle: true, // <- log information about request lifecycle (disabled by default)
PinoHandlerPluginOptions<T extends Context>.logAbort?: boolean | undefinedIf true, this plugin will log when a request signal is aborted.logAbort: true, // <- log information when requests are aborted (disabled by default)
}),
],
})
Using the Logger in Your Code
You can access the logger from the context object using the getLogger function:
import { getLogger, LoggerContext } from '@orpc/pino'
interface ServerContext extends LoggerContext {}
const procedure = os
.$context<ServerContext>()
.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 {
LOGGER_CONTEXT_SYMBOL,
LoggerContext,
PinoHandlerPlugin
} from '@orpc/pino'
const logger = pino()
const httpLogger = pinoHttp({ logger })
interface ServerContext extends LoggerContext {}
const router = {
ping: os.$context<ServerContext>().handler(() => 'pong')
}
const handler = new RPCHandler(router, {
plugins: [
new PinoHandlerPlugin({ logger }),
],
})
const server = createServer(async (req, res) => {
httpLogger(req, res)
const { matched } = await handler.handle(req, res, {
prefix: '/api',
context: {
[LOGGER_CONTEXT_SYMBOL]: req.log,
},
})
if (!matched) {
res.statusCode = 404
res.end('Not Found')
}
})