internal AggregatorStore(
            AggregationType aggType,
            AggregationTemporality temporality,
            double[] histogramBounds,
            string[] tagKeysInteresting = null)
        {
            this.metricPoints       = new MetricPoint[MaxMetricPoints];
            this.aggType            = aggType;
            this.temporality        = temporality;
            this.outputDelta        = temporality == AggregationTemporality.Delta ? true : false;
            this.histogramBounds    = histogramBounds;
            this.startTimeExclusive = DateTimeOffset.UtcNow;
            if (tagKeysInteresting == null)
            {
                this.updateLongCallback   = this.UpdateLong;
                this.updateDoubleCallback = this.UpdateDouble;
            }
            else
            {
                this.updateLongCallback   = this.UpdateLongCustomTags;
                this.updateDoubleCallback = this.UpdateDoubleCustomTags;
                var hs = new HashSet <string>(StringComparer.Ordinal);
                foreach (var key in tagKeysInteresting)
                {
                    hs.Add(key);
                }

                this.tagKeysInteresting       = hs;
                this.tagsKeysInterestingCount = hs.Count;
            }
        }
示例#2
0
        public void ExportOnlyWhenPointChanged(AggregationTemporality temporality)
        {
            using var meter = new Meter($"{Utils.GetCurrentMethodName()}.{temporality}");

            var exportedItems = new List <Metric>();

            using var meterProvider = Sdk.CreateMeterProviderBuilder()
                                      .AddMeter(meter.Name)
                                      .AddReader(
                      new BaseExportingMetricReader(new InMemoryExporter <Metric>(exportedItems))
            {
                Temporality = temporality,
            })
                                      .Build();

            var counter = meter.CreateCounter <long>("meter");

            counter.Add(10, new KeyValuePair <string, object>("tag1", "value1"));
            meterProvider.ForceFlush();
            Assert.Single(exportedItems);

            exportedItems.Clear();
            meterProvider.ForceFlush();
            if (temporality == AggregationTemporality.Cumulative)
            {
                Assert.Single(exportedItems);
            }
            else
            {
                Assert.Empty(exportedItems);
            }
        }
 internal AggregatorStore(
     string name,
     AggregationType aggType,
     AggregationTemporality temporality,
     int maxMetricPoints,
     double[] histogramBounds,
     string[] tagKeysInteresting = null)
 {
     this.name                     = name;
     this.maxMetricPoints          = maxMetricPoints;
     this.metricPointCapHitMessage = $"Maximum MetricPoints limit reached for this Metric stream. Configured limit: {this.maxMetricPoints}";
     this.metricPoints             = new MetricPoint[maxMetricPoints];
     this.currentMetricPointBatch  = new int[maxMetricPoints];
     this.aggType                  = aggType;
     this.temporality              = temporality;
     this.outputDelta              = temporality == AggregationTemporality.Delta ? true : false;
     this.histogramBounds          = histogramBounds;
     this.startTimeExclusive       = DateTimeOffset.UtcNow;
     if (tagKeysInteresting == null)
     {
         this.updateLongCallback   = this.UpdateLong;
         this.updateDoubleCallback = this.UpdateDouble;
     }
     else
     {
         this.updateLongCallback   = this.UpdateLongCustomTags;
         this.updateDoubleCallback = this.UpdateDoubleCustomTags;
         var hs = new HashSet <string>(tagKeysInteresting, StringComparer.Ordinal);
         this.tagKeysInteresting       = hs;
         this.tagsKeysInterestingCount = hs.Count;
     }
 }
        public void TestMetricPointCap(AggregationTemporality temporality)
        {
            var metricItems      = new List <Metric>();
            int metricPointCount = 0;
            var metricExporter   = new TestExporter <Metric>(ProcessExport);

            void ProcessExport(Batch <Metric> batch)
            {
                foreach (var metric in batch)
                {
                    foreach (ref var metricPoint in metric.GetMetricPoints())
                    {
                        metricPointCount++;
                    }
                }
            }

            var metricReader = new BaseExportingMetricReader(metricExporter)
            {
                PreferredAggregationTemporality = temporality,
            };

            using var meter = new Meter("TestPointCapMeter");
            var counterLong = meter.CreateCounter <long>("mycounterCapTest");

            using var meterProvider = Sdk.CreateMeterProviderBuilder()
                                      .AddMeter("TestPointCapMeter")
                                      .AddReader(metricReader)
                                      .Build();

            // Make one Add with no tags.
            // as currently we reserve 0th index
            // for no tag point!
            // This may be changed later.
            counterLong.Add(10);
            for (int i = 0; i < AggregatorStore.MaxMetricPoints + 1; i++)
            {
                counterLong.Add(10, new KeyValuePair <string, object>("key", "value" + i));
            }

            metricReader.Collect();
            Assert.Equal(AggregatorStore.MaxMetricPoints, metricPointCount);

            metricPointCount = 0;
            metricReader.Collect();
            Assert.Equal(AggregatorStore.MaxMetricPoints, metricPointCount);

            // These updates would be dropped.
            counterLong.Add(10, new KeyValuePair <string, object>("key", "valueA"));
            counterLong.Add(10, new KeyValuePair <string, object>("key", "valueB"));
            counterLong.Add(10, new KeyValuePair <string, object>("key", "valueC"));
            metricPointCount = 0;
            metricReader.Collect();
            Assert.Equal(AggregatorStore.MaxMetricPoints, metricPointCount);
        }
        public void StreamNamesDuplicatesAreNotAllowedTest(AggregationTemporality temporality)
        {
            var metricItems    = new List <Metric>();
            int metricCount    = 0;
            var metricExporter = new TestExporter <Metric>(ProcessExport);

            void ProcessExport(Batch <Metric> batch)
            {
                foreach (var metric in batch)
                {
                    metricCount++;
                }
            }

            var metricReader = new BaseExportingMetricReader(metricExporter)
            {
                PreferredAggregationTemporality = temporality,
            };

            using var meter1        = new Meter("TestDuplicateMetricName1");
            using var meter2        = new Meter("TestDuplicateMetricName2");
            using var meterProvider = Sdk.CreateMeterProviderBuilder()
                                      .AddMeter("TestDuplicateMetricName1")
                                      .AddMeter("TestDuplicateMetricName2")
                                      .AddReader(metricReader)
                                      .Build();

            // Expecting one metric stream.
            var counterLong = meter1.CreateCounter <long>("name1");

            counterLong.Add(10);
            metricReader.Collect();
            Assert.Equal(1, metricCount);

            // The following will be ignored as
            // metric of same name exists.
            // Metric stream will remain one.
            var anotherCounterSameName = meter1.CreateCounter <long>("name1");

            anotherCounterSameName.Add(10);
            metricCount = 0;
            metricReader.Collect();
            Assert.Equal(1, metricCount);

            // The following will also be ignored
            // as the name is same.
            // (the Meter name is not part of stream name)
            var anotherCounterSameNameDiffMeter = meter2.CreateCounter <long>("name1");

            anotherCounterSameNameDiffMeter.Add(10);
            metricCount = 0;
            metricReader.Collect();
            Assert.Equal(1, metricCount);
        }
        public void TestInstrumentDisposal(AggregationTemporality temporality)
        {
            var metricItems    = new List <Metric>();
            var metricExporter = new InMemoryExporter <Metric>(metricItems);
            var metricReader   = new BaseExportingMetricReader(metricExporter)
            {
                PreferredAggregationTemporality = temporality,
            };

            var meter1   = new Meter($"{Utils.GetCurrentMethodName()}.{temporality}.1");
            var meter2   = new Meter($"{Utils.GetCurrentMethodName()}.{temporality}.2");
            var counter1 = meter1.CreateCounter <long>("counterFromMeter1");
            var counter2 = meter2.CreateCounter <long>("counterFromMeter2");

            using var meterProvider = Sdk.CreateMeterProviderBuilder()
                                      .AddMeter(meter1.Name)
                                      .AddMeter(meter2.Name)
                                      .AddReader(metricReader)
                                      .Build();

            counter1.Add(10, new KeyValuePair <string, object>("key", "value"));
            counter2.Add(10, new KeyValuePair <string, object>("key", "value"));

            metricReader.Collect();
            Assert.Equal(2, metricItems.Count);
            metricItems.Clear();

            counter1.Add(10, new KeyValuePair <string, object>("key", "value"));
            counter2.Add(10, new KeyValuePair <string, object>("key", "value"));
            meter1.Dispose();

            metricReader.Collect();
            Assert.Equal(2, metricItems.Count);
            metricItems.Clear();

            counter1.Add(10, new KeyValuePair <string, object>("key", "value"));
            counter2.Add(10, new KeyValuePair <string, object>("key", "value"));
            metricReader.Collect();
            Assert.Single(metricItems);
            metricItems.Clear();

            counter1.Add(10, new KeyValuePair <string, object>("key", "value"));
            counter2.Add(10, new KeyValuePair <string, object>("key", "value"));
            meter2.Dispose();

            metricReader.Collect();
            Assert.Single(metricItems);
            metricItems.Clear();

            counter1.Add(10, new KeyValuePair <string, object>("key", "value"));
            counter2.Add(10, new KeyValuePair <string, object>("key", "value"));
            metricReader.Collect();
            Assert.Empty(metricItems);
        }
        public void DuplicateInstrumentNamesFromDifferentMetersAreAllowed(AggregationTemporality temporality, bool hasView)
        {
            var metricItems    = new List <Metric>();
            var metricExporter = new InMemoryExporter <Metric>(metricItems);

            var metricReader = new BaseExportingMetricReader(metricExporter)
            {
                PreferredAggregationTemporality = temporality,
            };

            using var meter1 = new Meter($"{Utils.GetCurrentMethodName()}.1.{temporality}");
            using var meter2 = new Meter($"{Utils.GetCurrentMethodName()}.2.{temporality}");
            var meterProviderBuilder = Sdk.CreateMeterProviderBuilder()
                                       .AddMeter(meter1.Name)
                                       .AddMeter(meter2.Name)
                                       .AddReader(metricReader);

            if (hasView)
            {
                meterProviderBuilder.AddView("name1", new MetricStreamConfiguration()
                {
                    Description = "description"
                });
            }

            using var meterProvider = meterProviderBuilder.Build();

            // Expecting one metric stream.
            var counterLong = meter1.CreateCounter <long>("name1");

            counterLong.Add(10);
            metricReader.Collect();
            Assert.Single(metricItems);

            // The following will not be ignored
            // as it is the same metric name but different meter.
            var anotherCounterSameNameDiffMeter = meter2.CreateCounter <long>("name1");

            anotherCounterSameNameDiffMeter.Add(10);
            counterLong.Add(10);
            metricItems.Clear();
            metricReader.Collect();
            Assert.Equal(2, metricItems.Count);
        }
        public void DuplicateInstrumentNamesFromSameMeterAreNotAllowed(AggregationTemporality temporality, bool hasView)
        {
            var metricItems    = new List <Metric>();
            var metricExporter = new InMemoryExporter <Metric>(metricItems);

            var metricReader = new BaseExportingMetricReader(metricExporter)
            {
                PreferredAggregationTemporality = temporality,
            };

            using var meter = new Meter($"{Utils.GetCurrentMethodName()}.{temporality}");
            var meterProviderBuilder = Sdk.CreateMeterProviderBuilder()
                                       .AddMeter(meter.Name)
                                       .AddReader(metricReader);

            if (hasView)
            {
                meterProviderBuilder.AddView("name1", new MetricStreamConfiguration()
                {
                    Description = "description"
                });
            }

            using var meterProvider = meterProviderBuilder.Build();

            // Expecting one metric stream.
            var counterLong = meter.CreateCounter <long>("name1");

            counterLong.Add(10);
            metricReader.Collect();
            Assert.Single(metricItems);

            // The following will be ignored as
            // metric of same name exists.
            // Metric stream will remain one.
            var anotherCounterSameName = meter.CreateCounter <long>("name1");

            anotherCounterSameName.Add(10);
            counterLong.Add(10);
            metricItems.Clear();
            metricReader.Collect();
            Assert.Single(metricItems);
        }
示例#9
0
        public void TestMetricPointCap(AggregationTemporality temporality)
        {
            var exportedItems = new List <Metric>();

            int MetricPointCount()
            {
                var count = 0;

                foreach (var metric in exportedItems)
                {
                    foreach (ref readonly var metricPoint in metric.GetMetricPoints())
                    {
                        count++;
                    }
                }

                return(count);
            }

            using var meter = new Meter($"{Utils.GetCurrentMethodName()}.{temporality}");
            var counterLong = meter.CreateCounter <long>("mycounterCapTest");

            using var meterProvider = Sdk.CreateMeterProviderBuilder()
                                      .AddMeter(meter.Name)
                                      .AddReader(new BaseExportingMetricReader(new InMemoryExporter <Metric>(exportedItems))
            {
                Temporality = temporality,
            })
                                      .Build();

            // Make one Add with no tags.
            // as currently we reserve 0th index
            // for no tag point!
            // This may be changed later.
            counterLong.Add(10);
            for (int i = 0; i < MeterProviderBuilderBase.MaxMetricPointsPerMetricDefault + 1; i++)
            {
                counterLong.Add(10, new KeyValuePair <string, object>("key", "value" + i));
            }

            meterProvider.ForceFlush(MaxTimeToAllowForFlush);
            Assert.Equal(MeterProviderBuilderBase.MaxMetricPointsPerMetricDefault, MetricPointCount());

            exportedItems.Clear();
            counterLong.Add(10);
            for (int i = 0; i < MeterProviderBuilderBase.MaxMetricPointsPerMetricDefault + 1; i++)
            {
                counterLong.Add(10, new KeyValuePair <string, object>("key", "value" + i));
            }

            meterProvider.ForceFlush(MaxTimeToAllowForFlush);
            Assert.Equal(MeterProviderBuilderBase.MaxMetricPointsPerMetricDefault, MetricPointCount());

            counterLong.Add(10);
            for (int i = 0; i < MeterProviderBuilderBase.MaxMetricPointsPerMetricDefault + 1; i++)
            {
                counterLong.Add(10, new KeyValuePair <string, object>("key", "value" + i));
            }

            // These updates would be dropped.
            counterLong.Add(10, new KeyValuePair <string, object>("key", "valueA"));
            counterLong.Add(10, new KeyValuePair <string, object>("key", "valueB"));
            counterLong.Add(10, new KeyValuePair <string, object>("key", "valueC"));
            exportedItems.Clear();
            meterProvider.ForceFlush(MaxTimeToAllowForFlush);
            Assert.Equal(MeterProviderBuilderBase.MaxMetricPointsPerMetricDefault, MetricPointCount());
        }
