Skip to content

Instrumentation scope glob matching is case-insensitive on Windows #5583

Description

@ocelotl

Describe your environment

OS: Windows (any version); also macOS with a case-insensitive filesystem
Python version: any supported version
SDK version: main (_scope_name_matches_glob added in #4966)
API version: main

What happened?

_scope_name_matches_glob in opentelemetry-sdk/src/opentelemetry/sdk/util/instrumentation.py uses fnmatch.fnmatch, which normalizes both the string and the pattern through os.path.normcase before comparing them. On Windows normcase lower-cases its argument, so the match becomes case-insensitive there while staying case-sensitive on Linux.

def _scope_name_matches_glob(
    glob_pattern: str,
) -> _InstrumentationScopePredicateT:
    def inner(scope: InstrumentationScope) -> bool:
        return fnmatch.fnmatch(scope.name, glob_pattern)

    return inner

This predicate is what backs instrumentation-scope name matching for the tracer, meter and logger configurators, so the platform leaks into observable SDK behavior: the same configuration disables a different set of scopes depending on the host operating system.

The declarative configuration schema states the opposite requirement. From ExperimentalTracerMatcherAndConfig.name in opentelemetry-configuration/src/opentelemetry/configuration/schema.json (the meter and logger matchers carry the same wording):

Configure tracer names to match. Matching is case-sensitive, evaluated as follows:

  • If the tracer name exactly matches.
  • If the tracer name matches the wildcard pattern, where '?' matches any single character and '*' matches any number of characters including none.

The rest of the SDK already avoids fnmatch for exactly this reason. opentelemetry-sdk/src/opentelemetry/sdk/metrics/_internal/view.py and opentelemetry-sdk/src/opentelemetry/sdk/trace/_sampling_experimental/_rule_based.py both use fnmatchcase, and view.py carries the comment "fnmatchcase is used instead of fnmatch so it does not rely on the host platform's filename case sensitivity (normcase)".

Steps to Reproduce

Run this on Windows:

from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.metrics._internal.configurator import (
    _MeterConfig,
    _RuleBasedMeterConfigurator,
)
from opentelemetry.sdk.util.instrumentation import (
    InstrumentationScope,
    _scope_name_matches_glob,
)

configurator = _RuleBasedMeterConfigurator(
    rules=[(_scope_name_matches_glob("noisy.*"), _MeterConfig(is_enabled=False))],
    default_config=_MeterConfig.default(),
)

# A scope whose name differs from the pattern only by case.
print(configurator(InstrumentationScope("NOISY.library", "1.0")).is_enabled)

Expected Result

True on every platform. NOISY.library does not match the pattern noisy.* under case-sensitive matching, so the disabling rule must not apply and the scope stays enabled.

Actual Result

True on Linux, False on Windows. On Windows fnmatch lower-cases both operands, NOISY.library matches noisy.*, and the meter is disabled.

Additional context

Reported by @lzchen while reviewing #5418: #5418 (comment)

The fix is to switch _scope_name_matches_glob to fnmatchcase, matching what view.py and _rule_based.py already do.

Would you like to implement a fix?

Yes

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions