Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add HTTP/Protobuf exporter for OTLP Logs #3225

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
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
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
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