示例#10
0
        public void TestHistogramToOltpMetric(string name, string description, string unit, long?longValue, double?doubleValue, AggregationTemporality aggregationTemporality, params object[] keysValues)
        {
            var metrics = new List <Metric>();

            var metricReader = new BaseExportingMetricReader(new InMemoryExporter <Metric>(metrics));

            metricReader.Temporality = aggregationTemporality;

            using var meter    = new Meter(Utils.GetCurrentMethodName());
            using var provider = Sdk.CreateMeterProviderBuilder()
                                 .AddMeter(meter.Name)
                                 .AddReader(metricReader)
                                 .Build();

            var attributes = ToAttributes(keysValues).ToArray();

            if (longValue.HasValue)
            {
                var histogram = meter.CreateHistogram <long>(name, unit, description);
                histogram.Record(longValue.Value, attributes);
            }
            else
            {
                var histogram = meter.CreateHistogram <double>(name, unit, description);
                histogram.Record(doubleValue.Value, attributes);
            }

            provider.ForceFlush();

            var batch = new Batch <Metric>(metrics.ToArray(), metrics.Count);

            var request = new OtlpCollector.ExportMetricsServiceRequest();

            request.AddMetrics(ResourceBuilder.CreateEmpty().Build().ToOtlpResource(), batch);

            var resourceMetric = request.ResourceMetrics.Single();
            var instrumentationLibraryMetrics = resourceMetric.InstrumentationLibraryMetrics.Single();
            var actual = instrumentationLibraryMetrics.Metrics.Single();

            Assert.Equal(name, actual.Name);
            Assert.Equal(description ?? string.Empty, actual.Description);
            Assert.Equal(unit ?? string.Empty, actual.Unit);

            Assert.Equal(OtlpMetrics.Metric.DataOneofCase.Histogram, actual.DataCase);

            Assert.Null(actual.Gauge);
            Assert.Null(actual.Sum);
            Assert.NotNull(actual.Histogram);
            Assert.Null(actual.ExponentialHistogram);
            Assert.Null(actual.Summary);

            var otlpAggregationTemporality = aggregationTemporality == AggregationTemporality.Cumulative
                ? OtlpMetrics.AggregationTemporality.Cumulative
                : OtlpMetrics.AggregationTemporality.Delta;

            Assert.Equal(otlpAggregationTemporality, actual.Histogram.AggregationTemporality);

            Assert.Single(actual.Histogram.DataPoints);
            var dataPoint = actual.Histogram.DataPoints.First();

            Assert.True(dataPoint.StartTimeUnixNano > 0);
            Assert.True(dataPoint.TimeUnixNano > 0);

            Assert.Equal(1UL, dataPoint.Count);

            if (longValue.HasValue)
            {
                Assert.Equal((double)longValue, dataPoint.Sum);
            }
            else
            {
                Assert.Equal(doubleValue, dataPoint.Sum);
            }

            int bucketIndex;

            for (bucketIndex = 0; bucketIndex < dataPoint.ExplicitBounds.Count; ++bucketIndex)
            {
                if (dataPoint.Sum <= dataPoint.ExplicitBounds[bucketIndex])
                {
                    break;
                }

                Assert.Equal(0UL, dataPoint.BucketCounts[bucketIndex]);
            }

            Assert.Equal(1UL, dataPoint.BucketCounts[bucketIndex]);

            if (attributes.Length > 0)
            {
                OtlpTestHelpers.AssertOtlpAttributes(attributes, dataPoint.Attributes);
            }
            else
            {
                Assert.Empty(dataPoint.Attributes);
            }

            Assert.Empty(dataPoint.Exemplars);

#pragma warning disable CS0612 // Type or member is obsolete
            Assert.Null(actual.IntGauge);
            Assert.Null(actual.IntSum);
            Assert.Null(actual.IntHistogram);
            Assert.Empty(dataPoint.Labels);
#pragma warning restore CS0612 // Type or member is obsolete
        }
