Skip to content

Commit

Permalink
[sdk-metrics] Pass all tags supplied at measurement to ExemplarReserv…
Browse files Browse the repository at this point in the history
…oir.Offer methods (#5414)
  • Loading branch information
CodeBlanch authored Mar 6, 2024
1 parent df2abe8 commit a7f3400
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 27 deletions.
4 changes: 2 additions & 2 deletions src/OpenTelemetry/Metrics/AggregatorStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -959,7 +959,7 @@ private void UpdateLong(long value, ReadOnlySpan<KeyValuePair<string, object?>>
{
var index = this.FindMetricAggregatorsDefault(tags);

this.UpdateLongMetricPoint(index, value, tags: default);
this.UpdateLongMetricPoint(index, value, tags);
}

private void UpdateLongCustomTags(long value, ReadOnlySpan<KeyValuePair<string, object?>> tags)
Expand Down Expand Up @@ -1014,7 +1014,7 @@ private void UpdateDouble(double value, ReadOnlySpan<KeyValuePair<string, object
{
var index = this.FindMetricAggregatorsDefault(tags);

this.UpdateDoubleMetricPoint(index, value, tags: default);
this.UpdateDoubleMetricPoint(index, value, tags);
}

private void UpdateDoubleCustomTags(double value, ReadOnlySpan<KeyValuePair<string, object?>> tags)
Expand Down
5 changes: 4 additions & 1 deletion src/OpenTelemetry/Metrics/Exemplar/Exemplar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,10 @@ internal void Update<T>(in ExemplarMeasurement<T> measurement)
this.SpanId = default;
}

this.StoreRawTags(measurement.Tags);
if (this.ViewDefinedTagKeys != null)
{
this.StoreRawTags(measurement.Tags);
}
}

internal void Reset()
Expand Down
100 changes: 76 additions & 24 deletions test/OpenTelemetry.Tests/Metrics/MetricExemplarTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -689,49 +689,79 @@ public void TestTraceBasedExemplarFilter(bool enableTracing)
}
}

[Fact]
public void TestExemplarsFilterTags()
[Theory]
[InlineData(true)]
[InlineData(false)]
public void TestExemplarsFilterTags(bool enableTagFiltering)
{
DateTime testStartTime = DateTime.UtcNow;
var exportedItems = new List<Metric>();

using var meter = new Meter($"{Utils.GetCurrentMethodName()}");

var histogram = meter.CreateHistogram<double>("testHistogram");

TestExemplarReservoir? testExemplarReservoir = null;

using var container = this.BuildMeterProvider(out var meterProvider, builder => builder
.AddMeter(meter.Name)
.SetExemplarFilter(ExemplarFilterType.AlwaysOn)
.AddView(histogram.Name, new MetricStreamConfiguration() { TagKeys = new string[] { "key1" } })
.AddInMemoryExporter(exportedItems, metricReaderOptions =>
{
metricReaderOptions.TemporalityPreference = MetricReaderTemporalityPreference.Delta;
}));
.AddView(
histogram.Name,
new MetricStreamConfiguration()
{
TagKeys = enableTagFiltering ? new string[] { "key1" } : null,
ExemplarReservoirFactory = () =>
{
if (testExemplarReservoir != null)
{
throw new InvalidOperationException();
}

return testExemplarReservoir = new TestExemplarReservoir();
},
})
.AddInMemoryExporter(exportedItems));

var measurementValues = GenerateRandomValues(10, false, null);
foreach (var value in measurementValues)
{
histogram.Record(
value.Value,
new("key1", "value1"),
new("key2", "value1"),
new("key3", "value1"));
}
histogram.Record(
0,
new("key1", "value1"),
new("key2", "value2"),
new("key3", "value3"));

meterProvider.ForceFlush();

Assert.NotNull(testExemplarReservoir);
Assert.NotNull(testExemplarReservoir.MeasurementTags);
Assert.Equal(3, testExemplarReservoir.MeasurementTags.Length);
Assert.Contains(testExemplarReservoir.MeasurementTags, t => t.Key == "key1" && (string?)t.Value == "value1");
Assert.Contains(testExemplarReservoir.MeasurementTags, t => t.Key == "key2" && (string?)t.Value == "value2");
Assert.Contains(testExemplarReservoir.MeasurementTags, t => t.Key == "key3" && (string?)t.Value == "value3");

meterProvider.ForceFlush(MaxTimeToAllowForFlush);
var metricPoint = GetFirstMetricPoint(exportedItems);

Assert.NotNull(metricPoint);
Assert.True(metricPoint.Value.StartTime >= testStartTime);
Assert.True(metricPoint.Value.EndTime != default);

var exemplars = GetExemplars(metricPoint.Value);

Assert.NotNull(exemplars);

foreach (var exemplar in exemplars)
{
Assert.NotEqual(0, exemplar.FilteredTags.MaximumCount);
if (!enableTagFiltering)
{
Assert.Equal(0, exemplar.FilteredTags.MaximumCount);
}
else
{
Assert.Equal(3, exemplar.FilteredTags.MaximumCount);

var filteredTags = exemplar.FilteredTags.ToReadOnlyList();
var filteredTags = exemplar.FilteredTags.ToReadOnlyList();

Assert.Contains(new("key2", "value1"), filteredTags);
Assert.Contains(new("key3", "value1"), filteredTags);
Assert.Equal(2, filteredTags.Count);

Assert.Contains(new("key2", "value2"), filteredTags);
Assert.Contains(new("key3", "value3"), filteredTags);
}
}
}

Expand Down Expand Up @@ -791,4 +821,26 @@ private static void ValidateExemplars(

Assert.Equal(measurementValues.Count(), count);
}

private sealed class TestExemplarReservoir : FixedSizeExemplarReservoir
{
public TestExemplarReservoir()
: base(1)
{
}

public KeyValuePair<string, object?>[]? MeasurementTags { get; private set; }

public override void Offer(in ExemplarMeasurement<double> measurement)
{
this.MeasurementTags = measurement.Tags.ToArray();

this.UpdateExemplar(0, in measurement);
}

public override void Offer(in ExemplarMeasurement<long> measurement)
{
throw new NotSupportedException();
}
}
}

0 comments on commit a7f3400

Please sign in to comment.