Metrics
Configuration
Endpoints
Access control: if no
auth_token is configured, only loopback addresses (127.x, ::1) are allowed. If auth_token is set, the Authorization: Bearer <token> header is required from any IP.
Prometheus metric reference
Connection metrics:
Request/response metrics:
Bandwidth:
Phase timing (for each of
cli_read, up_conn, up_write, up_read, cli_write):
io_uring health:
Non-zero values inUpstream pool:arc_ring_sq_dropped_totalorarc_ring_cq_overflow_totalindicate the io_uring ring is too small. Increaseio_uring.uring_entriesin your configuration.
Traffic mirroring:
Logging subsystem:
Rate limiting:
Config and routing:
TLS and plugins:
XDP:
Design
Workers writeAtomicU64::fetch_add with Ordering::Relaxed — one instruction, no locking. WorkerMetrics is #[repr(C, align(64))] so each worker’s struct occupies its own cache line. The admin server reads metric snapshots from a background thread that refreshes every 250ms.
Access logs
Arc writes structured NDJSON access logs. There is no text-format option.Configuration
Log record fields
Each access log line is a single JSON object:
Example:
Redaction
Arc redacts sensitive values before writing logs:- Headers — matched case-insensitively; values replaced with
[REDACTED] - Query parameters — matched case-insensitively; values replaced with
[REDACTED] - Body fields — JSONPath-style (
$.field.subfield); values replaced with"[REDACTED]"
File rotation
Rotation is triggered when the active log file exceedsmax_size. The steps are:
- Rename the active file to a timestamped archive name (near-instant metadata operation)
- Reopen the active path immediately so writes continue uninterrupted
- Compress the archive with gzip in a background thread (if
compress: true) - Delete the oldest archives to keep only
max_filesretained
Design — no backpressure on workers
Workers push log events into a bounded SPSC ring buffer. If the ring is full, the event is dropped and a counter is incremented. Workers never block. The writer thread drains all rings, encodes NDJSON manually (no serde at write time), and flushes via io_uringWrite operations in batches.
Distributed tracing
Arc implements W3C Trace Context. Every request gets atrace_id and span_id that appear in access logs and are propagated to upstreams.
How trace context is resolved
traceparent format
Arc parses and emits the standard W3C format:
- 2-char version (
00) - 32-char trace ID (must not be all zeros)
- 16-char span ID (must not be all zeros)
- 2-char flags (
01= sampled)
Upstream propagation
When Arc forwards a request to an upstream, it injects atraceparent header with the same trace_id but a freshly generated span_id. This creates a parent-child span relationship between the Arc hop and the upstream.
Searching logs by trace ID
OTLP export
To export traces to an OpenTelemetry collector:Troubleshooting
/metrics returns 404 or connection refused
/metrics returns 404 or connection refused
Check that
observability.metrics_bind is set and that Arc is running. The default is 127.0.0.1:9090 — requests from other hosts will be refused unless you bind to 0.0.0.0:9090. Confirm with: curl http://127.0.0.1:9090/metrics.Access logs are not appearing
Access logs are not appearing
Verify
observability.access_log.enabled: true and that logging.output.file is set to a writable path. Also check that sample is not set to 0.0. Logs are written asynchronously via SPSC ring buffer — if the writer thread is behind, a short delay is normal.Log file is not rotating
Log file is not rotating
Rotation is triggered when
FileState.offset >= RotationConfig.max_size_bytes. If the file never reaches that size, no rotation occurs. Check arc_log_written_total in /metrics to confirm bytes are being written. If compression is enabled and arc_log_compress_dropped_total is incrementing, the compression queue is full — reduce write rate or increase queue capacity via ARC_LOG_COMPRESS_QUEUE_CAPACITY.OTLP traces are not appearing in the backend
OTLP traces are not appearing in the backend
Check that
observability.tracing.endpoint is reachable from Arc. Set insecure: true if the collector does not have TLS. The trace_id field in access logs can be used to confirm Arc is generating trace context even if OTLP export is failing.arc_worker_phase_*_seconds histograms are missing
arc_worker_phase_*_seconds histograms are missing
Phase timing metrics are only emitted for requests that go through the full pipeline. Check that Arc is receiving and proxying traffic. If metrics appear after the first request, this is expected behavior.

