Transforming attributes in the OpenTelemetry Collector normalizes telemetry before it leaves a pipeline. Use the transform processor when incoming spans, metrics, or logs carry missing resource metadata, older semantic convention names, or custom keys that need to match a backend query model.
The transform processor uses OpenTelemetry Transformation Language, or OTTL, statements inside signal sections such as trace_statements, metric_statements, and log_statements. Each statement targets a telemetry context, so explicit paths such as resource.attributes and span.attributes keep the rule tied to the field being changed.
A local smoke test can receive one OTLP/HTTP trace, add resource attributes, rename a span attribute from http.method to http.request.method, and derive a service.tier value from the route. Keep the debug exporter only while checking the result because detailed exporter output can write service names, routes, and other telemetry attributes to Collector logs.
Steps to transform OpenTelemetry Collector attributes:
- Open the active Collector Contrib configuration file.
$ sudoedit /etc/otelcol-contrib/config.yaml
The transform processor is included in the otelcol-contrib and Kubernetes Collector distributions. Custom Collector builds must include the processor before this configuration can load.
- Add the transform processor to the trace pipeline.
- /etc/otelcol-contrib/config.yaml
receivers: otlp: protocols: http: endpoint: 0.0.0.0:4318 processors: transform/attributes: error_mode: ignore trace_statements: - context: resource statements: - set(resource.attributes["service.namespace"], "shop") - set(resource.attributes["deployment.environment.name"], "staging") - context: span statements: - set(span.attributes["http.request.method"], span.attributes["http.method"]) where span.attributes["http.method"] != nil - delete_key(span.attributes, "http.method") - set(span.attributes["service.tier"], "frontend") where span.attributes["http.route"] == "/checkout" exporters: debug: verbosity: detailed service: pipelines: traces: receivers: [otlp] processors: [transform/attributes] exporters: [debug]
error_mode: ignore keeps processing the record when a statement fails. Use propagate only when dropping the affected payload is safer than exporting it with the original attributes.
- Validate the Collector configuration.
$ otelcol-contrib validate --config=/etc/otelcol-contrib/config.yaml
No output with a zero exit status means the file parsed and the referenced receiver, processor, exporter, and pipeline exist in the Collector build.
- Restart the Collector service.
$ sudo systemctl restart otelcol-contrib
For a foreground smoke test, run otelcol-contrib --config=/etc/otelcol-contrib/config.yaml in one terminal and leave it open while sending telemetry from another terminal.
- Create an OTLP/HTTP trace payload with attributes to transform.
- trace.json
{ "resourceSpans": [ { "resource": { "attributes": [ { "key": "service.name", "value": { "stringValue": "checkout-api" } } ] }, "scopeSpans": [ { "scope": { "name": "manual-transform-smoke" }, "spans": [ { "traceId": "5b8efff798038103d269b633813fc60c", "spanId": "eee19b7ec3c1b174", "name": "checkout", "kind": 1, "startTimeUnixNano": "1717260000000000000", "endTimeUnixNano": "1717260001000000000", "attributes": [ { "key": "http.method", "value": { "stringValue": "POST" } }, { "key": "http.route", "value": { "stringValue": "/checkout" } } ] } ] } ] } ] }
The payload starts with service.name, http.method, and http.route. The processor should add service.namespace and deployment.environment.name, rename http.method, and add service.tier.
- Send the trace payload to the local OTLP/HTTP receiver.
$ curl --silent --show-error --include --request POST http://127.0.0.1:4318/v1/traces \ --header 'Content-Type: application/json' \ --data @trace.json HTTP/1.1 200 OK Content-Type: application/json Content-Length: 21 {"partialSuccess":{}}The 200 OK response confirms that the receiver accepted the trace. The transformed fields appear in the Collector log because the test pipeline exports to debug.
- Inspect the Collector log for transformed attributes.
$ journalctl -u otelcol-contrib --since "5 minutes ago" Jun 18 07:44:48 host otelcol-contrib[1234]: ResourceSpans #0 Resource attributes: -> service.name: Str(checkout-api) -> service.namespace: Str(shop) -> deployment.environment.name: Str(staging) ScopeSpans #0 InstrumentationScope manual-transform-smoke Span #0 Trace ID : 5b8efff798038103d269b633813fc60c ID : eee19b7ec3c1b174 Name : checkout Attributes: -> http.request.method: Str(POST) -> http.route: Str(/checkout) -> service.tier: Str(frontend)The old http.method key is absent, http.request.method is present, and the resource block contains the new namespace and deployment attributes.
- Replace the debug exporter before sending normal traffic.
- /etc/otelcol-contrib/config.yaml
exporters: otlp: endpoint: otel-gateway.example.com:4317 service: pipelines: traces: receivers: [otlp] processors: [transform/attributes] exporters: [otlp]
Review metric attribute transforms separately before changing metric names or labels. Removing or renaming metric-identifying attributes can split or merge time series in the backend.
- Remove the temporary smoke-test payload.
$ rm trace.json
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.