AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified Apache-2.0 Self-run

Otel Ottl

skill-ollygarden-opentelemetry-agent-skills-otel-ottl · by ollygarden

OpenTelemetry Transformation Language (OTTL) expert for writing and debugging telemetry transformations in the OpenTelemetry Collector. Use when authoring or reviewing `transform`, `filter`, `routing`, or `tail_sampling` processor configs, debugging OTTL syntax or semantics, transforming traces, metrics, logs, or profiles, or converting data-processing requirements into OTTL statements.

No reviews yet
0 installs
24 views
0.0% view→install

Install

$ agentstack add skill-ollygarden-opentelemetry-agent-skills-otel-ottl

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-ollygarden-opentelemetry-agent-skills-otel-ottl)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
2mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Otel Ottl? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

OpenTelemetry Transformation Language (OTTL)

OTTL is a domain-specific language for transforming telemetry inside the OpenTelemetry Collector. It is consumed by the transform, filter, routing, and tail_sampling processors (and a few others) in opentelemetry-collector-contrib.

This skill targets pkg/ottl as of collector-contrib v0.149.0. Function and path availability before that version differs; check the upstream pkg/ottl/ottlfuncs/README.md and pkg/ottl/contexts/*/README.md for the exact set in any older release.

Statement syntax

function(arguments) [where condition]

Every statement has exactly one editor (lowercase: set, delete_key, append, …) optionally guarded by a where clause whose body is a boolean expression. Conditions can call converters (uppercase: Concat, IsMatch, ParseJSON, …) which return values but do not mutate telemetry.

set(span.attributes["env"], "prod") where resource.attributes["env"] == nil

Workflow

  1. Pick the processor. transform rewrites; filter drops; routing fans out by pipeline; tail_sampling keeps/drops traces. The processor decides which contexts and function set are usable.
  2. Pick the context. resource, scope, span, spanevent, metric, datapoint, log, profile, profilesample. Operate at the lowest level that gives you the data — using datapoint to set attributes is much cheaper than walking through metric.data_points from the metric context.
  3. Write statements. Reach for references/quick-reference.md for common recipes; references/contexts.md for paths/enums; references/functions.md for the editor and converter catalog.
  4. Set error_mode. ignore (default) keeps the pipeline running and logs errors; silent does the same but quietly; propagate aborts on first failure (use only when you want a bad config to fail loud in tests).
  5. Verify. OTTL gotchas are the kind that pass the eye test (see [Common gotchas](#common-gotchas)). Use the [telemetrygen verification recipe](../telemetrygen/SKILL.md#verifying-a-collector-config) — otelcol-contrib + file exporter + telemetrygen — to confirm the snippet does what the prose claims before shipping.

Contexts at a glance

OTTL paths are scoped by signal. Higher levels are reachable from lower ones (e.g., resource.attributes from a span statement); the reverse is not true.

| Context | Common paths | |---------|--------------| | Resource | resource.attributes["service.name"], resource.metadata["X-Tenant-ID"] | | Scope | scope.name, scope.version, scope.attributes["…"] | | Span | span.name, span.kind, span.status.code, span.attributes["…"], span.flags | | Span Event | spanevent.name, spanevent.attributes["…"], spanevent.event_index | | Metric | metric.name, metric.unit, metric.type, metric.aggregation_temporality | | DataPoint | datapoint.value_double, datapoint.value_int, datapoint.attributes["…"] | | Log | log.body, log.body.string, log.severity_number, log.attributes["…"] | | Profile | profile.profile_id, profile.attributes["…"] (Development) |

Full path inventory plus enums in references/contexts.md.

Essential functions

# Editors (mutate telemetry)
set(target, value)
delete_key(target, key)               # delete by exact key
delete_matching_keys(target, regex)   # delete by regex
delete_index(target, index)           # remove from a slice (v0.145+)
keep_keys(target, [k1, k2])           # keep only these keys
merge_maps(target, source, "upsert")  # "insert" | "update" | "upsert"
truncate_all(target, max_len)         # UTF-8 safe by default in v0.148+
replace_pattern(target, regex, replacement)

# Converters (return values)
Concat([a, b], "-")
Split(s, ",")
ToLowerCase(s) / ToUpperCase(s)
IsMatch(s, "pattern")                 # bool
String(v) / Int(v) / Double(v) / Bool(v)
ParseJSON(s) / ParseKeyValue(s, "&", "=")
URL(s)                                # parse URL components (v0.127+)
ExtractPatterns(s, "(?P…)")     # named captures → map
ExtractGrokPatterns(s, "%{IP:client}") # Grok (v0.130+)
IsInCIDR(ip, ["10.0.0.0/8"])          # CIDR membership (v0.146+)
SHA256(v) / Murmur3Hash(v) / XXH3(v)  # hashing
UUID() / UUIDv7()

Full catalog with signatures in references/functions.md.

Common patterns

# Conditional set
set(span.attributes["sampled"], true)
    where (span.end_time_unix_nano - span.start_time_unix_nano) > 1000000000

# Normalize a value
set(span.attributes["http.method"],
    ToUpperCase(String(span.attributes["http.method"])))

# Parse a JSON log body into structured attributes
set(log.attributes, ParseJSON(log.body.string))
    where IsString(log.body) and IsMatch(log.body.string, "^\\s*\\{.*\\}\\s*$")

# Mark errored HTTP spans
set(span.status.code, STATUS_CODE_ERROR)
    where IsInt(span.attributes["http.status_code"])
      and Int(span.attributes["http.status_code"]) >= 400

# Redact secrets by key pattern
delete_matching_keys(span.attributes, "(?i).*(password|secret|token|apikey).*")

# Hash PII rather than dropping it (preserves cardinality for analytics)
set(span.attributes["user.email_hash"], SHA256(span.attributes["user.email"]))
delete_key(span.attributes, "user.email")

More recipes (sampling, redaction, time math, parsing) in references/quick-reference.md.

Processor wiring

processors:
  transform:
    error_mode: ignore        # ignore | silent | propagate
    trace_statements:
      - context: span
        statements:
          - set(span.attributes["processed"], true)
    log_statements:
      - context: log
        statements:
          - set(log.attributes["source"], "collector")
    metric_statements:
      - context: datapoint
        statements:
          - set(datapoint.attributes["env"], "prod")

  filter:
    error_mode: ignore
    traces:
      span:
        - 'IsMatch(span.name, "^/health.*")'
    logs:
      log_record:
        - 'log.severity_number  1024

Or use truncate_all for whole maps (UTF-8 safe by default since v0.148):

truncate_all(span.attributes, 1024)

attributes processor ≠ resource processor

The OTel attributes processor only operates on span/log/metric attributes. To touch a resource attribute use the resource processor or a transform processor with context: resource. A config like attributes/strip_resource: actions: [...delete os.description...] runs without error but doesn't change resource attributes — silent no-op.

logdedup paths use dot-notation only

The processor accepts include_fields / exclude_fields (not fields). Paths must start with attributes. or body. and use dot-notation. Bracket notation (attributes["service.name"]) is rejected, and resource[...] paths are not addressable. Default behavior dedups on the full record, which is usually what's wanted.

k8sattributes cannot extract k8s.cluster.name

The processor's metadata list is restricted to pod-level identity. Cluster name has to come from resourcedetection or a static resource processor that reads it from an env var.

Path syntax changed in v0.120

In older configs you may see span_event.* — current syntax is spanevent.*. Cache paths now require the context prefix: write span.cache["x"] not just cache["x"]. Plain cache is only valid in profile/profilesample contexts where it's the documented path. Paste-from-old-config is the most common source of regressions.

Base64Decode is deprecated

Use Decode(value, "base64") instead. The same Decode converter handles base64-raw, base64-url, base64-raw-url, and IANA character set encodings. Keep Base64Decode only if pinned to a pre-v0.141 collector.

Bool converter coercion is loose

Bool("true"), Bool("1"), Bool(1) all return true; Bool("false"), Bool("0"), Bool(0), Bool(0.0) return false. Anything else errors. Don't assume Python-like truthiness for arbitrary strings.

Verify before publishing

YAML/OTTL gotchas like the above pass the eye test. Use the [telemetrygen verification recipe](../telemetrygen/SKILL.md#verifying-a-collector-config) (otelcol-contrib + file exporter + telemetrygen) to confirm the snippet does what the surrounding prose claims, especially before shipping to a customer or production.

Best practices

  1. Validate inputs before conversion: where IsString(x), where x != nil.
  2. Order conditions by selectivity (cheap and most-selective first). span.kind == SPAN_KIND_SERVER and IsMatch(...) lets the kind check short-circuit before the regex runs.
  3. Cache expensive operations in .cache: set(span.cache["url_parts"], Split(span.attributes["http.url"], "/")), then read from cache.
  4. Use the most specific context. datapoint for metric-attribute work beats walking metric.data_points from the metric context.
  5. Escape regex correctly. Use \\d+, \\., \\s+ in OTTL strings (single backslash in YAML becomes a literal).
  6. Prefer keep_keys to a long list of delete_key when shaping output — easier to read, fails closed.

Versioning notes

Recently added (still useful to know which release introduced them when supporting users on older collectors):

| Feature | Since | |---------|-------| | Profile / ProfileSample contexts | v0.124 / v0.132 (Development) | | Cache paths require context prefix; spanevent rename | v0.120 (breaking) | | delete_index editor | v0.145 | | span.flags path | v0.145 | | .metadata for client request metadata | v0.147 | | truncate_all UTF-8 safe default (utf8_safe parameter) | v0.148 (behavior change) | | SpanID / TraceID accept hex strings | v0.142 | | flatten resolveConflicts parameter | v0.139 | | Base64Encode | v0.147 | | Decode, deprecates Base64Decode | v0.141 | | Bool converter | v0.143 | | ExtractGrokPatterns | v0.130 | | URL, UserAgent | v0.127, v0.134 | | IsInCIDR | v0.146 | | Murmur3Hash*, XXH3, XXH128 | v0.129, v0.135 | | Sort, Index, SliceToMap | v0.125, v0.126, v0.128 | | UUIDv7, ParseSeverity, CommunityID | v0.138, v0.133, v0.131 |

References

  • references/contexts.md — context paths and enums
  • references/functions.md — editors and converters with signatures
  • references/quick-reference.md — recipes, regex patterns, troubleshooting
  • Upstream:

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.