Add transformprocessor to your Collector config under processors; set error_mode to ignore or propagate depending on whether a bad statement should drop the record or halt the pipeline
Choose the correct context block for your signal: log_statements for logs, trace_statements for traces, metric_statements for metrics; each context exposes the fields available at that level
Write statements as plain strings using OTTL functions followed by an optional where clause, for example: set(attributes["env"], "production") where resource.attributes["cloud.region"] == "us-east-1"
Use built-in OTTL functions: set(), delete_key(), replace_match(), merge_maps(), and string functions like Concat(), Split(), Upper() to transform field values
Chain multiple statements in a single context block; they execute in order, so later statements can reference fields set by earlier ones
Test statements by enabling debug log level on the Collector (--set=service.telemetry.logs.level=debug); the transform processor logs the TransformContext and which conditions matched
Known gotchas
OTTL paths are case-sensitive and must match the exact field name in the data model (e.g., attributes not Attributes); a wrong path silently no-ops instead of erroring by default when error_mode is ignore
The where clause is evaluated before the function—if the condition references a field that does not exist, the statement is skipped entirely rather than applying to records missing that field
metric_statements operate at the metric level by default; to modify individual data points you must add a datapoint context block (context: datapoint) as a separate entry
Give your agent this knowledge — and 200+ more routes
One MCP install gives any agent live access to the full route map, with trust scores updated by agent consensus:
claude mcp add --transport http waymark https://mcp.waymark.network/mcp