opentelemetry-dotnet/test/OpenTelemetry.Exporter.Open.../UseOtlpExporterExtensionTes...

384 lines
15 KiB
C#

// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
using System.Diagnostics;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using OpenTelemetry.Logs;
using OpenTelemetry.Metrics;
using OpenTelemetry.Tests;
using OpenTelemetry.Trace;
using Xunit;
namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests;
[Collection("EnvVars")]
public class UseOtlpExporterExtensionTests : IDisposable
{
public UseOtlpExporterExtensionTests()
{
OtlpSpecConfigDefinitionTests.ClearEnvVars();
}
public void Dispose()
{
OtlpSpecConfigDefinitionTests.ClearEnvVars();
}
[Fact]
public void UseOtlpExporterDefaultTest()
{
var services = new ServiceCollection();
services.AddOpenTelemetry()
.UseOtlpExporter();
using var sp = services.BuildServiceProvider();
var exporterOptions = sp.GetRequiredService<IOptionsMonitor<OtlpExporterBuilderOptions>>().CurrentValue;
Assert.Equal(new Uri(OtlpExporterOptions.DefaultGrpcEndpoint), exporterOptions.DefaultOptions.Endpoint);
Assert.Equal(OtlpExporterOptions.DefaultOtlpExportProtocol, exporterOptions.DefaultOptions.Protocol);
Assert.False(((OtlpExporterOptions)exporterOptions.DefaultOptions).HasData);
Assert.False(((OtlpExporterOptions)exporterOptions.LoggingOptions).HasData);
Assert.False(((OtlpExporterOptions)exporterOptions.MetricsOptions).HasData);
Assert.False(((OtlpExporterOptions)exporterOptions.TracingOptions).HasData);
}
[Theory]
[InlineData(OtlpExportProtocol.Grpc)]
[InlineData(OtlpExportProtocol.HttpProtobuf)]
public void UseOtlpExporterSetEndpointAndProtocolTest(OtlpExportProtocol protocol)
{
var services = new ServiceCollection();
services.AddOpenTelemetry()
.UseOtlpExporter(
protocol,
new Uri("http://test_base_endpoint/"));
using var sp = services.BuildServiceProvider();
var exporterOptions = sp.GetRequiredService<IOptionsMonitor<OtlpExporterBuilderOptions>>().CurrentValue;
Assert.Equal(protocol, exporterOptions.DefaultOptions.Protocol);
Assert.Equal(new Uri("http://test_base_endpoint/"), exporterOptions.DefaultOptions.Endpoint);
Assert.True(((OtlpExporterOptions)exporterOptions.DefaultOptions).HasData);
Assert.False(((OtlpExporterOptions)exporterOptions.LoggingOptions).HasData);
Assert.False(((OtlpExporterOptions)exporterOptions.MetricsOptions).HasData);
Assert.False(((OtlpExporterOptions)exporterOptions.TracingOptions).HasData);
Assert.Throws<ArgumentNullException>(
() => services.AddOpenTelemetry().UseOtlpExporter(OtlpExportProtocol.HttpProtobuf, baseUrl: null!));
}
[Theory]
[InlineData(null)]
[InlineData("testNamedOptions")]
public void UseOtlpExporterConfigureTest(string? name)
{
var services = new ServiceCollection();
if (!string.IsNullOrEmpty(name))
{
services.AddOpenTelemetry()
.UseOtlpExporter(name, configuration: null, configure: Configure);
}
else
{
services.AddOpenTelemetry()
.UseOtlpExporter(Configure);
}
using var sp = services.BuildServiceProvider();
VerifyOptionsApplied(sp, name);
static void Configure(OtlpExporterBuilder builder)
{
builder.ConfigureDefaultExporterOptions(
defaultOptions => defaultOptions.Endpoint = new Uri("http://default_endpoint/"));
builder.ConfigureLoggingExporterOptions(
exporterOptions => exporterOptions.Endpoint = new Uri("http://signal_endpoint/logs/"));
builder.ConfigureLoggingProcessorOptions(
processorOptions =>
{
processorOptions.ExportProcessorType = ExportProcessorType.Simple;
processorOptions.BatchExportProcessorOptions.ScheduledDelayMilliseconds = 1000;
});
builder.ConfigureMetricsExporterOptions(
exporterOptions => exporterOptions.Endpoint = new Uri("http://signal_endpoint/metrics/"));
builder.ConfigureMetricsReaderOptions(
readerOptions =>
{
readerOptions.TemporalityPreference = MetricReaderTemporalityPreference.Delta;
readerOptions.PeriodicExportingMetricReaderOptions.ExportIntervalMilliseconds = 1001;
});
builder.ConfigureTracingExporterOptions(
exporterOptions => exporterOptions.Endpoint = new Uri("http://signal_endpoint/traces/"));
builder.ConfigureTracingProcessorOptions(
processorOptions =>
{
processorOptions.ExportProcessorType = ExportProcessorType.Simple;
processorOptions.BatchExportProcessorOptions.ScheduledDelayMilliseconds = 1002;
});
}
}
[Theory]
[InlineData(null)]
[InlineData("testNamedOptions")]
public void UseOtlpExporterConfigurationTest(string? name)
{
var config = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string?>
{
["DefaultOptions:Endpoint"] = "http://default_endpoint/",
["LoggingOptions:Endpoint"] = "http://signal_endpoint/logs/",
["LoggingOptions:ExportProcessorType"] = "Simple",
["LoggingOptions:BatchExportProcessorOptions:ScheduledDelayMilliseconds"] = "1000",
["MetricsOptions:Endpoint"] = "http://signal_endpoint/metrics/",
["MetricsOptions:TemporalityPreference"] = "Delta",
["MetricsOptions:PeriodicExportingMetricReaderOptions:ExportIntervalMilliseconds"] = "1001",
["TracingOptions:Endpoint"] = "http://signal_endpoint/traces/",
["TracingOptions:ExportProcessorType"] = "Simple",
["TracingOptions:BatchExportProcessorOptions:ScheduledDelayMilliseconds"] = "1002",
})
.Build();
var services = new ServiceCollection();
if (!string.IsNullOrEmpty(name))
{
services.AddOpenTelemetry()
.UseOtlpExporter(name: name, configuration: config, configure: null);
}
else
{
services.AddOpenTelemetry()
.UseOtlpExporter(config);
name = "otlp";
}
using var sp = services.BuildServiceProvider();
VerifyOptionsApplied(sp, name);
}
[Fact]
public void UseOtlpExporterSingleCallsTest()
{
var services = new ServiceCollection();
services.AddOpenTelemetry()
.UseOtlpExporter();
using var sp = services.BuildServiceProvider();
Assert.NotNull(sp.GetRequiredService<LoggerProvider>());
Assert.NotNull(sp.GetRequiredService<MeterProvider>());
Assert.NotNull(sp.GetRequiredService<TracerProvider>());
}
[Fact]
public void UseOtlpExporterMultipleCallsTest()
{
var services = new ServiceCollection();
services.AddOpenTelemetry()
.UseOtlpExporter()
.UseOtlpExporter();
using var sp = services.BuildServiceProvider();
Assert.Throws<NotSupportedException>(() => sp.GetRequiredService<LoggerProvider>());
Assert.Throws<NotSupportedException>(() => sp.GetRequiredService<MeterProvider>());
Assert.Throws<NotSupportedException>(() => sp.GetRequiredService<TracerProvider>());
}
[Fact]
public void UseOtlpExporterWithAddOtlpExporterLoggingTest()
{
var services = new ServiceCollection();
services.AddOpenTelemetry()
.UseOtlpExporter()
.WithLogging(builder => builder.AddOtlpExporter());
using var sp = services.BuildServiceProvider();
Assert.Throws<NotSupportedException>(() => sp.GetRequiredService<LoggerProvider>());
}
[Fact]
public void UseOtlpExporterWithAddOtlpExporterMetricsTest()
{
var services = new ServiceCollection();
services.AddOpenTelemetry()
.UseOtlpExporter()
.WithMetrics(builder => builder.AddOtlpExporter());
using var sp = services.BuildServiceProvider();
Assert.Throws<NotSupportedException>(() => sp.GetRequiredService<MeterProvider>());
}
[Fact]
public void UseOtlpExporterWithAddOtlpExporterTracingTest()
{
var services = new ServiceCollection();
services.AddOpenTelemetry()
.UseOtlpExporter()
.WithTracing(builder => builder.AddOtlpExporter());
using var sp = services.BuildServiceProvider();
Assert.Throws<NotSupportedException>(() => sp.GetRequiredService<TracerProvider>());
}
[Fact]
public void UseOtlpExporterAddsTracingProcessorToPipelineEndTest()
{
var services = new ServiceCollection();
services.AddOpenTelemetry()
.UseOtlpExporter()
.WithTracing(builder => builder.AddProcessor(new TestActivityProcessor()));
using var sp = services.BuildServiceProvider();
var tracerProvider = sp.GetRequiredService<TracerProvider>() as TracerProviderSdk;
Assert.NotNull(tracerProvider);
var processor = tracerProvider.Processor as CompositeProcessor<Activity>;
Assert.NotNull(processor);
var processors = processor.ToReadOnlyList();
Assert.True(processors[0] is TestActivityProcessor);
Assert.True(processors[1] is BatchActivityExportProcessor);
}
[Fact]
public void UseOtlpExporterAddsLoggingProcessorToPipelineEndTest()
{
var services = new ServiceCollection();
services.AddOpenTelemetry()
.UseOtlpExporter()
.WithLogging(builder => builder.AddProcessor(new TestLogRecordProcessor()));
using var sp = services.BuildServiceProvider();
var tracerProvider = sp.GetRequiredService<LoggerProvider>() as LoggerProviderSdk;
Assert.NotNull(tracerProvider);
var processor = tracerProvider.Processor as CompositeProcessor<LogRecord>;
Assert.NotNull(processor);
var processors = processor.ToReadOnlyList();
Assert.True(processors[0] is TestLogRecordProcessor);
Assert.True(processors[1] is BatchLogRecordExportProcessor);
}
[Fact]
public void UseOtlpExporterRespectsSpecEnvVarsTest()
{
OtlpSpecConfigDefinitionTests.SetEnvVars();
var services = new ServiceCollection();
services.AddOpenTelemetry()
.UseOtlpExporter();
using var sp = services.BuildServiceProvider();
var exporterBuilderOptions = sp.GetRequiredService<IOptionsMonitor<OtlpExporterBuilderOptions>>().Get(Options.DefaultName);
OtlpSpecConfigDefinitionTests.DefaultData.AssertMatches(exporterBuilderOptions.DefaultOptions);
OtlpSpecConfigDefinitionTests.LoggingData.AssertMatches(exporterBuilderOptions.LoggingOptions);
OtlpSpecConfigDefinitionTests.MetricsData.AssertMatches(exporterBuilderOptions.MetricsOptions);
OtlpSpecConfigDefinitionTests.TracingData.AssertMatches(exporterBuilderOptions.TracingOptions);
var metricReaderOptions = sp.GetRequiredService<IOptionsMonitor<MetricReaderOptions>>().Get(Options.DefaultName);
OtlpSpecConfigDefinitionTests.MetricsData.AssertMatches(metricReaderOptions);
}
[Fact]
public void UseOtlpExporterRespectsSpecEnvVarsSetUsingIConfigurationTest()
{
var services = new ServiceCollection();
services.AddSingleton(OtlpSpecConfigDefinitionTests.ToConfiguration());
services.AddOpenTelemetry()
.UseOtlpExporter();
using var sp = services.BuildServiceProvider();
var exporterBuilderOptions = sp.GetRequiredService<IOptionsMonitor<OtlpExporterBuilderOptions>>().Get(Options.DefaultName);
OtlpSpecConfigDefinitionTests.DefaultData.AssertMatches(exporterBuilderOptions.DefaultOptions);
OtlpSpecConfigDefinitionTests.LoggingData.AssertMatches(exporterBuilderOptions.LoggingOptions);
OtlpSpecConfigDefinitionTests.MetricsData.AssertMatches(exporterBuilderOptions.MetricsOptions);
OtlpSpecConfigDefinitionTests.TracingData.AssertMatches(exporterBuilderOptions.TracingOptions);
var metricReaderOptions = sp.GetRequiredService<IOptionsMonitor<MetricReaderOptions>>().Get(Options.DefaultName);
OtlpSpecConfigDefinitionTests.MetricsData.AssertMatches(metricReaderOptions);
}
private static void VerifyOptionsApplied(ServiceProvider serviceProvider, string? name)
{
var exporterOptions = serviceProvider.GetRequiredService<IOptionsMonitor<OtlpExporterBuilderOptions>>().Get(name);
Assert.Equal("http://default_endpoint/", exporterOptions.DefaultOptions.Endpoint.ToString());
/* Note: False is OK here. For cross-cutting extension
AppendSignalPathToEndpoint on default options isn't used for anything */
Assert.False(((OtlpExporterOptions)exporterOptions.DefaultOptions).AppendSignalPathToEndpoint);
Assert.Equal("http://signal_endpoint/logs/", exporterOptions.LoggingOptions.Endpoint.ToString());
Assert.False(((OtlpExporterOptions)exporterOptions.LoggingOptions).AppendSignalPathToEndpoint);
Assert.Equal("http://signal_endpoint/metrics/", exporterOptions.MetricsOptions.Endpoint.ToString());
Assert.False(((OtlpExporterOptions)exporterOptions.MetricsOptions).AppendSignalPathToEndpoint);
Assert.Equal("http://signal_endpoint/traces/", exporterOptions.TracingOptions.Endpoint.ToString());
Assert.False(((OtlpExporterOptions)exporterOptions.TracingOptions).AppendSignalPathToEndpoint);
var logRecordProcessorOptions = serviceProvider.GetRequiredService<IOptionsMonitor<LogRecordExportProcessorOptions>>().Get(name);
Assert.Equal(ExportProcessorType.Simple, logRecordProcessorOptions.ExportProcessorType);
Assert.Equal(1000, logRecordProcessorOptions.BatchExportProcessorOptions.ScheduledDelayMilliseconds);
var metricReaderOptions = serviceProvider.GetRequiredService<IOptionsMonitor<MetricReaderOptions>>().Get(name);
Assert.Equal(MetricReaderTemporalityPreference.Delta, metricReaderOptions.TemporalityPreference);
Assert.Equal(1001, metricReaderOptions.PeriodicExportingMetricReaderOptions.ExportIntervalMilliseconds);
var activityProcessorOptions = serviceProvider.GetRequiredService<IOptionsMonitor<ActivityExportProcessorOptions>>().Get(name);
Assert.Equal(ExportProcessorType.Simple, activityProcessorOptions.ExportProcessorType);
Assert.Equal(1002, activityProcessorOptions.BatchExportProcessorOptions.ScheduledDelayMilliseconds);
}
private sealed class TestLogRecordProcessor : BaseProcessor<LogRecord>
{
}
}