Skip to content

Commit 0e5e318

Browse files
committed
receiver/prometheusremotewritereceiver: add MetricIdentity with xxhash-based Hash method.
Creates MetricIdentity struct for uniquely identifying metrics and adds a deterministic Hash method using xxhash with proper field separation. partly fixes #37277.
1 parent 58099ca commit 0e5e318

File tree

2 files changed

+76
-7
lines changed

2 files changed

+76
-7
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
2+
change_type: enhancement
3+
4+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
5+
component: prometheusremotewritereciever
6+
7+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
8+
note: "Introduced `MetricIdentity` struct with xxhash-based hashing for uniquely identifying metrics."
9+
10+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
11+
issues: [37277]
12+
13+
# (Optional) One or more lines of additional information to render under the primary note.
14+
# These lines will be padded with 2 spaces and then inserted directly into the document.
15+
# Use pipe (|) for multiline entries.
16+
subtext: |
17+
The hash method ensures consistent, deterministic identification of metrics by using
18+
proper field separation and xxhash, which is already utilized in other parts of the code.
19+
20+
# If your change doesn't affect end users or the exported elements of any package,
21+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
22+
# Optional: The change log or logs in which this entry should be included.
23+
# e.g. '[user]' or '[user, api]'
24+
# Include 'user' if the change is relevant to end users.
25+
# Include 'api' if there is a change to a library API.
26+
# Default: '[user]'
27+
change_logs: [user]

receiver/prometheusremotewritereceiver/receiver.go

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,48 @@ type prometheusRemoteWriteReceiver struct {
4949
wg sync.WaitGroup
5050
}
5151

52+
// MetricIdentity contains all the components that uniquely identify a metric
53+
// according to the OpenTelemetry Protocol data model.
54+
// The definition of the metric uniqueness is based on the following document. Ref: https://opentelemetry.io/docs/specs/otel/metrics/data-model/#opentelemetry-protocol-data-model
55+
type MetricIdentity struct {
56+
ResourceID string
57+
ScopeName string
58+
ScopeVersion string
59+
MetricName string
60+
Unit string
61+
Type writev2.Metadata_MetricType
62+
}
63+
64+
// createMetricIdentity creates a MetricIdentity struct from the required components
65+
func createMetricIdentity(resourceID, scopeName, scopeVersion, metricName, unit string, metricType writev2.Metadata_MetricType) MetricIdentity {
66+
return MetricIdentity{
67+
ResourceID: resourceID,
68+
ScopeName: scopeName,
69+
ScopeVersion: scopeVersion,
70+
MetricName: metricName,
71+
Unit: unit,
72+
Type: metricType,
73+
}
74+
}
75+
76+
// Hash generates a unique hash for the metric identity
77+
func (mi MetricIdentity) Hash() uint64 {
78+
const separator = "\xff"
79+
80+
combined := strings.Join([]string{
81+
mi.ResourceID,
82+
mi.ScopeName,
83+
mi.ScopeVersion,
84+
mi.MetricName,
85+
mi.Unit,
86+
fmt.Sprintf("%d", mi.Type),
87+
}, separator)
88+
89+
hash := xxhash.Sum64String(combined)
90+
91+
return hash
92+
}
93+
5294
func (prw *prometheusRemoteWriteReceiver) Start(ctx context.Context, host component.Host) error {
5395
mux := http.NewServeMux()
5496
mux.HandleFunc("/api/v1/write", prw.handlePRW)
@@ -179,8 +221,7 @@ func (prw *prometheusRemoteWriteReceiver) translateV2(_ context.Context, req *wr
179221
// between requests based on the metric "target_info".
180222
intraRequestCache = make(map[uint64]pmetric.ResourceMetrics)
181223
// The key is composed by: resource_hash:scope_name:scope_version:metric_name:unit:type
182-
// TODO: use the appropriate hash function.
183-
metricCache = make(map[string]pmetric.Metric)
224+
metricCache = make(map[uint64]pmetric.Metric)
184225
)
185226

186227
for _, ts := range req.Timeseries {
@@ -221,16 +262,17 @@ func (prw *prometheusRemoteWriteReceiver) translateV2(_ context.Context, req *wr
221262
description := req.Symbols[ts.Metadata.HelpRef]
222263

223264
resourceID := identity.OfResource(rm.Resource())
224-
// Temporary approach to generate the metric key.
225-
// TODO: Replace this with a proper hashing function.
226-
// The definition of the metric uniqueness is based on the following document. Ref: https://opentelemetry.io/docs/specs/otel/metrics/data-model/#opentelemetry-protocol-data-model
227-
metricKey := fmt.Sprintf("%s:%s:%s:%s:%s:%d",
265+
266+
metricIdentity := createMetricIdentity(
228267
resourceID.String(), // Resource identity
229268
scopeName, // Scope name
230269
scopeVersion, // Scope version
231270
metricName, // Metric name
232271
unit, // Unit
233-
ts.Metadata.Type) // Metric type
272+
ts.Metadata.Type, // Metric type
273+
)
274+
275+
metricKey := metricIdentity.Hash()
234276

235277
var scope pmetric.ScopeMetrics
236278
var foundScope bool

0 commit comments

Comments
 (0)