Filtering telemetry should be one of the most boring things you do in an observability pipeline: drop noisy stuff, keep what you need, don’t accidentally remove signals you care about. In practice, it’s often the opposite—especially in OpenTelemetry Collector configurations where you end up thinking more about the Collector’s internal data model than about your actual filtering intent.
That’s why the OpenTelemetry project’s update in collector-contrib v0.146.0 is worth paying attention to: OTTL context inference is now available in the Filter Processor. Instead of splitting your drop rules across different context blocks (resource vs span vs span event vs datapoint…), you can write flat, readable conditions with prefixes that make the context obvious.
The old problem: context blocks turn intent into bureaucracy
In legacy configurations, filter rules must be placed inside specific context sections like resource, span, or spanevent. Even when your intent is a single logical policy—“drop spans from a particular container unless severity is WARN+” or “drop events matching some pattern”—you’re forced to express it as multiple disjoint lists purely because of internal structure.
That has two costs:
- Human cost: configs become hard to review. Every PR turns into “wait, what context is this evaluated in?”
- Operational cost: when configs are hard to reason about, teams ship changes slower and keep more noise “just in case.”
What changed: *_conditions fields with context inference
With context inference, the Filter Processor adds four new top-level config fields:
trace_conditionsmetric_conditionslog_conditionsprofile_conditions
You now write a flat list of conditions and specify context explicitly by prefixing paths with resource, scope, span, spanevent, metric, or datapoint (depending on the signal type). The processor infers the evaluation context from that prefix and groups/executes the conditions appropriately.
The result is a config that reads like policy, not like a schema puzzle.
Evaluation semantics: short-circuiting improves both correctness and cost
One subtle but important detail: inference isn’t just syntactic sugar. The processor executes grouped conditions hierarchically from higher to lower levels (for traces: resource → scope → span → spanevent). If a higher-level condition matches, the processor drops the subtree immediately and skips evaluating deeper levels. That means:
- You avoid wasting CPU evaluating span-event rules for resources you already know you want to drop.
- It’s easier to predict the blast radius of a rule: a resource-level match removes everything under it.
Cross-context conditions: power with a sharp edge
The new system also allows cross-context expressions (for example: “drop span events if the resource host is localhost OR event name is grpc.timeout”). These expressions can be evaluated at a specific level (e.g., per span event), which is powerful—but it means you need to be careful about what you are (and aren’t) dropping. In the example above, the span events get dropped; the parent spans remain.
Practical guidance: when adopting context inference, document whether your policy is intended to drop resources, spans, span events, or individual datapoints—and write one “explainability” comment per rule group in your config repo.
Migration strategy: adopt without breaking production
The OpenTelemetry maintainers note that the legacy configuration remains supported and backwards compatible. So you can adopt this incrementally:
- Start with a single service: convert its noisiest drop rules into
*_conditions. - Validate with sampling: run a canary Collector instance and compare output volumes and exemplars.
- Measure cost: if you have very high-cardinality telemetry, the short-circuit behavior can be a meaningful CPU win.
- Standardize patterns: create a shared library of “blessed” filtering snippets for your org.
Why this matters beyond “nicer YAML”
OpenTelemetry adoption is no longer a science experiment; it’s infrastructure. Changes like this reduce the friction of operating the Collector at scale—especially in Kubernetes clusters where the Collector ends up as a shared platform service. In practice, easier filtering leads to:
- Less telemetry noise (and lower spend)
- Fewer accidental drops
- Faster review cycles on observability PRs
