Pipeline

Tail sampling

Decide post-hoc whether to keep an event based on the request outcome — keep all errors, keep slow requests, keep specific paths, drop the rest.

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 keep rules (status, duration, path)
  • Custom predicates via evlog:emit:keep hook
  • 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 >= 500 AND user.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

  • Plugins when the keep decision is part of a broader feature
  • Sampling for the full theory and config reference