Skip to main content

Profile LLM gateway logs for prefix-cache reuse potential, and export anonymized replayable traces

Project description

llmtrafficlens

Point it at your LLM gateway's request log. It answers how much a prefix cache could save on your real traffic — before you build anything — and turns the log into an anonymized trace the standard benchmark tools can replay.

Two commands. Everything downstream of the trace is left to the tools that already do it well.

  gateway log CSV ──► llmtrafficlens profile ──► report.html / .json
   · request_json                                 decision numbers
   · timestamp, status
                  └──► llmtrafficlens export  ──► trace.jsonl
                                                  AIPerf · SGLang · AIBrix
                                                  · Mooncake simulator

Install

pip install llmtrafficlens

Zero runtime dependencies. Python ≥ 3.10.

profile — the decision numbers

llmtrafficlens profile gateway.csv -o report

Input: a CSV with a request_json column holding the OpenAI-format request body. Picked up automatically when present: response_json, model_name, status_code, and a timestamp column (timestamp, ts, created_at, ...; epoch or ISO-8601 — or name it with --ts-column). Public Mooncake and qwen-bailian traces also work as input (--format mooncake|bailian).

Output (report.html + report.json):

  • Hit rate by cache size — one LRU simulation per capacity, ending with the unbounded case: your ceiling.
  • Dual-metric prefix leaderboard — top prefixes by reuse count vs by reusable token volume. The heads differ, and only the second one matters: a 15-token greeting reused 870× is worthless to a cache; a 19K-token system prompt reused 95× is the whole prize.
  • Session-identifier presence — whether reuse is reachable by session affinity at all.
  • Input/output token distributions, streaming ratio, model mix, QPS.

Reading it: a 3% ceiling ends the discussion — decline the routing project with evidence. A 40% ceiling with 85% session-id presence means cheap session affinity captures most of it. A 40% ceiling with 0% presence means reuse lives in cross-request shared prefixes that only prefix-aware routing reaches, and the leaderboard names the prefixes it has to keep resident.

Where the curve flattens toward the ceiling is your cache-sizing answer; multiply tokens by per-token KV size for GB. See the next section for a worked example, and Methodology for two caveats that matter here.

export — an anonymized, replayable trace

llmtrafficlens export gateway.csv --to mooncake -o trace.jsonl   # or --to bailian

Hand-written benchmarks with uniform prompt groups report inflated hit rates, because every group stays warm. Replaying your own traffic avoids that, and the trace is safe to hand around: each request becomes one line of structure with no text.

{"timestamp": 1753340000123, "input_length": 1994, "output_length": 117,
 "hash_ids": [4251731047194047120, 8125214104179782736, ...]}

hash_ids is a salted chained block-hash fingerprint: two requests share the first N hashes exactly when they share their first N blocks. Replay tools regenerate synthetic prompts from the hashes — same hash, same synthetic block — so the prefix-sharing structure of production is reproduced while the content is fake.

Then hand it to the tools built for replay:

# faithful replay at the recorded pace
aiperf profile --custom-dataset-type mooncake_trace --input-file trace.jsonl --fixed-schedule ...
# same trace, 2× the pace (rate sweeps without leaving replay)
aiperf profile --custom-dataset-type mooncake_trace --input-file trace.jsonl --synthesis-speedup-ratio 2.0 ...
# or SGLang
python -m sglang.bench_serving --dataset-name mooncake --dataset-path trace.jsonl ...

--to bailian adds chat_id / parent_chat_id / turn for AIPerf's bailian_trace mode; use it when your log carries session identifiers. Tell the consumer which block size you exported with — AIPerf defaults to 512 for mooncake and 16 for bailian (--prompt-input-tokens-block-size).

Not yet verified: we have not round-tripped an export through AIPerf or SGLang ourselves. The formats match their documented schemas; replay verification is on the roadmap.

Try it on a public trace

No data of your own required, and it doubles as a correctness check:

curl -LO https://raw.githubusercontent.com/kvcache-ai/Mooncake/main/FAST25-release/traces/conversation_trace.jsonl
llmtrafficlens profile conversation_trace.jsonl --format mooncake -o mooncake-report

The curve it reports over those 12,031 requests:

cache size (tokens) hit rate
16K 3.3%
64K 4.2%
256K 4.3%
1M 5.6%
4M 18.5%
16M 34.2%
unbounded 37.4% (ceiling)

