diff --git a/examples/Console/Program.cs b/examples/Console/Program.cs
index 44bab047881..ae80904ba5e 100644
--- a/examples/Console/Program.cs
+++ b/examples/Console/Program.cs
@@ -169,6 +169,9 @@ internal class LogsOptions
{
[Option("useExporter", Default = "otlp", HelpText = "Options include otlp or console.", Required = false)]
public string UseExporter { get; set; }
+
+ [Option('p', "protocol", HelpText = "Transport protocol used by OTLP exporter. Supported values: grpc and http/protobuf. Only applicable if Exporter is OTLP", Default = "grpc")]
+ public string Protocol { get; set; }
}
[Verb("inmemory", HelpText = "Specify the options required to test InMemory Exporter")]
diff --git a/examples/Console/TestLogs.cs b/examples/Console/TestLogs.cs
index f508651bef6..76158593796 100644
--- a/examples/Console/TestLogs.cs
+++ b/examples/Console/TestLogs.cs
@@ -40,10 +40,10 @@ internal static object Run(LogsOptions options)
* launch the OpenTelemetry Collector with an OTLP receiver, by running:
*
* - On Unix based systems use:
- * docker run --rm -it -p 4317:4317 -v $(pwd):/cfg otel/opentelemetry-collector:0.33.0 --config=/cfg/otlp-collector-example/config.yaml
+ * docker run --rm -it -p 4317:4317 -p 4318:4318 -v $(pwd):/cfg otel/opentelemetry-collector:0.48.0 --config=/cfg/otlp-collector-example/config.yaml
*
* - On Windows use:
- * docker run --rm -it -p 4317:4317 -v "%cd%":/cfg otel/opentelemetry-collector:0.33.0 --config=/cfg/otlp-collector-example/config.yaml
+ * docker run --rm -it -p 4317:4317 -p 4318:4318 -v "%cd%":/cfg otel/opentelemetry-collector:0.48.0 --config=/cfg/otlp-collector-example/config.yaml
*
* Open another terminal window at the examples/Console/ directory and
* launch the OTLP example by running:
@@ -59,7 +59,28 @@ internal static object Run(LogsOptions options)
// See: https://docs.microsoft.com/aspnet/core/grpc/troubleshoot#call-insecure-grpc-services-with-net-core-client
AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
- opt.AddOtlpExporter();
+ if (options.Protocol.Trim().ToLower().Equals("grpc"))
+ {
+ opt.AddOtlpExporter(otlpOptions =>
+ {
+ otlpOptions.Protocol = OpenTelemetry.Exporter.OtlpExportProtocol.Grpc;
+ });
+ }
+ else if (options.Protocol.Trim().ToLower().Equals("http/protobuf"))
+ {
+ opt.AddOtlpExporter(otlpOptions =>
+ {
+ otlpOptions.Protocol = OpenTelemetry.Exporter.OtlpExportProtocol.HttpProtobuf;
+ });
+ }
+ else
+ {
+ System.Console.WriteLine($"Export protocol {options.Protocol} is not supported. Default protocol 'grpc' will be used.");
+ opt.AddOtlpExporter(otlpOptions =>
+ {
+ otlpOptions.Protocol = OpenTelemetry.Exporter.OtlpExportProtocol.Grpc;
+ });
+ }
}
else
{
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md
index 8bca96958d4..72c51b40b71 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md
@@ -5,6 +5,10 @@
* LogExporter to support Logging Scopes.
([#3277](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3217))
+* Support `HttpProtobuf` protocol with logs & added `HttpClientFactory`
+option
+([#3224](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3224))
+
## 1.3.0-beta.1
Released 2022-Apr-15
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/OtlpGrpcLogExportClient.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/OtlpGrpcLogExportClient.cs
index 1a87f48d5e3..2e5d03d6c16 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/OtlpGrpcLogExportClient.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/OtlpGrpcLogExportClient.cs
@@ -21,7 +21,7 @@
namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClient
{
- /// Class for sending OTLP metrics export request over gRPC.
+ /// Class for sending OTLP Logs export request over gRPC.
internal sealed class OtlpGrpcLogExportClient : BaseOtlpGrpcExportClient
{
private readonly OtlpCollector.LogsService.LogsServiceClient logsClient;
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/OtlpHttpLogExportClient.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/OtlpHttpLogExportClient.cs
new file mode 100644
index 00000000000..b30c199ca4c
--- /dev/null
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/OtlpHttpLogExportClient.cs
@@ -0,0 +1,86 @@
+//
+// 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.IO;
+using System.Net;
+using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Runtime.CompilerServices;
+#if NET5_0_OR_GREATER
+using System.Threading;
+#endif
+using System.Threading.Tasks;
+using Google.Protobuf;
+using OtlpCollector = Opentelemetry.Proto.Collector.Logs.V1;
+
+namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClient
+{
+ /// Class for sending OTLP log export request over HTTP.
+ internal sealed class OtlpHttpLogExportClient : BaseOtlpHttpExportClient
+ {
+ internal const string MediaContentType = "application/x-protobuf";
+ private const string LogsExportPath = "v1/logs";
+
+ public OtlpHttpLogExportClient(OtlpExporterOptions options, HttpClient httpClient)
+ : base(options, httpClient, LogsExportPath)
+ {
+ }
+
+ protected override HttpContent CreateHttpContent(OtlpCollector.ExportLogsServiceRequest exportRequest)
+ {
+ return new ExportRequestContent(exportRequest);
+ }
+
+ internal sealed class ExportRequestContent : HttpContent
+ {
+ private static readonly MediaTypeHeaderValue ProtobufMediaTypeHeader = new(MediaContentType);
+
+ private readonly OtlpCollector.ExportLogsServiceRequest exportRequest;
+
+ public ExportRequestContent(OtlpCollector.ExportLogsServiceRequest exportRequest)
+ {
+ this.exportRequest = exportRequest;
+ this.Headers.ContentType = ProtobufMediaTypeHeader;
+ }
+
+#if NET5_0_OR_GREATER
+ protected override void SerializeToStream(Stream stream, TransportContext context, CancellationToken cancellationToken)
+ {
+ this.SerializeToStreamInternal(stream);
+ }
+#endif
+
+ protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
+ {
+ this.SerializeToStreamInternal(stream);
+ return Task.CompletedTask;
+ }
+
+ protected override bool TryComputeLength(out long length)
+ {
+ // We can't know the length of the content being pushed to the output stream.
+ length = -1;
+ return false;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void SerializeToStreamInternal(Stream stream)
+ {
+ this.exportRequest.WriteTo(stream);
+ }
+ }
+ }
+}
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptionsExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptionsExtensions.cs
index 6c3005ccf40..7fee9f5a76f 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptionsExtensions.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptionsExtensions.cs
@@ -22,6 +22,7 @@
#if NETSTANDARD2_1 || NET5_0_OR_GREATER
using Grpc.Net.Client;
#endif
+using LogOtlpCollector = Opentelemetry.Proto.Collector.Logs.V1;
using MetricsOtlpCollector = Opentelemetry.Proto.Collector.Metrics.V1;
using TraceOtlpCollector = Opentelemetry.Proto.Collector.Trace.V1;
@@ -110,6 +111,16 @@ public static THeaders GetHeaders(this OtlpExporterOptions options, Ac
_ => throw new NotSupportedException($"Protocol {options.Protocol} is not supported."),
};
+ public static IExportClient GetLogExportClient(this OtlpExporterOptions options) =>
+ options.Protocol switch
+ {
+ OtlpExportProtocol.Grpc => new OtlpGrpcLogExportClient(options),
+ OtlpExportProtocol.HttpProtobuf => new OtlpHttpLogExportClient(
+ options,
+ options.HttpClientFactory?.Invoke() ?? throw new InvalidOperationException("OtlpExporterOptions was missing HttpClientFactory or it returned null.")),
+ _ => throw new NotSupportedException($"Protocol {options.Protocol} is not supported."),
+ };
+
public static OtlpExportProtocol? ToOtlpExportProtocol(this string protocol) =>
protocol.Trim() switch
{
diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpLogExporter.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpLogExporter.cs
index 22fdd978d4d..a712646cd7d 100644
--- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpLogExporter.cs
+++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpLogExporter.cs
@@ -55,8 +55,7 @@ internal OtlpLogExporter(OtlpExporterOptions options, IExportClient