Enrichers

Custom Enrichers

Write custom enrichers to add derived context to your wide events. Add deployment metadata, tenant IDs, feature flags, or any computed data.

Write custom enrichers to add any derived context to your wide events. An enricher is a function that receives an EnrichContext and mutates the event.

Basic Example

Add deployment metadata to every event:

server/plugins/evlog-enrich.ts
export default defineNitroPlugin((nitroApp) => {
  nitroApp.hooks.hook('evlog:enrich', (ctx) => {
    ctx.event.deploymentId = process.env.DEPLOYMENT_ID
    ctx.event.deployedBy = process.env.DEPLOYED_BY
  })
})

EnrichContext

The evlog:enrich hook receives an EnrichContext:

interface EnrichContext {
  /** The emitted wide event (mutable) */
  event: WideEvent
  /** Request metadata */
  request?: {
    method?: string
    path?: string
    requestId?: string
  }
  /** Safe HTTP request headers (sensitive headers filtered out) */
  headers?: Record<string, string>
  /** Response metadata */
  response?: {
    status?: number
    headers?: Record<string, string>
  }
}

Factory Pattern

For reusable enrichers with options, use the factory pattern (same as built-in enrichers):

server/utils/enrichers.ts
import type { EnrichContext } from 'evlog'

interface TenantEnricherOptions {
  headerName?: string
  overwrite?: boolean
}

export function createTenantEnricher(options: TenantEnricherOptions = {}) {
  const headerName = options.headerName ?? 'x-tenant-id'

  return (ctx: EnrichContext) => {
    if (!options.overwrite && ctx.event.tenantId !== undefined) return

    const tenantId = ctx.headers?.[headerName]
    if (tenantId) {
      ctx.event.tenantId = tenantId
    }
  }
}
server/plugins/evlog-enrich.ts
import { createTenantEnricher } from '~/server/utils/enrichers'

export default defineNitroPlugin((nitroApp) => {
  const enrichTenant = createTenantEnricher({ headerName: 'x-org-id' })

  nitroApp.hooks.hook('evlog:enrich', (ctx) => {
    enrichTenant(ctx)
  })
})

Combining with Built-in Enrichers

Mix custom enrichers with built-in ones:

server/plugins/evlog-enrich.ts
import { createUserAgentEnricher, createGeoEnricher } from 'evlog/enrichers'

export default defineNitroPlugin((nitroApp) => {
  const builtIn = [
    createUserAgentEnricher(),
    createGeoEnricher(),
  ]

  nitroApp.hooks.hook('evlog:enrich', (ctx) => {
    // Run built-in enrichers
    for (const enricher of builtIn) enricher(ctx)

    // Add custom context
    ctx.event.region = process.env.FLY_REGION ?? process.env.AWS_REGION
    ctx.event.instance = process.env.FLY_ALLOC_ID ?? process.env.HOSTNAME
  })
})

More Examples

Feature Flags

nitroApp.hooks.hook('evlog:enrich', (ctx) => {
  ctx.event.featureFlags = {
    newCheckout: isEnabled('new-checkout'),
    betaApi: isEnabled('beta-api'),
  }
})

Response Time Classification

nitroApp.hooks.hook('evlog:enrich', (ctx) => {
  const duration = ctx.event.duration as number | undefined
  if (duration === undefined) return

  if (duration < 100) ctx.event.performanceTier = 'fast'
  else if (duration < 500) ctx.event.performanceTier = 'normal'
  else if (duration < 2000) ctx.event.performanceTier = 'slow'
  else ctx.event.performanceTier = 'critical'
})

Next Steps

Copyright © 2026