Allow ability to override max Metric streams and MetricPoints per stream (#2635)

This commit is contained in:
Cijo Thomas 2021-11-19 10:50:16 -08:00 committed by GitHub
parent ca291422ff
commit 5dcf29f770
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 117 additions and 21 deletions

View File

@ -112,6 +112,8 @@ static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddView(this OpenTel
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddView(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder, string instrumentName, string name) -> OpenTelemetry.Metrics.MeterProviderBuilder
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddView(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder, System.Func<System.Diagnostics.Metrics.Instrument, OpenTelemetry.Metrics.MetricStreamConfiguration> viewConfig) -> OpenTelemetry.Metrics.MeterProviderBuilder
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.Build(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProvider
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.SetMaxMetricPointsPerMetricStream(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder, int maxMetricPointsPerMetricStream) -> OpenTelemetry.Metrics.MeterProviderBuilder
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.SetMaxMetricStreams(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder, int maxMetricStreams) -> OpenTelemetry.Metrics.MeterProviderBuilder
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.SetResourceBuilder(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder, OpenTelemetry.Resources.ResourceBuilder resourceBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder
static OpenTelemetry.Metrics.MeterProviderExtensions.ForceFlush(this OpenTelemetry.Metrics.MeterProvider provider, int timeoutMilliseconds = -1) -> bool
static OpenTelemetry.Metrics.MeterProviderExtensions.Shutdown(this OpenTelemetry.Metrics.MeterProvider provider, int timeoutMilliseconds = -1) -> bool

View File

@ -112,6 +112,8 @@ static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddView(this OpenTel
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddView(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder, string instrumentName, string name) -> OpenTelemetry.Metrics.MeterProviderBuilder
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.AddView(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder, System.Func<System.Diagnostics.Metrics.Instrument, OpenTelemetry.Metrics.MetricStreamConfiguration> viewConfig) -> OpenTelemetry.Metrics.MeterProviderBuilder
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.Build(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder) -> OpenTelemetry.Metrics.MeterProvider
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.SetMaxMetricPointsPerMetricStream(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder, int maxMetricPointsPerMetricStream) -> OpenTelemetry.Metrics.MeterProviderBuilder
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.SetMaxMetricStreams(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder, int maxMetricStreams) -> OpenTelemetry.Metrics.MeterProviderBuilder
static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.SetResourceBuilder(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder, OpenTelemetry.Resources.ResourceBuilder resourceBuilder) -> OpenTelemetry.Metrics.MeterProviderBuilder
static OpenTelemetry.Metrics.MeterProviderExtensions.ForceFlush(this OpenTelemetry.Metrics.MeterProvider provider, int timeoutMilliseconds = -1) -> bool
static OpenTelemetry.Metrics.MeterProviderExtensions.Shutdown(this OpenTelemetry.Metrics.MeterProvider provider, int timeoutMilliseconds = -1) -> bool

View File

@ -31,6 +31,9 @@
* Add support for multiple Metric readers
([#2596](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2596))
* Add ability to configure MaxMetricStreams, MaxMetricPointsPerMetricStream
([#2635](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2635))
## 1.2.0-beta1
Released 2021-Oct-08

View File

@ -24,7 +24,6 @@ namespace OpenTelemetry.Metrics
{
internal sealed class AggregatorStore
{
internal const int MaxMetricPoints = 2000;
private static readonly ObjectArrayEqualityComparer ObjectArrayComparer = new ObjectArrayEqualityComparer();
private readonly object lockZeroTags = new object();
private readonly HashSet<string> tagKeysInteresting;
@ -42,6 +41,7 @@ namespace OpenTelemetry.Metrics
private readonly double[] histogramBounds;
private readonly UpdateLongDelegate updateLongCallback;
private readonly UpdateDoubleDelegate updateDoubleCallback;
private readonly int maxMetricPoints;
private int metricPointIndex = 0;
private int batchSize = 0;
private bool zeroTagMetricPointInitialized;
@ -51,11 +51,13 @@ namespace OpenTelemetry.Metrics
internal AggregatorStore(
AggregationType aggType,
AggregationTemporality temporality,
int maxMetricPoints,
double[] histogramBounds,
string[] tagKeysInteresting = null)
{
this.metricPoints = new MetricPoint[MaxMetricPoints];
this.currentMetricPointBatch = new int[MaxMetricPoints];
this.maxMetricPoints = maxMetricPoints;
this.metricPoints = new MetricPoint[maxMetricPoints];
this.currentMetricPointBatch = new int[maxMetricPoints];
this.aggType = aggType;
this.temporality = temporality;
this.outputDelta = temporality == AggregationTemporality.Delta ? true : false;
@ -98,7 +100,7 @@ namespace OpenTelemetry.Metrics
internal int Snapshot()
{
this.batchSize = 0;
var indexSnapshot = Math.Min(this.metricPointIndex, MaxMetricPoints - 1);
var indexSnapshot = Math.Min(this.metricPointIndex, this.maxMetricPoints - 1);
if (this.temporality == AggregationTemporality.Delta)
{
this.SnapshotDelta(indexSnapshot);
@ -197,7 +199,7 @@ namespace OpenTelemetry.Metrics
if (!value2metrics.TryGetValue(tagValues, out aggregatorIndex))
{
aggregatorIndex = this.metricPointIndex;
if (aggregatorIndex >= MaxMetricPoints)
if (aggregatorIndex >= this.maxMetricPoints)
{
// sorry! out of data points.
// TODO: Once we support cleanup of
@ -212,7 +214,7 @@ namespace OpenTelemetry.Metrics
if (!value2metrics.TryGetValue(tagValues, out aggregatorIndex))
{
aggregatorIndex = Interlocked.Increment(ref this.metricPointIndex);
if (aggregatorIndex >= MaxMetricPoints)
if (aggregatorIndex >= this.maxMetricPoints)
{
// sorry! out of data points.
// TODO: Once we support cleanup of

View File

@ -29,10 +29,14 @@ namespace OpenTelemetry.Metrics
/// </summary>
public abstract class MeterProviderBuilderBase : MeterProviderBuilder
{
internal const int MaxMetricsDefault = 1000;
internal const int MaxMetricPointsPerMetricDefault = 2000;
private readonly List<InstrumentationFactory> instrumentationFactories = new List<InstrumentationFactory>();
private readonly List<string> meterSources = new List<string>();
private readonly List<Func<Instrument, MetricStreamConfiguration>> viewConfigs = new List<Func<Instrument, MetricStreamConfiguration>>();
private ResourceBuilder resourceBuilder = ResourceBuilder.CreateDefault();
private int maxMetricStreams = MaxMetricsDefault;
private int maxMetricPointsPerMetricStream = MaxMetricPointsPerMetricDefault;
protected MeterProviderBuilderBase()
{
@ -100,6 +104,22 @@ namespace OpenTelemetry.Metrics
return this;
}
internal MeterProviderBuilder SetMaxMetricStreams(int maxMetricStreams)
{
Guard.Range(maxMetricStreams, min: 1);
this.maxMetricStreams = maxMetricStreams;
return this;
}
internal MeterProviderBuilder SetMaxMetricPointsPerMetricStream(int maxMetricPointsPerMetricStream)
{
Guard.Range(maxMetricPointsPerMetricStream, min: 1);
this.maxMetricPointsPerMetricStream = maxMetricPointsPerMetricStream;
return this;
}
internal MeterProviderBuilder SetResourceBuilder(ResourceBuilder resourceBuilder)
{
Debug.Assert(resourceBuilder != null, $"{nameof(resourceBuilder)} must not be null");
@ -119,6 +139,8 @@ namespace OpenTelemetry.Metrics
this.meterSources,
this.instrumentationFactories,
this.viewConfigs,
this.maxMetricStreams,
this.maxMetricPointsPerMetricStream,
this.MetricReaders.ToArray());
}

View File

@ -121,6 +121,53 @@ namespace OpenTelemetry.Metrics
return meterProviderBuilder;
}
/// <summary>
/// Sets the maximum number of Metric streams supported by the MeterProvider.
/// When no Views are configured, every instrument will result in one metric stream,
/// so this control the numbers of instruments supported.
/// When Views are configued, a single instrument can result in multiple metric streams,
/// so this control the number of streams.
/// </summary>
/// <param name="meterProviderBuilder">MeterProviderBuilder instance.</param>
/// <param name="maxMetricStreams">Maximum number of metric streams allowed.</param>
/// <returns>Returns <see cref="MeterProviderBuilder"/> for chaining.</returns>
/// <remarks>
/// If an instrument is created, but disposed later, this will still be contributing to the limit.
/// This may change in the future.
/// </remarks>
public static MeterProviderBuilder SetMaxMetricStreams(this MeterProviderBuilder meterProviderBuilder, int maxMetricStreams)
{
if (meterProviderBuilder is MeterProviderBuilderBase meterProviderBuilderBase)
{
meterProviderBuilderBase.SetMaxMetricStreams(maxMetricStreams);
}
return meterProviderBuilder;
}
/// <summary>
/// Sets the maximum number of MetricPoints allowed per metric stream.
/// This limits the number of unique combinations of key/value pairs used
/// for reporting measurements.
/// </summary>
/// <param name="meterProviderBuilder">MeterProviderBuilder instance.</param>
/// <param name="maxMetricPointsPerMetricStream">Maximum maximum number of metric points allowed per metric stream.</param>
/// <returns>Returns <see cref="MeterProviderBuilder"/> for chaining.</returns>
/// <remarks>
/// If a particular key/value pair combination is used at least once,
/// it will contribute to the limit for the life of the process.
/// This may change in the future. See: https://github.com/open-telemetry/opentelemetry-dotnet/issues/2360.
/// </remarks>
public static MeterProviderBuilder SetMaxMetricPointsPerMetricStream(this MeterProviderBuilder meterProviderBuilder, int maxMetricPointsPerMetricStream)
{
if (meterProviderBuilder is MeterProviderBuilderBase meterProviderBuilderBase)
{
meterProviderBuilderBase.SetMaxMetricPointsPerMetricStream(maxMetricPointsPerMetricStream);
}
return meterProviderBuilder;
}
/// <summary>
/// Sets the <see cref="ResourceBuilder"/> from which the Resource associated with
/// this provider is built from. Overwrites currently set ResourceBuilder.

View File

@ -41,6 +41,8 @@ namespace OpenTelemetry.Metrics
IEnumerable<string> meterSources,
List<MeterProviderBuilderBase.InstrumentationFactory> instrumentationFactories,
List<Func<Instrument, MetricStreamConfiguration>> viewConfigs,
int maxMetricStreams,
int maxMetricPointsPerMetricStream,
IEnumerable<MetricReader> readers)
{
this.Resource = resource;
@ -51,6 +53,8 @@ namespace OpenTelemetry.Metrics
Guard.Null(reader, nameof(reader));
reader.SetParentProvider(this);
reader.SetMaxMetricStreams(maxMetricStreams);
reader.SetMaxMetricPointsPerMetricStream(maxMetricPointsPerMetricStream);
if (this.reader == null)
{

View File

@ -30,6 +30,7 @@ namespace OpenTelemetry.Metrics
AggregationTemporality temporality,
string metricName,
string metricDescription,
int maxMetricPointsPerMetricStream,
double[] histogramBounds = null,
string[] tagKeysInteresting = null)
{
@ -104,7 +105,7 @@ namespace OpenTelemetry.Metrics
// TODO: Log and assign some invalid Enum.
}
this.aggStore = new AggregatorStore(aggType, temporality, histogramBounds ?? DefaultHistogramBounds, tagKeysInteresting);
this.aggStore = new AggregatorStore(aggType, temporality, maxMetricPointsPerMetricStream, histogramBounds ?? DefaultHistogramBounds, tagKeysInteresting);
this.Temporality = temporality;
this.InstrumentDisposed = false;
}

View File

@ -26,11 +26,12 @@ namespace OpenTelemetry.Metrics
/// </summary>
public abstract partial class MetricReader
{
internal const int MaxMetrics = 1000;
private readonly Metric[] metrics = new Metric[MaxMetrics];
private readonly Metric[] metricsCurrentBatch = new Metric[MaxMetrics];
private readonly HashSet<string> metricStreamNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
private readonly object instrumentCreationLock = new object();
private int maxMetricStreams;
private int maxMetricPointsPerMetricStream;
private Metric[] metrics;
private Metric[] metricsCurrentBatch;
private int metricIndex = -1;
internal Metric AddMetricWithNoViews(Instrument instrument)
@ -47,14 +48,14 @@ namespace OpenTelemetry.Metrics
}
var index = ++this.metricIndex;
if (index >= MaxMetrics)
if (index >= this.maxMetricStreams)
{
OpenTelemetrySdkEventSource.Log.MetricInstrumentIgnored(metricName, instrument.Meter.Name, "Maximum allowed Metrics for the provider exceeded.", "Use views to drop unused instruments. Or configure Provider to allow higher limit.");
return null;
}
else
{
var metric = new Metric(instrument, this.preferredAggregationTemporality, metricName, instrument.Description);
var metric = new Metric(instrument, this.preferredAggregationTemporality, metricName, instrument.Description, this.maxMetricPointsPerMetricStream);
this.metrics[index] = metric;
this.metricStreamNames.Add(metricStreamName);
return metric;
@ -118,7 +119,7 @@ namespace OpenTelemetry.Metrics
}
var index = ++this.metricIndex;
if (index >= MaxMetrics)
if (index >= this.maxMetricStreams)
{
// TODO: Log that instrument is ignored
// as max number of Metrics have reached.
@ -130,7 +131,7 @@ namespace OpenTelemetry.Metrics
string[] tagKeysInteresting = metricStreamConfig?.TagKeys;
double[] histogramBucketBounds = (metricStreamConfig is ExplicitBucketHistogramConfiguration histogramConfig
&& histogramConfig.Boundaries != null) ? histogramConfig.Boundaries : null;
metric = new Metric(instrument, this.preferredAggregationTemporality, metricName, metricDescription, histogramBucketBounds, tagKeysInteresting);
metric = new Metric(instrument, this.preferredAggregationTemporality, metricName, metricDescription, this.maxMetricPointsPerMetricStream, histogramBucketBounds, tagKeysInteresting);
this.metrics[index] = metric;
metrics.Add(metric);
@ -191,11 +192,23 @@ namespace OpenTelemetry.Metrics
}
}
internal void SetMaxMetricStreams(int maxMetricStreams)
{
this.maxMetricStreams = maxMetricStreams;
this.metrics = new Metric[maxMetricStreams];
this.metricsCurrentBatch = new Metric[maxMetricStreams];
}
internal void SetMaxMetricPointsPerMetricStream(int maxMetricPointsPerMetricStream)
{
this.maxMetricPointsPerMetricStream = maxMetricPointsPerMetricStream;
}
private Batch<Metric> GetMetricsBatch()
{
try
{
var indexSnapshot = Math.Min(this.metricIndex, MaxMetrics - 1);
var indexSnapshot = Math.Min(this.metricIndex, this.maxMetricStreams - 1);
var target = indexSnapshot + 1;
int metricCountCurrentBatch = 0;
for (int i = 0; i < target; i++)

View File

@ -489,26 +489,26 @@ namespace OpenTelemetry.Metrics.Tests
// for no tag point!
// This may be changed later.
counterLong.Add(10);
for (int i = 0; i < AggregatorStore.MaxMetricPoints + 1; i++)
for (int i = 0; i < MeterProviderBuilderBase.MaxMetricPointsPerMetricDefault + 1; i++)
{
counterLong.Add(10, new KeyValuePair<string, object>("key", "value" + i));
}
metricReader.Collect();
Assert.Equal(AggregatorStore.MaxMetricPoints, MetricPointCount());
Assert.Equal(MeterProviderBuilderBase.MaxMetricPointsPerMetricDefault, MetricPointCount());
metricItems.Clear();
counterLong.Add(10);
for (int i = 0; i < AggregatorStore.MaxMetricPoints + 1; i++)
for (int i = 0; i < MeterProviderBuilderBase.MaxMetricPointsPerMetricDefault + 1; i++)
{
counterLong.Add(10, new KeyValuePair<string, object>("key", "value" + i));
}
metricReader.Collect();
Assert.Equal(AggregatorStore.MaxMetricPoints, MetricPointCount());
Assert.Equal(MeterProviderBuilderBase.MaxMetricPointsPerMetricDefault, MetricPointCount());
counterLong.Add(10);
for (int i = 0; i < AggregatorStore.MaxMetricPoints + 1; i++)
for (int i = 0; i < MeterProviderBuilderBase.MaxMetricPointsPerMetricDefault + 1; i++)
{
counterLong.Add(10, new KeyValuePair<string, object>("key", "value" + i));
}
@ -519,7 +519,7 @@ namespace OpenTelemetry.Metrics.Tests
counterLong.Add(10, new KeyValuePair<string, object>("key", "valueC"));
metricItems.Clear();
metricReader.Collect();
Assert.Equal(AggregatorStore.MaxMetricPoints, MetricPointCount());
Assert.Equal(MeterProviderBuilderBase.MaxMetricPointsPerMetricDefault, MetricPointCount());
}
[Fact]