Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/OpenTelemetry/Metrics/Reader/MetricReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,11 @@ public void Dispose()

internal virtual void SetParentProvider(BaseProvider parentProvider)
{
if (this.parentProvider != null && this.parentProvider != parentProvider)
{
throw new NotSupportedException("A MetricReader must not be registered with multiple MeterProviders.");
}

this.parentProvider = parentProvider;
}

Expand Down
91 changes: 91 additions & 0 deletions test/OpenTelemetry.Tests/Metrics/MultipleReadersTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,104 @@

using System.Diagnostics.Metrics;
using Microsoft.Extensions.DependencyInjection;
using OpenTelemetry.Exporter;
using OpenTelemetry.Tests;
using Xunit;

namespace OpenTelemetry.Metrics.Tests;

public class MultipleReadersTests
{
[Fact]
public void ReaderCannotBeRegisteredMoreThanOnce()
{
var exportedItems = new List<Metric>();
using var exporter = new InMemoryExporter<Metric>(exportedItems);
using var reader = new BaseExportingMetricReader(exporter);

using var meter = new Meter($"{Utils.GetCurrentMethodName()}");

var meterProviderBuilder1 = Sdk.CreateMeterProviderBuilder()
.AddMeter(meter.Name)
.AddReader(reader);
var meterProviderBuilder2 = Sdk.CreateMeterProviderBuilder()
.AddMeter(meter.Name)
.AddReader(reader);

using var meterProvider1 = meterProviderBuilder1.Build();
Assert.Throws<NotSupportedException>(() => meterProviderBuilder2.Build());
}

[Fact]
public void MultipleReadersOneCollectsIndependently()
{
var exportedItems1 = new List<Metric>();
var exportedItems2 = new List<Metric>();

using var exporter1 = new InMemoryExporter<Metric>(exportedItems1);
using var exporter2 = new InMemoryExporter<Metric>(exportedItems2);
using var reader1 = new BaseExportingMetricReader(exporter1);
using var reader2 = new BaseExportingMetricReader(exporter2);

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

var meterProviderBuilder = Sdk.CreateMeterProviderBuilder()
.AddMeter(meter.Name)
.AddReader(reader1)
.AddReader(reader2);

using var meterProvider = meterProviderBuilder.Build();

counter.Add(1);

reader1.Collect();

Assert.Single(exportedItems1);
Assert.Empty(exportedItems2);
}

[Fact]
public void MultipleReadersDifferentTemporality()
{
var exportedItems1 = new List<Metric>();
var exportedItems2 = new List<Metric>();

using var exporter1 = new InMemoryExporter<Metric>(exportedItems1);
using var exporter2 = new InMemoryExporter<Metric>(exportedItems2);
using var reader1 = new BaseExportingMetricReader(exporter1);
using var reader2 = new BaseExportingMetricReader(exporter2);
reader1.TemporalityPreference = MetricReaderTemporalityPreference.Delta;
reader2.TemporalityPreference = MetricReaderTemporalityPreference.Cumulative;

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

var meterProviderBuilder = Sdk.CreateMeterProviderBuilder()
.AddMeter(meter.Name)
.AddReader(reader1)
.AddReader(reader2);

using var meterProvider = meterProviderBuilder.Build();

counter.Add(1);

reader1.Collect();
reader2.Collect();

AssertLongSumValueForMetric(exportedItems1[0], 1);
AssertLongSumValueForMetric(exportedItems2[0], 1);

exportedItems1.Clear();

counter.Add(10);
reader1.Collect();
reader2.Collect();

AssertLongSumValueForMetric(exportedItems1[0], 10);
AssertLongSumValueForMetric(exportedItems2[0], 11);
}

[Theory]
[InlineData(MetricReaderTemporalityPreference.Delta, false)]
[InlineData(MetricReaderTemporalityPreference.Delta, true)]
Expand Down