[Exporter.OpenTelemetry.Protocol.Tests] enable analysis (#6264)
This commit is contained in:
parent
13ed63a88c
commit
ceebd456f1
|
|
@ -0,0 +1,144 @@
|
|||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClient.Grpc;
|
||||
using Xunit;
|
||||
|
||||
namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClient.Tests;
|
||||
|
||||
#pragma warning disable CA1515 // Consider making public types internal
|
||||
public class GrpcRetryTestCase
|
||||
#pragma warning restore CA1515 // Consider making public types internal
|
||||
{
|
||||
private readonly string testRunnerName;
|
||||
|
||||
private GrpcRetryTestCase(string testRunnerName, GrpcRetryAttempt[] retryAttempts, int expectedRetryAttempts = 1)
|
||||
{
|
||||
this.ExpectedRetryAttempts = expectedRetryAttempts;
|
||||
this.RetryAttempts = retryAttempts;
|
||||
this.testRunnerName = testRunnerName;
|
||||
}
|
||||
|
||||
public int ExpectedRetryAttempts { get; }
|
||||
|
||||
internal GrpcRetryAttempt[] RetryAttempts { get; }
|
||||
|
||||
public static TheoryData<GrpcRetryTestCase> GetGrpcTestCases()
|
||||
{
|
||||
return
|
||||
[
|
||||
new("Cancelled", [new(StatusCode.Cancelled)]),
|
||||
new("DeadlineExceeded", [new(StatusCode.DeadlineExceeded)]),
|
||||
new("Aborted", [new(StatusCode.Aborted)]),
|
||||
new("OutOfRange", [new(StatusCode.OutOfRange)]),
|
||||
new("DataLoss", [new(StatusCode.DataLoss)]),
|
||||
new("Unavailable", [new(StatusCode.Unavailable)]),
|
||||
|
||||
new("OK", [new(StatusCode.OK, expectedSuccess: false)]),
|
||||
new("PermissionDenied", [new(StatusCode.PermissionDenied, expectedSuccess: false)]),
|
||||
new("Unknown", [new(StatusCode.Unknown, expectedSuccess: false)]),
|
||||
|
||||
new("ResourceExhausted w/o RetryInfo", [new(StatusCode.ResourceExhausted, expectedSuccess: false)]),
|
||||
new("ResourceExhausted w/ RetryInfo", [new(StatusCode.ResourceExhausted, throttleDelay: GetThrottleDelayString(new Duration { Seconds = 2 }), expectedNextRetryDelayMilliseconds: 3000)]),
|
||||
|
||||
new("Unavailable w/ RetryInfo", [new(StatusCode.Unavailable, throttleDelay: GetThrottleDelayString(Duration.FromTimeSpan(TimeSpan.FromMilliseconds(2000))), expectedNextRetryDelayMilliseconds: 3000)]),
|
||||
|
||||
new("Expired deadline", [new(StatusCode.Unavailable, deadlineExceeded: true, expectedSuccess: false)]),
|
||||
|
||||
new(
|
||||
"Exponential backoff",
|
||||
[
|
||||
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 1500),
|
||||
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 2250),
|
||||
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 3375),
|
||||
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 5000),
|
||||
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 5000)
|
||||
],
|
||||
expectedRetryAttempts: 5),
|
||||
|
||||
new(
|
||||
"Retry until non-retryable status code encountered",
|
||||
[
|
||||
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 1500),
|
||||
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 2250),
|
||||
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 3375),
|
||||
new(StatusCode.PermissionDenied, expectedSuccess: false),
|
||||
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 5000)
|
||||
],
|
||||
expectedRetryAttempts: 4),
|
||||
|
||||
// Test throttling affects exponential backoff.
|
||||
new(
|
||||
"Exponential backoff after throttling",
|
||||
[
|
||||
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 1500),
|
||||
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 2250),
|
||||
new(StatusCode.Unavailable, throttleDelay: GetThrottleDelayString(Duration.FromTimeSpan(TimeSpan.FromMilliseconds(500))), expectedNextRetryDelayMilliseconds: 750),
|
||||
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 1125),
|
||||
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 1688),
|
||||
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 2532),
|
||||
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 3798),
|
||||
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 5000),
|
||||
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 5000)
|
||||
],
|
||||
expectedRetryAttempts: 9),
|
||||
];
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return this.testRunnerName;
|
||||
}
|
||||
|
||||
private static string GetThrottleDelayString(Duration throttleDelay)
|
||||
{
|
||||
var status = new Google.Rpc.Status
|
||||
{
|
||||
Code = 4,
|
||||
Message = "Only nanos",
|
||||
Details =
|
||||
{
|
||||
Any.Pack(new Google.Rpc.RetryInfo
|
||||
{
|
||||
RetryDelay = throttleDelay,
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
||||
return Convert.ToBase64String(status.ToByteArray());
|
||||
}
|
||||
|
||||
internal struct GrpcRetryAttempt
|
||||
{
|
||||
internal GrpcRetryAttempt(
|
||||
StatusCode statusCode,
|
||||
bool deadlineExceeded = false,
|
||||
string? throttleDelay = null,
|
||||
int expectedNextRetryDelayMilliseconds = 1500,
|
||||
bool expectedSuccess = true)
|
||||
{
|
||||
var status = new Status(statusCode, "Error");
|
||||
|
||||
// Using arbitrary +1 hr for deadline for test purposes.
|
||||
var deadlineUtc = deadlineExceeded ? DateTime.UtcNow.AddSeconds(-1) : DateTime.UtcNow.AddHours(1);
|
||||
|
||||
this.ThrottleDelay = throttleDelay;
|
||||
|
||||
this.Response = new ExportClientGrpcResponse(expectedSuccess, deadlineUtc, null, status, this.ThrottleDelay);
|
||||
|
||||
this.ExpectedNextRetryDelayMilliseconds = expectedNextRetryDelayMilliseconds;
|
||||
|
||||
this.ExpectedSuccess = expectedSuccess;
|
||||
}
|
||||
|
||||
public string? ThrottleDelay { get; }
|
||||
|
||||
public int? ExpectedNextRetryDelayMilliseconds { get; }
|
||||
|
||||
public bool ExpectedSuccess { get; }
|
||||
|
||||
internal ExportClientGrpcResponse Response { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
using System.Net;
|
||||
#if NETFRAMEWORK
|
||||
using System.Net.Http;
|
||||
#endif
|
||||
using System.Net.Http.Headers;
|
||||
using Xunit;
|
||||
|
||||
namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClient.Tests;
|
||||
|
||||
#pragma warning disable CA1515 // Consider making public types internal
|
||||
public class HttpRetryTestCase
|
||||
#pragma warning restore CA1515 // Consider making public types internal
|
||||
{
|
||||
private readonly string testRunnerName;
|
||||
|
||||
private HttpRetryTestCase(string testRunnerName, HttpRetryAttempt[] retryAttempts, int expectedRetryAttempts = 1)
|
||||
{
|
||||
this.ExpectedRetryAttempts = expectedRetryAttempts;
|
||||
this.RetryAttempts = retryAttempts;
|
||||
this.testRunnerName = testRunnerName;
|
||||
}
|
||||
|
||||
public int ExpectedRetryAttempts { get; }
|
||||
|
||||
internal HttpRetryAttempt[] RetryAttempts { get; }
|
||||
|
||||
public static TheoryData<HttpRetryTestCase> GetHttpTestCases()
|
||||
{
|
||||
return
|
||||
[
|
||||
new("NetworkError", [new(statusCode: null)]),
|
||||
new("GatewayTimeout", [new(statusCode: HttpStatusCode.GatewayTimeout, throttleDelay: TimeSpan.FromSeconds(1))]),
|
||||
#if NETSTANDARD2_1_OR_GREATER || NET
|
||||
new("ServiceUnavailable", [new(statusCode: HttpStatusCode.TooManyRequests, throttleDelay: TimeSpan.FromSeconds(1))]),
|
||||
#endif
|
||||
|
||||
new(
|
||||
"Exponential Backoff",
|
||||
[
|
||||
new(statusCode: null, expectedNextRetryDelayMilliseconds: 1500),
|
||||
new(statusCode: null, expectedNextRetryDelayMilliseconds: 2250),
|
||||
new(statusCode: null, expectedNextRetryDelayMilliseconds: 3375),
|
||||
new(statusCode: null, expectedNextRetryDelayMilliseconds: 5000),
|
||||
new(statusCode: null, expectedNextRetryDelayMilliseconds: 5000)
|
||||
],
|
||||
expectedRetryAttempts: 5),
|
||||
new(
|
||||
"Retry until non-retryable status code encountered",
|
||||
[
|
||||
new(statusCode: HttpStatusCode.ServiceUnavailable, expectedNextRetryDelayMilliseconds: 1500),
|
||||
new(statusCode: HttpStatusCode.ServiceUnavailable, expectedNextRetryDelayMilliseconds: 2250),
|
||||
new(statusCode: HttpStatusCode.ServiceUnavailable, expectedNextRetryDelayMilliseconds: 3375),
|
||||
new(statusCode: HttpStatusCode.BadRequest, expectedSuccess: false),
|
||||
new(statusCode: HttpStatusCode.ServiceUnavailable, expectedNextRetryDelayMilliseconds: 5000)
|
||||
],
|
||||
expectedRetryAttempts: 4),
|
||||
new(
|
||||
"Expired deadline",
|
||||
[
|
||||
new(statusCode: HttpStatusCode.ServiceUnavailable, isDeadlineExceeded: true, expectedSuccess: false)
|
||||
]),
|
||||
];
|
||||
|
||||
// TODO: Add more cases.
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return this.testRunnerName;
|
||||
}
|
||||
|
||||
internal sealed class HttpRetryAttempt
|
||||
{
|
||||
public ExportClientHttpResponse Response;
|
||||
public TimeSpan? ThrottleDelay;
|
||||
public int? ExpectedNextRetryDelayMilliseconds;
|
||||
public bool ExpectedSuccess;
|
||||
|
||||
internal HttpRetryAttempt(
|
||||
HttpStatusCode? statusCode,
|
||||
TimeSpan? throttleDelay = null,
|
||||
bool isDeadlineExceeded = false,
|
||||
int expectedNextRetryDelayMilliseconds = 1500,
|
||||
bool expectedSuccess = true)
|
||||
{
|
||||
this.ThrottleDelay = throttleDelay;
|
||||
|
||||
HttpResponseMessage? responseMessage = null;
|
||||
if (statusCode != null)
|
||||
{
|
||||
#pragma warning disable CA2000 // Dispose objects before losing scope
|
||||
responseMessage = new HttpResponseMessage();
|
||||
#pragma warning restore CA2000 // Dispose objects before losing scope
|
||||
|
||||
if (throttleDelay != null)
|
||||
{
|
||||
responseMessage.Headers.RetryAfter = new RetryConditionHeaderValue(throttleDelay.Value);
|
||||
}
|
||||
|
||||
responseMessage.StatusCode = (HttpStatusCode)statusCode;
|
||||
}
|
||||
|
||||
// Using arbitrary +1 hr for deadline for test purposes.
|
||||
var deadlineUtc = isDeadlineExceeded ? DateTime.UtcNow.AddMilliseconds(-1) : DateTime.UtcNow.AddHours(1);
|
||||
this.Response = new ExportClientHttpResponse(expectedSuccess, deadlineUtc, responseMessage, new HttpRequestException());
|
||||
this.ExpectedNextRetryDelayMilliseconds = expectedNextRetryDelayMilliseconds;
|
||||
this.ExpectedSuccess = expectedSuccess;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -90,11 +90,11 @@ public sealed class OtlpHttpTraceExportClientTests : IDisposable
|
|||
Headers = $"{header1.Name}={header1.Value}, {header2.Name} = {header2.Value}",
|
||||
};
|
||||
|
||||
#pragma warning disable CA2000 // Dispose objects before losing scope
|
||||
var testHttpHandler = new TestHttpMessageHandler();
|
||||
#pragma warning restore CA2000 // Dispose objects before losing scope
|
||||
|
||||
var httpRequestContent = Array.Empty<byte>();
|
||||
|
||||
var httpClient = new HttpClient(testHttpHandler);
|
||||
using var httpClient = new HttpClient(testHttpHandler);
|
||||
|
||||
var exportClient = new OtlpHttpExportClient(options, httpClient, string.Empty);
|
||||
|
||||
|
|
@ -117,7 +117,9 @@ public sealed class OtlpHttpTraceExportClientTests : IDisposable
|
|||
using var openTelemetrySdk = builder.Build();
|
||||
|
||||
var exportedItems = new List<Activity>();
|
||||
#pragma warning disable CA2000 // Dispose objects before losing scope
|
||||
var processor = new BatchActivityExportProcessor(new InMemoryExporter<Activity>(exportedItems));
|
||||
#pragma warning restore CA2000 // Dispose objects before losing scope
|
||||
const int numOfSpans = 10;
|
||||
bool isEven;
|
||||
for (var i = 0; i < numOfSpans; i++)
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ public sealed class OtlpArrayTagWriterTests : IDisposable
|
|||
// Assert
|
||||
Assert.NotNull(arrayState.Buffer);
|
||||
Assert.Equal(0, arrayState.WritePosition);
|
||||
Assert.True(arrayState.Buffer.Length == 2048);
|
||||
Assert.Equal(2048, arrayState.Buffer.Length);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -166,10 +166,11 @@ public sealed class OtlpArrayTagWriterTests : IDisposable
|
|||
lessthat1MBArray[i] = "1234";
|
||||
}
|
||||
|
||||
string?[] stringArray = ["12345"];
|
||||
var tags = new ActivityTagsCollection
|
||||
{
|
||||
new("lessthat1MBArray", lessthat1MBArray),
|
||||
new("StringArray", new string?[] { "12345" }),
|
||||
new("StringArray", stringArray),
|
||||
new("LargeArray", largeArray),
|
||||
};
|
||||
|
||||
|
|
@ -181,7 +182,7 @@ public sealed class OtlpArrayTagWriterTests : IDisposable
|
|||
var otlpSpan = ToOtlpSpanWithExtendedBuffer(new SdkLimitOptions(), activity);
|
||||
|
||||
Assert.NotNull(otlpSpan);
|
||||
Assert.True(otlpSpan.Attributes.Count == 3);
|
||||
Assert.Equal(3, otlpSpan.Attributes.Count);
|
||||
var keyValue = otlpSpan.Attributes.FirstOrDefault(kvp => kvp.Key == "StringArray");
|
||||
Assert.NotNull(keyValue);
|
||||
Assert.Equal("12345", keyValue.Value.ArrayValue.Values[0].StringValue);
|
||||
|
|
|
|||
|
|
@ -102,6 +102,14 @@ public class ProtobufSerializerTests
|
|||
[InlineData(268435455, new byte[] { 0xFF, 0xFF, 0xFF, 0x7F })] // Max 4-byte value
|
||||
public void WriteReservedLength_WritesCorrectly(int length, byte[] expectedBytes)
|
||||
{
|
||||
#if NET
|
||||
Assert.NotNull(expectedBytes);
|
||||
#else
|
||||
if (expectedBytes == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(expectedBytes));
|
||||
}
|
||||
#endif
|
||||
byte[] buffer = new byte[10];
|
||||
ProtobufSerializer.WriteReservedLength(buffer, 0, length);
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
using System.Diagnostics;
|
||||
using System.Diagnostics.Metrics;
|
||||
using System.Diagnostics.Tracing;
|
||||
using System.Globalization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation;
|
||||
using OpenTelemetry.Logs;
|
||||
|
|
@ -265,7 +266,7 @@ public sealed class IntegrationTests : IDisposable
|
|||
});
|
||||
|
||||
var logger = loggerFactory.CreateLogger("OtlpLogExporterTests");
|
||||
logger.LogInformation("Hello from {name} {price}.", "tomato", 2.99);
|
||||
logger.HelloFrom("tomato", 2.99);
|
||||
|
||||
switch (processorOptions.ExportProcessorType)
|
||||
{
|
||||
|
|
@ -307,7 +308,7 @@ public sealed class IntegrationTests : IDisposable
|
|||
string? message;
|
||||
if (eventData.Message != null && eventData.Payload != null && eventData.Payload.Count > 0)
|
||||
{
|
||||
message = string.Format(eventData.Message, eventData.Payload.ToArray());
|
||||
message = string.Format(CultureInfo.InvariantCulture, eventData.Message, eventData.Payload.ToArray());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests;
|
||||
|
||||
internal static partial class LoggerExtensions
|
||||
{
|
||||
[LoggerMessage(LogLevel.Information, "Hello from {Name} {Price}.")]
|
||||
public static partial void HelloFrom(this ILogger logger, string name, double price);
|
||||
|
||||
[LoggerMessage("Hello from {Name} {Price}.")]
|
||||
public static partial void HelloFrom(this ILogger logger, LogLevel logLevel, string name, double price);
|
||||
|
||||
[LoggerMessage(LogLevel.Information, EventId = 10, Message = "Hello from {Name} {Price}.")]
|
||||
public static partial void HelloFromWithEventId(this ILogger logger, string name, double price);
|
||||
|
||||
[LoggerMessage(LogLevel.Information, EventId = 10, EventName = "MyEvent10", Message = "Hello from {Name} {Price}.")]
|
||||
public static partial void HelloFromWithEventIdAndEventName(this ILogger logger, string name, double price);
|
||||
|
||||
[LoggerMessage(LogLevel.Information, "Log message")]
|
||||
public static partial void LogMessage(this ILogger logger);
|
||||
|
||||
[LoggerMessage(LogLevel.Information, "Log when there is no activity.")]
|
||||
public static partial void LogWhenThereIsNoActivity(this ILogger logger);
|
||||
|
||||
[LoggerMessage(LogLevel.Information, "Log within an activity.")]
|
||||
public static partial void LogWithinAnActivity(this ILogger logger);
|
||||
|
||||
[LoggerMessage(LogLevel.Information, "OpenTelemetry {Greeting} {Subject}!")]
|
||||
public static partial void OpenTelemetryGreeting(this ILogger logger, string greeting, string subject);
|
||||
|
||||
[LoggerMessage(LogLevel.Information, "OpenTelemetry {AttributeOne} {AttributeTwo} {AttributeThree}!")]
|
||||
public static partial void OpenTelemetryWithAttributes(this ILogger logger, string attributeOne, string attributeTwo, string attributeThree);
|
||||
|
||||
[LoggerMessage(LogLevel.Information, "Some log information message.")]
|
||||
public static partial void SomeLogInformation(this ILogger logger);
|
||||
|
||||
[LoggerMessage(LogLevel.Information, "Hello from red-tomato")]
|
||||
public static partial void HelloFromRedTomato(this ILogger logger);
|
||||
|
||||
[LoggerMessage(LogLevel.Information, "Hello from green-tomato")]
|
||||
public static partial void HelloFromGreenTomato(this ILogger logger);
|
||||
|
||||
[LoggerMessage(LogLevel.Information, "Exception Occurred")]
|
||||
public static partial void ExceptionOccured(this ILogger logger, Exception exception);
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
#if !NETFRAMEWORK
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Net;
|
||||
using Grpc.Core;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
|
|
@ -58,7 +59,7 @@ public sealed class MockCollectorIntegrationTests
|
|||
"/MockCollector/SetResponseCodes/{responseCodesCsv}",
|
||||
(MockCollectorState collectorState, string responseCodesCsv) =>
|
||||
{
|
||||
var codes = responseCodesCsv.Split(",").Select(x => int.Parse(x)).ToArray();
|
||||
var codes = responseCodesCsv.Split(",").Select(x => int.Parse(x, CultureInfo.InvariantCulture)).ToArray();
|
||||
collectorState.SetStatusCodes(codes);
|
||||
});
|
||||
|
||||
|
|
@ -70,13 +71,15 @@ public sealed class MockCollectorIntegrationTests
|
|||
using var httpClient = new HttpClient() { BaseAddress = new Uri($"http://localhost:{testHttpPort}") };
|
||||
|
||||
var codes = new[] { Grpc.Core.StatusCode.Unimplemented, Grpc.Core.StatusCode.OK };
|
||||
await httpClient.GetAsync($"/MockCollector/SetResponseCodes/{string.Join(",", codes.Select(x => (int)x))}");
|
||||
await httpClient.GetAsync(new Uri($"/MockCollector/SetResponseCodes/{string.Join(",", codes.Select(x => (int)x))}", UriKind.Relative));
|
||||
|
||||
var exportResults = new List<ExportResult>();
|
||||
using var otlpExporter = new OtlpTraceExporter(new OtlpExporterOptions() { Endpoint = new Uri($"http://localhost:{testGrpcPort}") });
|
||||
#pragma warning disable CA2000 // Dispose objects before losing scope
|
||||
var delegatingExporter = new DelegatingExporter<Activity>
|
||||
#pragma warning disable CA2000 // Dispose objects before losing scope
|
||||
{
|
||||
OnExportFunc = (batch) =>
|
||||
OnExportFunc = batch =>
|
||||
{
|
||||
var result = otlpExporter.Export(batch);
|
||||
exportResults.Add(result);
|
||||
|
|
@ -88,7 +91,9 @@ public sealed class MockCollectorIntegrationTests
|
|||
|
||||
using var tracerProvider = Sdk.CreateTracerProviderBuilder()
|
||||
.AddSource(activitySourceName)
|
||||
#pragma warning disable CA2000 // Dispose objects before losing scope
|
||||
.AddProcessor(new SimpleActivityExportProcessor(delegatingExporter))
|
||||
#pragma warning restore CA2000 // Dispose objects before losing scope
|
||||
.Build();
|
||||
|
||||
using var source = new ActivitySource(activitySourceName);
|
||||
|
|
@ -158,7 +163,7 @@ public sealed class MockCollectorIntegrationTests
|
|||
"/MockCollector/SetResponseCodes/{responseCodesCsv}",
|
||||
(MockCollectorState collectorState, string responseCodesCsv) =>
|
||||
{
|
||||
var codes = responseCodesCsv.Split(",").Select(x => int.Parse(x)).ToArray();
|
||||
var codes = responseCodesCsv.Split(",").Select(x => int.Parse(x, CultureInfo.InvariantCulture)).ToArray();
|
||||
collectorState.SetStatusCodes(codes);
|
||||
});
|
||||
|
||||
|
|
@ -171,7 +176,7 @@ public sealed class MockCollectorIntegrationTests
|
|||
|
||||
// First reply with failure and then Ok
|
||||
var codes = new[] { initialStatusCode, Grpc.Core.StatusCode.OK };
|
||||
await httpClient.GetAsync($"/MockCollector/SetResponseCodes/{string.Join(",", codes.Select(x => (int)x))}");
|
||||
await httpClient.GetAsync(new Uri($"/MockCollector/SetResponseCodes/{string.Join(",", codes.Select(x => (int)x))}", UriKind.Relative));
|
||||
|
||||
var endpoint = new Uri($"http://localhost:{testGrpcPort}");
|
||||
|
||||
|
|
@ -241,7 +246,7 @@ public sealed class MockCollectorIntegrationTests
|
|||
"/MockCollector/SetResponseCodes/{responseCodesCsv}",
|
||||
(MockCollectorHttpState collectorState, string responseCodesCsv) =>
|
||||
{
|
||||
var codes = responseCodesCsv.Split(",").Select(x => int.Parse(x)).ToArray();
|
||||
var codes = responseCodesCsv.Split(",").Select(x => int.Parse(x, CultureInfo.InvariantCulture)).ToArray();
|
||||
collectorState.SetStatusCodes(codes);
|
||||
});
|
||||
|
||||
|
|
@ -259,7 +264,7 @@ public sealed class MockCollectorIntegrationTests
|
|||
using var httpClient = new HttpClient() { BaseAddress = new Uri($"http://localhost:{testHttpPort}") };
|
||||
|
||||
var codes = new[] { initialHttpStatusCode, HttpStatusCode.OK };
|
||||
await httpClient.GetAsync($"/MockCollector/SetResponseCodes/{string.Join(",", codes.Select(x => (int)x))}");
|
||||
await httpClient.GetAsync(new Uri($"/MockCollector/SetResponseCodes/{string.Join(",", codes.Select(x => (int)x))}", UriKind.Relative));
|
||||
|
||||
var endpoint = new Uri($"http://localhost:{testHttpPort}/v1/traces");
|
||||
|
||||
|
|
@ -327,7 +332,7 @@ public sealed class MockCollectorIntegrationTests
|
|||
"/MockCollector/SetResponseCodes/{responseCodesCsv}",
|
||||
(MockCollectorHttpState collectorState, string responseCodesCsv) =>
|
||||
{
|
||||
var codes = responseCodesCsv.Split(",").Select(x => int.Parse(x)).ToArray();
|
||||
var codes = responseCodesCsv.Split(",").Select(x => int.Parse(x, CultureInfo.InvariantCulture)).ToArray();
|
||||
collectorState.SetStatusCodes(codes);
|
||||
});
|
||||
|
||||
|
|
@ -345,13 +350,14 @@ public sealed class MockCollectorIntegrationTests
|
|||
using var httpClient = new HttpClient() { BaseAddress = new Uri($"http://localhost:{testHttpPort}") };
|
||||
|
||||
var codes = new[] { initialHttpStatusCode, HttpStatusCode.OK };
|
||||
await httpClient.GetAsync($"/MockCollector/SetResponseCodes/{string.Join(",", codes.Select(x => (int)x))}");
|
||||
await httpClient.GetAsync(new Uri($"/MockCollector/SetResponseCodes/{string.Join(",", codes.Select(x => (int)x))}", UriKind.Relative));
|
||||
|
||||
var endpoint = new Uri($"http://localhost:{testHttpPort}/v1/traces");
|
||||
|
||||
var exporterOptions = new OtlpExporterOptions() { Endpoint = endpoint, TimeoutMilliseconds = 20000 };
|
||||
|
||||
var exportClient = new OtlpHttpExportClient(exporterOptions, new HttpClient(), "/v1/traces");
|
||||
using var exporterHttpClient = new HttpClient();
|
||||
var exportClient = new OtlpHttpExportClient(exporterOptions, exporterHttpClient, "/v1/traces");
|
||||
|
||||
// TODO: update this to configure via experimental environment variable.
|
||||
OtlpExporterTransmissionHandler transmissionHandler;
|
||||
|
|
@ -466,7 +472,7 @@ public sealed class MockCollectorIntegrationTests
|
|||
"/MockCollector/SetResponseCodes/{responseCodesCsv}",
|
||||
(MockCollectorState collectorState, string responseCodesCsv) =>
|
||||
{
|
||||
var codes = responseCodesCsv.Split(",").Select(x => int.Parse(x)).ToArray();
|
||||
var codes = responseCodesCsv.Split(",").Select(x => int.Parse(x, CultureInfo.InvariantCulture)).ToArray();
|
||||
collectorState.SetStatusCodes(codes);
|
||||
});
|
||||
|
||||
|
|
@ -478,13 +484,14 @@ public sealed class MockCollectorIntegrationTests
|
|||
using var httpClient = new HttpClient() { BaseAddress = new Uri($"http://localhost:{testHttpPort}") };
|
||||
|
||||
var codes = new[] { initialgrpcStatusCode, Grpc.Core.StatusCode.OK };
|
||||
await httpClient.GetAsync($"/MockCollector/SetResponseCodes/{string.Join(",", codes.Select(x => (int)x))}");
|
||||
await httpClient.GetAsync(new Uri($"/MockCollector/SetResponseCodes/{string.Join(",", codes.Select(x => (int)x))}", UriKind.Relative));
|
||||
|
||||
var endpoint = new Uri($"http://localhost:{testGrpcPort}");
|
||||
|
||||
var exporterOptions = new OtlpExporterOptions() { Endpoint = endpoint, TimeoutMilliseconds = 20000 };
|
||||
|
||||
var exportClient = new OtlpGrpcExportClient(exporterOptions, new HttpClient(), "opentelemetry.proto.collector.trace.v1.TraceService/Export");
|
||||
using var exporterHttpClient = new HttpClient();
|
||||
var exportClient = new OtlpGrpcExportClient(exporterOptions, exporterHttpClient, "opentelemetry.proto.collector.trace.v1.TraceService/Export");
|
||||
|
||||
// TODO: update this to configure via experimental environment variable.
|
||||
OtlpExporterTransmissionHandler transmissionHandler;
|
||||
|
|
@ -547,10 +554,10 @@ public sealed class MockCollectorIntegrationTests
|
|||
transmissionHandler.Dispose();
|
||||
}
|
||||
|
||||
private class MockCollectorState
|
||||
private sealed class MockCollectorState
|
||||
{
|
||||
private Grpc.Core.StatusCode[] statusCodes = { };
|
||||
private int statusCodeIndex = 0;
|
||||
private Grpc.Core.StatusCode[] statusCodes = [];
|
||||
private int statusCodeIndex;
|
||||
|
||||
public void SetStatusCodes(int[] statusCodes)
|
||||
{
|
||||
|
|
@ -566,10 +573,10 @@ public sealed class MockCollectorIntegrationTests
|
|||
}
|
||||
}
|
||||
|
||||
private class MockCollectorHttpState
|
||||
private sealed class MockCollectorHttpState
|
||||
{
|
||||
private HttpStatusCode[] statusCodes = { };
|
||||
private int statusCodeIndex = 0;
|
||||
private HttpStatusCode[] statusCodes = [];
|
||||
private int statusCodeIndex;
|
||||
|
||||
public void SetStatusCodes(int[] statusCodes)
|
||||
{
|
||||
|
|
@ -585,7 +592,9 @@ public sealed class MockCollectorIntegrationTests
|
|||
}
|
||||
}
|
||||
|
||||
private class MockTraceService : TraceService.TraceServiceBase
|
||||
#pragma warning disable CA1812 // Avoid uninstantiated internal classes
|
||||
private sealed class MockTraceService : TraceService.TraceServiceBase
|
||||
#pragma warning restore CA1812 // Avoid uninstantiated internal classes
|
||||
{
|
||||
private readonly MockCollectorState state;
|
||||
|
||||
|
|
@ -606,9 +615,9 @@ public sealed class MockCollectorIntegrationTests
|
|||
}
|
||||
}
|
||||
|
||||
private class MockFileProvider : PersistentBlobProvider
|
||||
private sealed class MockFileProvider : PersistentBlobProvider
|
||||
{
|
||||
private readonly List<PersistentBlob> mockStorage = new();
|
||||
private readonly List<PersistentBlob> mockStorage = [];
|
||||
|
||||
public IEnumerable<PersistentBlob> TryGetBlobs() => this.mockStorage.AsEnumerable();
|
||||
|
||||
|
|
@ -637,11 +646,11 @@ public sealed class MockCollectorIntegrationTests
|
|||
}
|
||||
}
|
||||
|
||||
private class MockFileBlob : PersistentBlob
|
||||
private sealed class MockFileBlob : PersistentBlob
|
||||
{
|
||||
private readonly List<PersistentBlob> mockStorage;
|
||||
|
||||
private byte[] buffer = Array.Empty<byte>();
|
||||
private byte[] buffer = [];
|
||||
|
||||
public MockFileBlob(List<PersistentBlob> mockStorage)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>$(TargetFrameworksForTests)</TargetFrameworks>
|
||||
<AnalysisLevel>latest-all</AnalysisLevel>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Add MSBuild Task to Generate Certificates -->
|
||||
|
|
@ -47,7 +48,6 @@
|
|||
<Compile Include="$(RepoRoot)\test\OpenTelemetry.Tests\Shared\DelegatingExporter.cs" Link="Includes\DelegatingExporter.cs" />
|
||||
<Compile Include="$(RepoRoot)\test\OpenTelemetry.Tests\Shared\EventSourceTestHelper.cs" Link="Includes\EventSourceTestHelper.cs" />
|
||||
<Compile Include="$(RepoRoot)\test\OpenTelemetry.Tests\Shared\SkipUnlessEnvVarFoundTheoryAttribute.cs" Link="Includes\SkipUnlessEnvVarFoundTheoryAttribute.cs" />
|
||||
<Compile Include="$(RepoRoot)\test\OpenTelemetry.Tests\Shared\SkipUnlessEnvVarFoundFactAttribute.cs" Link="Includes\SkipUnlessEnvVarFoundFactAttribute.cs" />
|
||||
<Compile Include="$(RepoRoot)\test\OpenTelemetry.Tests\Shared\TestActivityProcessor.cs" Link="Includes\TestActivityProcessor.cs" />
|
||||
<Compile Include="$(RepoRoot)\test\OpenTelemetry.Tests\Shared\TestEventListener.cs" Link="Includes\TestEventListener.cs" />
|
||||
<Compile Include="$(RepoRoot)\test\OpenTelemetry.Tests\Shared\Utils.cs" Link="Includes\Utils.cs" />
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.Serializer;
|
||||
using Xunit;
|
||||
using OtlpCommon = OpenTelemetry.Proto.Common.V1;
|
||||
|
|
@ -64,14 +65,14 @@ public class OtlpAttributeTests
|
|||
var expectedArray = new long[array.Length];
|
||||
for (var i = 0; i < array.Length; i++)
|
||||
{
|
||||
expectedArray[i] = Convert.ToInt64(array.GetValue(i));
|
||||
expectedArray[i] = Convert.ToInt64(array.GetValue(i), CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
Assert.Equal(expectedArray, attribute.Value.ArrayValue.Values.Select(x => x.IntValue));
|
||||
break;
|
||||
default:
|
||||
Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.IntValue, attribute.Value.ValueCase);
|
||||
Assert.Equal(Convert.ToInt64(value), attribute.Value.IntValue);
|
||||
Assert.Equal(Convert.ToInt64(value, CultureInfo.InvariantCulture), attribute.Value.IntValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -93,14 +94,14 @@ public class OtlpAttributeTests
|
|||
var expectedArray = new double[array.Length];
|
||||
for (var i = 0; i < array.Length; i++)
|
||||
{
|
||||
expectedArray[i] = Convert.ToDouble(array.GetValue(i));
|
||||
expectedArray[i] = Convert.ToDouble(array.GetValue(i), CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
Assert.Equal(expectedArray, attribute.Value.ArrayValue.Values.Select(x => x.DoubleValue));
|
||||
break;
|
||||
default:
|
||||
Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.DoubleValue, attribute.Value.ValueCase);
|
||||
Assert.Equal(Convert.ToDouble(value), attribute.Value.DoubleValue);
|
||||
Assert.Equal(Convert.ToDouble(value, CultureInfo.InvariantCulture), attribute.Value.DoubleValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -120,14 +121,14 @@ public class OtlpAttributeTests
|
|||
var expectedArray = new bool[array.Length];
|
||||
for (var i = 0; i < array.Length; i++)
|
||||
{
|
||||
expectedArray[i] = Convert.ToBoolean(array.GetValue(i));
|
||||
expectedArray[i] = Convert.ToBoolean(array.GetValue(i), CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
Assert.Equal(expectedArray, attribute.Value.ArrayValue.Values.Select(x => x.BoolValue));
|
||||
break;
|
||||
default:
|
||||
Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.BoolValue, attribute.Value.ValueCase);
|
||||
Assert.Equal(Convert.ToBoolean(value), attribute.Value.BoolValue);
|
||||
Assert.Equal(Convert.ToBoolean(value, CultureInfo.InvariantCulture), attribute.Value.BoolValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -140,7 +141,7 @@ public class OtlpAttributeTests
|
|||
var kvp = new KeyValuePair<string, object?>("key", value);
|
||||
Assert.True(TryTransformTag(kvp, out var attribute));
|
||||
Assert.Equal(OtlpCommon.AnyValue.ValueOneofCase.StringValue, attribute.Value.ValueCase);
|
||||
Assert.Equal(Convert.ToString(value), attribute.Value.StringValue);
|
||||
Assert.Equal(Convert.ToString(value, CultureInfo.InvariantCulture), attribute.Value.StringValue);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -219,7 +220,7 @@ public class OtlpAttributeTests
|
|||
(nint)int.MaxValue,
|
||||
(nuint)uint.MaxValue,
|
||||
decimal.MaxValue,
|
||||
new object(),
|
||||
new(),
|
||||
};
|
||||
|
||||
var testArrayValues = new object[]
|
||||
|
|
@ -227,7 +228,7 @@ public class OtlpAttributeTests
|
|||
new nint[] { 1, 2, 3 },
|
||||
new nuint[] { 1, 2, 3 },
|
||||
new decimal[] { 1, 2, 3 },
|
||||
new object?[] { new object[3], new object(), null },
|
||||
new object?[] { new object[3], new(), null },
|
||||
};
|
||||
|
||||
foreach (var value in testValues)
|
||||
|
|
@ -297,11 +298,11 @@ public class OtlpAttributeTests
|
|||
return false;
|
||||
}
|
||||
|
||||
private class MyToStringMethodThrowsAnException
|
||||
private sealed class MyToStringMethodThrowsAnException
|
||||
{
|
||||
public override string ToString()
|
||||
{
|
||||
throw new Exception("Nope.");
|
||||
throw new InvalidOperationException("Nope.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ public class OtlpExporterOptionsExtensionsTests
|
|||
[InlineData("key1")]
|
||||
public void GetHeaders_InvalidOptionHeaders_ThrowsArgumentException(string inputOptionHeaders)
|
||||
{
|
||||
this.VerifyHeaders(inputOptionHeaders, string.Empty, true);
|
||||
VerifyHeaders(inputOptionHeaders, string.Empty, true);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -57,7 +57,7 @@ public class OtlpExporterOptionsExtensionsTests
|
|||
[InlineData("key1=value1%2Ckey2=value2%2Ckey3=value3", "key1=value1,key2=value2,key3=value3")]
|
||||
public void GetHeaders_ValidAndUrlEncodedHeaders_ReturnsCorrectHeaders(string inputOptionHeaders, string expectedNormalizedOptional)
|
||||
{
|
||||
this.VerifyHeaders(inputOptionHeaders, expectedNormalizedOptional);
|
||||
VerifyHeaders(inputOptionHeaders, expectedNormalizedOptional);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -93,13 +93,13 @@ public class OtlpExporterOptionsExtensionsTests
|
|||
[InlineData("http://test:8888/", "http://test:8888/v1/traces")]
|
||||
[InlineData("http://test:8888/v1/traces", "http://test:8888/v1/traces")]
|
||||
[InlineData("http://test:8888/v1/traces/", "http://test:8888/v1/traces/")]
|
||||
public void AppendPathIfNotPresent_TracesPath_AppendsCorrectly(string inputUri, string expectedUri)
|
||||
public void AppendPathIfNotPresent_TracesPath_AppendsCorrectly(string input, string expected)
|
||||
{
|
||||
var uri = new Uri(inputUri, UriKind.Absolute);
|
||||
var uri = new Uri(input, UriKind.Absolute);
|
||||
|
||||
var resultUri = uri.AppendPathIfNotPresent("v1/traces");
|
||||
|
||||
Assert.Equal(expectedUri, resultUri.AbsoluteUri);
|
||||
Assert.Equal(expected, resultUri.AbsoluteUri);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -163,7 +163,7 @@ public class OtlpExporterOptionsExtensionsTests
|
|||
/// This will be parsed into a dictionary and compared with the actual extracted headers.</param>
|
||||
/// <param name="expectException">If `true`, the method expects `GetHeaders` to throw an `ArgumentException`
|
||||
/// when processing `inputOptionHeaders`.</param>
|
||||
private void VerifyHeaders(string inputOptionHeaders, string expectedNormalizedOptional, bool expectException = false)
|
||||
private static void VerifyHeaders(string inputOptionHeaders, string expectedNormalizedOptional, bool expectException = false)
|
||||
{
|
||||
var options = new OtlpExporterOptions { Headers = inputOptionHeaders };
|
||||
|
||||
|
|
@ -179,9 +179,9 @@ public class OtlpExporterOptionsExtensionsTests
|
|||
|
||||
if (!string.IsNullOrEmpty(expectedNormalizedOptional))
|
||||
{
|
||||
foreach (var segment in expectedNormalizedOptional.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
foreach (var segment in expectedNormalizedOptional.Split([','], StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
var parts = segment.Split(new[] { '=' }, 2);
|
||||
var parts = segment.Split(['='], 2);
|
||||
expectedOptional.Add(parts[0].Trim(), parts[1].Trim());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ using Xunit;
|
|||
namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests;
|
||||
|
||||
[Collection("EnvVars")]
|
||||
public class OtlpExporterOptionsTests : IDisposable
|
||||
public sealed class OtlpExporterOptionsTests : IDisposable
|
||||
{
|
||||
public OtlpExporterOptionsTests()
|
||||
{
|
||||
|
|
@ -52,6 +52,14 @@ public class OtlpExporterOptionsTests : IDisposable
|
|||
[ClassData(typeof(OtlpSpecConfigDefinitionTests))]
|
||||
public void OtlpExporterOptions_EnvironmentVariableOverride(object testDataObject)
|
||||
{
|
||||
#if NET
|
||||
Assert.NotNull(testDataObject);
|
||||
#else
|
||||
if (testDataObject == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(testDataObject));
|
||||
}
|
||||
#endif
|
||||
var testData = testDataObject as OtlpSpecConfigDefinitionTests.TestData;
|
||||
Assert.NotNull(testData);
|
||||
|
||||
|
|
@ -66,6 +74,14 @@ public class OtlpExporterOptionsTests : IDisposable
|
|||
[ClassData(typeof(OtlpSpecConfigDefinitionTests))]
|
||||
public void OtlpExporterOptions_UsingIConfiguration(object testDataObject)
|
||||
{
|
||||
#if NET
|
||||
Assert.NotNull(testDataObject);
|
||||
#else
|
||||
if (testDataObject == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(testDataObject));
|
||||
}
|
||||
#endif
|
||||
var testData = testDataObject as OtlpSpecConfigDefinitionTests.TestData;
|
||||
Assert.NotNull(testData);
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,8 @@ public class OtlpHttpExportClientTests
|
|||
options.Endpoint = new Uri(optionEndpoint);
|
||||
}
|
||||
|
||||
var exporterClient = new OtlpHttpExportClient(options, new HttpClient(), "signal/path");
|
||||
using var httpClient = new HttpClient();
|
||||
var exporterClient = new OtlpHttpExportClient(options, httpClient, "signal/path");
|
||||
Assert.Equal(new Uri(expectedExporterEndpoint), exporterClient.Endpoint);
|
||||
}
|
||||
finally
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
|
@ -148,7 +149,7 @@ public class OtlpLogExporterTests
|
|||
Assert.True(optionsValidated);
|
||||
|
||||
var logger = loggerFactory.CreateLogger("OtlpLogExporterTests");
|
||||
logger.LogInformation("Hello from {name} {price}.", "tomato", 2.99);
|
||||
logger.HelloFrom("tomato", 2.99);
|
||||
Assert.Single(logRecords);
|
||||
var logRecord = logRecords[0];
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
|
|
@ -261,8 +262,7 @@ public class OtlpLogExporterTests
|
|||
});
|
||||
|
||||
var logger = loggerFactory.CreateLogger("OtlpLogExporterTests");
|
||||
logger.LogInformation("Hello from {name} {price}.", "tomato", 2.99);
|
||||
|
||||
logger.HelloFrom("tomato", 2.99);
|
||||
Assert.Single(logRecords);
|
||||
|
||||
var logRecord = logRecords[0];
|
||||
|
|
@ -274,16 +274,16 @@ public class OtlpLogExporterTests
|
|||
var index = 0;
|
||||
var attribute = otlpLogRecord.Attributes[index];
|
||||
|
||||
Assert.Equal("name", attribute.Key);
|
||||
Assert.Equal("Name", attribute.Key);
|
||||
Assert.Equal("tomato", attribute.Value.StringValue);
|
||||
|
||||
attribute = otlpLogRecord.Attributes[++index];
|
||||
Assert.Equal("price", attribute.Key);
|
||||
Assert.Equal("Price", attribute.Key);
|
||||
Assert.Equal(2.99, attribute.Value.DoubleValue);
|
||||
|
||||
attribute = otlpLogRecord.Attributes[++index];
|
||||
Assert.Equal("{OriginalFormat}", attribute.Key);
|
||||
Assert.Equal("Hello from {name} {price}.", attribute.Value.StringValue);
|
||||
Assert.Equal("Hello from {Name} {Price}.", attribute.Value.StringValue);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -305,7 +305,7 @@ public class OtlpLogExporterTests
|
|||
});
|
||||
|
||||
var logger = loggerFactory.CreateLogger("OtlpLogExporterTests");
|
||||
logger.LogInformation(new EventId(10, null), "Hello from {name} {price}.", "tomato", 2.99);
|
||||
logger.HelloFromWithEventId("tomato", 2.99);
|
||||
Assert.Single(logRecords);
|
||||
|
||||
var configuration = new ConfigurationBuilder()
|
||||
|
|
@ -313,7 +313,7 @@ public class OtlpLogExporterTests
|
|||
.Build();
|
||||
|
||||
var logRecord = logRecords[0];
|
||||
OtlpLogs.LogRecord? otlpLogRecord = otlpLogRecord = ToOtlpLogs(DefaultSdkLimitOptions, new(configuration), logRecord);
|
||||
OtlpLogs.LogRecord? otlpLogRecord = ToOtlpLogs(DefaultSdkLimitOptions, new(configuration), logRecord);
|
||||
|
||||
Assert.NotNull(otlpLogRecord);
|
||||
Assert.Equal("Hello from tomato 2.99.", otlpLogRecord.Body.StringValue);
|
||||
|
|
@ -322,17 +322,17 @@ public class OtlpLogExporterTests
|
|||
var otlpLogRecordAttributes = otlpLogRecord.Attributes.ToString();
|
||||
if (emitLogEventAttributes == "true")
|
||||
{
|
||||
Assert.Contains(ExperimentalOptions.LogRecordEventIdAttribute, otlpLogRecordAttributes);
|
||||
Assert.Contains("10", otlpLogRecordAttributes);
|
||||
Assert.Contains(ExperimentalOptions.LogRecordEventIdAttribute, otlpLogRecordAttributes, StringComparison.Ordinal);
|
||||
Assert.Contains("10", otlpLogRecordAttributes, StringComparison.Ordinal);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.DoesNotContain(ExperimentalOptions.LogRecordEventIdAttribute, otlpLogRecordAttributes);
|
||||
Assert.DoesNotContain(ExperimentalOptions.LogRecordEventIdAttribute, otlpLogRecordAttributes, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
logRecords.Clear();
|
||||
|
||||
logger.LogInformation(new EventId(10, "MyEvent10"), "Hello from {name} {price}.", "tomato", 2.99);
|
||||
logger.HelloFromWithEventIdAndEventName("tomato", 2.99);
|
||||
Assert.Single(logRecords);
|
||||
|
||||
logRecord = logRecords[0];
|
||||
|
|
@ -346,15 +346,15 @@ public class OtlpLogExporterTests
|
|||
otlpLogRecordAttributes = otlpLogRecord.Attributes.ToString();
|
||||
if (emitLogEventAttributes == "true")
|
||||
{
|
||||
Assert.Contains(ExperimentalOptions.LogRecordEventIdAttribute, otlpLogRecordAttributes);
|
||||
Assert.Contains("10", otlpLogRecordAttributes);
|
||||
Assert.Contains(ExperimentalOptions.LogRecordEventNameAttribute, otlpLogRecordAttributes);
|
||||
Assert.Contains("MyEvent10", otlpLogRecordAttributes);
|
||||
Assert.Contains(ExperimentalOptions.LogRecordEventIdAttribute, otlpLogRecordAttributes, StringComparison.Ordinal);
|
||||
Assert.Contains("10", otlpLogRecordAttributes, StringComparison.Ordinal);
|
||||
Assert.Contains(ExperimentalOptions.LogRecordEventNameAttribute, otlpLogRecordAttributes, StringComparison.Ordinal);
|
||||
Assert.Contains("MyEvent10", otlpLogRecordAttributes, StringComparison.Ordinal);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.DoesNotContain(ExperimentalOptions.LogRecordEventIdAttribute, otlpLogRecordAttributes);
|
||||
Assert.DoesNotContain(ExperimentalOptions.LogRecordEventNameAttribute, otlpLogRecordAttributes);
|
||||
Assert.DoesNotContain(ExperimentalOptions.LogRecordEventIdAttribute, otlpLogRecordAttributes, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain(ExperimentalOptions.LogRecordEventNameAttribute, otlpLogRecordAttributes, StringComparison.Ordinal);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -368,7 +368,7 @@ public class OtlpLogExporterTests
|
|||
});
|
||||
|
||||
var logger = loggerFactory.CreateLogger("OtlpLogExporterTests");
|
||||
logger.LogInformation("Log message");
|
||||
logger.LogMessage();
|
||||
|
||||
var logRecord = logRecords[0];
|
||||
OtlpLogs.LogRecord? otlpLogRecord = ToOtlpLogs(DefaultSdkLimitOptions, new ExperimentalOptions(), logRecord);
|
||||
|
|
@ -388,7 +388,7 @@ public class OtlpLogExporterTests
|
|||
});
|
||||
|
||||
var logger = loggerFactory.CreateLogger("OtlpLogExporterTests");
|
||||
logger.LogInformation("Log when there is no activity.");
|
||||
logger.LogWhenThereIsNoActivity();
|
||||
|
||||
var logRecord = logRecords[0];
|
||||
OtlpLogs.LogRecord? otlpLogRecord = ToOtlpLogs(DefaultSdkLimitOptions, new ExperimentalOptions(), logRecord);
|
||||
|
|
@ -413,9 +413,10 @@ public class OtlpLogExporterTests
|
|||
|
||||
ActivityTraceId expectedTraceId = default;
|
||||
ActivitySpanId expectedSpanId = default;
|
||||
using (var activity = new Activity(Utils.GetCurrentMethodName()).Start())
|
||||
using (var activity = new Activity(Utils.GetCurrentMethodName()))
|
||||
{
|
||||
logger.LogInformation("Log within an activity.");
|
||||
activity.Start();
|
||||
logger.LogWithinAnActivity();
|
||||
|
||||
expectedTraceId = activity.TraceId;
|
||||
expectedSpanId = activity.SpanId;
|
||||
|
|
@ -451,7 +452,7 @@ public class OtlpLogExporterTests
|
|||
});
|
||||
|
||||
var logger = loggerFactory.CreateLogger("CheckToOtlpLogRecordSeverityLevelAndText");
|
||||
logger.Log(logLevel, "Hello from {name} {price}.", "tomato", 2.99);
|
||||
logger.HelloFrom(logLevel, "tomato", 2.99);
|
||||
Assert.Single(logRecords);
|
||||
|
||||
var logRecord = logRecords[0];
|
||||
|
|
@ -506,7 +507,7 @@ public class OtlpLogExporterTests
|
|||
var logger = loggerFactory.CreateLogger("OtlpLogExporterTests");
|
||||
|
||||
// Scenario 1 - Using ExtensionMethods on ILogger.Log
|
||||
logger.LogInformation("OpenTelemetry {Greeting} {Subject}!", "Hello", "World");
|
||||
logger.OpenTelemetryGreeting("Hello", "World");
|
||||
Assert.Single(logRecords);
|
||||
|
||||
var logRecord = logRecords[0];
|
||||
|
|
@ -620,7 +621,7 @@ public class OtlpLogExporterTests
|
|||
});
|
||||
|
||||
var logger = loggerFactory.CreateLogger("OtlpLogExporterTests");
|
||||
logger.LogInformation(new Exception("Exception Message"), "Exception Occurred");
|
||||
logger.ExceptionOccured(new InvalidOperationException("Exception Message"));
|
||||
|
||||
var logRecord = logRecords[0];
|
||||
var loggedException = logRecord.Exception;
|
||||
|
|
@ -630,15 +631,15 @@ public class OtlpLogExporterTests
|
|||
Assert.NotNull(otlpLogRecord);
|
||||
var otlpLogRecordAttributes = otlpLogRecord.Attributes.ToString();
|
||||
|
||||
Assert.Contains(SemanticConventions.AttributeExceptionType, otlpLogRecordAttributes);
|
||||
Assert.Contains(SemanticConventions.AttributeExceptionType, otlpLogRecordAttributes, StringComparison.Ordinal);
|
||||
Assert.NotNull(logRecord.Exception);
|
||||
Assert.Contains(logRecord.Exception.GetType().Name, otlpLogRecordAttributes);
|
||||
Assert.Contains(logRecord.Exception.GetType().Name, otlpLogRecordAttributes, StringComparison.Ordinal);
|
||||
|
||||
Assert.Contains(SemanticConventions.AttributeExceptionMessage, otlpLogRecordAttributes);
|
||||
Assert.Contains(logRecord.Exception.Message, otlpLogRecordAttributes);
|
||||
Assert.Contains(SemanticConventions.AttributeExceptionMessage, otlpLogRecordAttributes, StringComparison.Ordinal);
|
||||
Assert.Contains(logRecord.Exception.Message, otlpLogRecordAttributes, StringComparison.Ordinal);
|
||||
|
||||
Assert.Contains(SemanticConventions.AttributeExceptionStacktrace, otlpLogRecordAttributes);
|
||||
Assert.Contains(logRecord.Exception.ToInvariantString(), otlpLogRecordAttributes);
|
||||
Assert.Contains(SemanticConventions.AttributeExceptionStacktrace, otlpLogRecordAttributes, StringComparison.Ordinal);
|
||||
Assert.Contains(logRecord.Exception.ToInvariantString(), otlpLogRecordAttributes, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -659,7 +660,7 @@ public class OtlpLogExporterTests
|
|||
});
|
||||
|
||||
var logger = loggerFactory.CreateLogger(string.Empty);
|
||||
logger.LogInformation("OpenTelemetry {AttributeOne} {AttributeTwo} {AttributeThree}!", "I'm an attribute", "I too am an attribute", "I get dropped :(");
|
||||
logger.OpenTelemetryWithAttributes("I'm an attribute", "I too am an attribute", "I get dropped :(");
|
||||
|
||||
var logRecord = logRecords[0];
|
||||
OtlpLogs.LogRecord? otlpLogRecord = ToOtlpLogs(sdkLimitOptions, new(), logRecord);
|
||||
|
|
@ -688,10 +689,10 @@ public class OtlpLogExporterTests
|
|||
// Arrange.
|
||||
var testExportClient = new TestExportClient();
|
||||
var exporterOptions = new OtlpExporterOptions();
|
||||
var transmissionHandler = new OtlpExporterTransmissionHandler(testExportClient, exporterOptions.TimeoutMilliseconds);
|
||||
using var transmissionHandler = new OtlpExporterTransmissionHandler(testExportClient, exporterOptions.TimeoutMilliseconds);
|
||||
var emptyLogRecords = Array.Empty<LogRecord>();
|
||||
var emptyBatch = new Batch<LogRecord>(emptyLogRecords, emptyLogRecords.Length);
|
||||
var sut = new OtlpLogExporter(
|
||||
using var sut = new OtlpLogExporter(
|
||||
exporterOptions,
|
||||
new SdkLimitOptions(),
|
||||
new ExperimentalOptions(),
|
||||
|
|
@ -710,10 +711,10 @@ public class OtlpLogExporterTests
|
|||
// Arrange.
|
||||
var testExportClient = new TestExportClient(throwException: true);
|
||||
var exporterOptions = new OtlpExporterOptions();
|
||||
var transmissionHandler = new OtlpExporterTransmissionHandler(testExportClient, exporterOptions.TimeoutMilliseconds);
|
||||
using var transmissionHandler = new OtlpExporterTransmissionHandler(testExportClient, exporterOptions.TimeoutMilliseconds);
|
||||
var emptyLogRecords = Array.Empty<LogRecord>();
|
||||
var emptyBatch = new Batch<LogRecord>(emptyLogRecords, emptyLogRecords.Length);
|
||||
var sut = new OtlpLogExporter(
|
||||
using var sut = new OtlpLogExporter(
|
||||
exporterOptions,
|
||||
new SdkLimitOptions(),
|
||||
new ExperimentalOptions(),
|
||||
|
|
@ -732,10 +733,10 @@ public class OtlpLogExporterTests
|
|||
// Arrange.
|
||||
var testExportClient = new TestExportClient();
|
||||
var exporterOptions = new OtlpExporterOptions();
|
||||
var transmissionHandler = new OtlpExporterTransmissionHandler(testExportClient, exporterOptions.TimeoutMilliseconds);
|
||||
using var transmissionHandler = new OtlpExporterTransmissionHandler(testExportClient, exporterOptions.TimeoutMilliseconds);
|
||||
var emptyLogRecords = Array.Empty<LogRecord>();
|
||||
var emptyBatch = new Batch<LogRecord>(emptyLogRecords, emptyLogRecords.Length);
|
||||
var sut = new OtlpLogExporter(
|
||||
using var sut = new OtlpLogExporter(
|
||||
exporterOptions,
|
||||
new SdkLimitOptions(),
|
||||
new ExperimentalOptions(),
|
||||
|
|
@ -767,10 +768,10 @@ public class OtlpLogExporterTests
|
|||
// Act.
|
||||
using (logger.BeginScope(new List<KeyValuePair<string, object>>
|
||||
{
|
||||
new KeyValuePair<string, object>(expectedScopeKey, expectedScopeValue),
|
||||
new(expectedScopeKey, expectedScopeValue),
|
||||
}))
|
||||
{
|
||||
logger.LogInformation("Some log information message.");
|
||||
logger.SomeLogInformation();
|
||||
}
|
||||
|
||||
// Assert.
|
||||
|
|
@ -787,6 +788,15 @@ public class OtlpLogExporterTests
|
|||
[InlineData('a')]
|
||||
public void ToOtlpLog_WhenOptionsIncludeScopesIsTrue_ContainsScopeAttributeStringValue(object scopeValue)
|
||||
{
|
||||
#if NET
|
||||
Assert.NotNull(scopeValue);
|
||||
#else
|
||||
if (scopeValue == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(scopeValue));
|
||||
}
|
||||
#endif
|
||||
|
||||
// Arrange.
|
||||
var logRecords = new List<LogRecord>(1);
|
||||
using var loggerFactory = LoggerFactory.Create(builder =>
|
||||
|
|
@ -802,10 +812,10 @@ public class OtlpLogExporterTests
|
|||
// Act.
|
||||
using (logger.BeginScope(new List<KeyValuePair<string, object>>
|
||||
{
|
||||
new KeyValuePair<string, object>(scopeKey, scopeValue),
|
||||
new(scopeKey, scopeValue),
|
||||
}))
|
||||
{
|
||||
logger.LogInformation("Some log information message.");
|
||||
logger.SomeLogInformation();
|
||||
}
|
||||
|
||||
// Assert.
|
||||
|
|
@ -841,10 +851,10 @@ public class OtlpLogExporterTests
|
|||
// Act.
|
||||
using (logger.BeginScope(new List<KeyValuePair<string, object>>
|
||||
{
|
||||
new KeyValuePair<string, object>(scopeKey, scopeValue),
|
||||
new(scopeKey, scopeValue),
|
||||
}))
|
||||
{
|
||||
logger.LogInformation("Some log information message.");
|
||||
logger.SomeLogInformation();
|
||||
}
|
||||
|
||||
// Assert.
|
||||
|
|
@ -877,6 +887,15 @@ public class OtlpLogExporterTests
|
|||
[InlineData(long.MaxValue)]
|
||||
public void ToOtlpLog_WhenOptionsIncludeScopesIsTrue_ContainsScopeAttributeIntValue(object scopeValue)
|
||||
{
|
||||
#if NET
|
||||
Assert.NotNull(scopeValue);
|
||||
#else
|
||||
if (scopeValue == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(scopeValue));
|
||||
}
|
||||
#endif
|
||||
|
||||
// Arrange.
|
||||
var logRecords = new List<LogRecord>(1);
|
||||
using var loggerFactory = LoggerFactory.Create(builder =>
|
||||
|
|
@ -892,10 +911,10 @@ public class OtlpLogExporterTests
|
|||
// Act.
|
||||
using (logger.BeginScope(new List<KeyValuePair<string, object>>
|
||||
{
|
||||
new KeyValuePair<string, object>(scopeKey, scopeValue),
|
||||
new(scopeKey, scopeValue),
|
||||
}))
|
||||
{
|
||||
logger.LogInformation("Some log information message.");
|
||||
logger.SomeLogInformation();
|
||||
}
|
||||
|
||||
// Assert.
|
||||
|
|
@ -908,7 +927,7 @@ public class OtlpLogExporterTests
|
|||
Assert.NotNull(actualScope);
|
||||
Assert.Equal(scopeKey, actualScope.Key);
|
||||
Assert.Equal(ValueOneofCase.IntValue, actualScope.Value.ValueCase);
|
||||
Assert.Equal(scopeValue.ToString(), actualScope.Value.IntValue.ToString());
|
||||
Assert.Equal(scopeValue.ToString(), actualScope.Value.IntValue.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -934,7 +953,7 @@ public class OtlpLogExporterTests
|
|||
new(scopeKey, scopeValue),
|
||||
}))
|
||||
{
|
||||
logger.LogInformation("Some log information message.");
|
||||
logger.SomeLogInformation();
|
||||
}
|
||||
|
||||
// Assert.
|
||||
|
|
@ -948,7 +967,7 @@ public class OtlpLogExporterTests
|
|||
Assert.NotNull(actualScope);
|
||||
Assert.Equal(scopeKey, actualScope.Key);
|
||||
Assert.Equal(ValueOneofCase.DoubleValue, actualScope.Value.ValueCase);
|
||||
Assert.Equal(((double)scopeValue).ToString(), actualScope.Value.DoubleValue.ToString());
|
||||
Assert.Equal(scopeValue, actualScope.Value.DoubleValue);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -974,7 +993,7 @@ public class OtlpLogExporterTests
|
|||
new(scopeKey, scopeValue),
|
||||
}))
|
||||
{
|
||||
logger.LogInformation("Some log information message.");
|
||||
logger.SomeLogInformation();
|
||||
}
|
||||
|
||||
// Assert.
|
||||
|
|
@ -986,7 +1005,7 @@ public class OtlpLogExporterTests
|
|||
var actualScope = TryGetAttribute(otlpLogRecord, scopeKey);
|
||||
Assert.NotNull(actualScope);
|
||||
Assert.Equal(scopeKey, actualScope.Key);
|
||||
Assert.Equal(scopeValue.ToString(), actualScope.Value.DoubleValue.ToString());
|
||||
Assert.Equal(scopeValue, actualScope.Value.DoubleValue);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -1007,7 +1026,7 @@ public class OtlpLogExporterTests
|
|||
// Act.
|
||||
using (logger.BeginScope(scopeState))
|
||||
{
|
||||
logger.LogInformation("Some log information message.");
|
||||
logger.SomeLogInformation();
|
||||
}
|
||||
|
||||
// Assert.
|
||||
|
|
@ -1042,7 +1061,7 @@ public class OtlpLogExporterTests
|
|||
// Act.
|
||||
using (logger.BeginScope(scopeState))
|
||||
{
|
||||
logger.LogInformation("Some log information message.");
|
||||
logger.SomeLogInformation();
|
||||
}
|
||||
|
||||
// Assert.
|
||||
|
|
@ -1073,7 +1092,7 @@ public class OtlpLogExporterTests
|
|||
// Act.
|
||||
using (logger.BeginScope(scopeState))
|
||||
{
|
||||
logger.LogInformation("Some log information message.");
|
||||
logger.SomeLogInformation();
|
||||
}
|
||||
|
||||
// Assert.
|
||||
|
|
@ -1113,7 +1132,7 @@ public class OtlpLogExporterTests
|
|||
Assert.NotNull(scopeState);
|
||||
using (logger.BeginScope(scopeState))
|
||||
{
|
||||
logger.LogInformation("Some log information message.");
|
||||
logger.SomeLogInformation();
|
||||
}
|
||||
|
||||
// Assert.
|
||||
|
|
@ -1149,11 +1168,11 @@ public class OtlpLogExporterTests
|
|||
// Act.
|
||||
using (logger.BeginScope(new List<KeyValuePair<string, object>>
|
||||
{
|
||||
new KeyValuePair<string, object>(scopeKey1, scopeValue1),
|
||||
new KeyValuePair<string, object>(scopeKey2, scopeValue2),
|
||||
new(scopeKey1, scopeValue1),
|
||||
new(scopeKey2, scopeValue2),
|
||||
}))
|
||||
{
|
||||
logger.LogInformation("Some log information message.");
|
||||
logger.SomeLogInformation();
|
||||
}
|
||||
|
||||
// Assert.
|
||||
|
|
@ -1189,11 +1208,11 @@ public class OtlpLogExporterTests
|
|||
const string scopeValue2 = "Some other scope value";
|
||||
|
||||
// Act.
|
||||
using (logger.BeginScope(new List<KeyValuePair<string, object>> { new KeyValuePair<string, object>(scopeKey1, scopeValue1) }))
|
||||
using (logger.BeginScope(new List<KeyValuePair<string, object>> { new(scopeKey1, scopeValue1) }))
|
||||
{
|
||||
using (logger.BeginScope(new List<KeyValuePair<string, object>> { new KeyValuePair<string, object>(scopeKey2, scopeValue2) }))
|
||||
using (logger.BeginScope(new List<KeyValuePair<string, object>> { new(scopeKey2, scopeValue2) }))
|
||||
{
|
||||
logger.LogInformation("Some log information message.");
|
||||
logger.SomeLogInformation();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1232,14 +1251,14 @@ public class OtlpLogExporterTests
|
|||
// Act.
|
||||
using (logger.BeginScope(new List<KeyValuePair<string, object>>
|
||||
{
|
||||
new KeyValuePair<string, object>(scopeKey1, scopeValue1),
|
||||
new(scopeKey1, scopeValue1),
|
||||
}))
|
||||
{
|
||||
logger.Log(
|
||||
LogLevel.Error,
|
||||
new EventId(1),
|
||||
new List<KeyValuePair<string, object>> { new KeyValuePair<string, object>(scopeKey2, scopeValue2) },
|
||||
exception: new Exception("Some exception message"),
|
||||
new List<KeyValuePair<string, object>> { new(scopeKey2, scopeValue2) },
|
||||
exception: new InvalidOperationException("Some exception message"),
|
||||
formatter: (s, e) => string.Empty);
|
||||
}
|
||||
|
||||
|
|
@ -1336,10 +1355,10 @@ public class OtlpLogExporterTests
|
|||
});
|
||||
|
||||
var logger1 = loggerFactory.CreateLogger("OtlpLogExporterTests-A");
|
||||
logger1.LogInformation("Hello from red-tomato");
|
||||
logger1.HelloFromRedTomato();
|
||||
|
||||
var logger2 = loggerFactory.CreateLogger("OtlpLogExporterTests-B");
|
||||
logger2.LogInformation("Hello from green-tomato");
|
||||
logger2.HelloFromGreenTomato();
|
||||
|
||||
Assert.Equal(2, logRecords.Count);
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ using OtlpMetrics = OpenTelemetry.Proto.Metrics.V1;
|
|||
namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests;
|
||||
|
||||
[Collection("EnvVars")]
|
||||
public class OtlpMetricsExporterTests : IDisposable
|
||||
public sealed class OtlpMetricsExporterTests : IDisposable
|
||||
{
|
||||
private static readonly KeyValuePair<string, object?>[] KeyValues =
|
||||
[
|
||||
|
|
|
|||
|
|
@ -1,13 +1,6 @@
|
|||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
using System.Net;
|
||||
using System.Net.Http.Headers;
|
||||
#if NETFRAMEWORK
|
||||
using System.Net.Http;
|
||||
#endif
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClient.Grpc;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -15,14 +8,22 @@ namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClie
|
|||
|
||||
public class OtlpRetryTests
|
||||
{
|
||||
public static IEnumerable<object[]> GrpcRetryTestData => GrpcRetryTestCase.GetGrpcTestCases();
|
||||
public static TheoryData<GrpcRetryTestCase> GrpcRetryTestData => GrpcRetryTestCase.GetGrpcTestCases();
|
||||
|
||||
public static IEnumerable<object[]> HttpRetryTestData => HttpRetryTestCase.GetHttpTestCases();
|
||||
public static TheoryData<HttpRetryTestCase> HttpRetryTestData => HttpRetryTestCase.GetHttpTestCases();
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(GrpcRetryTestData))]
|
||||
public void TryGetGrpcRetryResultTest(GrpcRetryTestCase testCase)
|
||||
{
|
||||
#if NET
|
||||
Assert.NotNull(testCase);
|
||||
#else
|
||||
if (testCase == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(testCase));
|
||||
}
|
||||
#endif
|
||||
var attempts = 0;
|
||||
var nextRetryDelayMilliseconds = OtlpRetry.InitialBackoffMilliseconds;
|
||||
|
||||
|
|
@ -65,6 +66,14 @@ public class OtlpRetryTests
|
|||
[MemberData(nameof(HttpRetryTestData))]
|
||||
public void TryGetHttpRetryResultTest(HttpRetryTestCase testCase)
|
||||
{
|
||||
#if NET
|
||||
Assert.NotNull(testCase);
|
||||
#else
|
||||
if (testCase == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(testCase));
|
||||
}
|
||||
#endif
|
||||
var attempts = 0;
|
||||
var nextRetryDelayMilliseconds = OtlpRetry.InitialBackoffMilliseconds;
|
||||
|
||||
|
|
@ -101,242 +110,4 @@ public class OtlpRetryTests
|
|||
|
||||
Assert.Equal(testCase.ExpectedRetryAttempts, attempts);
|
||||
}
|
||||
|
||||
public class GrpcRetryTestCase
|
||||
{
|
||||
public int ExpectedRetryAttempts;
|
||||
public GrpcRetryAttempt[] RetryAttempts;
|
||||
|
||||
private string testRunnerName;
|
||||
|
||||
private GrpcRetryTestCase(string testRunnerName, GrpcRetryAttempt[] retryAttempts, int expectedRetryAttempts = 1)
|
||||
{
|
||||
this.ExpectedRetryAttempts = expectedRetryAttempts;
|
||||
this.RetryAttempts = retryAttempts;
|
||||
this.testRunnerName = testRunnerName;
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> GetGrpcTestCases()
|
||||
{
|
||||
yield return new[] { new GrpcRetryTestCase("Cancelled", new GrpcRetryAttempt[] { new(StatusCode.Cancelled) }) };
|
||||
yield return new[] { new GrpcRetryTestCase("DeadlineExceeded", new GrpcRetryAttempt[] { new(StatusCode.DeadlineExceeded) }) };
|
||||
yield return new[] { new GrpcRetryTestCase("Aborted", new GrpcRetryAttempt[] { new(StatusCode.Aborted) }) };
|
||||
yield return new[] { new GrpcRetryTestCase("OutOfRange", new GrpcRetryAttempt[] { new(StatusCode.OutOfRange) }) };
|
||||
yield return new[] { new GrpcRetryTestCase("DataLoss", new GrpcRetryAttempt[] { new(StatusCode.DataLoss) }) };
|
||||
yield return new[] { new GrpcRetryTestCase("Unavailable", new GrpcRetryAttempt[] { new(StatusCode.Unavailable) }) };
|
||||
|
||||
yield return new[] { new GrpcRetryTestCase("OK", new GrpcRetryAttempt[] { new(StatusCode.OK, expectedSuccess: false) }) };
|
||||
yield return new[] { new GrpcRetryTestCase("PermissionDenied", new GrpcRetryAttempt[] { new(StatusCode.PermissionDenied, expectedSuccess: false) }) };
|
||||
yield return new[] { new GrpcRetryTestCase("Unknown", new GrpcRetryAttempt[] { new(StatusCode.Unknown, expectedSuccess: false) }) };
|
||||
|
||||
yield return new[] { new GrpcRetryTestCase("ResourceExhausted w/o RetryInfo", new GrpcRetryAttempt[] { new(StatusCode.ResourceExhausted, expectedSuccess: false) }) };
|
||||
yield return new[] { new GrpcRetryTestCase("ResourceExhausted w/ RetryInfo", new GrpcRetryAttempt[] { new(StatusCode.ResourceExhausted, throttleDelay: GetThrottleDelayString(new Duration { Seconds = 2 }), expectedNextRetryDelayMilliseconds: 3000) }) };
|
||||
|
||||
yield return new[] { new GrpcRetryTestCase("Unavailable w/ RetryInfo", new GrpcRetryAttempt[] { new(StatusCode.Unavailable, throttleDelay: GetThrottleDelayString(Duration.FromTimeSpan(TimeSpan.FromMilliseconds(2000))), expectedNextRetryDelayMilliseconds: 3000) }) };
|
||||
|
||||
yield return new[] { new GrpcRetryTestCase("Expired deadline", new GrpcRetryAttempt[] { new(StatusCode.Unavailable, deadlineExceeded: true, expectedSuccess: false) }) };
|
||||
|
||||
yield return new[]
|
||||
{
|
||||
new GrpcRetryTestCase(
|
||||
"Exponential backoff",
|
||||
new GrpcRetryAttempt[]
|
||||
{
|
||||
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 1500),
|
||||
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 2250),
|
||||
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 3375),
|
||||
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 5000),
|
||||
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 5000),
|
||||
},
|
||||
expectedRetryAttempts: 5),
|
||||
};
|
||||
|
||||
yield return new[]
|
||||
{
|
||||
new GrpcRetryTestCase(
|
||||
"Retry until non-retryable status code encountered",
|
||||
new GrpcRetryAttempt[]
|
||||
{
|
||||
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 1500),
|
||||
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 2250),
|
||||
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 3375),
|
||||
new(StatusCode.PermissionDenied, expectedSuccess: false),
|
||||
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 5000),
|
||||
},
|
||||
expectedRetryAttempts: 4),
|
||||
};
|
||||
|
||||
// Test throttling affects exponential backoff.
|
||||
yield return new[]
|
||||
{
|
||||
new GrpcRetryTestCase(
|
||||
"Exponential backoff after throttling",
|
||||
new GrpcRetryAttempt[]
|
||||
{
|
||||
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 1500),
|
||||
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 2250),
|
||||
new(StatusCode.Unavailable, throttleDelay: GetThrottleDelayString(Duration.FromTimeSpan(TimeSpan.FromMilliseconds(500))), expectedNextRetryDelayMilliseconds: 750),
|
||||
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 1125),
|
||||
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 1688),
|
||||
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 2532),
|
||||
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 3798),
|
||||
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 5000),
|
||||
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 5000),
|
||||
},
|
||||
expectedRetryAttempts: 9),
|
||||
};
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return this.testRunnerName;
|
||||
}
|
||||
|
||||
private static string GetThrottleDelayString(Duration throttleDelay)
|
||||
{
|
||||
var status = new Google.Rpc.Status
|
||||
{
|
||||
Code = 4,
|
||||
Message = "Only nanos",
|
||||
Details =
|
||||
{
|
||||
Any.Pack(new Google.Rpc.RetryInfo
|
||||
{
|
||||
RetryDelay = throttleDelay,
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
||||
return Convert.ToBase64String(status.ToByteArray());
|
||||
}
|
||||
|
||||
public struct GrpcRetryAttempt
|
||||
{
|
||||
public string? ThrottleDelay;
|
||||
public int? ExpectedNextRetryDelayMilliseconds;
|
||||
public bool ExpectedSuccess;
|
||||
internal ExportClientGrpcResponse Response;
|
||||
|
||||
internal GrpcRetryAttempt(
|
||||
StatusCode statusCode,
|
||||
bool deadlineExceeded = false,
|
||||
string? throttleDelay = null,
|
||||
int expectedNextRetryDelayMilliseconds = 1500,
|
||||
bool expectedSuccess = true)
|
||||
{
|
||||
var status = new Status(statusCode, "Error");
|
||||
|
||||
// Using arbitrary +1 hr for deadline for test purposes.
|
||||
var deadlineUtc = deadlineExceeded ? DateTime.UtcNow.AddSeconds(-1) : DateTime.UtcNow.AddHours(1);
|
||||
|
||||
this.ThrottleDelay = throttleDelay;
|
||||
|
||||
this.Response = new ExportClientGrpcResponse(expectedSuccess, deadlineUtc, null, status, this.ThrottleDelay);
|
||||
|
||||
this.ExpectedNextRetryDelayMilliseconds = expectedNextRetryDelayMilliseconds;
|
||||
|
||||
this.ExpectedSuccess = expectedSuccess;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class HttpRetryTestCase
|
||||
{
|
||||
public int ExpectedRetryAttempts;
|
||||
internal HttpRetryAttempt[] RetryAttempts;
|
||||
|
||||
private string testRunnerName;
|
||||
|
||||
private HttpRetryTestCase(string testRunnerName, HttpRetryAttempt[] retryAttempts, int expectedRetryAttempts = 1)
|
||||
{
|
||||
this.ExpectedRetryAttempts = expectedRetryAttempts;
|
||||
this.RetryAttempts = retryAttempts;
|
||||
this.testRunnerName = testRunnerName;
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> GetHttpTestCases()
|
||||
{
|
||||
yield return new[] { new HttpRetryTestCase("NetworkError", [new(statusCode: null)]) };
|
||||
yield return new[] { new HttpRetryTestCase("GatewayTimeout", [new(statusCode: HttpStatusCode.GatewayTimeout, throttleDelay: TimeSpan.FromSeconds(1))]) };
|
||||
#if NETSTANDARD2_1_OR_GREATER || NET
|
||||
yield return new[] { new HttpRetryTestCase("ServiceUnavailable", [new(statusCode: HttpStatusCode.TooManyRequests, throttleDelay: TimeSpan.FromSeconds(1))]) };
|
||||
#endif
|
||||
|
||||
yield return new[]
|
||||
{
|
||||
new HttpRetryTestCase(
|
||||
"Exponential Backoff",
|
||||
new HttpRetryAttempt[]
|
||||
{
|
||||
new(statusCode: null, expectedNextRetryDelayMilliseconds: 1500),
|
||||
new(statusCode: null, expectedNextRetryDelayMilliseconds: 2250),
|
||||
new(statusCode: null, expectedNextRetryDelayMilliseconds: 3375),
|
||||
new(statusCode: null, expectedNextRetryDelayMilliseconds: 5000),
|
||||
new(statusCode: null, expectedNextRetryDelayMilliseconds: 5000),
|
||||
},
|
||||
expectedRetryAttempts: 5),
|
||||
};
|
||||
|
||||
yield return new[]
|
||||
{
|
||||
new HttpRetryTestCase(
|
||||
"Retry until non-retryable status code encountered",
|
||||
new HttpRetryAttempt[]
|
||||
{
|
||||
new(statusCode: HttpStatusCode.ServiceUnavailable, expectedNextRetryDelayMilliseconds: 1500),
|
||||
new(statusCode: HttpStatusCode.ServiceUnavailable, expectedNextRetryDelayMilliseconds: 2250),
|
||||
new(statusCode: HttpStatusCode.ServiceUnavailable, expectedNextRetryDelayMilliseconds: 3375),
|
||||
new(statusCode: HttpStatusCode.BadRequest, expectedSuccess: false),
|
||||
new(statusCode: HttpStatusCode.ServiceUnavailable, expectedNextRetryDelayMilliseconds: 5000),
|
||||
},
|
||||
expectedRetryAttempts: 4),
|
||||
};
|
||||
|
||||
yield return new[] { new HttpRetryTestCase("Expired deadline", new HttpRetryAttempt[] { new(statusCode: HttpStatusCode.ServiceUnavailable, isDeadlineExceeded: true, expectedSuccess: false) }) };
|
||||
|
||||
// TODO: Add more cases.
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return this.testRunnerName;
|
||||
}
|
||||
|
||||
internal class HttpRetryAttempt
|
||||
{
|
||||
public ExportClientHttpResponse Response;
|
||||
public TimeSpan? ThrottleDelay;
|
||||
public int? ExpectedNextRetryDelayMilliseconds;
|
||||
public bool ExpectedSuccess;
|
||||
|
||||
internal HttpRetryAttempt(
|
||||
HttpStatusCode? statusCode,
|
||||
TimeSpan? throttleDelay = null,
|
||||
bool isDeadlineExceeded = false,
|
||||
int expectedNextRetryDelayMilliseconds = 1500,
|
||||
bool expectedSuccess = true)
|
||||
{
|
||||
this.ThrottleDelay = throttleDelay;
|
||||
|
||||
HttpResponseMessage? responseMessage = null;
|
||||
if (statusCode != null)
|
||||
{
|
||||
responseMessage = new HttpResponseMessage();
|
||||
|
||||
if (throttleDelay != null)
|
||||
{
|
||||
responseMessage.Headers.RetryAfter = new RetryConditionHeaderValue(throttleDelay.Value);
|
||||
}
|
||||
|
||||
responseMessage.StatusCode = (HttpStatusCode)statusCode;
|
||||
}
|
||||
|
||||
// Using arbitrary +1 hr for deadline for test purposes.
|
||||
var deadlineUtc = isDeadlineExceeded ? DateTime.UtcNow.AddMilliseconds(-1) : DateTime.UtcNow.AddHours(1);
|
||||
this.Response = new ExportClientHttpResponse(expectedSuccess, deadlineUtc, responseMessage, new HttpRequestException());
|
||||
this.ExpectedNextRetryDelayMilliseconds = expectedNextRetryDelayMilliseconds;
|
||||
this.ExpectedSuccess = expectedSuccess;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
using System.Collections;
|
||||
using System.Globalization;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using OpenTelemetry.Metrics;
|
||||
using Xunit;
|
||||
|
|
@ -190,12 +191,13 @@ public class OtlpSpecConfigDefinitionTests : IEnumerable<object[]>
|
|||
|
||||
public ConfigurationBuilder AddToConfiguration(ConfigurationBuilder configurationBuilder)
|
||||
{
|
||||
Dictionary<string, string?> dictionary = new();
|
||||
|
||||
dictionary[this.EndpointKeyName] = this.EndpointValue;
|
||||
dictionary[this.HeadersKeyName] = this.HeadersValue;
|
||||
dictionary[this.TimeoutKeyName] = this.TimeoutValue;
|
||||
dictionary[this.ProtocolKeyName] = this.ProtocolValue;
|
||||
Dictionary<string, string?> dictionary = new()
|
||||
{
|
||||
[this.EndpointKeyName] = this.EndpointValue,
|
||||
[this.HeadersKeyName] = this.HeadersValue,
|
||||
[this.TimeoutKeyName] = this.TimeoutValue,
|
||||
[this.ProtocolKeyName] = this.ProtocolValue,
|
||||
};
|
||||
|
||||
this.OnAddToDictionary(dictionary);
|
||||
|
||||
|
|
@ -228,7 +230,7 @@ public class OtlpSpecConfigDefinitionTests : IEnumerable<object[]>
|
|||
{
|
||||
Assert.Equal(new Uri(this.EndpointValue), otlpExporterOptions.Endpoint);
|
||||
Assert.Equal(this.HeadersValue, otlpExporterOptions.Headers);
|
||||
Assert.Equal(int.Parse(this.TimeoutValue), otlpExporterOptions.TimeoutMilliseconds);
|
||||
Assert.Equal(int.Parse(this.TimeoutValue, CultureInfo.InvariantCulture), otlpExporterOptions.TimeoutMilliseconds);
|
||||
|
||||
if (!OtlpExportProtocolParser.TryParse(this.ProtocolValue, out var protocol))
|
||||
{
|
||||
|
|
@ -291,7 +293,11 @@ public class OtlpSpecConfigDefinitionTests : IEnumerable<object[]>
|
|||
|
||||
public void AssertMatches(MetricReaderOptions metricReaderOptions)
|
||||
{
|
||||
#if NET
|
||||
Assert.Equal(Enum.Parse<MetricReaderTemporalityPreference>(this.TemporalityValue), metricReaderOptions.TemporalityPreference);
|
||||
#else
|
||||
Assert.Equal(Enum.Parse(typeof(MetricReaderTemporalityPreference), this.TemporalityValue), metricReaderOptions.TemporalityPreference);
|
||||
#endif
|
||||
}
|
||||
|
||||
protected override void OnSetEnvVars()
|
||||
|
|
|
|||
|
|
@ -161,7 +161,9 @@ public sealed class OtlpTraceExporterTests : IDisposable
|
|||
.SetResourceBuilder(resourceBuilder)
|
||||
.AddSource(sources[0].Name)
|
||||
.AddSource(sources[1].Name)
|
||||
#pragma warning disable CA2000 // Dispose objects before losing scope
|
||||
.AddProcessor(new SimpleActivityExportProcessor(new InMemoryExporter<Activity>(exportedItems)));
|
||||
#pragma warning restore CA2000 // Dispose objects before losing scope
|
||||
|
||||
using var openTelemetrySdk = builder.Build();
|
||||
|
||||
|
|
@ -248,7 +250,9 @@ public sealed class OtlpTraceExporterTests : IDisposable
|
|||
.SetResourceBuilder(resourceBuilder)
|
||||
.AddSource(activitySourceWithTags.Name)
|
||||
.AddSource(activitySourceWithoutTags.Name)
|
||||
#pragma warning disable CA2000 // Dispose objects before losing scope
|
||||
.AddProcessor(new SimpleActivityExportProcessor(new InMemoryExporter<Activity>(exportedItems)));
|
||||
#pragma warning restore CA2000 // Dispose objects before losing scope
|
||||
|
||||
using var openTelemetrySdk = builder.Build();
|
||||
|
||||
|
|
@ -336,7 +340,9 @@ public sealed class OtlpTraceExporterTests : IDisposable
|
|||
var builder = Sdk.CreateTracerProviderBuilder()
|
||||
.SetResourceBuilder(resourceBuilder)
|
||||
.AddSource(activitySource.Name)
|
||||
#pragma warning disable CA2000 // Dispose objects before losing scope
|
||||
.AddProcessor(new SimpleActivityExportProcessor(new InMemoryExporter<Activity>(exportedItems)));
|
||||
#pragma warning restore CA2000 // Dispose objects before losing scope
|
||||
|
||||
using var openTelemetrySdk = builder.Build();
|
||||
|
||||
|
|
@ -363,7 +369,7 @@ public sealed class OtlpTraceExporterTests : IDisposable
|
|||
Assert.Equal(3, scope.Attributes.Count);
|
||||
Assert.Equal(1u, scope.DroppedAttributesCount);
|
||||
Assert.Equal("1234", scope.Attributes[0].Value.StringValue);
|
||||
this.ArrayValueAsserts(scope.Attributes[1].Value.ArrayValue.Values);
|
||||
ArrayValueAsserts(scope.Attributes[1].Value.ArrayValue.Values);
|
||||
Assert.Equal(new object().ToString()!.Substring(0, 4), scope.Attributes[2].Value.StringValue);
|
||||
}
|
||||
}
|
||||
|
|
@ -410,7 +416,7 @@ public sealed class OtlpTraceExporterTests : IDisposable
|
|||
Assert.Equal(3, otlpSpan.Attributes.Count);
|
||||
Assert.Equal(1u, otlpSpan.DroppedAttributesCount);
|
||||
Assert.Equal("1234", otlpSpan.Attributes[0].Value.StringValue);
|
||||
this.ArrayValueAsserts(otlpSpan.Attributes[1].Value.ArrayValue.Values);
|
||||
ArrayValueAsserts(otlpSpan.Attributes[1].Value.ArrayValue.Values);
|
||||
Assert.Equal(new object().ToString()!.Substring(0, 4), otlpSpan.Attributes[2].Value.StringValue);
|
||||
|
||||
Assert.Single(otlpSpan.Events);
|
||||
|
|
@ -418,7 +424,7 @@ public sealed class OtlpTraceExporterTests : IDisposable
|
|||
Assert.Equal(3, otlpSpan.Events[0].Attributes.Count);
|
||||
Assert.Equal(1u, otlpSpan.Events[0].DroppedAttributesCount);
|
||||
Assert.Equal("1234", otlpSpan.Events[0].Attributes[0].Value.StringValue);
|
||||
this.ArrayValueAsserts(otlpSpan.Events[0].Attributes[1].Value.ArrayValue.Values);
|
||||
ArrayValueAsserts(otlpSpan.Events[0].Attributes[1].Value.ArrayValue.Values);
|
||||
Assert.Equal(new object().ToString()!.Substring(0, 4), otlpSpan.Events[0].Attributes[2].Value.StringValue);
|
||||
|
||||
Assert.Single(otlpSpan.Links);
|
||||
|
|
@ -426,7 +432,7 @@ public sealed class OtlpTraceExporterTests : IDisposable
|
|||
Assert.Equal(3, otlpSpan.Links[0].Attributes.Count);
|
||||
Assert.Equal(1u, otlpSpan.Links[0].DroppedAttributesCount);
|
||||
Assert.Equal("1234", otlpSpan.Links[0].Attributes[0].Value.StringValue);
|
||||
this.ArrayValueAsserts(otlpSpan.Links[0].Attributes[1].Value.ArrayValue.Values);
|
||||
ArrayValueAsserts(otlpSpan.Links[0].Attributes[1].Value.ArrayValue.Values);
|
||||
Assert.Equal(new object().ToString()!.Substring(0, 4), otlpSpan.Links[0].Attributes[2].Value.StringValue);
|
||||
}
|
||||
|
||||
|
|
@ -437,6 +443,11 @@ public sealed class OtlpTraceExporterTests : IDisposable
|
|||
|
||||
using var rootActivity = activitySource.StartActivity("root", ActivityKind.Producer);
|
||||
|
||||
bool[] boolArray = [true, false];
|
||||
int[] intArray = [1, 2];
|
||||
double[] doubleArray = [1.0, 2.09];
|
||||
string[] stringArray = ["a", "b"];
|
||||
|
||||
var attributes = new List<KeyValuePair<string, object?>>
|
||||
{
|
||||
new("bool", true),
|
||||
|
|
@ -445,10 +456,10 @@ public sealed class OtlpTraceExporterTests : IDisposable
|
|||
new("double", 3.14),
|
||||
new("int", 1),
|
||||
new("datetime", DateTime.UtcNow),
|
||||
new("bool_array", new bool[] { true, false }),
|
||||
new("int_array", new int[] { 1, 2 }),
|
||||
new("double_array", new double[] { 1.0, 2.09 }),
|
||||
new("string_array", new string[] { "a", "b" }),
|
||||
new("bool_array", boolArray),
|
||||
new("int_array", intArray),
|
||||
new("double_array", doubleArray),
|
||||
new("string_array", stringArray),
|
||||
new("datetime_array", new DateTime[] { DateTime.UtcNow, DateTime.Now }),
|
||||
};
|
||||
|
||||
|
|
@ -761,7 +772,9 @@ public sealed class OtlpTraceExporterTests : IDisposable
|
|||
public void UseOpenTelemetryProtocolActivityExporterWithCustomActivityProcessor()
|
||||
{
|
||||
const string ActivitySourceName = "otlp.test";
|
||||
#pragma warning disable CA2000 // Dispose objects before losing scope
|
||||
TestActivityProcessor testActivityProcessor = new TestActivityProcessor();
|
||||
#pragma warning restore CA2000 // Dispose objects before losing scope
|
||||
|
||||
bool startCalled = false;
|
||||
bool endCalled = false;
|
||||
|
|
@ -798,7 +811,7 @@ public sealed class OtlpTraceExporterTests : IDisposable
|
|||
var exportClientMock = new TestExportClient();
|
||||
|
||||
var exporterOptions = new OtlpExporterOptions();
|
||||
var transmissionHandler = new OtlpExporterTransmissionHandler(exportClientMock, exporterOptions.TimeoutMilliseconds);
|
||||
using var transmissionHandler = new OtlpExporterTransmissionHandler(exportClientMock, exporterOptions.TimeoutMilliseconds);
|
||||
|
||||
using var exporter = new OtlpTraceExporter(new OtlpExporterOptions(), DefaultSdkLimitOptions, DefaultExperimentalOptions, transmissionHandler);
|
||||
exporter.Shutdown();
|
||||
|
|
@ -1030,7 +1043,7 @@ public sealed class OtlpTraceExporterTests : IDisposable
|
|||
return request;
|
||||
}
|
||||
|
||||
private void ArrayValueAsserts(RepeatedField<OtlpCommon.AnyValue> values)
|
||||
private static void ArrayValueAsserts(RepeatedField<OtlpCommon.AnyValue> values)
|
||||
{
|
||||
var expectedStringArray = new string?[] { "1234", "1234", string.Empty, null };
|
||||
for (var i = 0; i < expectedStringArray.Length; ++i)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClient;
|
|||
|
||||
namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests;
|
||||
|
||||
internal class TestExportClient(bool throwException = false) : IExportClient
|
||||
internal sealed class TestExportClient(bool throwException = false) : IExportClient
|
||||
{
|
||||
public bool SendExportRequestCalled { get; private set; }
|
||||
|
||||
|
|
@ -17,7 +17,7 @@ internal class TestExportClient(bool throwException = false) : IExportClient
|
|||
{
|
||||
if (this.ThrowException)
|
||||
{
|
||||
throw new Exception("Exception thrown from SendExportRequest");
|
||||
throw new InvalidOperationException("Exception thrown from SendExportRequest");
|
||||
}
|
||||
|
||||
this.SendExportRequestCalled = true;
|
||||
|
|
@ -30,7 +30,7 @@ internal class TestExportClient(bool throwException = false) : IExportClient
|
|||
return true;
|
||||
}
|
||||
|
||||
private class TestExportClientResponse : ExportClientResponse
|
||||
private sealed class TestExportClientResponse : ExportClientResponse
|
||||
{
|
||||
public TestExportClientResponse(bool success, DateTime deadline, Exception? exception)
|
||||
: base(success, deadline, exception)
|
||||
|
|
|
|||
|
|
@ -7,16 +7,20 @@ using System.Net.Http;
|
|||
|
||||
namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests;
|
||||
|
||||
internal class TestHttpMessageHandler : HttpMessageHandler
|
||||
internal sealed class TestHttpMessageHandler : HttpMessageHandler
|
||||
{
|
||||
public HttpRequestMessage? HttpRequestMessage { get; private set; }
|
||||
|
||||
public byte[]? HttpRequestContent { get; private set; }
|
||||
|
||||
public virtual HttpResponseMessage InternalSend(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
public HttpResponseMessage InternalSend(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
this.HttpRequestMessage = request;
|
||||
#if NET
|
||||
this.HttpRequestContent = request.Content!.ReadAsByteArrayAsync(cancellationToken).Result;
|
||||
#else
|
||||
this.HttpRequestContent = request.Content!.ReadAsByteArrayAsync().Result;
|
||||
#endif
|
||||
return new HttpResponseMessage();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ using Xunit;
|
|||
namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests;
|
||||
|
||||
[Collection("EnvVars")]
|
||||
public class UseOtlpExporterExtensionTests : IDisposable
|
||||
public sealed class UseOtlpExporterExtensionTests : IDisposable
|
||||
{
|
||||
public UseOtlpExporterExtensionTests()
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue