# Operations & Functions Reference

> Complete reference for all Uptrace transformation operation types and built-in Expr functions for spans, logs, events, and metric datapoints.

Complete reference for all transformation operation types and built-in functions. See [Introduction](/features/transformations) for an overview, scope rules, and common recipes.

## Operations

### Rename attribute

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

Set `overwrite: true` to overwrite the target attribute if it already exists:

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

### Delete attributes

By key list:

```yaml
name: Delete foo and bar
scope: [spans, logs, events, datapoints]
type: delete_attrs
keys:
  - foo
  - bar
```

By regular expression:

```yaml
name: Delete foo and bar
scope: [spans, logs, events, datapoints]
type: delete_attrs
regexp: ^(foo|bar)$
```

Scoped to a specific metric:

```yaml
name: Delete foo and bar from my_metric
scope: [datapoints]
type: delete_attrs
keys:
  - foo
  - bar
if: metricName() == "my_metric_name"
```

### Keep attributes

```yaml
name: Keep foo and bar
scope: [spans, logs, events, datapoints]
type: keep_attrs
keys:
  - foo
  - bar
```

By regular expression:

```yaml
name: Keep foo and bar
scope: [spans, logs, events, datapoints]
type: keep_attrs
regexp: ^(foo|bar)$
```

### Drop

```yaml
name: Drop hello logs
scope: [logs]
type: drop
if: attr("log_message") contains "hello"
```

```yaml
name: Drop Redis evalsha
scope: [spans]
type: drop
if: spanName() == "evalsha" && spanStatusCode() != "error"
```

The `if` condition is required for `drop`. Execution stops for the matching record — subsequent operations are skipped.

### Sample

```yaml
name: Sample 50% hello logs
scope: [logs]
type: sample
fraction: 0.5
if: attr("log_message") startsWith "hello"
```

`fraction` must be between 0 and 1. For spans, sampling is trace-aware: all spans in a trace are kept or dropped together. The `if` condition is optional — omitting it applies sampling to all records in scope.

### Change attribute type

```yaml
name: Convert elapsed_ms to float
scope: [spans]
type: change_attr_type
key: elapsed_ms
type: float
```

Supported types: `string`, `int`, `float`, `bool`.

<note>

`change_attr_type` is not supported for datapoints. Use the `script` operation with type parsing functions instead.

</note>

### Flatten map

By default, Uptrace does not index attributes that contain nested maps. The `flatten_map` operation extracts dot-separated paths from a map attribute so they can be queried:

```yaml
name: Flatten the object attribute
scope: [spans]
type: flatten_map
maps: ['object']
include_paths: ['object.nested.foo']
include_regexp: '^object.nested\.'
exclude_paths: ['object.nested.hello']
exclude_regexp: 'secret'
```

Without `include_paths` or `include_regexp`, the entire map is indexed up to 32 paths.

### IP geo attributes

Enriches IP address attributes with GeoIP data. For each specified key, Uptrace adds `{key}_country_code`, `{key}_country_name`, and `{key}_city`:

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

<note>

`client_address` and `client_socket_address` are automatically processed by Uptrace and should not be added manually.

</note>

<note>

`ip_geo_attrs` is not supported for datapoints.

</note>

### Text index

