diff --git a/src/OpenTelemetry.Exporter.InMemory/.publicApi/net462/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Exporter.InMemory/.publicApi/net462/PublicAPI.Unshipped.txt index ca21920895c..f6c31a64817 100644 --- a/src/OpenTelemetry.Exporter.InMemory/.publicApi/net462/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry.Exporter.InMemory/.publicApi/net462/PublicAPI.Unshipped.txt @@ -1,3 +1,15 @@ +OpenTelemetry.Exporter.InMemoryExporter.InMemoryExporter(System.Func, OpenTelemetry.ExportResult> exportFunc) -> void +OpenTelemetry.Metrics.ExportableMetricCopy +OpenTelemetry.Metrics.ExportableMetricCopy.Description.get -> string +OpenTelemetry.Metrics.ExportableMetricCopy.ExportableMetricCopy(OpenTelemetry.Metrics.Metric metric) -> void +OpenTelemetry.Metrics.ExportableMetricCopy.MeterName.get -> string +OpenTelemetry.Metrics.ExportableMetricCopy.MeterVersion.get -> string +OpenTelemetry.Metrics.ExportableMetricCopy.MetricPoints.get -> System.Collections.Generic.IReadOnlyList +OpenTelemetry.Metrics.ExportableMetricCopy.MetricType.get -> OpenTelemetry.Metrics.MetricType +OpenTelemetry.Metrics.ExportableMetricCopy.Name.get -> string +OpenTelemetry.Metrics.ExportableMetricCopy.Unit.get -> string OpenTelemetry.Metrics.InMemoryExporterMetricsExtensions -static OpenTelemetry.Metrics.InMemoryExporterMetricsExtensions.AddInMemoryExporter(this OpenTelemetry.Metrics.MeterProviderBuilder builder, System.Collections.Generic.ICollection exportedItems) -> OpenTelemetry.Metrics.MeterProviderBuilder -static OpenTelemetry.Metrics.InMemoryExporterMetricsExtensions.AddInMemoryExporter(this OpenTelemetry.Metrics.MeterProviderBuilder builder, System.Collections.Generic.ICollection exportedItems, System.Action configureMetricReader) -> OpenTelemetry.Metrics.MeterProviderBuilder \ No newline at end of file +static OpenTelemetry.Metrics.InMemoryExporterMetricsExtensions.AddInMemoryExporter(this OpenTelemetry.Metrics.MeterProviderBuilder builder, System.Collections.Generic.ICollection exportedItems) -> OpenTelemetry.Metrics.MeterProviderBuilder +static OpenTelemetry.Metrics.InMemoryExporterMetricsExtensions.AddInMemoryExporter(this OpenTelemetry.Metrics.MeterProviderBuilder builder, System.Collections.Generic.ICollection exportedItems, System.Action configureMetricReader) -> OpenTelemetry.Metrics.MeterProviderBuilder +static OpenTelemetry.Metrics.InMemoryExporterMetricsExtensions.AddInMemoryExporter(this OpenTelemetry.Metrics.MeterProviderBuilder builder, System.Func, OpenTelemetry.ExportResult> exportFunc) -> OpenTelemetry.Metrics.MeterProviderBuilder +static OpenTelemetry.Metrics.InMemoryExporterMetricsExtensions.AddInMemoryExporter(this OpenTelemetry.Metrics.MeterProviderBuilder builder, System.Func, OpenTelemetry.ExportResult> exportFunc, System.Action configureMetricReader) -> OpenTelemetry.Metrics.MeterProviderBuilder diff --git a/src/OpenTelemetry.Exporter.InMemory/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Exporter.InMemory/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt index ca21920895c..f6c31a64817 100644 --- a/src/OpenTelemetry.Exporter.InMemory/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry.Exporter.InMemory/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt @@ -1,3 +1,15 @@ +OpenTelemetry.Exporter.InMemoryExporter.InMemoryExporter(System.Func, OpenTelemetry.ExportResult> exportFunc) -> void +OpenTelemetry.Metrics.ExportableMetricCopy +OpenTelemetry.Metrics.ExportableMetricCopy.Description.get -> string +OpenTelemetry.Metrics.ExportableMetricCopy.ExportableMetricCopy(OpenTelemetry.Metrics.Metric metric) -> void +OpenTelemetry.Metrics.ExportableMetricCopy.MeterName.get -> string +OpenTelemetry.Metrics.ExportableMetricCopy.MeterVersion.get -> string +OpenTelemetry.Metrics.ExportableMetricCopy.MetricPoints.get -> System.Collections.Generic.IReadOnlyList +OpenTelemetry.Metrics.ExportableMetricCopy.MetricType.get -> OpenTelemetry.Metrics.MetricType +OpenTelemetry.Metrics.ExportableMetricCopy.Name.get -> string +OpenTelemetry.Metrics.ExportableMetricCopy.Unit.get -> string OpenTelemetry.Metrics.InMemoryExporterMetricsExtensions -static OpenTelemetry.Metrics.InMemoryExporterMetricsExtensions.AddInMemoryExporter(this OpenTelemetry.Metrics.MeterProviderBuilder builder, System.Collections.Generic.ICollection exportedItems) -> OpenTelemetry.Metrics.MeterProviderBuilder -static OpenTelemetry.Metrics.InMemoryExporterMetricsExtensions.AddInMemoryExporter(this OpenTelemetry.Metrics.MeterProviderBuilder builder, System.Collections.Generic.ICollection exportedItems, System.Action configureMetricReader) -> OpenTelemetry.Metrics.MeterProviderBuilder \ No newline at end of file +static OpenTelemetry.Metrics.InMemoryExporterMetricsExtensions.AddInMemoryExporter(this OpenTelemetry.Metrics.MeterProviderBuilder builder, System.Collections.Generic.ICollection exportedItems) -> OpenTelemetry.Metrics.MeterProviderBuilder +static OpenTelemetry.Metrics.InMemoryExporterMetricsExtensions.AddInMemoryExporter(this OpenTelemetry.Metrics.MeterProviderBuilder builder, System.Collections.Generic.ICollection exportedItems, System.Action configureMetricReader) -> OpenTelemetry.Metrics.MeterProviderBuilder +static OpenTelemetry.Metrics.InMemoryExporterMetricsExtensions.AddInMemoryExporter(this OpenTelemetry.Metrics.MeterProviderBuilder builder, System.Func, OpenTelemetry.ExportResult> exportFunc) -> OpenTelemetry.Metrics.MeterProviderBuilder +static OpenTelemetry.Metrics.InMemoryExporterMetricsExtensions.AddInMemoryExporter(this OpenTelemetry.Metrics.MeterProviderBuilder builder, System.Func, OpenTelemetry.ExportResult> exportFunc, System.Action configureMetricReader) -> OpenTelemetry.Metrics.MeterProviderBuilder diff --git a/src/OpenTelemetry.Exporter.InMemory/ExportableMetricCopy.cs b/src/OpenTelemetry.Exporter.InMemory/ExportableMetricCopy.cs new file mode 100644 index 00000000000..3397be30e26 --- /dev/null +++ b/src/OpenTelemetry.Exporter.InMemory/ExportableMetricCopy.cs @@ -0,0 +1,58 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System.Collections.Generic; + +namespace OpenTelemetry.Metrics +{ + /// + /// This class represents a selective copy of . + /// This contains the minimum fields and properties needed for most + /// unit testing scenarios. + /// + public class ExportableMetricCopy + { + private readonly MetricStreamIdentity instrumentIdentity; + + public ExportableMetricCopy(Metric metric) + { + this.instrumentIdentity = metric.InstrumentIdentity; + this.MetricType = metric.MetricType; + + List metricPoints = new(); + foreach (ref readonly var metricPoint in metric.GetMetricPoints()) + { + metricPoints.Add(metricPoint.Copy()); + } + + this.MetricPoints = metricPoints; + } + + public string Name => this.instrumentIdentity.InstrumentName; + + public string Description => this.instrumentIdentity.Description; + + public string Unit => this.instrumentIdentity.Unit; + + public string MeterName => this.instrumentIdentity.MeterName; + + public MetricType MetricType { get; } + + public string MeterVersion => this.instrumentIdentity.MeterVersion; + + public IReadOnlyList MetricPoints { get; } + } +} diff --git a/src/OpenTelemetry.Exporter.InMemory/InMemoryExporter.cs b/src/OpenTelemetry.Exporter.InMemory/InMemoryExporter.cs index d76995f8fb6..e382ff41ed1 100644 --- a/src/OpenTelemetry.Exporter.InMemory/InMemoryExporter.cs +++ b/src/OpenTelemetry.Exporter.InMemory/InMemoryExporter.cs @@ -14,6 +14,7 @@ // limitations under the License. // +using System; using System.Collections.Generic; namespace OpenTelemetry.Exporter @@ -22,13 +23,29 @@ public class InMemoryExporter : BaseExporter where T : class { private readonly ICollection exportedItems; + private readonly ExportDelegate onExport; public InMemoryExporter(ICollection exportedItems) { + if (typeof(T) == typeof(Metrics.Metric)) + { + throw new NotSupportedException("Exported Metrics are not trustworthy because they can continue to be updated after export. Recommend use ExportableMetricCopy."); + } + this.exportedItems = exportedItems; + this.onExport = this.DefaultExport; + } + + public InMemoryExporter(Func, ExportResult> exportFunc) + { + this.onExport = (in Batch batch) => exportFunc(batch); } - public override ExportResult Export(in Batch batch) + private delegate ExportResult ExportDelegate(in Batch batch); + + public override ExportResult Export(in Batch batch) => this.onExport(batch); + + private ExportResult DefaultExport(in Batch batch) { if (this.exportedItems == null) { diff --git a/src/OpenTelemetry.Exporter.InMemory/InMemoryExporterMetricsExtensions.cs b/src/OpenTelemetry.Exporter.InMemory/InMemoryExporterMetricsExtensions.cs index 9809b09552b..e257485fb6c 100644 --- a/src/OpenTelemetry.Exporter.InMemory/InMemoryExporterMetricsExtensions.cs +++ b/src/OpenTelemetry.Exporter.InMemory/InMemoryExporterMetricsExtensions.cs @@ -34,9 +34,39 @@ public static class InMemoryExporterMetricsExtensions /// Adds InMemory metric exporter to the using default options. /// /// builder to use. - /// Collection which will be populated with the exported MetricItem. + /// Collection which will be populated with the exported MetricItem represented as . /// The instance of to chain the calls. - public static MeterProviderBuilder AddInMemoryExporter(this MeterProviderBuilder builder, ICollection exportedItems) + public static MeterProviderBuilder AddInMemoryExporter( + this MeterProviderBuilder builder, + ICollection exportedItems) + { + return builder.AddInMemoryExporter(exportedItems: exportedItems, configureMetricReader: null); + } + + /// + /// Adds InMemory metric exporter to the using default options. + /// + /// builder to use. + /// A function which will replace . + /// The instance of to chain the calls. + public static MeterProviderBuilder AddInMemoryExporter( + this MeterProviderBuilder builder, + Func, ExportResult> exportFunc) + { + return builder.AddInMemoryExporter(exportFunc: exportFunc, configureMetricReader: null); + } + + /// + /// Adds InMemory metric exporter to the using default options. + /// + /// builder to use. + /// Collection which will be populated with the exported MetricItem represented as . + /// configuration options. + /// The instance of to chain the calls. + public static MeterProviderBuilder AddInMemoryExporter( + this MeterProviderBuilder builder, + ICollection exportedItems, + Action configureMetricReader) { Guard.ThrowIfNull(builder); Guard.ThrowIfNull(exportedItems); @@ -45,45 +75,76 @@ public static MeterProviderBuilder AddInMemoryExporter(this MeterProviderBuilder { return deferredMeterProviderBuilder.Configure((sp, builder) => { - AddInMemoryExporter(builder, exportedItems, sp.GetOptions(), null); + AddInMemoryExporter(builder, exportedItems, sp.GetOptions(), configureMetricReader); }); } - return AddInMemoryExporter(builder, exportedItems, new MetricReaderOptions(), null); + return AddInMemoryExporter(builder, exportedItems, new MetricReaderOptions(), configureMetricReader); } /// /// Adds InMemory metric exporter to the using default options. /// /// builder to use. - /// Collection which will be populated with the exported MetricItem. + /// A function which will replace . /// configuration options. /// The instance of to chain the calls. - public static MeterProviderBuilder AddInMemoryExporter(this MeterProviderBuilder builder, ICollection exportedItems, Action configureMetricReader) + public static MeterProviderBuilder AddInMemoryExporter( + this MeterProviderBuilder builder, + Func, ExportResult> exportFunc, + Action configureMetricReader) { Guard.ThrowIfNull(builder); - Guard.ThrowIfNull(exportedItems); + Guard.ThrowIfNull(exportFunc); if (builder is IDeferredMeterProviderBuilder deferredMeterProviderBuilder) { return deferredMeterProviderBuilder.Configure((sp, builder) => { - AddInMemoryExporter(builder, exportedItems, sp.GetOptions(), configureMetricReader); + AddInMemoryExporter(builder, exportFunc, sp.GetOptions(), configureMetricReader); }); } - return AddInMemoryExporter(builder, exportedItems, new MetricReaderOptions(), configureMetricReader); + return AddInMemoryExporter(builder, exportFunc, new MetricReaderOptions(), configureMetricReader); + } + + private static MeterProviderBuilder AddInMemoryExporter( + MeterProviderBuilder builder, + ICollection exportedItems, + MetricReaderOptions metricReaderOptions, + Action configureMetricReader) + { + configureMetricReader?.Invoke(metricReaderOptions); + + var metricExporter = new InMemoryExporter( + exportFunc: metricBatch => + { + foreach (var metric in metricBatch) + { + exportedItems.Add(new ExportableMetricCopy(metric)); + } + + return ExportResult.Success; + }); + + var metricReader = PeriodicExportingMetricReaderHelper.CreatePeriodicExportingMetricReader( + metricExporter, + metricReaderOptions, + DefaultExportIntervalMilliseconds, + DefaultExportTimeoutMilliseconds); + + return builder.AddReader(metricReader); } private static MeterProviderBuilder AddInMemoryExporter( MeterProviderBuilder builder, - ICollection exportedItems, + Func, ExportResult> exportFunc, MetricReaderOptions metricReaderOptions, Action configureMetricReader) { configureMetricReader?.Invoke(metricReaderOptions); - var metricExporter = new InMemoryExporter(exportedItems); + var metricExporter = new InMemoryExporter(exportFunc); var metricReader = PeriodicExportingMetricReaderHelper.CreatePeriodicExportingMetricReader( metricExporter, diff --git a/src/OpenTelemetry.Exporter.InMemory/OpenTelemetry.Exporter.InMemory.csproj b/src/OpenTelemetry.Exporter.InMemory/OpenTelemetry.Exporter.InMemory.csproj index bdb3c634cd8..546d54e153f 100644 --- a/src/OpenTelemetry.Exporter.InMemory/OpenTelemetry.Exporter.InMemory.csproj +++ b/src/OpenTelemetry.Exporter.InMemory/OpenTelemetry.Exporter.InMemory.csproj @@ -27,8 +27,6 @@ - - diff --git a/src/OpenTelemetry/AssemblyInfo.cs b/src/OpenTelemetry/AssemblyInfo.cs index 5b17a4357a6..545b35a13e8 100644 --- a/src/OpenTelemetry/AssemblyInfo.cs +++ b/src/OpenTelemetry/AssemblyInfo.cs @@ -17,6 +17,7 @@ using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("OpenTelemetry.Tests" + AssemblyInfo.PublicKey)] +[assembly: InternalsVisibleTo("OpenTelemetry.Exporter.InMemory" + AssemblyInfo.PublicKey)] [assembly: InternalsVisibleTo("OpenTelemetry.Exporter.Prometheus" + AssemblyInfo.PublicKey)] [assembly: InternalsVisibleTo("OpenTelemetry.Exporter.Prometheus.Tests" + AssemblyInfo.PublicKey)] [assembly: InternalsVisibleTo("OpenTelemetry.Extensions.Hosting.Tests" + AssemblyInfo.PublicKey)] diff --git a/src/OpenTelemetry/Metrics/HistogramBuckets.cs b/src/OpenTelemetry/Metrics/HistogramBuckets.cs index 626779d4901..42db69f9972 100644 --- a/src/OpenTelemetry/Metrics/HistogramBuckets.cs +++ b/src/OpenTelemetry/Metrics/HistogramBuckets.cs @@ -52,6 +52,7 @@ internal HistogramBuckets Copy() HistogramBuckets copy = new HistogramBuckets(this.ExplicitBounds); Array.Copy(this.SnapshotBucketCounts, copy.SnapshotBucketCounts, this.SnapshotBucketCounts.Length); + Array.Copy(this.RunningBucketCounts, copy.RunningBucketCounts, this.RunningBucketCounts.Length); copy.SnapshotSum = this.SnapshotSum; return copy; diff --git a/test/Benchmarks/Benchmarks.csproj b/test/Benchmarks/Benchmarks.csproj index 12e759d9f1c..f0c69683ad6 100644 --- a/test/Benchmarks/Benchmarks.csproj +++ b/test/Benchmarks/Benchmarks.csproj @@ -32,4 +32,8 @@ + + + + diff --git a/test/Benchmarks/Metrics/HistogramBenchmarks.cs b/test/Benchmarks/Metrics/HistogramBenchmarks.cs index 5511b82a0eb..f3756263d71 100644 --- a/test/Benchmarks/Metrics/HistogramBenchmarks.cs +++ b/test/Benchmarks/Metrics/HistogramBenchmarks.cs @@ -83,7 +83,7 @@ public void Setup() this.bounds[i] = i * MaxValue / this.bounds.Length; } - var exportedItems = new List(); + var exportedItems = new List(); this.provider = Sdk.CreateMeterProviderBuilder() .AddMeter(this.meter.Name) diff --git a/test/Benchmarks/Metrics/MetricsBenchmarks.cs b/test/Benchmarks/Metrics/MetricsBenchmarks.cs index e9fd3f6d4fc..b07cb274de0 100644 --- a/test/Benchmarks/Metrics/MetricsBenchmarks.cs +++ b/test/Benchmarks/Metrics/MetricsBenchmarks.cs @@ -68,7 +68,7 @@ public void Setup() { this.meter = new Meter(Utils.GetCurrentMethodName()); - var exportedItems = new List(); + var exportedItems = new List(); this.provider = Sdk.CreateMeterProviderBuilder() .AddMeter(this.meter.Name) // All instruments from this meter are enabled. .AddInMemoryExporter(exportedItems, metricReaderOptions => diff --git a/test/Benchmarks/Metrics/MetricsViewBenchmarks.cs b/test/Benchmarks/Metrics/MetricsViewBenchmarks.cs index ffea2a2033d..cc602e5ab71 100644 --- a/test/Benchmarks/Metrics/MetricsViewBenchmarks.cs +++ b/test/Benchmarks/Metrics/MetricsViewBenchmarks.cs @@ -45,7 +45,7 @@ public class MetricsViewBenchmarks private static readonly ThreadLocal ThreadLocalRandom = new(() => new Random()); private static readonly string[] DimensionValues = new string[] { "DimVal1", "DimVal2", "DimVal3", "DimVal4", "DimVal5", "DimVal6", "DimVal7", "DimVal8", "DimVal9", "DimVal10" }; private static readonly int DimensionsValuesLength = DimensionValues.Length; - private List metrics; + private List metrics; private Counter counter; private MeterProvider provider; private Meter meter; @@ -81,7 +81,7 @@ public void Setup() { this.meter = new Meter(Utils.GetCurrentMethodName()); this.counter = this.meter.CreateCounter("counter"); - this.metrics = new List(); + this.metrics = new List(); if (this.ViewConfig == ViewConfiguration.NoView) { diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests.csproj b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests.csproj index bc0829061d4..2c8ce4e35d9 100644 --- a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests.csproj +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests.csproj @@ -30,6 +30,7 @@ + diff --git a/test/OpenTelemetry.Exporter.Prometheus.Tests/OpenTelemetry.Exporter.Prometheus.Tests.csproj b/test/OpenTelemetry.Exporter.Prometheus.Tests/OpenTelemetry.Exporter.Prometheus.Tests.csproj index e3ff74abad7..00777632edb 100644 --- a/test/OpenTelemetry.Exporter.Prometheus.Tests/OpenTelemetry.Exporter.Prometheus.Tests.csproj +++ b/test/OpenTelemetry.Exporter.Prometheus.Tests/OpenTelemetry.Exporter.Prometheus.Tests.csproj @@ -34,6 +34,7 @@ + diff --git a/test/OpenTelemetry.Instrumentation.AspNet.Tests/HttpInMetricsListenerTests.cs b/test/OpenTelemetry.Instrumentation.AspNet.Tests/HttpInMetricsListenerTests.cs index b9fbbbeebeb..64cc67648b0 100644 --- a/test/OpenTelemetry.Instrumentation.AspNet.Tests/HttpInMetricsListenerTests.cs +++ b/test/OpenTelemetry.Instrumentation.AspNet.Tests/HttpInMetricsListenerTests.cs @@ -49,7 +49,7 @@ public void HttpDurationMetricIsEmitted() }) .Build(); - var exportedItems = new List(); + var exportedItems = new List(); using var meterprovider = Sdk.CreateMeterProviderBuilder() .AddAspNetInstrumentation() .AddInMemoryExporter(exportedItems) @@ -61,7 +61,7 @@ public void HttpDurationMetricIsEmitted() meterprovider.ForceFlush(); var metricPoints = new List(); - foreach (var p in exportedItems[0].GetMetricPoints()) + foreach (var p in exportedItems[0].MetricPoints) { metricPoints.Add(p); } diff --git a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/MetricTests.cs b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/MetricTests.cs index 92512230663..10969ebde1c 100644 --- a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/MetricTests.cs +++ b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/MetricTests.cs @@ -52,7 +52,7 @@ public void AddAspNetCoreInstrumentation_BadArgs() [Fact] public async Task RequestMetricIsCaptured() { - var metricItems = new List(); + var metricItems = new List(); this.meterProvider = Sdk.CreateMeterProviderBuilder() .AddAspNetCoreInstrumentation() @@ -82,7 +82,7 @@ public async Task RequestMetricIsCaptured() Assert.NotNull(metric); Assert.True(metric.MetricType == MetricType.Histogram); var metricPoints = new List(); - foreach (var p in metric.GetMetricPoints()) + foreach (var p in metric.MetricPoints) { metricPoints.Add(p); } diff --git a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.netcore31.cs b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.netcore31.cs index 4cf0ff75a49..67bb1ef6027 100644 --- a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.netcore31.cs +++ b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.netcore31.cs @@ -54,7 +54,7 @@ public async Task HttpOutCallsAreCollectedSuccessfullyAsync(HttpTestData.HttpOut var processor = new Mock>(); tc.Url = HttpTestData.NormalizeValues(tc.Url, host, port); - var metrics = new List(); + var metrics = new List(); var meterProvider = Sdk.CreateMeterProviderBuilder() .AddHttpClientInstrumentation() @@ -146,7 +146,7 @@ public async Task HttpOutCallsAreCollectedSuccessfullyAsync(HttpTestData.HttpOut Assert.True(metric.MetricType == MetricType.Histogram); var metricPoints = new List(); - foreach (var p in metric.GetMetricPoints()) + foreach (var p in metric.MetricPoints) { metricPoints.Add(p); } diff --git a/test/OpenTelemetry.Tests/Metrics/InMemoryExporterTests.cs b/test/OpenTelemetry.Tests/Metrics/InMemoryExporterTests.cs index c5337ef49a6..4902e978032 100644 --- a/test/OpenTelemetry.Tests/Metrics/InMemoryExporterTests.cs +++ b/test/OpenTelemetry.Tests/Metrics/InMemoryExporterTests.cs @@ -14,8 +14,11 @@ // limitations under the License. // +using System; using System.Collections.Generic; using System.Diagnostics.Metrics; + +using OpenTelemetry.Exporter; using OpenTelemetry.Tests; using Xunit; @@ -23,10 +26,10 @@ namespace OpenTelemetry.Metrics.Tests { public class InMemoryExporterTests { - [Fact(Skip = "To be run after https://github.com/open-telemetry/opentelemetry-dotnet/issues/2361 is fixed")] + [Fact] public void InMemoryExporterShouldDeepCopyMetricPoints() { - var exportedItems = new List(); + var exportedItems = new List(); using var meter = new Meter(Utils.GetCurrentMethodName()); using var meterProvider = Sdk.CreateMeterProviderBuilder() @@ -45,9 +48,9 @@ public void InMemoryExporterShouldDeepCopyMetricPoints() meterProvider.ForceFlush(); var metric = exportedItems[0]; // Only one Metric object is added to the collection at this point - var metricPointsEnumerator = metric.GetMetricPoints().GetEnumerator(); + var metricPointsEnumerator = metric.MetricPoints.GetEnumerator(); Assert.True(metricPointsEnumerator.MoveNext()); // One MetricPoint is emitted for the Metric - ref readonly var metricPointForFirstExport = ref metricPointsEnumerator.Current; + var metricPointForFirstExport = metricPointsEnumerator.Current; Assert.Equal(10, metricPointForFirstExport.GetSumLong()); // Emit 25 for the MetricPoint with a single key-vaue pair: ("tag1", "value1") @@ -56,7 +59,7 @@ public void InMemoryExporterShouldDeepCopyMetricPoints() meterProvider.ForceFlush(); metric = exportedItems[1]; // Second Metric object is added to the collection at this point - metricPointsEnumerator = metric.GetMetricPoints().GetEnumerator(); + metricPointsEnumerator = metric.MetricPoints.GetEnumerator(); Assert.True(metricPointsEnumerator.MoveNext()); // One MetricPoint is emitted for the Metric var metricPointForSecondExport = metricPointsEnumerator.Current; Assert.Equal(25, metricPointForSecondExport.GetSumLong()); @@ -64,5 +67,13 @@ public void InMemoryExporterShouldDeepCopyMetricPoints() // MetricPoint.LongValue for the first exporter metric should still be 10 Assert.Equal(10, metricPointForFirstExport.GetSumLong()); } + + [Fact] + public void CannotCreateInMemoryExporterWithMetric() + { + // Exported Metrics are not trustworthy because they can continue to be updated after export. + var metrics = new List(); + Assert.Throws(() => new InMemoryExporter(metrics)); + } } } diff --git a/test/OpenTelemetry.Tests/Metrics/MemoryEfficiencyTests.cs b/test/OpenTelemetry.Tests/Metrics/MemoryEfficiencyTests.cs index 451ec5aba80..27e4e6c2f21 100644 --- a/test/OpenTelemetry.Tests/Metrics/MemoryEfficiencyTests.cs +++ b/test/OpenTelemetry.Tests/Metrics/MemoryEfficiencyTests.cs @@ -30,7 +30,7 @@ public void ExportOnlyWhenPointChanged(MetricReaderTemporalityPreference tempora { using var meter = new Meter($"{Utils.GetCurrentMethodName()}.{temporality}"); - var exportedItems = new List(); + var exportedItems = new List(); using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddMeter(meter.Name) diff --git a/test/OpenTelemetry.Tests/Metrics/MeterProviderTests.cs b/test/OpenTelemetry.Tests/Metrics/MeterProviderTests.cs index aa034bdd406..a1315696c97 100644 --- a/test/OpenTelemetry.Tests/Metrics/MeterProviderTests.cs +++ b/test/OpenTelemetry.Tests/Metrics/MeterProviderTests.cs @@ -25,7 +25,7 @@ public class MeterProviderTests [Fact] public void MeterProviderFindExporterTest() { - var exportedItems = new List(); + var exportedItems = new List(); using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddInMemoryExporter(exportedItems) .Build(); diff --git a/test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs b/test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs index 3b70cf5f022..12519ab2e42 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs @@ -46,7 +46,7 @@ public MetricApiTest(ITestOutputHelper output) public void ObserverCallbackTest() { using var meter = new Meter(Utils.GetCurrentMethodName()); - var exportedItems = new List(); + var exportedItems = new List(); using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddMeter(meter.Name) .AddInMemoryExporter(exportedItems) @@ -60,7 +60,7 @@ public void ObserverCallbackTest() var metric = exportedItems[0]; Assert.Equal("myGauge", metric.Name); List metricPoints = new List(); - foreach (ref readonly var mp in metric.GetMetricPoints()) + foreach (var mp in metric.MetricPoints) { metricPoints.Add(mp); } @@ -75,7 +75,7 @@ public void ObserverCallbackTest() public void ObserverCallbackExceptionTest() { using var meter = new Meter(Utils.GetCurrentMethodName()); - var exportedItems = new List(); + var exportedItems = new List(); using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddMeter(meter.Name) .AddInMemoryExporter(exportedItems) @@ -90,7 +90,7 @@ public void ObserverCallbackExceptionTest() var metric = exportedItems[0]; Assert.Equal("myGauge", metric.Name); List metricPoints = new List(); - foreach (ref readonly var mp in metric.GetMetricPoints()) + foreach (var mp in metric.MetricPoints) { metricPoints.Add(mp); } @@ -107,7 +107,7 @@ public void ObserverCallbackExceptionTest() [InlineData(null)] public void MetricUnitIsExportedCorrectly(string unit) { - var exportedItems = new List(); + var exportedItems = new List(); using var meter = new Meter($"{Utils.GetCurrentMethodName()}"); var meterProviderBuilder = Sdk.CreateMeterProviderBuilder() @@ -130,7 +130,7 @@ public void MetricUnitIsExportedCorrectly(string unit) [InlineData(null)] public void MetricDescriptionIsExportedCorrectly(string description) { - var exportedItems = new List(); + var exportedItems = new List(); using var meter = new Meter($"{Utils.GetCurrentMethodName()}"); var meterProviderBuilder = Sdk.CreateMeterProviderBuilder() @@ -150,7 +150,7 @@ public void MetricDescriptionIsExportedCorrectly(string description) [Fact] public void DuplicateInstrumentRegistration_NoViews_IdenticalInstruments() { - var exportedItems = new List(); + var exportedItems = new List(); using var meter = new Meter($"{Utils.GetCurrentMethodName()}"); var meterProviderBuilder = Sdk.CreateMeterProviderBuilder() @@ -171,7 +171,7 @@ public void DuplicateInstrumentRegistration_NoViews_IdenticalInstruments() var metric = exportedItems[0]; Assert.Equal("instrumentName", metric.Name); List metricPoints = new List(); - foreach (ref readonly var mp in metric.GetMetricPoints()) + foreach (var mp in metric.MetricPoints) { metricPoints.Add(mp); } @@ -184,7 +184,7 @@ public void DuplicateInstrumentRegistration_NoViews_IdenticalInstruments() [Fact] public void DuplicateInstrumentRegistration_NoViews_DuplicateInstruments_DifferentDescription() { - var exportedItems = new List(); + var exportedItems = new List(); using var meter = new Meter($"{Utils.GetCurrentMethodName()}"); var meterProviderBuilder = Sdk.CreateMeterProviderBuilder() @@ -208,7 +208,7 @@ public void DuplicateInstrumentRegistration_NoViews_DuplicateInstruments_Differe Assert.Equal("instrumentDescription2", metric2.Description); List metric1MetricPoints = new List(); - foreach (ref readonly var mp in metric1.GetMetricPoints()) + foreach (var mp in metric1.MetricPoints) { metric1MetricPoints.Add(mp); } @@ -218,7 +218,7 @@ public void DuplicateInstrumentRegistration_NoViews_DuplicateInstruments_Differe Assert.Equal(10, metricPoint1.GetSumLong()); List metric2MetricPoints = new List(); - foreach (ref readonly var mp in metric2.GetMetricPoints()) + foreach (var mp in metric2.MetricPoints) { metric2MetricPoints.Add(mp); } @@ -231,7 +231,7 @@ public void DuplicateInstrumentRegistration_NoViews_DuplicateInstruments_Differe [Fact] public void DuplicateInstrumentRegistration_NoViews_DuplicateInstruments_DifferentUnit() { - var exportedItems = new List(); + var exportedItems = new List(); using var meter = new Meter($"{Utils.GetCurrentMethodName()}"); var meterProviderBuilder = Sdk.CreateMeterProviderBuilder() @@ -255,7 +255,7 @@ public void DuplicateInstrumentRegistration_NoViews_DuplicateInstruments_Differe Assert.Equal("instrumentUnit2", metric2.Unit); List metric1MetricPoints = new List(); - foreach (ref readonly var mp in metric1.GetMetricPoints()) + foreach (var mp in metric1.MetricPoints) { metric1MetricPoints.Add(mp); } @@ -265,7 +265,7 @@ public void DuplicateInstrumentRegistration_NoViews_DuplicateInstruments_Differe Assert.Equal(10, metricPoint1.GetSumLong()); List metric2MetricPoints = new List(); - foreach (ref readonly var mp in metric2.GetMetricPoints()) + foreach (var mp in metric2.MetricPoints) { metric2MetricPoints.Add(mp); } @@ -278,7 +278,7 @@ public void DuplicateInstrumentRegistration_NoViews_DuplicateInstruments_Differe [Fact] public void DuplicateInstrumentRegistration_NoViews_DuplicateInstruments_DifferentDataType() { - var exportedItems = new List(); + var exportedItems = new List(); using var meter = new Meter($"{Utils.GetCurrentMethodName()}"); var meterProviderBuilder = Sdk.CreateMeterProviderBuilder() @@ -300,7 +300,7 @@ public void DuplicateInstrumentRegistration_NoViews_DuplicateInstruments_Differe var metric2 = exportedItems[1]; List metric1MetricPoints = new List(); - foreach (ref readonly var mp in metric1.GetMetricPoints()) + foreach (var mp in metric1.MetricPoints) { metric1MetricPoints.Add(mp); } @@ -310,7 +310,7 @@ public void DuplicateInstrumentRegistration_NoViews_DuplicateInstruments_Differe Assert.Equal(10, metricPoint1.GetSumLong()); List metric2MetricPoints = new List(); - foreach (ref readonly var mp in metric2.GetMetricPoints()) + foreach (var mp in metric2.MetricPoints) { metric2MetricPoints.Add(mp); } @@ -323,7 +323,7 @@ public void DuplicateInstrumentRegistration_NoViews_DuplicateInstruments_Differe [Fact] public void DuplicateInstrumentRegistration_NoViews_DuplicateInstruments_DifferentInstrumentType() { - var exportedItems = new List(); + var exportedItems = new List(); using var meter = new Meter($"{Utils.GetCurrentMethodName()}"); var meterProviderBuilder = Sdk.CreateMeterProviderBuilder() @@ -345,7 +345,7 @@ public void DuplicateInstrumentRegistration_NoViews_DuplicateInstruments_Differe var metric2 = exportedItems[1]; List metric1MetricPoints = new List(); - foreach (ref readonly var mp in metric1.GetMetricPoints()) + foreach (var mp in metric1.MetricPoints) { metric1MetricPoints.Add(mp); } @@ -355,7 +355,7 @@ public void DuplicateInstrumentRegistration_NoViews_DuplicateInstruments_Differe Assert.Equal(10, metricPoint1.GetSumLong()); List metric2MetricPoints = new List(); - foreach (ref readonly var mp in metric2.GetMetricPoints()) + foreach (var mp in metric2.MetricPoints) { metric2MetricPoints.Add(mp); } @@ -369,7 +369,7 @@ public void DuplicateInstrumentRegistration_NoViews_DuplicateInstruments_Differe [Fact] public void DuplicateInstrumentNamesFromDifferentMetersWithSameNameDifferentVersion() { - var exportedItems = new List(); + var exportedItems = new List(); using var meter1 = new Meter($"{Utils.GetCurrentMethodName()}", "1.0"); using var meter2 = new Meter($"{Utils.GetCurrentMethodName()}", "2.0"); @@ -402,7 +402,7 @@ public void DuplicateInstrumentNamesFromDifferentMetersWithSameNameDifferentVers [InlineData(MetricReaderTemporalityPreference.Delta, false)] public void DuplicateInstrumentNamesFromDifferentMetersAreAllowed(MetricReaderTemporalityPreference temporality, bool hasView) { - var exportedItems = new List(); + var exportedItems = new List(); using var meter1 = new Meter($"{Utils.GetCurrentMethodName()}.1.{temporality}"); using var meter2 = new Meter($"{Utils.GetCurrentMethodName()}.2.{temporality}"); @@ -449,7 +449,7 @@ public void MeterSourcesWildcardSupportMatchTest(bool hasView) using var meter5 = new Meter("GhiCompany.qweProduct.ComponentN"); using var meter6 = new Meter("SomeCompany.SomeProduct.SomeComponent"); - var exportedItems = new List(); + var exportedItems = new List(); var meterProviderBuilder = Sdk.CreateMeterProviderBuilder() .AddMeter("AbcCompany.XyzProduct.Component?") .AddMeter("DefCompany.*.ComponentC") @@ -498,7 +498,7 @@ public void MeterSourcesWildcardSupportNegativeTestNoMeterAdded(bool hasView) using var meter1 = new Meter($"AbcCompany.XyzProduct.ComponentA.{hasView}"); using var meter2 = new Meter($"abcCompany.xYzProduct.componentC.{hasView}"); - var exportedItems = new List(); + var exportedItems = new List(); var meterProviderBuilder = Sdk.CreateMeterProviderBuilder() .AddInMemoryExporter(exportedItems); @@ -524,7 +524,7 @@ public void CounterAggregationTest(bool exportDelta) { DateTime testStartTime = DateTime.UtcNow; - var exportedItems = new List(); + var exportedItems = new List(); using var meter = new Meter($"{Utils.GetCurrentMethodName()}.{exportDelta}"); var counterLong = meter.CreateCounter("mycounter"); @@ -616,7 +616,7 @@ public void CounterAggregationTest(bool exportDelta) [InlineData(false)] public void ObservableCounterAggregationTest(bool exportDelta) { - var exportedItems = new List(); + var exportedItems = new List(); using var meter = new Meter($"{Utils.GetCurrentMethodName()}.{exportDelta}"); int i = 1; @@ -672,7 +672,7 @@ public void ObservableCounterAggregationTest(bool exportDelta) [InlineData(false)] public void ObservableCounterWithTagsAggregationTest(bool exportDelta) { - var exportedItems = new List(); + var exportedItems = new List(); var tags1 = new List> { new("statusCode", 200), @@ -718,7 +718,7 @@ public void ObservableCounterWithTagsAggregationTest(bool exportDelta) var metric = exportedItems[0]; Assert.Equal("observable-counter", metric.Name); List metricPoints = new List(); - foreach (ref readonly var mp in metric.GetMetricPoints()) + foreach (var mp in metric.MetricPoints) { metricPoints.Add(mp); } @@ -744,7 +744,7 @@ public void ObservableCounterWithTagsAggregationTest(bool exportDelta) metric = exportedItems[0]; Assert.Equal("observable-counter", metric.Name); metricPoints.Clear(); - foreach (ref readonly var mp in metric.GetMetricPoints()) + foreach (var mp in metric.MetricPoints) { metricPoints.Add(mp); } @@ -769,7 +769,7 @@ public void ObservableCounterWithTagsAggregationTest(bool exportDelta) [InlineData(false)] public void ObservableCounterSpatialAggregationTest(bool exportDelta) { - var exportedItems = new List(); + var exportedItems = new List(); var tags1 = new List> { new("statusCode", 200), @@ -815,7 +815,7 @@ public void ObservableCounterSpatialAggregationTest(bool exportDelta) var metric = exportedItems[0]; Assert.Equal("requestCount", metric.Name); List metricPoints = new List(); - foreach (ref readonly var mp in metric.GetMetricPoints()) + foreach (var mp in metric.MetricPoints) { metricPoints.Add(mp); } @@ -836,7 +836,7 @@ public void ObservableCounterSpatialAggregationTest(bool exportDelta) [InlineData(false)] public void DimensionsAreOrderInsensitiveWithSortedKeysFirst(bool exportDelta) { - var exportedItems = new List(); + var exportedItems = new List(); using var meter = new Meter($"{Utils.GetCurrentMethodName()}.{exportDelta}"); var counterLong = meter.CreateCounter("Counter"); @@ -927,7 +927,7 @@ public void DimensionsAreOrderInsensitiveWithSortedKeysFirst(bool exportDelta) [InlineData(false)] public void DimensionsAreOrderInsensitiveWithUnsortedKeysFirst(bool exportDelta) { - var exportedItems = new List(); + var exportedItems = new List(); using var meter = new Meter($"{Utils.GetCurrentMethodName()}.{exportDelta}"); var counterLong = meter.CreateCounter("Counter"); @@ -1018,7 +1018,7 @@ public void DimensionsAreOrderInsensitiveWithUnsortedKeysFirst(bool exportDelta) [InlineData(MetricReaderTemporalityPreference.Delta)] public void TestInstrumentDisposal(MetricReaderTemporalityPreference temporality) { - var exportedItems = new List(); + var exportedItems = new List(); var meter1 = new Meter($"{Utils.GetCurrentMethodName()}.{temporality}.1"); var meter2 = new Meter($"{Utils.GetCurrentMethodName()}.{temporality}.2"); @@ -1073,7 +1073,7 @@ public void TestInstrumentDisposal(MetricReaderTemporalityPreference temporality [InlineData(MetricReaderTemporalityPreference.Delta)] public void TestMetricPointCap(MetricReaderTemporalityPreference temporality) { - var exportedItems = new List(); + var exportedItems = new List(); int MetricPointCount() { @@ -1081,7 +1081,7 @@ int MetricPointCount() foreach (var metric in exportedItems) { - foreach (ref readonly var metricPoint in metric.GetMetricPoints()) + foreach (var mp in metric.MetricPoints) { count++; } @@ -1184,7 +1184,7 @@ public void MultithreadedDoubleHistogramTest() [MemberData(nameof(MetricTestData.InvalidInstrumentNames), MemberType = typeof(MetricTestData))] public void InstrumentWithInvalidNameIsIgnoredTest(string instrumentName) { - var exportedItems = new List(); + var exportedItems = new List(); using var meter = new Meter("InstrumentWithInvalidNameIsIgnoredTest"); @@ -1206,7 +1206,7 @@ public void InstrumentWithInvalidNameIsIgnoredTest(string instrumentName) [MemberData(nameof(MetricTestData.ValidInstrumentNames), MemberType = typeof(MetricTestData))] public void InstrumentWithValidNameIsExportedTest(string name) { - var exportedItems = new List(); + var exportedItems = new List(); using var meter = new Meter("InstrumentValidNameIsExportedTest"); @@ -1251,7 +1251,7 @@ public void SetupSdkProviderWithNoReader(bool hasViews) public void UnsupportedMetricInstrument() { using var meter = new Meter($"{Utils.GetCurrentMethodName()}"); - var exportedItems = new List(); + var exportedItems = new List(); using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddMeter(meter.Name) .AddInMemoryExporter(exportedItems) @@ -1329,7 +1329,7 @@ private static void HistogramUpdateThread(object obj) private void MultithreadedCounterTest(T deltaValueUpdatedByEachCall) where T : struct, IComparable { - var metricItems = new List(); + var metricItems = new List(); using var meter = new Meter($"{Utils.GetCurrentMethodName()}.{typeof(T).Name}.{deltaValueUpdatedByEachCall}"); using var meterProvider = Sdk.CreateMeterProviderBuilder() @@ -1384,8 +1384,16 @@ private void MultithreadedHistogramTest(long[] expected, T[] values) { var bucketCounts = new long[11]; - var metrics = new List(); - var metricReader = new BaseExportingMetricReader(new InMemoryExporter(metrics)); + var metrics = new List(); + var metricReader = new BaseExportingMetricReader(new InMemoryExporter(exportFunc: batch => + { + foreach (var metric in batch) + { + metrics.Add(new ExportableMetricCopy(metric)); + } + + return ExportResult.Success; + })); using var meter = new Meter($"{Utils.GetCurrentMethodName()}.{typeof(T).Name}"); using var meterProvider = Sdk.CreateMeterProviderBuilder() @@ -1423,7 +1431,7 @@ private void MultithreadedHistogramTest(long[] expected, T[] values) foreach (var metric in metrics) { - foreach (var metricPoint in metric.GetMetricPoints()) + foreach (var metricPoint in metric.MetricPoints) { bucketCounts = metricPoint.GetHistogramBuckets().RunningBucketCounts; } diff --git a/test/OpenTelemetry.Tests/Metrics/MetricPointTests.cs b/test/OpenTelemetry.Tests/Metrics/MetricPointTests.cs index 211df37e7cf..fc514cf00ab 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricPointTests.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricPointTests.cs @@ -26,7 +26,7 @@ public sealed class MetricPointTests : IDisposable { private readonly Meter meter; private readonly MeterProvider provider; - private readonly Metric metric; + private readonly ExportableMetricCopy metric; private readonly Histogram histogram; private readonly double[] bounds; private MetricPoint metricPoint; @@ -43,7 +43,7 @@ public MetricPointTests() this.bounds[i] = i * 1000 / this.bounds.Length; } - var exportedItems = new List(); + var exportedItems = new List(); this.provider = Sdk.CreateMeterProviderBuilder() .AddMeter(this.meter.Name) @@ -56,7 +56,7 @@ public MetricPointTests() this.provider.ForceFlush(); this.metric = exportedItems[0]; - var metricPointsEnumerator = this.metric.GetMetricPoints().GetEnumerator(); + var metricPointsEnumerator = this.metric.MetricPoints.GetEnumerator(); metricPointsEnumerator.MoveNext(); this.metricPoint = metricPointsEnumerator.Current; } diff --git a/test/OpenTelemetry.Tests/Metrics/MetricTestsBase.cs b/test/OpenTelemetry.Tests/Metrics/MetricTestsBase.cs index 5f89766a79e..fa29940b45b 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricTestsBase.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricTestsBase.cs @@ -34,12 +34,12 @@ public static void ValidateMetricPointTags(List> ex Assert.Equal(expectedTags.Count, tagIndex); } - public static long GetLongSum(List metrics) + public static long GetLongSum(List metrics) { long sum = 0; foreach (var metric in metrics) { - foreach (ref readonly var metricPoint in metric.GetMetricPoints()) + foreach (var metricPoint in metric.MetricPoints) { if (metric.MetricType.IsSum()) { @@ -55,12 +55,12 @@ public static long GetLongSum(List metrics) return sum; } - public static double GetDoubleSum(List metrics) + public static double GetDoubleSum(List metrics) { double sum = 0; foreach (var metric in metrics) { - foreach (ref readonly var metricPoint in metric.GetMetricPoints()) + foreach (var metricPoint in metric.MetricPoints) { if (metric.MetricType.IsSum()) { @@ -76,12 +76,12 @@ public static double GetDoubleSum(List metrics) return sum; } - public static int GetNumberOfMetricPoints(List metrics) + public static int GetNumberOfMetricPoints(List metrics) { int count = 0; foreach (var metric in metrics) { - foreach (ref readonly var metricPoint in metric.GetMetricPoints()) + foreach (var metricPoint in metric.MetricPoints) { count++; } @@ -90,11 +90,11 @@ public static int GetNumberOfMetricPoints(List metrics) return count; } - public static MetricPoint? GetFirstMetricPoint(List metrics) + public static MetricPoint? GetFirstMetricPoint(List metrics) { foreach (var metric in metrics) { - foreach (ref readonly var metricPoint in metric.GetMetricPoints()) + foreach (var metricPoint in metric.MetricPoints) { return metricPoint; } @@ -104,10 +104,10 @@ public static int GetNumberOfMetricPoints(List metrics) } // Provide tags input sorted by Key - public static void CheckTagsForNthMetricPoint(List metrics, List> tags, int n) + public static void CheckTagsForNthMetricPoint(List metrics, List> tags, int n) { var metric = metrics[0]; - var metricPointEnumerator = metric.GetMetricPoints().GetEnumerator(); + var metricPointEnumerator = metric.MetricPoints.GetEnumerator(); for (int i = 0; i < n; i++) { diff --git a/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs b/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs index 3a12cd4ac05..2375f2d9d1a 100644 --- a/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs +++ b/test/OpenTelemetry.Tests/Metrics/MetricViewTests.cs @@ -32,7 +32,7 @@ public class MetricViewTests : MetricTestsBase public void ViewToRenameMetric() { using var meter = new Meter(Utils.GetCurrentMethodName()); - var exportedItems = new List(); + var exportedItems = new List(); using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddMeter(meter.Name) .AddView("name1", "renamed") @@ -52,7 +52,7 @@ public void ViewToRenameMetric() [MemberData(nameof(MetricTestData.InvalidInstrumentNames), MemberType = typeof(MetricTestData))] public void AddViewWithInvalidNameThrowsArgumentException(string viewNewName) { - var exportedItems = new List(); + var exportedItems = new List(); using var meter1 = new Meter("AddViewWithInvalidNameThrowsArgumentException"); @@ -76,7 +76,7 @@ public void AddViewWithInvalidNameThrowsArgumentException(string viewNewName) [Fact] public void AddViewWithNullMetricStreamConfigurationThrowsArgumentnullException() { - var exportedItems = new List(); + var exportedItems = new List(); using var meter1 = new Meter("AddViewWithInvalidNameThrowsArgumentException"); @@ -90,7 +90,7 @@ public void AddViewWithNullMetricStreamConfigurationThrowsArgumentnullException( [Fact] public void AddViewWithNameThrowsInvalidArgumentExceptionWhenConflict() { - var exportedItems = new List(); + var exportedItems = new List(); using var meter1 = new Meter("AddViewWithGuaranteedConflictThrowsInvalidArgumentException"); @@ -104,7 +104,7 @@ public void AddViewWithNameThrowsInvalidArgumentExceptionWhenConflict() [Fact] public void AddViewWithNameInMetricStreamConfigurationThrowsInvalidArgumentExceptionWhenConflict() { - var exportedItems = new List(); + var exportedItems = new List(); using var meter1 = new Meter("AddViewWithGuaranteedConflictThrowsInvalidArgumentException"); @@ -118,7 +118,7 @@ public void AddViewWithNameInMetricStreamConfigurationThrowsInvalidArgumentExcep [Fact] public void AddViewWithExceptionInUserCallbackAppliedDefault() { - var exportedItems = new List(); + var exportedItems = new List(); using var meter1 = new Meter("AddViewWithExceptionInUserCallback"); using var meterProvider = Sdk.CreateMeterProviderBuilder() @@ -144,7 +144,7 @@ public void AddViewWithExceptionInUserCallbackAppliedDefault() [Fact] public void AddViewWithExceptionInUserCallbackNoDefault() { - var exportedItems = new List(); + var exportedItems = new List(); using var meter1 = new Meter("AddViewWithExceptionInUserCallback"); using var meterProvider = Sdk.CreateMeterProviderBuilder() @@ -172,7 +172,7 @@ public void AddViewWithExceptionInUserCallbackNoDefault() [Fact] public void AddViewsWithAndWithoutExceptionInUserCallback() { - var exportedItems = new List(); + var exportedItems = new List(); using var meter1 = new Meter("AddViewWithExceptionInUserCallback"); using var meterProvider = Sdk.CreateMeterProviderBuilder() @@ -211,7 +211,7 @@ public void AddViewWithInvalidHistogramBoundsThrowsArgumentException(double[] bo [MemberData(nameof(MetricTestData.InvalidHistogramBoundaries), MemberType = typeof(MetricTestData))] public void AddViewWithInvalidHistogramBoundsIgnored(double[] boundaries) { - var exportedItems = new List(); + var exportedItems = new List(); using var meter1 = new Meter("AddViewWithInvalidHistogramBoundsIgnored"); @@ -240,7 +240,7 @@ public void AddViewWithInvalidHistogramBoundsIgnored(double[] boundaries) [MemberData(nameof(MetricTestData.ValidInstrumentNames), MemberType = typeof(MetricTestData))] public void ViewWithValidNameExported(string viewNewName) { - var exportedItems = new List(); + var exportedItems = new List(); using var meter1 = new Meter("ViewWithInvalidNameIgnoredTest"); using var meterProvider = Sdk.CreateMeterProviderBuilder() @@ -265,7 +265,7 @@ public void ViewToRenameMetricConditionally() using var meter1 = new Meter($"{Utils.GetCurrentMethodName()}.1"); using var meter2 = new Meter($"{Utils.GetCurrentMethodName()}.2"); - var exportedItems = new List(); + var exportedItems = new List(); using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddMeter(meter1.Name) @@ -306,7 +306,7 @@ public void ViewToRenameMetricConditionally() public void ViewWithInvalidNameIgnoredConditionally(string viewNewName) { using var meter1 = new Meter("ViewToRenameMetricConditionallyTest"); - var exportedItems = new List(); + var exportedItems = new List(); using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddMeter(meter1.Name) @@ -343,7 +343,7 @@ public void ViewWithInvalidNameIgnoredConditionally(string viewNewName) public void ViewWithValidNameConditionally(string viewNewName) { using var meter1 = new Meter("ViewToRenameMetricConditionallyTest"); - var exportedItems = new List(); + var exportedItems = new List(); using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddMeter(meter1.Name) .AddView((instrument) => @@ -377,7 +377,7 @@ public void ViewWithValidNameConditionally(string viewNewName) [Fact] public void ViewWithNullCustomNameTakesInstrumentName() { - var exportedItems = new List(); + var exportedItems = new List(); using var meter = new Meter("ViewToRenameMetricConditionallyTest"); @@ -415,7 +415,7 @@ public void ViewWithNullCustomNameTakesInstrumentName() public void ViewToProduceMultipleStreamsFromInstrument() { using var meter = new Meter(Utils.GetCurrentMethodName()); - var exportedItems = new List(); + var exportedItems = new List(); using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddMeter(meter.Name) .AddView("name1", "renamedStream1") @@ -436,7 +436,7 @@ public void ViewToProduceMultipleStreamsFromInstrument() public void ViewToProduceMultipleStreamsWithDuplicatesFromInstrument() { using var meter = new Meter(Utils.GetCurrentMethodName()); - var exportedItems = new List(); + var exportedItems = new List(); using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddMeter(meter.Name) .AddView("name1", "renamedStream1") @@ -461,7 +461,7 @@ public void ViewToProduceMultipleStreamsWithDuplicatesFromInstrument() public void ViewWithHistogramConfigurationIgnoredWhenAppliedToNonHistogram() { using var meter = new Meter(Utils.GetCurrentMethodName()); - var exportedItems = new List(); + var exportedItems = new List(); using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddMeter(meter.Name) .AddView("NotAHistogram", new ExplicitBucketHistogramConfiguration() { Name = "ImAHistogram" }) @@ -478,7 +478,7 @@ public void ViewWithHistogramConfigurationIgnoredWhenAppliedToNonHistogram() Assert.Equal("NotAHistogram", metric.Name); List metricPoints = new List(); - foreach (ref readonly var mp in metric.GetMetricPoints()) + foreach (var mp in metric.MetricPoints) { metricPoints.Add(mp); } @@ -492,7 +492,7 @@ public void ViewWithHistogramConfigurationIgnoredWhenAppliedToNonHistogram() public void ViewToProduceCustomHistogramBound() { using var meter = new Meter(Utils.GetCurrentMethodName()); - var exportedItems = new List(); + var exportedItems = new List(); var boundaries = new double[] { 10, 20 }; using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddMeter(meter.Name) @@ -518,7 +518,7 @@ public void ViewToProduceCustomHistogramBound() Assert.Equal("MyHistogram", metricCustom.Name); List metricPointsDefault = new List(); - foreach (ref readonly var mp in metricDefault.GetMetricPoints()) + foreach (var mp in metricDefault.MetricPoints) { metricPointsDefault.Add(mp); } @@ -545,7 +545,7 @@ public void ViewToProduceCustomHistogramBound() Assert.Equal(Metric.DefaultHistogramBounds.Length + 1, actualCount); List metricPointsCustom = new List(); - foreach (ref readonly var mp in metricCustom.GetMetricPoints()) + foreach (var mp in metricCustom.MetricPoints) { metricPointsCustom.Add(mp); } @@ -576,7 +576,7 @@ public void ViewToProduceCustomHistogramBound() public void ViewToSelectTagKeys() { using var meter = new Meter(Utils.GetCurrentMethodName()); - var exportedItems = new List(); + var exportedItems = new List(); using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddMeter(meter.Name) .AddView("FruitCounter", new MetricStreamConfiguration() @@ -612,7 +612,7 @@ public void ViewToSelectTagKeys() var metric = exportedItems[0]; Assert.Equal("NameOnly", metric.Name); List metricPoints = new List(); - foreach (ref readonly var mp in metric.GetMetricPoints()) + foreach (var mp in metric.MetricPoints) { metricPoints.Add(mp); } @@ -623,7 +623,7 @@ public void ViewToSelectTagKeys() metric = exportedItems[1]; Assert.Equal("SizeOnly", metric.Name); metricPoints.Clear(); - foreach (ref readonly var mp in metric.GetMetricPoints()) + foreach (var mp in metric.MetricPoints) { metricPoints.Add(mp); } @@ -634,7 +634,7 @@ public void ViewToSelectTagKeys() metric = exportedItems[2]; Assert.Equal("NoTags", metric.Name); metricPoints.Clear(); - foreach (ref readonly var mp in metric.GetMetricPoints()) + foreach (var mp in metric.MetricPoints) { metricPoints.Add(mp); } @@ -647,7 +647,7 @@ public void ViewToSelectTagKeys() public void ViewToDropSingleInstrument() { using var meter = new Meter(Utils.GetCurrentMethodName()); - var exportedItems = new List(); + var exportedItems = new List(); using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddMeter(meter.Name) .AddView("counterNotInteresting", MetricStreamConfiguration.Drop) @@ -670,7 +670,7 @@ public void ViewToDropSingleInstrument() public void ViewToDropSingleInstrumentObservableCounter() { using var meter = new Meter(Utils.GetCurrentMethodName()); - var exportedItems = new List(); + var exportedItems = new List(); using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddMeter(meter.Name) .AddView("observableCounterNotInteresting", MetricStreamConfiguration.Drop) @@ -691,7 +691,7 @@ public void ViewToDropSingleInstrumentObservableCounter() public void ViewToDropSingleInstrumentObservableGauge() { using var meter = new Meter(Utils.GetCurrentMethodName()); - var exportedItems = new List(); + var exportedItems = new List(); using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddMeter(meter.Name) .AddView("observableGaugeNotInteresting", MetricStreamConfiguration.Drop) @@ -712,7 +712,7 @@ public void ViewToDropSingleInstrumentObservableGauge() public void ViewToDropMultipleInstruments() { using var meter = new Meter(Utils.GetCurrentMethodName()); - var exportedItems = new List(); + var exportedItems = new List(); using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddMeter(meter.Name) .AddView("server*", MetricStreamConfiguration.Drop) @@ -739,7 +739,7 @@ public void ViewToDropMultipleInstruments() public void ViewToDropAndRetainInstrument() { using var meter = new Meter(Utils.GetCurrentMethodName()); - var exportedItems = new List(); + var exportedItems = new List(); using var meterProvider = Sdk.CreateMeterProviderBuilder() .AddMeter(meter.Name) .AddView("server.requests", MetricStreamConfiguration.Drop) @@ -762,7 +762,7 @@ public void ViewToDropAndRetainInstrument() [Fact] public void ViewConflict_OneInstrument_DifferentDescription() { - var exportedItems = new List(); + var exportedItems = new List(); using var meter = new Meter($"{Utils.GetCurrentMethodName()}"); var meterProviderBuilder = Sdk.CreateMeterProviderBuilder() @@ -786,7 +786,7 @@ public void ViewConflict_OneInstrument_DifferentDescription() Assert.Equal("newDescription2", metric2.Description); List metric1MetricPoints = new List(); - foreach (ref readonly var mp in metric1.GetMetricPoints()) + foreach (var mp in metric1.MetricPoints) { metric1MetricPoints.Add(mp); } @@ -796,7 +796,7 @@ public void ViewConflict_OneInstrument_DifferentDescription() Assert.Equal(10, metricPoint1.GetSumLong()); List metric2MetricPoints = new List(); - foreach (ref readonly var mp in metric2.GetMetricPoints()) + foreach (var mp in metric2.MetricPoints) { metric2MetricPoints.Add(mp); } @@ -809,7 +809,7 @@ public void ViewConflict_OneInstrument_DifferentDescription() [Fact] public void ViewConflict_TwoDistinctInstruments_ThreeStreams() { - var exportedItems = new List(); + var exportedItems = new List(); using var meter = new Meter($"{Utils.GetCurrentMethodName()}"); var meterProviderBuilder = Sdk.CreateMeterProviderBuilder() @@ -850,10 +850,10 @@ public void ViewConflict_TwoDistinctInstruments_ThreeStreams() Assert.Equal("MetricStreamC", metricC.Name); Assert.Equal(10, GetAggregatedValue(metricC)); - long GetAggregatedValue(Metric metric) + long GetAggregatedValue(ExportableMetricCopy metric) { var metricPoints = new List(); - foreach (ref readonly var mp in metric.GetMetricPoints()) + foreach (var mp in metric.MetricPoints) { metricPoints.Add(mp); } @@ -866,7 +866,7 @@ long GetAggregatedValue(Metric metric) [Fact] public void ViewConflict_TwoIdenticalInstruments_TwoViews_DifferentTags() { - var exportedItems = new List(); + var exportedItems = new List(); using var meter = new Meter($"{Utils.GetCurrentMethodName()}"); var meterProviderBuilder = Sdk.CreateMeterProviderBuilder() @@ -898,8 +898,8 @@ public void ViewConflict_TwoIdenticalInstruments_TwoViews_DifferentTags() meterProvider.ForceFlush(MaxTimeToAllowForFlush); Assert.Equal(2, exportedItems.Count); - var metric1 = new List() { exportedItems[0] }; - var metric2 = new List() { exportedItems[1] }; + var metric1 = new List() { exportedItems[0] }; + var metric2 = new List() { exportedItems[1] }; var tag1 = new List> { tags[0] }; var tag2 = new List> { tags[1] }; @@ -914,7 +914,7 @@ public void ViewConflict_TwoIdenticalInstruments_TwoViews_DifferentTags() [Fact] public void ViewConflict_TwoIdenticalInstruments_TwoViews_SameTags() { - var exportedItems = new List(); + var exportedItems = new List(); using var meter = new Meter($"{Utils.GetCurrentMethodName()}"); var meterProviderBuilder = Sdk.CreateMeterProviderBuilder() @@ -947,13 +947,13 @@ public void ViewConflict_TwoIdenticalInstruments_TwoViews_SameTags() Assert.Equal(2, exportedItems.Count); - var metric1 = new List() { exportedItems[0] }; + var metric1 = new List() { exportedItems[0] }; var tag1 = new List> { tags[0] }; Assert.Equal("name", exportedItems[0].Name); Assert.Equal(20, GetLongSum(metric1)); CheckTagsForNthMetricPoint(metric1, tag1, 1); - var metric2 = new List() { exportedItems[1] }; + var metric2 = new List() { exportedItems[1] }; var tag2 = new List> { tags[0] }; Assert.Equal("name", exportedItems[1].Name); Assert.Equal(20, GetLongSum(metric2)); @@ -963,7 +963,7 @@ public void ViewConflict_TwoIdenticalInstruments_TwoViews_SameTags() [Fact] public void ViewConflict_TwoIdenticalInstruments_TwoViews_DifferentHistogramBounds() { - var exportedItems = new List(); + var exportedItems = new List(); using var meter = new Meter($"{Utils.GetCurrentMethodName()}"); var meterProviderBuilder = Sdk.CreateMeterProviderBuilder() @@ -996,7 +996,7 @@ public void ViewConflict_TwoIdenticalInstruments_TwoViews_DifferentHistogramBoun Assert.Equal("name", exportedItems[1].Name); var metricPoints = new List(); - foreach (ref readonly var mp in metric1.GetMetricPoints()) + foreach (var mp in metric1.MetricPoints) { metricPoints.Add(mp); } @@ -1017,7 +1017,7 @@ public void ViewConflict_TwoIdenticalInstruments_TwoViews_DifferentHistogramBoun } metricPoints = new List(); - foreach (ref readonly var mp in metric2.GetMetricPoints()) + foreach (var mp in metric2.MetricPoints) { metricPoints.Add(mp); } @@ -1041,7 +1041,7 @@ public void ViewConflict_TwoIdenticalInstruments_TwoViews_DifferentHistogramBoun [Fact] public void ViewConflict_TwoInstruments_OneMatchesView() { - var exportedItems = new List(); + var exportedItems = new List(); using var meter = new Meter($"{Utils.GetCurrentMethodName()}"); var meterProviderBuilder = Sdk.CreateMeterProviderBuilder() @@ -1076,8 +1076,8 @@ public void ViewConflict_TwoInstruments_OneMatchesView() meterProvider.ForceFlush(MaxTimeToAllowForFlush); Assert.Equal(2, exportedItems.Count); - var metric1 = new List() { exportedItems[0] }; - var metric2 = new List() { exportedItems[1] }; + var metric1 = new List() { exportedItems[0] }; + var metric2 = new List() { exportedItems[1] }; var tags1 = new List> { tags[0] }; var tags2 = new List> { tags[0], tags[1] }; @@ -1095,7 +1095,7 @@ public void ViewConflict_TwoInstruments_OneMatchesView() [Fact] public void ViewConflict_TwoInstruments_ConflictAvoidedBecauseSecondInstrumentIsDropped() { - var exportedItems = new List(); + var exportedItems = new List(); using var meter = new Meter($"{Utils.GetCurrentMethodName()}"); var meterProviderBuilder = Sdk.CreateMeterProviderBuilder() @@ -1124,7 +1124,7 @@ public void ViewConflict_TwoInstruments_ConflictAvoidedBecauseSecondInstrumentIs meterProvider.ForceFlush(MaxTimeToAllowForFlush); Assert.Single(exportedItems); - var metric1 = new List() { exportedItems[0] }; + var metric1 = new List() { exportedItems[0] }; Assert.Equal("othername", exportedItems[0].Name); Assert.Equal(10, GetLongSum(metric1)); diff --git a/test/OpenTelemetry.Tests/Metrics/MultipleReadersTests.cs b/test/OpenTelemetry.Tests/Metrics/MultipleReadersTests.cs index 142ed9371f9..3fd8b4b35f0 100644 --- a/test/OpenTelemetry.Tests/Metrics/MultipleReadersTests.cs +++ b/test/OpenTelemetry.Tests/Metrics/MultipleReadersTests.cs @@ -30,8 +30,8 @@ public class MultipleReadersTests [InlineData(MetricReaderTemporalityPreference.Cumulative, true)] public void SdkSupportsMultipleReaders(MetricReaderTemporalityPreference aggregationTemporality, bool hasViews) { - var exportedItems1 = new List(); - var exportedItems2 = new List(); + var exportedItems1 = new List(); + var exportedItems2 = new List(); using var meter = new Meter($"{Utils.GetCurrentMethodName()}.{aggregationTemporality}.{hasViews}"); @@ -158,8 +158,8 @@ public void SdkSupportsMultipleReaders(MetricReaderTemporalityPreference aggrega [InlineData(true)] public void ObservableInstrumentCallbacksInvokedForEachReaders(bool hasViews) { - var exportedItems1 = new List(); - var exportedItems2 = new List(); + var exportedItems1 = new List(); + var exportedItems2 = new List(); using var meter = new Meter($"{Utils.GetCurrentMethodName()}.{hasViews}"); int callbackInvocationCount = 0; var gauge = meter.CreateObservableGauge("gauge", () => @@ -198,12 +198,12 @@ public void ObservableInstrumentCallbacksInvokedForEachReaders(bool hasViews) } } - private static void AssertLongSumValueForMetric(Metric metric, long value) + private static void AssertLongSumValueForMetric(ExportableMetricCopy metric, long value) { - var metricPoints = metric.GetMetricPoints(); + var metricPoints = metric.MetricPoints; var metricPointsEnumerator = metricPoints.GetEnumerator(); Assert.True(metricPointsEnumerator.MoveNext()); // One MetricPoint is emitted for the Metric - ref readonly var metricPointForFirstExport = ref metricPointsEnumerator.Current; + var metricPointForFirstExport = metricPointsEnumerator.Current; if (metric.MetricType.IsSum()) { Assert.Equal(value, metricPointForFirstExport.GetSumLong()); diff --git a/test/OpenTelemetry.Tests/Shared/InMemoryExporterMetricsExtensions.cs b/test/OpenTelemetry.Tests/Shared/InMemoryExporterMetricsExtensions.cs new file mode 100644 index 00000000000..12faddc92de --- /dev/null +++ b/test/OpenTelemetry.Tests/Shared/InMemoryExporterMetricsExtensions.cs @@ -0,0 +1,83 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using System.Collections.Generic; +using System.Threading; +using OpenTelemetry.Exporter; + +namespace OpenTelemetry.Metrics +{ + /// + /// Extension methods to simplify registering of the InMemory exporter. + /// + public static class InMemoryExporterMetricsExtensions + { + private const int DefaultExportIntervalMilliseconds = Timeout.Infinite; + private const int DefaultExportTimeoutMilliseconds = Timeout.Infinite; + + /// + /// Adds InMemory metric exporter to the using default options. + /// + /// builder to use. + /// Collection which will be populated with the exported MetricItem represented as . + /// configuration options. + /// The instance of to chain the calls. + public static MeterProviderBuilder AddInMemoryExporter( + this MeterProviderBuilder builder, + ICollection exportedItems, + Action configureMetricReader = null) + { + if (builder is IDeferredMeterProviderBuilder deferredMeterProviderBuilder) + { + return deferredMeterProviderBuilder.Configure((sp, builder) => + { + AddInMemoryExporter(builder, exportedItems, sp.GetOptions(), configureMetricReader); + }); + } + + return AddInMemoryExporter(builder, exportedItems, new MetricReaderOptions(), configureMetricReader); + } + + private static MeterProviderBuilder AddInMemoryExporter( + MeterProviderBuilder builder, + ICollection exportedItems, + MetricReaderOptions metricReaderOptions, + Action configureMetricReader) + { + configureMetricReader?.Invoke(metricReaderOptions); + + var metricExporter = new InMemoryExporter( + exportFunc: metricBatch => + { + foreach (var metric in metricBatch) + { + exportedItems.Add(metric); + } + + return ExportResult.Success; + }); + + var metricReader = PeriodicExportingMetricReaderHelper.CreatePeriodicExportingMetricReader( + metricExporter, + metricReaderOptions, + DefaultExportIntervalMilliseconds, + DefaultExportTimeoutMilliseconds); + + return builder.AddReader(metricReader); + } + } +} diff --git a/test/OpenTelemetry.Tests/Trace/BatchExportActivityProcessorTest.cs b/test/OpenTelemetry.Tests/Trace/BatchExportActivityProcessorTest.cs index 33c6579d11c..c2ccad327c8 100644 --- a/test/OpenTelemetry.Tests/Trace/BatchExportActivityProcessorTest.cs +++ b/test/OpenTelemetry.Tests/Trace/BatchExportActivityProcessorTest.cs @@ -190,9 +190,8 @@ public void CheckExportForRecordingButNotSampledActivity() [Fact] public void CheckExportDrainsBatchOnFailure() { - using var exporter = new InMemoryExporter(null); using var processor = new BatchActivityExportProcessor( - exporter, + exporter: new FailureExporter(), maxQueueSize: 3, maxExportBatchSize: 3); @@ -208,5 +207,10 @@ public void CheckExportDrainsBatchOnFailure() Assert.Equal(3, processor.ProcessedCount); // Verify batch was drained even though nothing was exported. } + + private class FailureExporter : BaseExporter + { + public override ExportResult Export(in Batch batch) => ExportResult.Failure; + } } }