示例#11
0
        public void SdkSupportsMultipleReaders(AggregationTemporality aggregationTemporality, bool hasViews)
        {
            var exportedItems1 = new List <Metric>();

            using var deltaExporter1 = new InMemoryExporter <Metric>(exportedItems1);
            using var deltaReader1   = new BaseExportingMetricReader(deltaExporter1)
                  {
                      Temporality = AggregationTemporality.Delta,
                  };

            var exportedItems2 = new List <Metric>();

            using var deltaExporter2 = new InMemoryExporter <Metric>(exportedItems2);
            using var deltaReader2   = new BaseExportingMetricReader(deltaExporter2)
                  {
                      Temporality = aggregationTemporality,
                  };
            using var meter = new Meter($"{Utils.GetCurrentMethodName()}.{aggregationTemporality}.{hasViews}");

            var counter = meter.CreateCounter <long>("counter");

            int index  = 0;
            var values = new long[] { 100, 200, 300, 400 };

            long GetValue() => values[index++];

            var gauge = meter.CreateObservableGauge("gauge", () => GetValue());

            var meterProviderBuilder = Sdk.CreateMeterProviderBuilder()
                                       .AddMeter(meter.Name)
                                       .AddReader(deltaReader1)
                                       .AddReader(deltaReader2);

            if (hasViews)
            {
                meterProviderBuilder.AddView("counter", "renamedCounter");
            }

            using var meterProvider = meterProviderBuilder.Build();

            counter.Add(10, new KeyValuePair <string, object>("key", "value"));

            meterProvider.ForceFlush();

            Assert.Equal(2, exportedItems1.Count);
            Assert.Equal(2, exportedItems2.Count);

            // Check value exported for Counter
            this.AssertLongSumValueForMetric(exportedItems1[0], 10);
            this.AssertLongSumValueForMetric(exportedItems2[0], 10);

            // Check value exported for Gauge
            this.AssertLongSumValueForMetric(exportedItems1[1], 100);
            this.AssertLongSumValueForMetric(exportedItems2[1], 200);

            exportedItems1.Clear();
            exportedItems2.Clear();

            counter.Add(15, new KeyValuePair <string, object>("key", "value"));

            meterProvider.ForceFlush();

            Assert.Equal(2, exportedItems1.Count);
            Assert.Equal(2, exportedItems2.Count);

            // Check value exported for Counter
            this.AssertLongSumValueForMetric(exportedItems1[0], 15);
            if (aggregationTemporality == AggregationTemporality.Delta)
            {
                this.AssertLongSumValueForMetric(exportedItems2[0], 15);
            }
            else
            {
                this.AssertLongSumValueForMetric(exportedItems2[0], 25);
            }

            // Check value exported for Gauge
            this.AssertLongSumValueForMetric(exportedItems1[1], 300);
            this.AssertLongSumValueForMetric(exportedItems2[1], 400);
        }
