Skip to content

Commit 305597d

Browse files
[otlp] Fix TODOs, Refactor Buffer Size Handling, and Cleanup Environment Variables (open-telemetry#6009)
Co-authored-by: Mikel Blanchard <[email protected]>
1 parent 0c775e5 commit 305597d

File tree

13 files changed

+82
-106
lines changed

13 files changed

+82
-106
lines changed

src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Builder/OpenTelemetryBuilderOtlpExporterExtensions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,8 @@ internal static IOpenTelemetryBuilder UseOtlpExporter(
8888
/// <para><see cref="IConfiguration"/> to bind onto <see cref="OtlpExporterBuilderOptions"/>.</para>
8989
/// <para>Notes:
9090
/// <list type="bullet">
91-
/// <item docLink="true">See [TODO:Add doc link] for details on the configuration
92-
/// schema.</item>
91+
/// <item docLink="true"><see href="https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md"/>
92+
/// for details on the configuration schema.</item>
9393
/// <item>The <see cref="OtlpExporterBuilderOptions"/> instance will be
9494
/// named "otlp" by default when calling this method.</item>
9595
/// </list>

src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExperimentalOptions.cs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@ internal sealed class ExperimentalOptions
1717

1818
public const string OtlpDiskRetryDirectoryPathEnvVar = "OTEL_DOTNET_EXPERIMENTAL_OTLP_DISK_RETRY_DIRECTORY_PATH";
1919

20-
public const string OtlpUseCustomSerializer = "OTEL_DOTNET_EXPERIMENTAL_USE_CUSTOM_PROTOBUF_SERIALIZER";
21-
2220
public ExperimentalOptions()
2321
: this(new ConfigurationBuilder().AddEnvironmentVariables().Build())
2422
{
@@ -31,11 +29,6 @@ public ExperimentalOptions(IConfiguration configuration)
3129
this.EmitLogEventAttributes = emitLogEventAttributes;
3230
}
3331

34-
if (configuration.TryGetBoolValue(OpenTelemetryProtocolExporterEventSource.Log, OtlpUseCustomSerializer, out var useCustomSerializer))
35-
{
36-
this.UseCustomProtobufSerializer = useCustomSerializer;
37-
}
38-
3932
if (configuration.TryGetStringValue(OtlpRetryEnvVar, out var retryPolicy) && retryPolicy != null)
4033
{
4134
if (retryPolicy.Equals("in_memory", StringComparison.OrdinalIgnoreCase))
@@ -85,9 +78,4 @@ public ExperimentalOptions(IConfiguration configuration)
8578
/// Gets the path on disk where the telemetry will be stored for retries at a later point.
8679
/// </summary>
8780
public string? DiskRetryDirectoryPath { get; }
88-
89-
/// <summary>
90-
/// Gets a value indicating whether custom serializer should be used for OTLP export.
91-
/// </summary>
92-
public bool UseCustomProtobufSerializer { get; }
9381
}

src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/Grpc/GrpcStatusDeserializer.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ internal static class GrpcStatusDeserializer
2626
TimeSpan.FromTicks(retryInfo.Value.RetryDelay.Value.Nanos / 100); // Convert nanos to ticks
2727
}
2828
}
29-
catch
29+
catch (Exception ex)
3030
{
31-
// TODO: Log exception to event source.
31+
OpenTelemetryProtocolExporterEventSource.Log.GrpcRetryDelayParsingFailed(grpcStatusDetailsHeader, ex);
3232
return null;
3333
}
3434

src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OpenTelemetryProtocolExporterEventSource.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,15 @@ public void RequestTimedOut(Uri endpoint, Exception ex)
8585
}
8686
}
8787

88+
[NonEvent]
89+
public void GrpcRetryDelayParsingFailed(string? grpcStatusDetailsHeader, Exception ex)
90+
{
91+
if (Log.IsEnabled(EventLevel.Warning, EventKeywords.All))
92+
{
93+
this.GrpcRetryDelayParsingFailed(grpcStatusDetailsHeader ?? "null", ex.ToInvariantString());
94+
}
95+
}
96+
8897
[Event(2, Message = "Exporter failed send data to collector to {0} endpoint. Data will not be sent. Exception: {1}", Level = EventLevel.Error)]
8998
public void FailedToReachCollector(string rawCollectorUri, string ex)
9099
{
@@ -205,6 +214,12 @@ public void ExportFailure(string endpoint, string message)
205214
this.WriteEvent(23, endpoint, message);
206215
}
207216

