Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix SimpleExemplarReservoir for cumulative #5230

Merged
merged 13 commits into from
Jan 18, 2024
4 changes: 4 additions & 0 deletions src/OpenTelemetry/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
state compared to the current activity. For details see:
[#5136](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5136)

* Fixed an issue where `SimpleExemplarReservoir` was not resetting internal
state for cumulative temporality.
[#5230](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5230)

## 1.7.0

Released 2023-Dec-08
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,13 @@ public override Exemplar[] Collect(ReadOnlyTagCollection actualTags, bool reset)
if (reset)
Copy link
Member

Choose a reason for hiding this comment

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

unrelated but kind of related nit: maybe this variable should be named isDelta for readability?

Copy link
Member Author

Choose a reason for hiding this comment

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

yes... The Reservoir itself is not necessarily aware of temporality concept. All it needs to know is if it should reset its internal state or not.. The caller knows temporality and passes reset to this...

Copy link
Member

Choose a reason for hiding this comment

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

Not a blocker for this PR, but just looking at this API shape, is the correct thing to do to expose bool reset?

SDKs are free to decide whether "collect" should also reset internal storage for delta temporal aggregation collection, or use a more optimal implementation.

Curious what other languages have done to solve this.

Copy link
Member Author

Choose a reason for hiding this comment

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

The current APIs need to be revised before exposing them to public (its marked internal), and there are many TODOs to be solved.

{
this.runningExemplars[i].Timestamp = default;
this.measurementsSeen = 0;
}
}
}

// Reset internal state irrespective of temporality.
// This ensures incoming measurements have fair chance
// of making it to the reservoir.
this.measurementsSeen = 0;
cijothomas marked this conversation as resolved.
Show resolved Hide resolved

return this.tempExemplars;
}
Expand Down
14 changes: 11 additions & 3 deletions test/OpenTelemetry.Tests/Metrics/MetricExemplarTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ public MetricExemplarTests(ITestOutputHelper output)
this.output = output;
}

[Fact]
public void TestExemplarsCounter()
[Theory]
[InlineData(MetricReaderTemporalityPreference.Cumulative)]
[InlineData(MetricReaderTemporalityPreference.Delta)]
public void TestExemplarsCounter(MetricReaderTemporalityPreference temporality)
{
DateTime testStartTime = DateTime.UtcNow;
var exportedItems = new List<Metric>();
Expand All @@ -33,7 +35,7 @@ public void TestExemplarsCounter()
.SetExemplarFilter(new AlwaysOnExemplarFilter())
.AddInMemoryExporter(exportedItems, metricReaderOptions =>
{
metricReaderOptions.TemporalityPreference = MetricReaderTemporalityPreference.Delta;
metricReaderOptions.TemporalityPreference = temporality;
}));

var measurementValues = GenerateRandomValues(10);
Expand All @@ -48,6 +50,12 @@ public void TestExemplarsCounter()
Assert.True(metricPoint.Value.StartTime >= testStartTime);
Assert.True(metricPoint.Value.EndTime != default);
var exemplars = GetExemplars(metricPoint.Value);

// TODO: Modify the test to better test cumulative.
// In cumulative where SimpleExemplarReservoir's size is
// more than the count of new measurements, it is possible
// that the exemplar value is for a measurement that was recorded in the prior
// cycle. The current ValidateExemplars() does not handle this case.
ValidateExemplars(exemplars, metricPoint.Value.StartTime, metricPoint.Value.EndTime, measurementValues, false);

exportedItems.Clear();
Expand Down
Loading