Skip to content
oRPC
Esc
navigateopen⌘Jpreview
On this page

Evlog Integration

Evlog integration for oRPC adds structured logging so you can trace requests, monitor errors, and inspect application behavior.

Installation

npm install @orpc/evlog@beta evlog@beta
pnpm add @orpc/evlog@beta evlog@beta
yarn add @orpc/evlog@beta evlog@beta
bun add @orpc/evlog@beta evlog@beta

Setup

Use EvlogHandlerPlugin to instrument your handler with structured logs, request tracking, and error monitoring.

import { class EvlogHandlerPlugin<T extends Context>
Instruments an oRPC handler with Evlog structured logging, request tracking, and error monitoring.
@see{@link https://orpc.dev/docs/integrations/evlog Evlog Integration}
EvlogHandlerPlugin
} from '@orpc/evlog'
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.
@see{@link https://orpc.dev/docs/adapters/fetch-api Fetch API Adapter}
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<{
            id: ZodNumber;
        }, $strip>, ZodObject<...>, object>;
        create: ImplementedProcedure<...>;
    };
}
router
, {
FetchHandlerOptions<{ headers?: IncomingHttpHeaders; } & object>.plugins?: FetchHandlerPlugin<{
    headers?: IncomingHttpHeaders;
} & object>[] | undefined
plugins
: [
new
new EvlogHandlerPlugin<{
    headers?: IncomingHttpHeaders;
} & object>({ storage, logAbort, ...evlogOptions }?: EvlogHandlerPluginOptions<{
    headers?: IncomingHttpHeaders;
} & object>): EvlogHandlerPlugin<{
    headers?: IncomingHttpHeaders;
} & object>
Instruments an oRPC handler with Evlog structured logging, request tracking, and error monitoring.
@see{@link https://orpc.dev/docs/integrations/evlog Evlog Integration}
EvlogHandlerPlugin
({
BaseEvlogOptions.drain?: ((ctx: DrainContext) => void | Promise<void>) | undefined
Drain callback invoked with every emitted event.
drain
: var undefinedundefined, // <- custom Evlog drain (optional)
BaseEvlogOptions.plugins?: EvlogPlugin[] | undefined
Plugins for this middleware, merged with globally-registered ones.
plugins
: [], // <- additional Evlog plugins (optional)
EvlogHandlerPluginOptions<_T extends Context>.logAbort?: boolean | undefined
If true, this plugin will log when a request signal is aborted.
@defaultfalse
logAbort
: true, // <- log when requests are aborted (disabled by default)
}), ], })

Using the Logger in Your Code

This plugin supports using AsyncLocalStorage to access the logger throughout a request and enrich the final wide event. It is the most convenient way to use Evlog’s full feature set. If your runtime does not support AsyncLocalStorage, you can still access the logger from the context.

import { createLoggerStorage } from '@orpc/evlog/node'

/**
 * Pass `storage` to the plugin configuration.
 * Call `useLogger` inside a procedure to access the request logger.
 */
export const { storage, useLogger } = createLoggerStorage()

const procedure = os
  .handler(async () => {
    const logger = useLogger() 

    logger?.set({ user: { id: 123, name: 'John Doe' } }) 

    await logger.fork('child-procedure', () => {
      const logger = useLogger() 
    })

    return { success: true }
  })
const handler = new RPCHandler(router, {
  plugins: [
    new EvlogHandlerPlugin({
      storage, // <- pass the storage to the plugin
    }),
  ],
})

Without AsyncLocalStorage

If you do not want to use AsyncLocalStorage, or your runtime does not support it, you can still read the logger from the context.

import { getLogger, LoggerContext } from '@orpc/evlog'

interface ServerContext extends LoggerContext {} 

const procedure = os
  .$context<ServerContext>()
  .handler(({ context }) => {
    const logger = getLogger(context) 

    logger?.set({ user: { id: 123, name: 'John Doe' } }) 

    return { success: true }
  })

Last updated on August 6, 2026

Was this page helpful?