217+
[Event(24, Message = "Failed to parse gRPC retry delay from header grpcStatusDetailsHeader: '{0}'. Exception: {1}", Level = EventLevel.Warning)]
218+
public void GrpcRetryDelayParsingFailed(string grpcStatusDetailsHeader, string exception)
219+
{
220+
this.WriteEvent(24, grpcStatusDetailsHeader, exception);
221+
}
222+
208223
void IConfigurationExtensionsLogger.LogInvalidConfigurationValue(string key, string value)
209224
{
210225
this.InvalidConfigurationValue(key, value);

src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Serializer/ProtobufOtlpLogSerializer.cs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,32 @@ internal static int WriteLogsData(byte[] buffer, int writePosition, SdkLimitOpti
4747
logRecords.Add(logRecord);
4848
}
4949

50-
writePosition = WriteResourceLogs(buffer, writePosition, sdkLimitOptions, experimentalOptions, resource, ScopeLogsList);
50+
writePosition = TryWriteResourceLogs(buffer, writePosition, sdkLimitOptions, experimentalOptions, resource, ScopeLogsList);
5151
ProtobufSerializer.WriteReservedLength(buffer, logsDataLengthPosition, writePosition - (logsDataLengthPosition + ReserveSizeForLength));
5252
ReturnLogRecordListToPool();
5353

5454
return writePosition;
5555
}
5656

57+
internal static int TryWriteResourceLogs(byte[] buffer, int writePosition, SdkLimitOptions sdkLimitOptions, ExperimentalOptions experimentalOptions, Resources.Resource? resource, Dictionary<string, List<LogRecord>> scopeLogs)
58+
{
59+
try
60+
{
61+
writePosition = WriteResourceLogs(buffer, writePosition, sdkLimitOptions, experimentalOptions, resource, scopeLogs);
62+
}
63+
catch (IndexOutOfRangeException)
64+
{
65+
if (!ProtobufSerializer.IncreaseBufferSize(ref buffer, OtlpSignalType.Logs))
66+
{
67+
throw;
68+
}
69+
70+
return TryWriteResourceLogs(buffer, writePosition, sdkLimitOptions, experimentalOptions, resource, scopeLogs);
71+
}
72+
73+
return writePosition;
74+
}
75+
5776
internal static void ReturnLogRecordListToPool()
5877
{
5978
if (ScopeLogsList.Count != 0)

src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Serializer/ProtobufOtlpMetricSerializer.cs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,32 @@ internal static int WriteMetricsData(byte[] buffer, int writePosition, Resources
3535
metrics.Add(metric);
3636
}
3737

38-
writePosition = WriteResourceMetrics(buffer, writePosition, resource, ScopeMetricsList);
38+
writePosition = TryWriteResourceMetrics(buffer, writePosition, resource, ScopeMetricsList);
3939
ProtobufSerializer.WriteReservedLength(buffer, mericsDataLengthPosition, writePosition - (mericsDataLengthPosition + ReserveSizeForLength));
4040
ReturnMetricListToPool();
4141

4242
return writePosition;
4343
}
4444

45+
internal static int TryWriteResourceMetrics(byte[] buffer, int writePosition, Resources.Resource? resource, Dictionary<string, List<Metric>> scopeMetrics)
46+
{
47+
try
48+
{
49+
writePosition = WriteResourceMetrics(buffer, writePosition, resource, scopeMetrics);
50+
}
51+
catch (IndexOutOfRangeException)
52+
{
53+
if (!ProtobufSerializer.IncreaseBufferSize(ref buffer, OtlpSignalType.Metrics))
54+
{
55+
throw;
56+
}
57+
58+
return TryWriteResourceMetrics(buffer, writePosition, resource, scopeMetrics);
59+
}
60+
61+
return writePosition;
62+
}
63+
4564
private static void ReturnMetricListToPool()
4665
{
4766
if (ScopeMetricsList.Count != 0)

src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Serializer/ProtobufOtlpTraceSerializer.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,6 @@ internal static int TryWriteResourceSpans(byte[] buffer, int writePosition, SdkL
6363
// and avoids stack overflow.
6464
return TryWriteResourceSpans(buffer, writePosition, sdkLimitOptions, resource);
6565
}
66-
catch
67-
{
68-
throw;
69-
}
7066

7167
return writePosition;
7268
}

src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptionsExtensions.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,9 @@ public static THeaders GetHeaders<THeaders>(this OtlpExporterOptions options, Ac
5858
return headers;
5959
}
6060

