How to Debug Compression Issues Using Headroom's Routing Logs and Strategy Chain Metadata
Debug compression decisions in Headroom by inspecting structured routing logs that capture the strategy chain's decision field, reason codes, and per-strategy metadata, combined with Prometheus metrics for aggregate analysis.
Headroom compresses request bodies in the Live-Zone phase of its proxy before forwarding them to LLM providers. The decision-making process is driven by a strategy chain—a series of compressors that may be applied in order—with each strategy emitting metadata that is logged on a per-request basis. This article explains how to interpret these logs and metadata to diagnose why a particular request was or was not compressed.
Understanding Headroom's Live-Zone Compression Pipeline
When a request enters the proxy, the handler in src/proxy.rs calls the Live-Zone dispatcher. This dispatcher orchestrates the compression workflow by iterating through configured strategies such as smart_crusher, log_compressor, and diff_compressor.
Each compressor implements the CompressionStrategy trait defined in crates/headroom-core/src/transforms/smart_crusher/traits.rs. When a strategy runs, it returns a CrushResult object containing the compressed output, a boolean was_modified flag, the strategy identifier, and a strategy_info string describing the compression path taken.
The dispatcher aggregates results from every invoked strategy. If any strategy produces a better compression ratio that passes the token-size check defined in crates/headroom-proxy/src/compression/model_limits.rs, that result becomes the outbound payload. Otherwise, the request is forwarded unchanged.
Reading Routing Logs for Compression Decisions
The Live-Zone dispatcher records a structured log entry for every request processed. These logs are emitted via the tracing crate and appear as JSON when log_level=info is configured.
Key fields in the routing log include:
decision– Final outcome of the Live-Zone pass ("compressed","no_change", or"rejected")reason– Human-readable explanation such asno_block_compressedorrejected_not_smallercompression_mode– Always"live_zone"for the current phasebody_bytes– Size of the original request body in bytesfrozen_message_count– Number of messages kept unchangedmessages_total– Total number of chat messages in the requestlive_zone_blocks– Content blocks processed by Live-Zone logicstrategy– Name of the compressor that produced the final output (e.g.,smart_crusher)strategy_info– Debug string describing the exact compression path (e.g.,"smart_crusher → log_compressor")per_strategy_tokens– Optional token-count contribution of each strategy for ratio metrics
The integration tests in crates/headroom-proxy/tests/integration_compression.rs verify that all these fields are present and that sensitive headers such as Authorization are never logged.
Analyzing Strategy Chain Metadata
Strategy chain metadata reveals the internal decision path taken during compression. Each CrushResult object provides:
compressed– The final compressed string (or original if unchanged)was_modified– Boolean indicating whether the body was alteredstrategy– Enum variant identifying the compressor (SmartCrush,LogCompress, etc.)strategy_info– Short description of the path taken
The Live-Zone dispatcher records strategies_applied to show which compressors were evaluated. If a previous strategy already produced the optimal result, later strategies are skipped, which appears in the logs as a shorter strategy chain.
Using Prometheus Metrics for Observability
Two critical Prometheus metrics expose aggregate compression data for debugging trends:
proxy_compression_ratio_by_strategy – Records the compression ratio for each strategy (via the strategy label) and content type (content_type label). This metric is implemented in crates/headroom-proxy/src/observability/compression_ratio.rs.
proxy_compression_rejected_by_token_check_total – Counts how many times a strategy was rejected because the token-size reduction was insufficient.
These metrics help identify patterns such as a particular strategy never achieving required reduction thresholds or sudden increases in rejected attempts after content-type changes.
Step-by-Step Debugging Workflow
Follow this systematic approach to diagnose compression behavior:
- Enable INFO-level logs for the proxy by setting the environment variable
HEADROOM_LOG_LEVEL=info. - Capture the logs via stdout, file redirection, or a centralized logging system.
- Filter for the request ID using the
request_idfield included in every log line. - Inspect the JSON fields to determine which strategy fired and whether the decision was
compressed,no_change, orrejected. - Cross-reference with Prometheus by querying
proxy_compression_ratio_by_strategyto verify that observed outcomes match metric values.
Common Culprits for Uncompressed Requests
If a request is not being compressed despite being large, check for these typical issues:
- Token threshold not met – The body's token count after the best-available strategy remains above the
min_compression_ratio_for_ccrthreshold (default0.8, configurable via the Python API incrates/headroom-py/src/lib.rs). - Unsupported content type – The request content type is not supported by any strategy (e.g., binary payloads).
- Optimal result already achieved – A previous strategy produced the best possible result, causing later strategies to be skipped.
Configuration Adjustments via Code
Enable logging and adjust compression thresholds programmatically using these patterns:
// Enable INFO-level logging for the proxy
use tracing_subscriber::fmt::format::FmtSpan;
tracing_subscriber::fmt()
.with_max_level(tracing::Level::INFO)
.with_span_events(FmtSpan::CLOSE)
.init();
// Parse a captured log line to extract compression metadata
use serde_json::Value;
let log_line = r#"{"request_id":"abc123","decision":"compressed","reason":"size_reduction","strategy":"smart_crusher","body_bytes":8192,"compression_mode":"live_zone"}"#;
let v: Value = serde_json::from_str(log_line).unwrap();
println!("Request {}: {} ({} bytes)", v["request_id"], v["decision"], v["body_bytes"]);
// Query Prometheus for per-strategy ratios
use reqwest::blocking::Client;
let client = Client::new();
let resp = client.get("http://localhost:9090/api/v1/query")
.query(&[("query","proxy_compression_ratio_by_strategy")])
.send()
.unwrap()
.text()
.unwrap();
println!("{}", resp);
// Adjust the minimum compression ratio via the Python API
use headroom_py::Headroom;
let mut headroom = Headroom::new();
headroom.set_min_compression_ratio_for_ccr(0.6);
Summary
- Headroom compresses requests in the Live-Zone phase, logging structured metadata about every decision via
tracinginsrc/proxy.rs. - Routing logs contain critical fields including
decision,reason,strategy, andstrategy_infothat explain why compression succeeded or failed. - The
CompressionStrategytrait intraits.rsdefines how each compressor returnsCrushResultmetadata describing the compression path. - Prometheus metrics
proxy_compression_ratio_by_strategyandproxy_compression_rejected_by_token_check_totalprovide aggregate observability for spotting trends. - Adjust the
min_compression_ratio_for_ccrthreshold (default 0.8) incrates/headroom-py/src/lib.rswhen requests are not being compressed due to insufficient token reduction.
Frequently Asked Questions
Where are Headroom's compression logs stored?
Headroom emits compression logs via the tracing crate to stdout by default. Configure the output destination using your tracing subscriber setup. When HEADROOM_LOG_LEVEL=info is set, logs appear as JSON objects containing the decision metadata fields.
What does the no_block_compressed reason indicate?
The no_block_compressed reason in the routing logs means that none of the strategies in the chain achieved a better compression ratio than the original request. This typically occurs when the min_compression_ratio_for_ccr threshold is not met or when the content type is not supported by any configured compressor.
How can I tell which specific compressor modified my request?
Check the strategy and strategy_info fields in the routing logs. The strategy field names the final compressor (e.g., smart_crusher), while strategy_info provides a debug string showing the full chain path taken, such as "smart_crusher → log_compressor".
Why do my Prometheus metrics show rejected compression attempts?
Rejected attempts recorded in proxy_compression_rejected_by_token_check_total indicate that strategies ran but failed to reduce token count sufficiently. Cross-reference the per_strategy_tokens field in your logs with the proxy_compression_ratio_by_strategy metric to identify which specific strategy is underperforming for your content type.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →