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
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_globadded in #4966)API version: main
What happened?
_scope_name_matches_globinopentelemetry-sdk/src/opentelemetry/sdk/util/instrumentation.pyusesfnmatch.fnmatch, which normalizes both the string and the pattern throughos.path.normcasebefore comparing them. On Windowsnormcaselower-cases its argument, so the match becomes case-insensitive there while staying case-sensitive on Linux.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.nameinopentelemetry-configuration/src/opentelemetry/configuration/schema.json(the meter and logger matchers carry the same wording):The rest of the SDK already avoids
fnmatchfor exactly this reason.opentelemetry-sdk/src/opentelemetry/sdk/metrics/_internal/view.pyandopentelemetry-sdk/src/opentelemetry/sdk/trace/_sampling_experimental/_rule_based.pyboth usefnmatchcase, andview.pycarries 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:
Expected Result
Trueon every platform.NOISY.librarydoes not match the patternnoisy.*under case-sensitive matching, so the disabling rule must not apply and the scope stays enabled.Actual Result
Trueon Linux,Falseon Windows. On Windowsfnmatchlower-cases both operands,NOISY.librarymatchesnoisy.*, and the meter is disabled.Additional context
Reported by @lzchen while reviewing #5418: #5418 (comment)
The fix is to switch
_scope_name_matches_globtofnmatchcase, matching whatview.pyand_rule_based.pyalready do.Would you like to implement a fix?
Yes