This workload only takes off past 1M tokens: a small cache buys almost nothing, and most of the ceiling is reachable at 16M.

Feed the same trace to the official KV Cache Hit Rate Simulator and compare its infinite-capacity ceiling. Ours is consistent with third-party analysis of this trace (a prefix-caching study reports ≈40% for the conversation workload, arXiv:2505.21919); an automated side-by-side check against the official simulator has not been run yet.

A second, fully synthetic sample lives in the source repository (not in the pip package): 360 requests, three shared system prompts with deliberately skewed popularity, sparse session keys, real timestamps. llmtrafficlens profile examples/sample_gateway.csv reports a 66.4% ceiling and, more interestingly, a leaderboard whose two heads disagree — 16 tokens × 180 requests is 2.3% of the reusable volume, while 2400 tokens × 30 requests is 55.6% of it. Regenerate it with python examples/generate_sample.py.

Methodology

Every number follows a published construction; deviations are listed, not hidden.

  • Hit rate — replay requests in timestamp order against an LRU block cache. Unbounded capacity is the "ideal hit rate" of KVCache in the Wild (ATC'25) and the Mooncake simulator's infinite-capacity ceiling; bounded capacities give the Mooncake simulator's capacity curve. LRU is the default eviction policy in vLLM and SGLang. The simulation models a single global cache (one worker, or perfect routing): with N workers behind hash routing each sees a partition, so treat it as fleet-level guidance. The engine's KV pool also holds in-flight requests — the reuse pool is what remains.
  • Block hashing — chained per-block hashing (hash(parent, block), 16-token blocks) follows the vLLM prefix-cache block scheme and the qwen-bailian trace convention. Deviation: in approximate mode we hash fixed-size character chunks, not tokenizer output, so two prompts match only if byte-identical.
  • Token counts — chars/4 unless the log carries usage (exact counts are then used and marked in the report). CJK-heavy text tokenizes closer to 1–2 chars/token: absolute counts skew low, ratios stay usable.
  • Coverage — the ceiling covers cross-request sharing only. Intra-session reuse is invisible unless the log carries session ids. Without a timestamp column, row order stands in: arrival stats are omitted and exports are flagged unfit for fixed-schedule replay.

Privacy

All processing is local. Reports contain aggregates only. Exports contain lengths, timestamps, anonymized session ids, and keyed block hashes — a vendor can reproduce your cache behavior and tune against it without recovering a word of any prompt. The hash key is generated at .ltl-salt — keep it stable across runs and treat it as a secret.

Scope

Observability platforms (Langfuse, Helicone, Datadog LLM) count tokens and cost but never look inside prompt structure. Trace analyzers (Mooncake simulator, AIPerf analyze-trace) require pre-hashed traces. Load generators and capacity simulators (AIPerf, SGLang, Vidur) consume traces nobody produces from production logs (our survey: July 2026). llmtrafficlens fills exactly that gap and stops there: raw gateway logs → structure → decision numbers → a standard trace. Replay, rate control, and deployment search belong to the tools above.

License

Apache-2.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

llmtrafficlens-0.3.3.tar.gz (17.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

llmtrafficlens-0.3.3-py3-none-any.whl (21.9 kB view details)

Uploaded Python 3

File details

Details for the file llmtrafficlens-0.3.3.tar.gz.

File metadata

  • Download URL: llmtrafficlens-0.3.3.tar.gz
  • Upload date:
  • Size: 17.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for llmtrafficlens-0.3.3.tar.gz
Algorithm Hash digest
SHA256 272313a7f668a318accd4ad338e5c3425393654c376cfe96aea68d74728c6b6b
MD5 2500c64237c9f2d61090303bbcd5907f
BLAKE2b-256 9fcc398210fbc5bec0fdfb84f001ef244b47412f3755154a61c93820b81df00f

See more details on using hashes here.

File details

Details for the file llmtrafficlens-0.3.3-py3-none-any.whl.

File metadata

  • Download URL: llmtrafficlens-0.3.3-py3-none-any.whl
  • Upload date:
  • Size: 21.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for llmtrafficlens-0.3.3-py3-none-any.whl
Algorithm Hash digest
SHA256 b4b6a224bd5f71e3f44cce8e75c40b9271174746d064d1d6683c73f76bf104e4
MD5 bf61571c29a538ea22bc7d9a382f5a5f
BLAKE2b-256 858141b3ef3e590e851e210e9e59ed80e2284bc7bb0e8f0a0bc463558d73473c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page