Skip to main content

Lookup Processor

Status Maintainers: @jsvd, @dehaansa, @VihasMakwana Source: opentelemetry-collector-contrib

Supported Telemetry

Logs

Overview

Configuration

processors:
  lookup:
    source:
      type: yaml
      path: /etc/otel/mappings.yaml
    lookups:
      - key: log.attributes["user.id"]
        attributes:
          - destination: user.name
            default: "Unknown User"

Full Configuration

FieldDescriptionDefault
source.typeThe source type identifier (noop, yaml, dns)noop
lookupsList of lookup rules (required, at least one)-

Lookup Configuration

Each entry in lookups defines a lookup rule:
FieldDescriptionDefault
keyOTTL value expression for extracting the lookup key (required)-
contextDefault context for destination attributes: record, resourcerecord
attributesList of attribute mappings for writing results (required, at least one)-
The key field supports any OTTL value expression, including paths across contexts and converters:
  • log.attributes["user.id"] - record attribute
  • resource.attributes["service.name"] - resource attribute
  • Trim(log.attributes["raw.id"]) - apply a converter

Attribute Mapping

Each entry in attributes defines where to write a lookup result:
FieldDescriptionDefault
sourceField name in the lookup result (for map results, leave empty for scalar)-
destinationAttribute key to write the result to (required)-
defaultValue to use when the lookup returns no result-
contextOverride the key’s context for this attributeinherited from key’s context (record if unset)

Examples

Scalar Lookup (1:1)

When the source returns a single value per key, leave the source field empty:
processors:
  lookup:
    source:
      type: yaml
      path: /etc/otel/mappings.yaml
    lookups:
      - key: log.attributes["user.id"]
        attributes:
          - destination: user.name
            default: "Unknown User"

Map Lookup (1:N)

When the source returns a map of fields per key, use the source field to extract individual values:
processors:
  lookup:
    source:
      type: yaml
      path: /etc/otel/user-details.yaml
    lookups:
      - key: log.attributes["user.id"]
        attributes:
          - source: name
            destination: user.name
            default: "Unknown"
          - source: email
            destination: user.email
          - source: role
            destination: user.role
            context: resource

OTTL Converter on Key

The key field supports OTTL converters for transforming the lookup key before querying the source:
processors:
  lookup:
    source:
      type: yaml
      path: /etc/otel/mappings.yaml
    lookups:
      - key: Trim(log.attributes["raw.id"])
        attributes:
          - destination: display.name

Context

  • record: Read from and write to record-level attributes (log records, spans, metric data points) (default)
  • resource: Read from and write to resource attributes
The context field on a key sets the default for all its destination attributes. Each attribute mapping can override this with its own context field. Lookups are evaluated per record. When writing to resource attributes, later records in the same resource may overwrite values written by earlier records.

Built-in Sources

  • noop - No-operation source for testing
  • yaml - Key-value mappings from YAML files
  • dns - DNS lookups with caching

Caching

Sources that support external lookups (like DNS) can use the built-in LRU caching system to reduce latency and external queries. The cache uses a doubly-linked list with a hash map for O(1) lookups, insertions, and evictions.

Cache Configuration

FieldDescriptionDefault
cache.enabledEnable cachingvaries by source
cache.sizeMaximum number of entries (LRU eviction, must be > 0 when enabled)varies by source
cache.ttlTime-to-live for successful lookups0 (no expiration)
cache.negative_ttlTTL for “not found” results0 (disabled)

Cache Performance

Run with go test -bench=BenchmarkCache -run=^$ ./lookupsource/ Single-threaded (Apple M4 Pro):
Operationns/opB/opallocs/op
Get (hit)3600
Get (negative hit)3600
Get (miss)500
Set (new entry)2811513
Set (update existing)4200
Set (with eviction)1521524
Concurrent (12 goroutines):
Operationns/opB/opallocs/op
Get (parallel)131131
Mixed read/write (parallel)145251

