Logging and metrics
Logs
Structured logs go to stdout — the collection point every platform
scrapes (Log Analytics, CloudWatch, fluentbit/EKS, journald, docker logs). JSON by default; text for humans at a console:
[observability]
log_format = "json" # or "text"
log_level = "info" # RUST_LOG env var overrides when set
Every business event in a message’s life is emitted as a structured log
line (target as2_journal) and persisted in the message journal, so
your dashboards and the durable audit trail always agree. Event kinds
include: received, stored, rejected, duplicate, mdn-received,
mdn-rejected, mdn-mic-mismatch, delivered, retry-scheduled,
gave-up, receipt-request-failed, store-failed.
Startup logs additionally surface the loaded license (customer, type, days remaining), certificates expiring within 30 days, and any partnership configured with an algorithm known to be problematic with BouncyCastle-based partners.
Metrics (optional)
Prometheus metrics are opt-in and served on a dedicated listener that never rides the partner-facing ingress:
[observability.metrics]
enabled = true
listen = "0.0.0.0:9090"
| Metric | Labels | Meaning |
|---|---|---|
as2_journal_events_total | kind, partnership | business events (same taxonomy as the journal) |
as2_http_requests_total | route, status | partner-facing HTTP requests |
as2_http_request_duration_seconds | route | request latency histogram |
as2_license_state | — | 0 valid · 1 grace · 2 expired · 3 unlicensed · 4 build-not-covered |
as2_license_days_remaining | — | days to subscription expiry (−1 when not applicable) |
Alerting suggestions: page on as2_license_state > 0, on
as2_journal_events_total{kind="gave-up"} increases, and on
kind="mdn-mic-mismatch".
The Helm chart adds Prometheus scrape annotations automatically when metrics are enabled. Clients who do not want metrics simply leave them disabled — the metrics listener then does not exist at all.