-
Notifications
You must be signed in to change notification settings - Fork 786
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[otlp] Add Log and Mertic Exporter to transmit custom serialized data (…
…#5977) Co-authored-by: Mikel Blanchard <[email protected]>
- Loading branch information
1 parent
1e7397e
commit 2ae01a7
Showing
9 changed files
with
286 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
127 changes: 127 additions & 0 deletions
127
src/OpenTelemetry.Exporter.OpenTelemetryProtocol/ProtobufOtlpLogExporter.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
using System.Buffers.Binary; | ||
using System.Diagnostics; | ||
using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation; | ||
using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.Serializer; | ||
using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.Transmission; | ||
using OpenTelemetry.Logs; | ||
using OpenTelemetry.Resources; | ||
|
||
namespace OpenTelemetry.Exporter; | ||
|
||
/// <summary> | ||
/// Exporter consuming <see cref="LogRecord"/> and exporting the data using | ||
/// the OpenTelemetry protocol (OTLP). | ||
/// </summary> | ||
internal sealed class ProtobufOtlpLogExporter : BaseExporter<LogRecord> | ||
{ | ||
private readonly SdkLimitOptions sdkLimitOptions; | ||
private readonly ExperimentalOptions experimentalOptions; | ||
private readonly ProtobufOtlpExporterTransmissionHandler transmissionHandler; | ||
private readonly int startWritePosition; | ||
|
||
private Resource? resource; | ||
|
||
// Initial buffer size set to ~732KB. | ||
// This choice allows us to gradually grow the buffer while targeting a final capacity of around 100 MB, | ||
// by the 7th doubling to maintain efficient allocation without frequent resizing. | ||
private byte[] buffer = new byte[750000]; | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="ProtobufOtlpLogExporter"/> class. | ||
/// </summary> | ||
/// <param name="options">Configuration options for the exporter.</param> | ||
public ProtobufOtlpLogExporter(OtlpExporterOptions options) | ||
: this(options, sdkLimitOptions: new(), experimentalOptions: new(), transmissionHandler: null) | ||
{ | ||
} | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="ProtobufOtlpLogExporter"/> class. | ||
/// </summary> | ||
/// <param name="exporterOptions"><see cref="OtlpExporterOptions"/>.</param> | ||
/// <param name="sdkLimitOptions"><see cref="SdkLimitOptions"/>.</param> | ||
/// <param name="experimentalOptions"><see cref="ExperimentalOptions"/>.</param> | ||
/// <param name="transmissionHandler"><see cref="OtlpExporterTransmissionHandler{T}"/>.</param> | ||
internal ProtobufOtlpLogExporter( | ||
OtlpExporterOptions exporterOptions, | ||
SdkLimitOptions sdkLimitOptions, | ||
ExperimentalOptions experimentalOptions, | ||
ProtobufOtlpExporterTransmissionHandler? transmissionHandler = null) | ||
{ | ||
Debug.Assert(exporterOptions != null, "exporterOptions was null"); | ||
Debug.Assert(sdkLimitOptions != null, "sdkLimitOptions was null"); | ||
Debug.Assert(experimentalOptions != null, "experimentalOptions was null"); | ||
|
||
this.experimentalOptions = experimentalOptions!; | ||
this.sdkLimitOptions = sdkLimitOptions!; | ||
this.startWritePosition = exporterOptions!.Protocol == OtlpExportProtocol.Grpc ? 5 : 0; | ||
this.transmissionHandler = transmissionHandler ?? exporterOptions!.GetProtobufExportTransmissionHandler(experimentalOptions!); | ||
} | ||
|
||
internal Resource Resource => this.resource ??= this.ParentProvider.GetResource(); | ||
|
||
/// <inheritdoc/> | ||
public override ExportResult Export(in Batch<LogRecord> logRecordBatch) | ||
{ | ||
// Prevents the exporter's gRPC and HTTP operations from being instrumented. | ||
using var scope = SuppressInstrumentationScope.Begin(); | ||
|
||
try | ||
{ | ||
int writePosition = ProtobufOtlpLogSerializer.WriteLogsData(this.buffer, this.startWritePosition, this.sdkLimitOptions, this.experimentalOptions, this.Resource, logRecordBatch); | ||
|
||
if (this.startWritePosition == 5) | ||
{ | ||
// Grpc payload consists of 3 parts | ||
// byte 0 - Specifying if the payload is compressed. | ||
// 1-4 byte - Specifies the length of payload in big endian format. | ||
// 5 and above - Protobuf serialized data. | ||
Span<byte> data = new Span<byte>(this.buffer, 1, 4); | ||
var dataLength = writePosition - 5; | ||
BinaryPrimitives.WriteUInt32BigEndian(data, (uint)dataLength); | ||
} | ||
|
||
if (!this.transmissionHandler.TrySubmitRequest(this.buffer, writePosition)) | ||
{ | ||
return ExportResult.Failure; | ||
} | ||
} | ||
catch (IndexOutOfRangeException) | ||
{ | ||
if (!this.IncreaseBufferSize()) | ||
{ | ||
throw; | ||
} | ||
} | ||
catch (Exception ex) | ||
{ | ||
OpenTelemetryProtocolExporterEventSource.Log.ExportMethodException(ex); | ||
return ExportResult.Failure; | ||
} | ||
|
||
return ExportResult.Success; | ||
} | ||
|
||
/// <inheritdoc /> | ||
protected override bool OnShutdown(int timeoutMilliseconds) => this.transmissionHandler?.Shutdown(timeoutMilliseconds) ?? true; | ||
|
||
// TODO: Consider moving this to a shared utility class. | ||
private bool IncreaseBufferSize() | ||
{ | ||
var newBufferSize = this.buffer.Length * 2; | ||
|
||
if (newBufferSize > 100 * 1024 * 1024) | ||
{ | ||
return false; | ||
} | ||
|
||
var newBuffer = new byte[newBufferSize]; | ||
this.buffer.CopyTo(newBuffer, 0); | ||
this.buffer = newBuffer; | ||
|
||
return true; | ||
} | ||
} |
120 changes: 120 additions & 0 deletions
120
src/OpenTelemetry.Exporter.OpenTelemetryProtocol/ProtobufOtlpMetricExporter.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
using System.Buffers.Binary; | ||
using System.Diagnostics; | ||
using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation; | ||
using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.Serializer; | ||
using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.Transmission; | ||
using OpenTelemetry.Metrics; | ||
using OpenTelemetry.Resources; | ||
|
||
namespace OpenTelemetry.Exporter; | ||
|
||
/// <summary> | ||
/// Exporter consuming <see cref="Metric"/> and exporting the data using | ||
/// the OpenTelemetry protocol (OTLP). | ||
/// </summary> | ||
internal sealed class ProtobufOtlpMetricExporter : BaseExporter<Metric> | ||
{ | ||
private readonly ProtobufOtlpExporterTransmissionHandler transmissionHandler; | ||
private readonly int startWritePosition; | ||
|
||
private Resource? resource; | ||
|
||
// Initial buffer size set to ~732KB. | ||
// This choice allows us to gradually grow the buffer while targeting a final capacity of around 100 MB, | ||
// by the 7th doubling to maintain efficient allocation without frequent resizing. | ||
private byte[] buffer = new byte[750000]; | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="ProtobufOtlpMetricExporter"/> class. | ||
/// </summary> | ||
/// <param name="options">Configuration options for the exporter.</param> | ||
public ProtobufOtlpMetricExporter(OtlpExporterOptions options) | ||
: this(options, experimentalOptions: new(), transmissionHandler: null) | ||
{ | ||
} | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="ProtobufOtlpMetricExporter"/> class. | ||
/// </summary> | ||
/// <param name="exporterOptions"><see cref="OtlpExporterOptions"/>.</param> | ||
/// <param name="experimentalOptions"><see cref="ExperimentalOptions"/>.</param> | ||
/// <param name="transmissionHandler"><see cref="OtlpExporterTransmissionHandler{T}"/>.</param> | ||
internal ProtobufOtlpMetricExporter( | ||
OtlpExporterOptions exporterOptions, | ||
ExperimentalOptions experimentalOptions, | ||
ProtobufOtlpExporterTransmissionHandler? transmissionHandler = null) | ||
{ | ||
Debug.Assert(exporterOptions != null, "exporterOptions was null"); | ||
Debug.Assert(experimentalOptions != null, "experimentalOptions was null"); | ||
|
||
this.startWritePosition = exporterOptions!.Protocol == OtlpExportProtocol.Grpc ? 5 : 0; | ||
this.transmissionHandler = transmissionHandler ?? exporterOptions!.GetProtobufExportTransmissionHandler(experimentalOptions!); | ||
} | ||
|
||
internal Resource Resource => this.resource ??= this.ParentProvider.GetResource(); | ||
|
||
/// <inheritdoc /> | ||
public override ExportResult Export(in Batch<Metric> metrics) | ||
{ | ||
// Prevents the exporter's gRPC and HTTP operations from being instrumented. | ||
using var scope = SuppressInstrumentationScope.Begin(); | ||
|
||
try | ||
{ | ||
int writePosition = ProtobufOtlpMetricSerializer.WriteMetricsData(this.buffer, this.startWritePosition, this.Resource, metrics); | ||
|
||
if (this.startWritePosition == 5) | ||
{ | ||
// Grpc payload consists of 3 parts | ||
// byte 0 - Specifying if the payload is compressed. | ||
// 1-4 byte - Specifies the length of payload in big endian format. | ||
// 5 and above - Protobuf serialized data. | ||
Span<byte> data = new Span<byte>(this.buffer, 1, 4); | ||
var dataLength = writePosition - 5; | ||
BinaryPrimitives.WriteUInt32BigEndian(data, (uint)dataLength); | ||
} | ||
|
||
if (!this.transmissionHandler.TrySubmitRequest(this.buffer, writePosition)) | ||
{ | ||
return ExportResult.Failure; | ||
} | ||
} | ||
catch (IndexOutOfRangeException) | ||
{ | ||
if (!this.IncreaseBufferSize()) | ||
{ | ||
throw; | ||
} | ||
} | ||
catch (Exception ex) | ||
{ | ||
OpenTelemetryProtocolExporterEventSource.Log.ExportMethodException(ex); | ||
return ExportResult.Failure; | ||
} | ||
|
||
return ExportResult.Success; | ||
} | ||
|
||
/// <inheritdoc /> | ||
protected override bool OnShutdown(int timeoutMilliseconds) => this.transmissionHandler.Shutdown(timeoutMilliseconds); | ||
|
||
// TODO: Consider moving this to a shared utility class. | ||
private bool IncreaseBufferSize() | ||
{ | ||
var newBufferSize = this.buffer.Length * 2; | ||
|
||
if (newBufferSize > 100 * 1024 * 1024) | ||
{ | ||
return false; | ||
} | ||
|
||
var newBuffer = new byte[newBufferSize]; | ||
this.buffer.CopyTo(newBuffer, 0); | ||
this.buffer = newBuffer; | ||
|
||
return true; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters