Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .changelog/5430.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
`opentelemetry-sdk`: fix `View` instrument-name matching so a view configured with an instrument's real (mixed-case) name is applied; matching is now case-insensitive and platform-independent instead of relying on `fnmatch`'s OS-dependent case handling
Comment thread
aabmass marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@


from collections.abc import Callable
from fnmatch import fnmatch
from fnmatch import fnmatchcase
from logging import getLogger

from opentelemetry.metrics import Instrument
Expand Down Expand Up @@ -146,11 +146,17 @@ def _match(self, instrument: _Instrument) -> bool:
return False

if self._instrument_name is not None:
if not fnmatch(instrument.name, self._instrument_name):
# Instrument names are treated case-insensitively and are stored
# lower-cased by the SDK, so the pattern is lower-cased to match.
# fnmatchcase is used instead of fnmatch so it does not rely
# on the host platform's filename case sensitivity (normcase).
if not fnmatchcase(instrument.name, self._instrument_name.lower()):
return False
Comment thread
aabmass marked this conversation as resolved.

if self._instrument_unit is not None:
if not fnmatch(instrument.unit, self._instrument_unit):
# Units are case-sensitive; fnmatchcase keeps matching consistent
# across platforms.
if not fnmatchcase(instrument.unit, self._instrument_unit):
return False
Comment thread
aabmass marked this conversation as resolved.

if self._meter_name is not None:
Expand Down
20 changes: 20 additions & 0 deletions opentelemetry-sdk/tests/metrics/test_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,32 @@ def test_instrument_name(self):

self.assertTrue(View(instrument_name="instrument_name")._match(mock_instrument))

def test_instrument_name_case_insensitive(self):
# The SDK stores instrument names lower-cased, so a view pattern that
# reuses the instrument's original name must still match regardless of
# case (and regardless of the host platform).
mock_instrument = Mock()
mock_instrument.configure_mock(**{"name": "instrument_name"})

self.assertTrue(View(instrument_name="Instrument_Name")._match(mock_instrument))
self.assertTrue(View(instrument_name="INSTRUMENT_*")._match(mock_instrument))
self.assertFalse(View(instrument_name="other_name")._match(mock_instrument))

def test_instrument_unit(self):
mock_instrument = Mock()
mock_instrument.configure_mock(**{"unit": "instrument_unit"})

self.assertTrue(View(instrument_unit="instrument_unit")._match(mock_instrument))

def test_instrument_unit_case_sensitive(self):
# Units are case-sensitive and matching must not depend on the host
# platform's filename case sensitivity.
mock_instrument = Mock()
mock_instrument.configure_mock(**{"unit": "By"})

self.assertTrue(View(instrument_unit="By")._match(mock_instrument))
self.assertFalse(View(instrument_unit="by")._match(mock_instrument))

def test_meter_name(self):
self.assertTrue(View(meter_name="meter_name")._match(Mock(**{"instrumentation_scope.name": "meter_name"})))

Expand Down