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:

  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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.

  6. 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.

  7. 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.

  8. 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.

  9. Remove the temporary smoke-test payload.
    $ rm trace.json