# How to Debug Compression Issues Using Headroom's Routing Logs and Strategy Chain Metadata

> Debug compression issues in Headroom with routing logs and strategy chain metadata. Analyze decision fields, reason codes, and metadata for effective troubleshooting.

- Repository: [Tejas Chopra/headroom](https://github.com/chopratejas/headroom)
- Tags: how-to-guide
- Published: 2026-06-07

---

**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`](https://github.com/chopratejas/headroom/blob/main/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`](https://github.com/chopratejas/headroom/blob/main/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`](https://github.com/chopratejas/headroom/blob/main/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`](https://github.com/chopratejas/headroom/blob/main/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`](https://github.com/chopratejas/headroom/blob/main/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`](https://github.com/chopratejas/headroom/blob/main/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:

```rust
// 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();

```

```rust
// 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"]);

```

```rust
// 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);

```

```rust
// 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`](https://github.com/chopratejas/headroom/blob/main/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`](https://github.com/chopratejas/headroom/blob/main/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`](https://github.com/chopratejas/headroom/blob/main/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.