Jorge Turbica / blog · Blog ← All articles ES · Leer en español
Technologies

OTTL hits v1: the syntax of your OTel Collector rules is frozen for all of 1.x

As of Collector contrib v0.164.0, OTTL is stable for traces, metrics and logs. What the guarantee covers, what it leaves out, which gates to drop.

The rules you write in the transform processor to drop a header or relabel a span now come with a contract. As of opentelemetry-collector-contrib v0.164.0, released on October 26, 2026, the OpenTelemetry Transformation Language (OTTL) is stable for traces, metrics and logs. A statement that parses today will parse, and behave the same way, on every 1.x release.

OTTL was still beta, even though 14 Collector components already rely on it: the transform, filter, tail sampling and log deduplication processors, the routing, count and signal-to-metrics connectors, and a couple of exporters. In other words, much of the filtering and enrichment in any serious telemetry pipeline. With v1 it stops being a bet.

What OTTL 1.x guarantees

The syntax is frozen: paths (span.attributes[...]), literals, operators, function calls and where clauses, as defined in the language reference. Minor releases may add syntax, but never remove existing syntax or change what it means. The same goes for the standard function library: functions won't be removed or have their signatures changed in incompatible ways. The Go API, for anyone maintaining custom components on top of OTTL, is also meant to stay backward compatible.

For platform teams this changes how Collector upgrades work. Until now, every bump meant scanning the pkg/ottl changelog in case a function was renamed or a path moved to another context. From here on, transformation rules can be treated as stable, versioned configuration like the rest of the pipeline.

What the contract leaves out

Not everything is covered by v1, and the exclusions are exactly the parts people are most tempted to use:

  • Lambda-powered functions (Filter, MapEach, MapKeys, Any, All, Find, Reduce, When) remain experimental and require the ottl.functions.enableLambda feature gate.
  • Profiles support lives in the xprofile module, still at 0.x.
  • New functions start in xottl, can change or disappear in any release, and are enabled with --feature-gates=pkg.ottl.functions.enableExperimental, with no custom Collector build needed.

To join the standard set, an experimental function needs at least two minor releases in that state, complete tests and docs, no open change proposals, and real user demand. Once promoted, its signature is frozen. My advice: if a critical rule (say, the one that strips personal data from logs) depends on an experimental function or a lambda, rewrite it with standard functions before you call the pipeline stable.

What breaks when you upgrade to v0.164.0

The project used stabilization as a chance to clean house. It removed long-deprecated functions such as Base64Decode and the old profile functions, plus feature gates that had already reached stable (ottl.PanicDuplicateName and ottl.contexts.enableOTelColContext). v0.164.0 itself also removes:

  • The ottl.set.allowNil gate in pkg/ottl.
  • The processor.filter.defaultErrorModeIgnore gate in the filter processor.

If any of those gates are still in your startup flags, drop them before upgrading. In the transform processor, flatten_data is now deprecated in favor of flatten.log and will be removed in a future release, so this is a good time to switch.

How to upgrade the Collector

The contrib distribution, which ships the OTTL-based processors, is on Docker Hub tagged by version:

bash
docker pull otel/opentelemetry-collector-contrib:0.164.0

Before rolling out, check the configuration with your distribution binary's validate subcommand:

bash
otelcol validate --config=customconfig.yaml

A typical rule, like the documentation example that marks 400 responses as OK, carries over to v1 unchanged:

yaml
transform:
  error_mode: ignore
  trace_statements:
    - set(span.status.code, STATUS_CODE_OK) where span.attributes["http.request.status_code"] == 400

Checklist before production:

  1. Search your config and container arguments for the four removed gates and delete them.
  2. If you are several releases behind, read the pkg/ottl entries in the contrib changelog between your version and v0.164.0, and grep your rules for Base64Decode.
  3. Inventory which statements use lambdas or xottl functions: those carry no guarantee.
  4. Run validate in CI against the new image and, in staging, compare span and log volume at the filter processor's output. A change in error handling shows up there before anywhere else.

Next up: the transform processor

A stable language doesn't make every component that uses it stable. The transform processor is being promoted to stable, with its testing, documentation, configuration and observability reviews already done. Lambdas and their Go API are being considered for the v1 guarantee, and xprofile could join once profiles stabilize.

Sources

Jorge Turbica

Software Engineer and SRE. I write about the real challenges I run into in production.

See portfolio ↗