Why an AI agent needs a stable pattern ID to cut your log bill
An AI agent cutting a log bill works in steps days apart: find the expensive messages, write a rule against one, check a week later what it removed. Each step has to point at the same message as the last, and a rule written against the text of a log line stops matching once a deploy changes that text. The check then reads zero, which looks exactly like success. 10x gives every line printed by the same statement in your code the same ID, so the rule and the check still mean the same message.
Cutting a log bill means finding the messages that dominate your volume, capping or rerouting the worst of them, and checking a week later what actually came off. It is repetitive, it is measurable, and every step is a query or a config change. That is a good fit for an AI agent, and agents are being pointed at it already.
The catch is the week in between. Whatever the agent capped, it capped by matching the text of a log line, and any deploy in that week can reword the line and stop the match. When the agent comes back to check, the number reads zero. That is indistinguishable from the message having gone away, so the agent reports a saving that never happened.
10x runs in-path with your log forwarder (Fluent Bit, the OpenTelemetry Collector, and others), so it sees every log line before your log platform does. It gives every line printed by the same statement in your code the same ID, and reports your volume against those IDs. Edit the wording of a message and its text changes, but the line of code printing it does not, so the ID an agent wrote a rule against last week still means the same message this week.
What breaks when a deploy changes the text
The OpenTelemetry Collector in this pipeline prints an exporter failure, carrying the exporter version and the source line number:
2026-07-27T16:10:03.063Z error opensearchexporter@v0.142.0/logger.go:36 Request failed.
{"resource": {"service.name": "otelcol-contrib", "service.version": "0.142.0"},
"otelcol.component.id": "opensearch",
"path": "/_bulk",
"duration": 0.003685783,
"reason": "dial tcp: lookup opensearch on 172.20.0.10:53: no such host"}Upgrading the exporter moves both, to v0.143.0 and line 41. A regular expression written against the earlier form was fed 20 of these lines, 10 from before the upgrade and 10 from after: it matched the 10 earlier ones and none of the later ones. An agent that wrote that rule and came back a week later would read zero and report success.
10x keys on the part a developer wrote, the class, the method and the message text, rather than on the values around it. That part comes out of a library compiled from your source, binaries and container images, so a message has an ID before it is ever printed. Run those same 20 lines through it three times, once on the earlier 10, once on the later 10, once on all of them, and every run returns one ID, with the version and line number recorded as values:
"input_line_count": 20,
"resolved_pattern_count": 1,
"template_hash": "2qiwE{k$rY",
"slots": [
{ "inferred_name": "slot_1",
"top_values": [ {"value":"142","pct":0.5}, {"value":"143","pct":0.5} ] },
{ "inferred_name": "logger.go",
"top_values": [ {"value":"36","pct":0.5}, {"value":"41","pct":0.5} ] }
]That check needs no pipeline and no account: log10x_resolve_batch runs the engine over lines pasted straight into it. It works on a single line too, which is where grouping tools cannot follow. Drain3, the library several log platforms build their pattern views on, works by comparing lines to each other, so from one line it can only return that line, timestamp included, matching nothing else until a second occurrence teaches it which parts vary.
The four calls an agent needs to make to cut the bill
These are functions on an MCP server, which is how an AI assistant is handed things it can call. Each call takes an ID the previous one returned.
1. Rank. log10x_top_patterns returns the messages ordered by volume, each with its ID. Asked for the side that never reached the platform, it returned 161 message types totalling 88.8 GB, out of 182.2 GB in 24 hours. Close to half the volume is missing from any export you could pull from the platform, because the platform never received it.
2. Attribute. log10x_services splits each service's bytes by what the engine did with them, so the agent can see where that held-back volume sits before it touches anything:
service passed offloaded compacted dropped
product-reviews 11.25 GB 0 0 32.04 GB
cart 4.98 GB 37.23 GB 0 0
payment 6.79 GB 10.06 GB 0 6.64 GB
llm 4.51 GB 0 0 13.95 GB
opentelemetry-collector 0.54 GB 0 0 9.33 GB3. Act. log10x_configure_engine takes a service and a percentage and returns a plan. Given payment, which runs 705.3 GB a month, and a 40% cut, it came back with three message types worth capping, keyed to the IDs the first call returned. The plan ships as a pull request; once merged, the engine picks it up on its next poll with the pipeline still running.
4. Verify. A week later, log10x_estimate_savings compares the week before against the week after and splits the difference four ways: what the caps removed, what drifted, what arrived as message types that did not exist before, and what got through anyway. On payment, the caps accounted for 46.53 GB.
That last call is where the chain holds or quietly fails. It reads the same IDs the first call handed over, a week and any number of deploys later. Had those IDs come from log text, a deploy inside the window would change what the two halves of the subtraction were counting, and the drift the split exists to expose would disappear into the result.
The lever the agent picks depends on the platform
The same ID supports different actions depending on what each platform can do about a message once you have singled one out. The agent asks which of them apply before it plans anything, because picking the wrong one wastes the week.
- Datadog bills for the events it indexes, so a smaller event costs exactly what a large one does. Move the message to Flex Logs, the cheaper tier Datadog already sells, or route it out to an S3 bucket you own.
- CloudWatch bills for the bytes it ingests and hands back the text it was given, so shrinking saves nothing. Move the message to Infrequent Access, at half the ingest price, or to your own S3. The routing rule has to exist on the CloudWatch side before the cheaper rate applies.
- Splunk takes either. Routing to S3 keeps the message out of the index entirely, and where the 10x app is installed, shrunk events stay searchable because the app expands them at search time.
- Elasticsearch, self-run, takes either as well, and the 10x plugin cuts what sits on disk by roughly half with existing queries unchanged. Managed Elasticsearch cannot run that plugin, so S3 is the only route there.
- ClickHouse is the one place shrinking leads, because plain SQL returns the original lines and there is nothing to install.
- Azure Monitor bills most to ingest into the Analytics plan. Move the message to the cheaper Basic or Auxiliary table plan, or offload it to a storage account the subscription owns.
- Coralogix prices each gigabyte by the priority class it lands in. Move the message from High to Medium, where it stays queryable with alerting and dashboarding, or offload it to a bucket you own. Nothing forks to reach the cheaper class, so the decision has to arrive as a field on the event for the policy to read.
This pipeline ships to CloudWatch, which is why the compacted column above reads zero on every row, and why the plan moved messages to a cheaper tier instead.
Capped messages can still be read back from S3
Capping a message means one of two things here, and the engine's record distinguishes them: cart's 37.23 GB was routed to an S3 bucket in your account and still exists, while the collector's 9.33 GB was discarded at the forwarder and does not.
The routed side stays addressable by the same ID the cap was written against, which is what lets the agent go back for it. log10x_overflow_contents lists that bucket by message type and log10x_retriever_query reads the events behind one of them, through an index held in the S3 object keys. A message can come off the bill and still answer a question a week later.
Installing the tools and the engine
The MCP server is at github.com/log-10x/log10x-mcp, MIT licensed, and installs with npx -y log10x-mcp. The counts it reads come from the engine in your pipeline, which the install guide covers putting there. The local check needs neither, so the upgrade test above is the cheapest place to start.