Extend

Identity Headers

Custom Drains
Every drain request carries User-Agent and X-Evlog-Source so receivers can triage the traffic. Override or suppress them when you need to.

Every drain request sent by evlog is tagged with two identity headers so receivers can identify the traffic:

HeaderValue
User-Agentevlog/<version> (Node / server runtimes only — browsers strip this header)
X-Evlog-SourceThe adapter name (axiom, datadog, otlp, posthog, sentry, better-stack, client, …)

The browser-side evlog/http drain (used by client logging) sets X-Evlog-Source: client instead, since browsers cannot override User-Agent.

Why

  • Triage at the receiver. Quickly distinguish evlog traffic from other clients in the receiving system's logs.
  • Track adapter usage and version drift. Roll out a new evlog version and watch the User-Agent distribution change centrally.
  • Debug a specific drain. Filter by X-Evlog-Source to isolate one adapter's behavior in a sea of incoming requests.

Reading the version

Both constants are exported from evlog/toolkit so your drain (or your receiver) can reference the canonical values:

import { EVLOG_USER_AGENT, EVLOG_VERSION } from 'evlog/toolkit'

console.log(EVLOG_VERSION)    // → "2.16.0"
console.log(EVLOG_USER_AGENT) // → "evlog/2.16.0"

Overriding from a custom drain

Adapters built with defineHttpDrain() automatically pass the drain name as source and the canonical evlog/<version> as userAgent. You don't need to think about it.

When you build a drain on top of httpPost from evlog/toolkit directly (e.g. for a fork with a different identity, or for a vendor that wants its own UA), pass source and/or userAgent to override:

import { httpPost } from 'evlog/toolkit'

await httpPost({
  url: 'https://my-platform.example.com/ingest',
  headers: { 'Content-Type': 'application/json' },
  body: '[]',
  timeout: 5000,
  label: 'my-platform',
  source: 'my-platform',           // sent as X-Evlog-Source
  userAgent: 'my-fork/1.0',        // overrides the default User-Agent
  // userAgent: false,             // suppress the header entirely
})

Next steps

  • Custom DrainsdefineHttpDrain injects identity headers automatically
  • Drain Pipeline — wrap any drain in batch + retry while keeping identity headers