示例#12
0
 public AggregationTemporalityAttribute(AggregationTemporality supported, AggregationTemporality preferred)
 {
     this.supportedAggregationTemporality = supported;
     this.preferredAggregationTemporality = preferred;
 }
示例#13
0
        internal Metric(
            Instrument instrument,
            AggregationTemporality temporality,
            string metricName,
            string metricDescription,
            double[] histogramBounds    = null,
            string[] tagKeysInteresting = null)
        {
            this.Name        = metricName;
            this.Description = metricDescription ?? string.Empty;
            this.Unit        = instrument.Unit ?? string.Empty;
            this.Meter       = instrument.Meter;
            AggregationType aggType = default;

            if (instrument.GetType() == typeof(ObservableCounter <long>) ||
                instrument.GetType() == typeof(ObservableCounter <int>) ||
                instrument.GetType() == typeof(ObservableCounter <short>) ||
                instrument.GetType() == typeof(ObservableCounter <byte>))
            {
                aggType         = AggregationType.LongSumIncomingCumulative;
                this.MetricType = MetricType.LongSum;
            }
            else if (instrument.GetType() == typeof(Counter <long>) ||
                     instrument.GetType() == typeof(Counter <int>) ||
                     instrument.GetType() == typeof(Counter <short>) ||
                     instrument.GetType() == typeof(Counter <byte>))
            {
                aggType         = AggregationType.LongSumIncomingDelta;
                this.MetricType = MetricType.LongSum;
            }
            else if (instrument.GetType() == typeof(Counter <double>) ||
                     instrument.GetType() == typeof(Counter <float>))
            {
                aggType         = AggregationType.DoubleSumIncomingDelta;
                this.MetricType = MetricType.DoubleSum;
            }
            else if (instrument.GetType() == typeof(ObservableCounter <double>) ||
                     instrument.GetType() == typeof(ObservableCounter <float>))
            {
                aggType         = AggregationType.DoubleSumIncomingCumulative;
                this.MetricType = MetricType.DoubleSum;
            }
            else if (instrument.GetType() == typeof(ObservableGauge <double>) ||
                     instrument.GetType() == typeof(ObservableGauge <float>))
            {
                aggType         = AggregationType.DoubleGauge;
                this.MetricType = MetricType.DoubleGauge;
            }
            else if (instrument.GetType() == typeof(ObservableGauge <long>) ||
                     instrument.GetType() == typeof(ObservableGauge <int>) ||
                     instrument.GetType() == typeof(ObservableGauge <short>) ||
                     instrument.GetType() == typeof(ObservableGauge <byte>))
            {
                aggType         = AggregationType.LongGauge;
                this.MetricType = MetricType.LongGauge;
            }
            else if (instrument.GetType() == typeof(Histogram <long>) ||
                     instrument.GetType() == typeof(Histogram <int>) ||
                     instrument.GetType() == typeof(Histogram <short>) ||
                     instrument.GetType() == typeof(Histogram <byte>) ||
                     instrument.GetType() == typeof(Histogram <float>) ||
                     instrument.GetType() == typeof(Histogram <double>))
            {
                this.MetricType = MetricType.Histogram;

                if (histogramBounds != null &&
                    histogramBounds.Length == 0)
                {
                    aggType = AggregationType.HistogramSumCount;
                }
                else
                {
                    aggType = AggregationType.Histogram;
                }
            }
            else
            {
                // TODO: Log and assign some invalid Enum.
            }

            this.aggStore           = new AggregatorStore(aggType, temporality, histogramBounds ?? DefaultHistogramBounds, tagKeysInteresting);
            this.Temporality        = temporality;
            this.InstrumentDisposed = false;
        }
        internal Metric(
            MetricStreamIdentity instrumentIdentity,
            AggregationTemporality temporality,
            int maxMetricPointsPerMetricStream,
            double[] histogramBounds    = null,
            string[] tagKeysInteresting = null)
        {
            this.InstrumentIdentity = instrumentIdentity;

            AggregationType aggType;

            if (instrumentIdentity.InstrumentType == typeof(ObservableCounter <long>) ||
                instrumentIdentity.InstrumentType == typeof(ObservableCounter <int>) ||
                instrumentIdentity.InstrumentType == typeof(ObservableCounter <short>) ||
                instrumentIdentity.InstrumentType == typeof(ObservableCounter <byte>))
            {
                aggType         = AggregationType.LongSumIncomingCumulative;
                this.MetricType = MetricType.LongSum;
            }
            else if (instrumentIdentity.InstrumentType == typeof(Counter <long>) ||
                     instrumentIdentity.InstrumentType == typeof(Counter <int>) ||
                     instrumentIdentity.InstrumentType == typeof(Counter <short>) ||
                     instrumentIdentity.InstrumentType == typeof(Counter <byte>))
            {
                aggType         = AggregationType.LongSumIncomingDelta;
                this.MetricType = MetricType.LongSum;
            }
            else if (instrumentIdentity.InstrumentType == typeof(Counter <double>) ||
                     instrumentIdentity.InstrumentType == typeof(Counter <float>))
            {
                aggType         = AggregationType.DoubleSumIncomingDelta;
                this.MetricType = MetricType.DoubleSum;
            }
            else if (instrumentIdentity.InstrumentType == typeof(ObservableCounter <double>) ||
                     instrumentIdentity.InstrumentType == typeof(ObservableCounter <float>))
            {
                aggType         = AggregationType.DoubleSumIncomingCumulative;
                this.MetricType = MetricType.DoubleSum;
            }
            else if (instrumentIdentity.InstrumentType == typeof(ObservableGauge <double>) ||
                     instrumentIdentity.InstrumentType == typeof(ObservableGauge <float>))
            {
                aggType         = AggregationType.DoubleGauge;
                this.MetricType = MetricType.DoubleGauge;
            }
            else if (instrumentIdentity.InstrumentType == typeof(ObservableGauge <long>) ||
                     instrumentIdentity.InstrumentType == typeof(ObservableGauge <int>) ||
                     instrumentIdentity.InstrumentType == typeof(ObservableGauge <short>) ||
                     instrumentIdentity.InstrumentType == typeof(ObservableGauge <byte>))
            {
                aggType         = AggregationType.LongGauge;
                this.MetricType = MetricType.LongGauge;
            }
            else if (instrumentIdentity.InstrumentType == typeof(Histogram <long>) ||
                     instrumentIdentity.InstrumentType == typeof(Histogram <int>) ||
                     instrumentIdentity.InstrumentType == typeof(Histogram <short>) ||
                     instrumentIdentity.InstrumentType == typeof(Histogram <byte>) ||
                     instrumentIdentity.InstrumentType == typeof(Histogram <float>) ||
                     instrumentIdentity.InstrumentType == typeof(Histogram <double>))
            {
                this.MetricType = MetricType.Histogram;

                if (histogramBounds != null &&
                    histogramBounds.Length == 0)
                {
                    aggType = AggregationType.HistogramSumCount;
                }
                else
                {
                    aggType = AggregationType.Histogram;
                }
            }
            else
            {
                throw new NotSupportedException($"Unsupported Instrument Type: {instrumentIdentity.InstrumentType.FullName}");
            }

            this.aggStore           = new AggregatorStore(instrumentIdentity.InstrumentName, aggType, temporality, maxMetricPointsPerMetricStream, histogramBounds ?? DefaultHistogramBounds, tagKeysInteresting);
            this.Temporality        = temporality;
            this.InstrumentDisposed = false;
        }
 public AggregationTemporalityAttribute(AggregationTemporality temporality)
 {
     this.temporality = temporality;
 }
        internal MeterProviderSdk(
            Resource resource,
            IEnumerable <string> meterSources,
            List <MeterProviderBuilderBase.InstrumentationFactory> instrumentationFactories,
            List <Func <Instrument, MetricStreamConfiguration> > viewConfigs,
            IEnumerable <MetricReader> readers)
        {
            this.Resource            = resource;
            this.viewConfigs         = viewConfigs;
            this.metrics             = new Metric[MaxMetrics];
            this.metricsCurrentBatch = new Metric[MaxMetrics];

            AggregationTemporality temporality = AggregationTemporality.Cumulative;

            foreach (var reader in readers)
            {
                Guard.Null(reader, nameof(reader));

                reader.SetParentProvider(this);

                // TODO: Actually support multiple readers.
                // Currently the last reader's temporality wins.
                temporality = reader.PreferredAggregationTemporality;

                if (this.reader == null)
                {
                    this.reader = reader;
                }
                else if (this.reader is CompositeMetricReader compositeReader)
                {
                    compositeReader.AddReader(reader);
                }
                else
                {
                    this.reader = new CompositeMetricReader(new[] { this.reader, reader });
                }
            }

            if (instrumentationFactories.Any())
            {
                foreach (var instrumentationFactory in instrumentationFactories)
                {
                    this.instrumentations.Add(instrumentationFactory.Factory());
                }
            }

            // Setup Listener
            Func <Instrument, bool> shouldListenTo = instrument => false;

            if (meterSources.Any(s => s.Contains('*')))
            {
                var regex = GetWildcardRegex(meterSources);
                shouldListenTo = instrument => regex.IsMatch(instrument.Meter.Name);
            }
            else if (meterSources.Any())
            {
                var meterSourcesToSubscribe = new HashSet <string>(StringComparer.OrdinalIgnoreCase);
                foreach (var meterSource in meterSources)
                {
                    meterSourcesToSubscribe.Add(meterSource);
                }

                shouldListenTo = instrument => meterSourcesToSubscribe.Contains(instrument.Meter.Name);
            }

            this.listener = new MeterListener();
            var viewConfigCount = this.viewConfigs.Count;

            if (viewConfigCount > 0)
            {
                this.listener.InstrumentPublished = (instrument, listener) =>
                {
                    if (!shouldListenTo(instrument))
                    {
                        OpenTelemetrySdkEventSource.Log.MetricInstrumentIgnored(instrument.Name, instrument.Meter.Name, "Instrument belongs to a Meter not subscribed by the provider.", "Use AddMeter to add the Meter to the provider.");
                        return;
                    }

                    // Creating list with initial capacity as the maximum
                    // possible size, to avoid any array resize/copy internally.
                    // There may be excess space wasted, but it'll eligible for
                    // GC right after this method.
                    var metricStreamConfigs = new List <MetricStreamConfiguration>(viewConfigCount);
                    foreach (var viewConfig in this.viewConfigs)
                    {
                        var metricStreamConfig = viewConfig(instrument);
                        if (metricStreamConfig != null)
                        {
                            metricStreamConfigs.Add(metricStreamConfig);
                        }
                    }

                    if (metricStreamConfigs.Count == 0)
                    {
                        // No views matched. Add null
                        // which will apply defaults.
                        // Users can turn off this default
                        // by adding a view like below as the last view.
                        // .AddView(instrumentName: "*", MetricStreamConfiguration.Drop)
                        metricStreamConfigs.Add(null);
                    }

                    var maxCountMetricsToBeCreated = metricStreamConfigs.Count;

                    // Create list with initial capacity as the max metric count.
                    // Due to duplicate/max limit, we may not end up using them
                    // all, and that memory is wasted until Meter disposed.
                    // TODO: Revisit to see if we need to do metrics.TrimExcess()
                    var metrics = new List <Metric>(maxCountMetricsToBeCreated);
                    lock (this.instrumentCreationLock)
                    {
                        for (int i = 0; i < maxCountMetricsToBeCreated; i++)
                        {
                            var metricStreamConfig = metricStreamConfigs[i];
                            var meterName          = instrument.Meter.Name;
                            var metricName         = metricStreamConfig?.Name ?? instrument.Name;
                            var metricStreamName   = $"{meterName}.{metricName}";

                            if (!MeterProviderBuilderSdk.IsValidInstrumentName(metricName))
                            {
                                OpenTelemetrySdkEventSource.Log.MetricInstrumentIgnored(
                                    metricName,
                                    instrument.Meter.Name,
                                    "Metric name is invalid.",
                                    "The name must comply with the OpenTelemetry specification.");

                                continue;
                            }

                            if (this.metricStreamNames.Contains(metricStreamName))
                            {
                                // TODO: Log that instrument is ignored
                                // as the resulting Metric name is conflicting
                                // with existing name.
                                continue;
                            }

                            if (metricStreamConfig?.Aggregation == Aggregation.Drop)
                            {
                                // TODO: Log that instrument is ignored
                                // as user explicitly asked to drop it
                                // with View.
                                continue;
                            }

                            var index = ++this.metricIndex;
                            if (index >= MaxMetrics)
                            {
                                // TODO: Log that instrument is ignored
                                // as max number of Metrics have reached.
                            }
                            else
                            {
                                Metric   metric;
                                var      metricDescription     = metricStreamConfig?.Description ?? instrument.Description;
                                string[] tagKeysInteresting    = metricStreamConfig?.TagKeys;
                                double[] histogramBucketBounds = (metricStreamConfig is ExplicitBucketHistogramConfiguration histogramConfig &&
                                                                  histogramConfig.Boundaries != null) ? histogramConfig.Boundaries : null;
                                metric = new Metric(instrument, temporality, metricName, metricDescription, histogramBucketBounds, tagKeysInteresting);

                                this.metrics[index] = metric;
                                metrics.Add(metric);
                                this.metricStreamNames.Add(metricStreamName);
                            }
                        }

                        if (metrics.Count > 0)
                        {
                            listener.EnableMeasurementEvents(instrument, metrics);
                        }
                    }
                };

                // Everything double
                this.listener.SetMeasurementEventCallback <double>(this.MeasurementRecordedDouble);
                this.listener.SetMeasurementEventCallback <float>((instrument, value, tags, state) => this.MeasurementRecordedDouble(instrument, value, tags, state));

                // Everything long
                this.listener.SetMeasurementEventCallback <long>(this.MeasurementRecordedLong);
                this.listener.SetMeasurementEventCallback <int>((instrument, value, tags, state) => this.MeasurementRecordedLong(instrument, value, tags, state));
                this.listener.SetMeasurementEventCallback <short>((instrument, value, tags, state) => this.MeasurementRecordedLong(instrument, value, tags, state));
                this.listener.SetMeasurementEventCallback <byte>((instrument, value, tags, state) => this.MeasurementRecordedLong(instrument, value, tags, state));

                this.listener.MeasurementsCompleted = (instrument, state) => this.MeasurementsCompleted(instrument, state);
            }
            else
            {
                this.listener.InstrumentPublished = (instrument, listener) =>
                {
                    if (!shouldListenTo(instrument))
                    {
                        OpenTelemetrySdkEventSource.Log.MetricInstrumentIgnored(instrument.Name, instrument.Meter.Name, "Instrument belongs to a Meter not subscribed by the provider.", "Use AddMeter to add the Meter to the provider.");
                        return;
                    }

                    try
                    {
                        if (!MeterProviderBuilderSdk.IsValidInstrumentName(instrument.Name))
                        {
                            OpenTelemetrySdkEventSource.Log.MetricInstrumentIgnored(
                                instrument.Name,
                                instrument.Meter.Name,
                                "Instrument name is invalid.",
                                "The name must comply with the OpenTelemetry specification");

                            return;
                        }

                        var    meterName        = instrument.Meter.Name;
                        var    metricName       = instrument.Name;
                        var    metricStreamName = $"{meterName}.{metricName}";
                        Metric metric           = null;
                        lock (this.instrumentCreationLock)
                        {
                            if (this.metricStreamNames.Contains(metricStreamName))
                            {
                                OpenTelemetrySdkEventSource.Log.MetricInstrumentIgnored(metricName, instrument.Meter.Name, "Metric name conflicting with existing name.", "Either change the name of the instrument or change name using View.");
                                return;
                            }

                            var index = ++this.metricIndex;
                            if (index >= MaxMetrics)
                            {
                                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;
                            }
                            else
                            {
                                metric = new Metric(instrument, temporality, metricName, instrument.Description);
                                this.metrics[index] = metric;
                                this.metricStreamNames.Add(metricStreamName);
                            }
                        }

                        listener.EnableMeasurementEvents(instrument, metric);
                    }
                    catch (Exception)
                    {
                        OpenTelemetrySdkEventSource.Log.MetricInstrumentIgnored(instrument.Name, instrument.Meter.Name, "SDK internal error occurred.", "Contact SDK owners.");
                    }
                };

                // Everything double
                this.listener.SetMeasurementEventCallback <double>(this.MeasurementRecordedDoubleSingleStream);
                this.listener.SetMeasurementEventCallback <float>((instrument, value, tags, state) => this.MeasurementRecordedDoubleSingleStream(instrument, value, tags, state));

                // Everything long
                this.listener.SetMeasurementEventCallback <long>(this.MeasurementRecordedLongSingleStream);
                this.listener.SetMeasurementEventCallback <int>((instrument, value, tags, state) => this.MeasurementRecordedLongSingleStream(instrument, value, tags, state));
                this.listener.SetMeasurementEventCallback <short>((instrument, value, tags, state) => this.MeasurementRecordedLongSingleStream(instrument, value, tags, state));
                this.listener.SetMeasurementEventCallback <byte>((instrument, value, tags, state) => this.MeasurementRecordedLongSingleStream(instrument, value, tags, state));

                this.listener.MeasurementsCompleted = (instrument, state) => this.MeasurementsCompletedSingleStream(instrument, state);
            }

            this.listener.Start();
示例#17
0
 public AggregationTemporalityAttribute(AggregationTemporality supported)
     : this(supported, supported)
 {
 }