Tail sampling
Tail sampling is a decision made after the request runs, with full knowledge of its outcome (status, duration, errors, custom flags). It's how you keep all errors and slow requests while throwing away the bulk of healthy traffic — the opposite of head sampling, which decides up front before knowing what happens.
Canonical guide
Full reference at Sampling, section "Tail sampling":
- Built-in
keeprules (status,duration,path) - Custom predicates via
evlog:emit:keephook - Combining head + tail sampling
This page exists in the build-on-top section as a pointer — same content, classified by axis.
When to write a custom keep hook
The built-in declarative keep rules cover the typical cases. Drop to a custom hook when you need :
- Conditional logic on more than one field (e.g. "keep if
status >= 500ANDuser.plan === 'enterprise'") - Keep based on a derived value (e.g. "keep if
event.audit?.context.actor.role === 'admin'") - Stateful decisions (rare; needs care since sampling runs in the hot path)
nitroApp.hooks.hook('evlog:emit:keep', (ctx) => {
if (ctx.context.user?.plan === 'enterprise' && ctx.status >= 500) {
ctx.shouldKeep = true
}
})
Or as a plugin (preferred for non-trivial logic):
import { definePlugin } from 'evlog/toolkit'
definePlugin({
name: 'keep-enterprise-errors',
keep(ctx) {
if (ctx.context.user?.plan === 'enterprise' && ctx.status >= 500) {
ctx.shouldKeep = true
}
},
})
Going further
Custom enrichers
defineEnricher derives context from request headers, env, or anything else, and adds it to every wide event before drain — without touching call sites.
Overview
Real-world scenarios that combine several axes of evlog — bring a local debugging toolkit, multi-tenant context, compliance audit, or shared error vocabulary into your project.