diff --git a/Directory.Packages.props b/Directory.Packages.props index 7f7418ea3b0..bf588e7ddde 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -57,15 +57,6 @@ even during major version bumps, so compatibility is not a concern here. --> - - - - - - @@ -97,6 +88,9 @@ + + + diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md index 71e0e5899ac..08ae5ab9b67 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md @@ -7,6 +7,16 @@ Notes](../../RELEASENOTES.md). ## Unreleased +* **Breaking Change**: .NET Framework and .NET Standard builds now default to + exporting over OTLP/HTTP instead of OTLP/gRPC. **This change could result in a + failure to export telemetry unless appropriate measures are taken.** + Additionally, if you explicitly configure the exporter to use OTLP/gRPC it may + result in a `NotSupportedException` without further configuration. Please + carefully review issue + ([#6209](https://github.com/open-telemetry/opentelemetry-dotnet/pull/6209)) + for additional information and workarounds. + ([#6229](https://github.com/open-telemetry/opentelemetry-dotnet/pull/6229)) + ## 1.11.2 Released 2025-Mar-04 diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/GrpcExportClient.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/GrpcExportClient.cs deleted file mode 100644 index c3c0c8012c9..00000000000 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/GrpcExportClient.cs +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -#if NET462_OR_GREATER || NETSTANDARD2_0 -using Grpc.Core; -using OpenTelemetry.Internal; - -using InternalStatus = OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClient.Grpc.Status; -using InternalStatusCode = OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClient.Grpc.StatusCode; -using Status = Grpc.Core.Status; -using StatusCode = Grpc.Core.StatusCode; - -namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClient; - -internal sealed class GrpcExportClient : IExportClient -{ - private static readonly ExportClientGrpcResponse SuccessExportResponse = new( - success: true, - deadlineUtc: default, - exception: null, - status: null, - grpcStatusDetailsHeader: null); - - private static readonly Marshaller ByteArrayMarshaller = Marshallers.Create( - serializer: static input => input, - deserializer: static data => data); - - private readonly Method exportMethod; - - private readonly CallInvoker callInvoker; - - public GrpcExportClient(OtlpExporterOptions options, string signalPath) - { - Guard.ThrowIfNull(options); - Guard.ThrowIfInvalidTimeout(options.TimeoutMilliseconds); - Guard.ThrowIfNull(signalPath); - - var exporterEndpoint = options.Endpoint.AppendPathIfNotPresent(signalPath); - this.Endpoint = new UriBuilder(exporterEndpoint).Uri; - this.Channel = options.CreateChannel(); - this.Headers = options.GetMetadataFromHeaders(); - - var serviceAndMethod = signalPath.Split('/'); - this.exportMethod = new Method(MethodType.Unary, serviceAndMethod[0], serviceAndMethod[1], ByteArrayMarshaller, ByteArrayMarshaller); - this.callInvoker = this.Channel.CreateCallInvoker(); - } - - internal Channel Channel { get; } - - internal Uri Endpoint { get; } - - internal Metadata Headers { get; } - - public ExportClientResponse SendExportRequest(byte[] buffer, int contentLength, DateTime deadlineUtc, CancellationToken cancellationToken = default) - { - try - { - var contentSpan = buffer.AsSpan(0, contentLength); - this.callInvoker?.BlockingUnaryCall(this.exportMethod, null, new CallOptions(this.Headers, deadlineUtc, cancellationToken), contentSpan.ToArray()); - return SuccessExportResponse; - } - catch (RpcException rpcException) - { - OpenTelemetryProtocolExporterEventSource.Log.FailedToReachCollector(this.Endpoint, rpcException); - return new ExportClientGrpcResponse(success: false, deadlineUtc: deadlineUtc, exception: rpcException, ConvertGrpcStatusToStatus(rpcException.Status), rpcException.Trailers.ToString()); - } - } - - public bool Shutdown(int timeoutMilliseconds) - { - if (this.Channel == null) - { - return true; - } - - if (timeoutMilliseconds == -1) - { - this.Channel.ShutdownAsync().Wait(); - return true; - } - else - { - return Task.WaitAny([this.Channel.ShutdownAsync(), Task.Delay(timeoutMilliseconds)]) == 0; - } - } - - private static InternalStatus ConvertGrpcStatusToStatus(Status grpcStatus) => grpcStatus.StatusCode switch - { - StatusCode.OK => new InternalStatus(InternalStatusCode.OK, grpcStatus.Detail), - StatusCode.Cancelled => new InternalStatus(InternalStatusCode.Cancelled, grpcStatus.Detail), - StatusCode.Unknown => new InternalStatus(InternalStatusCode.Unknown, grpcStatus.Detail), - StatusCode.InvalidArgument => new InternalStatus(InternalStatusCode.InvalidArgument, grpcStatus.Detail), - StatusCode.DeadlineExceeded => new InternalStatus(InternalStatusCode.DeadlineExceeded, grpcStatus.Detail), - StatusCode.NotFound => new InternalStatus(InternalStatusCode.NotFound, grpcStatus.Detail), - StatusCode.AlreadyExists => new InternalStatus(InternalStatusCode.AlreadyExists, grpcStatus.Detail), - StatusCode.PermissionDenied => new InternalStatus(InternalStatusCode.PermissionDenied, grpcStatus.Detail), - StatusCode.Unauthenticated => new InternalStatus(InternalStatusCode.Unauthenticated, grpcStatus.Detail), - StatusCode.ResourceExhausted => new InternalStatus(InternalStatusCode.ResourceExhausted, grpcStatus.Detail), - StatusCode.FailedPrecondition => new InternalStatus(InternalStatusCode.FailedPrecondition, grpcStatus.Detail), - StatusCode.Aborted => new InternalStatus(InternalStatusCode.Aborted, grpcStatus.Detail), - StatusCode.OutOfRange => new InternalStatus(InternalStatusCode.OutOfRange, grpcStatus.Detail), - StatusCode.Unimplemented => new InternalStatus(InternalStatusCode.Unimplemented, grpcStatus.Detail), - StatusCode.Internal => new InternalStatus(InternalStatusCode.Internal, grpcStatus.Detail), - StatusCode.Unavailable => new InternalStatus(InternalStatusCode.Unavailable, grpcStatus.Detail), - StatusCode.DataLoss => new InternalStatus(InternalStatusCode.DataLoss, grpcStatus.Detail), - _ => new InternalStatus(InternalStatusCode.Unknown, grpcStatus.Detail), - }; -} -#endif diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/OtlpExportClient.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/OtlpExportClient.cs index 7347c69b271..8e56ba88cbc 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/OtlpExportClient.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/OtlpExportClient.cs @@ -35,7 +35,9 @@ protected OtlpExportClient(OtlpExporterOptions options, HttpClient httpClient, s Guard.ThrowIfNull(signalPath); Uri exporterEndpoint; +#pragma warning disable CS0618 // Suppressing gRPC obsolete warning if (options.Protocol == OtlpExportProtocol.Grpc) +#pragma warning restore CS0618 // Suppressing gRPC obsolete warning { exporterEndpoint = options.Endpoint.AppendPathIfNotPresent(signalPath); } diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OpenTelemetry.Exporter.OpenTelemetryProtocol.csproj b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OpenTelemetry.Exporter.OpenTelemetryProtocol.csproj index a29ba23649e..2277f25a16b 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OpenTelemetry.Exporter.OpenTelemetryProtocol.csproj +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OpenTelemetry.Exporter.OpenTelemetryProtocol.csproj @@ -23,10 +23,6 @@ - - - - diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExportProtocol.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExportProtocol.cs index 10375e1dfc6..806d3b9defc 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExportProtocol.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExportProtocol.cs @@ -11,6 +11,9 @@ public enum OtlpExportProtocol : byte /// /// OTLP over gRPC (corresponds to 'grpc' Protocol configuration option). Used as default. /// +#if NET462_OR_GREATER || NETSTANDARD2_0 + [Obsolete("CAUTION: OTLP/gRPC is no longer supported for .NET Framework or .NET Standard targets without supplying a properly configured HttpClientFactory. It is strongly encouraged that you migrate to using OTLP/HTTPPROTOBUF.")] +#endif Grpc = 0, /// diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExportProtocolParser.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExportProtocolParser.cs index e5e788c5617..563c6b8a6b8 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExportProtocolParser.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExportProtocolParser.cs @@ -10,7 +10,9 @@ public static bool TryParse(string value, out OtlpExportProtocol result) switch (value?.Trim()) { case "grpc": +#pragma warning disable CS0618 // Suppressing gRPC obsolete warning result = OtlpExportProtocol.Grpc; +#pragma warning restore CS0618 // Suppressing gRPC obsolete warning return true; case "http/protobuf": result = OtlpExportProtocol.HttpProtobuf; diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs index 355ab376743..91ebfdbd3e1 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs @@ -26,7 +26,11 @@ public class OtlpExporterOptions : IOtlpExporterOptions { internal const string DefaultGrpcEndpoint = "http://localhost:4317"; internal const string DefaultHttpEndpoint = "http://localhost:4318"; +#if NET462_OR_GREATER || NETSTANDARD2_0 + internal const OtlpExportProtocol DefaultOtlpExportProtocol = OtlpExportProtocol.HttpProtobuf; +#else internal const OtlpExportProtocol DefaultOtlpExportProtocol = OtlpExportProtocol.Grpc; +#endif internal static readonly KeyValuePair[] StandardHeaders = new KeyValuePair[] { @@ -84,7 +88,9 @@ public Uri Endpoint { if (this.endpoint == null) { +#pragma warning disable CS0618 // Suppressing gRPC obsolete warning return this.Protocol == OtlpExportProtocol.Grpc +#pragma warning restore CS0618 // Suppressing gRPC obsolete warning ? new Uri(DefaultGrpcEndpoint) : new Uri(DefaultHttpEndpoint); } diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptionsExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptionsExtensions.cs index 8a2956939db..73ac888cc68 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptionsExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptionsExtensions.cs @@ -9,9 +9,6 @@ using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation; using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClient; using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.Transmission; -#if NET462_OR_GREATER || NETSTANDARD2_0 -using Grpc.Core; -#endif namespace OpenTelemetry.Exporter; @@ -25,30 +22,6 @@ internal static class OtlpExporterOptionsExtensions private const string MetricsHttpServicePath = "v1/metrics"; private const string LogsHttpServicePath = "v1/logs"; -#if NET462_OR_GREATER || NETSTANDARD2_0 - public static Channel CreateChannel(this OtlpExporterOptions options) - { - if (options.Endpoint.Scheme != Uri.UriSchemeHttp && options.Endpoint.Scheme != Uri.UriSchemeHttps) - { - throw new NotSupportedException($"Endpoint URI scheme ({options.Endpoint.Scheme}) is not supported. Currently only \"http\" and \"https\" are supported."); - } - - ChannelCredentials channelCredentials; - if (options.Endpoint.Scheme == Uri.UriSchemeHttps) - { - channelCredentials = new SslCredentials(); - } - else - { - channelCredentials = ChannelCredentials.Insecure; - } - - return new Channel(options.Endpoint.Authority, channelCredentials); - } - - public static Metadata GetMetadataFromHeaders(this OtlpExporterOptions options) => options.GetHeaders((m, k, v) => m.Add(k, v)); -#endif - public static THeaders GetHeaders(this OtlpExporterOptions options, Action addHeader) where THeaders : new() { @@ -129,25 +102,12 @@ public static IExportClient GetExportClient(this OtlpExporterOptions options, Ot { var httpClient = options.HttpClientFactory?.Invoke() ?? throw new InvalidOperationException("OtlpExporterOptions was missing HttpClientFactory or it returned null."); +#pragma warning disable CS0618 // Suppressing gRPC obsolete warning if (options.Protocol != OtlpExportProtocol.Grpc && options.Protocol != OtlpExportProtocol.HttpProtobuf) { throw new NotSupportedException($"Protocol {options.Protocol} is not supported."); } -#if NET462_OR_GREATER || NETSTANDARD2_0 - if (options.Protocol == OtlpExportProtocol.Grpc) - { - var servicePath = otlpSignalType switch - { - OtlpSignalType.Traces => TraceGrpcServicePath, - OtlpSignalType.Metrics => MetricsGrpcServicePath, - OtlpSignalType.Logs => LogsGrpcServicePath, - _ => throw new NotSupportedException($"OtlpSignalType {otlpSignalType} is not supported."), - }; - return new GrpcExportClient(options, servicePath); - } -#endif - return otlpSignalType switch { OtlpSignalType.Traces => options.Protocol == OtlpExportProtocol.Grpc @@ -164,6 +124,7 @@ public static IExportClient GetExportClient(this OtlpExporterOptions options, Ot _ => throw new NotSupportedException($"OtlpSignalType {otlpSignalType} is not supported."), }; +#pragma warning restore CS0618 // Suppressing gRPC obsolete warning } public static void TryEnableIHttpClientFactoryIntegration(this OtlpExporterOptions options, IServiceProvider serviceProvider, string httpClientName) diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpLogExporterHelperExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpLogExporterHelperExtensions.cs index 42faf425356..1d69cfff851 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpLogExporterHelperExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpLogExporterHelperExtensions.cs @@ -284,6 +284,17 @@ internal static BaseProcessor BuildOtlpLogExporter( Debug.Assert(sdkLimitOptions != null, "sdkLimitOptions was null"); Debug.Assert(experimentalOptions != null, "experimentalOptions was null"); +#if NET462_OR_GREATER || NETSTANDARD2_0 +#pragma warning disable CS0618 // Suppressing gRPC obsolete warning + if (exporterOptions!.Protocol == OtlpExportProtocol.Grpc && + ReferenceEquals(exporterOptions.HttpClientFactory, exporterOptions.DefaultHttpClientFactory)) +#pragma warning restore CS0618 // Suppressing gRPC obsolete warning + { + throw new NotSupportedException("OtlpExportProtocol.Grpc with the default HTTP client factory is not supported on .NET Framework or .NET Standard 2.0." + + "Please switch to OtlpExportProtocol.HttpProtobuf or provide a custom HttpClientFactory."); + } +#endif + if (!skipUseOtlpExporterRegistrationCheck) { serviceProvider!.EnsureNoUseOtlpExporterRegistrations(); diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpMetricExporterExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpMetricExporterExtensions.cs index 1a8ef2f1b42..2a08c7d0a1a 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpMetricExporterExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpMetricExporterExtensions.cs @@ -168,6 +168,17 @@ internal static MetricReader BuildOtlpExporterMetricReader( Debug.Assert(metricReaderOptions != null, "metricReaderOptions was null"); Debug.Assert(experimentalOptions != null, "experimentalOptions was null"); +#if NET462_OR_GREATER || NETSTANDARD2_0 +#pragma warning disable CS0618 // Suppressing gRPC obsolete warning + if (exporterOptions!.Protocol == OtlpExportProtocol.Grpc && + ReferenceEquals(exporterOptions.HttpClientFactory, exporterOptions.DefaultHttpClientFactory)) +#pragma warning restore CS0618 // Suppressing gRPC obsolete warning + { + throw new NotSupportedException("OtlpExportProtocol.Grpc with the default HTTP client factory is not supported on .NET Framework or .NET Standard 2.0." + + "Please switch to OtlpExportProtocol.HttpProtobuf or provide a custom HttpClientFactory."); + } +#endif + if (!skipUseOtlpExporterRegistrationCheck) { serviceProvider!.EnsureNoUseOtlpExporterRegistrations(); diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpTraceExporterHelperExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpTraceExporterHelperExtensions.cs index 3a18b3da423..f892201983b 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpTraceExporterHelperExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpTraceExporterHelperExtensions.cs @@ -129,6 +129,17 @@ internal static BaseProcessor BuildOtlpExporterProcessor( Debug.Assert(experimentalOptions != null, "experimentalOptions was null"); Debug.Assert(batchExportProcessorOptions != null, "batchExportProcessorOptions was null"); +#if NET462_OR_GREATER || NETSTANDARD2_0 +#pragma warning disable CS0618 // Suppressing gRPC obsolete warning + if (exporterOptions!.Protocol == OtlpExportProtocol.Grpc && + ReferenceEquals(exporterOptions.HttpClientFactory, exporterOptions.DefaultHttpClientFactory)) +#pragma warning restore CS0618 // Suppressing gRPC obsolete warning + { + throw new NotSupportedException("OtlpExportProtocol.Grpc with the default HTTP client factory is not supported on .NET Framework or .NET Standard 2.0." + + "Please switch to OtlpExportProtocol.HttpProtobuf or provide a custom HttpClientFactory."); + } +#endif + if (!skipUseOtlpExporterRegistrationCheck) { serviceProvider!.EnsureNoUseOtlpExporterRegistrations(); diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/IntegrationTest/IntegrationTests.cs b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/IntegrationTest/IntegrationTests.cs index 3e40b9c6d9f..eb97a2260ec 100644 --- a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/IntegrationTest/IntegrationTests.cs +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/IntegrationTest/IntegrationTests.cs @@ -34,6 +34,7 @@ public void Dispose() this.openTelemetryEventListener.Dispose(); } +#pragma warning disable CS0618 // Suppressing gRPC obsolete warning [InlineData(OtlpExportProtocol.Grpc, ":4317", ExportProcessorType.Batch, false)] [InlineData(OtlpExportProtocol.HttpProtobuf, ":4318/v1/traces", ExportProcessorType.Batch, false)] [InlineData(OtlpExportProtocol.Grpc, ":4317", ExportProcessorType.Batch, true)] @@ -44,6 +45,7 @@ public void Dispose() [InlineData(OtlpExportProtocol.HttpProtobuf, ":4318/v1/traces", ExportProcessorType.Simple, true)] [InlineData(OtlpExportProtocol.Grpc, ":5317", ExportProcessorType.Simple, true, "https")] [InlineData(OtlpExportProtocol.HttpProtobuf, ":5318/v1/traces", ExportProcessorType.Simple, true, "https")] +#pragma warning restore CS0618 // Suppressing gRPC obsolete warning [Trait("CategoryName", "CollectorIntegrationTests")] [SkipUnlessEnvVarFoundTheory(CollectorHostnameEnvVarName)] public void TraceExportResultIsSuccess(OtlpExportProtocol protocol, string endpoint, ExportProcessorType exportProcessorType, bool forceFlush, string scheme = "http") @@ -118,6 +120,7 @@ public void TraceExportResultIsSuccess(OtlpExportProtocol protocol, string endpo } } +#pragma warning disable CS0618 // Suppressing gRPC obsolete warning [InlineData(OtlpExportProtocol.Grpc, ":4317", false, false)] [InlineData(OtlpExportProtocol.HttpProtobuf, ":4318/v1/metrics", false, false)] [InlineData(OtlpExportProtocol.Grpc, ":4317", false, true)] @@ -128,6 +131,7 @@ public void TraceExportResultIsSuccess(OtlpExportProtocol protocol, string endpo [InlineData(OtlpExportProtocol.HttpProtobuf, ":4318/v1/metrics", true, true)] [InlineData(OtlpExportProtocol.Grpc, ":5317", true, true, "https")] [InlineData(OtlpExportProtocol.HttpProtobuf, ":5318/v1/metrics", true, true, "https")] +#pragma warning restore CS0618 // Suppressing gRPC obsolete warning [Trait("CategoryName", "CollectorIntegrationTests")] [SkipUnlessEnvVarFoundTheory(CollectorHostnameEnvVarName)] public void MetricExportResultIsSuccess(OtlpExportProtocol protocol, string endpoint, bool useManualExport, bool forceFlush, string scheme = "http") @@ -202,12 +206,14 @@ public void MetricExportResultIsSuccess(OtlpExportProtocol protocol, string endp } } +#pragma warning disable CS0618 // Suppressing gRPC obsolete warning [InlineData(OtlpExportProtocol.Grpc, ":4317", ExportProcessorType.Batch)] [InlineData(OtlpExportProtocol.HttpProtobuf, ":4318/v1/logs", ExportProcessorType.Batch)] [InlineData(OtlpExportProtocol.Grpc, ":4317", ExportProcessorType.Simple)] [InlineData(OtlpExportProtocol.HttpProtobuf, ":4318/v1/logs", ExportProcessorType.Simple)] [InlineData(OtlpExportProtocol.Grpc, ":5317", ExportProcessorType.Simple, "https")] [InlineData(OtlpExportProtocol.HttpProtobuf, ":5318/v1/logs", ExportProcessorType.Simple, "https")] +#pragma warning restore CS0618 // Suppressing gRPC obsolete warning [Trait("CategoryName", "CollectorIntegrationTests")] [SkipUnlessEnvVarFoundTheory(CollectorHostnameEnvVarName)] public void LogExportResultIsSuccess(OtlpExportProtocol protocol, string endpoint, ExportProcessorType exportProcessorType, string scheme = "http") diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpExportProtocolParserTests.cs b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpExportProtocolParserTests.cs index b4b2917491b..c2fdc81eb2e 100644 --- a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpExportProtocolParserTests.cs +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpExportProtocolParserTests.cs @@ -8,7 +8,9 @@ namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests; public class OtlpExportProtocolParserTests { [Theory] +#pragma warning disable CS0618 // Suppressing gRPC obsolete warning [InlineData("grpc", true, OtlpExportProtocol.Grpc)] +#pragma warning restore CS0618 // Suppressing gRPC obsolete warning [InlineData("http/protobuf", true, OtlpExportProtocol.HttpProtobuf)] [InlineData("unsupported", false, default(OtlpExportProtocol))] public void TryParse_Protocol_MapsToCorrectValue(string protocol, bool expectedResult, OtlpExportProtocol expectedExportProtocol) diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpExporterHelperExtensionsTests.cs b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpExporterHelperExtensionsTests.cs new file mode 100644 index 00000000000..4dcd98eb22d --- /dev/null +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpExporterHelperExtensionsTests.cs @@ -0,0 +1,138 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#if NET462_OR_GREATER || NETSTANDARD2_0 +#pragma warning disable CS0618 // Suppressing gRPC obsolete warning +using System.Net.Http; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using OpenTelemetry.Logs; +using OpenTelemetry.Metrics; +using OpenTelemetry.Trace; +using Xunit; + +namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests; + +public class OtlpExporterHelperExtensionsTests +{ + [Fact] + public void OtlpExporter_Throws_OnGrpcWithDefaultFactory_ForTracing() + { + var services = new ServiceCollection(); + services.AddOpenTelemetry() + .WithTracing(tracing => tracing.AddOtlpExporter(options => options.Protocol = OtlpExportProtocol.Grpc)); + + using var sp = services.BuildServiceProvider(); + + Assert.Throws(() => sp.GetRequiredService()); + + var tracerProviderBuilder = Sdk.CreateTracerProviderBuilder() + .AddOtlpExporter(o => o.Protocol = OtlpExportProtocol.Grpc); + + Assert.Throws(() => tracerProviderBuilder.Build()); + } + + [Fact] + public void OtlpExporter_Throws_OnGrpcWithDefaultFactory_ForMetrics() + { + var services = new ServiceCollection(); + + services.AddOpenTelemetry() + .WithMetrics(metrics => metrics.AddOtlpExporter(options => options.Protocol = OtlpExportProtocol.Grpc)); + + using var sp = services.BuildServiceProvider(); + + Assert.Throws(() => sp.GetRequiredService()); + + var meterProviderBuilder = Sdk.CreateMeterProviderBuilder() + .AddOtlpExporter(o => o.Protocol = OtlpExportProtocol.Grpc); + + Assert.Throws(() => meterProviderBuilder.Build()); + } + + [Fact] + public void OtlpExporter_Throws_OnGrpcWithDefaultFactory_ForLogging() + { + var services = new ServiceCollection(); + + services.AddOpenTelemetry() + .WithLogging(builder => builder.AddOtlpExporter(options => options.Protocol = OtlpExportProtocol.Grpc)); + + using var sp = services.BuildServiceProvider(); + + Assert.Throws(() => sp.GetRequiredService()); + + Assert.Throws(() => LoggerFactory.Create(builder => + { + builder.AddOpenTelemetry(logging => + { + logging.AddOtlpExporter(o => o.Protocol = OtlpExportProtocol.Grpc); + }); + })); + } + + [Fact] + public void OtlpExporter_DoesNotThrow_WhenCustomHttpClientFactoryIsSet_ForTraces() + { + var services = new ServiceCollection(); + + services.AddOpenTelemetry() + .WithTracing(builder => + { + builder.AddOtlpExporter(options => + { + options.Protocol = OtlpExportProtocol.Grpc; + options.HttpClientFactory = () => new HttpClient(); + }); + }); + + using var sp = services.BuildServiceProvider(); + + var tracerProvider = sp.GetRequiredService(); + Assert.NotNull(tracerProvider); + } + + [Fact] + public void OtlpExporter_DoesNotThrow_WhenCustomHttpClientFactoryIsSet_ForMetrics() + { + var services = new ServiceCollection(); + + services.AddOpenTelemetry() + .WithMetrics(builder => + { + builder.AddOtlpExporter(options => + { + options.Protocol = OtlpExportProtocol.Grpc; + options.HttpClientFactory = () => new HttpClient(); + }); + }); + + using var sp = services.BuildServiceProvider(); + + var meterProvider = sp.GetRequiredService(); + Assert.NotNull(meterProvider); + } + + [Fact] + public void OtlpExporter_DoesNotThrow_WhenCustomHttpClientFactoryIsSet_ForLogging() + { + var services = new ServiceCollection(); + + services.AddOpenTelemetry() + .WithLogging(builder => + { + builder.AddOtlpExporter(options => + { + options.Protocol = OtlpExportProtocol.Grpc; + options.HttpClientFactory = () => new HttpClient(); + }); + }); + + using var sp = services.BuildServiceProvider(); + + var loggerProvider = sp.GetRequiredService(); + Assert.NotNull(loggerProvider); + } +} +#pragma warning restore CS0618 // Suppressing gRPC obsolete warning +#endif diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpExporterOptionsExtensionsTests.cs b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpExporterOptionsExtensionsTests.cs index 00696f57b0c..f1e3a5fd5fa 100644 --- a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpExporterOptionsExtensionsTests.cs +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpExporterOptionsExtensionsTests.cs @@ -61,11 +61,9 @@ public void GetHeaders_ValidAndUrlEncodedHeaders_ReturnsCorrectHeaders(string in } [Theory] -#if NET462_OR_GREATER - [InlineData(OtlpExportProtocol.Grpc, typeof(GrpcExportClient))] -#else +#pragma warning disable CS0618 // Suppressing gRPC obsolete warning [InlineData(OtlpExportProtocol.Grpc, typeof(OtlpGrpcExportClient))] -#endif +#pragma warning restore CS0618 // Suppressing gRPC obsolete warning [InlineData(OtlpExportProtocol.HttpProtobuf, typeof(OtlpHttpExportClient))] public void GetTraceExportClient_SupportedProtocol_ReturnsCorrectExportClient(OtlpExportProtocol protocol, Type expectedExportClientType) { @@ -105,15 +103,11 @@ public void AppendPathIfNotPresent_TracesPath_AppendsCorrectly(string inputUri, } [Theory] -#if NET462_OR_GREATER - [InlineData(OtlpExportProtocol.Grpc, typeof(GrpcExportClient), false, 10000, null)] - [InlineData(OtlpExportProtocol.Grpc, typeof(GrpcExportClient), false, 10000, "in_memory")] - [InlineData(OtlpExportProtocol.Grpc, typeof(GrpcExportClient), false, 10000, "disk")] -#else +#pragma warning disable CS0618 // Suppressing gRPC obsolete warning [InlineData(OtlpExportProtocol.Grpc, typeof(OtlpGrpcExportClient), false, 10000, null)] [InlineData(OtlpExportProtocol.Grpc, typeof(OtlpGrpcExportClient), false, 10000, "in_memory")] [InlineData(OtlpExportProtocol.Grpc, typeof(OtlpGrpcExportClient), false, 10000, "disk")] -#endif +#pragma warning restore CS0618 // Suppressing gRPC obsolete warning [InlineData(OtlpExportProtocol.HttpProtobuf, typeof(OtlpHttpExportClient), false, 10000, null)] [InlineData(OtlpExportProtocol.HttpProtobuf, typeof(OtlpHttpExportClient), true, 8000, null)] [InlineData(OtlpExportProtocol.HttpProtobuf, typeof(OtlpHttpExportClient), false, 10000, "in_memory")] diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpExporterOptionsTests.cs b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpExporterOptionsTests.cs index c22f0e14863..b0fcee2f48d 100644 --- a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpExporterOptionsTests.cs +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpExporterOptionsTests.cs @@ -24,7 +24,12 @@ public void OtlpExporterOptions_Defaults() { var options = new OtlpExporterOptions(); +#if NET462_OR_GREATER || NETSTANDARD2_0 + Assert.Equal(new Uri(OtlpExporterOptions.DefaultHttpEndpoint), options.Endpoint); +#else Assert.Equal(new Uri(OtlpExporterOptions.DefaultGrpcEndpoint), options.Endpoint); +#endif + Assert.Null(options.Headers); Assert.Equal(10000, options.TimeoutMilliseconds); Assert.Equal(OtlpExporterOptions.DefaultOtlpExportProtocol, options.Protocol); @@ -95,7 +100,12 @@ public void OtlpExporterOptions_InvalidEnvironmentVariableOverride() "NoopHeaders", "TimeoutWithInvalidValue"); +#if NET462_OR_GREATER || NETSTANDARD2_0 + Assert.Equal(new Uri(OtlpExporterOptions.DefaultHttpEndpoint), options.Endpoint); +#else Assert.Equal(new Uri(OtlpExporterOptions.DefaultGrpcEndpoint), options.Endpoint); +#endif + Assert.Equal(10000, options.TimeoutMilliseconds); Assert.Equal(OtlpExporterOptions.DefaultOtlpExportProtocol, options.Protocol); Assert.Null(options.Headers); @@ -143,14 +153,20 @@ public void OtlpExporterOptions_EndpointGetterUsesProtocolWhenNull() { var options = new OtlpExporterOptions(); +#if NET462_OR_GREATER || NETSTANDARD2_0 + Assert.Equal(new Uri(OtlpExporterOptions.DefaultHttpEndpoint), options.Endpoint); +#else Assert.Equal(new Uri(OtlpExporterOptions.DefaultGrpcEndpoint), options.Endpoint); +#endif + Assert.Equal(OtlpExporterOptions.DefaultOtlpExportProtocol, options.Protocol); options.Protocol = OtlpExportProtocol.HttpProtobuf; Assert.Equal(new Uri(OtlpExporterOptions.DefaultHttpEndpoint), options.Endpoint); - +#pragma warning disable CS0618 // Suppressing gRPC obsolete warning options.Protocol = OtlpExportProtocol.Grpc; +#pragma warning restore CS0618 // Suppressing gRPC obsolete warning Assert.Equal(new Uri(OtlpExporterOptions.DefaultGrpcEndpoint), options.Endpoint); } @@ -158,10 +174,12 @@ public void OtlpExporterOptions_EndpointGetterUsesProtocolWhenNull() [Fact] public void OtlpExporterOptions_EndpointThrowsWhenSetToNull() { +#pragma warning disable CS0618 // Suppressing gRPC obsolete warning var options = new OtlpExporterOptions { Endpoint = new Uri("http://test:8888"), Protocol = OtlpExportProtocol.Grpc }; Assert.Equal(new Uri("http://test:8888"), options.Endpoint); Assert.Equal(OtlpExportProtocol.Grpc, options.Protocol); +#pragma warning restore CS0618 // Suppressing gRPC obsolete warning } [Fact] @@ -210,7 +228,9 @@ public void OtlpExporterOptions_ApplyDefaultsTest() var targetOptionsWithData = new OtlpExporterOptions { Endpoint = new Uri("http://metrics_endpoint/"), +#pragma warning disable CS0618 // Suppressing gRPC obsolete warning Protocol = OtlpExportProtocol.Grpc, +#pragma warning restore CS0618 // Suppressing gRPC obsolete warning Headers = "key2=value2", TimeoutMilliseconds = 1800, HttpClientFactory = () => throw new NotImplementedException(), diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/UseOtlpExporterExtensionTests.cs b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/UseOtlpExporterExtensionTests.cs index 467ed6c0c25..67160d2c3fd 100644 --- a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/UseOtlpExporterExtensionTests.cs +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/UseOtlpExporterExtensionTests.cs @@ -38,7 +38,12 @@ public void UseOtlpExporterDefaultTest() var exporterOptions = sp.GetRequiredService>().CurrentValue; +#if NET462_OR_GREATER || NETSTANDARD2_0 + Assert.Equal(new Uri(OtlpExporterOptions.DefaultHttpEndpoint), exporterOptions.DefaultOptions.Endpoint); +#else Assert.Equal(new Uri(OtlpExporterOptions.DefaultGrpcEndpoint), exporterOptions.DefaultOptions.Endpoint); +#endif + Assert.Equal(OtlpExporterOptions.DefaultOtlpExportProtocol, exporterOptions.DefaultOptions.Protocol); Assert.False(((OtlpExporterOptions)exporterOptions.DefaultOptions).HasData); @@ -48,7 +53,9 @@ public void UseOtlpExporterDefaultTest() } [Theory] +#pragma warning disable CS0618 // Suppressing gRPC obsolete warning [InlineData(OtlpExportProtocol.Grpc)] +#pragma warning restore CS0618 // Suppressing gRPC obsolete warning [InlineData(OtlpExportProtocol.HttpProtobuf)] public void UseOtlpExporterSetEndpointAndProtocolTest(OtlpExportProtocol protocol) {