Skip to content

IncludeExclude filters treat wildcard patterns as literal attribute keys #9300

Description

@pellared

Component

Config

Describe the issue you are facing

The declarative configuration contract defines IncludeExclude.included and IncludeExclude.excluded entries as case-sensitive wildcard patterns: * matches zero or more characters and ? matches exactly one character. Exclusions are applied after inclusions.

The Go implementation in newIncludeExcludeFilter instead converts entries to map[attribute.Key]struct{} and performs exact-key lookups. As a result, wildcard patterns are treated as literal attribute keys.

For example, this configuration does not exclude secret.token or process.command_args:

with_resource_constant_labels:
  excluded:
    - "secret.*"
    - "process.*"

The helper also returns an error when an identical literal appears in both lists. The configuration contract says exclusions take precedence, so overlapping include/exclude entries should be valid.

The affected helper is copied across:

  • otelconf/metric.go
  • otelconf/v0.2.0/metric.go
  • otelconf/v0.3.0/metric.go
  • otelconf/x/metric.go

It is used for view attribute filters and, depending on the schema package, resource detector and Prometheus resource-label filters.

Specification references:

This is a configuration correctness issue, not an endpoint-wide redaction mechanism. In particular, Prometheus target_info is controlled separately from WithResourceAsConstantLabels; tests for resource constant labels should assert the labels on a named application metric rather than search the entire scrape body.

Expected behavior

  • * and ? use the specified case-sensitive wildcard semantics.
  • If included is empty, attributes are included unless an exclusion matches.
  • If included is non-empty, an attribute must match at least one inclusion.
  • Exclusions are evaluated after inclusions and always win.
  • Overlapping include/exclude entries are accepted.

Steps to Reproduce

Add focused tests next to newIncludeExcludeFilter:

func TestIncludeExcludeWildcard(t *testing.T) {
    filter, err := newIncludeExcludeFilter(&IncludeExclude{
        Excluded: []string{"secret.*", "process.?ommand_args"},
    })
    require.NoError(t, err)

    assert.False(t, filter(attribute.String("secret.token", "value")))
    assert.False(t, filter(attribute.String("process.command_args", "value")))
    assert.True(t, filter(attribute.String("service.name", "svc")))
}

func TestIncludeExcludeOverlap(t *testing.T) {
    filter, err := newIncludeExcludeFilter(&IncludeExclude{
        Included: []string{"service.name"},
        Excluded: []string{"service.name"},
    })
    require.NoError(t, err)
    assert.False(t, filter(attribute.String("service.name", "svc")))
}

On current code, the wildcard assertions fail because the keys are compared literally, and the overlap test fails because constructing the filter returns an error.

Operating System

Linux

Device Architecture

x86_64

Go Version

go1.26.4

Component Version

go.opentelemetry.io/contrib/otelconf v0.24.0 and current main (234cdab235e4)

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: file-configRelated to file-based configurationbugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions