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

Make MetricPoint reclaim an opt-in experimental feature #5052

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
7 changes: 7 additions & 0 deletions src/OpenTelemetry/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@
`8.0.0`.
([#5051](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5051))

* Revert the default behavior of Metrics SDK for Delta aggregation. It would not
reclaim unused Metric Points by default. You can enable the SDK to reclaim
unused Metric Points by setting the environment variable
`OTEL_DOTNET_EXPERIMENTAL_METRICS_RECLAIM_UNUSED_METRIC_POINTS` to `true`
before setting up the `MeterProvider`.
([#5052](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5052))

## 1.7.0-alpha.1

Released 2023-Oct-16
Expand Down
8 changes: 6 additions & 2 deletions src/OpenTelemetry/Metrics/AggregatorStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ namespace OpenTelemetry.Metrics;
internal sealed class AggregatorStore
{
internal readonly bool OutputDelta;
internal readonly bool ShouldReclaimUnusedMetricPoints;
internal long DroppedMeasurements = 0;

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.";
Expand Down Expand Up @@ -81,6 +82,7 @@ internal AggregatorStore(
AggregationTemporality temporality,
int maxMetricPoints,
bool emitOverflowAttribute,
bool shouldReclaimUnusedMetricPoints,
ExemplarFilter? exemplarFilter = null)
{
this.name = metricStreamIdentity.InstrumentName;
Expand Down Expand Up @@ -122,7 +124,9 @@ internal AggregatorStore(
reservedMetricPointsCount++;
}

if (this.OutputDelta)
this.ShouldReclaimUnusedMetricPoints = shouldReclaimUnusedMetricPoints;

if (this.OutputDelta && shouldReclaimUnusedMetricPoints)
{
this.availableMetricPoints = new Queue<int>(maxMetricPoints - reservedMetricPointsCount);

Expand Down Expand Up @@ -181,7 +185,7 @@ internal int Snapshot()
this.batchSize = 0;
if (this.OutputDelta)
{
if (this.reclaimMetricPoints)
if (this.ShouldReclaimUnusedMetricPoints && this.reclaimMetricPoints)
{
this.SnapshotDeltaWithMetricPointReclaim();
}
Expand Down
3 changes: 3 additions & 0 deletions src/OpenTelemetry/Metrics/MeterProviderSdk.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ internal sealed class MeterProviderSdk : MeterProvider
internal readonly IDisposable? OwnedServiceProvider;
internal int ShutdownCount;
internal bool Disposed;
internal bool ShouldReclaimUnusedMetricPoints;

private const string EmitOverFlowAttributeConfigKey = "OTEL_DOTNET_EXPERIMENTAL_METRICS_EMIT_OVERFLOW_ATTRIBUTE";
private const string ReclaimUnusedMetricPointsConfigKey = "OTEL_DOTNET_EXPERIMENTAL_METRICS_RECLAIM_UNUSED_METRIC_POINTS";

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

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

this.ServiceProvider = serviceProvider!;

Expand Down
3 changes: 2 additions & 1 deletion src/OpenTelemetry/Metrics/Metric.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ internal Metric(
AggregationTemporality temporality,
int maxMetricPointsPerMetricStream,
bool emitOverflowAttribute,
bool shouldReclaimUnusedMetricPoints,
ExemplarFilter? exemplarFilter = null)
{
this.InstrumentIdentity = instrumentIdentity;
Expand Down Expand Up @@ -166,7 +167,7 @@ internal Metric(
throw new NotSupportedException($"Unsupported Instrument Type: {instrumentIdentity.InstrumentType.FullName}");
}

this.aggStore = new AggregatorStore(instrumentIdentity, aggType, temporality, maxMetricPointsPerMetricStream, emitOverflowAttribute, exemplarFilter);
this.aggStore = new AggregatorStore(instrumentIdentity, aggType, temporality, maxMetricPointsPerMetricStream, emitOverflowAttribute, shouldReclaimUnusedMetricPoints, exemplarFilter);
this.Temporality = temporality;
this.InstrumentDisposed = false;
}
Expand Down
2 changes: 1 addition & 1 deletion src/OpenTelemetry/Metrics/MetricPoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ internal MetricPoint(
Debug.Assert(aggregatorStore != null, "AggregatorStore was null.");
Debug.Assert(histogramExplicitBounds != null, "Histogram explicit Bounds was null.");

if (aggregatorStore!.OutputDelta)
if (aggregatorStore!.OutputDelta && aggregatorStore.ShouldReclaimUnusedMetricPoints)
{
Debug.Assert(lookupData != null, "LookupData was null.");
}
Expand Down
6 changes: 4 additions & 2 deletions src/OpenTelemetry/Metrics/MetricReaderExt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ internal AggregationTemporality GetAggregationTemporality(Type instrumentType)
Metric? metric = null;
try
{
metric = new Metric(metricStreamIdentity, this.GetAggregationTemporality(metricStreamIdentity.InstrumentType), this.maxMetricPointsPerMetricStream, this.emitOverflowAttribute, this.exemplarFilter);
bool shouldReclaimUnusedMetricPoints = this.parentProvider is MeterProviderSdk meterProviderSdk && meterProviderSdk.ShouldReclaimUnusedMetricPoints;
metric = new Metric(metricStreamIdentity, this.GetAggregationTemporality(metricStreamIdentity.InstrumentType), this.maxMetricPointsPerMetricStream, this.emitOverflowAttribute, shouldReclaimUnusedMetricPoints, this.exemplarFilter);
}
catch (NotSupportedException nse)
{
Expand Down Expand Up @@ -162,7 +163,8 @@ internal List<Metric> AddMetricsListWithViews(Instrument instrument, List<Metric
}
else
{
Metric metric = new(metricStreamIdentity, this.GetAggregationTemporality(metricStreamIdentity.InstrumentType), this.maxMetricPointsPerMetricStream, this.emitOverflowAttribute, this.exemplarFilter);
bool shouldReclaimUnusedMetricPoints = this.parentProvider is MeterProviderSdk meterProviderSdk && meterProviderSdk.ShouldReclaimUnusedMetricPoints;
Metric metric = new(metricStreamIdentity, this.GetAggregationTemporality(metricStreamIdentity.InstrumentType), this.maxMetricPointsPerMetricStream, this.emitOverflowAttribute, shouldReclaimUnusedMetricPoints, this.exemplarFilter);

this.instrumentIdentityToMetric[metricStreamIdentity] = metric;
this.metrics![index] = metric;
Expand Down
38 changes: 28 additions & 10 deletions test/OpenTelemetry.Tests/Metrics/AggregatorTestsBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,15 @@ public abstract class AggregatorTestsBase
private static readonly MetricStreamIdentity MetricStreamIdentity = new(Instrument, HistogramConfiguration);

private readonly bool emitOverflowAttribute;
private readonly bool shouldReclaimUnusedMetricPoints;
private readonly AggregatorStore aggregatorStore;

protected AggregatorTestsBase(bool emitOverflowAttribute)
protected AggregatorTestsBase(bool emitOverflowAttribute, bool shouldReclaimUnusedMetricPoints)
{
if (emitOverflowAttribute)
{
this.emitOverflowAttribute = emitOverflowAttribute;
}
this.emitOverflowAttribute = emitOverflowAttribute;
this.shouldReclaimUnusedMetricPoints = shouldReclaimUnusedMetricPoints;

this.aggregatorStore = new(MetricStreamIdentity, AggregationType.HistogramWithBuckets, AggregationTemporality.Cumulative, 1024, emitOverflowAttribute);
this.aggregatorStore = new(MetricStreamIdentity, AggregationType.HistogramWithBuckets, AggregationTemporality.Cumulative, 1024, emitOverflowAttribute, this.shouldReclaimUnusedMetricPoints);
}

[Fact]
Expand Down Expand Up @@ -268,7 +267,8 @@ public void HistogramBucketsDefaultUpdatesForSecondsTest(string meterName, strin
AggregationType.Histogram,
AggregationTemporality.Cumulative,
maxMetricPoints: 1024,
this.emitOverflowAttribute);
this.emitOverflowAttribute,
this.shouldReclaimUnusedMetricPoints);

KnownHistogramBuckets actualHistogramBounds = KnownHistogramBuckets.Default;
if (aggregatorStore.HistogramBounds == Metric.DefaultHistogramBoundsShortSeconds)
Expand Down Expand Up @@ -345,6 +345,7 @@ internal void ExponentialHistogramTests(AggregationType aggregationType, Aggrega
aggregationTemporality,
maxMetricPoints: 1024,
this.emitOverflowAttribute,
this.shouldReclaimUnusedMetricPoints,
exemplarsEnabled ? new AlwaysOnExemplarFilter() : null);

var expectedHistogram = new Base2ExponentialBucketHistogram();
Expand Down Expand Up @@ -453,7 +454,8 @@ internal void ExponentialMaxScaleConfigWorks(int? maxScale)
AggregationType.Base2ExponentialHistogram,
AggregationTemporality.Cumulative,
maxMetricPoints: 1024,
this.emitOverflowAttribute);
this.emitOverflowAttribute,
this.shouldReclaimUnusedMetricPoints);

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

Expand Down Expand Up @@ -529,15 +531,31 @@ private class ThreadArguments
public class AggregatorTests : AggregatorTestsBase
{
public AggregatorTests()
: base(false)
: base(emitOverflowAttribute: false, shouldReclaimUnusedMetricPoints: false)
{
}
}

public class AggregatorTestsWithOverflowAttribute : AggregatorTestsBase
{
public AggregatorTestsWithOverflowAttribute()
: base(true)
: base(emitOverflowAttribute: true, shouldReclaimUnusedMetricPoints: false)
{
}
}

public class AggregatorTestsWithReclaimAttribute : AggregatorTestsBase
{
public AggregatorTestsWithReclaimAttribute()
: base(emitOverflowAttribute: false, shouldReclaimUnusedMetricPoints: true)
{
}
}

public class AggregatorTestsWithBothReclaimAndOverflowAttributes : AggregatorTestsBase
{
public AggregatorTestsWithBothReclaimAndOverflowAttributes()
: base(emitOverflowAttribute: true, shouldReclaimUnusedMetricPoints: true)
{
}
}
Loading