Using Cache in Custom Sources

Custom sources can use the cache by wrapping their lookup function:
func createSource(ctx context.Context, settings lookupsource.CreateSettings, cfg lookupsource.SourceConfig) (lookupsource.Source, error) {
    myCfg := cfg.(*Config)

    // Create base lookup function
    lookupFn := func(ctx context.Context, key string) (any, bool, error) {
        // Perform actual lookup
        return result, true, nil
    }

    // Wrap with cache if enabled
    if myCfg.Cache.Enabled {
        cache := lookupsource.NewCache(myCfg.Cache)
        lookupFn = lookupsource.WrapWithCache(cache, lookupFn)
    }

    return lookupsource.NewSource(lookupFn, ...), nil
}

Custom Sources

Custom lookup sources can be added using WithSources:
import (
    "github.com/open-telemetry/opentelemetry-collector-contrib/processor/lookupprocessor"
    "github.com/example/httplookup"
)

factories.Processors[lookupprocessor.Type] = lookupprocessor.NewFactoryWithOptions(
    lookupprocessor.WithSources(httplookup.NewFactory()),
)

Source contract

  • Concurrency: Lookup is called concurrently from multiple goroutines. Implementations must be safe for concurrent use.
  • Keys are strings: The OTTL expression result is converted to a string before calling Lookup.
  • Return values: For scalar (1:1) lookups, return any single value. For map (1:N) lookups, return map[string]any. Values are written to attributes via pcommon.Value.FromRaw. Unsupported types are stringified via fmt.Sprintf.
  • Errors are non-fatal: When Lookup returns an error the processor logs it at Debug level and skips the lookup. It does not fail the batch.
  • Lifecycle: Start is called once before any Lookup; Shutdown is called once after all processing stops. Both are optional (pass nil to NewSource).
  • Config tags: Source config structs must use mapstructure struct tags. The processor decodes source configuration from a raw map using mapstructure.

Implementing a Source

package mysource

import (
    "context"
    "errors"
    "time"

    "github.com/open-telemetry/opentelemetry-collector-contrib/processor/lookupprocessor/lookupsource"
)

type Config struct {
    Endpoint string        `mapstructure:"endpoint"`
    Timeout  time.Duration `mapstructure:"timeout"`
}

func (c *Config) Validate() error {
    if c.Endpoint == "" {
        return errors.New("endpoint is required")
    }
    return nil
}

func NewFactory() lookupsource.SourceFactory {
    return lookupsource.NewSourceFactory(
        "mysource",
        func() lookupsource.SourceConfig {
            return &Config{Timeout: 5 * time.Second}
        },
        createSource,
    )
}

func createSource(
    ctx context.Context,
    settings lookupsource.CreateSettings,
    cfg lookupsource.SourceConfig,
) (lookupsource.Source, error) {
    c := cfg.(*Config)

    return lookupsource.NewSource(
        func(ctx context.Context, key string) (any, bool, error) {
            // Perform lookup - return (value, found, error)
            return "result", true, nil
        },
        func() string { return "mysource" },
        nil, // start function (optional)
        nil, // shutdown function (optional)
    ), nil
}

Benchmarks

Run benchmarks with:
make benchmark

Processor Performance

Measures the full processing pipeline including OTTL key evaluation, source lookup, value conversion, and attribute writes. Uses noop source to isolate processor overhead from source implementation (Apple M4 Pro):
Scenarions/opB/opallocs/op
1 log, 1 lookup39672822
10 logs, 1 lookup1,8293,53894
100 logs, 1 lookup17,57731,732814
100 logs, 3 lookups34,99363,7521,614
1000 logs, 1 lookup183,558312,8448,014

YAML Source Performance

Measures only the source lookup operation (map access), isolated from processor overhead:
Map Sizens/opallocs/op
10 entries1,4620
100 entries1,4150
1,000 entries1,3880
10,000 entries1,3680

Last generated: 2026-04-13