Skip to content

Observability

FrogDB exposes Prometheus metrics, OTLP export, distributed tracing, HTTP health/status endpoints, structured logging, and optional USDT probes. The metric catalog itself lives in Metrics Reference — this page covers how to enable and configure each observability channel. For interactive diagnostics (slowlog, LATENCY, hot-key detection, the debug web UI), see Diagnostics.

FrogDB exports metrics in Prometheus text format (version=0.0.4) on the HTTP server:

GET http://<host>:9090/metrics

The listener is controlled by [http], not [metrics][metrics] only configures OTLP export (below). /metrics shares the same HTTP server as the health, status, and debug endpoints:

[http]
enabled = true
bind = "127.0.0.1"
port = 9090

/metrics is always unauthenticated and always returns 200, regardless of http.token. See Metrics Reference for the complete, generated list of exported metrics — this page does not duplicate metric names.

In addition to the pull-based /metrics endpoint, FrogDB can push metrics to any OpenTelemetry-compatible collector via OTLP/gRPC on an interval:

[metrics]
otlp-enabled = false
otlp-endpoint = "http://localhost:4317"
otlp-interval-secs = 15
SettingTypeDefaultDescription
otlp-enabledbooleanfalseEnable OTLP metrics export
otlp-endpointstringhttp://localhost:4317gRPC endpoint of the OTLP collector
otlp-interval-secsinteger15Export interval in seconds

This otlp-endpoint is distinct from tracing.otlp-endpoint below — metrics and traces are exported independently and can point at different collectors.

See Configuration Reference → Metrics.

FrogDB supports OpenTelemetry distributed tracing with configurable span granularity:

[tracing]
enabled = false
otlp-endpoint = "http://localhost:4317"
sampling-rate = 1.0
service-name = "frogdb"
scatter-gather-spans = false # Child spans per shard for MGET/MSET
shard-spans = false # Spans inside shard workers
persistence-spans = false # WAL/snapshot spans

Tracing is disabled by default; sampling-rate defaults to 1.0 (sample everything) once enabled — lower it in production to control span volume.

When tracing is enabled, FrogDB emits spans at three levels:

  1. Request span — created at the connection handler, covers the full command lifecycle
  2. Shard execution span — created in the shard worker, covers command processing
  3. Store operation span — individual data structure operations

FrogDB uses OpenTelemetry database semantic conventions:

AttributeExample
db.systemfrogdb
db.operationGET, SET, MGET
db.statementSET mykey myvalue
frogdb.shard_id3
frogdb.connection_id42
frogdb.key_count1

FrogDB keeps the last tracing.recent-traces-max traces (default 100) in memory for debugging. These feed the recent-traces view in the debug web UI.

See Configuration Reference → Distributed Tracing.

All endpoints below are served on the [http] listener (default port 9090) and are unauthenticated regardless of http.token:

EndpointDescriptionResponse
GET /health/liveLiveness — process is running200 if alive, 503 after shutdown begins
GET /health/readyReadiness — accepting commands503 until the server signals ready, 200 once ready, 503 again during shutdown
GET /healthzAlias for /health/liveSame as /health/live
GET /readyzAlias for /health/readySame as /health/ready
GET /status/jsonFull server status (JSON)200 with the status document

/health/ready starts not ready and only flips to 200 once the server finishes startup — this is intentional for readiness-gated rollouts (don’t route traffic to a node that hasn’t finished recovery). /status/json is documented in full in Diagnostics → Server status; it’s listed here only to complete the endpoint table.