61-
public static OtlpExporterTransmissionHandler GetProtobufExportTransmissionHandler(this OtlpExporterOptions options, ExperimentalOptions experimentalOptions, OtlpSignalType otlpSignalType)
61+
public static OtlpExporterTransmissionHandler GetExportTransmissionHandler(this OtlpExporterOptions options, ExperimentalOptions experimentalOptions, OtlpSignalType otlpSignalType)
6262
{
63-
var exportClient = GetProtobufExportClient(options, otlpSignalType);
63+
var exportClient = GetExportClient(options, otlpSignalType);
6464

6565
// `HttpClient.Timeout.TotalMilliseconds` would be populated with the correct timeout value for both the exporter configuration cases:
6666
// 1. User provides their own HttpClient. This case is straightforward as the user wants to use their `HttpClient` and thereby the same client's timeout value.
@@ -88,7 +88,7 @@ public static OtlpExporterTransmissionHandler GetProtobufExportTransmissionHandl
8888
}
8989
}
9090

91-
public static IExportClient GetProtobufExportClient(this OtlpExporterOptions options, OtlpSignalType otlpSignalType)
91+
public static IExportClient GetExportClient(this OtlpExporterOptions options, OtlpSignalType otlpSignalType)
9292
{
9393
var httpClient = options.HttpClientFactory?.Invoke() ?? throw new InvalidOperationException("OtlpExporterOptions was missing HttpClientFactory or it returned null.");
9494

src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpLogExporter.cs

Lines changed: 5 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ namespace OpenTelemetry.Exporter;
1717
/// </summary>
1818
public sealed class OtlpLogExporter : BaseExporter<LogRecord>
1919
{
20+
private const int GrpcStartWritePosition = 5;
2021
private readonly SdkLimitOptions sdkLimitOptions;
2122
private readonly ExperimentalOptions experimentalOptions;
2223
private readonly OtlpExporterTransmissionHandler transmissionHandler;
@@ -57,8 +58,8 @@ internal OtlpLogExporter(
5758

5859
this.experimentalOptions = experimentalOptions!;
5960
this.sdkLimitOptions = sdkLimitOptions!;
60-
this.startWritePosition = exporterOptions!.Protocol == OtlpExportProtocol.Grpc ? 5 : 0;
61-
this.transmissionHandler = transmissionHandler ?? exporterOptions!.GetProtobufExportTransmissionHandler(experimentalOptions!, OtlpSignalType.Logs);
61+
this.startWritePosition = exporterOptions!.Protocol == OtlpExportProtocol.Grpc ? GrpcStartWritePosition : 0;
62+
this.transmissionHandler = transmissionHandler ?? exporterOptions!.GetExportTransmissionHandler(experimentalOptions!, OtlpSignalType.Logs);
6263
}
6364

6465
internal Resource Resource => this.resource ??= this.ParentProvider.GetResource();
@@ -73,14 +74,14 @@ public override ExportResult Export(in Batch<LogRecord> logRecordBatch)
7374
{
7475
int writePosition = ProtobufOtlpLogSerializer.WriteLogsData(this.buffer, this.startWritePosition, this.sdkLimitOptions, this.experimentalOptions, this.Resource, logRecordBatch);
7576

76-
if (this.startWritePosition == 5)
77+
if (this.startWritePosition == GrpcStartWritePosition)
7778
{
7879
// Grpc payload consists of 3 parts
7980
// byte 0 - Specifying if the payload is compressed.
8081
// 1-4 byte - Specifies the length of payload in big endian format.
8182
// 5 and above - Protobuf serialized data.
8283
Span<byte> data = new Span<byte>(this.buffer, 1, 4);
83-
var dataLength = writePosition - 5;
84+
var dataLength = writePosition - GrpcStartWritePosition;
8485
BinaryPrimitives.WriteUInt32BigEndian(data, (uint)dataLength);
8586
}
8687

@@ -89,13 +90,6 @@ public override ExportResult Export(in Batch<LogRecord> logRecordBatch)
8990
return ExportResult.Failure;
9091
}
9192
}
92-
catch (IndexOutOfRangeException)
93-
{
94-
if (!this.IncreaseBufferSize())
95-
{
96-
throw;
97-
}
98-
}
9993
catch (Exception ex)
10094
{
10195
OpenTelemetryProtocolExporterEventSource.Log.ExportMethodException(ex);
@@ -107,21 +101,4 @@ public override ExportResult Export(in Batch<LogRecord> logRecordBatch)
107101

108102
/// <inheritdoc />
109103
protected override bool OnShutdown(int timeoutMilliseconds) => this.transmissionHandler?.Shutdown(timeoutMilliseconds) ?? true;
110-
111-
// TODO: Consider moving this to a shared utility class.
112-
private bool IncreaseBufferSize()
113-
{
114-
var newBufferSize = this.buffer.Length * 2;
115-
116-
if (newBufferSize > 100 * 1024 * 1024)
117-
{
118-
return false;
119-
}
120-
121-
var newBuffer = new byte[newBufferSize];
122-
this.buffer.CopyTo(newBuffer, 0);
123-
this.buffer = newBuffer;
124-
125-
return true;
126-
}
127104
}

src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpMetricExporter.cs

Lines changed: 5 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ namespace OpenTelemetry.Exporter;
1717
/// </summary>
1818
public class OtlpMetricExporter : BaseExporter<Metric>
1919
{
20+
private const int GrpcStartWritePosition = 5;
2021
private readonly OtlpExporterTransmissionHandler transmissionHandler;
2122
private readonly int startWritePosition;
2223

@@ -50,8 +51,8 @@ internal OtlpMetricExporter(
5051
Debug.Assert(exporterOptions != null, "exporterOptions was null");
5152
Debug.Assert(experimentalOptions != null, "experimentalOptions was null");
5253

53-
this.startWritePosition = exporterOptions!.Protocol == OtlpExportProtocol.Grpc ? 5 : 0;
54-
this.transmissionHandler = transmissionHandler ?? exporterOptions!.GetProtobufExportTransmissionHandler(experimentalOptions!, OtlpSignalType.Metrics);
54+
this.startWritePosition = exporterOptions!.Protocol == OtlpExportProtocol.Grpc ? GrpcStartWritePosition : 0;
55+
this.transmissionHandler = transmissionHandler ?? exporterOptions!.GetExportTransmissionHandler(experimentalOptions!, OtlpSignalType.Metrics);
5556
}
5657

5758
internal Resource Resource => this.resource ??= this.ParentProvider.GetResource();
@@ -66,14 +67,14 @@ public override ExportResult Export(in Batch<Metric> metrics)
6667
{
6768
int writePosition = ProtobufOtlpMetricSerializer.WriteMetricsData(this.buffer, this.startWritePosition, this.Resource, metrics);
6869

69-
if (this.startWritePosition == 5)
70+
if (this.startWritePosition == GrpcStartWritePosition)
7071
{
7172
// Grpc payload consists of 3 parts
7273
// byte 0 - Specifying if the payload is compressed.
7374
// 1-4 byte - Specifies the length of payload in big endian format.
7475
// 5 and above - Protobuf serialized data.
7576
Span<byte> data = new Span<byte>(this.buffer, 1, 4);
76-
var dataLength = writePosition - 5;
77+
var dataLength = writePosition - GrpcStartWritePosition;
7778
BinaryPrimitives.WriteUInt32BigEndian(data, (uint)dataLength);
7879
}
7980

@@ -82,13 +83,6 @@ public override ExportResult Export(in Batch<Metric> metrics)
8283
return ExportResult.Failure;
8384
}
8485
}
85-
catch (IndexOutOfRangeException)
86-
{
87-
if (!this.IncreaseBufferSize())
88-
{
89-
throw;
90-
}
91-
}
9286
catch (Exception ex)
9387
{
9488
OpenTelemetryProtocolExporterEventSource.Log.ExportMethodException(ex);
@@ -100,21 +94,4 @@ public override ExportResult Export(in Batch<Metric> metrics)
10094

10195
/// <inheritdoc />
10296
protected override bool OnShutdown(int timeoutMilliseconds) => this.transmissionHandler.Shutdown(timeoutMilliseconds);
103-
104-
// TODO: Consider moving this to a shared utility class.
105-
private bool IncreaseBufferSize()
106-
{
107-
var newBufferSize = this.buffer.Length * 2;
108-
109-
if (newBufferSize > 100 * 1024 * 1024)
110-
{
111-
return false;
112-
}
113-
114-
var newBuffer = new byte[newBufferSize];
115-
this.buffer.CopyTo(newBuffer, 0);
116-
this.buffer = newBuffer;
117-
118-
return true;
119-
}
12097
}

0 commit comments

Comments
 (0)