Monitoring
Metrics, OpenTelemetry traces and the event log.
Metrics
GET /metrics (API key with the read scope) gives the same state in the OpenMetrics text format for a monitoring system: jobs by state, recipients by status and domain, each path’s speed, pause and backlog, webhook backlog, suppressions and holds. With BUNZZLE_OTLP_ENDPOINT, the same metrics and a trace per email (intake, each delivery attempt and each SMTP session) are sent to an OpenTelemetry collector.
OpenTelemetry
| Variable | Default | |
|---|---|---|
BUNZZLE_OTLP_ENDPOINT |
Base URL of an OTLP/HTTP collector, for example http://127.0.0.1:4318. Traces go to /v1/traces and metrics to /v1/metrics, as JSON. |
|
BUNZZLE_OTLP_HEADERS_FILE |
File with headers for the collector as name=value pairs, separated by commas or lines, values URL-encoded. Only the delivery role reads it. |
|
BUNZZLE_OTLP_METRICS_INTERVAL |
60 |
Seconds between metric pushes (10 to 3600). |
Each email is one trace, and its trace id is the email id without dashes (or, for an id you chose that is not a UUID, the first 32 hex digits of its SHA-256). The trace has an email.intake span when the email is accepted and an email.deliver span for each delivery attempt, with one smtp.session span per connection to a mail server. When POST /emails gets a traceparent header, the intake span links to that span. Metrics are the same as GET /metrics.
Event log
With BUNZZLE_EVENT_LOG=true every event also goes to local files, one JSON object per line, rotated daily and gzipped, for log shippers and grep (see docs/configuration.md).
| Variable | Default | |
|---|---|---|
BUNZZLE_EVENT_LOG |
false |
Write every delivery event to local files as JSON lines. |
BUNZZLE_EVENT_LOG_DIR |
./logs/events |
Where the files go. With the systemd units: /var/log/bunzzle/events. |
BUNZZLE_EVENT_LOG_MAX_MB |
100 |
A new file starts after this many megabytes, and every day at 00:00 UTC. |
BUNZZLE_EVENT_LOG_DAYS |
30 |
Files older than this many days are deleted. |
The current file is events-YYYYMMDD-HHMMSS.jsonl (its start time in UTC), so tail -f works; finished files are gzipped. Each line is one event, for example:
{"id":1042,"at":"2026-10-19T10:00:01.000Z","email_id":"01a1...","event":"recipient","source":"delivery","data":{"address":"user@example.com","status":"delivered"}}
The log starts with the events that happen after it is turned on. id grows with every event; after a crash a few lines can appear twice, so readers that need exact counts skip ids they have seen. If the disk is full, the log waits and catches up later; email keeps flowing.