public void ExportOnlyWhenPointChanged(MetricReaderTemporalityPreference temporality) { using var meter = new Meter($"{Utils.GetCurrentMethodName()}.{temporality}"); var exportedItems = new List <Metric>(); using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddMeter(meter.Name) .AddInMemoryExporter(exportedItems, metricReaderOptions => { metricReaderOptions.TemporalityPreference = 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 == MetricReaderTemporalityPreference.Cumulative) { Assert.Single(exportedItems); } else { Assert.Empty(exportedItems); } }
public void SdkSupportsMultipleReaders(MetricReaderTemporalityPreference aggregationTemporality, bool hasViews) { var exportedItems1 = new List <Metric>(); var exportedItems2 = new List <Metric>(); 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()); int indexSum = 0; var valuesSum = new long[] { 1000, 1200, 1300, 1400 }; long GetSum() => valuesSum[indexSum++]; var observableCounter = meter.CreateObservableCounter("obs-counter", () => GetSum()); var meterProviderBuilder = Sdk.CreateMeterProviderBuilder() .AddMeter(meter.Name) .AddInMemoryExporter(exportedItems1, metricReaderOptions => { metricReaderOptions.TemporalityPreference = MetricReaderTemporalityPreference.Delta; }) .AddInMemoryExporter(exportedItems2, metricReaderOptions => { metricReaderOptions.TemporalityPreference = aggregationTemporality; }); if (hasViews) { meterProviderBuilder.AddView("counter", "renamedCounter"); meterProviderBuilder.AddView("gauge", "renamedGauge"); meterProviderBuilder.AddView("obs-counter", "renamedObservableCounter"); } using var meterProvider = meterProviderBuilder.Build(); counter.Add(10, new KeyValuePair <string, object>("key", "value")); meterProvider.ForceFlush(); Assert.Equal(3, exportedItems1.Count); Assert.Equal(3, exportedItems2.Count); if (hasViews) { Assert.Equal("renamedCounter", exportedItems1[0].Name); Assert.Equal("renamedCounter", exportedItems2[0].Name); Assert.Equal("renamedGauge", exportedItems1[1].Name); Assert.Equal("renamedGauge", exportedItems2[1].Name); Assert.Equal("renamedObservableCounter", exportedItems1[2].Name); Assert.Equal("renamedObservableCounter", exportedItems2[2].Name); } else { Assert.Equal("counter", exportedItems1[0].Name); Assert.Equal("counter", exportedItems2[0].Name); Assert.Equal("gauge", exportedItems1[1].Name); Assert.Equal("gauge", exportedItems2[1].Name); Assert.Equal("obs-counter", exportedItems1[2].Name); Assert.Equal("obs-counter", exportedItems2[2].Name); } // Check value exported for Counter AssertLongSumValueForMetric(exportedItems1[0], 10); AssertLongSumValueForMetric(exportedItems2[0], 10); // Check value exported for Gauge AssertLongSumValueForMetric(exportedItems1[1], 100); AssertLongSumValueForMetric(exportedItems2[1], 200); // Check value exported for ObservableCounter AssertLongSumValueForMetric(exportedItems1[2], 1000); if (aggregationTemporality == MetricReaderTemporalityPreference.Delta) { AssertLongSumValueForMetric(exportedItems2[2], 1200); } else { AssertLongSumValueForMetric(exportedItems2[2], 1200); } exportedItems1.Clear(); exportedItems2.Clear(); counter.Add(15, new KeyValuePair <string, object>("key", "value")); meterProvider.ForceFlush(); Assert.Equal(3, exportedItems1.Count); Assert.Equal(3, exportedItems2.Count); // Check value exported for Counter AssertLongSumValueForMetric(exportedItems1[0], 15); if (aggregationTemporality == MetricReaderTemporalityPreference.Delta) { AssertLongSumValueForMetric(exportedItems2[0], 15); } else { AssertLongSumValueForMetric(exportedItems2[0], 25); } // Check value exported for Gauge AssertLongSumValueForMetric(exportedItems1[1], 300); AssertLongSumValueForMetric(exportedItems2[1], 400); // Check value exported for ObservableCounter AssertLongSumValueForMetric(exportedItems1[2], 300); if (aggregationTemporality == MetricReaderTemporalityPreference.Delta) { AssertLongSumValueForMetric(exportedItems2[2], 200); } else { AssertLongSumValueForMetric(exportedItems2[2], 1400); } }
public void TestHistogramToOtlpMetric(string name, string description, string unit, long?longValue, double?doubleValue, MetricReaderTemporalityPreference aggregationTemporality, params object[] keysValues) { var metrics = new List <Metric>(); using var meter = new Meter(Utils.GetCurrentMethodName()); using var provider = Sdk.CreateMeterProviderBuilder() .AddMeter(meter.Name) .AddInMemoryExporter(metrics, metricReaderOptions => { metricReaderOptions.TemporalityPreference = aggregationTemporality; }) .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 scopeMetrics = resourceMetric.ScopeMetrics.Single(); var actual = scopeMetrics.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 == MetricReaderTemporalityPreference.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); }