Skip to content

Commit d7544ff

Browse files
metricstarttimeprocessor: add reset detection for histograms (open-telemetry#38583)
<!--Ex. Fixing a bug - Describe the bug and how this fixes the issue. Ex. Adding a feature - Explain what this achieves.--> #### Description When an individual bucket counter decreases but the total count and sum goes up, the adjuster now recognizes it as a reset. <!-- Issue number (e.g. open-telemetry#1234) or full URL to issue, if applicable. --> #### Link to tracking issue Fixes open-telemetry#38582 <!--Describe what testing was performed and which tests were added.--> #### Testing Added unit tests. <!--Describe the documentation added.--> #### Documentation N/A <!--Please delete paragraphs that you did not use before submitting.--> --------- Signed-off-by: Ridwan Sharif <[email protected]> Co-authored-by: Antoine Toulme <[email protected]>
1 parent f887aa4 commit d7544ff

File tree

4 files changed

+633
-9
lines changed

4 files changed

+633
-9
lines changed

.chloggen/detect-resets.yaml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: bug_fix
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
7+
component: metricstarttimeprocessor
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Add reset detection for histograms
11+
12+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
13+
issues: [38582]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext:
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: []

processor/metricstarttimeprocessor/internal/datapointstorage/timeseries_map.go

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,96 @@ func (tsm *TimeseriesMap) GC() {
101101
tsm.Mark = false
102102
}
103103

104+
// IsResetHistogram compares the given histogram datapoint h, to tsi.Histogram
105+
// and determines whether the metric has been reset based on the values. It is
106+
// a reset if any of the bucket boundaries have changed, if any of the bucket
107+
// counts have decreased or if the total sum or count have decreased.
108+
func (tsi *TimeseriesInfo) IsResetHistogram(h pmetric.HistogramDataPoint) bool {
109+
if h.Count() < tsi.Histogram.Count() {
110+
return true
111+
}
112+
if h.Sum() < tsi.Histogram.Sum() {
113+
return true
114+
}
115+
116+
// Guard against bucket boundaries changes.
117+
refBounds := tsi.Histogram.ExplicitBounds().AsRaw()
118+
hBounds := h.ExplicitBounds().AsRaw()
119+
if len(refBounds) != len(hBounds) {
120+
return true
121+
}
122+
for i := range len(refBounds) {
123+
if hBounds[i] != refBounds[i] {
124+
return true
125+
}
126+
}
127+
128+
// We need to check individual buckets to make sure the counts are all increasing.
129+
if tsi.Histogram.BucketCounts().Len() != h.BucketCounts().Len() {
130+
return true
131+
}
132+
for i := range tsi.Histogram.BucketCounts().Len() {
133+
if h.BucketCounts().At(i) < tsi.Histogram.BucketCounts().At(i) {
134+
return true
135+
}
136+
}
137+
return false
138+
}
139+
140+
// IsResetExponentialHistogram compares the given exponential histogram
141+
// datapoint eh, to tsi.ExponentialHistogram and determines whether the metric
142+
// has been reset based on the values. It is a reset if any of the bucket
143+
// boundaries have changed, if any of the bucket counts have decreased or if the
144+
// total sum or count have decreased.
145+
func (tsi *TimeseriesInfo) IsResetExponentialHistogram(eh pmetric.ExponentialHistogramDataPoint) bool {
146+
// Same as the histogram implementation
147+
if eh.Count() < tsi.ExponentialHistogram.Count() {
148+
return true
149+
}
150+
if eh.Sum() < tsi.ExponentialHistogram.Sum() {
151+
return true
152+
}
153+
154+
// Guard against bucket boundaries changes.
155+
if tsi.ExponentialHistogram.Scale() != eh.Scale() {
156+
return true
157+
}
158+
159+
// We need to check individual buckets to make sure the counts are all increasing.
160+
if tsi.ExponentialHistogram.Positive().BucketCounts().Len() != eh.Positive().BucketCounts().Len() {
161+
return true
162+
}
163+
for i := range tsi.ExponentialHistogram.Positive().BucketCounts().Len() {
164+
if eh.Positive().BucketCounts().At(i) < tsi.ExponentialHistogram.Positive().BucketCounts().At(i) {
165+
return true
166+
}
167+
}
168+
if tsi.ExponentialHistogram.Negative().BucketCounts().Len() != eh.Negative().BucketCounts().Len() {
169+
return true
170+
}
171+
for i := range tsi.ExponentialHistogram.Negative().BucketCounts().Len() {
172+
if eh.Negative().BucketCounts().At(i) < tsi.ExponentialHistogram.Negative().BucketCounts().At(i) {
173+
return true
174+
}
175+
}
176+
177+
return false
178+
}
179+
180+
// IsResetSummary compares the given summary datapoint s to tsi.Summary and
181+
// determines whether the metric has been reset based on the values. It is a
182+
// reset if the count or sum has decreased.
183+
func (tsi *TimeseriesInfo) IsResetSummary(s pmetric.SummaryDataPoint) bool {
184+
return s.Count() < tsi.Summary.Count() || s.Sum() < tsi.Summary.Sum()
185+
}
186+
187+
// IsResetSum compares the given number datapoint s to tsi.Number and determines
188+
// whether the metric has been reset based on the values. It is a reset if the
189+
// value has decreased.
190+
func (tsi *TimeseriesInfo) IsResetSum(s pmetric.NumberDataPoint) bool {
191+
return s.DoubleValue() < tsi.Number.DoubleValue()
192+
}
193+
104194
func newTimeseriesMap() *TimeseriesMap {
105195
return &TimeseriesMap{Mark: true, TsiMap: map[TimeseriesKey]*TimeseriesInfo{}}
106196
}

0 commit comments

Comments
 (0)