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

[sdk-metrics] Support exemplars when using exponential histograms #5396

Merged
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
5 changes: 5 additions & 0 deletions src/OpenTelemetry/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@
metrics exporters which support exemplars.
([#5386](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5386))

* **Experimental (pre-release builds only):** Added support for exemplars when
using Base2 Exponential Bucket Histogram Aggregation configured via the View
API.
([#5396](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5396))

## 1.7.0

Released 2023-Dec-08
Expand Down
78 changes: 50 additions & 28 deletions src/OpenTelemetry/Metrics/MetricPoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ internal MetricPoint(
{
this.mpComponents = new MetricPointOptionalComponents();
this.mpComponents.Base2ExponentialBucketHistogram = new Base2ExponentialBucketHistogram(exponentialHistogramMaxSize, exponentialHistogramMaxScale);
if (isExemplarEnabled && reservoir == null)
{
reservoir = new SimpleFixedSizeExemplarReservoir(Math.Min(20, exponentialHistogramMaxSize));
cijothomas marked this conversation as resolved.
Show resolved Hide resolved
}
}
else
{
Expand Down Expand Up @@ -558,13 +562,13 @@ internal void UpdateWithExemplar(long number, ReadOnlySpan<KeyValuePair<string,

case AggregationType.Base2ExponentialHistogram:
{
this.UpdateBase2ExponentialHistogram((double)number, tags, true);
this.UpdateBase2ExponentialHistogram((double)number, tags, reportExemplar: true, isSampled);
break;
}

case AggregationType.Base2ExponentialHistogramWithMinMax:
{
this.UpdateBase2ExponentialHistogramWithMinMax((double)number, tags, true);
this.UpdateBase2ExponentialHistogramWithMinMax((double)number, tags, reportExemplar: true, isSampled);
break;
}
}
Expand Down Expand Up @@ -770,13 +774,13 @@ internal void UpdateWithExemplar(double number, ReadOnlySpan<KeyValuePair<string

case AggregationType.Base2ExponentialHistogram:
{
this.UpdateBase2ExponentialHistogram(number, tags, true);
this.UpdateBase2ExponentialHistogram(number, tags, reportExemplar: true, isSampled);
break;
}

case AggregationType.Base2ExponentialHistogramWithMinMax:
{
this.UpdateBase2ExponentialHistogramWithMinMax(number, tags, true);
this.UpdateBase2ExponentialHistogramWithMinMax(number, tags, reportExemplar: true, isSampled);
break;
}
}
Expand Down Expand Up @@ -1262,6 +1266,7 @@ internal void TakeSnapshotWithExemplar(bool outputDelta)
histogram.Reset();
}

this.mpComponents.Exemplars = this.mpComponents.ExemplarReservoir?.Collect();
this.MetricPointStatus = MetricPointStatus.NoCollectPending;

this.mpComponents.ReleaseLock();
Expand Down Expand Up @@ -1292,6 +1297,7 @@ internal void TakeSnapshotWithExemplar(bool outputDelta)
histogram.RunningMax = double.NegativeInfinity;
}

this.mpComponents.Exemplars = this.mpComponents.ExemplarReservoir?.Collect();
this.MetricPointStatus = MetricPointStatus.NoCollectPending;

this.mpComponents.ReleaseLock();
Expand Down Expand Up @@ -1372,16 +1378,16 @@ private void UpdateHistogramWithBuckets(double number, ReadOnlySpan<KeyValuePair
this.runningValue.AsLong++;
histogramBuckets.RunningSum += number;
histogramBuckets.BucketCounts[i].RunningValue++;
}

if (reportExemplar && isSampled)
{
Debug.Assert(this.mpComponents.ExemplarReservoir != null, "ExemplarReservoir was null");
if (reportExemplar && isSampled)
{
Debug.Assert(this.mpComponents.ExemplarReservoir != null, "ExemplarReservoir was null");

// TODO: Need to ensure that the lock is always released.
// A custom implementation of `ExemplarReservoir.Offer` might throw an exception.
this.mpComponents.ExemplarReservoir!.Offer(
new ExemplarMeasurement<double>(number, tags, i));
}
// TODO: Need to ensure that the lock is always released.
// A custom implementation of `ExemplarReservoir.Offer` might throw an exception.
this.mpComponents.ExemplarReservoir!.Offer(
new ExemplarMeasurement<double>(number, tags, i));
}

this.mpComponents.ReleaseLock();
Expand All @@ -1403,26 +1409,24 @@ private void UpdateHistogramWithBucketsAndMinMax(double number, ReadOnlySpan<Key
histogramBuckets.RunningSum += number;
histogramBuckets.BucketCounts[i].RunningValue++;

if (reportExemplar && isSampled)
{
Debug.Assert(this.mpComponents.ExemplarReservoir != null, "ExemplarReservoir was null");

// TODO: Need to ensure that the lock is always released.
// A custom implementation of `ExemplarReservoir.Offer` might throw an exception.
this.mpComponents.ExemplarReservoir!.Offer(
new ExemplarMeasurement<double>(number, tags, i));
}

histogramBuckets.RunningMin = Math.Min(histogramBuckets.RunningMin, number);
histogramBuckets.RunningMax = Math.Max(histogramBuckets.RunningMax, number);
}

if (reportExemplar && isSampled)
{
Debug.Assert(this.mpComponents.ExemplarReservoir != null, "ExemplarReservoir was null");

// TODO: Need to ensure that the lock is always released.
// A custom implementation of `ExemplarReservoir.Offer` might throw an exception.
this.mpComponents.ExemplarReservoir!.Offer(
new ExemplarMeasurement<double>(number, tags, i));
}

this.mpComponents.ReleaseLock();
}

#pragma warning disable IDE0060 // Remove unused parameter: Exemplars for exponential histograms will be a follow up PR
private void UpdateBase2ExponentialHistogram(double number, ReadOnlySpan<KeyValuePair<string, object?>> tags = default, bool reportExemplar = false)
#pragma warning restore IDE0060 // Remove unused parameter
private void UpdateBase2ExponentialHistogram(double number, ReadOnlySpan<KeyValuePair<string, object?>> tags = default, bool reportExemplar = false, bool isSampled = false)
{
if (number < 0)
{
Expand All @@ -1442,12 +1446,20 @@ private void UpdateBase2ExponentialHistogram(double number, ReadOnlySpan<KeyValu
histogram.Record(number);
}

if (reportExemplar && isSampled)
{
Debug.Assert(this.mpComponents.ExemplarReservoir != null, "ExemplarReservoir was null");

// TODO: Need to ensure that the lock is always released.
// A custom implementation of `ExemplarReservoir.Offer` might throw an exception.
this.mpComponents.ExemplarReservoir!.Offer(
new ExemplarMeasurement<double>(number, tags));
}

this.mpComponents.ReleaseLock();
}

#pragma warning disable IDE0060 // Remove unused parameter: Exemplars for exponential histograms will be a follow up PR
private void UpdateBase2ExponentialHistogramWithMinMax(double number, ReadOnlySpan<KeyValuePair<string, object?>> tags = default, bool reportExemplar = false)
#pragma warning restore IDE0060 // Remove unused parameter
private void UpdateBase2ExponentialHistogramWithMinMax(double number, ReadOnlySpan<KeyValuePair<string, object?>> tags = default, bool reportExemplar = false, bool isSampled = false)
{
if (number < 0)
{
Expand All @@ -1470,6 +1482,16 @@ private void UpdateBase2ExponentialHistogramWithMinMax(double number, ReadOnlySp
histogram.RunningMax = Math.Max(histogram.RunningMax, number);
}

if (reportExemplar && isSampled)
{
Debug.Assert(this.mpComponents.ExemplarReservoir != null, "ExemplarReservoir was null");

// TODO: Need to ensure that the lock is always released.
// A custom implementation of `ExemplarReservoir.Offer` might throw an exception.
this.mpComponents.ExemplarReservoir!.Offer(
new ExemplarMeasurement<double>(number, tags));
}

this.mpComponents.ReleaseLock();
}

Expand Down
Loading