Builds a full-text index column from selected attribute values, enabling `*:value` [search syntax](/features/searching#searching-indexed-content):

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

The `include` field accepts glob patterns:

<table>
<thead>
  <tr>
    <th>
      Pattern
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        foo
      </code>
    </td>
    
    <td>
      Indexes the <code>
        foo
      </code>
      
       attribute directly
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        foo.**
      </code>
    </td>
    
    <td>
      Indexes all nested keys in the <code>
        foo
      </code>
      
       map
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        foo.*
      </code>
    </td>
    
    <td>
      Indexes one level of nested keys
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        foo?.bar
      </code>
    </td>
    
    <td>
      Matches <code>
        foo1
      </code>
      
      , <code>
        foo2
      </code>
      
      , etc.
    </td>
  </tr>
</tbody>
</table>

Search is case-insensitive and token-based (no substring matching). Maximum indexed text per record: 4096 bytes.

<note>

Text Index is billed separately based on indexed bytes. See the pricing page for details.

</note>

### Script

Write arbitrary expressions to modify telemetry. The `if` condition is required.

Set error status when exception attributes are present:

```yaml
name: Set error status when exception attributes are present
scope: [spans]
type: script
if: hasAttr("exception_type") && hasAttr("exception_message")
then:
  - setSpanStatusCode("error")
  - setSpanStatusMessage(attr("exception_message"))
else:
  - setSpanStatusCode("ok")
```

Parse a string attribute as float:

```yaml
name: Parse elapsed_ms
scope: [spans]
type: script
if: hasAttr("elapsed_ms")
then:
  - setAttr("elapsed_ms", parseFloat(attr("elapsed_ms")))
```

Reduce attribute cardinality:

```yaml
name: Normalize http_target
scope: [spans]
type: script
if: metricName() startsWith "http_server_" && hasAttr("http_target")
then:
  - setAttr("http_target", replaceGlob(attr("http_target"), "/user/*/list/*", "/user/{userId}/list/{listId}"))
```

Replace all numbers using a regular expression:

```yaml
name: Replace numbers in foo
scope: [spans]
type: script
if: hasAttr("foo")
then:
  - setAttr("foo", replaceAllRegexp(attr("foo"), "(\\d+)", "<number>"))
```

Convert a log into a span:

```yaml
name: Convert logs with elapsed_ms to spans
scope: [logs]
type: script
if: hasAttr("elapsed_ms")
then:
  - setSpanName("operation-name")
  - setLogName("")
  - setSpanDuration(parseFloat(attr("elapsed_ms")) * 1e6)
  - setSpanStatusCode("ok")
```

---

## Functions reference

In addition to built-in [Expr](https://expr-lang.org/docs/language-definition) functions, Uptrace provides the following. All functions work in both `if` conditions and `script` expressions.

### Span, log, and event functions

#### Getters

<table>
<thead>
  <tr>
    <th>
      Function
    </th>
    
    <th>
      Scope
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        spanName()
      </code>
    </td>
    
    <td>
      spans, logs, events
    </td>
    
    <td>
      Returns the span name or an empty string.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        eventName()
      </code>
    </td>
    
    <td>
      events
    </td>
    
    <td>
      Returns the event name or an empty string.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        logName()
      </code>
    </td>
    
    <td>
      logs
    </td>
    
    <td>
      Returns the log name (alias for <code>
        eventName
      </code>
      
      ).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        spanKind()
      </code>
    </td>
    
    <td>
      spans
    </td>
    
    <td>
      Returns the span kind (<code>
        internal
      </code>
      
      , <code>
        server
      </code>
      
      , <code>
        client
      </code>
      
      , <code>
        producer
      </code>
      
      , <code>
        consumer
      </code>
      
      ).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        spanDuration()
      </code>
    </td>
    
    <td>
      spans
    </td>
    
    <td>
      Returns the span duration as a <code>
        time.Duration
      </code>
      
       (nanosecond precision).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        spanStatusCode()
      </code>
    </td>
    
    <td>
      spans, logs, events
    </td>
    
    <td>
      Returns the span status code (<code>
        unset
      </code>
      
      , <code>
        ok
      </code>
      
      , <code>
        error
      </code>
      
      ).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        spanStatusMessage()
      </code>
    </td>
    
    <td>
      spans, logs, events
    </td>
    
    <td>
      Returns the span status message.
    </td>
  </tr>
</tbody>
</table>

#### Setters

<table>
<thead>
  <tr>
    <th>
      Function
    </th>
    
    <th>
      Scope
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        setSpanName(string)
      </code>
    </td>
    
    <td>
      spans
    </td>
    
    <td>
      Sets the span name.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        setEventName(string)
      </code>
    </td>
    
    <td>
      events
    </td>
    
    <td>
      Sets the event name.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        setLogName(string)
      </code>
    </td>
    
    <td>
      logs
    </td>
    
    <td>
      Sets the log name.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        setSpanKind(string)
      </code>
    </td>
    
    <td>
      spans
    </td>
    
    <td>
      Sets the span kind. Must be one of: <code>
        internal
      </code>
      
      , <code>
        server
      </code>
      
      , <code>
        client
      </code>
      
      , <code>
        producer
      </code>
      
      , <code>
        consumer
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        setSpanDuration(nanoseconds)
      </code>
    </td>
    
    <td>
      spans
    </td>
    
    <td>
      Sets the span duration in nanoseconds. Accepts <code>
        int
      </code>
      
      , <code>
        int64
      </code>
      
      , or <code>
        time.Duration
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        setSpanStatusCode(string)
      </code>
    </td>
    
    <td>
      spans
    </td>
    
    <td>
      Sets the span status code (<code>
        unset
      </code>
      
      , <code>
        ok
      </code>
      
      , <code>
        error
      </code>
      
      ).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        setSpanStatusMessage(string)
      </code>
    </td>
    
    <td>
      spans
    </td>
    
    <td>
      Sets the span status message.
    </td>
  </tr>
</tbody>
</table>

#### Attribute functions

<table>
<thead>
  <tr>
    <th>
      Function
    </th>
    
    <th>
      Scope
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        attr(key)
      </code>
    </td>
    
    <td>
      spans, logs, events
    </td>
    
    <td>
      Returns the attribute value by key.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        attrType(key)
      </code>
    </td>
    
    <td>
      spans, logs, events
    </td>
    
    <td>
      Returns the type: <code>
        nil
      </code>
      
      , <code>
        string
      </code>
      
      , <code>
        int
      </code>
      
      , <code>
        float
      </code>
      
      , <code>
        bool
      </code>
      
      , <code>
        array
      </code>
      
      , or <code>
        map
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        hasAttr(key)
      </code>
    </td>
    
    <td>
      spans, logs, events
    </td>
    
    <td>
      Returns <code>
        true
      </code>
      
       if the attribute exists.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        setAttr(key, value)
      </code>
    </td>
    
    <td>
      spans, logs, events
    </td>
    
    <td>
      Sets the attribute value.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        deleteAttr(key)
      </code>
    </td>
    
    <td>
      spans, logs, events
    </td>
    
    <td>
      Deletes the attribute.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        renameAttr(oldKey, newKey)
      </code>
    </td>
    
    <td>
      spans, logs, events
    </td>
    
    <td>
      Renames the attribute.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        renameAttr(oldKey, newKey, overwrite)
      </code>
    </td>
    
    <td>
      spans, logs, events
    </td>
    
    <td>
      Renames the attribute, optionally overwriting if the target exists.
    </td>
  </tr>
</tbody>
</table>

#### Type parsing functions

<table>
<thead>
  <tr>
    <th>
      Function
    </th>
    
    <th>
      Scope
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        parseInt(value)
      </code>
    </td>
    
    <td>
      spans, logs, events
    </td>
    
    <td>
      Parses the value as <code>
        int64
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        parseUint(value)
      </code>
    </td>
    
    <td>
      spans, logs, events
    </td>
    
    <td>
      Parses the value as <code>
        uint64
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        parseFloat(value)
      </code>
    </td>
    
    <td>
      spans, logs, events
    </td>
    
    <td>
      Parses the value as <code>
        float64
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        parseBool(value)
      </code>
    </td>
    
    <td>
      spans, logs, events
    </td>
    
    <td>
      Parses as <code>
        bool
      </code>
      
      . Accepts <code>
        "true"
      </code>
      
      , <code>
        "false"
      </code>
      
      , <code>
        "1"
      </code>
      
      , <code>
        "0"
      </code>
      
      .
    </td>
  </tr>
</tbody>
</table>

### Datapoint functions

#### Getters

<table>
<thead>
  <tr>
    <th>
      Function
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        metricName()
      </code>
    </td>
    
    <td>
      Returns the metric name.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        metricUnit()
      </code>
    </td>
    
    <td>
      Returns the metric unit.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        metricInstrument()
      </code>
    </td>
    
    <td>
      Returns the metric instrument type.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        libraryName()
      </code>
    </td>
    
    <td>
      Returns the instrumentation library name.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        libraryVersion()
      </code>
    </td>
    
    <td>
      Returns the instrumentation library version.
    </td>
  </tr>
</tbody>
</table>

#### Setters

<table>
<thead>
  <tr>
    <th>
      Function
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        setMetricName(string)
      </code>
    </td>
    
    <td>
      Sets the metric name.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        setMetricUnit(string)
      </code>
    </td>
    
    <td>
      Sets the metric unit.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        setMetricInstrument(string)
      </code>
    </td>
    
    <td>
      Sets the metric instrument type.
    </td>
  </tr>
</tbody>
</table>

#### Attribute functions

<table>
<thead>
  <tr>
    <th>
      Function
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        attr(key)
      </code>
    </td>
    
    <td>
      Returns the attribute value as a string.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        hasAttr(key)
      </code>
    </td>
    
    <td>
      Returns <code>
        true
      </code>
      
       if the attribute exists.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        setAttr(key, value)
      </code>
    </td>
    
    <td>
      Sets the attribute value.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        deleteAttr(key)
      </code>
    </td>
    
    <td>
      Deletes the attribute.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        renameAttr(oldKey, newKey)
      </code>
    </td>
    
    <td>
      Renames the attribute.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        renameAttr(oldKey, newKey, overwrite)
      </code>
    </td>
    
    <td>
      Renames the attribute, optionally overwriting.
    </td>
  </tr>
</tbody>
</table>

### Common functions

<table>
<thead>
  <tr>
    <th>
      Function
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        replaceGlob(src, pattern, repl)
      </code>
    </td>
    
    <td>
      Returns <code>
        repl
      </code>
      
       if <code>
        src
      </code>
      
       matches glob <code>
        pattern
      </code>
      
      , otherwise returns <code>
        src
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        replaceAllRegexp(src, pattern, repl)
      </code>
    </td>
    
    <td>
      Replaces all regexp matches in <code>
        src
      </code>
      
       with <code>
        repl
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        extractAllRegexp(src, pattern, repl)
      </code>
    </td>
    
    <td>
      Extracts and transforms all regexp matches from <code>
        src
      </code>
      
       using <code>
        repl
      </code>
      
       template.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        parseDuration(string)
      </code>
    </td>
    
    <td>
      Parses a duration string (e.g. <code>
        "1h30m"
      </code>
      
      , <code>
        "500ms"
      </code>
      
      ) as <code>
        time.Duration
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        parseByteSize(string)
      </code>
    </td>
    
    <td>
      Parses a byte size string (e.g. <code>
        "1GB"
      </code>
      
      , <code>
        "512MB"
      </code>
      
      ) as <code>
        int64
      </code>
      
       bytes.
    </td>
  </tr>
</tbody>
</table>

## Related

- [Expr language definition](https://expr-lang.org/docs/language-definition)
- [Introduction](/features/transformations) — overview, scope rules, and common recipes
