Health checks, metrics and logs
What ReputeCast exposes for ReputeCast monitoring with Prometheus, load balancer health checks and log shipping.
Endpoints
Section titled “Endpoints”| Endpoint | Answer | Use it for |
|---|---|---|
GET /healthz |
200 with the body ok (text/plain). Never touches the database. |
Liveness: the process is up and serving HTTP. |
GET /readyz |
200 with ready after a database ping; 503 with database unavailable when the ping fails or takes over 2 s. |
Readiness: take the process out of the load balancer while PostgreSQL is unreachable. |
GET /metrics |
Prometheus text format. | Scraping. Served on the main listener unless metrics.addr is set; metrics.enabled: false turns it off. |
- The three endpoints live on the HTTP listener (
http.addr, default:8080), which runs only in processes with theweboringestrole. A worker-only process (reputecast workerorserve --role=worker) has no HTTP listener: setmetrics.addr(for example:9090) to scrape it. See scale with web, ingest and worker roles. - With
metrics.addrset, a separate server answers on that address and/metricsis no longer served on the main listener. - None of the three endpoints asks for authentication.
Docker image
Section titled “Docker image”The release image is distroless: it has no shell, no curl and no HEALTHCHECK. A Compose healthcheck that runs a
command inside the app container can’t work. Check /healthz and /readyz over HTTP from outside the container:
from your load balancer, orchestrator, reverse proxy or uptime monitor.
Metrics
Section titled “Metrics”| Series | Type | Labels | Meaning |
|---|---|---|---|
reputecast_http_requests_total |
counter | method, route, status |
HTTP requests. route is the matched route pattern (/api/v1/auth/password), or unmatched; status is the class: 2xx, 4xx, 5xx. |
reputecast_http_request_duration_seconds |
histogram | method, route |
Request latency. Buckets: 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5 and 10 seconds. |
go_* |
various | — | Go runtime collector: goroutines, garbage collection, memory. |
process_* |
various | — | Process collector: CPU time, resident memory, open file descriptors, start time. |
ReputeCast exports no other metrics: there are no series for sends, the job queue or sending providers. Watch those in the app, under Deliverability and Sending providers.
scrape_configs: - job_name: reputecast static_configs: - targets: ['reputecast.internal:9090'] # the host and port of metrics.addr, or of http.addr# Server errors per second, by routesum by (route) (rate(reputecast_http_requests_total{status="5xx"}[5m]))
# 95th percentile latency, by routehistogram_quantile(0.95, sum by (le, route) (rate(reputecast_http_request_duration_seconds_bucket[5m])))| Setting | Values | Default |
|---|---|---|
log.level |
debug, info, warn, error |
info; --log-level overrides it |
log.format |
text or json (one JSON object a line) |
text; the Docker image sets json |
Every process writes its logs to standard error. In Docker, read them with docker compose logs app.
{"time":"2026-10-22T12:24:02.125352804Z","level":"INFO","msg":"http listening","addr":":8080","public_url":"http://localhost:8110","roles":["web","worker","ingest"]}- One
httpline per request, withmethod,path,status,bytes,duration_msandrequest_id. The same request ID is stored with the request’s audit log entries. - Responses with status 500 and above log at
error, 400 to 499 atwarn. Requests to/healthz,/readyzand static assets log atdebug, so probes don’t fill the log. - Secret path parts are replaced with
{token}before logging: tracking and email links, unsubscribe and preference links, shared reports, provider webhook addresses, invitations and password reset links.
Lines worth alerting on:
| Message | Level | Meaning |
|---|---|---|
generated a new secret key; back it up together with the database |
WARN | No key was found, so a new one was written. Expected once on a new install; after a restore, the key is missing (back up and restore). |
database has pending migrations; run `reputecast migrate up` or pass --auto-migrate |
WARN | The binary is newer than the schema (upgrade ReputeCast). |
ignoring invalid trusted proxy |
WARN | A value in http.trusted_proxies is not an IP or CIDR. |
http listening |
INFO | The HTTP listener started; shows addr, public_url and roles. |
workers started |
INFO | A worker role started; shows concurrency. |
HTTP server limits
Section titled “HTTP server limits”| Setting | Default | How to change |
|---|---|---|
| Request timeouts | Headers 10 s, read 30 s, write 60 s, idle connections 120 s | Config http.read_timeout and http.write_timeout; the others are fixed |
| Largest request headers | 1 MiB | Fixed |
| Graceful shutdown | 20 s | Config http.shutdown_timeout |
/readyz database check | 2 s, then 503 | Fixed |
| Live monitor event stream | Heartbeat every 15 s; retry 3,000 ms | Fixed; don't buffer this stream in your proxy |
Related
Section titled “Related”- Configuration reference:
metrics.*,log.*andhttp.*keys. - Troubleshooting: symptoms, causes and fixes.
- Public URLs and endpoints: every path ReputeCast serves, and which role serves it.