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:
- Go to Project → Transformations in the left navigation.
- Click New Operation → New operation from YAML.
- Paste a YAML rule and click Create.
Common recipes
Drop health check spans
name: Drop healthcheck spans
scope: [spans]
type: drop
if: spanName() == "GET /healthz" && spanStatusCode() != "error"
Sample successful requests
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
name: Rename service to service_name
scope: [spans, logs, events, datapoints]
type: rename_attr
old_key: service
new_key: service_name
Reduce URL cardinality
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
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
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:
spanslogseventsdatapoints
Conditions
Narrow which records an operation applies to using an if expression written in Expr:
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.name → service_name). A drop operation stops execution for that record. All other operations always run to completion regardless of errors.
Use run_order to control order when two operations must run in a specific sequence. The lowest value runs first, and an absent value is 0:
name: Rename service to service_name
scope: [spans, logs, events, datapoints]
run_order: 100
type: rename_attr
old_key: service
new_key: service_name
run_order replaces the deprecated priority key. Uptrace still reads priority when run_order is absent.
Debugging the pipeline
Click Debug on the Project → Transformations page, or Debug in the operation editor, to open the pipeline debugger. It is a separate page with its own link. Select a real recent record and see how each operation changes it. When you open the debugger from the editor, the unsaved operation is placed in the pipeline, so you can test it before you save it.
Transformations run before Uptrace processes data internally, so certain computed columns are not yet available. Use these replacements:
| Uptrace column | Replacement |
|---|---|
_display_name | spanName(), eventName(), attr("log_message") |
db_arg_* | attr("db_statement") contains "something" |
http_response_status_class | http_response_status_code |
user_agent_* | user_agent_original |
Next steps
- Operations & functions reference — all operation types and built-in functions
- Searching — use
*:valueafter configuring a text index - Observability as Code — manage transformation rules as version-controlled YAML files