Skip to content

Commit f2c2255

Browse files
authored
Make MetricPoint reclaim an opt-in experimental feature (#5052)
1 parent bdd931e commit f2c2255

13 files changed

+831
-491
lines changed

src/OpenTelemetry/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@
3737
`8.0.0`.
3838
([#5051](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5051))
3939

40+
* Revert the default behavior of Metrics SDK for Delta aggregation. It would not
41+
reclaim unused Metric Points by default. You can enable the SDK to reclaim
42+
unused Metric Points by setting the environment variable
43+
`OTEL_DOTNET_EXPERIMENTAL_METRICS_RECLAIM_UNUSED_METRIC_POINTS` to `true`
44+
before setting up the `MeterProvider`.
45+
([#5052](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5052))
46+
4047
## 1.7.0-alpha.1
4148

4249
Released 2023-Oct-16

src/OpenTelemetry/Metrics/AggregatorStore.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ namespace OpenTelemetry.Metrics;
2525
internal sealed class AggregatorStore
2626
{
2727
internal readonly bool OutputDelta;
28+
internal readonly bool ShouldReclaimUnusedMetricPoints;
2829
internal long DroppedMeasurements = 0;
2930

3031
private static readonly string MetricPointCapHitFixMessage = "Consider opting in for the experimental SDK feature to emit all the throttled metrics under the overflow attribute by setting env variable OTEL_DOTNET_EXPERIMENTAL_METRICS_EMIT_OVERFLOW_ATTRIBUTE = true. You could also modify instrumentation to reduce the number of unique key/value pair combinations. Or use Views to drop unwanted tags. Or use MeterProviderBuilder.SetMaxMetricPointsPerMetricStream to set higher limit.";
@@ -81,6 +82,7 @@ internal AggregatorStore(
8182
AggregationTemporality temporality,
8283
int maxMetricPoints,
8384
bool emitOverflowAttribute,
85+
bool shouldReclaimUnusedMetricPoints,
8486
ExemplarFilter? exemplarFilter = null)
8587
{
8688
this.name = metricStreamIdentity.InstrumentName;
@@ -122,7 +124,9 @@ internal AggregatorStore(
122124
reservedMetricPointsCount++;
123125
}
124126

125-
if (this.OutputDelta)
127+
this.ShouldReclaimUnusedMetricPoints = shouldReclaimUnusedMetricPoints;
128+
129+
if (this.OutputDelta && shouldReclaimUnusedMetricPoints)
126130
{
127131
this.availableMetricPoints = new Queue<int>(maxMetricPoints - reservedMetricPointsCount);
128132

@@ -181,7 +185,7 @@ internal int Snapshot()
181185
this.batchSize = 0;
182186
if (this.OutputDelta)
183187
{
184-
if (this.reclaimMetricPoints)
188+
if (this.ShouldReclaimUnusedMetricPoints && this.reclaimMetricPoints)
185189
{
186190
this.SnapshotDeltaWithMetricPointReclaim();
187191
}

src/OpenTelemetry/Metrics/MeterProviderSdk.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@ internal sealed class MeterProviderSdk : MeterProvider
3030
internal readonly IDisposable? OwnedServiceProvider;
3131
internal int ShutdownCount;
3232
internal bool Disposed;
33+
internal bool ShouldReclaimUnusedMetricPoints;
3334

3435
private const string EmitOverFlowAttributeConfigKey = "OTEL_DOTNET_EXPERIMENTAL_METRICS_EMIT_OVERFLOW_ATTRIBUTE";
36+
private const string ReclaimUnusedMetricPointsConfigKey = "OTEL_DOTNET_EXPERIMENTAL_METRICS_RECLAIM_UNUSED_METRIC_POINTS";
3537

3638
private readonly List<object> instrumentations = new();
3739
private readonly List<Func<Instrument, MetricStreamConfiguration?>> viewConfigs;
@@ -51,6 +53,7 @@ internal MeterProviderSdk(
5153

5254
var config = serviceProvider!.GetRequiredService<IConfiguration>();
5355
_ = config.TryGetBoolValue(EmitOverFlowAttributeConfigKey, out bool isEmitOverflowAttributeKeySet);
56+
_ = config.TryGetBoolValue(ReclaimUnusedMetricPointsConfigKey, out this.ShouldReclaimUnusedMetricPoints);
5457

5558
this.ServiceProvider = serviceProvider!;
5659

src/OpenTelemetry/Metrics/Metric.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ internal Metric(
6060
AggregationTemporality temporality,
6161
int maxMetricPointsPerMetricStream,
6262
bool emitOverflowAttribute,
63+
bool shouldReclaimUnusedMetricPoints,
6364
ExemplarFilter? exemplarFilter = null)
6465
{
6566
this.InstrumentIdentity = instrumentIdentity;
@@ -166,7 +167,7 @@ internal Metric(
166167
throw new NotSupportedException($"Unsupported Instrument Type: {instrumentIdentity.InstrumentType.FullName}");
167168
}
168169

169-
this.aggStore = new AggregatorStore(instrumentIdentity, aggType, temporality, maxMetricPointsPerMetricStream, emitOverflowAttribute, exemplarFilter);
170+
this.aggStore = new AggregatorStore(instrumentIdentity, aggType, temporality, maxMetricPointsPerMetricStream, emitOverflowAttribute, shouldReclaimUnusedMetricPoints, exemplarFilter);
170171
this.Temporality = temporality;
171172
this.InstrumentDisposed = false;
172173
}

src/OpenTelemetry/Metrics/MetricPoint.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ internal MetricPoint(
6464
Debug.Assert(aggregatorStore != null, "AggregatorStore was null.");
6565
Debug.Assert(histogramExplicitBounds != null, "Histogram explicit Bounds was null.");
6666

67-
if (aggregatorStore!.OutputDelta)
67+
if (aggregatorStore!.OutputDelta && aggregatorStore.ShouldReclaimUnusedMetricPoints)
6868
{
6969
Debug.Assert(lookupData != null, "LookupData was null.");
7070
}

src/OpenTelemetry/Metrics/MetricReaderExt.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ internal AggregationTemporality GetAggregationTemporality(Type instrumentType)
7575
Metric? metric = null;
7676
try
7777
{
78-
metric = new Metric(metricStreamIdentity, this.GetAggregationTemporality(metricStreamIdentity.InstrumentType), this.maxMetricPointsPerMetricStream, this.emitOverflowAttribute, this.exemplarFilter);
78+
bool shouldReclaimUnusedMetricPoints = this.parentProvider is MeterProviderSdk meterProviderSdk && meterProviderSdk.ShouldReclaimUnusedMetricPoints;
79+
metric = new Metric(metricStreamIdentity, this.GetAggregationTemporality(metricStreamIdentity.InstrumentType), this.maxMetricPointsPerMetricStream, this.emitOverflowAttribute, shouldReclaimUnusedMetricPoints, this.exemplarFilter);
7980
}
8081
catch (NotSupportedException nse)
8182
{
@@ -162,7 +163,8 @@ internal List<Metric> AddMetricsListWithViews(Instrument instrument, List<Metric
162163
}
163164
else
164165
{
165-
Metric metric = new(metricStreamIdentity, this.GetAggregationTemporality(metricStreamIdentity.InstrumentType), this.maxMetricPointsPerMetricStream, this.emitOverflowAttribute, this.exemplarFilter);
166+
bool shouldReclaimUnusedMetricPoints = this.parentProvider is MeterProviderSdk meterProviderSdk && meterProviderSdk.ShouldReclaimUnusedMetricPoints;
167+
Metric metric = new(metricStreamIdentity, this.GetAggregationTemporality(metricStreamIdentity.InstrumentType), this.maxMetricPointsPerMetricStream, this.emitOverflowAttribute, shouldReclaimUnusedMetricPoints, this.exemplarFilter);
166168

167169
this.instrumentIdentityToMetric[metricStreamIdentity] = metric;
168170
this.metrics![index] = metric;

test/OpenTelemetry.Tests/Metrics/AggregatorTestsBase.cs

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,15 @@ public abstract class AggregatorTestsBase
2929
private static readonly MetricStreamIdentity MetricStreamIdentity = new(Instrument, HistogramConfiguration);
3030

3131
private readonly bool emitOverflowAttribute;
32+
private readonly bool shouldReclaimUnusedMetricPoints;
3233
private readonly AggregatorStore aggregatorStore;
3334

34-
protected AggregatorTestsBase(bool emitOverflowAttribute)
35+
protected AggregatorTestsBase(bool emitOverflowAttribute, bool shouldReclaimUnusedMetricPoints)
3536
{
36-
if (emitOverflowAttribute)
37-
{
38-
this.emitOverflowAttribute = emitOverflowAttribute;
39-
}
37+
this.emitOverflowAttribute = emitOverflowAttribute;
38+
this.shouldReclaimUnusedMetricPoints = shouldReclaimUnusedMetricPoints;
4039

41-
this.aggregatorStore = new(MetricStreamIdentity, AggregationType.HistogramWithBuckets, AggregationTemporality.Cumulative, 1024, emitOverflowAttribute);
40+
this.aggregatorStore = new(MetricStreamIdentity, AggregationType.HistogramWithBuckets, AggregationTemporality.Cumulative, 1024, emitOverflowAttribute, this.shouldReclaimUnusedMetricPoints);
4241
}
4342

4443
[Fact]
@@ -268,7 +267,8 @@ public void HistogramBucketsDefaultUpdatesForSecondsTest(string meterName, strin
268267
AggregationType.Histogram,
269268
AggregationTemporality.Cumulative,
270269
maxMetricPoints: 1024,
271-
this.emitOverflowAttribute);
270+
this.emitOverflowAttribute,
271+
this.shouldReclaimUnusedMetricPoints);
272272

273273
KnownHistogramBuckets actualHistogramBounds = KnownHistogramBuckets.Default;
274274
if (aggregatorStore.HistogramBounds == Metric.DefaultHistogramBoundsShortSeconds)
@@ -345,6 +345,7 @@ internal void ExponentialHistogramTests(AggregationType aggregationType, Aggrega
345345
aggregationTemporality,
346346
maxMetricPoints: 1024,
347347
this.emitOverflowAttribute,
348+
this.shouldReclaimUnusedMetricPoints,
348349
exemplarsEnabled ? new AlwaysOnExemplarFilter() : null);
349350

350351
var expectedHistogram = new Base2ExponentialBucketHistogram();
@@ -453,7 +454,8 @@ internal void ExponentialMaxScaleConfigWorks(int? maxScale)
453454
AggregationType.Base2ExponentialHistogram,
454455
AggregationTemporality.Cumulative,
455456
maxMetricPoints: 1024,
456-
this.emitOverflowAttribute);
457+
this.emitOverflowAttribute,
458+
this.shouldReclaimUnusedMetricPoints);
457459

458460
aggregatorStore.Update(10, Array.Empty<KeyValuePair<string, object>>());
459461

@@ -529,15 +531,31 @@ private class ThreadArguments
529531
public class AggregatorTests : AggregatorTestsBase
530532
{
531533
public AggregatorTests()
532-
: base(false)
534+
: base(emitOverflowAttribute: false, shouldReclaimUnusedMetricPoints: false)
533535
{
534536
}
535537
}
536538

537539
public class AggregatorTestsWithOverflowAttribute : AggregatorTestsBase
538540
{
539541
public AggregatorTestsWithOverflowAttribute()
540-
: base(true)
542+
: base(emitOverflowAttribute: true, shouldReclaimUnusedMetricPoints: false)
543+
{
544+
}
545+
}
546+
547+
public class AggregatorTestsWithReclaimAttribute : AggregatorTestsBase
548+
{
549+
public AggregatorTestsWithReclaimAttribute()
550+
: base(emitOverflowAttribute: false, shouldReclaimUnusedMetricPoints: true)
551+
{
552+
}
553+
}
554+
555+
public class AggregatorTestsWithBothReclaimAndOverflowAttributes : AggregatorTestsBase
556+
{
557+
public AggregatorTestsWithBothReclaimAndOverflowAttributes()
558+
: base(emitOverflowAttribute: true, shouldReclaimUnusedMetricPoints: true)
541559
{
542560
}
543561
}

0 commit comments

Comments
 (0)