Observability#
LMCache multiprocess mode provides three complementary observability modes: metrics (Prometheus counters via OTel), logging (Python logging with optional OTel log forwarding), and tracing (OTel spans for per-request latency).
All three modes are powered by an internal EventBus that decouples producers (L1Manager, StorageManager, MPCacheServer) from subscribers.
Quick Start#
By default, metrics and logging are enabled; tracing is disabled. No extra flags are needed:
lmcache server \
--l1-size-gb 100 --eviction-policy LRU
The server then exposes Prometheus metrics at /metrics on its HTTP
frontend port (--http-port, default 8080):
curl http://localhost:8080/metrics | grep lmcache_mp_
Important
For lmcache server, /metrics lives on --http-port (default
8080), not on --prometheus-port: the HTTP frontend already
serves /metrics, so the standalone Prometheus server is disabled and
--prometheus-port has no effect under this command. --prometheus-port
is the metrics endpoint for the frontend-less entrypoints
(python -m lmcache.v1.multiprocess.server and lmcache trace replay)
— see Where /metrics lives. Also note metrics are lazy: a series
only appears after the first store/retrieve that produces it, so drive
some traffic before scraping.
To also see L2 (storage-tier) metrics, attach an L2 backend with
--l2-adapter. The simplest is the local filesystem:
lmcache server \
--l1-size-gb 100 --eviction-policy LRU \
--l2-adapter '{"type": "fs", "base_path": "/data/lmcache/l2"}'
To enable tracing instead of (or alongside) Prometheus pull, supply an OTLP endpoint — this switches metrics to push mode (see Viewing Metrics in Grafana):
lmcache server \
--l1-size-gb 100 --eviction-policy LRU \
--enable-tracing --otlp-endpoint http://localhost:4317
Where /metrics lives#
The pull-mode /metrics endpoint is served in one of two places depending
on the entrypoint. Entrypoints that embed the uvicorn HTTP frontend serve it
there (and disable the standalone Prometheus server); entrypoints with no
HTTP frontend start the standalone server on --prometheus-port instead.
Entrypoint |
HTTP frontend? |
Pull-mode |
|---|---|---|
|
yes |
|
|
no |
|
|
no |
|
In push mode (--otlp-endpoint set) none of these serve /metrics —
metrics are pushed to the collector instead.
Viewing Metrics in Grafana#
There are two ways to get LMCache metrics into Grafana. Pick based on whether you also want traces.
Path |
Server flags |
What you run |
Gives you |
|---|---|---|---|
A. Bundled stack |
|
|
Metrics + traces, Grafana with the LMCache dashboard auto-provisioned |
B. Pull mode |
none (default) |
Your own Prometheus + Grafana scraping |
Metrics only, minimal moving parts, no collector |
Path A — bundled Prometheus + Tempo + Grafana#
The repository ships a ready-to-run stack (OpenTelemetry Collector →
Prometheus + Tempo → Grafana) under examples/observability/. Grafana comes
with the LMCache dashboard and datasources pre-provisioned and anonymous
access enabled, so there is nothing to click to log in.
# 1. Start the observability stack (Collector :4320, Prometheus, Tempo,
# Grafana :3000)
cd examples/observability
docker compose up -d
# 2. Start the LMCache server (+ vLLM) pushing OTLP to the collector
MODEL=/path/to/model bash start-server.sh
# 3. Generate traffic, then open Grafana
# http://localhost:3000 -> Dashboards -> "LMCache"
In this path the server pushes to the Collector and Prometheus scrapes the
Collector, so you do not scrape the server’s :8080 directly.
Path B — pull mode (metrics only, no collector)#
If you only want metrics, skip the collector entirely and have Prometheus
scrape the server’s /metrics endpoint directly. Start the server without
--otlp-endpoint (see Quick Start above), then:
# 1. Prometheus config: scrape the server's HTTP-frontend port (8080)
cat > prometheus.yml <<'YAML'
global:
scrape_interval: 5s
scrape_configs:
- job_name: lmcache
static_configs:
- targets: ["localhost:8080"] # --http-port, NOT --prometheus-port
YAML
# 2. Run Prometheus (:9090) and Grafana (:3000) on the host network so
# they can reach localhost:8080 and each other.
docker run -d --name lmcache-prom --network host \
-v "$PWD/prometheus.yml:/etc/prometheus/prometheus.yml:ro" \
prom/prometheus
docker run -d --name lmcache-grafana --network host \
-e GF_AUTH_ANONYMOUS_ENABLED=true \
-e GF_AUTH_ANONYMOUS_ORG_ROLE=Admin \
grafana/grafana
Then in Grafana (http://localhost:3000):
Add a datasource → Prometheus → URL
http://localhost:9090→ Save.Import the dashboard: Dashboards → New → Import → upload
examples/observability/grafana/provisioning/dashboards/lmcache.jsonand select the Prometheus datasource. This is the same dashboard the bundled stack provisions (cache hit rate, L1/L2 cache ops, L1↔L2 throughput, eviction loop, EventBus health, and more).
Verify the pipeline end to end:
# target should be "up"
curl -s localhost:9090/api/v1/targets | grep -o '"health":"[a-z]*"'
# after driving traffic, L2 store throughput (GB/s) per backend:
curl -s localhost:9090/api/v1/query --data-urlencode \
'query=sum by (l2_name) (rate(lmcache_mp_l2_store_throughput_GB_per_second_sum[1m]))
/ sum by (l2_name) (rate(lmcache_mp_l2_store_throughput_GB_per_second_count[1m]))'
See Metrics for the full metric catalog and more PromQL examples.
Note
--network host (used above) is the simplest option on Linux. On Docker
Desktop (macOS/Windows), drop --network host, publish ports with
-p 9090:9090 / -p 3000:3000, and set the scrape target to
host.docker.internal:8080 and the Grafana datasource URL to
http://host.docker.internal:9090.
Configuration#
Argument |
Default |
Description |
|---|---|---|
|
off |
Master switch: disable the EventBus entirely (no metrics, logging, or tracing subscribers are registered). |
|
off |
Skip metrics subscribers (Prometheus endpoint is not started). |
|
off |
Skip logging subscribers. |
|
off |
Register tracing subscribers. Requires |
|
|
Maximum events in the EventBus queue before tail-drop. |
|
(none) |
OTLP gRPC endpoint (e.g. |
|
|
Port of the standalone Prometheus |
|
|
Port of the HTTP frontend, which serves the Prometheus |
|
|
Fraction of chunks/blocks to track for lifecycle histograms (0, 1.0]. Counters always count all events. Default is 1%. |
|
(none) |
Enable trace recording at the given level. Currently only
|
|
(none) |
Path to write the trace file. If omitted while |
Environment variables:
Variable |
Default |
Description |
|---|---|---|
|
|
Controls the log level for all LMCache loggers. Valid values:
|