Bearer-token-protected routes (/debug/*, /admin/*) only require Authorization: Bearer <token> when http.token is configured — otherwise they’re open on whatever http.bind allows (127.0.0.1 by default, so loopback-only out of the box). See Diagnostics → Debug web UI for the full auth story.

Kubernetes probe configuration:

livenessProbe:
httpGet:
path: /health/live
port: 9090
initialDelaySeconds: 5
readinessProbe:
httpGet:
path: /health/ready
port: 9090
initialDelaySeconds: 5

INFO returns the standard Redis-compatible sections plus FrogDB extras. Default sections (returned by a bare INFO):

INFO server|clients|memory|persistence|stats|replication|cpu|keyspace|ratelimit

ratelimit is a FrogDB extension: it only renders when per-user ACL rate limiting is active (fields ratelimit_users_configured, ratelimit_total_commands_rejected, ratelimit_total_bytes_rejected — see Security).

Extra sections available via INFO all / INFO everything:

INFO commandstats|errorstats|latencystats|latency_baseline|tiered|keysizes

For the meaning of the standard Redis fields within each section, see the Redis INFO documentation; this page documents only where FrogDB’s section list differs.

FrogDB uses structured logging with configurable output format and level:

[logging]
level = "info" # trace, debug, info, warn, error
format = "pretty" # "pretty" or "json"
output = "stdout" # "stdout", "stderr", or "none"
per-request-spans = false # Per-request tracing spans
file-path = "/var/log/frogdb/frogdb.log"
[logging.rotation]
max-size-mb = 100
frequency = "daily" # "daily", "hourly", or "never"
max-files = 5

per-request-spans adds a tracing span around every request; enabling it adds measurable CPU overhead and is intended for short diagnostic windows rather than continuous production use. Rotation requires file-path to be set and at least one of max-size-mb or frequency to be active.

The log level can be changed at runtime without a restart:

Terminal window
redis-cli CONFIG SET loglevel debug

loglevel accepts the same five levels as logging.level.

See Configuration Reference → Logging.

FrogDB includes USDT (User Statically Defined Tracing) probes for low-overhead, production-safe tracing on macOS and Linux. They compile to no-ops unless the server is built with --features usdt-probes.

ProbeArgumentsDescription
command__startcommand, key, conn_idFired when a command begins execution
command__donecommand, latency_us, statusFired when a command completes
shard__message__sentfrom_shard, to_shard, msg_typeInter-shard message dispatched
shard__message__receivedshard, msg_type, queue_depthShard received a message
key__expiredkey, shard_idKey expired via TTL
key__evictedkey, shard_id, policyKey evicted due to memory pressure
memory__pressureused, max, actionMemory pressure event
wal__writeshard_id, key, bytesWAL write for a key
scatter__startcommand, shard_count, txidScatter-gather operation started
scatter__donecommand, latency_us, shard_countScatter-gather operation completed
pubsub__publishchannel, subscribersMessage published to a channel
connection__acceptconn_id, addrNew client connection accepted

Probes are defined in frogdb-server/crates/core/src/probes.rs under the frogdb USDT provider.

Terminal window
# List all FrogDB probes (macOS)
sudo dtrace -l -n 'frogdb*:::'
# Trace all commands
sudo dtrace -n 'frogdb*:::command-start { printf("%s %s\n", copyinstr(arg0), copyinstr(arg1)); }'
# Measure command latency
sudo dtrace -n 'frogdb*:::command-done { printf("%s %d us\n", copyinstr(arg0), arg1); }'
# Watch memory pressure events
sudo dtrace -n 'frogdb*:::memory-pressure { printf("used=%d max=%d action=%s\n", arg0, arg1, copyinstr(arg2)); }'
# With bpftrace (Linux)
sudo bpftrace -e 'usdt:./frogdb-server:frogdb:command__start { printf("%s %s\n", str(arg0), str(arg1)); }'

A short, qualitative starting point — treat the thresholds as examples to tune for your workload, not SLAs:

MetricWatch for
frogdb_memory_used_bytes / frogdb_memory_maxmemory_bytesApproaching the configured limit
histogram_quantile(0.99, rate(frogdb_commands_duration_seconds_bucket[5m]))Sustained increases in tail command latency
frogdb_persistence_errors_totalAny increase (WAL/snapshot I/O trouble)
frogdb_connections_rejected_totalAny increase (hitting maxclients or auth failures)

All four metric names are validated against the generated Metrics Reference catalog.