Skip to content

Metric attribute hashing folds True, 1 and 1.0 into a single stream - #5573

Open
dwin-gharibi wants to merge 2 commits into
open-telemetry:mainfrom
dwin-gharibi:fix/metric-attribute-type-collision
Open

Metric attribute hashing folds True, 1 and 1.0 into a single stream#5573
dwin-gharibi wants to merge 2 commits into
open-telemetry:mainfrom
dwin-gharibi:fix/metric-attribute-type-collision

Conversation

@dwin-gharibi

Copy link
Copy Markdown

Closes #5572.

Description

_hash_attributes returns scalar attribute values unchanged as part of the aggregation key. Python compares True == 1 == 1.0 and hashes all three identically, so attribute sets that are distinct in the OpenTelemetry data model - OTLP encodes them as bool_value, int_value and double_value - collapse into a single time series. The surviving series is labelled with whichever type happened to arrive first.

The same flaw makes a sequence of pairs hash identically to the mapping it resembles.

Root cause

opentelemetry-sdk/src/opentelemetry/sdk/metrics/_internal/_view_instrument_match.py:36. The scalar branch returns the value itself, so key identity inherits Python's ==/hash semantics rather than the OTel data model's. The Sequence and Mapping branches return bare tuples, which is why a list of pairs and a mapping collide.

Approach

Tag every branch with its kind. Scalars become (type(value).__name__, value); sequences and mappings are prefixed with "sequence" and "mapping". The key stays a plain hashable tuple, so nothing downstream changes.

Sorting of mapping keys is untouched, so attribute ordering remains irrelevant - the property that actually matters for aggregation, and one the new tests pin down explicitly.

Files changed

  • opentelemetry-sdk/src/opentelemetry/sdk/metrics/_internal/_view_instrument_match.py
  • opentelemetry-sdk/tests/metrics/test_attribute_hashing.py
  • .changelog/5565.fixed

Testing

Unit coverage asserts True/1/1.0 yield three distinct keys, False and 0 differ, None and "None" differ, a sequence of pairs differs from the equivalent mapping, nested values are distinguished, and the key remains hashable. Two tests guard against over-correcting: key order must still be irrelevant, and equal attributes must still share a key.

Integration coverage drives a counter and a histogram end to end and checks the data point count and the attribute types on the exported points, plus that identical attributes still aggregate into one stream.

Six of the eleven fail before the change.

Result: 866 passed in opentelemetry-sdk (855 baseline plus 11 new).

Risk / compatibility

_HashedAttributes is private and the key never leaves the SDK, so the shape change is not observable to users. Series that were previously merged will now appear separately, which is the correction; for a backend this looks like a new series appearing at the point of upgrade.

Python compares True == 1 == 1.0 and hashes them identically, but OTLP encodes
them as bool_value, int_value and double_value: three different values. Assert
that _hash_attributes keeps them apart, that a sequence of pairs does not hash
like the equivalent mapping, and that key ordering remains irrelevant.

Integration coverage asserts a counter and a histogram produce one data point
per distinct attribute type, and that identical attributes still aggregate
into a single stream.

These tests fail against the current implementation.
_hash_attributes returned scalar attribute values unchanged as part of the
aggregation key, so key identity inherited Python's equality rather than the
OTel data model's. True == 1 == 1.0 and all three hash alike, yet OTLP encodes
them as bool_value, int_value and double_value. Distinct attribute sets were
therefore folded into one time series, and that series was exported labelled
with whichever type arrived first. A sequence of pairs collided with the
equivalent mapping for the same reason.

Tag every branch with its kind: scalars carry their concrete type name,
sequences and mappings carry a container tag. Mapping keys are still sorted,
so attribute ordering remains irrelevant.
Copilot AI lite review requested due to automatic review settings August 23, 2026 17:00
@dwin-gharibi
dwin-gharibi requested a review from a team as a code owner August 23, 2026 17:00

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@opentelemetry-pr-dashboard

opentelemetry-pr-dashboard Bot commented Aug 23, 2026

Copy link
Copy Markdown

Pull request dashboard status

Waiting on maintainers · refreshed 2026-08-24 13:11 UTC

Merge when ready.

Status above doesn't look right?
  • Just replied or pushed? Anything around or after the refresh time above may not be picked up yet — give it a few minutes.
  • Anything look wrong? Report it with what you expected; it helps us improve the dashboard.

@github-project-automation github-project-automation Bot moved this to Approved PRs in Python PR digest Aug 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Approved PRs

Development

Successfully merging this pull request may close these issues.

Metric attribute hashing folds True, 1 and 1.0 into a single stream

3 participants