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 as no_block_compressed or rejected_not_smaller
  • compression_mode – Always "live_zone" for the current phase
  • body_bytes – Size of the original request body in bytes
  • frozen_message_count – Number of messages kept unchanged
  • messages_total – Total number of chat messages in the request
  • live_zone_blocks – Content blocks processed by Live-Zone logic
  • strategy – 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 altered
  • strategy – 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:

  1. Enable INFO-level logs for the proxy by setting the environment variable HEADROOM_LOG_LEVEL=info.
  2. Capture the logs via stdout, file redirection, or a centralized logging system.
  3. Filter for the request ID using the request_id field included in every log line.
  4. Inspect the JSON fields to determine which strategy fired and whether the decision was compressed, no_change, or rejected.
  5. Cross-reference with Prometheus by querying proxy_compression_ratio_by_strategy to 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_ccr threshold (default 0.8, configurable via the Python API in crates/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 tracing in src/proxy.rs.
  • Routing logs contain critical fields including decision, reason, strategy, and strategy_info that explain why compression succeeded or failed.
  • The CompressionStrategy trait in traits.rs defines how each compressor returns CrushResult metadata describing the compression path.
  • Prometheus metrics proxy_compression_ratio_by_strategy and proxy_compression_rejected_by_token_check_total provide aggregate observability for spotting trends.
  • Adjust the min_compression_ratio_for_ccr threshold (default 0.8) in crates/headroom-py/src/lib.rs when 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →