Headroom

Metrics & Monitoring

Monitor compression performance, cost savings, and system health with Headroom's built-in metrics, Prometheus endpoint, and SDK APIs.

Headroom provides comprehensive metrics for monitoring compression performance, cost savings, and system health through both the proxy server and the SDK.

Proxy Endpoints

Stats Endpoint

curl http://localhost:8787/stats
{
  "persistent_savings": {
    "lifetime": {
      "tokens_saved": 12500,
      "compression_savings_usd": 0.04
    }
  },
  "requests": {
    "total": 42,
    "cached": 5,
    "rate_limited": 0,
    "failed": 0
  },
  "tokens": {
    "input": 50000,
    "output": 8000,
    "saved": 12500,
    "savings_percent": 25.0
  },
  "cost": {
    "total_cost_usd": 0.15,
    "total_savings_usd": 0.04
  },
  "cache": {
    "entries": 10,
    "total_hits": 5
  }
}

Persistent savings are stored at ~/.headroom/proxy_savings.json and survive proxy restarts. Override the path with HEADROOM_SAVINGS_PATH.

Historical Savings

curl http://localhost:8787/stats-history

Returns durable compression history with hourly, daily, weekly, and monthly rollups. Supports CSV export:

curl "http://localhost:8787/stats-history?format=csv&series=daily"
curl "http://localhost:8787/stats-history?format=csv&series=monthly"

Prometheus Metrics

curl http://localhost:8787/metrics
# HELP headroom_requests_total Total requests processed
headroom_requests_total{mode="optimize"} 1234

# HELP headroom_tokens_saved_total Total tokens saved
headroom_tokens_saved_total 5678900

# HELP headroom_persistent_savings_tokens_saved_total Durable lifetime input tokens saved by proxy compression
headroom_persistent_savings_tokens_saved_total 5678900

# HELP headroom_compression_ratio Compression ratio histogram
headroom_compression_ratio_bucket{le="0.5"} 890
headroom_compression_ratio_bucket{le="0.7"} 1100
headroom_compression_ratio_bucket{le="0.9"} 1200

# HELP headroom_latency_seconds Request latency histogram
headroom_latency_seconds_bucket{le="0.01"} 800
headroom_latency_seconds_bucket{le="0.1"} 1150

# HELP headroom_cache_hits_total Cache hit counter
headroom_cache_hits_total 456

OpenTelemetry (OTLP) Export

The proxy can also push its counters to any OTLP/HTTP endpoint. Install the extra and set four variables:

pip install "headroom-ai[proxy,otel]"
HEADROOM_OTEL_METRICS_ENABLED=1
HEADROOM_OTEL_METRICS_ENDPOINT=http://127.0.0.1:4318/v1/metrics
HEADROOM_OTEL_SERVICE_NAME=headroom-proxy
HEADROOM_OTEL_RESOURCE_ATTRIBUTES=deployment.environment=prod
VariableDefaultPurpose
HEADROOM_OTEL_METRICS_ENABLED0Enable Headroom-managed OTLP metric export
HEADROOM_OTEL_METRICS_EXPORTERotlp_httpotlp_http or console (local debugging)
HEADROOM_OTEL_METRICS_ENDPOINTunsetFull OTLP metrics URL — Headroom does not append /v1/metrics for you
HEADROOM_OTEL_METRICS_HEADERSunsetComma-separated key=value auth headers
HEADROOM_OTEL_METRICS_EXPORT_INTERVAL_MS10000Export interval
HEADROOM_OTEL_SERVICE_NAMEheadroom-proxyOTEL service.name
HEADROOM_OTEL_RESOURCE_ATTRIBUTESunsetComma-separated resource attributes

Exported counters include headroom.proxy.requests, headroom.proxy.tokens.input, and headroom.proxy.tokens.output. headroom.proxy.tokens.saved is the all-layer total: message/compression savings plus tool-schema deferral savings. The component counter headroom.proxy.tokens.tool_schema_saved exposes the deferral portion separately; headroom.compression.tokens.saved remains the compression-pipeline component.

