Skip to content

Commit

Permalink
Add HTTP/Protobuf exporter for OTLP Logs (#3225)
Browse files Browse the repository at this point in the history
  • Loading branch information
cijothomas authored Apr 22, 2022
1 parent 06d623b commit d1ec45c
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 6 deletions.
3 changes: 3 additions & 0 deletions examples/Console/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down
27 changes: 24 additions & 3 deletions examples/Console/TestLogs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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
{
Expand Down
4 changes: 4 additions & 0 deletions src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClient
{
/// <summary>Class for sending OTLP metrics export request over gRPC.</summary>
/// <summary>Class for sending OTLP Logs export request over gRPC.</summary>
internal sealed class OtlpGrpcLogExportClient : BaseOtlpGrpcExportClient<OtlpCollector.ExportLogsServiceRequest>
{
private readonly OtlpCollector.LogsService.LogsServiceClient logsClient;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// <copyright file="OtlpHttpLogExportClient.cs" company="OpenTelemetry Authors">
// 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.
// </copyright>

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
{
/// <summary>Class for sending OTLP log export request over HTTP.</summary>
internal sealed class OtlpHttpLogExportClient : BaseOtlpHttpExportClient<OtlpCollector.ExportLogsServiceRequest>
{
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);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -110,6 +111,16 @@ public static THeaders GetHeaders<THeaders>(this OtlpExporterOptions options, Ac
_ => throw new NotSupportedException($"Protocol {options.Protocol} is not supported."),
};

public static IExportClient<LogOtlpCollector.ExportLogsServiceRequest> 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
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,7 @@ internal OtlpLogExporter(OtlpExporterOptions options, IExportClient<OtlpCollecto
}
else
{
// TODO: this instantiation should be aligned with the protocol option (grpc or http/protobuf) when OtlpHttpMetricsExportClient will be implemented.
this.exportClient = new OtlpGrpcLogExportClient(options);
this.exportClient = options.GetLogExportClient();
}
}

Expand Down

0 comments on commit d1ec45c

Please sign in to comment.