Traces first (CLAUDE.md); ipx-web traces its requests (#213)

Caddy's tracing directive, switched by WEB_TRACING so a server without a collector does not log
a failed export every few seconds. It continues an incoming traceparent (the page starts one per
tap, #190) and passes it to ipx, so a request is one trace from the browser through Caddy into
ipx, and Caddy's access log carries its traceID. Checked against Tempo with a probe container:
service.name and deployment.environment.name come from the OTEL_ variables, over OTLP/HTTP.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-12 16:13:22 +00:00
parent ee7ab36730
commit a3708769a4
4 changed files with 27 additions and 0 deletions

View File

@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
- ipx-web sends a trace span for each request when `WEB_TRACING=on`, continuing the page's trace into ipx, so one trace runs from the browser through Caddy to ipx (#213).
- The Grafana dashboard is laid out by container: an overview of all three, Tower's load, CPU, memory and disks, then ipx-web (from its new request log), ipx's API, worker and process, and the directory, each with its own warnings (#210). - The Grafana dashboard is laid out by container: an overview of all three, Tower's load, CPU, memory and disks, then ipx-web (from its new request log), ipx's API, worker and process, and the directory, each with its own warnings (#210).
- `ipx-directory`, a directory of public podcasts that ipx servers share: each sends the public feeds its people subscribe to, and any server with a token browses them. Tokens are in its config file, each read-only, read-write or admin, and revoked one at a time (#204). - `ipx-directory`, a directory of public podcasts that ipx servers share: each sends the public feeds its people subscribe to, and any server with a token browses them. Tokens are in its config file, each read-only, read-write or admin, and revoked one at a time (#204).

View File

@@ -273,6 +273,13 @@ set `version` to the next patch with `-dev` (after 0.9.0, `0.9.1-dev`), so a bui
in the logo's tooltip instead of claiming to be the last release. The release that follows can in the logo's tooltip instead of claiming to be the last release. The release that follows can
still be a minor or major one; `-dev` only says the work comes after `X.Y.Z`. still be a minor or major one; `-dev` only says the work comes after `X.Y.Z`.
**Traces first, logs second.** Anything that does work (a service, a handler, a job, a call to
another service) gets spans, and passes `traceparent` on to whatever it calls, so one trace in
Tempo follows a request or a job across ipx-web, ipx and the directory. A trace shows where the
time went and what called what; a log line only that something happened. Log what a trace cannot
carry: events worth counting on the dashboard, warnings and errors. A new service or route without
traces is not finished.
Deliberate simplifications get a `ponytail:` comment naming the ceiling and the upgrade path, e.g. Deliberate simplifications get a `ponytail:` comment naming the ceiling and the upgrade path, e.g.
`// ponytail: global connection mutex, move to a pool if feed count makes it contend`. `// ponytail: global connection mutex, move to a pool if feed count makes it contend`.

View File

@@ -38,6 +38,11 @@ services:
# Behind Cloudflare Access only: where cloudflared's requests come from, the one address # Behind Cloudflare Access only: where cloudflared's requests come from, the one address
# whose Cf-Access-* headers are passed on. docs/sso.md says how to find it. # whose Cf-Access-* headers are passed on. docs/sso.md says how to find it.
# TUNNEL_PEER: "192.168.64.1" # TUNNEL_PEER: "192.168.64.1"
# Traces to an OpenTelemetry collector, a span for each request, continued into ipx:
# WEB_TRACING: "on"
# OTEL_EXPORTER_OTLP_ENDPOINT: "http://collector:4318"
# OTEL_EXPORTER_OTLP_PROTOCOL: "http/protobuf"
# OTEL_SERVICE_NAME: "ipx-web"
ports: ports:
- "8099:8080" # the web UI - "8099:8080" # the web UI
depends_on: depends_on:

View File

@@ -2,6 +2,10 @@
# so the session cookie, live updates and Cloudflare Access work as they did when ipx served it. # so the session cookie, live updates and Cloudflare Access work as they did when ipx served it.
# IPX_UPSTREAM where ipx is, host:port (ipx:8099) # IPX_UPSTREAM where ipx is, host:port (ipx:8099)
# WEB_BIND where to listen (:8080) # WEB_BIND where to listen (:8080)
# WEB_TRACING on: a span for each request to OpenTelemetry (OTEL_EXPORTER_OTLP_ENDPOINT,
# OTEL_EXPORTER_OTLP_PROTOCOL, OTEL_SERVICE_NAME), continuing the page's traceparent
# and passing it to ipx, so one trace runs browser, Caddy, ipx (#213). Off: none,
# and no export failing every few seconds where there is nothing to send to.
# TUNNEL_PEER the one address whose Cf-Access-* headers are passed on: where cloudflared's # TUNNEL_PEER the one address whose Cf-Access-* headers are passed on: where cloudflared's
# requests come from. Nobody else's are, so nobody else can claim to be signed in # requests come from. Nobody else's are, so nobody else can claim to be signed in
# by Cloudflare. Unset passes none. # by Cloudflare. Unset passes none.
@@ -24,7 +28,17 @@
} }
} }
(tracing-on) {
tracing {
span ipx-web
}
}
(tracing-off) {
}
http://{$WEB_BIND::8080} { http://{$WEB_BIND::8080} {
import tracing-{$WEB_TRACING:off}
root * {$WEB_ROOT:/srv} root * {$WEB_ROOT:/srv}
# One JSON line a request on stdout, for Loki and the dashboard's Page row (#210). Not the # One JSON line a request on stdout, for Loki and the dashboard's Page row (#210). Not the