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.
Write a custom evlog enricher
Basic Example
Add deployment metadata to every event. The enricher is the same function everywhere — only the wiring step differs per framework.
// 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
})
})
// lib/evlog.ts
import { createEvlog } from 'evlog/next'
export const { withEvlog, useLogger, log, createError } = createEvlog({
service: 'my-app',
enrich: (ctx) => {
ctx.event.deploymentId = process.env.DEPLOYMENT_ID
ctx.event.deployedBy = process.env.DEPLOYED_BY
},
})
import type { EnrichContext } from 'evlog'
const deployment = (ctx: EnrichContext) => {
ctx.event.deploymentId = process.env.DEPLOYMENT_ID
ctx.event.deployedBy = process.env.DEPLOYED_BY
}
app.use(evlog({ enrichers: [deployment] })) // Hono / Express / Elysia
// await app.register(evlog, { enrichers: [deployment] }) // Fastify
// EvlogModule.forRoot({ enrichers: [deployment] }) // NestJS
// index.ts
import type { EnrichContext } from 'evlog'
import { initLogger } from 'evlog'
const deployment = (ctx: EnrichContext) => {
ctx.event.deploymentId = process.env.DEPLOYMENT_ID
ctx.event.deployedBy = process.env.DEPLOYED_BY
}
initLogger({ enrichers: [deployment] })
EnrichContext
The evlog:enrich hook receives an EnrichContext:
enrich-context.ts
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', enrichTenant)
})
// lib/evlog.ts
import { createEvlog } from 'evlog/next'
import { createTenantEnricher } from './enrichers'
const enrichTenant = createTenantEnricher({ headerName: 'x-org-id' })
export const { withEvlog, useLogger, log, createError } = createEvlog({
service: 'my-app',
enrich: enrichTenant,
})
import { createTenantEnricher } from './enrichers'
const enrichTenant = createTenantEnricher({ headerName: 'x-org-id' })
app.use(evlog({ enrichers: [enrichTenant] }))
// await app.register(evlog, { enrichers: [enrichTenant] }) // Fastify
// EvlogModule.forRoot({ enrichers: [enrichTenant] }) // NestJS
import { initLogger } from 'evlog'
import { createTenantEnricher } from './enrichers'
initLogger({
enrichers: [createTenantEnricher({ headerName: 'x-org-id' })],
})
Combining with Built-in Enrichers
Custom and built-in enrichers compose freely — they're all just (ctx: EnrichContext) => void functions:
enrichers.ts
import type { EnrichContext } from 'evlog'
import { createUserAgentEnricher, createGeoEnricher } from 'evlog/enrichers'
const region = (ctx: EnrichContext) => {
ctx.event.region = process.env.FLY_REGION ?? process.env.AWS_REGION
ctx.event.instance = process.env.FLY_ALLOC_ID ?? process.env.HOSTNAME
}
export const enrichers = [
createUserAgentEnricher(),
createGeoEnricher(),
region,
]
// Wire `enrichers` to your framework — see the Basic Example above for tabs per framework.
More Examples
Each example below is a plain (ctx: EnrichContext) => void function — wire it the same way as the Basic Example, regardless of framework.
Feature Flags
enricher-feature-flags.ts
import type { EnrichContext } from 'evlog'
export const featureFlags = (ctx: EnrichContext) => {
ctx.event.featureFlags = {
newCheckout: isEnabled('new-checkout'),
betaApi: isEnabled('beta-api'),
}
}
Response Time Classification
enricher-perf-tier.ts
import type { EnrichContext } from 'evlog'
export const performanceTier = (ctx: EnrichContext) => {
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
- Built-in Enrichers - See all available built-in enrichers
- Adapters - Send enriched events to external services