Confirm the exporter is live with curl -s http://localhost:8787/stats | jq .otel.

If your application already configures a global OTEL meter provider, leave HEADROOM_OTEL_* unset — Headroom records into the ambient provider automatically.

Dynatrace

Point the exporter at your environment's OTLP API and add the API token as a header. The token needs the metrics.ingest scope.

HEADROOM_OTEL_METRICS_ENABLED=1
HEADROOM_OTEL_METRICS_ENDPOINT="https://<env-id>.live.dynatrace.com/api/v2/otlp/v1/metrics"
HEADROOM_OTEL_METRICS_HEADERS="Authorization=Api-Token dt0c01.XXXX"
OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE=DELTA
HEADROOM_OTEL_SERVICE_NAME=headroom-proxy

Delta temporality is not optional

OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE=DELTA is required. Dynatrace only ingests delta counters and rejects cumulative ones with UNSUPPORTED_METRIC_TYPE_MONOTONIC_CUMULATIVE_SUM, while the OTEL SDK default is cumulative. Without this line, every Headroom metric is dropped at ingest and the proxy logs no error.

Restart the proxy, then search the Dynatrace metric explorer for headroom.proxy.tokens.saved — data appears within ~30s.

For an ActiveGate deployment, swap the base URL for https://<activegate>:9999/e/<env-id>/api/v2/otlp/v1/metrics. If you already run an OpenTelemetry Collector, send Headroom to it instead and add the cumulativetodelta processor — then the temporality variable is unnecessary and the collector holds the token.

Trace export is separate: Headroom's self-configured tracing targets Langfuse only. To land its spans in Dynatrace, leave HEADROOM_LANGFUSE_* unset and run the proxy under opentelemetry-instrument with the standard OTEL_EXPORTER_OTLP_ENDPOINT / OTEL_EXPORTER_OTLP_HEADERS / OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf variables; Headroom records into the ambient tracer provider.

Health Check

curl http://localhost:8787/health
{
  "status": "healthy",
  "version": "0.1.0",
  "uptime_seconds": 3600
}

SDK Metrics

Proxy Stats

The TypeScript SDK queries the proxy for stats:

import {  } from 'headroom-ai';

const  = new ();

// Get proxy stats
const  = await .proxyStats();
.(`Tokens saved: ${.tokens.saved}`);
.(`Savings: ${.tokens.savings_percent}%`);

Compression Result Metrics

Every compress() call returns metrics:

import {  } from 'headroom-ai';

const  = await (messages, { : 'gpt-4o' });
.(`Tokens: ${.tokensBefore} -> ${.tokensAfter}`);
.(`Saved: ${.tokensSaved} (${(.compressionRatio * 100).(1)}%)`);
.(`Transforms: ${.transformsApplied.join(', ')}`);

Session Stats

Quick stats for the current session (no database query):

stats = client.get_stats()
print(f"Mode: {stats['config']['mode']}")
print(f"Tokens saved: {stats['session']['tokens_saved_total']}")
print(f"Avg compression: {stats['session']['compression_ratio_avg']:.1%}")

Returns:

{
    "session": {
        "requests_total": 10,
        "tokens_input_before": 50000,
        "tokens_input_after": 35000,
        "tokens_saved_total": 15000,
        "tokens_output_total": 8000,
        "cache_hits": 3,
        "compression_ratio_avg": 0.70,
    },
    "config": {
        "mode": "optimize",
        "provider": "openai",
        "cache_optimizer_enabled": True,
        "semantic_cache_enabled": False,
    },
    "transforms": {
        "smart_crusher_enabled": True,
        "cache_aligner_enabled": True,
        "rolling_window_enabled": True,
    },
}

Historical Metrics

Query stored metrics from the database:

from datetime import datetime, timedelta

metrics = client.get_metrics(
    start_time=datetime.utcnow() - timedelta(hours=1),
    limit=100,
)

for m in metrics:
    print(f"{m.timestamp}: {m.tokens_input_before} -> {m.tokens_input_after}")

Summary Statistics

Aggregate statistics across all stored metrics:

summary = client.get_summary()
print(f"Total requests: {summary['total_requests']}")
print(f"Total tokens saved: {summary['total_tokens_saved']}")
print(f"Average compression: {summary['avg_compression_ratio']:.1%}")
print(f"Total cost savings: ${summary['total_cost_saved_usd']:.2f}")

Logging

import logging

# INFO level shows compression summaries
logging.basicConfig(level=logging.INFO)

# DEBUG level shows detailed transform decisions
logging.basicConfig(level=logging.DEBUG)

Example output:

INFO:headroom.transforms.pipeline:Pipeline complete: 45000 -> 4500 tokens (saved 40500, 90.0% reduction)
INFO:headroom.transforms.smart_crusher:SmartCrusher applied top_n strategy: kept 15 of 1000 items
DEBUG:headroom.transforms.smart_crusher:Kept items: [0,1,2,42,77,97,98,99] (errors at 42, warnings at 77)
# Log to file
headroom proxy --log-file headroom.jsonl

# Increase verbosity
headroom proxy --log-level debug

Cost Tracking

Budget Alerts

Set a budget limit in the proxy:

headroom proxy --budget 10.00

When the budget is exceeded, requests return a budget exceeded error, the /stats endpoint shows budget status, and logs indicate the budget state.

Measured vs Estimated Spend

Every cost record carries a basis — where its input-token count came from. When a provider response includes a usage breakdown, the basis is measured. When it doesn't, Headroom substitutes its own tokens_sent count so input cost isn't dropped from the budget, and the record's basis is estimated. Headroom logs one warning per model the first time this happens.

/stats keeps the two separable under cost.budget_basis:

{
  "cost": {
    "budget_limit_usd": 10.0,
    "budget_period": "daily",
    "budget_estimated_basis": "count",
    "budget_basis": {
      "total_usd": 3.1400,
      "measured_usd": 2.9000,
      "estimated_usd": 0.2400,
      "estimated_pct": 7.6,
      "records": 412,
      "estimated_records": 31
    }
  }
}

An estimate can drift in either direction, so you choose what it does to the hard limit:

headroom proxy --budget 10.00 --budget-estimated-basis count   # default
ValueEffect
countEstimated spend consumes the budget like measured spend. The default; matches historical behavior.
ignoreEstimated spend is still booked and reported, but only provider-reported spend consumes the budget.
blockRefuse requests once the period holds any estimated spend, rather than enforcing a hard limit against a guess.

Env: HEADROOM_BUDGET_ESTIMATED_BASIS. headroom doctor reports the estimated share alongside the budget check.

Key Metrics to Monitor

MetricWhat It Tells YouTarget
headroom_tokens_saved_totalRuntime tokens saved since this proxy process startedHigher is better
headroom_persistent_savings_tokens_saved_totalDurable lifetime tokens saved from /stats.persistent_savingsHigher is better
compression_ratio_avgEfficiency0.7--0.9 typical
cache_hit_rateCache effectiveness>20% is good
latency_p99Performance impact<10ms
failed_requestsReliability0

Grafana Dashboard

A ready-to-import dashboard ships in examples/grafana/headroom-dashboard.json. Import it in Grafana (Dashboards → New → Import → Upload) and pick your Prometheus datasource — it renders tokens saved, request throughput, and processing overhead (headroom_overhead_ms_sum / headroom_overhead_ms_count) straight from the metrics the /metrics endpoint exposes.

Example ad-hoc queries against the same metric family:

PanelPromQL
Runtime Tokens Savedheadroom_tokens_saved_total
Lifetime Tokens Savedheadroom_persistent_savings_tokens_saved_total
Compression Ratio (median)histogram_quantile(0.5, headroom_compression_ratio_bucket)
Request Latency (p99)histogram_quantile(0.99, headroom_latency_seconds_bucket)
Cache Hit Rateheadroom_cache_hits_total / (headroom_cache_hits_total + headroom_cache_misses_total)

On this page