Transformations

Transformations let you modify ingested telemetry before it reaches storage. Each operation is a small YAML rule applied to spans, logs, events, or metric datapoints — in the order you define. Use them to clean up noisy data, normalize attribute names, reduce cardinality, and control costs.

To create an operation:

  1. Go to Project → Transformations in the left navigation.
  2. Click New Operation → New operation from YAML.
  3. Paste a YAML rule and click Create.

Common recipes

Drop health check spans

yaml
name: Drop healthcheck spans
scope: [spans]
type: drop
if: spanName() == "GET /healthz" && spanStatusCode() != "error"

Sample successful requests

yaml
name: Sample 10% of successful spans
scope: [spans]
type: sample
fraction: 0.1
if: spanStatusCode() != "error"

Sampling for spans is trace-aware: all spans in the same trace are either kept or dropped together, preserving trace completeness.

Rename a legacy attribute

yaml
name: Rename service to service_name
scope: [spans, logs, events, datapoints]
type: rename_attr
old_key: service
new_key: service_name

Reduce URL cardinality

yaml
name: Normalize user profile URLs
scope: [spans]
type: script
if: hasAttr("http_target")
then:
  - setAttr("http_target", replaceGlob(attr("http_target"), "/user/*/profile", "/user/{id}/profile"))

Build a full-text index

yaml
name: Index request and exception attributes
scope: [spans, logs, events]
type: text_index
include:
  - log_message
  - exception_message
  - http.request.**
exclude:
  - http.request.headers.**

Once configured, search indexed content with *:value in the search bar.

Enrich IP addresses with geo data

yaml
name: Enrich client IP with geo data
scope: [spans, logs, events]
type: ip_geo_attrs
keys:
  - custom_ip_address

Adds {key}_country_code, {key}_country_name, and {key}_city attributes for each specified key.

How operations work

Scope

Every operation requires a scope field that limits it to specific signal types:

  • spans
  • logs
  • events
  • datapoints

Conditions

Narrow which records an operation applies to using an if expression written in Expr:

yaml
name: Rename service to service_name
scope: [spans, logs, events, datapoints]
type: rename_attr
old_key: service
new_key: service_name
if: attr("deployment_environment") == "prod"

Execution order

Uptrace runs all operations in order after normalising attribute names (e.g. service.nameservice_name). A drop operation stops execution for that record. All other operations always run to completion regardless of errors.

Use priority to control order when two operations must run in a specific sequence:

yaml
name: Rename service to service_name
scope: [spans, logs, events, datapoints]
priority: 100
type: rename_attr
old_key: service
new_key: service_name

Transformations run before Uptrace processes data internally, so certain computed columns are not yet available. Use these replacements:

Uptrace columnReplacement
_display_namespanName(), eventName(), attr("log_message")
db_arg_*attr("db_statement") contains "something"
http_response_status_classhttp_response_status_code
user_agent_*user_agent_original

Next steps