diff --git a/examples/grpc.core/Examples.GrpcCore.AspNetCore/Controllers/WeatherForecastController.cs b/examples/grpc.core/Examples.GrpcCore.AspNetCore/Controllers/WeatherForecastController.cs index 7b9f689d90..69ceb10bcb 100644 --- a/examples/grpc.core/Examples.GrpcCore.AspNetCore/Controllers/WeatherForecastController.cs +++ b/examples/grpc.core/Examples.GrpcCore.AspNetCore/Controllers/WeatherForecastController.cs @@ -20,38 +20,37 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; -namespace Examples.GrpcCore.AspNetCore.Controllers +namespace Examples.GrpcCore.AspNetCore.Controllers; + +[ApiController] +[Route("[controller]")] +public class WeatherForecastController : ControllerBase { - [ApiController] - [Route("[controller]")] - public class WeatherForecastController : ControllerBase + private static readonly string[] Summaries = new[] { - private static readonly string[] Summaries = new[] - { - "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching", - }; + "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching", + }; - private readonly Echo.EchoClient echoClient; + private readonly Echo.EchoClient echoClient; - public WeatherForecastController(Echo.EchoClient echoClient) - { - this.echoClient = echoClient; - } + public WeatherForecastController(Echo.EchoClient echoClient) + { + this.echoClient = echoClient; + } - [HttpGet] - public async Task> Get() - { - var echoCall = this.echoClient.EchoAsync(new EchoRequest { Message = "Hello" }); - var echoResponse = await echoCall.ResponseAsync.ConfigureAwait(false); + [HttpGet] + public async Task> Get() + { + var echoCall = this.echoClient.EchoAsync(new EchoRequest { Message = "Hello" }); + var echoResponse = await echoCall.ResponseAsync.ConfigureAwait(false); - var rng = new Random(); - return Enumerable.Range(1, 5).Select(index => new WeatherForecast - { - Date = DateTime.Now.AddDays(index), - TemperatureC = rng.Next(-20, 55), - Summary = Summaries[rng.Next(Summaries.Length)], - }) + var rng = new Random(); + return Enumerable.Range(1, 5).Select(index => new WeatherForecast + { + Date = DateTime.Now.AddDays(index), + TemperatureC = rng.Next(-20, 55), + Summary = Summaries[rng.Next(Summaries.Length)], + }) .ToArray(); - } } } diff --git a/examples/grpc.core/Examples.GrpcCore.AspNetCore/EchoService.cs b/examples/grpc.core/Examples.GrpcCore.AspNetCore/EchoService.cs index 688478c96f..46c9269931 100644 --- a/examples/grpc.core/Examples.GrpcCore.AspNetCore/EchoService.cs +++ b/examples/grpc.core/Examples.GrpcCore.AspNetCore/EchoService.cs @@ -17,17 +17,16 @@ using System.Threading.Tasks; using Grpc.Core; -namespace Examples.GrpcCore.AspNetCore +namespace Examples.GrpcCore.AspNetCore; + +/// +/// Simple implementation of the echo service. +/// +internal class EchoService : Echo.EchoBase { - /// - /// Simple implementation of the echo service. - /// - internal class EchoService : Echo.EchoBase + /// + public override Task Echo(EchoRequest request, ServerCallContext context) { - /// - public override Task Echo(EchoRequest request, ServerCallContext context) - { - return Task.FromResult(new EchoResponse { Message = request.Message }); - } + return Task.FromResult(new EchoResponse { Message = request.Message }); } } diff --git a/examples/grpc.core/Examples.GrpcCore.AspNetCore/Program.cs b/examples/grpc.core/Examples.GrpcCore.AspNetCore/Program.cs index fc53b160af..f9b834c954 100644 --- a/examples/grpc.core/Examples.GrpcCore.AspNetCore/Program.cs +++ b/examples/grpc.core/Examples.GrpcCore.AspNetCore/Program.cs @@ -17,24 +17,23 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Hosting; -namespace Examples.GrpcCore.AspNetCore -{ - public class Program - { - internal const int Port = 5000; - internal const int GrpcServicePort = 5001; +namespace Examples.GrpcCore.AspNetCore; - public static void Main(string[] args) - { - CreateHostBuilder(args).Build().Run(); - } +public class Program +{ + internal const int Port = 5000; + internal const int GrpcServicePort = 5001; - public static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) - .ConfigureWebHostDefaults(webBuilder => - { - webBuilder.UseUrls($"http://+:{Port}"); - webBuilder.UseStartup(); - }); + public static void Main(string[] args) + { + CreateHostBuilder(args).Build().Run(); } + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseUrls($"http://+:{Port}"); + webBuilder.UseStartup(); + }); } diff --git a/examples/grpc.core/Examples.GrpcCore.AspNetCore/Startup.cs b/examples/grpc.core/Examples.GrpcCore.AspNetCore/Startup.cs index 607462e16c..374ec30c48 100644 --- a/examples/grpc.core/Examples.GrpcCore.AspNetCore/Startup.cs +++ b/examples/grpc.core/Examples.GrpcCore.AspNetCore/Startup.cs @@ -26,92 +26,91 @@ using OpenTelemetry.Instrumentation.GrpcCore; using OpenTelemetry.Trace; -namespace Examples.GrpcCore.AspNetCore +namespace Examples.GrpcCore.AspNetCore; + +public class Startup { - public class Startup + public Startup(IConfiguration configuration) { - public Startup(IConfiguration configuration) - { - this.Configuration = configuration; - } + this.Configuration = configuration; + } - public IConfiguration Configuration { get; } + public IConfiguration Configuration { get; } - // This method gets called by the runtime. Use this method to add services to the container. - public void ConfigureServices(IServiceCollection services) - { - services.AddControllers(); + // This method gets called by the runtime. Use this method to add services to the container. + public void ConfigureServices(IServiceCollection services) + { + services.AddControllers(); - // Wire in otel - services.AddOpenTelemetryTracing( - (builder) => builder - .AddAspNetCoreInstrumentation() - .AddGrpcCoreInstrumentation() - .AddConsoleExporter()); + // Wire in otel + services.AddOpenTelemetryTracing( + (builder) => builder + .AddAspNetCoreInstrumentation() + .AddGrpcCoreInstrumentation() + .AddConsoleExporter()); - // We are running an in-process gRPC Core service. - services.AddHostedService(); + // We are running an in-process gRPC Core service. + services.AddHostedService(); - // Add a singleton for the gRPC client to our local service. - services.AddSingleton(provider => - { - var channel = new Channel($"dns:localhost:{Program.GrpcServicePort}", ChannelCredentials.Insecure); + // Add a singleton for the gRPC client to our local service. + services.AddSingleton(provider => + { + var channel = new Channel($"dns:localhost:{Program.GrpcServicePort}", ChannelCredentials.Insecure); - var callInvoker = channel.CreateCallInvoker() - .Intercept(new ClientTracingInterceptor(new ClientTracingInterceptorOptions())); + var callInvoker = channel.CreateCallInvoker() + .Intercept(new ClientTracingInterceptor(new ClientTracingInterceptorOptions())); - return new Echo.EchoClient(callInvoker); - }); - } + return new Echo.EchoClient(callInvoker); + }); + } - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) { - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } + app.UseDeveloperExceptionPage(); + } - app.UseRouting(); + app.UseRouting(); - app.UseAuthorization(); + app.UseAuthorization(); - app.UseEndpoints(endpoints => - { - endpoints.MapControllers(); - }); - } + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); + } - /// - /// A hosted service wrapper for an in-process gRPC Core service. - /// This gRPC service is instrumented using the server interceptor. - /// - private sealed class EchoGrpcHostedService : BackgroundService + /// + /// A hosted service wrapper for an in-process gRPC Core service. + /// This gRPC service is instrumented using the server interceptor. + /// + private sealed class EchoGrpcHostedService : BackgroundService + { + protected override Task ExecuteAsync(CancellationToken stoppingToken) { - protected override Task ExecuteAsync(CancellationToken stoppingToken) - { - var serviceDefinition = Echo.BindService(new EchoService()) - .Intercept(new ServerTracingInterceptor(new ServerTracingInterceptorOptions())); + var serviceDefinition = Echo.BindService(new EchoService()) + .Intercept(new ServerTracingInterceptor(new ServerTracingInterceptorOptions())); - var server = new Server - { - Ports = { new ServerPort("localhost", Program.GrpcServicePort, ServerCredentials.Insecure) }, - Services = { serviceDefinition }, - }; + var server = new Server + { + Ports = { new ServerPort("localhost", Program.GrpcServicePort, ServerCredentials.Insecure) }, + Services = { serviceDefinition }, + }; - server.Start(); + server.Start(); - var tcs = new TaskCompletionSource(); + var tcs = new TaskCompletionSource(); - var tokenRegistration = stoppingToken.Register( - async () => - { - await server.ShutdownAsync().ConfigureAwait(false); - tcs.SetResult(true); - }); + var tokenRegistration = stoppingToken.Register( + async () => + { + await server.ShutdownAsync().ConfigureAwait(false); + tcs.SetResult(true); + }); - return tcs.Task.ContinueWith(antecedent => tokenRegistration.Dispose()); - } + return tcs.Task.ContinueWith(antecedent => tokenRegistration.Dispose()); } } } diff --git a/examples/grpc.core/Examples.GrpcCore.AspNetCore/WeatherForecast.cs b/examples/grpc.core/Examples.GrpcCore.AspNetCore/WeatherForecast.cs index 0c2f9fd7eb..f840e9cfce 100644 --- a/examples/grpc.core/Examples.GrpcCore.AspNetCore/WeatherForecast.cs +++ b/examples/grpc.core/Examples.GrpcCore.AspNetCore/WeatherForecast.cs @@ -16,16 +16,15 @@ using System; -namespace Examples.GrpcCore.AspNetCore +namespace Examples.GrpcCore.AspNetCore; + +public class WeatherForecast { - public class WeatherForecast - { - public DateTime Date { get; set; } + public DateTime Date { get; set; } - public int TemperatureC { get; set; } + public int TemperatureC { get; set; } - public int TemperatureF => 32 + (int)(this.TemperatureC / 0.5556); + public int TemperatureF => 32 + (int)(this.TemperatureC / 0.5556); - public string Summary { get; set; } - } + public string Summary { get; set; } } diff --git a/examples/owin/Controllers/TestController.cs b/examples/owin/Controllers/TestController.cs index ad469faf07..c47aa92312 100644 --- a/examples/owin/Controllers/TestController.cs +++ b/examples/owin/Controllers/TestController.cs @@ -14,17 +14,15 @@ // limitations under the License. // -using System; using System.Web.Http; -namespace Examples.Owin.Controllers +namespace Examples.Owin.Controllers; + +public class TestController : ApiController { - public class TestController : ApiController + // GET api/test/{id} + public string Get(string id = null) { - // GET api/test/{id} - public string Get(string id = null) - { - return $"id:{id}"; - } + return $"id:{id}"; } } diff --git a/examples/owin/Program.cs b/examples/owin/Program.cs index a9bab679c5..2267c5399c 100644 --- a/examples/owin/Program.cs +++ b/examples/owin/Program.cs @@ -26,60 +26,59 @@ using OpenTelemetry.Trace; using Owin; -namespace Examples.Owin +namespace Examples.Owin; + +internal static class Program { - internal static class Program + public static void Main() { - public static void Main() - { - using var host = WebApp.Start( - "http://localhost:9000", - appBuilder => - { - // Add OpenTelemetry early in the pipeline to start timing - // the request as soon as possible. - appBuilder.UseOpenTelemetry(); + using var host = WebApp.Start( + "http://localhost:9000", + appBuilder => + { + // Add OpenTelemetry early in the pipeline to start timing + // the request as soon as possible. + appBuilder.UseOpenTelemetry(); - HttpConfiguration config = new HttpConfiguration(); + HttpConfiguration config = new HttpConfiguration(); - config.MessageHandlers.Add(new ActivityDisplayNameRouteEnrichingHandler()); + config.MessageHandlers.Add(new ActivityDisplayNameRouteEnrichingHandler()); - config.Routes.MapHttpRoute( - name: "DefaultApi", - routeTemplate: "api/{controller}/{id}", - defaults: new { id = RouteParameter.Optional }); + config.Routes.MapHttpRoute( + name: "DefaultApi", + routeTemplate: "api/{controller}/{id}", + defaults: new { id = RouteParameter.Optional }); - appBuilder.UseWebApi(config); - }); + appBuilder.UseWebApi(config); + }); - using var openTelemetry = Sdk.CreateTracerProviderBuilder() - .SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("Owin-Example")) - .AddOwinInstrumentation() - .AddConsoleExporter() - .Build(); + using var openTelemetry = Sdk.CreateTracerProviderBuilder() + .SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("Owin-Example")) + .AddOwinInstrumentation() + .AddConsoleExporter() + .Build(); - Console.WriteLine("Service listening. Press enter to exit."); - Console.ReadLine(); - } + Console.WriteLine("Service listening. Press enter to exit."); + Console.ReadLine(); + } - private class ActivityDisplayNameRouteEnrichingHandler : DelegatingHandler + private class ActivityDisplayNameRouteEnrichingHandler : DelegatingHandler + { + protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { - protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + try { - try - { - return await base.SendAsync(request, cancellationToken).ConfigureAwait(false); - } - finally + return await base.SendAsync(request, cancellationToken).ConfigureAwait(false); + } + finally + { + var activity = Activity.Current; + if (activity != null) { - var activity = Activity.Current; - if (activity != null) + var routeData = request.GetRouteData(); + if (routeData != null) { - var routeData = request.GetRouteData(); - if (routeData != null) - { - activity.DisplayName = routeData.Route.RouteTemplate; - } + activity.DisplayName = routeData.Route.RouteTemplate; } } } diff --git a/examples/redis/Examples.StackExchangeRedis/Program.cs b/examples/redis/Examples.StackExchangeRedis/Program.cs index b36b680f5a..e395b698b5 100644 --- a/examples/redis/Examples.StackExchangeRedis/Program.cs +++ b/examples/redis/Examples.StackExchangeRedis/Program.cs @@ -14,7 +14,6 @@ // limitations under the License. // -using System.Diagnostics; using OpenTelemetry; using OpenTelemetry.Trace; using StackExchange.Redis; @@ -37,7 +36,7 @@ public static void Main() .AddConsoleExporter() .AddRedisInstrumentation(connection, options => { - // changing flushinterval from 10s to 5s + // changing flush interval from 10s to 5s options.FlushInterval = TimeSpan.FromSeconds(5); }) .Build(); diff --git a/examples/wcf/client-core/Program.cs b/examples/wcf/client-core/Program.cs index c1b958d6c6..96504c1f0c 100644 --- a/examples/wcf/client-core/Program.cs +++ b/examples/wcf/client-core/Program.cs @@ -25,70 +25,69 @@ using OpenTelemetry.Resources; using OpenTelemetry.Trace; -namespace Examples.Wcf.Client +namespace Examples.Wcf.Client; + +internal static class Program { - internal static class Program + public static async Task Main() { - public static async Task Main() - { - IConfigurationRoot config = new ConfigurationBuilder() - .SetBasePath(Directory.GetCurrentDirectory()) - .AddJsonFile("appsettings.json") - .Build(); + IConfigurationRoot config = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json") + .Build(); - using var openTelemetry = Sdk.CreateTracerProviderBuilder() - .SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("Wcf-Client-Core")) - .AddWcfInstrumentation() - .AddZipkinExporter() - .Build(); + using var openTelemetry = Sdk.CreateTracerProviderBuilder() + .SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("Wcf-Client-Core")) + .AddWcfInstrumentation() + .AddZipkinExporter() + .Build(); - await CallService( - new BasicHttpBinding(BasicHttpSecurityMode.None), - new EndpointAddress(config.GetSection("Service").GetValue("HttpAddress"))).ConfigureAwait(false); - await CallService( - new NetTcpBinding(SecurityMode.None), - new EndpointAddress(config.GetSection("Service").GetValue("TcpAddress"))).ConfigureAwait(false); + await CallService( + new BasicHttpBinding(BasicHttpSecurityMode.None), + new EndpointAddress(config.GetSection("Service").GetValue("HttpAddress"))).ConfigureAwait(false); + await CallService( + new NetTcpBinding(SecurityMode.None), + new EndpointAddress(config.GetSection("Service").GetValue("TcpAddress"))).ConfigureAwait(false); - Console.WriteLine("Press enter to exit."); - Console.ReadLine(); - } + Console.WriteLine("Press enter to exit."); + Console.ReadLine(); + } - private static async Task CallService(Binding binding, EndpointAddress remoteAddress) + private static async Task CallService(Binding binding, EndpointAddress remoteAddress) + { + // Note: Best practice is to re-use your client/channel instances. + // This code is not meant to illustrate best practices, only the + // instrumentation. + StatusServiceClient client = new StatusServiceClient(binding, remoteAddress); + client.Endpoint.EndpointBehaviors.Add(new TelemetryEndpointBehavior()); + try { - // Note: Best practice is to re-use your client/channel instances. - // This code is not meant to illustrate best practices, only the - // instrumentation. - StatusServiceClient client = new StatusServiceClient(binding, remoteAddress); - client.Endpoint.EndpointBehaviors.Add(new TelemetryEndpointBehavior()); - try - { - await client.OpenAsync().ConfigureAwait(false); + await client.OpenAsync().ConfigureAwait(false); - var response = await client.PingAsync( - new StatusRequest - { - Status = Guid.NewGuid().ToString("N"), - }).ConfigureAwait(false); + var response = await client.PingAsync( + new StatusRequest + { + Status = Guid.NewGuid().ToString("N"), + }).ConfigureAwait(false); - Console.WriteLine($"Server returned: {response?.ServerTime}"); - } - finally + Console.WriteLine($"Server returned: {response?.ServerTime}"); + } + finally + { + try { - try + if (client.State == CommunicationState.Faulted) { - if (client.State == CommunicationState.Faulted) - { - client.Abort(); - } - else - { - await client.CloseAsync().ConfigureAwait(false); - } + client.Abort(); } - catch + else { + await client.CloseAsync().ConfigureAwait(false); } } + catch + { + } } } } diff --git a/examples/wcf/client-core/StatusServiceClient.cs b/examples/wcf/client-core/StatusServiceClient.cs index 11a2e533f4..ac8e4a2301 100644 --- a/examples/wcf/client-core/StatusServiceClient.cs +++ b/examples/wcf/client-core/StatusServiceClient.cs @@ -18,33 +18,32 @@ using System.ServiceModel.Channels; using System.Threading.Tasks; -namespace Examples.Wcf.Client +namespace Examples.Wcf.Client; + +public class StatusServiceClient : ClientBase, IStatusServiceContract { - public class StatusServiceClient : ClientBase, IStatusServiceContract + public StatusServiceClient(string name) + : base(name) { - public StatusServiceClient(string name) - : base(name) - { - } + } - public StatusServiceClient(Binding binding, EndpointAddress remoteAddress) - : base(binding, remoteAddress) - { - } + public StatusServiceClient(Binding binding, EndpointAddress remoteAddress) + : base(binding, remoteAddress) + { + } - public Task PingAsync(StatusRequest request) - => this.Channel.PingAsync(request); + public Task PingAsync(StatusRequest request) + => this.Channel.PingAsync(request); - public Task OpenAsync() - { - ICommunicationObject communicationObject = this; - return Task.Factory.FromAsync(communicationObject.BeginOpen, communicationObject.EndOpen, null); - } + public Task OpenAsync() + { + ICommunicationObject communicationObject = this; + return Task.Factory.FromAsync(communicationObject.BeginOpen, communicationObject.EndOpen, null); + } - public Task CloseAsync() - { - ICommunicationObject communicationObject = this; - return Task.Factory.FromAsync(communicationObject.BeginClose, communicationObject.EndClose, null); - } + public Task CloseAsync() + { + ICommunicationObject communicationObject = this; + return Task.Factory.FromAsync(communicationObject.BeginClose, communicationObject.EndClose, null); } } diff --git a/examples/wcf/client-netframework/Program.cs b/examples/wcf/client-netframework/Program.cs index 19882fef1a..dddbedcf1e 100644 --- a/examples/wcf/client-netframework/Program.cs +++ b/examples/wcf/client-netframework/Program.cs @@ -21,60 +21,59 @@ using OpenTelemetry.Resources; using OpenTelemetry.Trace; -namespace Examples.Wcf.Client +namespace Examples.Wcf.Client; + +internal static class Program { - internal static class Program + public static async Task Main() { - public static async Task Main() - { - using var openTelemetry = Sdk.CreateTracerProviderBuilder() - .SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("Wcf-Client")) - .AddWcfInstrumentation() - .AddZipkinExporter() - .Build(); + using var openTelemetry = Sdk.CreateTracerProviderBuilder() + .SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("Wcf-Client")) + .AddWcfInstrumentation() + .AddZipkinExporter() + .Build(); - await CallService("StatusService_Http").ConfigureAwait(false); - await CallService("StatusService_Tcp").ConfigureAwait(false); + await CallService("StatusService_Http").ConfigureAwait(false); + await CallService("StatusService_Tcp").ConfigureAwait(false); - Console.WriteLine("Press enter to exit."); - Console.ReadLine(); - } + Console.WriteLine("Press enter to exit."); + Console.ReadLine(); + } - private static async Task CallService(string name) + private static async Task CallService(string name) + { + // Note: Best practice is to re-use your client/channel instances. + // This code is not meant to illustrate best practices, only the + // instrumentation. + StatusServiceClient client = new StatusServiceClient(name); + try { - // Note: Best practice is to re-use your client/channel instances. - // This code is not meant to illustrate best practices, only the - // instrumentation. - StatusServiceClient client = new StatusServiceClient(name); - try - { - await client.OpenAsync().ConfigureAwait(false); + await client.OpenAsync().ConfigureAwait(false); - var response = await client.PingAsync( - new StatusRequest - { - Status = Guid.NewGuid().ToString("N"), - }).ConfigureAwait(false); + var response = await client.PingAsync( + new StatusRequest + { + Status = Guid.NewGuid().ToString("N"), + }).ConfigureAwait(false); - Console.WriteLine($"Server returned: {response?.ServerTime}"); - } - finally + Console.WriteLine($"Server returned: {response?.ServerTime}"); + } + finally + { + try { - try + if (client.State == CommunicationState.Faulted) { - if (client.State == CommunicationState.Faulted) - { - client.Abort(); - } - else - { - await client.CloseAsync().ConfigureAwait(false); - } + client.Abort(); } - catch + else { + await client.CloseAsync().ConfigureAwait(false); } } + catch + { + } } } } diff --git a/examples/wcf/client-netframework/StatusServiceClient.cs b/examples/wcf/client-netframework/StatusServiceClient.cs index 5cfe67a273..b7c28e21e5 100644 --- a/examples/wcf/client-netframework/StatusServiceClient.cs +++ b/examples/wcf/client-netframework/StatusServiceClient.cs @@ -17,28 +17,27 @@ using System.ServiceModel; using System.Threading.Tasks; -namespace Examples.Wcf.Client +namespace Examples.Wcf.Client; + +public class StatusServiceClient : ClientBase, IStatusServiceContract { - public class StatusServiceClient : ClientBase, IStatusServiceContract + public StatusServiceClient(string name) + : base(name) { - public StatusServiceClient(string name) - : base(name) - { - } + } - public Task PingAsync(StatusRequest request) - => this.Channel.PingAsync(request); + public Task PingAsync(StatusRequest request) + => this.Channel.PingAsync(request); - public Task OpenAsync() - { - ICommunicationObject communicationObject = this; - return Task.Factory.FromAsync(communicationObject.BeginOpen, communicationObject.EndOpen, null); - } + public Task OpenAsync() + { + ICommunicationObject communicationObject = this; + return Task.Factory.FromAsync(communicationObject.BeginOpen, communicationObject.EndOpen, null); + } - public Task CloseAsync() - { - ICommunicationObject communicationObject = this; - return Task.Factory.FromAsync(communicationObject.BeginClose, communicationObject.EndClose, null); - } + public Task CloseAsync() + { + ICommunicationObject communicationObject = this; + return Task.Factory.FromAsync(communicationObject.BeginClose, communicationObject.EndClose, null); } } diff --git a/examples/wcf/server-netframework/Program.cs b/examples/wcf/server-netframework/Program.cs index c09b115db4..a2a230b5fd 100644 --- a/examples/wcf/server-netframework/Program.cs +++ b/examples/wcf/server-netframework/Program.cs @@ -20,25 +20,24 @@ using OpenTelemetry.Resources; using OpenTelemetry.Trace; -namespace Examples.Wcf.Server +namespace Examples.Wcf.Server; + +internal static class Program { - internal static class Program + public static void Main() { - public static void Main() - { - using var openTelemetry = Sdk.CreateTracerProviderBuilder() - .SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("Wcf-Server")) - .AddWcfInstrumentation() - .AddZipkinExporter() - .Build(); + using var openTelemetry = Sdk.CreateTracerProviderBuilder() + .SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("Wcf-Server")) + .AddWcfInstrumentation() + .AddZipkinExporter() + .Build(); - ServiceHost serviceHost = new ServiceHost(typeof(StatusService)); - serviceHost.Open(); + ServiceHost serviceHost = new ServiceHost(typeof(StatusService)); + serviceHost.Open(); - Console.WriteLine("Service listening. Press enter to exit."); - Console.ReadLine(); + Console.WriteLine("Service listening. Press enter to exit."); + Console.ReadLine(); - serviceHost.Close(); - } + serviceHost.Close(); } } diff --git a/examples/wcf/server-netframework/StatusService.cs b/examples/wcf/server-netframework/StatusService.cs index e2553b9020..e173d122a3 100644 --- a/examples/wcf/server-netframework/StatusService.cs +++ b/examples/wcf/server-netframework/StatusService.cs @@ -18,23 +18,22 @@ using System.ServiceModel; using System.Threading.Tasks; -namespace Examples.Wcf.Server +namespace Examples.Wcf.Server; + +[ServiceBehavior( + Namespace = "http://opentelemetry.io/", + ConcurrencyMode = ConcurrencyMode.Multiple, + InstanceContextMode = InstanceContextMode.Single, + UseSynchronizationContext = false, + Name = "StatusService")] +public class StatusService : IStatusServiceContract { - [ServiceBehavior( - Namespace = "http://opentelemetry.io/", - ConcurrencyMode = ConcurrencyMode.Multiple, - InstanceContextMode = InstanceContextMode.Single, - UseSynchronizationContext = false, - Name = "StatusService")] - public class StatusService : IStatusServiceContract + public Task PingAsync(StatusRequest request) { - public Task PingAsync(StatusRequest request) - { - return Task.FromResult( - new StatusResponse - { - ServerTime = DateTimeOffset.UtcNow, - }); - } + return Task.FromResult( + new StatusResponse + { + ServerTime = DateTimeOffset.UtcNow, + }); } } diff --git a/examples/wcf/shared/IStatusServiceContract.cs b/examples/wcf/shared/IStatusServiceContract.cs index cf7c8a73ad..0c620e9472 100644 --- a/examples/wcf/shared/IStatusServiceContract.cs +++ b/examples/wcf/shared/IStatusServiceContract.cs @@ -17,12 +17,11 @@ using System.ServiceModel; using System.Threading.Tasks; -namespace Examples.Wcf +namespace Examples.Wcf; + +[ServiceContract(Namespace = "http://opentelemetry.io/", Name = "StatusService", SessionMode = SessionMode.Allowed)] +public interface IStatusServiceContract { - [ServiceContract(Namespace = "http://opentelemetry.io/", Name = "StatusService", SessionMode = SessionMode.Allowed)] - public interface IStatusServiceContract - { - [OperationContract] - Task PingAsync(StatusRequest request); - } + [OperationContract] + Task PingAsync(StatusRequest request); } diff --git a/examples/wcf/shared/StatusRequest.cs b/examples/wcf/shared/StatusRequest.cs index 1061df0261..701b1f3bee 100644 --- a/examples/wcf/shared/StatusRequest.cs +++ b/examples/wcf/shared/StatusRequest.cs @@ -16,12 +16,11 @@ using System.Runtime.Serialization; -namespace Examples.Wcf +namespace Examples.Wcf; + +[DataContract] +public class StatusRequest { - [DataContract] - public class StatusRequest - { - [DataMember] - public string Status { get; set; } - } + [DataMember] + public string Status { get; set; } } diff --git a/examples/wcf/shared/StatusResponse.cs b/examples/wcf/shared/StatusResponse.cs index b3d43b27c0..1207917842 100644 --- a/examples/wcf/shared/StatusResponse.cs +++ b/examples/wcf/shared/StatusResponse.cs @@ -17,12 +17,11 @@ using System; using System.Runtime.Serialization; -namespace Examples.Wcf +namespace Examples.Wcf; + +[DataContract] +public class StatusResponse { - [DataContract] - public class StatusResponse - { - [DataMember] - public DateTimeOffset ServerTime { get; set; } - } + [DataMember] + public DateTimeOffset ServerTime { get; set; } } diff --git a/test/OpenTelemetry.Exporter.Geneva.Benchmark/Exporter/Food.cs b/test/OpenTelemetry.Exporter.Geneva.Benchmark/Exporter/Food.cs index 8ce08e7269..5c553eb788 100644 --- a/test/OpenTelemetry.Exporter.Geneva.Benchmark/Exporter/Food.cs +++ b/test/OpenTelemetry.Exporter.Geneva.Benchmark/Exporter/Food.cs @@ -16,15 +16,14 @@ using Microsoft.Extensions.Logging; -namespace OpenTelemetry.Exporter.Geneva.Benchmark +namespace OpenTelemetry.Exporter.Geneva.Benchmark; + +public static partial class Food { - public static partial class Food - { - [LoggerMessage( - EventId = 0, - Level = LogLevel.Information, - Message = "Hello from {food} {price}.")] - public static partial void SayHello( - ILogger logger, string food, double price); - } + [LoggerMessage( + EventId = 0, + Level = LogLevel.Information, + Message = "Hello from {food} {price}.")] + public static partial void SayHello( + ILogger logger, string food, double price); } diff --git a/test/OpenTelemetry.Exporter.Geneva.Benchmark/Exporter/LogExporterBenchmarks.cs b/test/OpenTelemetry.Exporter.Geneva.Benchmark/Exporter/LogExporterBenchmarks.cs index b839bd5f14..876d10f014 100644 --- a/test/OpenTelemetry.Exporter.Geneva.Benchmark/Exporter/LogExporterBenchmarks.cs +++ b/test/OpenTelemetry.Exporter.Geneva.Benchmark/Exporter/LogExporterBenchmarks.cs @@ -15,7 +15,6 @@ // using System.Collections.Generic; -using System.Diagnostics; using BenchmarkDotNet.Attributes; using Microsoft.Extensions.Logging; using OpenTelemetry.Logs; @@ -59,69 +58,69 @@ With Scopes (https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull | Export | True | 772.2 ns | 14.02 ns | 13.11 ns | 774.8 ns | 0.0200 | 128 B | */ -namespace OpenTelemetry.Exporter.Geneva.Benchmark +namespace OpenTelemetry.Exporter.Geneva.Benchmark; + +[MemoryDiagnoser] +public class LogExporterBenchmarks { - [MemoryDiagnoser] - public class LogExporterBenchmarks - { - private readonly ILogger logger; - private readonly ILoggerFactory loggerFactory; - private readonly GenevaLogExporter exporter; - private readonly LogRecord logRecord; - private readonly Batch batch; + private readonly ILogger logger; + private readonly ILoggerFactory loggerFactory; + private readonly GenevaLogExporter exporter; + private readonly LogRecord logRecord; + private readonly Batch batch; - [Params(true, false)] - public bool IncludeFormattedMessage { get; set; } + [Params(true, false)] + public bool IncludeFormattedMessage { get; set; } - public LogExporterBenchmarks() - { - // for total cost of logging + msgpack serialization + export - this.loggerFactory = LoggerFactory.Create(builder => builder - .AddOpenTelemetry(loggerOptions => - { - loggerOptions.AddGenevaLogExporter(exporterOptions => - { - exporterOptions.ConnectionString = "EtwSession=OpenTelemetry"; - exporterOptions.PrepopulatedFields = new Dictionary - { - ["cloud.role"] = "BusyWorker", - ["cloud.roleInstance"] = "CY1SCH030021417", - ["cloud.roleVer"] = "9.0.15289.2", - }; - }); - - loggerOptions.IncludeFormattedMessage = this.IncludeFormattedMessage; - })); - - this.logger = this.loggerFactory.CreateLogger("TestLogger"); - - // For msgpack serialization + export - this.logRecord = GenerateTestLogRecord(); - this.batch = GenerateTestLogRecordBatch(); - this.exporter = new GenevaLogExporter(new GenevaExporterOptions + public LogExporterBenchmarks() + { + // for total cost of logging + msgpack serialization + export + this.loggerFactory = LoggerFactory.Create(builder => builder + .AddOpenTelemetry(loggerOptions => { - ConnectionString = "EtwSession=OpenTelemetry", - PrepopulatedFields = new Dictionary + loggerOptions.AddGenevaLogExporter(exporterOptions => { - ["cloud.role"] = "BusyWorker", - ["cloud.roleInstance"] = "CY1SCH030021417", - ["cloud.roleVer"] = "9.0.15289.2", - }, - }); - } + exporterOptions.ConnectionString = "EtwSession=OpenTelemetry"; + exporterOptions.PrepopulatedFields = new Dictionary + { + ["cloud.role"] = "BusyWorker", + ["cloud.roleInstance"] = "CY1SCH030021417", + ["cloud.roleVer"] = "9.0.15289.2", + }; + }); - [Benchmark] - public void LoggerWithMessageTemplate() - { - this.logger.LogInformation("Hello from {food} {price}.", "artichoke", 3.99); - } + loggerOptions.IncludeFormattedMessage = this.IncludeFormattedMessage; + })); + + this.logger = this.loggerFactory.CreateLogger("TestLogger"); - [Benchmark] - public void LoggerWithDirectLoggerAPI() + // For msgpack serialization + export + this.logRecord = GenerateTestLogRecord(); + this.batch = GenerateTestLogRecordBatch(); + this.exporter = new GenevaLogExporter(new GenevaExporterOptions { - var food = "artichoke"; - var price = 3.99; - this.logger.Log( + ConnectionString = "EtwSession=OpenTelemetry", + PrepopulatedFields = new Dictionary + { + ["cloud.role"] = "BusyWorker", + ["cloud.roleInstance"] = "CY1SCH030021417", + ["cloud.roleVer"] = "9.0.15289.2", + }, + }); + } + + [Benchmark] + public void LoggerWithMessageTemplate() + { + this.logger.LogInformation("Hello from {food} {price}.", "artichoke", 3.99); + } + + [Benchmark] + public void LoggerWithDirectLoggerAPI() + { + var food = "artichoke"; + var price = 3.99; + this.logger.Log( logLevel: LogLevel.Information, eventId: default, state: new List>() @@ -131,72 +130,71 @@ public void LoggerWithDirectLoggerAPI() }, exception: null, formatter: (state, ex) => $"Hello from {food} {price}."); - } + } - [Benchmark] - public void LoggerWithSourceGenerator() - { - Food.SayHello(this.logger, "artichoke", 3.99); - } + [Benchmark] + public void LoggerWithSourceGenerator() + { + Food.SayHello(this.logger, "artichoke", 3.99); + } - [Benchmark] - public void SerializeLogRecord() - { - this.exporter.SerializeLogRecord(this.logRecord); - } + [Benchmark] + public void SerializeLogRecord() + { + this.exporter.SerializeLogRecord(this.logRecord); + } - [Benchmark] - public void Export() - { - this.exporter.Export(this.batch); - } + [Benchmark] + public void Export() + { + this.exporter.Export(this.batch); + } - [GlobalCleanup] - public void Cleanup() - { - this.loggerFactory.Dispose(); - this.batch.Dispose(); - this.exporter.Dispose(); - } + [GlobalCleanup] + public void Cleanup() + { + this.loggerFactory.Dispose(); + this.batch.Dispose(); + this.exporter.Dispose(); + } - private static LogRecord GenerateTestLogRecord() - { - var items = new List(1); - using var factory = LoggerFactory.Create(builder => builder - .AddOpenTelemetry(loggerOptions => - { - loggerOptions.AddInMemoryExporter(items); - })); + private static LogRecord GenerateTestLogRecord() + { + var items = new List(1); + using var factory = LoggerFactory.Create(builder => builder + .AddOpenTelemetry(loggerOptions => + { + loggerOptions.AddInMemoryExporter(items); + })); - var logger = factory.CreateLogger("TestLogger"); - logger.LogInformation("Hello from {food} {price}.", "artichoke", 3.99); - return items[0]; - } + var logger = factory.CreateLogger("TestLogger"); + logger.LogInformation("Hello from {food} {price}.", "artichoke", 3.99); + return items[0]; + } - private static Batch GenerateTestLogRecordBatch() - { - var items = new List(1); - using var batchGeneratorExporter = new BatchGeneratorExporter(); - using var factory = LoggerFactory.Create(builder => builder - .AddOpenTelemetry(loggerOptions => - { - loggerOptions.AddProcessor(new SimpleLogRecordExportProcessor(batchGeneratorExporter)); - })); + private static Batch GenerateTestLogRecordBatch() + { + var items = new List(1); + using var batchGeneratorExporter = new BatchGeneratorExporter(); + using var factory = LoggerFactory.Create(builder => builder + .AddOpenTelemetry(loggerOptions => + { + loggerOptions.AddProcessor(new SimpleLogRecordExportProcessor(batchGeneratorExporter)); + })); - var logger = factory.CreateLogger("TestLogger"); - logger.LogInformation("Hello from {food} {price}.", "artichoke", 3.99); - return batchGeneratorExporter.Batch; - } + var logger = factory.CreateLogger("TestLogger"); + logger.LogInformation("Hello from {food} {price}.", "artichoke", 3.99); + return batchGeneratorExporter.Batch; + } - private class BatchGeneratorExporter : BaseExporter - { - public Batch Batch { get; set; } + private class BatchGeneratorExporter : BaseExporter + { + public Batch Batch { get; set; } - public override ExportResult Export(in Batch batch) - { - this.Batch = batch; - return ExportResult.Success; - } + public override ExportResult Export(in Batch batch) + { + this.Batch = batch; + return ExportResult.Success; } } } diff --git a/test/OpenTelemetry.Exporter.Geneva.Benchmark/Exporter/MetricExporterBenchmarks.cs b/test/OpenTelemetry.Exporter.Geneva.Benchmark/Exporter/MetricExporterBenchmarks.cs index 425cfb815c..0bb882d50b 100644 --- a/test/OpenTelemetry.Exporter.Geneva.Benchmark/Exporter/MetricExporterBenchmarks.cs +++ b/test/OpenTelemetry.Exporter.Geneva.Benchmark/Exporter/MetricExporterBenchmarks.cs @@ -49,167 +49,167 @@ | ExportHistogramMetricItemWith4Dimensions | 618.47 ns | 4.946 ns | 4.384 ns | - | */ -namespace OpenTelemetry.Exporter.Geneva.Benchmark +namespace OpenTelemetry.Exporter.Geneva.Benchmark; + +[MemoryDiagnoser] +public class MetricExporterBenchmarks { - [MemoryDiagnoser] - public class MetricExporterBenchmarks + private Metric counterMetricWith3Dimensions; + private Metric counterMetricWith4Dimensions; + private MetricPoint counterMetricPointWith3Dimensions; + private MetricPoint counterMetricPointWith4Dimensions; + private MetricData counterMetricDataWith3Dimensions; + private MetricData counterMetricDataWith4Dimensions; + private Batch counterMetricBatchWith3Dimensions; + private Batch counterMetricBatchWith4Dimensions; + private Metric histogramMetricWith3Dimensions; + private Metric histogramMetricWith4Dimensions; + private MetricPoint histogramMetricPointWith3Dimensions; + private MetricPoint histogramMetricPointWith4Dimensions; + private MetricData histogramSumWith3Dimensions; + private MetricData histogramSumWith4Dimensions; + private uint histogramCountWith3Dimensions; + private uint histogramCountWith4Dimensions; + private Batch histogramMetricBatchWith3Dimensions; + private Batch histogramMetricBatchWith4Dimensions; + private Meter meterWithNoListener = new Meter("MeterWithNoListener", "0.0.1"); + private Meter meterWithListener = new Meter("MeterWithListener", "0.0.1"); + private Meter meterWithDummyReader = new Meter("MeterWithDummyReader", "0.0.1"); + private Meter meterWithGenevaMetricExporter = new Meter("MeterWithGenevaMetricExporter", "0.0.1"); + private Counter counterWithNoListener; + private Counter counterWithListener; + private Counter counterWithDummyReader; + private Counter counterWithGenevaMetricExporter; + private MeterListener listener; + private MeterProvider meterProviderWithDummyReader; + private MeterProvider meterProviderWithGenevaMetricExporter; + private MeterProvider meterProviderForCounterBatchWith3Dimensions; + private MeterProvider meterProviderForCounterBatchWith4Dimensions; + private MeterProvider meterProviderForHistogramBatchWith3Dimensions; + private MeterProvider meterProviderForHistogramBatchWith4Dimensions; + private GenevaMetricExporter exporter; + private ThreadLocal random = new ThreadLocal(() => new Random()); + + private static readonly Random randomForHistogram = new Random(); // Use the same seed for all the benchmarks to have the same data exported + private static readonly string[] dimensionValues = new string[] { "DimVal1", "DimVal2", "DimVal3", "DimVal4", "DimVal5", "DimVal6", "DimVal7", "DimVal8", "DimVal9", "DimVal10" }; + + [GlobalSetup] + public void Setup() { - private Metric counterMetricWith3Dimensions; - private Metric counterMetricWith4Dimensions; - private MetricPoint counterMetricPointWith3Dimensions; - private MetricPoint counterMetricPointWith4Dimensions; - private MetricData counterMetricDataWith3Dimensions; - private MetricData counterMetricDataWith4Dimensions; - private Batch counterMetricBatchWith3Dimensions; - private Batch counterMetricBatchWith4Dimensions; - private Metric histogramMetricWith3Dimensions; - private Metric histogramMetricWith4Dimensions; - private MetricPoint histogramMetricPointWith3Dimensions; - private MetricPoint histogramMetricPointWith4Dimensions; - private MetricData histogramSumWith3Dimensions; - private MetricData histogramSumWith4Dimensions; - private uint histogramCountWith3Dimensions; - private uint histogramCountWith4Dimensions; - private Batch histogramMetricBatchWith3Dimensions; - private Batch histogramMetricBatchWith4Dimensions; - private Meter meterWithNoListener = new Meter("MeterWithNoListener", "0.0.1"); - private Meter meterWithListener = new Meter("MeterWithListener", "0.0.1"); - private Meter meterWithDummyReader = new Meter("MeterWithDummyReader", "0.0.1"); - private Meter meterWithGenevaMetricExporter = new Meter("MeterWithGenevaMetricExporter", "0.0.1"); - private Counter counterWithNoListener; - private Counter counterWithListener; - private Counter counterWithDummyReader; - private Counter counterWithGenevaMetricExporter; - private MeterListener listener; - private MeterProvider meterProviderWithDummyReader; - private MeterProvider meterProviderWithGenevaMetricExporter; - private MeterProvider meterProviderForCounterBatchWith3Dimensions; - private MeterProvider meterProviderForCounterBatchWith4Dimensions; - private MeterProvider meterProviderForHistogramBatchWith3Dimensions; - private MeterProvider meterProviderForHistogramBatchWith4Dimensions; - private GenevaMetricExporter exporter; - private ThreadLocal random = new ThreadLocal(() => new Random()); - - private static readonly Random randomForHistogram = new Random(); // Use the same seed for all the benchmarks to have the same data exported - private static readonly string[] dimensionValues = new string[] { "DimVal1", "DimVal2", "DimVal3", "DimVal4", "DimVal5", "DimVal6", "DimVal7", "DimVal8", "DimVal9", "DimVal10" }; - - [GlobalSetup] - public void Setup() - { - this.counterWithNoListener = this.meterWithNoListener.CreateCounter("counter"); - this.counterWithListener = this.meterWithListener.CreateCounter("counter"); - this.counterWithDummyReader = this.meterWithDummyReader.CreateCounter("counter"); - this.counterWithGenevaMetricExporter = this.meterWithGenevaMetricExporter.CreateCounter("counter"); + this.counterWithNoListener = this.meterWithNoListener.CreateCounter("counter"); + this.counterWithListener = this.meterWithListener.CreateCounter("counter"); + this.counterWithDummyReader = this.meterWithDummyReader.CreateCounter("counter"); + this.counterWithGenevaMetricExporter = this.meterWithGenevaMetricExporter.CreateCounter("counter"); - var exporterOptions = new GenevaMetricExporterOptions() { ConnectionString = "Account=OTelMonitoringAccount;Namespace=OTelMetricNamespace" }; - this.exporter = new GenevaMetricExporter(exporterOptions); + var exporterOptions = new GenevaMetricExporterOptions() { ConnectionString = "Account=OTelMonitoringAccount;Namespace=OTelMetricNamespace" }; + this.exporter = new GenevaMetricExporter(exporterOptions); - this.counterMetricPointWith3Dimensions = this.GenerateCounterMetricItemWith3Dimensions(out this.counterMetricDataWith3Dimensions); - this.counterMetricPointWith4Dimensions = this.GenerateCounterMetricItemWith4Dimensions(out this.counterMetricDataWith4Dimensions); + this.counterMetricPointWith3Dimensions = this.GenerateCounterMetricItemWith3Dimensions(out this.counterMetricDataWith3Dimensions); + this.counterMetricPointWith4Dimensions = this.GenerateCounterMetricItemWith4Dimensions(out this.counterMetricDataWith4Dimensions); - this.counterMetricBatchWith3Dimensions = this.GenerateCounterBatchWith3Dimensions(); - this.counterMetricBatchWith4Dimensions = this.GenerateCounterBatchWith4Dimensions(); + this.counterMetricBatchWith3Dimensions = this.GenerateCounterBatchWith3Dimensions(); + this.counterMetricBatchWith4Dimensions = this.GenerateCounterBatchWith4Dimensions(); - using var enumeratorForCounterBatchWith3Dimensions = this.counterMetricBatchWith3Dimensions.GetEnumerator(); - enumeratorForCounterBatchWith3Dimensions.MoveNext(); - this.counterMetricWith3Dimensions = enumeratorForCounterBatchWith3Dimensions.Current; + using var enumeratorForCounterBatchWith3Dimensions = this.counterMetricBatchWith3Dimensions.GetEnumerator(); + enumeratorForCounterBatchWith3Dimensions.MoveNext(); + this.counterMetricWith3Dimensions = enumeratorForCounterBatchWith3Dimensions.Current; - using var enumeratorForCounterBatchWith4Dimensions = this.counterMetricBatchWith4Dimensions.GetEnumerator(); - enumeratorForCounterBatchWith4Dimensions.MoveNext(); - this.counterMetricWith4Dimensions = enumeratorForCounterBatchWith4Dimensions.Current; + using var enumeratorForCounterBatchWith4Dimensions = this.counterMetricBatchWith4Dimensions.GetEnumerator(); + enumeratorForCounterBatchWith4Dimensions.MoveNext(); + this.counterMetricWith4Dimensions = enumeratorForCounterBatchWith4Dimensions.Current; - this.histogramMetricPointWith3Dimensions = this.GenerateHistogramMetricItemWith3Dimensions(out this.histogramSumWith3Dimensions, out this.histogramCountWith3Dimensions); - this.histogramMetricPointWith4Dimensions = this.GenerateHistogramMetricItemWith4Dimensions(out this.histogramSumWith4Dimensions, out this.histogramCountWith4Dimensions); + this.histogramMetricPointWith3Dimensions = this.GenerateHistogramMetricItemWith3Dimensions(out this.histogramSumWith3Dimensions, out this.histogramCountWith3Dimensions); + this.histogramMetricPointWith4Dimensions = this.GenerateHistogramMetricItemWith4Dimensions(out this.histogramSumWith4Dimensions, out this.histogramCountWith4Dimensions); - this.histogramMetricBatchWith3Dimensions = this.GenerateHistogramBatchWith3Dimensions(); - this.histogramMetricBatchWith4Dimensions = this.GenerateHistogramBatchWith4Dimensions(); + this.histogramMetricBatchWith3Dimensions = this.GenerateHistogramBatchWith3Dimensions(); + this.histogramMetricBatchWith4Dimensions = this.GenerateHistogramBatchWith4Dimensions(); - using var enumeratorForHistogramBatchWith3Dimensions = this.histogramMetricBatchWith3Dimensions.GetEnumerator(); - enumeratorForHistogramBatchWith3Dimensions.MoveNext(); - this.histogramMetricWith3Dimensions = enumeratorForHistogramBatchWith3Dimensions.Current; + using var enumeratorForHistogramBatchWith3Dimensions = this.histogramMetricBatchWith3Dimensions.GetEnumerator(); + enumeratorForHistogramBatchWith3Dimensions.MoveNext(); + this.histogramMetricWith3Dimensions = enumeratorForHistogramBatchWith3Dimensions.Current; - using var enumeratorForHistogramBatchWith4Dimensions = this.histogramMetricBatchWith4Dimensions.GetEnumerator(); - enumeratorForHistogramBatchWith4Dimensions.MoveNext(); - this.histogramMetricWith4Dimensions = enumeratorForHistogramBatchWith4Dimensions.Current; + using var enumeratorForHistogramBatchWith4Dimensions = this.histogramMetricBatchWith4Dimensions.GetEnumerator(); + enumeratorForHistogramBatchWith4Dimensions.MoveNext(); + this.histogramMetricWith4Dimensions = enumeratorForHistogramBatchWith4Dimensions.Current; - #region Setup MeterListener - this.listener = new MeterListener(); - this.listener.InstrumentPublished = (instrument, listener) => + #region Setup MeterListener + this.listener = new MeterListener(); + this.listener.InstrumentPublished = (instrument, listener) => + { + if (instrument.Meter.Name == this.meterWithListener.Name) { - if (instrument.Meter.Name == this.meterWithListener.Name) - { - listener.EnableMeasurementEvents(instrument); - } - }; + listener.EnableMeasurementEvents(instrument); + } + }; - this.listener.Start(); - #endregion + this.listener.Start(); + #endregion - this.meterProviderWithDummyReader = Sdk.CreateMeterProviderBuilder() + this.meterProviderWithDummyReader = Sdk.CreateMeterProviderBuilder() .AddMeter(this.meterWithDummyReader.Name) .AddReader(new DummyReader(new DummyMetricExporter())) .Build(); - this.meterProviderWithGenevaMetricExporter = Sdk.CreateMeterProviderBuilder() + this.meterProviderWithGenevaMetricExporter = Sdk.CreateMeterProviderBuilder() .AddMeter(this.meterWithGenevaMetricExporter.Name) .AddGenevaMetricExporter(options => { options.ConnectionString = "Account=OTelMonitoringAccount;Namespace=OTelMetricNamespace"; }) .Build(); - } + } + + private MetricPoint GenerateCounterMetricItemWith3Dimensions(out MetricData metricData) + { + using var meterWithInMemoryExporter = new Meter("GenerateCounterMetricItemWith3Dimensions", "0.0.1"); + var counter = meterWithInMemoryExporter.CreateCounter("CounterWithThreeDimensions"); - private MetricPoint GenerateCounterMetricItemWith3Dimensions(out MetricData metricData) + var exportedItems = new List(); + using var inMemoryReader = new BaseExportingMetricReader(new InMemoryExporter(exportedItems)) { - using var meterWithInMemoryExporter = new Meter("GenerateCounterMetricItemWith3Dimensions", "0.0.1"); - var counter = meterWithInMemoryExporter.CreateCounter("CounterWithThreeDimensions"); + TemporalityPreference = MetricReaderTemporalityPreference.Delta, + }; - var exportedItems = new List(); - using var inMemoryReader = new BaseExportingMetricReader(new InMemoryExporter(exportedItems)) - { - TemporalityPreference = MetricReaderTemporalityPreference.Delta, - }; - - using var meterProvider = Sdk.CreateMeterProviderBuilder() - .AddMeter("GenerateCounterMetricItemWith3Dimensions") - .AddReader(inMemoryReader) - .Build(); - - counter.Add( - 100, - new("DimName1", dimensionValues[this.random.Value.Next(0, 10)]), - new("DimName2", dimensionValues[this.random.Value.Next(0, 10)]), - new("DimName3", dimensionValues[this.random.Value.Next(0, 10)])); - - inMemoryReader.Collect(); - - var metric = exportedItems[0]; - var metricPointsEnumerator = metric.GetMetricPoints().GetEnumerator(); - metricPointsEnumerator.MoveNext(); - var metricPoint = metricPointsEnumerator.Current; - var metricDataValue = Convert.ToUInt64(metricPoint.GetSumLong()); - metricData = new MetricData { UInt64Value = metricDataValue }; - - return metricPoint; - } + using var meterProvider = Sdk.CreateMeterProviderBuilder() + .AddMeter("GenerateCounterMetricItemWith3Dimensions") + .AddReader(inMemoryReader) + .Build(); - private MetricPoint GenerateCounterMetricItemWith4Dimensions(out MetricData metricData) - { - using var meterWithInMemoryExporter = new Meter("GenerateCounterMetricItemWith4Dimensions", "0.0.1"); - var counter = meterWithInMemoryExporter.CreateCounter("CounterWith4Dimensions"); + counter.Add( + 100, + new("DimName1", dimensionValues[this.random.Value.Next(0, 10)]), + new("DimName2", dimensionValues[this.random.Value.Next(0, 10)]), + new("DimName3", dimensionValues[this.random.Value.Next(0, 10)])); - var exportedItems = new List(); - using var inMemoryReader = new BaseExportingMetricReader(new InMemoryExporter(exportedItems)) - { - TemporalityPreference = MetricReaderTemporalityPreference.Delta, - }; + inMemoryReader.Collect(); + + var metric = exportedItems[0]; + var metricPointsEnumerator = metric.GetMetricPoints().GetEnumerator(); + metricPointsEnumerator.MoveNext(); + var metricPoint = metricPointsEnumerator.Current; + var metricDataValue = Convert.ToUInt64(metricPoint.GetSumLong()); + metricData = new MetricData { UInt64Value = metricDataValue }; + + return metricPoint; + } + + private MetricPoint GenerateCounterMetricItemWith4Dimensions(out MetricData metricData) + { + using var meterWithInMemoryExporter = new Meter("GenerateCounterMetricItemWith4Dimensions", "0.0.1"); + var counter = meterWithInMemoryExporter.CreateCounter("CounterWith4Dimensions"); + + var exportedItems = new List(); + using var inMemoryReader = new BaseExportingMetricReader(new InMemoryExporter(exportedItems)) + { + TemporalityPreference = MetricReaderTemporalityPreference.Delta, + }; - using var meterProvider = Sdk.CreateMeterProviderBuilder() - .AddMeter("GenerateCounterMetricItemWith4Dimensions") - .AddReader(inMemoryReader) - .Build(); + using var meterProvider = Sdk.CreateMeterProviderBuilder() + .AddMeter("GenerateCounterMetricItemWith4Dimensions") + .AddReader(inMemoryReader) + .Build(); - var tags = new TagList + var tags = new TagList { { "DimName1", dimensionValues[this.random.Value.Next(0, 2)] }, { "DimName2", dimensionValues[this.random.Value.Next(0, 5)] }, @@ -217,63 +217,63 @@ private MetricPoint GenerateCounterMetricItemWith4Dimensions(out MetricData metr { "DimName4", dimensionValues[this.random.Value.Next(0, 10)] }, }; - counter.Add(100, tags); + counter.Add(100, tags); - inMemoryReader.Collect(); + inMemoryReader.Collect(); - var metric = exportedItems[0]; - var metricPointsEnumerator = metric.GetMetricPoints().GetEnumerator(); - metricPointsEnumerator.MoveNext(); - var metricPoint = metricPointsEnumerator.Current; - var metricDataValue = Convert.ToUInt64(metricPoint.GetSumLong()); - metricData = new MetricData { UInt64Value = metricDataValue }; + var metric = exportedItems[0]; + var metricPointsEnumerator = metric.GetMetricPoints().GetEnumerator(); + metricPointsEnumerator.MoveNext(); + var metricPoint = metricPointsEnumerator.Current; + var metricDataValue = Convert.ToUInt64(metricPoint.GetSumLong()); + metricData = new MetricData { UInt64Value = metricDataValue }; - return metricPoint; - } + return metricPoint; + } - private Batch GenerateCounterBatchWith3Dimensions() + private Batch GenerateCounterBatchWith3Dimensions() + { + using var meterWithInMemoryExporter = new Meter("GenerateCounterBatchWith3Dimensions", "0.0.1"); + var counter = meterWithInMemoryExporter.CreateCounter("CounterWithThreeDimensions"); + + var batchGeneratorExporter = new BatchGenerator(); + var batchGeneratorReader = new BaseExportingMetricReader(batchGeneratorExporter) { - using var meterWithInMemoryExporter = new Meter("GenerateCounterBatchWith3Dimensions", "0.0.1"); - var counter = meterWithInMemoryExporter.CreateCounter("CounterWithThreeDimensions"); + TemporalityPreference = MetricReaderTemporalityPreference.Delta, + }; - var batchGeneratorExporter = new BatchGenerator(); - var batchGeneratorReader = new BaseExportingMetricReader(batchGeneratorExporter) - { - TemporalityPreference = MetricReaderTemporalityPreference.Delta, - }; - - this.meterProviderForCounterBatchWith3Dimensions = Sdk.CreateMeterProviderBuilder() - .AddMeter("GenerateCounterBatchWith3Dimensions") - .AddReader(batchGeneratorReader) - .Build(); - - counter.Add( - 100, - new("DimName1", dimensionValues[this.random.Value.Next(0, 10)]), - new("DimName2", dimensionValues[this.random.Value.Next(0, 10)]), - new("DimName3", dimensionValues[this.random.Value.Next(0, 10)])); - - this.meterProviderForCounterBatchWith3Dimensions.ForceFlush(); - return batchGeneratorExporter.Batch; - } + this.meterProviderForCounterBatchWith3Dimensions = Sdk.CreateMeterProviderBuilder() + .AddMeter("GenerateCounterBatchWith3Dimensions") + .AddReader(batchGeneratorReader) + .Build(); - private Batch GenerateCounterBatchWith4Dimensions() - { - using var meterWithInMemoryExporter = new Meter("GenerateCounterBatchWith4Dimensions", "0.0.1"); - var counter = meterWithInMemoryExporter.CreateCounter("CounterWith4Dimensions"); + counter.Add( + 100, + new("DimName1", dimensionValues[this.random.Value.Next(0, 10)]), + new("DimName2", dimensionValues[this.random.Value.Next(0, 10)]), + new("DimName3", dimensionValues[this.random.Value.Next(0, 10)])); - var batchGeneratorExporter = new BatchGenerator(); - var batchGeneratorReader = new BaseExportingMetricReader(batchGeneratorExporter) - { - TemporalityPreference = MetricReaderTemporalityPreference.Delta, - }; + this.meterProviderForCounterBatchWith3Dimensions.ForceFlush(); + return batchGeneratorExporter.Batch; + } + + private Batch GenerateCounterBatchWith4Dimensions() + { + using var meterWithInMemoryExporter = new Meter("GenerateCounterBatchWith4Dimensions", "0.0.1"); + var counter = meterWithInMemoryExporter.CreateCounter("CounterWith4Dimensions"); - this.meterProviderForCounterBatchWith4Dimensions = Sdk.CreateMeterProviderBuilder() - .AddMeter("GenerateCounterBatchWith4Dimensions") - .AddReader(batchGeneratorReader) - .Build(); + var batchGeneratorExporter = new BatchGenerator(); + var batchGeneratorReader = new BaseExportingMetricReader(batchGeneratorExporter) + { + TemporalityPreference = MetricReaderTemporalityPreference.Delta, + }; - var tags = new TagList + this.meterProviderForCounterBatchWith4Dimensions = Sdk.CreateMeterProviderBuilder() + .AddMeter("GenerateCounterBatchWith4Dimensions") + .AddReader(batchGeneratorReader) + .Build(); + + var tags = new TagList { { "DimName1", dimensionValues[this.random.Value.Next(0, 2)] }, { "DimName2", dimensionValues[this.random.Value.Next(0, 5)] }, @@ -281,66 +281,66 @@ private Batch GenerateCounterBatchWith4Dimensions() { "DimName4", dimensionValues[this.random.Value.Next(0, 10)] }, }; - counter.Add(100, tags); + counter.Add(100, tags); - this.meterProviderForCounterBatchWith4Dimensions.ForceFlush(); - return batchGeneratorExporter.Batch; - } + this.meterProviderForCounterBatchWith4Dimensions.ForceFlush(); + return batchGeneratorExporter.Batch; + } + + private MetricPoint GenerateHistogramMetricItemWith3Dimensions(out MetricData sum, out uint count) + { + using var meterWithInMemoryExporter = new Meter("GenerateHistogramMetricItemWith3Dimensions", "0.0.1"); + var histogram = meterWithInMemoryExporter.CreateHistogram("HistogramWith3Dimensions"); - private MetricPoint GenerateHistogramMetricItemWith3Dimensions(out MetricData sum, out uint count) + var exportedItems = new List(); + using var inMemoryReader = new BaseExportingMetricReader(new InMemoryExporter(exportedItems)) { - using var meterWithInMemoryExporter = new Meter("GenerateHistogramMetricItemWith3Dimensions", "0.0.1"); - var histogram = meterWithInMemoryExporter.CreateHistogram("HistogramWith3Dimensions"); + TemporalityPreference = MetricReaderTemporalityPreference.Delta, + }; - var exportedItems = new List(); - using var inMemoryReader = new BaseExportingMetricReader(new InMemoryExporter(exportedItems)) - { - TemporalityPreference = MetricReaderTemporalityPreference.Delta, - }; + using var meterProvider = Sdk.CreateMeterProviderBuilder() + .AddMeter("GenerateHistogramMetricItemWith3Dimensions") + .AddReader(inMemoryReader) + .Build(); - using var meterProvider = Sdk.CreateMeterProviderBuilder() - .AddMeter("GenerateHistogramMetricItemWith3Dimensions") - .AddReader(inMemoryReader) - .Build(); + var tag1 = new KeyValuePair("DimName1", dimensionValues[this.random.Value.Next(0, 10)]); + var tag2 = new KeyValuePair("DimName2", dimensionValues[this.random.Value.Next(0, 10)]); + var tag3 = new KeyValuePair("DimName3", dimensionValues[this.random.Value.Next(0, 10)]); - var tag1 = new KeyValuePair("DimName1", dimensionValues[this.random.Value.Next(0, 10)]); - var tag2 = new KeyValuePair("DimName2", dimensionValues[this.random.Value.Next(0, 10)]); - var tag3 = new KeyValuePair("DimName3", dimensionValues[this.random.Value.Next(0, 10)]); + for (int i = 0; i < 1000; i++) + { + histogram.Record(randomForHistogram.Next(1, 1000), tag1, tag2, tag3); + } - for (int i = 0; i < 1000; i++) - { - histogram.Record(randomForHistogram.Next(1, 1000), tag1, tag2, tag3); - } + inMemoryReader.Collect(); - inMemoryReader.Collect(); + var metric = exportedItems[0]; + var metricPointsEnumerator = metric.GetMetricPoints().GetEnumerator(); + metricPointsEnumerator.MoveNext(); + var metricPoint = metricPointsEnumerator.Current; + sum = new MetricData { UInt64Value = Convert.ToUInt64(metricPoint.GetHistogramSum()) }; + count = Convert.ToUInt32(metricPoint.GetHistogramCount()); - var metric = exportedItems[0]; - var metricPointsEnumerator = metric.GetMetricPoints().GetEnumerator(); - metricPointsEnumerator.MoveNext(); - var metricPoint = metricPointsEnumerator.Current; - sum = new MetricData { UInt64Value = Convert.ToUInt64(metricPoint.GetHistogramSum()) }; - count = Convert.ToUInt32(metricPoint.GetHistogramCount()); + return metricPoint; + } - return metricPoint; - } + private MetricPoint GenerateHistogramMetricItemWith4Dimensions(out MetricData sum, out uint count) + { + using var meterWithInMemoryExporter = new Meter("GenerateHistogramMetricItemWith4Dimensions", "0.0.1"); + var histogram = meterWithInMemoryExporter.CreateHistogram("HistogramWith4Dimensions"); - private MetricPoint GenerateHistogramMetricItemWith4Dimensions(out MetricData sum, out uint count) + var exportedItems = new List(); + using var inMemoryReader = new BaseExportingMetricReader(new InMemoryExporter(exportedItems)) { - using var meterWithInMemoryExporter = new Meter("GenerateHistogramMetricItemWith4Dimensions", "0.0.1"); - var histogram = meterWithInMemoryExporter.CreateHistogram("HistogramWith4Dimensions"); - - var exportedItems = new List(); - using var inMemoryReader = new BaseExportingMetricReader(new InMemoryExporter(exportedItems)) - { - TemporalityPreference = MetricReaderTemporalityPreference.Delta, - }; + TemporalityPreference = MetricReaderTemporalityPreference.Delta, + }; - using var meterProvider = Sdk.CreateMeterProviderBuilder() - .AddMeter("GenerateHistogramMetricItemWith4Dimensions") - .AddReader(inMemoryReader) - .Build(); + using var meterProvider = Sdk.CreateMeterProviderBuilder() + .AddMeter("GenerateHistogramMetricItemWith4Dimensions") + .AddReader(inMemoryReader) + .Build(); - var tags = new TagList + var tags = new TagList { { "DimName1", dimensionValues[this.random.Value.Next(0, 2)] }, { "DimName2", dimensionValues[this.random.Value.Next(0, 5)] }, @@ -348,69 +348,69 @@ private MetricPoint GenerateHistogramMetricItemWith4Dimensions(out MetricData su { "DimName4", dimensionValues[this.random.Value.Next(0, 10)] }, }; - for (int i = 0; i < 1000; i++) - { - histogram.Record(randomForHistogram.Next(1, 1000), tags); - } + for (int i = 0; i < 1000; i++) + { + histogram.Record(randomForHistogram.Next(1, 1000), tags); + } - inMemoryReader.Collect(); + inMemoryReader.Collect(); - var metric = exportedItems[0]; - var metricPointsEnumerator = metric.GetMetricPoints().GetEnumerator(); - metricPointsEnumerator.MoveNext(); - var metricPoint = metricPointsEnumerator.Current; - sum = new MetricData { UInt64Value = Convert.ToUInt64(metricPoint.GetHistogramSum()) }; - count = Convert.ToUInt32(metricPoint.GetHistogramCount()); + var metric = exportedItems[0]; + var metricPointsEnumerator = metric.GetMetricPoints().GetEnumerator(); + metricPointsEnumerator.MoveNext(); + var metricPoint = metricPointsEnumerator.Current; + sum = new MetricData { UInt64Value = Convert.ToUInt64(metricPoint.GetHistogramSum()) }; + count = Convert.ToUInt32(metricPoint.GetHistogramCount()); - return metricPoint; - } + return metricPoint; + } + + private Batch GenerateHistogramBatchWith3Dimensions() + { + using var meterWithInMemoryExporter = new Meter("GenerateHistogramBatchWith3Dimensions", "0.0.1"); + var histogram = meterWithInMemoryExporter.CreateHistogram("HistogramWith3Dimensions"); - private Batch GenerateHistogramBatchWith3Dimensions() + var batchGeneratorExporter = new BatchGenerator(); + var batchGeneratorReader = new BaseExportingMetricReader(batchGeneratorExporter) { - using var meterWithInMemoryExporter = new Meter("GenerateHistogramBatchWith3Dimensions", "0.0.1"); - var histogram = meterWithInMemoryExporter.CreateHistogram("HistogramWith3Dimensions"); + TemporalityPreference = MetricReaderTemporalityPreference.Delta, + }; - var batchGeneratorExporter = new BatchGenerator(); - var batchGeneratorReader = new BaseExportingMetricReader(batchGeneratorExporter) - { - TemporalityPreference = MetricReaderTemporalityPreference.Delta, - }; + this.meterProviderForHistogramBatchWith3Dimensions = Sdk.CreateMeterProviderBuilder() + .AddMeter("GenerateHistogramBatchWith3Dimensions") + .AddReader(batchGeneratorReader) + .Build(); - this.meterProviderForHistogramBatchWith3Dimensions = Sdk.CreateMeterProviderBuilder() - .AddMeter("GenerateHistogramBatchWith3Dimensions") - .AddReader(batchGeneratorReader) - .Build(); + var tag1 = new KeyValuePair("DimName1", dimensionValues[this.random.Value.Next(0, 10)]); + var tag2 = new KeyValuePair("DimName2", dimensionValues[this.random.Value.Next(0, 10)]); + var tag3 = new KeyValuePair("DimName3", dimensionValues[this.random.Value.Next(0, 10)]); - var tag1 = new KeyValuePair("DimName1", dimensionValues[this.random.Value.Next(0, 10)]); - var tag2 = new KeyValuePair("DimName2", dimensionValues[this.random.Value.Next(0, 10)]); - var tag3 = new KeyValuePair("DimName3", dimensionValues[this.random.Value.Next(0, 10)]); + for (int i = 0; i < 1000; i++) + { + histogram.Record(randomForHistogram.Next(1, 1000), tag1, tag2, tag3); + } - for (int i = 0; i < 1000; i++) - { - histogram.Record(randomForHistogram.Next(1, 1000), tag1, tag2, tag3); - } + this.meterProviderForHistogramBatchWith3Dimensions.ForceFlush(); + return batchGeneratorExporter.Batch; + } - this.meterProviderForHistogramBatchWith3Dimensions.ForceFlush(); - return batchGeneratorExporter.Batch; - } + private Batch GenerateHistogramBatchWith4Dimensions() + { + using var meterWithInMemoryExporter = new Meter("GenerateHistogramBatchWith4Dimensions", "0.0.1"); + var histogram = meterWithInMemoryExporter.CreateHistogram("HistogramWith4Dimensions"); - private Batch GenerateHistogramBatchWith4Dimensions() + var batchGeneratorExporter = new BatchGenerator(); + var batchGeneratorReader = new BaseExportingMetricReader(batchGeneratorExporter) { - using var meterWithInMemoryExporter = new Meter("GenerateHistogramBatchWith4Dimensions", "0.0.1"); - var histogram = meterWithInMemoryExporter.CreateHistogram("HistogramWith4Dimensions"); - - var batchGeneratorExporter = new BatchGenerator(); - var batchGeneratorReader = new BaseExportingMetricReader(batchGeneratorExporter) - { - TemporalityPreference = MetricReaderTemporalityPreference.Delta, - }; + TemporalityPreference = MetricReaderTemporalityPreference.Delta, + }; - this.meterProviderForHistogramBatchWith4Dimensions = Sdk.CreateMeterProviderBuilder() - .AddMeter("GenerateHistogramBatchWith4Dimensions") - .AddReader(batchGeneratorReader) - .Build(); + this.meterProviderForHistogramBatchWith4Dimensions = Sdk.CreateMeterProviderBuilder() + .AddMeter("GenerateHistogramBatchWith4Dimensions") + .AddReader(batchGeneratorReader) + .Build(); - var tags = new TagList + var tags = new TagList { { "DimName1", dimensionValues[this.random.Value.Next(0, 2)] }, { "DimName2", dimensionValues[this.random.Value.Next(0, 5)] }, @@ -418,45 +418,45 @@ private Batch GenerateHistogramBatchWith4Dimensions() { "DimName4", dimensionValues[this.random.Value.Next(0, 10)] }, }; - for (int i = 0; i < 1000; i++) - { - histogram.Record(randomForHistogram.Next(1, 1000), tags); - } - - this.meterProviderForHistogramBatchWith4Dimensions.ForceFlush(); - return batchGeneratorExporter.Batch; - } - - [GlobalCleanup] - public void Cleanup() + for (int i = 0; i < 1000; i++) { - this.meterWithNoListener?.Dispose(); - this.meterWithListener?.Dispose(); - this.meterWithDummyReader?.Dispose(); - this.meterWithGenevaMetricExporter?.Dispose(); - this.listener?.Dispose(); - this.meterProviderWithDummyReader?.Dispose(); - this.meterProviderWithGenevaMetricExporter?.Dispose(); - this.meterProviderForCounterBatchWith3Dimensions?.Dispose(); - this.meterProviderForCounterBatchWith4Dimensions?.Dispose(); - this.meterProviderForHistogramBatchWith3Dimensions?.Dispose(); - this.meterProviderForHistogramBatchWith4Dimensions?.Dispose(); - this.exporter?.Dispose(); + histogram.Record(randomForHistogram.Next(1, 1000), tags); } - [Benchmark] - public void InstrumentWithNoListener3Dimensions() - { - var tag1 = new KeyValuePair("DimName1", dimensionValues[this.random.Value.Next(0, 10)]); - var tag2 = new KeyValuePair("DimName2", dimensionValues[this.random.Value.Next(0, 10)]); - var tag3 = new KeyValuePair("DimName3", dimensionValues[this.random.Value.Next(0, 10)]); - this.counterWithNoListener?.Add(100, tag1, tag2, tag3); - } + this.meterProviderForHistogramBatchWith4Dimensions.ForceFlush(); + return batchGeneratorExporter.Batch; + } - [Benchmark] - public void InstrumentWithNoListener4Dimensions() - { - var tags = new TagList + [GlobalCleanup] + public void Cleanup() + { + this.meterWithNoListener?.Dispose(); + this.meterWithListener?.Dispose(); + this.meterWithDummyReader?.Dispose(); + this.meterWithGenevaMetricExporter?.Dispose(); + this.listener?.Dispose(); + this.meterProviderWithDummyReader?.Dispose(); + this.meterProviderWithGenevaMetricExporter?.Dispose(); + this.meterProviderForCounterBatchWith3Dimensions?.Dispose(); + this.meterProviderForCounterBatchWith4Dimensions?.Dispose(); + this.meterProviderForHistogramBatchWith3Dimensions?.Dispose(); + this.meterProviderForHistogramBatchWith4Dimensions?.Dispose(); + this.exporter?.Dispose(); + } + + [Benchmark] + public void InstrumentWithNoListener3Dimensions() + { + var tag1 = new KeyValuePair("DimName1", dimensionValues[this.random.Value.Next(0, 10)]); + var tag2 = new KeyValuePair("DimName2", dimensionValues[this.random.Value.Next(0, 10)]); + var tag3 = new KeyValuePair("DimName3", dimensionValues[this.random.Value.Next(0, 10)]); + this.counterWithNoListener?.Add(100, tag1, tag2, tag3); + } + + [Benchmark] + public void InstrumentWithNoListener4Dimensions() + { + var tags = new TagList { { "DimName1", dimensionValues[this.random.Value.Next(0, 2)] }, { "DimName2", dimensionValues[this.random.Value.Next(0, 5)] }, @@ -464,23 +464,23 @@ public void InstrumentWithNoListener4Dimensions() { "DimName4", dimensionValues[this.random.Value.Next(0, 10)] }, }; - // 2 * 5 * 10 * 10 = 1000 time series max. - this.counterWithNoListener?.Add(100, tags); - } + // 2 * 5 * 10 * 10 = 1000 time series max. + this.counterWithNoListener?.Add(100, tags); + } - [Benchmark] - public void InstrumentWithWithListener3Dimensions() - { - var tag1 = new KeyValuePair("DimName1", dimensionValues[this.random.Value.Next(0, 10)]); - var tag2 = new KeyValuePair("DimName2", dimensionValues[this.random.Value.Next(0, 10)]); - var tag3 = new KeyValuePair("DimName3", dimensionValues[this.random.Value.Next(0, 10)]); - this.counterWithListener?.Add(100, tag1, tag2, tag3); - } + [Benchmark] + public void InstrumentWithWithListener3Dimensions() + { + var tag1 = new KeyValuePair("DimName1", dimensionValues[this.random.Value.Next(0, 10)]); + var tag2 = new KeyValuePair("DimName2", dimensionValues[this.random.Value.Next(0, 10)]); + var tag3 = new KeyValuePair("DimName3", dimensionValues[this.random.Value.Next(0, 10)]); + this.counterWithListener?.Add(100, tag1, tag2, tag3); + } - [Benchmark] - public void InstrumentWithWithListener4Dimensions() - { - var tags = new TagList + [Benchmark] + public void InstrumentWithWithListener4Dimensions() + { + var tags = new TagList { { "DimName1", dimensionValues[this.random.Value.Next(0, 2)] }, { "DimName2", dimensionValues[this.random.Value.Next(0, 5)] }, @@ -488,23 +488,23 @@ public void InstrumentWithWithListener4Dimensions() { "DimName4", dimensionValues[this.random.Value.Next(0, 10)] }, }; - // 2 * 5 * 10 * 10 = 1000 time series max. - this.counterWithListener?.Add(100, tags); - } + // 2 * 5 * 10 * 10 = 1000 time series max. + this.counterWithListener?.Add(100, tags); + } - [Benchmark] - public void InstrumentWithWithDummyReader3Dimensions() - { - var tag1 = new KeyValuePair("DimName1", dimensionValues[this.random.Value.Next(0, 10)]); - var tag2 = new KeyValuePair("DimName2", dimensionValues[this.random.Value.Next(0, 10)]); - var tag3 = new KeyValuePair("DimName3", dimensionValues[this.random.Value.Next(0, 10)]); - this.counterWithDummyReader?.Add(100, tag1, tag2, tag3); - } + [Benchmark] + public void InstrumentWithWithDummyReader3Dimensions() + { + var tag1 = new KeyValuePair("DimName1", dimensionValues[this.random.Value.Next(0, 10)]); + var tag2 = new KeyValuePair("DimName2", dimensionValues[this.random.Value.Next(0, 10)]); + var tag3 = new KeyValuePair("DimName3", dimensionValues[this.random.Value.Next(0, 10)]); + this.counterWithDummyReader?.Add(100, tag1, tag2, tag3); + } - [Benchmark] - public void InstrumentWithWithDummyReader4Dimensions() - { - var tags = new TagList + [Benchmark] + public void InstrumentWithWithDummyReader4Dimensions() + { + var tags = new TagList { { "DimName1", dimensionValues[this.random.Value.Next(0, 2)] }, { "DimName2", dimensionValues[this.random.Value.Next(0, 5)] }, @@ -512,23 +512,23 @@ public void InstrumentWithWithDummyReader4Dimensions() { "DimName4", dimensionValues[this.random.Value.Next(0, 10)] }, }; - // 2 * 5 * 10 * 10 = 1000 time series max. - this.counterWithDummyReader?.Add(100, tags); - } + // 2 * 5 * 10 * 10 = 1000 time series max. + this.counterWithDummyReader?.Add(100, tags); + } - [Benchmark] - public void InstrumentWithWithGenevaCounterMetricExporter3Dimensions() - { - var tag1 = new KeyValuePair("DimName1", dimensionValues[this.random.Value.Next(0, 10)]); - var tag2 = new KeyValuePair("DimName2", dimensionValues[this.random.Value.Next(0, 10)]); - var tag3 = new KeyValuePair("DimName3", dimensionValues[this.random.Value.Next(0, 10)]); - this.counterWithGenevaMetricExporter?.Add(100, tag1, tag2, tag3); - } + [Benchmark] + public void InstrumentWithWithGenevaCounterMetricExporter3Dimensions() + { + var tag1 = new KeyValuePair("DimName1", dimensionValues[this.random.Value.Next(0, 10)]); + var tag2 = new KeyValuePair("DimName2", dimensionValues[this.random.Value.Next(0, 10)]); + var tag3 = new KeyValuePair("DimName3", dimensionValues[this.random.Value.Next(0, 10)]); + this.counterWithGenevaMetricExporter?.Add(100, tag1, tag2, tag3); + } - [Benchmark] - public void InstrumentWithWithGenevaCounterMetricExporter4Dimensions() - { - var tags = new TagList + [Benchmark] + public void InstrumentWithWithGenevaCounterMetricExporter4Dimensions() + { + var tags = new TagList { { "DimName1", dimensionValues[this.random.Value.Next(0, 2)] }, { "DimName2", dimensionValues[this.random.Value.Next(0, 5)] }, @@ -536,105 +536,104 @@ public void InstrumentWithWithGenevaCounterMetricExporter4Dimensions() { "DimName4", dimensionValues[this.random.Value.Next(0, 10)] }, }; - // 2 * 5 * 10 * 10 = 1000 time series max. - this.counterWithGenevaMetricExporter?.Add(100, tags); - } + // 2 * 5 * 10 * 10 = 1000 time series max. + this.counterWithGenevaMetricExporter?.Add(100, tags); + } - [Benchmark] - public void SerializeCounterMetricItemWith3Dimensions() - { - this.exporter.SerializeMetric( - MetricEventType.ULongMetric, - this.counterMetricWith3Dimensions.Name, - this.counterMetricPointWith3Dimensions.EndTime.ToFileTime(), - this.counterMetricPointWith3Dimensions.Tags, - this.counterMetricDataWith3Dimensions); - } + [Benchmark] + public void SerializeCounterMetricItemWith3Dimensions() + { + this.exporter.SerializeMetric( + MetricEventType.ULongMetric, + this.counterMetricWith3Dimensions.Name, + this.counterMetricPointWith3Dimensions.EndTime.ToFileTime(), + this.counterMetricPointWith3Dimensions.Tags, + this.counterMetricDataWith3Dimensions); + } - [Benchmark] - public void SerializeCounterMetricItemWith4Dimensions() - { - this.exporter.SerializeMetric( - MetricEventType.ULongMetric, - this.counterMetricWith4Dimensions.Name, - this.counterMetricPointWith4Dimensions.EndTime.ToFileTime(), - this.counterMetricPointWith4Dimensions.Tags, - this.counterMetricDataWith4Dimensions); - } + [Benchmark] + public void SerializeCounterMetricItemWith4Dimensions() + { + this.exporter.SerializeMetric( + MetricEventType.ULongMetric, + this.counterMetricWith4Dimensions.Name, + this.counterMetricPointWith4Dimensions.EndTime.ToFileTime(), + this.counterMetricPointWith4Dimensions.Tags, + this.counterMetricDataWith4Dimensions); + } - [Benchmark] - public void ExportCounterMetricItemWith3Dimensions() - { - this.exporter.Export(this.counterMetricBatchWith3Dimensions); - } + [Benchmark] + public void ExportCounterMetricItemWith3Dimensions() + { + this.exporter.Export(this.counterMetricBatchWith3Dimensions); + } - [Benchmark] - public void ExportCounterMetricItemWith4Dimensions() - { - this.exporter.Export(this.counterMetricBatchWith4Dimensions); - } + [Benchmark] + public void ExportCounterMetricItemWith4Dimensions() + { + this.exporter.Export(this.counterMetricBatchWith4Dimensions); + } - [Benchmark] - public void SerializeHistogramMetricItemWith3Dimensions() - { - this.exporter.SerializeHistogramMetric( - this.histogramMetricWith3Dimensions.Name, - this.histogramMetricPointWith3Dimensions.EndTime.ToFileTime(), - this.histogramMetricPointWith3Dimensions.Tags, - this.histogramMetricPointWith3Dimensions.GetHistogramBuckets(), - this.histogramSumWith3Dimensions, - this.histogramCountWith3Dimensions); - } + [Benchmark] + public void SerializeHistogramMetricItemWith3Dimensions() + { + this.exporter.SerializeHistogramMetric( + this.histogramMetricWith3Dimensions.Name, + this.histogramMetricPointWith3Dimensions.EndTime.ToFileTime(), + this.histogramMetricPointWith3Dimensions.Tags, + this.histogramMetricPointWith3Dimensions.GetHistogramBuckets(), + this.histogramSumWith3Dimensions, + this.histogramCountWith3Dimensions); + } - [Benchmark] - public void SerializeHistogramMetricItemWith4Dimensions() - { - this.exporter.SerializeHistogramMetric( - this.histogramMetricWith4Dimensions.Name, - this.histogramMetricPointWith4Dimensions.EndTime.ToFileTime(), - this.histogramMetricPointWith4Dimensions.Tags, - this.histogramMetricPointWith4Dimensions.GetHistogramBuckets(), - this.histogramSumWith4Dimensions, - this.histogramCountWith4Dimensions); - } + [Benchmark] + public void SerializeHistogramMetricItemWith4Dimensions() + { + this.exporter.SerializeHistogramMetric( + this.histogramMetricWith4Dimensions.Name, + this.histogramMetricPointWith4Dimensions.EndTime.ToFileTime(), + this.histogramMetricPointWith4Dimensions.Tags, + this.histogramMetricPointWith4Dimensions.GetHistogramBuckets(), + this.histogramSumWith4Dimensions, + this.histogramCountWith4Dimensions); + } - [Benchmark] - public void ExportHistogramMetricItemWith3Dimensions() - { - this.exporter.Export(this.histogramMetricBatchWith3Dimensions); - } + [Benchmark] + public void ExportHistogramMetricItemWith3Dimensions() + { + this.exporter.Export(this.histogramMetricBatchWith3Dimensions); + } - [Benchmark] - public void ExportHistogramMetricItemWith4Dimensions() - { - this.exporter.Export(this.histogramMetricBatchWith4Dimensions); - } + [Benchmark] + public void ExportHistogramMetricItemWith4Dimensions() + { + this.exporter.Export(this.histogramMetricBatchWith4Dimensions); + } - private class DummyReader : BaseExportingMetricReader + private class DummyReader : BaseExportingMetricReader + { + public DummyReader(BaseExporter exporter) + : base(exporter) { - public DummyReader(BaseExporter exporter) - : base(exporter) - { - } } + } - private class DummyMetricExporter : BaseExporter + private class DummyMetricExporter : BaseExporter + { + public override ExportResult Export(in Batch batch) { - public override ExportResult Export(in Batch batch) - { - return ExportResult.Success; - } + return ExportResult.Success; } + } - private class BatchGenerator : BaseExporter - { - public Batch Batch { get; set; } + private class BatchGenerator : BaseExporter + { + public Batch Batch { get; set; } - public override ExportResult Export(in Batch batch) - { - this.Batch = batch; - return ExportResult.Success; - } + public override ExportResult Export(in Batch batch) + { + this.Batch = batch; + return ExportResult.Success; } } } diff --git a/test/OpenTelemetry.Exporter.Geneva.Benchmark/Exporter/TraceExporterBenchmarks.cs b/test/OpenTelemetry.Exporter.Geneva.Benchmark/Exporter/TraceExporterBenchmarks.cs index f305ae24a9..3460304ff1 100644 --- a/test/OpenTelemetry.Exporter.Geneva.Benchmark/Exporter/TraceExporterBenchmarks.cs +++ b/test/OpenTelemetry.Exporter.Geneva.Benchmark/Exporter/TraceExporterBenchmarks.cs @@ -17,7 +17,6 @@ using System.Collections.Generic; using System.Diagnostics; using BenchmarkDotNet.Attributes; -using OpenTelemetry.Metrics; using OpenTelemetry.Trace; /* @@ -34,101 +33,100 @@ | SerializeActivity | 387.4 ns | 7.22 ns | 7.09 ns | 0.0062 | 40 B | */ -namespace OpenTelemetry.Exporter.Geneva.Benchmark +namespace OpenTelemetry.Exporter.Geneva.Benchmark; + +[MemoryDiagnoser] +public class TraceExporterBenchmarks { - [MemoryDiagnoser] - public class TraceExporterBenchmarks + private readonly Activity activity; + private readonly Batch batch; + private readonly GenevaTraceExporter exporter; + private readonly ActivitySource activitySource = new ActivitySource("OpenTelemetry.Exporter.Geneva.Benchmark"); + + public TraceExporterBenchmarks() { - private readonly Activity activity; - private readonly Batch batch; - private readonly GenevaTraceExporter exporter; - private readonly ActivitySource activitySource = new ActivitySource("OpenTelemetry.Exporter.Geneva.Benchmark"); + Activity.DefaultIdFormat = ActivityIdFormat.W3C; - public TraceExporterBenchmarks() - { - Activity.DefaultIdFormat = ActivityIdFormat.W3C; + this.batch = this.CreateBatch(); - this.batch = this.CreateBatch(); + using var activityListener = new ActivityListener + { + ActivityStarted = null, + ActivityStopped = null, + ShouldListenTo = (activitySource) => activitySource.Name == this.activitySource.Name, + Sample = (ref ActivityCreationOptions options) => ActivitySamplingResult.AllDataAndRecorded, + }; - using var activityListener = new ActivityListener - { - ActivityStarted = null, - ActivityStopped = null, - ShouldListenTo = (activitySource) => activitySource.Name == this.activitySource.Name, - Sample = (ref ActivityCreationOptions options) => ActivitySamplingResult.AllDataAndRecorded, - }; + ActivitySource.AddActivityListener(activityListener); - ActivitySource.AddActivityListener(activityListener); + using (var testActivity = this.activitySource.StartActivity("Benchmark")) + { + this.activity = testActivity; + this.activity?.SetTag("tagString", "value"); + this.activity?.SetTag("tagInt", 100); + this.activity?.SetStatus(Status.Error); + } - using (var testActivity = this.activitySource.StartActivity("Benchmark")) + this.exporter = new GenevaTraceExporter(new GenevaExporterOptions + { + ConnectionString = "EtwSession=OpenTelemetry", + PrepopulatedFields = new Dictionary { - this.activity = testActivity; - this.activity?.SetTag("tagString", "value"); - this.activity?.SetTag("tagInt", 100); - this.activity?.SetStatus(Status.Error); - } + ["cloud.role"] = "BusyWorker", + ["cloud.roleInstance"] = "CY1SCH030021417", + ["cloud.roleVer"] = "9.0.15289.2", + }, + }); + } - this.exporter = new GenevaTraceExporter(new GenevaExporterOptions - { - ConnectionString = "EtwSession=OpenTelemetry", - PrepopulatedFields = new Dictionary - { - ["cloud.role"] = "BusyWorker", - ["cloud.roleInstance"] = "CY1SCH030021417", - ["cloud.roleVer"] = "9.0.15289.2", - }, - }); - } + [Benchmark] + public void ExportActivity() + { + this.exporter.Export(this.batch); + } - [Benchmark] - public void ExportActivity() - { - this.exporter.Export(this.batch); - } + [Benchmark] + public void SerializeActivity() + { + this.exporter.SerializeActivity(this.activity); + } - [Benchmark] - public void SerializeActivity() - { - this.exporter.SerializeActivity(this.activity); - } + [GlobalCleanup] + public void Cleanup() + { + this.activity.Dispose(); + this.activitySource.Dispose(); + this.batch.Dispose(); + this.exporter.Dispose(); + } - [GlobalCleanup] - public void Cleanup() + private Batch CreateBatch() + { + using var batchGeneratorExporter = new BatchGeneratorExporter(); + using var tracerProvider = Sdk.CreateTracerProviderBuilder() + .SetSampler(new AlwaysOnSampler()) + .AddSource(this.activitySource.Name) + .AddProcessor(new SimpleActivityExportProcessor(batchGeneratorExporter)) + .Build(); + + using (var activity = this.activitySource.StartActivity("Benchmark")) { - this.activity.Dispose(); - this.activitySource.Dispose(); - this.batch.Dispose(); - this.exporter.Dispose(); + activity.SetTag("tagString", "value"); + activity.SetTag("tagInt", 100); + activity.SetStatus(Status.Error); } - private Batch CreateBatch() - { - using var batchGeneratorExporter = new BatchGeneratorExporter(); - using var tracerProvider = Sdk.CreateTracerProviderBuilder() - .SetSampler(new AlwaysOnSampler()) - .AddSource(this.activitySource.Name) - .AddProcessor(new SimpleActivityExportProcessor(batchGeneratorExporter)) - .Build(); - - using (var activity = this.activitySource.StartActivity("Benchmark")) - { - activity.SetTag("tagString", "value"); - activity.SetTag("tagInt", 100); - activity.SetStatus(Status.Error); - } + return batchGeneratorExporter.Batch; + } - return batchGeneratorExporter.Batch; - } + private class BatchGeneratorExporter : BaseExporter + { + public Batch Batch { get; set; } - private class BatchGeneratorExporter : BaseExporter + public override ExportResult Export(in Batch batch) { - public Batch Batch { get; set; } - - public override ExportResult Export(in Batch batch) - { - this.Batch = batch; - return ExportResult.Success; - } + this.Batch = batch; + return ExportResult.Success; } } } diff --git a/test/OpenTelemetry.Exporter.Geneva.Benchmark/Program.cs b/test/OpenTelemetry.Exporter.Geneva.Benchmark/Program.cs index 2616c540d0..ac7b7f625e 100644 --- a/test/OpenTelemetry.Exporter.Geneva.Benchmark/Program.cs +++ b/test/OpenTelemetry.Exporter.Geneva.Benchmark/Program.cs @@ -16,10 +16,9 @@ using BenchmarkDotNet.Running; -namespace OpenTelemetry.Exporter.Geneva.Benchmark +namespace OpenTelemetry.Exporter.Geneva.Benchmark; + +internal class Program { - internal class Program - { - private static void Main(string[] args) => BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args); - } + private static void Main(string[] args) => BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args); } diff --git a/test/OpenTelemetry.Exporter.Geneva.Stress/DummyServer.cs b/test/OpenTelemetry.Exporter.Geneva.Stress/DummyServer.cs index 4521c6f4ed..1757f49f2e 100644 --- a/test/OpenTelemetry.Exporter.Geneva.Stress/DummyServer.cs +++ b/test/OpenTelemetry.Exporter.Geneva.Stress/DummyServer.cs @@ -21,82 +21,81 @@ using System.Threading; using System.Threading.Tasks; -namespace OpenTelemetry.Exporter.Geneva.Stress +namespace OpenTelemetry.Exporter.Geneva.Stress; + +internal class DummyServer { - internal class DummyServer - { - private EndPoint endpoint; - private Socket serverSocket; + private EndPoint endpoint; + private Socket serverSocket; - public DummyServer(string path) - { - Console.WriteLine($"Server socket listening at path: {path}"); + public DummyServer(string path) + { + Console.WriteLine($"Server socket listening at path: {path}"); - // Unix sockets must be unlink()ed before being reused again. - // Or there will be System.Net.Sockets.SocketException (98): SocketError.AddressAlreadyInUse - // https://github.com/dotnet/runtime/issues/23803 - // C# doesn't have the unlink() function in C - // Shutdown() and setting SocketOptions like ReuseAddress and Linger doesn't solve the problem as they do for TCP - // https://stackoverflow.com/questions/2821520/how-can-i-unbind-a-socket-in-c - File.Delete(path); - this.endpoint = new UnixDomainSocketEndPoint(path); - this.serverSocket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); - } + // Unix sockets must be unlink()ed before being reused again. + // Or there will be System.Net.Sockets.SocketException (98): SocketError.AddressAlreadyInUse + // https://github.com/dotnet/runtime/issues/23803 + // C# doesn't have the unlink() function in C + // Shutdown() and setting SocketOptions like ReuseAddress and Linger doesn't solve the problem as they do for TCP + // https://stackoverflow.com/questions/2821520/how-can-i-unbind-a-socket-in-c + File.Delete(path); + this.endpoint = new UnixDomainSocketEndPoint(path); + this.serverSocket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); + } - public void Start() + public void Start() + { + try { - try - { - this.serverSocket.Bind(this.endpoint); - this.serverSocket.Listen(20); + this.serverSocket.Bind(this.endpoint); + this.serverSocket.Listen(20); - Console.CancelKeyPress += (object sender, ConsoleCancelEventArgs args) => - { - Console.WriteLine("Program is terminating."); - this.serverSocket.Close(); - }; + Console.CancelKeyPress += (object sender, ConsoleCancelEventArgs args) => + { + Console.WriteLine("Program is terminating."); + this.serverSocket.Close(); + }; - while (true) + while (true) + { + Socket acceptSocket = this.serverSocket.Accept(); + Task.Run(() => { - Socket acceptSocket = this.serverSocket.Accept(); - Task.Run(() => + int threadId = Thread.CurrentThread.ManagedThreadId; + Console.WriteLine($"ThreadID {threadId}: Start reading from socket."); + int totalBytes = 0; + try { - int threadId = Thread.CurrentThread.ManagedThreadId; - Console.WriteLine($"ThreadID {threadId}: Start reading from socket."); - int totalBytes = 0; - try - { - while (acceptSocket.Connected) - { - var receivedData = new byte[1024]; - int receivedDataSize = acceptSocket.Receive(receivedData); - totalBytes += receivedDataSize; - } - - acceptSocket.Shutdown(SocketShutdown.Both); - } - catch (Exception e) + while (acceptSocket.Connected) { - Console.WriteLine($"acceptSocket exception: {e}"); - } - finally - { - Console.WriteLine($"ThreadID {threadId}: Closing socket"); - acceptSocket.Close(); + var receivedData = new byte[1024]; + int receivedDataSize = acceptSocket.Receive(receivedData); + totalBytes += receivedDataSize; } - Console.WriteLine($"ThreadID {threadId}: Socket received {totalBytes} bytes in total."); - }); - } - } - catch (Exception e) - { - Console.WriteLine($"Server socket exception: {e}"); - } - finally - { - this.serverSocket.Close(); + acceptSocket.Shutdown(SocketShutdown.Both); + } + catch (Exception e) + { + Console.WriteLine($"acceptSocket exception: {e}"); + } + finally + { + Console.WriteLine($"ThreadID {threadId}: Closing socket"); + acceptSocket.Close(); + } + + Console.WriteLine($"ThreadID {threadId}: Socket received {totalBytes} bytes in total."); + }); } } + catch (Exception e) + { + Console.WriteLine($"Server socket exception: {e}"); + } + finally + { + this.serverSocket.Close(); + } } } diff --git a/test/OpenTelemetry.Exporter.Geneva.Stress/Program.cs b/test/OpenTelemetry.Exporter.Geneva.Stress/Program.cs index e0d264e6a4..b1b8275038 100644 --- a/test/OpenTelemetry.Exporter.Geneva.Stress/Program.cs +++ b/test/OpenTelemetry.Exporter.Geneva.Stress/Program.cs @@ -24,93 +24,93 @@ using CommandLine; using OpenTelemetry.Trace; -namespace OpenTelemetry.Exporter.Geneva.Stress +namespace OpenTelemetry.Exporter.Geneva.Stress; + +internal class Program { - internal class Program - { - private static volatile bool s_bContinue = true; - private static long s_nEvents = 0; + private static volatile bool s_bContinue = true; + private static long s_nEvents = 0; - private static ActivitySource source = new ActivitySource("OpenTelemetry.Exporter.Geneva.Stress"); + private static ActivitySource source = new ActivitySource("OpenTelemetry.Exporter.Geneva.Stress"); - private static int Main(string[] args) - { - return Parser.Default.ParseArguments(args) - .MapResult( - (WindowsOptions options) => EntryPoint(InitTraces, RunTraces), - (LinuxOptions options) => RunLinux(options), - (ServerOptions options) => RunServer(options), - (ExporterCreationOptions options) => RunExporterCreation(), - errs => 1); - - // return EntryPoint(InitMetrics, RunMetrics); - } + private static int Main(string[] args) + { + return Parser.Default.ParseArguments(args) + .MapResult( + (WindowsOptions options) => EntryPoint(InitTraces, RunTraces), + (LinuxOptions options) => RunLinux(options), + (ServerOptions options) => RunServer(options), + (ExporterCreationOptions options) => RunExporterCreation(), + errs => 1); + + // return EntryPoint(InitMetrics, RunMetrics); + } - [Verb("Windows", HelpText = "Run stress test on Windows.")] - private class WindowsOptions - { - } + [Verb("Windows", HelpText = "Run stress test on Windows.")] + private class WindowsOptions + { + } - [Verb("Linux", HelpText = "Run stress test on Linux.")] - private class LinuxOptions - { - [Option('p', "path", Default = "/var/run/default_fluent.socket", HelpText = "Specify a path for Unix domain socket.")] - public string Path { get; set; } - } + [Verb("Linux", HelpText = "Run stress test on Linux.")] + private class LinuxOptions + { + [Option('p', "path", Default = "/var/run/default_fluent.socket", HelpText = "Specify a path for Unix domain socket.")] + public string Path { get; set; } + } - [Verb("server", HelpText = "Start a dummy server on Linux.")] - private class ServerOptions - { - [Option('p', "path", HelpText = "Specify a path for Unix domain socket.", Required = true)] - public string Path { get; set; } - } + [Verb("server", HelpText = "Start a dummy server on Linux.")] + private class ServerOptions + { + [Option('p', "path", HelpText = "Specify a path for Unix domain socket.", Required = true)] + public string Path { get; set; } + } - [Verb("ExporterCreation", HelpText = "Validate exporter dispose behavior")] - private class ExporterCreationOptions - { - } + [Verb("ExporterCreation", HelpText = "Validate exporter dispose behavior")] + private class ExporterCreationOptions + { + } - private static int RunExporterCreation() + private static int RunExporterCreation() + { + var options = new GenevaExporterOptions() { - var options = new GenevaExporterOptions() - { - ConnectionString = "EtwSession=OpenTelemetry", - PrepopulatedFields = new Dictionary - { - ["ver"] = "4.0", - ["cloud.role"] = "BusyWorker", - ["cloud.roleInstance"] = "CY1SCH030021417", - ["cloud.roleVer"] = "9.0.15289.2", - }, - }; - - for (var i = 0; i < 300000; ++i) + ConnectionString = "EtwSession=OpenTelemetry", + PrepopulatedFields = new Dictionary { - using var dataTransport = new EtwDataTransport("OpenTelemetry"); - } - - return 0; - } + ["ver"] = "4.0", + ["cloud.role"] = "BusyWorker", + ["cloud.roleInstance"] = "CY1SCH030021417", + ["cloud.roleVer"] = "9.0.15289.2", + }, + }; - private static int RunLinux(LinuxOptions options) + for (var i = 0; i < 300000; ++i) { - return EntryPoint(() => InitTracesOnLinux(options.Path), RunTraces); + using var dataTransport = new EtwDataTransport("OpenTelemetry"); } - private static int RunServer(ServerOptions options) - { - var server = new DummyServer(options.Path); - server.Start(); - return 0; - } + return 0; + } - private static int EntryPoint(Action init, Action run) - { - init(); + private static int RunLinux(LinuxOptions options) + { + return EntryPoint(() => InitTracesOnLinux(options.Path), RunTraces); + } + + private static int RunServer(ServerOptions options) + { + var server = new DummyServer(options.Path); + server.Start(); + return 0; + } - var statistics = new long[Environment.ProcessorCount]; - Parallel.Invoke( - () => + private static int EntryPoint(Action init, Action run) + { + init(); + + var statistics = new long[Environment.ProcessorCount]; + Parallel.Invoke( + () => { Console.WriteLine("Running, press to stop..."); var watch = new Stopwatch(); @@ -138,7 +138,7 @@ private static int EntryPoint(Action init, Action run) Console.Title = string.Format("Loops: {0:n0}, Loops/Second: {1:n0}", nEvents, nEventPerSecond); } }, - () => + () => { Parallel.For(0, statistics.Length, (i) => { @@ -150,54 +150,53 @@ private static int EntryPoint(Action init, Action run) } }); }); - return 0; - } + return 0; + } - private static void InitTraces() - { - Sdk.CreateTracerProviderBuilder() - .SetSampler(new AlwaysOnSampler()) - .AddSource("OpenTelemetry.Exporter.Geneva.Stress") - .AddGenevaTraceExporter(options => + private static void InitTraces() + { + Sdk.CreateTracerProviderBuilder() + .SetSampler(new AlwaysOnSampler()) + .AddSource("OpenTelemetry.Exporter.Geneva.Stress") + .AddGenevaTraceExporter(options => + { + options.ConnectionString = "EtwSession=OpenTelemetry"; + options.PrepopulatedFields = new Dictionary { - options.ConnectionString = "EtwSession=OpenTelemetry"; - options.PrepopulatedFields = new Dictionary - { - ["cloud.role"] = "BusyWorker", - ["cloud.roleInstance"] = "CY1SCH030021417", - ["cloud.roleVer"] = "9.0.15289.2", - }; - }) - .Build(); - } + ["cloud.role"] = "BusyWorker", + ["cloud.roleInstance"] = "CY1SCH030021417", + ["cloud.roleVer"] = "9.0.15289.2", + }; + }) + .Build(); + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void RunTraces() + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void RunTraces() + { + using (var activity = source.StartActivity("Stress")) { - using (var activity = source.StartActivity("Stress")) - { - activity?.SetTag("http.method", "GET"); - activity?.SetTag("http.url", "https://www.wikipedia.org/wiki/Rabbit"); - activity?.SetTag("http.status_code", 200); - } + activity?.SetTag("http.method", "GET"); + activity?.SetTag("http.url", "https://www.wikipedia.org/wiki/Rabbit"); + activity?.SetTag("http.status_code", 200); } + } - private static void InitTracesOnLinux(string path) - { - Sdk.CreateTracerProviderBuilder() - .SetSampler(new AlwaysOnSampler()) - .AddSource("OpenTelemetry.Exporter.Geneva.Stress") - .AddGenevaTraceExporter(options => + private static void InitTracesOnLinux(string path) + { + Sdk.CreateTracerProviderBuilder() + .SetSampler(new AlwaysOnSampler()) + .AddSource("OpenTelemetry.Exporter.Geneva.Stress") + .AddGenevaTraceExporter(options => + { + options.ConnectionString = "Endpoint=unix:" + path; + options.PrepopulatedFields = new Dictionary { - options.ConnectionString = "Endpoint=unix:" + path; - options.PrepopulatedFields = new Dictionary - { - ["cloud.role"] = "BusyWorker", - ["cloud.roleInstance"] = "CY1SCH030021417", - ["cloud.roleVer"] = "9.0.15289.2", - }; - }) - .Build(); - } + ["cloud.role"] = "BusyWorker", + ["cloud.roleInstance"] = "CY1SCH030021417", + ["cloud.roleVer"] = "9.0.15289.2", + }; + }) + .Build(); } } diff --git a/test/OpenTelemetry.Exporter.Geneva.Tests/ConnectionStringBuilderTests.cs b/test/OpenTelemetry.Exporter.Geneva.Tests/ConnectionStringBuilderTests.cs index 9f579c0b8e..35473e893e 100644 --- a/test/OpenTelemetry.Exporter.Geneva.Tests/ConnectionStringBuilderTests.cs +++ b/test/OpenTelemetry.Exporter.Geneva.Tests/ConnectionStringBuilderTests.cs @@ -17,217 +17,216 @@ using System; using Xunit; -namespace OpenTelemetry.Exporter.Geneva.Tests +namespace OpenTelemetry.Exporter.Geneva.Tests; + +public class ConnectionStringBuilderTests { - public class ConnectionStringBuilderTests + [Fact] + public void ConnectionStringBuilder_constructor_Invalid_Input() + { + // null connection string + Assert.Throws(() => _ = new ConnectionStringBuilder(null)); + + // empty connection string + Assert.Throws(() => _ = new ConnectionStringBuilder(string.Empty)); + Assert.Throws(() => _ = new ConnectionStringBuilder(" ")); + + // empty key + Assert.Throws(() => _ = new ConnectionStringBuilder("=value")); + Assert.Throws(() => _ = new ConnectionStringBuilder("=value1;key2=value2")); + Assert.Throws(() => _ = new ConnectionStringBuilder("key1=value1;=value2")); + + // empty value + Assert.Throws(() => _ = new ConnectionStringBuilder("key=")); + Assert.Throws(() => _ = new ConnectionStringBuilder("key1=;key2=value2")); + Assert.Throws(() => _ = new ConnectionStringBuilder("key1=value1;key2=")); + + // invalid format + Assert.Throws(() => _ = new ConnectionStringBuilder("key;value")); + Assert.Throws(() => _ = new ConnectionStringBuilder("key==value")); + } + + [Fact] + public void ConnectionStringBuilder_constructor_Duplicated_Keys() + { + var builder = new ConnectionStringBuilder("Account=value1;Account=VALUE2"); + Assert.Equal("VALUE2", builder.Account); + } + + [Fact] + public void ConnectionStringBuilder_Protocol_No_Default_Value() + { + var builder = new ConnectionStringBuilder("key1=value1"); + Assert.Equal(TransportProtocol.Unspecified, builder.Protocol); + + builder = new ConnectionStringBuilder("EtwSession=OpenTelemetry"); + Assert.Equal(TransportProtocol.Etw, builder.Protocol); + + builder = new ConnectionStringBuilder("Endpoint=udp://localhost:11013"); + Assert.Equal(TransportProtocol.Udp, builder.Protocol); + + builder = new ConnectionStringBuilder("Endpoint=tcp://localhost:11013"); + Assert.Equal(TransportProtocol.Tcp, builder.Protocol); + + builder = new ConnectionStringBuilder("Endpoint=foo://localhost:11013"); + Assert.Throws(() => _ = builder.Protocol); + } + + [Fact] + public void ConnectionStringBuilder_EtwSession() + { + var builder = new ConnectionStringBuilder("EtwSession=OpenTelemetry"); + Assert.Equal(TransportProtocol.Etw, builder.Protocol); + Assert.Equal("OpenTelemetry", builder.EtwSession); + Assert.Throws(() => _ = builder.Host); + Assert.Throws(() => _ = builder.Port); + + builder = new ConnectionStringBuilder("Endpoint=udp://localhost:11013"); + Assert.Equal(TransportProtocol.Udp, builder.Protocol); + Assert.Throws(() => _ = builder.EtwSession); + } + + [Fact] + public void ConnectionStringBuilder_Endpoint_UnixDomainSocketPath() + { + var builder = new ConnectionStringBuilder("Endpoint=unix:/var/run/default_fluent.socket"); + Assert.Equal("unix:/var/run/default_fluent.socket", builder.Endpoint); + Assert.Equal(TransportProtocol.Unix, builder.Protocol); + Assert.Equal("/var/run/default_fluent.socket", builder.ParseUnixDomainSocketPath()); + + builder = new ConnectionStringBuilder("Endpoint=unix:///var/run/default_fluent.socket"); + Assert.Equal("unix:///var/run/default_fluent.socket", builder.Endpoint); + Assert.Equal(TransportProtocol.Unix, builder.Protocol); + Assert.Equal("/var/run/default_fluent.socket", builder.ParseUnixDomainSocketPath()); + + builder = new ConnectionStringBuilder("Endpoint=unix://:11111"); + Assert.Throws(() => _ = builder.ParseUnixDomainSocketPath()); + + builder = new ConnectionStringBuilder("EtwSession=OpenTelemetry"); + Assert.Throws(() => _ = builder.ParseUnixDomainSocketPath()); + } + + [Fact] + public void ConnectionStringBuilder_TimeoutMilliseconds() + { + var builder = new ConnectionStringBuilder("TimeoutMilliseconds=10000"); + Assert.Equal(10000, builder.TimeoutMilliseconds); + + builder.TimeoutMilliseconds = 6000; + Assert.Equal(6000, builder.TimeoutMilliseconds); + + builder = new ConnectionStringBuilder("Endpoint=unix:/var/run/default_fluent.socket"); + Assert.Equal(UnixDomainSocketDataTransport.DefaultTimeoutMilliseconds, builder.TimeoutMilliseconds); + + builder = new ConnectionStringBuilder("TimeoutMilliseconds=0"); + Assert.Throws(() => _ = builder.TimeoutMilliseconds); + + builder = new ConnectionStringBuilder("TimeoutMilliseconds=-1"); + Assert.Throws(() => _ = builder.TimeoutMilliseconds); + + builder = new ConnectionStringBuilder("TimeoutMilliseconds=-2"); + Assert.Throws(() => _ = builder.TimeoutMilliseconds); + + builder = new ConnectionStringBuilder("TimeoutMilliseconds=10.5"); + Assert.Throws(() => _ = builder.TimeoutMilliseconds); + + builder = new ConnectionStringBuilder("TimeoutMilliseconds=abc"); + Assert.Throws(() => _ = builder.TimeoutMilliseconds); + } + + [Fact] + public void ConnectionStringBuilder_Endpoint_Udp() + { + var builder = new ConnectionStringBuilder("Endpoint=udp://localhost:11111"); + Assert.Equal("udp://localhost:11111", builder.Endpoint); + Assert.Equal(TransportProtocol.Udp, builder.Protocol); + Assert.Equal("localhost", builder.Host); + Assert.Equal(11111, builder.Port); + + builder = new ConnectionStringBuilder("Endpoint=Udp://localhost:11111"); + Assert.Equal(TransportProtocol.Udp, builder.Protocol); + + builder = new ConnectionStringBuilder("Endpoint=UDP://localhost:11111"); + Assert.Equal(TransportProtocol.Udp, builder.Protocol); + + builder = new ConnectionStringBuilder("Endpoint=udp://localhost"); + Assert.Equal(TransportProtocol.Udp, builder.Protocol); + Assert.Equal("localhost", builder.Host); + Assert.Throws(() => _ = builder.Port); + + builder = new ConnectionStringBuilder("Endpoint=udp://:11111"); + Assert.Throws(() => _ = builder.Protocol); + Assert.Throws(() => _ = builder.Host); + Assert.Throws(() => _ = builder.Port); + } + + [Fact] + public void ConnectionStringBuilder_Endpoint_Tcp() + { + var builder = new ConnectionStringBuilder("Endpoint=tcp://localhost:33333"); + Assert.Equal("tcp://localhost:33333", builder.Endpoint); + Assert.Equal(TransportProtocol.Tcp, builder.Protocol); + Assert.Equal("localhost", builder.Host); + Assert.Equal(33333, builder.Port); + + builder = new ConnectionStringBuilder("Endpoint=Tcp://localhost:11111"); + Assert.Equal(TransportProtocol.Tcp, builder.Protocol); + + builder = new ConnectionStringBuilder("Endpoint=TCP://localhost:11111"); + Assert.Equal(TransportProtocol.Tcp, builder.Protocol); + + builder = new ConnectionStringBuilder("Endpoint=tcp://localhost"); + Assert.Equal(TransportProtocol.Tcp, builder.Protocol); + Assert.Equal("localhost", builder.Host); + Assert.Throws(() => _ = builder.Port); + + builder = new ConnectionStringBuilder("Endpoint=tpc://:11111"); + Assert.Throws(() => _ = builder.Protocol); + Assert.Throws(() => _ = builder.Host); + Assert.Throws(() => _ = builder.Port); + } + + [Fact] + public void ConnectionStringBuilder_EtwSession_Endpoint_Both_Set() + { + var builder = new ConnectionStringBuilder("Endpoint=tcp://localhost:33333;EtwSession=OpenTelemetry"); + Assert.Equal(TransportProtocol.Etw, builder.Protocol); + + Assert.Equal("OpenTelemetry", builder.EtwSession); + + Assert.Equal("tcp://localhost:33333", builder.Endpoint); + Assert.Equal("localhost", builder.Host); + Assert.Equal(33333, builder.Port); + } + + [Fact] + public void ConnectionStringBuilder_MonitoringAccount_No_Default_Value() + { + var builder = new ConnectionStringBuilder("key1=value1"); + Assert.Throws(() => _ = builder.Account); + + builder.Account = "TestAccount"; + Assert.Equal("TestAccount", builder.Account); + + builder = new ConnectionStringBuilder("Account=TestAccount"); + Assert.Equal("TestAccount", builder.Account); + } + + [Fact] + public void ConnectionStringBuilder_Keywords_Are_Case_Sensitive() { - [Fact] - public void ConnectionStringBuilder_constructor_Invalid_Input() - { - // null connection string - Assert.Throws(() => _ = new ConnectionStringBuilder(null)); - - // empty connection string - Assert.Throws(() => _ = new ConnectionStringBuilder(string.Empty)); - Assert.Throws(() => _ = new ConnectionStringBuilder(" ")); - - // empty key - Assert.Throws(() => _ = new ConnectionStringBuilder("=value")); - Assert.Throws(() => _ = new ConnectionStringBuilder("=value1;key2=value2")); - Assert.Throws(() => _ = new ConnectionStringBuilder("key1=value1;=value2")); - - // empty value - Assert.Throws(() => _ = new ConnectionStringBuilder("key=")); - Assert.Throws(() => _ = new ConnectionStringBuilder("key1=;key2=value2")); - Assert.Throws(() => _ = new ConnectionStringBuilder("key1=value1;key2=")); - - // invalid format - Assert.Throws(() => _ = new ConnectionStringBuilder("key;value")); - Assert.Throws(() => _ = new ConnectionStringBuilder("key==value")); - } - - [Fact] - public void ConnectionStringBuilder_constructor_Duplicated_Keys() - { - var builder = new ConnectionStringBuilder("Account=value1;Account=VALUE2"); - Assert.Equal("VALUE2", builder.Account); - } - - [Fact] - public void ConnectionStringBuilder_Protocol_No_Default_Value() - { - var builder = new ConnectionStringBuilder("key1=value1"); - Assert.Equal(TransportProtocol.Unspecified, builder.Protocol); - - builder = new ConnectionStringBuilder("EtwSession=OpenTelemetry"); - Assert.Equal(TransportProtocol.Etw, builder.Protocol); - - builder = new ConnectionStringBuilder("Endpoint=udp://localhost:11013"); - Assert.Equal(TransportProtocol.Udp, builder.Protocol); - - builder = new ConnectionStringBuilder("Endpoint=tcp://localhost:11013"); - Assert.Equal(TransportProtocol.Tcp, builder.Protocol); - - builder = new ConnectionStringBuilder("Endpoint=foo://localhost:11013"); - Assert.Throws(() => _ = builder.Protocol); - } - - [Fact] - public void ConnectionStringBuilder_EtwSession() - { - var builder = new ConnectionStringBuilder("EtwSession=OpenTelemetry"); - Assert.Equal(TransportProtocol.Etw, builder.Protocol); - Assert.Equal("OpenTelemetry", builder.EtwSession); - Assert.Throws(() => _ = builder.Host); - Assert.Throws(() => _ = builder.Port); - - builder = new ConnectionStringBuilder("Endpoint=udp://localhost:11013"); - Assert.Equal(TransportProtocol.Udp, builder.Protocol); - Assert.Throws(() => _ = builder.EtwSession); - } - - [Fact] - public void ConnectionStringBuilder_Endpoint_UnixDomainSocketPath() - { - var builder = new ConnectionStringBuilder("Endpoint=unix:/var/run/default_fluent.socket"); - Assert.Equal("unix:/var/run/default_fluent.socket", builder.Endpoint); - Assert.Equal(TransportProtocol.Unix, builder.Protocol); - Assert.Equal("/var/run/default_fluent.socket", builder.ParseUnixDomainSocketPath()); - - builder = new ConnectionStringBuilder("Endpoint=unix:///var/run/default_fluent.socket"); - Assert.Equal("unix:///var/run/default_fluent.socket", builder.Endpoint); - Assert.Equal(TransportProtocol.Unix, builder.Protocol); - Assert.Equal("/var/run/default_fluent.socket", builder.ParseUnixDomainSocketPath()); - - builder = new ConnectionStringBuilder("Endpoint=unix://:11111"); - Assert.Throws(() => _ = builder.ParseUnixDomainSocketPath()); - - builder = new ConnectionStringBuilder("EtwSession=OpenTelemetry"); - Assert.Throws(() => _ = builder.ParseUnixDomainSocketPath()); - } - - [Fact] - public void ConnectionStringBuilder_TimeoutMilliseconds() - { - var builder = new ConnectionStringBuilder("TimeoutMilliseconds=10000"); - Assert.Equal(10000, builder.TimeoutMilliseconds); - - builder.TimeoutMilliseconds = 6000; - Assert.Equal(6000, builder.TimeoutMilliseconds); - - builder = new ConnectionStringBuilder("Endpoint=unix:/var/run/default_fluent.socket"); - Assert.Equal(UnixDomainSocketDataTransport.DefaultTimeoutMilliseconds, builder.TimeoutMilliseconds); - - builder = new ConnectionStringBuilder("TimeoutMilliseconds=0"); - Assert.Throws(() => _ = builder.TimeoutMilliseconds); - - builder = new ConnectionStringBuilder("TimeoutMilliseconds=-1"); - Assert.Throws(() => _ = builder.TimeoutMilliseconds); - - builder = new ConnectionStringBuilder("TimeoutMilliseconds=-2"); - Assert.Throws(() => _ = builder.TimeoutMilliseconds); - - builder = new ConnectionStringBuilder("TimeoutMilliseconds=10.5"); - Assert.Throws(() => _ = builder.TimeoutMilliseconds); - - builder = new ConnectionStringBuilder("TimeoutMilliseconds=abc"); - Assert.Throws(() => _ = builder.TimeoutMilliseconds); - } - - [Fact] - public void ConnectionStringBuilder_Endpoint_Udp() - { - var builder = new ConnectionStringBuilder("Endpoint=udp://localhost:11111"); - Assert.Equal("udp://localhost:11111", builder.Endpoint); - Assert.Equal(TransportProtocol.Udp, builder.Protocol); - Assert.Equal("localhost", builder.Host); - Assert.Equal(11111, builder.Port); - - builder = new ConnectionStringBuilder("Endpoint=Udp://localhost:11111"); - Assert.Equal(TransportProtocol.Udp, builder.Protocol); - - builder = new ConnectionStringBuilder("Endpoint=UDP://localhost:11111"); - Assert.Equal(TransportProtocol.Udp, builder.Protocol); - - builder = new ConnectionStringBuilder("Endpoint=udp://localhost"); - Assert.Equal(TransportProtocol.Udp, builder.Protocol); - Assert.Equal("localhost", builder.Host); - Assert.Throws(() => _ = builder.Port); - - builder = new ConnectionStringBuilder("Endpoint=udp://:11111"); - Assert.Throws(() => _ = builder.Protocol); - Assert.Throws(() => _ = builder.Host); - Assert.Throws(() => _ = builder.Port); - } - - [Fact] - public void ConnectionStringBuilder_Endpoint_Tcp() - { - var builder = new ConnectionStringBuilder("Endpoint=tcp://localhost:33333"); - Assert.Equal("tcp://localhost:33333", builder.Endpoint); - Assert.Equal(TransportProtocol.Tcp, builder.Protocol); - Assert.Equal("localhost", builder.Host); - Assert.Equal(33333, builder.Port); - - builder = new ConnectionStringBuilder("Endpoint=Tcp://localhost:11111"); - Assert.Equal(TransportProtocol.Tcp, builder.Protocol); - - builder = new ConnectionStringBuilder("Endpoint=TCP://localhost:11111"); - Assert.Equal(TransportProtocol.Tcp, builder.Protocol); - - builder = new ConnectionStringBuilder("Endpoint=tcp://localhost"); - Assert.Equal(TransportProtocol.Tcp, builder.Protocol); - Assert.Equal("localhost", builder.Host); - Assert.Throws(() => _ = builder.Port); - - builder = new ConnectionStringBuilder("Endpoint=tpc://:11111"); - Assert.Throws(() => _ = builder.Protocol); - Assert.Throws(() => _ = builder.Host); - Assert.Throws(() => _ = builder.Port); - } - - [Fact] - public void ConnectionStringBuilder_EtwSession_Endpoint_Both_Set() - { - var builder = new ConnectionStringBuilder("Endpoint=tcp://localhost:33333;EtwSession=OpenTelemetry"); - Assert.Equal(TransportProtocol.Etw, builder.Protocol); - - Assert.Equal("OpenTelemetry", builder.EtwSession); - - Assert.Equal("tcp://localhost:33333", builder.Endpoint); - Assert.Equal("localhost", builder.Host); - Assert.Equal(33333, builder.Port); - } - - [Fact] - public void ConnectionStringBuilder_MonitoringAccount_No_Default_Value() - { - var builder = new ConnectionStringBuilder("key1=value1"); - Assert.Throws(() => _ = builder.Account); - - builder.Account = "TestAccount"; - Assert.Equal("TestAccount", builder.Account); - - builder = new ConnectionStringBuilder("Account=TestAccount"); - Assert.Equal("TestAccount", builder.Account); - } - - [Fact] - public void ConnectionStringBuilder_Keywords_Are_Case_Sensitive() - { - var builder = new ConnectionStringBuilder("etwSession=OpenTelemetry"); - Assert.Throws(() => builder.EtwSession); - Assert.Equal(TransportProtocol.Unspecified, builder.Protocol); - - builder = new ConnectionStringBuilder("endpoint=tcp://localhost:33333"); - Assert.Throws(() => builder.Endpoint); - Assert.Equal(TransportProtocol.Unspecified, builder.Protocol); - Assert.Throws(() => builder.Host); - Assert.Throws(() => builder.Port); - - builder = new ConnectionStringBuilder("monitoringAccount=TestAccount"); - Assert.Throws(() => builder.Account); - Assert.Equal(TransportProtocol.Unspecified, builder.Protocol); - } + var builder = new ConnectionStringBuilder("etwSession=OpenTelemetry"); + Assert.Throws(() => builder.EtwSession); + Assert.Equal(TransportProtocol.Unspecified, builder.Protocol); + + builder = new ConnectionStringBuilder("endpoint=tcp://localhost:33333"); + Assert.Throws(() => builder.Endpoint); + Assert.Equal(TransportProtocol.Unspecified, builder.Protocol); + Assert.Throws(() => builder.Host); + Assert.Throws(() => builder.Port); + + builder = new ConnectionStringBuilder("monitoringAccount=TestAccount"); + Assert.Throws(() => builder.Account); + Assert.Equal(TransportProtocol.Unspecified, builder.Protocol); } } diff --git a/test/OpenTelemetry.Exporter.Geneva.Tests/GenevaLogExporterTests.cs b/test/OpenTelemetry.Exporter.Geneva.Tests/GenevaLogExporterTests.cs index 91d82c38c3..0f1168c856 100644 --- a/test/OpenTelemetry.Exporter.Geneva.Tests/GenevaLogExporterTests.cs +++ b/test/OpenTelemetry.Exporter.Geneva.Tests/GenevaLogExporterTests.cs @@ -24,226 +24,225 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; -using System.Threading.Tasks; using Microsoft.Extensions.Logging; using OpenTelemetry.Logs; using Xunit; -namespace OpenTelemetry.Exporter.Geneva.Tests +namespace OpenTelemetry.Exporter.Geneva.Tests; + +public class GenevaLogExporterTests { - public class GenevaLogExporterTests + [Fact] + public void BadArgs() + { + GenevaExporterOptions exporterOptions = null; + Assert.Throws(() => + { + using var exporter = new GenevaLogExporter(exporterOptions); + }); + } + + [Fact] + public void SpecialCharactersInTableNameMappings() { - [Fact] - public void BadArgs() + Assert.Throws(() => { - GenevaExporterOptions exporterOptions = null; - Assert.Throws(() => + using var exporter = new GenevaLogExporter(new GenevaExporterOptions { - using var exporter = new GenevaLogExporter(exporterOptions); + TableNameMappings = new Dictionary { ["TestCategory"] = "\u0418" }, }); - } + }); - [Fact] - public void SpecialChractersInTableNameMappings() + Assert.Throws(() => { - Assert.Throws(() => + using var exporter = new GenevaLogExporter(new GenevaExporterOptions { - using var exporter = new GenevaLogExporter(new GenevaExporterOptions - { - TableNameMappings = new Dictionary { ["TestCategory"] = "\u0418" }, - }); + TableNameMappings = new Dictionary { ["*"] = "\u0418" }, }); + }); - Assert.Throws(() => + // Throw on null value - include key in exception message + var ex = Assert.Throws(() => + { + new GenevaExporterOptions { - using var exporter = new GenevaLogExporter(new GenevaExporterOptions - { - TableNameMappings = new Dictionary { ["*"] = "\u0418" }, - }); - }); + TableNameMappings = new Dictionary { ["TestCategory"] = null }, + }; + }); + Assert.Contains("TableNameMappings must not contain null values.", ex.Message); + Assert.Equal("TestCategory", ex.ParamName); - // Throw on null value - include key in exception message - var ex = Assert.Throws(() => + // Throw when TableNameMappings is null + Assert.Throws(() => + { + new GenevaExporterOptions { - new GenevaExporterOptions - { - TableNameMappings = new Dictionary { ["TestCategory"] = null }, - }; - }); - Assert.Contains("TableNameMappings must not contain null values.", ex.Message); - Assert.Equal("TestCategory", ex.ParamName); + TableNameMappings = null, + }; + }); + } + + [Theory] + [InlineData(null)] + [InlineData("")] + [InlineData(" ")] + public void InvalidConnectionString(string connectionString) + { + var exporterOptions = new GenevaExporterOptions() { ConnectionString = connectionString }; + var exception = Assert.Throws(() => + { + using var exporter = new GenevaLogExporter(exporterOptions); + }); + } - // Throw when TableNameMappings is null - Assert.Throws(() => + [Fact] + public void IncompatibleConnectionString_Windows() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + var exporterOptions = new GenevaExporterOptions() { ConnectionString = "Endpoint=unix:" + @"C:\Users\user\AppData\Local\Temp\14tj4ac4.v2q" }; + var exception = Assert.Throws(() => { - new GenevaExporterOptions - { - TableNameMappings = null, - }; + using var exporter = new GenevaLogExporter(exporterOptions); }); + Assert.Equal("Unix domain socket should not be used on Windows.", exception.Message); } + } - [Theory] - [InlineData(null)] - [InlineData("")] - [InlineData(" ")] - public void InvalidConnectionString(string connectionString) + [Fact] + public void IncompatibleConnectionString_Linux() + { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - var exporterOptions = new GenevaExporterOptions() { ConnectionString = connectionString }; + var exporterOptions = new GenevaExporterOptions() { ConnectionString = "EtwSession=OpenTelemetry" }; var exception = Assert.Throws(() => { using var exporter = new GenevaLogExporter(exporterOptions); }); + Assert.Equal("ETW cannot be used on non-Windows operating systems.", exception.Message); } + } - [Fact] - public void IncompatibleConnectionString_Windows() + [Theory] + [InlineData("categoryA", "TableA")] + [InlineData("categoryB", "TableB")] + [InlineData("categoryA", "TableA", "categoryB", "TableB")] + [InlineData("categoryA", "TableA", "*", "CatchAll")] + [InlineData(null)] + public void TableNameMappingTest(params string[] category) + { + // ARRANGE + string path = string.Empty; + Socket server = null; + var logRecordList = new List(); + Dictionary mappingsDict = null; + try { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + var exporterOptions = new GenevaExporterOptions(); + if (category?.Length > 0) { - var exporterOptions = new GenevaExporterOptions() { ConnectionString = "Endpoint=unix:" + @"C:\Users\user\AppData\Local\Temp\14tj4ac4.v2q" }; - var exception = Assert.Throws(() => + mappingsDict = new Dictionary(); + for (int i = 0; i < category.Length; i = i + 2) { - using var exporter = new GenevaLogExporter(exporterOptions); - }); - Assert.Equal("Unix domain socket should not be used on Windows.", exception.Message); + mappingsDict.Add(category[i], category[i + 1]); + } + + exporterOptions.TableNameMappings = mappingsDict; } - } - [Fact] - public void IncompatibleConnectionString_Linux() - { - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - var exporterOptions = new GenevaExporterOptions() { ConnectionString = "EtwSession=OpenTelemetry" }; - var exception = Assert.Throws(() => - { - using var exporter = new GenevaLogExporter(exporterOptions); - }); - Assert.Equal("ETW cannot be used on non-Windows operating systems.", exception.Message); + exporterOptions.ConnectionString = "EtwSession=OpenTelemetry"; } - } - - [Theory] - [InlineData("categoryA", "TableA")] - [InlineData("categoryB", "TableB")] - [InlineData("categoryA", "TableA", "categoryB", "TableB")] - [InlineData("categoryA", "TableA", "*", "CatchAll")] - [InlineData(null)] - public void TableNameMappingTest(params string[] category) - { - // ARRANGE - string path = string.Empty; - Socket server = null; - var logRecordList = new List(); - Dictionary mappingsDict = null; - try + else { - var exporterOptions = new GenevaExporterOptions(); - if (category?.Length > 0) - { - mappingsDict = new Dictionary(); - for (int i = 0; i < category.Length; i = i + 2) - { - mappingsDict.Add(category[i], category[i + 1]); - } - - exporterOptions.TableNameMappings = mappingsDict; - } - - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - exporterOptions.ConnectionString = "EtwSession=OpenTelemetry"; - } - else - { - path = GenerateTempFilePath(); - exporterOptions.ConnectionString = "Endpoint=unix:" + path; - var endpoint = new UnixDomainSocketEndPoint(path); - server = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); - server.Bind(endpoint); - server.Listen(1); - } + path = GenerateTempFilePath(); + exporterOptions.ConnectionString = "Endpoint=unix:" + path; + var endpoint = new UnixDomainSocketEndPoint(path); + server = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); + server.Bind(endpoint); + server.Listen(1); + } - using var loggerFactory = LoggerFactory.Create(builder => builder + using var loggerFactory = LoggerFactory.Create(builder => builder .AddOpenTelemetry(options => { options.AddInMemoryExporter(logRecordList); }) .AddFilter("*", LogLevel.Trace)); // Enable all LogLevels - // Create a test exporter to get MessagePack byte data to validate if the data was serialized correctly. - using var exporter = new GenevaLogExporter(exporterOptions); + // Create a test exporter to get MessagePack byte data to validate if the data was serialized correctly. + using var exporter = new GenevaLogExporter(exporterOptions); - ILogger logger; - ThreadLocal m_buffer; - object fluentdData; - string actualTableName; - string defaultLogTable = "Log"; - if (mappingsDict != null) + ILogger logger; + ThreadLocal m_buffer; + object fluentdData; + string actualTableName; + string defaultLogTable = "Log"; + if (mappingsDict != null) + { + foreach (var mapping in mappingsDict) { - foreach (var mapping in mappingsDict) + if (!mapping.Key.Equals("*")) { - if (!mapping.Key.Equals("*")) - { - logger = loggerFactory.CreateLogger(mapping.Key); - logger.LogError("this does not matter"); - - Assert.Single(logRecordList); - m_buffer = typeof(GenevaLogExporter).GetField("m_buffer", BindingFlags.NonPublic | BindingFlags.Static).GetValue(exporter) as ThreadLocal; - _ = exporter.SerializeLogRecord(logRecordList[0]); - fluentdData = MessagePack.MessagePackSerializer.Deserialize(m_buffer.Value, MessagePack.Resolvers.ContractlessStandardResolver.Instance); - actualTableName = (fluentdData as object[])[0] as string; - Assert.Equal(mapping.Value, actualTableName); - logRecordList.Clear(); - } - else - { - defaultLogTable = mapping.Value; - } + logger = loggerFactory.CreateLogger(mapping.Key); + logger.LogError("this does not matter"); + + Assert.Single(logRecordList); + m_buffer = typeof(GenevaLogExporter).GetField("m_buffer", BindingFlags.NonPublic | BindingFlags.Static).GetValue(exporter) as ThreadLocal; + _ = exporter.SerializeLogRecord(logRecordList[0]); + fluentdData = MessagePack.MessagePackSerializer.Deserialize(m_buffer.Value, MessagePack.Resolvers.ContractlessStandardResolver.Instance); + actualTableName = (fluentdData as object[])[0] as string; + Assert.Equal(mapping.Value, actualTableName); + logRecordList.Clear(); } + else + { + defaultLogTable = mapping.Value; + } + } - // test default table - logger = loggerFactory.CreateLogger("random category"); - logger.LogError("this does not matter"); + // test default table + logger = loggerFactory.CreateLogger("random category"); + logger.LogError("this does not matter"); - Assert.Single(logRecordList); - m_buffer = typeof(GenevaLogExporter).GetField("m_buffer", BindingFlags.NonPublic | BindingFlags.Static).GetValue(exporter) as ThreadLocal; - _ = exporter.SerializeLogRecord(logRecordList[0]); - fluentdData = MessagePack.MessagePackSerializer.Deserialize(m_buffer.Value, MessagePack.Resolvers.ContractlessStandardResolver.Instance); - actualTableName = (fluentdData as object[])[0] as string; - Assert.Equal(defaultLogTable, actualTableName); - logRecordList.Clear(); - } + Assert.Single(logRecordList); + m_buffer = typeof(GenevaLogExporter).GetField("m_buffer", BindingFlags.NonPublic | BindingFlags.Static).GetValue(exporter) as ThreadLocal; + _ = exporter.SerializeLogRecord(logRecordList[0]); + fluentdData = MessagePack.MessagePackSerializer.Deserialize(m_buffer.Value, MessagePack.Resolvers.ContractlessStandardResolver.Instance); + actualTableName = (fluentdData as object[])[0] as string; + Assert.Equal(defaultLogTable, actualTableName); + logRecordList.Clear(); } - finally + } + finally + { + server?.Dispose(); + try + { + File.Delete(path); + } + catch { - server?.Dispose(); - try - { - File.Delete(path); - } - catch - { - } } } + } - [Fact] - public void PassThruTableMappingsWhenTheRuleIsEnabled() + [Fact] + public void PassThruTableMappingsWhenTheRuleIsEnabled() + { + string path = string.Empty; + Socket server = null; + try { - string path = string.Empty; - Socket server = null; - try + var userInitializedCategoryToTableNameMappings = new Dictionary { - var userInitializedCategoryToTableNameMappings = new Dictionary - { - ["Company.Store"] = "Store", - ["Company.Orders"] = "Orders", - ["*"] = "*", - }; + ["Company.Store"] = "Store", + ["Company.Orders"] = "Orders", + ["*"] = "*", + }; - var expectedCategoryToTableNameList = new List> + var expectedCategoryToTableNameList = new List> { // The category name must match "^[A-Z][a-zA-Z0-9]*$"; any character that is not allowed will be removed. new KeyValuePair("Company.Customer", "CompanyCustomer"), @@ -267,116 +266,116 @@ public void PassThruTableMappingsWhenTheRuleIsEnabled() new KeyValuePair("1.2", null), }; - var logRecordList = new List(); - var exporterOptions = new GenevaExporterOptions - { - TableNameMappings = userInitializedCategoryToTableNameMappings, - }; + var logRecordList = new List(); + var exporterOptions = new GenevaExporterOptions + { + TableNameMappings = userInitializedCategoryToTableNameMappings, + }; - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - exporterOptions.ConnectionString = "EtwSession=OpenTelemetry"; - } - else - { - path = GenerateTempFilePath(); - exporterOptions.ConnectionString = "Endpoint=unix:" + path; - var endpoint = new UnixDomainSocketEndPoint(path); - server = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); - server.Bind(endpoint); - server.Listen(1); - } + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + exporterOptions.ConnectionString = "EtwSession=OpenTelemetry"; + } + else + { + path = GenerateTempFilePath(); + exporterOptions.ConnectionString = "Endpoint=unix:" + path; + var endpoint = new UnixDomainSocketEndPoint(path); + server = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); + server.Bind(endpoint); + server.Listen(1); + } - using var loggerFactory = LoggerFactory.Create(builder => builder + using var loggerFactory = LoggerFactory.Create(builder => builder .AddOpenTelemetry(options => { options.AddInMemoryExporter(logRecordList); }) .AddFilter("*", LogLevel.Trace)); // Enable all LogLevels - // Create a test exporter to get MessagePack byte data to validate if the data was serialized correctly. - using var exporter = new GenevaLogExporter(exporterOptions); - - ILogger passThruTableMappingsLogger, userInitializedTableMappingsLogger; - ThreadLocal m_buffer; - object fluentdData; - string actualTableName; - m_buffer = typeof(GenevaLogExporter).GetField("m_buffer", BindingFlags.NonPublic | BindingFlags.Static).GetValue(exporter) as ThreadLocal; + // Create a test exporter to get MessagePack byte data to validate if the data was serialized correctly. + using var exporter = new GenevaLogExporter(exporterOptions); - // Verify that the category table mappings specified by the users in the Geneva Configuration are mapped correctly. - foreach (var mapping in userInitializedCategoryToTableNameMappings) - { - if (mapping.Key != "*") - { - userInitializedTableMappingsLogger = loggerFactory.CreateLogger(mapping.Key); - userInitializedTableMappingsLogger.LogInformation("This information does not matter."); - Assert.Single(logRecordList); + ILogger passThruTableMappingsLogger, userInitializedTableMappingsLogger; + ThreadLocal m_buffer; + object fluentdData; + string actualTableName; + m_buffer = typeof(GenevaLogExporter).GetField("m_buffer", BindingFlags.NonPublic | BindingFlags.Static).GetValue(exporter) as ThreadLocal; - _ = exporter.SerializeLogRecord(logRecordList[0]); - fluentdData = MessagePack.MessagePackSerializer.Deserialize(m_buffer.Value, MessagePack.Resolvers.ContractlessStandardResolver.Instance); - actualTableName = (fluentdData as object[])[0] as string; - userInitializedCategoryToTableNameMappings.TryGetValue(mapping.Key, out var expectedTableNme); - Assert.Equal(expectedTableNme, actualTableName); - - logRecordList.Clear(); - } - } - - // Verify that when the "*" = "*" were enabled, the correct table names were being deduced following the set of rules. - foreach (var mapping in expectedCategoryToTableNameList) + // Verify that the category table mappings specified by the users in the Geneva Configuration are mapped correctly. + foreach (var mapping in userInitializedCategoryToTableNameMappings) + { + if (mapping.Key != "*") { - passThruTableMappingsLogger = loggerFactory.CreateLogger(mapping.Key); - passThruTableMappingsLogger.LogInformation("This information does not matter."); + userInitializedTableMappingsLogger = loggerFactory.CreateLogger(mapping.Key); + userInitializedTableMappingsLogger.LogInformation("This information does not matter."); Assert.Single(logRecordList); _ = exporter.SerializeLogRecord(logRecordList[0]); fluentdData = MessagePack.MessagePackSerializer.Deserialize(m_buffer.Value, MessagePack.Resolvers.ContractlessStandardResolver.Instance); actualTableName = (fluentdData as object[])[0] as string; - string expectedTableName = string.Empty; - expectedTableName = mapping.Value; - Assert.Equal(expectedTableName, actualTableName); + userInitializedCategoryToTableNameMappings.TryGetValue(mapping.Key, out var expectedTableNme); + Assert.Equal(expectedTableNme, actualTableName); logRecordList.Clear(); } } - finally + + // Verify that when the "*" = "*" were enabled, the correct table names were being deduced following the set of rules. + foreach (var mapping in expectedCategoryToTableNameList) { - server?.Dispose(); - try - { - File.Delete(path); - } - catch - { - } + passThruTableMappingsLogger = loggerFactory.CreateLogger(mapping.Key); + passThruTableMappingsLogger.LogInformation("This information does not matter."); + Assert.Single(logRecordList); + + _ = exporter.SerializeLogRecord(logRecordList[0]); + fluentdData = MessagePack.MessagePackSerializer.Deserialize(m_buffer.Value, MessagePack.Resolvers.ContractlessStandardResolver.Instance); + actualTableName = (fluentdData as object[])[0] as string; + string expectedTableName = string.Empty; + expectedTableName = mapping.Value; + Assert.Equal(expectedTableName, actualTableName); + + logRecordList.Clear(); } } - - [Fact] - public void SerializeILoggerScopes() + finally { - string path = string.Empty; - Socket senderSocket = null; - Socket receiverSocket = null; + server?.Dispose(); try { - var exporterOptions = new GenevaExporterOptions(); + File.Delete(path); + } + catch + { + } + } + } - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - exporterOptions.ConnectionString = "EtwSession=OpenTelemetry"; - } - else - { - path = GenerateTempFilePath(); - exporterOptions.ConnectionString = "Endpoint=unix:" + path; - var endpoint = new UnixDomainSocketEndPoint(path); - senderSocket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); - senderSocket.Bind(endpoint); - senderSocket.Listen(1); - } + [Fact] + public void SerializeILoggerScopes() + { + string path = string.Empty; + Socket senderSocket = null; + Socket receiverSocket = null; + try + { + var exporterOptions = new GenevaExporterOptions(); - using var loggerFactory = LoggerFactory.Create(builder => builder + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + exporterOptions.ConnectionString = "EtwSession=OpenTelemetry"; + } + else + { + path = GenerateTempFilePath(); + exporterOptions.ConnectionString = "Endpoint=unix:" + path; + var endpoint = new UnixDomainSocketEndPoint(path); + senderSocket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); + senderSocket.Bind(endpoint); + senderSocket.Listen(1); + } + + using var loggerFactory = LoggerFactory.Create(builder => builder .AddOpenTelemetry(options => { options.IncludeScopes = true; @@ -386,114 +385,114 @@ public void SerializeILoggerScopes() }); })); - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - receiverSocket = senderSocket.Accept(); - receiverSocket.ReceiveTimeout = 10000; - } + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + receiverSocket = senderSocket.Accept(); + receiverSocket.ReceiveTimeout = 10000; + } - // Create a test exporter to get MessagePack byte data to validate if the data was serialized correctly. - using var exporter = new GenevaLogExporter(exporterOptions); + // Create a test exporter to get MessagePack byte data to validate if the data was serialized correctly. + using var exporter = new GenevaLogExporter(exporterOptions); - // Emit a LogRecord and grab a copy of internal buffer for validation. - var logger = loggerFactory.CreateLogger(); + // Emit a LogRecord and grab a copy of internal buffer for validation. + var logger = loggerFactory.CreateLogger(); - using (logger.BeginScope("MyOuterScope")) - using (logger.BeginScope("MyInnerScope")) - using (logger.BeginScope("MyInnerInnerScope with {name} and {age} of custom", "John Doe", 35)) - using (logger.BeginScope(new List> { new KeyValuePair("MyKey", "MyValue") })) - { - logger.LogInformation("Hello from {food} {price}.", "artichoke", 3.99); - } + using (logger.BeginScope("MyOuterScope")) + using (logger.BeginScope("MyInnerScope")) + using (logger.BeginScope("MyInnerInnerScope with {name} and {age} of custom", "John Doe", 35)) + using (logger.BeginScope(new List> { new KeyValuePair("MyKey", "MyValue") })) + { + logger.LogInformation("Hello from {food} {price}.", "artichoke", 3.99); + } - byte[] serializedData; - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - var m_buffer = typeof(GenevaLogExporter).GetField("m_buffer", BindingFlags.NonPublic | BindingFlags.Static).GetValue(exporter) as ThreadLocal; - serializedData = m_buffer.Value; - } - else - { - // Read the data sent via socket. - serializedData = new byte[65360]; - _ = receiverSocket.Receive(serializedData); - } + byte[] serializedData; + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + var m_buffer = typeof(GenevaLogExporter).GetField("m_buffer", BindingFlags.NonPublic | BindingFlags.Static).GetValue(exporter) as ThreadLocal; + serializedData = m_buffer.Value; + } + else + { + // Read the data sent via socket. + serializedData = new byte[65360]; + _ = receiverSocket.Receive(serializedData); + } - object fluentdData = MessagePack.MessagePackSerializer.Deserialize(serializedData, MessagePack.Resolvers.ContractlessStandardResolver.Instance); - var signal = (fluentdData as object[])[0] as string; - var TimeStampAndMappings = ((fluentdData as object[])[1] as object[])[0]; - var mapping = (TimeStampAndMappings as object[])[1] as Dictionary; - var serializedScopes = mapping["scopes"] as object[]; - - Assert.Equal(4, serializedScopes.Length); - - // Test 1st scope - var scope = serializedScopes[0] as ICollection>; - Assert.Single(scope); - Assert.Contains(new KeyValuePair("scope", "MyOuterScope"), scope); - - // Test 2nd scope - scope = serializedScopes[1] as ICollection>; - Assert.Single(scope); - Assert.Contains(new KeyValuePair("scope", "MyInnerScope"), scope); - - // Test 3rd scope - scope = serializedScopes[2] as ICollection>; - Assert.Equal(3, scope.Count); - Assert.Contains(new KeyValuePair("name", "John Doe"), scope); - Assert.Contains(new KeyValuePair("age", (byte)35), scope); - Assert.Contains(new KeyValuePair("{OriginalFormat}", "MyInnerInnerScope with {name} and {age} of custom"), scope); - - // Test 4th scope - scope = serializedScopes[3] as ICollection>; - Assert.Single(scope); - Assert.Contains(new KeyValuePair("MyKey", "MyValue"), scope); + object fluentdData = MessagePack.MessagePackSerializer.Deserialize(serializedData, MessagePack.Resolvers.ContractlessStandardResolver.Instance); + var signal = (fluentdData as object[])[0] as string; + var TimeStampAndMappings = ((fluentdData as object[])[1] as object[])[0]; + var mapping = (TimeStampAndMappings as object[])[1] as Dictionary; + var serializedScopes = mapping["scopes"] as object[]; + + Assert.Equal(4, serializedScopes.Length); + + // Test 1st scope + var scope = serializedScopes[0] as ICollection>; + Assert.Single(scope); + Assert.Contains(new KeyValuePair("scope", "MyOuterScope"), scope); + + // Test 2nd scope + scope = serializedScopes[1] as ICollection>; + Assert.Single(scope); + Assert.Contains(new KeyValuePair("scope", "MyInnerScope"), scope); + + // Test 3rd scope + scope = serializedScopes[2] as ICollection>; + Assert.Equal(3, scope.Count); + Assert.Contains(new KeyValuePair("name", "John Doe"), scope); + Assert.Contains(new KeyValuePair("age", (byte)35), scope); + Assert.Contains(new KeyValuePair("{OriginalFormat}", "MyInnerInnerScope with {name} and {age} of custom"), scope); + + // Test 4th scope + scope = serializedScopes[3] as ICollection>; + Assert.Single(scope); + Assert.Contains(new KeyValuePair("MyKey", "MyValue"), scope); + } + finally + { + senderSocket?.Dispose(); + receiverSocket?.Dispose(); + try + { + File.Delete(path); } - finally + catch { - senderSocket?.Dispose(); - receiverSocket?.Dispose(); - try - { - File.Delete(path); - } - catch - { - } } } + } - [Theory] - [InlineData(true)] - [InlineData(false)] - public void SerializationTestWithILoggerLogMethod(bool includeFormattedMessage) + [Theory] + [InlineData(true)] + [InlineData(false)] + public void SerializationTestWithILoggerLogMethod(bool includeFormattedMessage) + { + // Dedicated test for the raw ILogger.Log method + // https://docs.microsoft.com/dotnet/api/microsoft.extensions.logging.ilogger.log + + // ARRANGE + string path = string.Empty; + Socket server = null; + var logRecordList = new List(); + try { - // Dedicated test for the raw ILogger.Log method - // https://docs.microsoft.com/dotnet/api/microsoft.extensions.logging.ilogger.log + var exporterOptions = new GenevaExporterOptions(); - // ARRANGE - string path = string.Empty; - Socket server = null; - var logRecordList = new List(); - try + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - var exporterOptions = new GenevaExporterOptions(); - - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - exporterOptions.ConnectionString = "EtwSession=OpenTelemetry"; - } - else - { - path = GenerateTempFilePath(); - exporterOptions.ConnectionString = "Endpoint=unix:" + path; - var endpoint = new UnixDomainSocketEndPoint(path); - server = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); - server.Bind(endpoint); - server.Listen(1); - } + exporterOptions.ConnectionString = "EtwSession=OpenTelemetry"; + } + else + { + path = GenerateTempFilePath(); + exporterOptions.ConnectionString = "Endpoint=unix:" + path; + var endpoint = new UnixDomainSocketEndPoint(path); + server = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); + server.Bind(endpoint); + server.Listen(1); + } - using var loggerFactory = LoggerFactory.Create(builder => builder + using var loggerFactory = LoggerFactory.Create(builder => builder .AddOpenTelemetry(options => { options.AddGenevaLogExporter(options => @@ -503,198 +502,198 @@ public void SerializationTestWithILoggerLogMethod(bool includeFormattedMessage) options.AddInMemoryExporter(logRecordList); options.IncludeFormattedMessage = includeFormattedMessage; }) - .AddFilter(typeof(GenevaLogExporterTests).FullName, LogLevel.Trace)); // Enable all LogLevels - - // Create a test exporter to get MessagePack byte data to validate if the data was serialized correctly. - using var exporter = new GenevaLogExporter(exporterOptions); - - // Emit a LogRecord and grab a copy of the LogRecord from the collection passed to InMemoryExporter - var logger = loggerFactory.CreateLogger(); - - // ACT - // This is treated as structured logging as the state can be converted to IReadOnlyList> - logger.Log( - LogLevel.Information, - default, - new List>() - { - new KeyValuePair("Key1", "Value1"), - new KeyValuePair("Key2", "Value2"), - }, - null, - (state, ex) => "Formatted Message"); - - // VALIDATE - Assert.Single(logRecordList); - var m_buffer = typeof(GenevaLogExporter).GetField("m_buffer", BindingFlags.NonPublic | BindingFlags.Static).GetValue(exporter) as ThreadLocal; - _ = exporter.SerializeLogRecord(logRecordList[0]); - object fluentdData = MessagePack.MessagePackSerializer.Deserialize(m_buffer.Value, MessagePack.Resolvers.ContractlessStandardResolver.Instance); - var body = GetField(fluentdData, "body"); - if (includeFormattedMessage) - { - Assert.Equal("Formatted Message", body); - } - else - { - Assert.Null(body); - } - - Assert.Equal("Value1", GetField(fluentdData, "Key1")); - Assert.Equal("Value2", GetField(fluentdData, "Key2")); - - // ARRANGE - logRecordList.Clear(); - - // ACT - // This is treated as Un-structured logging as the state cannot be converted to IReadOnlyList> - logger.Log( - LogLevel.Information, - default, - state: "somestringasdata", - exception: null, - formatter: (state, ex) => "Formatted Message"); - - // VALIDATE - Assert.Single(logRecordList); - m_buffer = typeof(GenevaLogExporter).GetField("m_buffer", BindingFlags.NonPublic | BindingFlags.Static).GetValue(exporter) as ThreadLocal; - _ = exporter.SerializeLogRecord(logRecordList[0]); - fluentdData = MessagePack.MessagePackSerializer.Deserialize(m_buffer.Value, MessagePack.Resolvers.ContractlessStandardResolver.Instance); - body = GetField(fluentdData, "body"); - if (includeFormattedMessage) - { - Assert.Equal("Formatted Message", body); - } - else - { - Assert.Null(body); - } - - // ARRANGE - logRecordList.Clear(); + .AddFilter(typeof(GenevaLogExporterTests).FullName, LogLevel.Trace)); // Enable all LogLevels - // ACT - // This is treated as Un-structured logging as the state cannot be converted to IReadOnlyList> - logger.Log( - LogLevel.Information, - default, - state: "somestringasdata", - exception: null, - formatter: null); + // Create a test exporter to get MessagePack byte data to validate if the data was serialized correctly. + using var exporter = new GenevaLogExporter(exporterOptions); - // VALIDATE - Assert.Single(logRecordList); - m_buffer = typeof(GenevaLogExporter).GetField("m_buffer", BindingFlags.NonPublic | BindingFlags.Static).GetValue(exporter) as ThreadLocal; - _ = exporter.SerializeLogRecord(logRecordList[0]); - fluentdData = MessagePack.MessagePackSerializer.Deserialize(m_buffer.Value, MessagePack.Resolvers.ContractlessStandardResolver.Instance); - body = GetField(fluentdData, "body"); + // Emit a LogRecord and grab a copy of the LogRecord from the collection passed to InMemoryExporter + var logger = loggerFactory.CreateLogger(); - // Formatter is null, hence body is always null + // ACT + // This is treated as structured logging as the state can be converted to IReadOnlyList> + logger.Log( + LogLevel.Information, + default, + new List>() + { + new KeyValuePair("Key1", "Value1"), + new KeyValuePair("Key2", "Value2"), + }, + null, + (state, ex) => "Formatted Message"); + + // VALIDATE + Assert.Single(logRecordList); + var m_buffer = typeof(GenevaLogExporter).GetField("m_buffer", BindingFlags.NonPublic | BindingFlags.Static).GetValue(exporter) as ThreadLocal; + _ = exporter.SerializeLogRecord(logRecordList[0]); + object fluentdData = MessagePack.MessagePackSerializer.Deserialize(m_buffer.Value, MessagePack.Resolvers.ContractlessStandardResolver.Instance); + var body = GetField(fluentdData, "body"); + if (includeFormattedMessage) + { + Assert.Equal("Formatted Message", body); + } + else + { Assert.Null(body); + } - // ARRANGE - logRecordList.Clear(); - - // ACT - // This is treated as Structured logging as the state can be converted to IReadOnlyList> - logger.Log( - logLevel: LogLevel.Information, - eventId: default, - new List>() - { - new KeyValuePair("Key1", "Value1"), - }, - exception: null, - formatter: (state, ex) => "Example formatted message."); + Assert.Equal("Value1", GetField(fluentdData, "Key1")); + Assert.Equal("Value2", GetField(fluentdData, "Key2")); - // VALIDATE - Assert.Single(logRecordList); - m_buffer = typeof(GenevaLogExporter).GetField("m_buffer", BindingFlags.NonPublic | BindingFlags.Static).GetValue(exporter) as ThreadLocal; - _ = exporter.SerializeLogRecord(logRecordList[0]); - fluentdData = MessagePack.MessagePackSerializer.Deserialize(m_buffer.Value, MessagePack.Resolvers.ContractlessStandardResolver.Instance); - Assert.Equal("Value1", GetField(fluentdData, "Key1")); + // ARRANGE + logRecordList.Clear(); + + // ACT + // This is treated as Un-structured logging as the state cannot be converted to IReadOnlyList> + logger.Log( + LogLevel.Information, + default, + state: "somestringasdata", + exception: null, + formatter: (state, ex) => "Formatted Message"); + + // VALIDATE + Assert.Single(logRecordList); + m_buffer = typeof(GenevaLogExporter).GetField("m_buffer", BindingFlags.NonPublic | BindingFlags.Static).GetValue(exporter) as ThreadLocal; + _ = exporter.SerializeLogRecord(logRecordList[0]); + fluentdData = MessagePack.MessagePackSerializer.Deserialize(m_buffer.Value, MessagePack.Resolvers.ContractlessStandardResolver.Instance); + body = GetField(fluentdData, "body"); + if (includeFormattedMessage) + { + Assert.Equal("Formatted Message", body); + } + else + { + Assert.Null(body); + } - body = GetField(fluentdData, "body"); + // ARRANGE + logRecordList.Clear(); + + // ACT + // This is treated as Un-structured logging as the state cannot be converted to IReadOnlyList> + logger.Log( + LogLevel.Information, + default, + state: "somestringasdata", + exception: null, + formatter: null); + + // VALIDATE + Assert.Single(logRecordList); + m_buffer = typeof(GenevaLogExporter).GetField("m_buffer", BindingFlags.NonPublic | BindingFlags.Static).GetValue(exporter) as ThreadLocal; + _ = exporter.SerializeLogRecord(logRecordList[0]); + fluentdData = MessagePack.MessagePackSerializer.Deserialize(m_buffer.Value, MessagePack.Resolvers.ContractlessStandardResolver.Instance); + body = GetField(fluentdData, "body"); + + // Formatter is null, hence body is always null + Assert.Null(body); - // Only populate body if FormattedMessage is enabled - if (includeFormattedMessage) - { - Assert.Equal("Example formatted message.", body); - } - else + // ARRANGE + logRecordList.Clear(); + + // ACT + // This is treated as Structured logging as the state can be converted to IReadOnlyList> + logger.Log( + logLevel: LogLevel.Information, + eventId: default, + new List>() { - Assert.Null(body); - } + new KeyValuePair("Key1", "Value1"), + }, + exception: null, + formatter: (state, ex) => "Example formatted message."); + + // VALIDATE + Assert.Single(logRecordList); + m_buffer = typeof(GenevaLogExporter).GetField("m_buffer", BindingFlags.NonPublic | BindingFlags.Static).GetValue(exporter) as ThreadLocal; + _ = exporter.SerializeLogRecord(logRecordList[0]); + fluentdData = MessagePack.MessagePackSerializer.Deserialize(m_buffer.Value, MessagePack.Resolvers.ContractlessStandardResolver.Instance); + Assert.Equal("Value1", GetField(fluentdData, "Key1")); + + body = GetField(fluentdData, "body"); + + // Only populate body if FormattedMessage is enabled + if (includeFormattedMessage) + { + Assert.Equal("Example formatted message.", body); } - finally + else { - server?.Dispose(); - try - { - File.Delete(path); - } - catch - { - } + Assert.Null(body); } } - - [Theory] - [InlineData(false, false, false)] - [InlineData(false, true, false)] - [InlineData(true, false, false)] - [InlineData(true, true, false)] - [InlineData(false, false, true)] - [InlineData(false, true, true)] - [InlineData(true, false, true)] - [InlineData(true, true, true)] - public void SerializationTestWithILoggerLogWithTemplates(bool hasTableNameMapping, bool hasCustomFields, bool parseStateValues) + finally { - string path = string.Empty; - Socket server = null; - var logRecordList = new List(); + server?.Dispose(); try { - var exporterOptions = new GenevaExporterOptions - { - PrepopulatedFields = new Dictionary - { - ["cloud.role"] = "BusyWorker", - ["cloud.roleInstance"] = "CY1SCH030021417", - ["cloud.roleVer"] = "9.0.15289.2", - }, - }; + File.Delete(path); + } + catch + { + } + } + } - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - exporterOptions.ConnectionString = "EtwSession=OpenTelemetry"; - } - else + [Theory] + [InlineData(false, false, false)] + [InlineData(false, true, false)] + [InlineData(true, false, false)] + [InlineData(true, true, false)] + [InlineData(false, false, true)] + [InlineData(false, true, true)] + [InlineData(true, false, true)] + [InlineData(true, true, true)] + public void SerializationTestWithILoggerLogWithTemplates(bool hasTableNameMapping, bool hasCustomFields, bool parseStateValues) + { + string path = string.Empty; + Socket server = null; + var logRecordList = new List(); + try + { + var exporterOptions = new GenevaExporterOptions + { + PrepopulatedFields = new Dictionary { - path = GenerateTempFilePath(); - exporterOptions.ConnectionString = "Endpoint=unix:" + path; - var endpoint = new UnixDomainSocketEndPoint(path); - server = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); - server.Bind(endpoint); - server.Listen(1); - } + ["cloud.role"] = "BusyWorker", + ["cloud.roleInstance"] = "CY1SCH030021417", + ["cloud.roleVer"] = "9.0.15289.2", + }, + }; - if (hasTableNameMapping) - { - exporterOptions.TableNameMappings = new Dictionary - { - { typeof(GenevaLogExporterTests).FullName, "CustomLogRecord" }, - { "*", "DefaultLogRecord" }, - }; - } + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + exporterOptions.ConnectionString = "EtwSession=OpenTelemetry"; + } + else + { + path = GenerateTempFilePath(); + exporterOptions.ConnectionString = "Endpoint=unix:" + path; + var endpoint = new UnixDomainSocketEndPoint(path); + server = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); + server.Bind(endpoint); + server.Listen(1); + } - if (hasCustomFields) + if (hasTableNameMapping) + { + exporterOptions.TableNameMappings = new Dictionary { - // The field "customField" of LogRecord.State should be present in the mapping as a separate key. Other fields of LogRecord.State which are not present - // in CustomFields should be added in the mapping under "env_properties" - exporterOptions.CustomFields = new string[] { "customField" }; - } + { typeof(GenevaLogExporterTests).FullName, "CustomLogRecord" }, + { "*", "DefaultLogRecord" }, + }; + } - using var loggerFactory = LoggerFactory.Create(builder => builder + if (hasCustomFields) + { + // The field "customField" of LogRecord.State should be present in the mapping as a separate key. Other fields of LogRecord.State which are not present + // in CustomFields should be added in the mapping under "env_properties" + exporterOptions.CustomFields = new string[] { "customField" }; + } + + using var loggerFactory = LoggerFactory.Create(builder => builder .AddOpenTelemetry(options => { options.AddGenevaLogExporter(options => @@ -707,90 +706,90 @@ public void SerializationTestWithILoggerLogWithTemplates(bool hasTableNameMappin }) .AddFilter(typeof(GenevaLogExporterTests).FullName, LogLevel.Trace)); // Enable all LogLevels - // Create a test exporter to get MessagePack byte data to validate if the data was serialized correctly. - using var exporter = new GenevaLogExporter(exporterOptions); + // Create a test exporter to get MessagePack byte data to validate if the data was serialized correctly. + using var exporter = new GenevaLogExporter(exporterOptions); - // Emit a LogRecord and grab a copy of the LogRecord from the collection passed to InMemoryExporter - var logger = loggerFactory.CreateLogger(); + // Emit a LogRecord and grab a copy of the LogRecord from the collection passed to InMemoryExporter + var logger = loggerFactory.CreateLogger(); - // Set the ActivitySourceName to the unique value of the test method name to avoid interference with - // the ActivitySource used by other unit tests. - var sourceName = GetTestMethodName(); + // Set the ActivitySourceName to the unique value of the test method name to avoid interference with + // the ActivitySource used by other unit tests. + var sourceName = GetTestMethodName(); - using var listener = new ActivityListener(); - listener.ShouldListenTo = (activitySource) => activitySource.Name == sourceName; - listener.Sample = (ref ActivityCreationOptions options) => ActivitySamplingResult.AllDataAndRecorded; - ActivitySource.AddActivityListener(listener); + using var listener = new ActivityListener(); + listener.ShouldListenTo = (activitySource) => activitySource.Name == sourceName; + listener.Sample = (ref ActivityCreationOptions options) => ActivitySamplingResult.AllDataAndRecorded; + ActivitySource.AddActivityListener(listener); - using var source = new ActivitySource(sourceName); + using var source = new ActivitySource(sourceName); - using (var activity = source.StartActivity("Activity")) - { - // Log inside an activity to set LogRecord.TraceId and LogRecord.SpanId - logger.LogInformation("Hello from {food} {price}.", "artichoke", 3.99); // structured logging - } + using (var activity = source.StartActivity("Activity")) + { + // Log inside an activity to set LogRecord.TraceId and LogRecord.SpanId + logger.LogInformation("Hello from {food} {price}.", "artichoke", 3.99); // structured logging + } - // When the exporter options are configured with TableMappings only "customField" will be logged as a separate key in the mapping - // "property" will be logged under "env_properties" in the mapping - logger.Log(LogLevel.Trace, 101, "Log a {customField} and {property}", "CustomFieldValue", "PropertyValue"); - logger.Log(LogLevel.Trace, 101, "Log a {customField} and {property}", "CustomFieldValue", null); - logger.Log(LogLevel.Trace, 101, "Log a {customField} and {property}", null, "PropertyValue"); - logger.Log(LogLevel.Debug, 101, "Log a {customField} and {property}", "CustomFieldValue", "PropertyValue"); - logger.Log(LogLevel.Information, 101, "Log a {customField} and {property}", "CustomFieldValue", "PropertyValue"); - logger.Log(LogLevel.Warning, 101, "Log a {customField} and {property}", "CustomFieldValue", "PropertyValue"); - logger.Log(LogLevel.Error, 101, "Log a {customField} and {property}", "CustomFieldValue", "PropertyValue"); - logger.Log(LogLevel.Critical, 101, "Log a {customField} and {property}", "CustomFieldValue", "PropertyValue"); - logger.LogInformation("Hello World!"); // unstructured logging - logger.LogError(new InvalidOperationException("Oops! Food is spoiled!"), "Hello from {food} {price}.", "artichoke", 3.99); - - // Exception with a non-ASCII character in its type name - logger.LogError(new CustomException\u0418(), "Hello from {food} {price}.", "artichoke", 3.99); - - var loggerWithDefaultCategory = loggerFactory.CreateLogger("DefaultCategory"); - loggerWithDefaultCategory.LogInformation("Basic test"); - loggerWithDefaultCategory.LogInformation("\u0418"); // Include non-ASCII characters in the message - - // logRecordList should have 14 logRecord entries as there were 14 Log calls - Assert.Equal(14, logRecordList.Count); + // When the exporter options are configured with TableMappings only "customField" will be logged as a separate key in the mapping + // "property" will be logged under "env_properties" in the mapping + logger.Log(LogLevel.Trace, 101, "Log a {customField} and {property}", "CustomFieldValue", "PropertyValue"); + logger.Log(LogLevel.Trace, 101, "Log a {customField} and {property}", "CustomFieldValue", null); + logger.Log(LogLevel.Trace, 101, "Log a {customField} and {property}", null, "PropertyValue"); + logger.Log(LogLevel.Debug, 101, "Log a {customField} and {property}", "CustomFieldValue", "PropertyValue"); + logger.Log(LogLevel.Information, 101, "Log a {customField} and {property}", "CustomFieldValue", "PropertyValue"); + logger.Log(LogLevel.Warning, 101, "Log a {customField} and {property}", "CustomFieldValue", "PropertyValue"); + logger.Log(LogLevel.Error, 101, "Log a {customField} and {property}", "CustomFieldValue", "PropertyValue"); + logger.Log(LogLevel.Critical, 101, "Log a {customField} and {property}", "CustomFieldValue", "PropertyValue"); + logger.LogInformation("Hello World!"); // unstructured logging + logger.LogError(new InvalidOperationException("Oops! Food is spoiled!"), "Hello from {food} {price}.", "artichoke", 3.99); - var m_buffer = typeof(GenevaLogExporter).GetField("m_buffer", BindingFlags.NonPublic | BindingFlags.Static).GetValue(exporter) as ThreadLocal; + // Exception with a non-ASCII character in its type name + logger.LogError(new CustomException\u0418(), "Hello from {food} {price}.", "artichoke", 3.99); - foreach (var logRecord in logRecordList) - { - _ = exporter.SerializeLogRecord(logRecord); - object fluentdData = MessagePack.MessagePackSerializer.Deserialize(m_buffer.Value, MessagePack.Resolvers.ContractlessStandardResolver.Instance); - this.AssertFluentdForwardModeForLogRecord(exporterOptions, fluentdData, logRecord); - } + var loggerWithDefaultCategory = loggerFactory.CreateLogger("DefaultCategory"); + loggerWithDefaultCategory.LogInformation("Basic test"); + loggerWithDefaultCategory.LogInformation("\u0418"); // Include non-ASCII characters in the message + + // logRecordList should have 14 logRecord entries as there were 14 Log calls + Assert.Equal(14, logRecordList.Count); + + var m_buffer = typeof(GenevaLogExporter).GetField("m_buffer", BindingFlags.NonPublic | BindingFlags.Static).GetValue(exporter) as ThreadLocal; + + foreach (var logRecord in logRecordList) + { + _ = exporter.SerializeLogRecord(logRecord); + object fluentdData = MessagePack.MessagePackSerializer.Deserialize(m_buffer.Value, MessagePack.Resolvers.ContractlessStandardResolver.Instance); + this.AssertFluentdForwardModeForLogRecord(exporterOptions, fluentdData, logRecord); } - finally + } + finally + { + server?.Dispose(); + try + { + File.Delete(path); + } + catch { - server?.Dispose(); - try - { - File.Delete(path); - } - catch - { - } } } + } - [Fact] - public void SuccessfulExport_Windows() + [Fact] + public void SuccessfulExport_Windows() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + var exporterOptions = new GenevaExporterOptions() { - var exporterOptions = new GenevaExporterOptions() + PrepopulatedFields = new Dictionary { - PrepopulatedFields = new Dictionary - { - ["cloud.role"] = "BusyWorker", - ["cloud.roleInstance"] = "CY1SCH030021417", - ["cloud.roleVer"] = "9.0.15289.2", - }, - }; + ["cloud.role"] = "BusyWorker", + ["cloud.roleInstance"] = "CY1SCH030021417", + ["cloud.roleVer"] = "9.0.15289.2", + }, + }; - using var loggerFactory = LoggerFactory.Create(builder => builder + using var loggerFactory = LoggerFactory.Create(builder => builder .AddOpenTelemetry(options => { options.AddGenevaLogExporter(options => @@ -805,27 +804,27 @@ public void SuccessfulExport_Windows() }); })); - var logger = loggerFactory.CreateLogger(); + var logger = loggerFactory.CreateLogger(); - logger.LogInformation("Hello from {food} {price}.", "artichoke", 3.99); - } + logger.LogInformation("Hello from {food} {price}.", "artichoke", 3.99); } + } - [Fact] - public void SuccessfulExportOnLinux() + [Fact] + public void SuccessfulExportOnLinux() + { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + string path = GenerateTempFilePath(); + var logRecordList = new List(); + try { - string path = GenerateTempFilePath(); - var logRecordList = new List(); - try - { - var endpoint = new UnixDomainSocketEndPoint(path); - using var server = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); - server.Bind(endpoint); - server.Listen(1); + var endpoint = new UnixDomainSocketEndPoint(path); + using var server = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); + server.Bind(endpoint); + server.Listen(1); - using var loggerFactory = LoggerFactory.Create(builder => builder + using var loggerFactory = LoggerFactory.Create(builder => builder .AddOpenTelemetry(options => { options.AddGenevaLogExporter(options => @@ -840,257 +839,256 @@ public void SuccessfulExportOnLinux() }); options.AddInMemoryExporter(logRecordList); })); - using var serverSocket = server.Accept(); - serverSocket.ReceiveTimeout = 10000; + using var serverSocket = server.Accept(); + serverSocket.ReceiveTimeout = 10000; - // Create a test exporter to get MessagePack byte data for validation of the data received via Socket. - using var exporter = new GenevaLogExporter(new GenevaExporterOptions + // Create a test exporter to get MessagePack byte data for validation of the data received via Socket. + using var exporter = new GenevaLogExporter(new GenevaExporterOptions + { + ConnectionString = "Endpoint=unix:" + path, + PrepopulatedFields = new Dictionary { - ConnectionString = "Endpoint=unix:" + path, - PrepopulatedFields = new Dictionary - { - ["cloud.role"] = "BusyWorker", - ["cloud.roleInstance"] = "CY1SCH030021417", - ["cloud.roleVer"] = "9.0.15289.2", - }, - }); + ["cloud.role"] = "BusyWorker", + ["cloud.roleInstance"] = "CY1SCH030021417", + ["cloud.roleVer"] = "9.0.15289.2", + }, + }); - // Emit a LogRecord and grab a copy of internal buffer for validation. - var logger = loggerFactory.CreateLogger(); + // Emit a LogRecord and grab a copy of internal buffer for validation. + var logger = loggerFactory.CreateLogger(); - logger.LogInformation("Hello from {food} {price}.", "artichoke", 3.99); + logger.LogInformation("Hello from {food} {price}.", "artichoke", 3.99); - // logRecordList should have a singleLogRecord entry after the logger.LogInformation call - Assert.Single(logRecordList); + // logRecordList should have a singleLogRecord entry after the logger.LogInformation call + Assert.Single(logRecordList); - int messagePackDataSize; - messagePackDataSize = exporter.SerializeLogRecord(logRecordList[0]); + int messagePackDataSize; + messagePackDataSize = exporter.SerializeLogRecord(logRecordList[0]); - // Read the data sent via socket. - var receivedData = new byte[1024]; - int receivedDataSize = serverSocket.Receive(receivedData); + // Read the data sent via socket. + var receivedData = new byte[1024]; + int receivedDataSize = serverSocket.Receive(receivedData); - // Validation - Assert.Equal(messagePackDataSize, receivedDataSize); + // Validation + Assert.Equal(messagePackDataSize, receivedDataSize); - logRecordList.Clear(); + logRecordList.Clear(); - // Emit log on a different thread to test for multithreading scenarios - var thread = new Thread(() => - { - logger.LogInformation("Hello from another thread {food} {price}.", "artichoke", 3.99); - }); - thread.Start(); - thread.Join(); + // Emit log on a different thread to test for multithreading scenarios + var thread = new Thread(() => + { + logger.LogInformation("Hello from another thread {food} {price}.", "artichoke", 3.99); + }); + thread.Start(); + thread.Join(); - // logRecordList should have a singleLogRecord entry after the logger.LogInformation call - Assert.Single(logRecordList); + // logRecordList should have a singleLogRecord entry after the logger.LogInformation call + Assert.Single(logRecordList); - messagePackDataSize = exporter.SerializeLogRecord(logRecordList[0]); - receivedDataSize = serverSocket.Receive(receivedData); - Assert.Equal(messagePackDataSize, receivedDataSize); + messagePackDataSize = exporter.SerializeLogRecord(logRecordList[0]); + receivedDataSize = serverSocket.Receive(receivedData); + Assert.Equal(messagePackDataSize, receivedDataSize); + } + finally + { + try + { + File.Delete(path); } - finally + catch { - try - { - File.Delete(path); - } - catch - { - } } } } + } - private static string GenerateTempFilePath() + private static string GenerateTempFilePath() + { + while (true) { - while (true) + string path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + if (!File.Exists(path)) { - string path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); - if (!File.Exists(path)) - { - return path; - } + return path; } } + } - private static string GetTestMethodName([CallerMemberName] string callingMethodName = "") - { - return callingMethodName; - } + private static string GetTestMethodName([CallerMemberName] string callingMethodName = "") + { + return callingMethodName; + } - private static object GetField(object fluentdData, string key) - { - /* Fluentd Forward Mode: + private static object GetField(object fluentdData, string key) + { + /* Fluentd Forward Mode: + [ + "Log", [ - "Log", - [ - [ , { "env_ver": "4.0", ... } ] - ], - { "TimeFormat": "DateTime" } - ] - */ + [ , { "env_ver": "4.0", ... } ] + ], + { "TimeFormat": "DateTime" } + ] + */ - var TimeStampAndMappings = ((fluentdData as object[])[1] as object[])[0]; - var mapping = (TimeStampAndMappings as object[])[1] as Dictionary; + var TimeStampAndMappings = ((fluentdData as object[])[1] as object[])[0]; + var mapping = (TimeStampAndMappings as object[])[1] as Dictionary; + + if (mapping.ContainsKey(key)) + { + return mapping[key]; + } + else + { + return null; + } + } - if (mapping.ContainsKey(key)) + private void AssertFluentdForwardModeForLogRecord(GenevaExporterOptions exporterOptions, object fluentdData, LogRecord logRecord) + { + /* Fluentd Forward Mode: + [ + "Log", + [ + [ , { "env_ver": "4.0", ... } ] + ], + { "TimeFormat": "DateTime" } + ] + */ + + var signal = (fluentdData as object[])[0] as string; + var TimeStampAndMappings = ((fluentdData as object[])[1] as object[])[0]; + var timeStamp = (DateTime)(TimeStampAndMappings as object[])[0]; + var mapping = (TimeStampAndMappings as object[])[1] as Dictionary; + var timeFormat = (fluentdData as object[])[2] as Dictionary; + + var partAName = "Log"; + if (exporterOptions.TableNameMappings != null) + { + if (exporterOptions.TableNameMappings.ContainsKey(logRecord.CategoryName)) { - return mapping[key]; + partAName = exporterOptions.TableNameMappings[logRecord.CategoryName]; } - else + else if (exporterOptions.TableNameMappings.ContainsKey("*")) { - return null; + partAName = exporterOptions.TableNameMappings["*"]; } } - private void AssertFluentdForwardModeForLogRecord(GenevaExporterOptions exporterOptions, object fluentdData, LogRecord logRecord) - { - /* Fluentd Forward Mode: - [ - "Log", - [ - [ , { "env_ver": "4.0", ... } ] - ], - { "TimeFormat": "DateTime" } - ] - */ - - var signal = (fluentdData as object[])[0] as string; - var TimeStampAndMappings = ((fluentdData as object[])[1] as object[])[0]; - var timeStamp = (DateTime)(TimeStampAndMappings as object[])[0]; - var mapping = (TimeStampAndMappings as object[])[1] as Dictionary; - var timeFormat = (fluentdData as object[])[2] as Dictionary; + Assert.Equal(partAName, signal); - var partAName = "Log"; - if (exporterOptions.TableNameMappings != null) - { - if (exporterOptions.TableNameMappings.ContainsKey(logRecord.CategoryName)) - { - partAName = exporterOptions.TableNameMappings[logRecord.CategoryName]; - } - else if (exporterOptions.TableNameMappings.ContainsKey("*")) - { - partAName = exporterOptions.TableNameMappings["*"]; - } - } + // Timestamp check + Assert.Equal(logRecord.Timestamp.Ticks, timeStamp.Ticks); - Assert.Equal(partAName, signal); + // Part A core envelope fields - // Timestamp check - Assert.Equal(logRecord.Timestamp.Ticks, timeStamp.Ticks); + var nameKey = GenevaBaseExporter.V40_PART_A_MAPPING[Schema.V40.PartA.Name]; - // Part A core envelope fields + // Check if the user has configured a custom table mapping + Assert.Equal(partAName, mapping[nameKey]); - var nameKey = GenevaBaseExporter.V40_PART_A_MAPPING[Schema.V40.PartA.Name]; + // TODO: Update this when we support multiple Schema formats + var partAVer = "4.0"; + var verKey = GenevaBaseExporter.V40_PART_A_MAPPING[Schema.V40.PartA.Ver]; + Assert.Equal(partAVer, mapping[verKey]); - // Check if the user has configured a custom table mapping - Assert.Equal(partAName, mapping[nameKey]); + foreach (var item in exporterOptions.PrepopulatedFields) + { + var partAValue = item.Value as string; + var partAKey = GenevaBaseExporter.V40_PART_A_MAPPING[item.Key]; + Assert.Equal(partAValue, mapping[partAKey]); + } - // TODO: Update this when we support multiple Schema formats - var partAVer = "4.0"; - var verKey = GenevaBaseExporter.V40_PART_A_MAPPING[Schema.V40.PartA.Ver]; - Assert.Equal(partAVer, mapping[verKey]); + var timeKey = GenevaBaseExporter.V40_PART_A_MAPPING[Schema.V40.PartA.Time]; + Assert.Equal(logRecord.Timestamp.Ticks, ((DateTime)mapping[timeKey]).Ticks); - foreach (var item in exporterOptions.PrepopulatedFields) - { - var partAValue = item.Value as string; - var partAKey = GenevaBaseExporter.V40_PART_A_MAPPING[item.Key]; - Assert.Equal(partAValue, mapping[partAKey]); - } + // Part A dt extensions - var timeKey = GenevaBaseExporter.V40_PART_A_MAPPING[Schema.V40.PartA.Time]; - Assert.Equal(logRecord.Timestamp.Ticks, ((DateTime)mapping[timeKey]).Ticks); + if (logRecord.TraceId != default) + { + Assert.Equal(logRecord.TraceId.ToHexString(), mapping["env_dt_traceId"]); + } - // Part A dt extensions + if (logRecord.SpanId != default) + { + Assert.Equal(logRecord.SpanId.ToHexString(), mapping["env_dt_spanId"]); + } - if (logRecord.TraceId != default) - { - Assert.Equal(logRecord.TraceId.ToHexString(), mapping["env_dt_traceId"]); - } + if (logRecord.Exception != null) + { + Assert.Equal(logRecord.Exception.GetType().FullName, mapping["env_ex_type"]); + Assert.Equal(logRecord.Exception.Message, mapping["env_ex_msg"]); + } - if (logRecord.SpanId != default) - { - Assert.Equal(logRecord.SpanId.ToHexString(), mapping["env_dt_spanId"]); - } + // Part B fields + Assert.Equal(logRecord.LogLevel.ToString(), mapping["severityText"]); + Assert.Equal((byte)(((int)logRecord.LogLevel * 4) + 1), mapping["severityNumber"]); - if (logRecord.Exception != null) - { - Assert.Equal(logRecord.Exception.GetType().FullName, mapping["env_ex_type"]); - Assert.Equal(logRecord.Exception.Message, mapping["env_ex_msg"]); - } + Assert.Equal(logRecord.CategoryName, mapping["name"]); - // Part B fields - Assert.Equal(logRecord.LogLevel.ToString(), mapping["severityText"]); - Assert.Equal((byte)(((int)logRecord.LogLevel * 4) + 1), mapping["severityNumber"]); + bool isUnstructuredLog = true; + IReadOnlyList> stateKeyValuePairList; + if (logRecord.State == null) + { + stateKeyValuePairList = logRecord.StateValues; + } + else + { + stateKeyValuePairList = logRecord.State as IReadOnlyList>; + } - Assert.Equal(logRecord.CategoryName, mapping["name"]); + if (stateKeyValuePairList != null) + { + isUnstructuredLog = stateKeyValuePairList.Count == 1; + } - bool isUnstructuredLog = true; - IReadOnlyList> stateKeyValuePairList; - if (logRecord.State == null) + if (isUnstructuredLog) + { + if (logRecord.State != null) { - stateKeyValuePairList = logRecord.StateValues; + Assert.Equal(logRecord.State.ToString(), mapping["body"]); } else { - stateKeyValuePairList = logRecord.State as IReadOnlyList>; - } - - if (stateKeyValuePairList != null) - { - isUnstructuredLog = stateKeyValuePairList.Count == 1; + Assert.Equal(stateKeyValuePairList[0].Value, mapping["body"]); } + } + else + { + _ = mapping.TryGetValue("env_properties", out object envProprties); + var envPropertiesMapping = envProprties as IDictionary; - if (isUnstructuredLog) + foreach (var item in stateKeyValuePairList) { - if (logRecord.State != null) + if (item.Key == "{OriginalFormat}") { - Assert.Equal(logRecord.State.ToString(), mapping["body"]); + Assert.Equal(item.Value.ToString(), mapping["body"]); } - else - { - Assert.Equal(stateKeyValuePairList[0].Value, mapping["body"]); - } - } - else - { - _ = mapping.TryGetValue("env_properties", out object envProprties); - var envPropertiesMapping = envProprties as IDictionary; - - foreach (var item in stateKeyValuePairList) + else if (exporterOptions.CustomFields == null || exporterOptions.CustomFields.Contains(item.Key)) { - if (item.Key == "{OriginalFormat}") - { - Assert.Equal(item.Value.ToString(), mapping["body"]); - } - else if (exporterOptions.CustomFields == null || exporterOptions.CustomFields.Contains(item.Key)) - { - if (item.Value != null) - { - Assert.Equal(item.Value, mapping[item.Key]); - } - } - else + if (item.Value != null) { - Assert.Equal(item.Value, envPropertiesMapping[item.Key]); + Assert.Equal(item.Value, mapping[item.Key]); } } + else + { + Assert.Equal(item.Value, envPropertiesMapping[item.Key]); + } } - - if (logRecord.EventId != default) - { - Assert.Equal(logRecord.EventId.Id, int.Parse(mapping["eventId"].ToString())); - } - - // Epilouge - Assert.Equal("DateTime", timeFormat["TimeFormat"]); } - // A custom exception class with non-ASCII character in the type name - private class CustomException\u0418 : Exception + if (logRecord.EventId != default) { + Assert.Equal(logRecord.EventId.Id, int.Parse(mapping["eventId"].ToString())); } + + // Epilouge + Assert.Equal("DateTime", timeFormat["TimeFormat"]); + } + + // A custom exception class with non-ASCII character in the type name + private class CustomException\u0418 : Exception + { } } diff --git a/test/OpenTelemetry.Exporter.Geneva.Tests/GenevaMetricExporterOptionsTests.cs b/test/OpenTelemetry.Exporter.Geneva.Tests/GenevaMetricExporterOptionsTests.cs index 9b0fb22a50..737e27bc1d 100644 --- a/test/OpenTelemetry.Exporter.Geneva.Tests/GenevaMetricExporterOptionsTests.cs +++ b/test/OpenTelemetry.Exporter.Geneva.Tests/GenevaMetricExporterOptionsTests.cs @@ -18,78 +18,77 @@ using System.Collections.Generic; using Xunit; -namespace OpenTelemetry.Exporter.Geneva.Tests +namespace OpenTelemetry.Exporter.Geneva.Tests; + +public class GenevaMetricExporterOptionsTests { - public class GenevaMetricExporterOptionsTests + [Fact] + public void InvalidPrepopulatedDimensions() { - [Fact] - public void InvalidPrepopulatedDimensions() + var exception = Assert.Throws(() => { - var exception = Assert.Throws(() => - { - var exporterOptions = new GenevaMetricExporterOptions { PrepopulatedMetricDimensions = null }; - }); + var exporterOptions = new GenevaMetricExporterOptions { PrepopulatedMetricDimensions = null }; + }); - Assert.Throws(() => + Assert.Throws(() => + { + var exporterOptions = new GenevaMetricExporterOptions { - var exporterOptions = new GenevaMetricExporterOptions + PrepopulatedMetricDimensions = new Dictionary { - PrepopulatedMetricDimensions = new Dictionary - { - ["DimensionKey"] = null, - }, - }; - }); + ["DimensionKey"] = null, + }, + }; + }); - var invalidDimensionNameException = Assert.Throws(() => + var invalidDimensionNameException = Assert.Throws(() => + { + var exporterOptions = new GenevaMetricExporterOptions { - var exporterOptions = new GenevaMetricExporterOptions + PrepopulatedMetricDimensions = new Dictionary { - PrepopulatedMetricDimensions = new Dictionary - { - [new string('a', GenevaMetricExporter.MaxDimensionNameSize + 1)] = "DimensionValue", - }, - }; - }); + [new string('a', GenevaMetricExporter.MaxDimensionNameSize + 1)] = "DimensionValue", + }, + }; + }); - var expectedErrorMessage = $"The dimension: {new string('a', GenevaMetricExporter.MaxDimensionNameSize + 1)} exceeds the maximum allowed limit of {GenevaMetricExporter.MaxDimensionNameSize} characters for a dimension name."; - Assert.Equal(expectedErrorMessage, invalidDimensionNameException.Message); + var expectedErrorMessage = $"The dimension: {new string('a', GenevaMetricExporter.MaxDimensionNameSize + 1)} exceeds the maximum allowed limit of {GenevaMetricExporter.MaxDimensionNameSize} characters for a dimension name."; + Assert.Equal(expectedErrorMessage, invalidDimensionNameException.Message); - var invalidDimensionValueException = Assert.Throws(() => + var invalidDimensionValueException = Assert.Throws(() => + { + var exporterOptions = new GenevaMetricExporterOptions { - var exporterOptions = new GenevaMetricExporterOptions + PrepopulatedMetricDimensions = new Dictionary { - PrepopulatedMetricDimensions = new Dictionary - { - ["DimensionKey"] = new string('a', GenevaMetricExporter.MaxDimensionValueSize + 1), - }, - }; - }); + ["DimensionKey"] = new string('a', GenevaMetricExporter.MaxDimensionValueSize + 1), + }, + }; + }); - expectedErrorMessage = $"Value provided for the dimension: DimensionKey exceeds the maximum allowed limit of {GenevaMetricExporter.MaxDimensionValueSize} characters for dimension value."; - Assert.Equal(expectedErrorMessage, invalidDimensionValueException.Message); - } + expectedErrorMessage = $"Value provided for the dimension: DimensionKey exceeds the maximum allowed limit of {GenevaMetricExporter.MaxDimensionValueSize} characters for dimension value."; + Assert.Equal(expectedErrorMessage, invalidDimensionValueException.Message); + } - [Fact] - public void MetricExportIntervalValidationTest() + [Fact] + public void MetricExportIntervalValidationTest() + { + Assert.Throws(() => { - Assert.Throws(() => + var exporterOptions = new GenevaMetricExporterOptions { - var exporterOptions = new GenevaMetricExporterOptions - { - MetricExportIntervalMilliseconds = 999, - }; - }); + MetricExportIntervalMilliseconds = 999, + }; + }); - var exception = Record.Exception(() => + var exception = Record.Exception(() => + { + var exporterOptions = new GenevaMetricExporterOptions { - var exporterOptions = new GenevaMetricExporterOptions - { - MetricExportIntervalMilliseconds = 1000, - }; - }); + MetricExportIntervalMilliseconds = 1000, + }; + }); - Assert.Null(exception); - } + Assert.Null(exception); } } diff --git a/test/OpenTelemetry.Exporter.Geneva.Tests/GenevaMetricExporterTests.cs b/test/OpenTelemetry.Exporter.Geneva.Tests/GenevaMetricExporterTests.cs index 746b413c00..1ace1bbd8b 100644 --- a/test/OpenTelemetry.Exporter.Geneva.Tests/GenevaMetricExporterTests.cs +++ b/test/OpenTelemetry.Exporter.Geneva.Tests/GenevaMetricExporterTests.cs @@ -26,584 +26,500 @@ using System.Threading.Tasks; using Kaitai; using OpenTelemetry.Metrics; -using OpenTelemetry.Trace; using Xunit; using static OpenTelemetry.Exporter.Geneva.Tests.MetricsContract; -namespace OpenTelemetry.Exporter.Geneva.Tests +namespace OpenTelemetry.Exporter.Geneva.Tests; + +public class GenevaMetricExporterTests { - public class GenevaMetricExporterTests + [Fact] + public void NullExporterOptions() { - [Fact] - public void NullExporterOptions() + GenevaMetricExporterOptions exporterOptions = null; + Assert.Throws(() => new GenevaMetricExporter(exporterOptions)); + } + + [Theory] + [InlineData(null)] + [InlineData("")] + [InlineData(" ")] + public void InvalidConnectionString(string connectionString) + { + var exporterOptions = new GenevaMetricExporterOptions() { ConnectionString = connectionString }; + var exception = Assert.Throws(() => { - GenevaMetricExporterOptions exporterOptions = null; - Assert.Throws(() => new GenevaMetricExporter(exporterOptions)); - } + using var exporter = new GenevaMetricExporter(exporterOptions); + }); + } - [Theory] - [InlineData(null)] - [InlineData("")] - [InlineData(" ")] - public void InvalidConnectionString(string connectionString) + [Fact] + public void ParseConnectionStringCorrectly() + { + string path = string.Empty; + Socket server = null; + try { - var exporterOptions = new GenevaMetricExporterOptions() { ConnectionString = connectionString }; - var exception = Assert.Throws(() => + var exporterOptions = new GenevaMetricExporterOptions(); + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - using var exporter = new GenevaMetricExporter(exporterOptions); - }); - } + exporterOptions.ConnectionString = "Account=OTelMonitoringAccount;Namespace=OTelMetricNamespace"; + } + else + { + path = GenerateTempFilePath(); + exporterOptions.ConnectionString = $"Endpoint=unix:{path};Account=OTelMonitoringAccount;Namespace=OTelMetricNamespace"; + var endpoint = new UnixDomainSocketEndPoint(path); + server = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); + server.Bind(endpoint); + server.Listen(1); + } - [Fact] - public void ParseConnectionStringCorrectly() + using var exporter = new GenevaMetricExporter(exporterOptions); + var monitoringAccount = typeof(GenevaMetricExporter).GetField("monitoringAccount", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(exporter) as string; + var metricNamespace = typeof(GenevaMetricExporter).GetField("metricNamespace", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(exporter) as string; + Assert.Equal("OTelMonitoringAccount", monitoringAccount); + Assert.Equal("OTelMetricNamespace", metricNamespace); + } + finally { - string path = string.Empty; - Socket server = null; + server?.Dispose(); try { - var exporterOptions = new GenevaMetricExporterOptions(); - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - exporterOptions.ConnectionString = "Account=OTelMonitoringAccount;Namespace=OTelMetricNamespace"; - } - else - { - path = GenerateTempFilePath(); - exporterOptions.ConnectionString = $"Endpoint=unix:{path};Account=OTelMonitoringAccount;Namespace=OTelMetricNamespace"; - var endpoint = new UnixDomainSocketEndPoint(path); - server = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); - server.Bind(endpoint); - server.Listen(1); - } - - using var exporter = new GenevaMetricExporter(exporterOptions); - var monitoringAccount = typeof(GenevaMetricExporter).GetField("monitoringAccount", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(exporter) as string; - var metricNamespace = typeof(GenevaMetricExporter).GetField("metricNamespace", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(exporter) as string; - Assert.Equal("OTelMonitoringAccount", monitoringAccount); - Assert.Equal("OTelMetricNamespace", metricNamespace); + File.Delete(path); } - finally + catch { - server?.Dispose(); - try - { - File.Delete(path); - } - catch - { - } } } + } - [Theory] - [InlineData(false)] - [InlineData(true)] - public void SuccessfulSerialization(bool testMaxLimits) + [Theory] + [InlineData(false)] + [InlineData(true)] + public void SuccessfulSerialization(bool testMaxLimits) + { + using var meter = new Meter("SuccessfulSerialization", "0.0.1"); + var longCounter = meter.CreateCounter("longCounter"); + var doubleCounter = meter.CreateCounter("doubleCounter"); + var histogram = meter.CreateHistogram("histogram"); + var exportedItems = new List(); + using var inMemoryReader = new BaseExportingMetricReader(new InMemoryExporter(exportedItems)) { - using var meter = new Meter("SuccessfulSerialization", "0.0.1"); - var longCounter = meter.CreateCounter("longCounter"); - var doubleCounter = meter.CreateCounter("doubleCounter"); - var histogram = meter.CreateHistogram("histogram"); - var exportedItems = new List(); - using var inMemoryReader = new BaseExportingMetricReader(new InMemoryExporter(exportedItems)) - { - TemporalityPreference = MetricReaderTemporalityPreference.Delta, - }; + TemporalityPreference = MetricReaderTemporalityPreference.Delta, + }; - using var meterProvider = Sdk.CreateMeterProviderBuilder() - .AddMeter("SuccessfulSerialization") - .AddReader(inMemoryReader) - .Build(); + using var meterProvider = Sdk.CreateMeterProviderBuilder() + .AddMeter("SuccessfulSerialization") + .AddReader(inMemoryReader) + .Build(); - long longValue = 123; - double doubleValue = 123.45; + long longValue = 123; + double doubleValue = 123.45; - if (testMaxLimits) - { - longValue = long.MaxValue; - doubleValue = double.MaxValue; - } + if (testMaxLimits) + { + longValue = long.MaxValue; + doubleValue = double.MaxValue; + } - longCounter.Add( - longValue, new("tag1", "value1"), new("tag2", "value2")); + longCounter.Add( + longValue, new("tag1", "value1"), new("tag2", "value2")); - doubleCounter.Add( - doubleValue, new("tag1", "value1"), new("tag2", "value2")); + doubleCounter.Add( + doubleValue, new("tag1", "value1"), new("tag2", "value2")); - meter.CreateObservableCounter( - "observableLongCounter", - () => new List>() - { - new(longValue, new("tag1", "value1"), new("tag2", "value2")), - }); + meter.CreateObservableCounter( + "observableLongCounter", + () => new List>() + { + new(longValue, new("tag1", "value1"), new("tag2", "value2")), + }); - meter.CreateObservableCounter( - "observableDoubleCounter", - () => new List>() - { - new(doubleValue, new("tag1", "value1"), new("tag2", "value2")), - }); + meter.CreateObservableCounter( + "observableDoubleCounter", + () => new List>() + { + new(doubleValue, new("tag1", "value1"), new("tag2", "value2")), + }); - meter.CreateObservableGauge( - "observableLongGauge", - () => new List>() - { - new(longValue, new("tag1", "value1"), new("tag2", "value2")), - }); + meter.CreateObservableGauge( + "observableLongGauge", + () => new List>() + { + new(longValue, new("tag1", "value1"), new("tag2", "value2")), + }); - meter.CreateObservableGauge( - "observableDoubleGauge", - () => new List>() - { - new(doubleValue, new("tag1", "value1"), new("tag2", "value2")), - }); + meter.CreateObservableGauge( + "observableDoubleGauge", + () => new List>() + { + new(doubleValue, new("tag1", "value1"), new("tag2", "value2")), + }); + + if (testMaxLimits) + { + // only testing the max value allowed for sum + // max value allowed for count is uint.MaxValue. It's not feasible to test that + histogram.Record(longValue, new("tag1", "value1"), new("tag2", "value2")); + } + else + { + // Record the following values from Histogram: + // (-inf - 0] : 1 + // (0 - 5] : 0 + // (5 - 10] : 0 + // (10 - 25] : 0 + // (25 - 50] : 0 + // (50 - 75] : 0 + // (75 - 100] : 0 + // (100 - 250] : 2 + // (250 - 500] : 0 + // (500 - 1000] : 1 + // (1000 - +inf) : 1 + // + // The corresponding value-count pairs to be sent for the given distribution: + // 0: 1 + // 250: 2 + // 1000: 1 + // 1001: 1 (We use one greater than the last bound provided (1000 + 1) as the value for the overflow bucket) + + histogram.Record(-1, new("tag1", "value1"), new("tag2", "value2")); + histogram.Record(150, new("tag1", "value1"), new("tag2", "value2")); + histogram.Record(150, new("tag1", "value1"), new("tag2", "value2")); + histogram.Record(750, new("tag1", "value1"), new("tag2", "value2")); + histogram.Record(2500, new("tag1", "value1"), new("tag2", "value2")); + } - if (testMaxLimits) + string path = string.Empty; + Socket server = null; + try + { + var exporterOptions = new GenevaMetricExporterOptions(); + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - // only testing the max value allowed for sum - // max value allowed for count is uint.MaxValue. It's not feasible to test that - histogram.Record(longValue, new("tag1", "value1"), new("tag2", "value2")); + exporterOptions.ConnectionString = "Account=OTelMonitoringAccount;Namespace=OTelMetricNamespace"; } else { - // Record the following values from Histogram: - // (-inf - 0] : 1 - // (0 - 5] : 0 - // (5 - 10] : 0 - // (10 - 25] : 0 - // (25 - 50] : 0 - // (50 - 75] : 0 - // (75 - 100] : 0 - // (100 - 250] : 2 - // (250 - 500] : 0 - // (500 - 1000] : 1 - // (1000 - +inf) : 1 - // - // The corresponding value-count pairs to be sent for the given distribution: - // 0: 1 - // 250: 2 - // 1000: 1 - // 1001: 1 (We use one greater than the last bound provided (1000 + 1) as the value for the overflow bucket) - - histogram.Record(-1, new("tag1", "value1"), new("tag2", "value2")); - histogram.Record(150, new("tag1", "value1"), new("tag2", "value2")); - histogram.Record(150, new("tag1", "value1"), new("tag2", "value2")); - histogram.Record(750, new("tag1", "value1"), new("tag2", "value2")); - histogram.Record(2500, new("tag1", "value1"), new("tag2", "value2")); + path = GenerateTempFilePath(); + exporterOptions.ConnectionString = $"Endpoint=unix:{path};Account=OTelMonitoringAccount;Namespace=OTelMetricNamespace"; + var endpoint = new UnixDomainSocketEndPoint(path); + server = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); + server.Bind(endpoint); + server.Listen(1); } - string path = string.Empty; - Socket server = null; - try + exporterOptions.PrepopulatedMetricDimensions = new Dictionary { - var exporterOptions = new GenevaMetricExporterOptions(); - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - exporterOptions.ConnectionString = "Account=OTelMonitoringAccount;Namespace=OTelMetricNamespace"; - } - else - { - path = GenerateTempFilePath(); - exporterOptions.ConnectionString = $"Endpoint=unix:{path};Account=OTelMonitoringAccount;Namespace=OTelMetricNamespace"; - var endpoint = new UnixDomainSocketEndPoint(path); - server = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); - server.Bind(endpoint); - server.Listen(1); - } - - exporterOptions.PrepopulatedMetricDimensions = new Dictionary - { - ["cloud.role"] = "BusyWorker", - ["cloud.roleInstance"] = "CY1SCH030021417", - ["cloud.roleVer"] = "9.0.15289.2", - }; + ["cloud.role"] = "BusyWorker", + ["cloud.roleInstance"] = "CY1SCH030021417", + ["cloud.roleVer"] = "9.0.15289.2", + }; - using var exporter = new GenevaMetricExporter(exporterOptions); + using var exporter = new GenevaMetricExporter(exporterOptions); - inMemoryReader.Collect(); + inMemoryReader.Collect(); - Assert.Equal(7, exportedItems.Count); + Assert.Equal(7, exportedItems.Count); - // check serialization for longCounter - this.CheckSerializationForSingleMetricPoint(exportedItems[0], exporter, exporterOptions); + // check serialization for longCounter + this.CheckSerializationForSingleMetricPoint(exportedItems[0], exporter, exporterOptions); - // check serialization for doubleCounter - this.CheckSerializationForSingleMetricPoint(exportedItems[1], exporter, exporterOptions); + // check serialization for doubleCounter + this.CheckSerializationForSingleMetricPoint(exportedItems[1], exporter, exporterOptions); - // check serialization for histogram - this.CheckSerializationForSingleMetricPoint(exportedItems[2], exporter, exporterOptions); + // check serialization for histogram + this.CheckSerializationForSingleMetricPoint(exportedItems[2], exporter, exporterOptions); - // check serialization for observableLongCounter - this.CheckSerializationForSingleMetricPoint(exportedItems[3], exporter, exporterOptions); + // check serialization for observableLongCounter + this.CheckSerializationForSingleMetricPoint(exportedItems[3], exporter, exporterOptions); - // check serialization for observableDoubleCounter - this.CheckSerializationForSingleMetricPoint(exportedItems[4], exporter, exporterOptions); + // check serialization for observableDoubleCounter + this.CheckSerializationForSingleMetricPoint(exportedItems[4], exporter, exporterOptions); - // check serialization for observableLongGauge - this.CheckSerializationForSingleMetricPoint(exportedItems[5], exporter, exporterOptions); + // check serialization for observableLongGauge + this.CheckSerializationForSingleMetricPoint(exportedItems[5], exporter, exporterOptions); - // check serialization for observableDoubleGauge - this.CheckSerializationForSingleMetricPoint(exportedItems[6], exporter, exporterOptions); + // check serialization for observableDoubleGauge + this.CheckSerializationForSingleMetricPoint(exportedItems[6], exporter, exporterOptions); + } + finally + { + server?.Dispose(); + try + { + File.Delete(path); } - finally + catch { - server?.Dispose(); - try - { - File.Delete(path); - } - catch - { - } } } + } - [Fact] - public void SuccessfulSerializationWithViews() + [Fact] + public void SuccessfulSerializationWithViews() + { + using var meter = new Meter("SuccessfulSerializationWithViews", "0.0.1"); + var longCounter = meter.CreateCounter("longCounter"); + var doubleCounter = meter.CreateCounter("doubleCounter"); + var histogramWithCustomBounds = meter.CreateHistogram("histogramWithCustomBounds"); + var histogramWithNoBounds = meter.CreateHistogram("histogramWithNoBounds"); + var exportedItems = new List(); + using var inMemoryReader = new BaseExportingMetricReader(new InMemoryExporter(exportedItems)) { - using var meter = new Meter("SuccessfulSerializationWithViews", "0.0.1"); - var longCounter = meter.CreateCounter("longCounter"); - var doubleCounter = meter.CreateCounter("doubleCounter"); - var histogramWithCustomBounds = meter.CreateHistogram("histogramWithCustomBounds"); - var histogramWithNoBounds = meter.CreateHistogram("histogramWithNoBounds"); - var exportedItems = new List(); - using var inMemoryReader = new BaseExportingMetricReader(new InMemoryExporter(exportedItems)) - { - TemporalityPreference = MetricReaderTemporalityPreference.Delta, - }; - - using var meterProvider = Sdk.CreateMeterProviderBuilder() - .AddMeter("SuccessfulSerializationWithViews") - .AddView("longCounter", "renamedLongCounter") - .AddView("doubleCounter", new MetricStreamConfiguration { TagKeys = new string[] { "tag1" } }) - .AddView( - "histogramWithCustomBounds", - new ExplicitBucketHistogramConfiguration - { - Name = "renamedhistogramWithCustomBounds", - Description = "modifiedDescription", - Boundaries = new double[] { 500, 1000 }, - }) - .AddView(instrument => + TemporalityPreference = MetricReaderTemporalityPreference.Delta, + }; + + using var meterProvider = Sdk.CreateMeterProviderBuilder() + .AddMeter("SuccessfulSerializationWithViews") + .AddView("longCounter", "renamedLongCounter") + .AddView("doubleCounter", new MetricStreamConfiguration { TagKeys = new string[] { "tag1" } }) + .AddView( + "histogramWithCustomBounds", + new ExplicitBucketHistogramConfiguration { - if (instrument.Name == "histogramWithNoBounds") - { - return new ExplicitBucketHistogramConfiguration { Boundaries = new double[] { } }; - } - - return null; + Name = "renamedhistogramWithCustomBounds", + Description = "modifiedDescription", + Boundaries = new double[] { 500, 1000 }, }) - .AddView("observableLongCounter", MetricStreamConfiguration.Drop) - .AddView("observableDoubleCounter", new MetricStreamConfiguration { TagKeys = new string[] { } }) - .AddView(instrument => + .AddView(instrument => + { + if (instrument.Name == "histogramWithNoBounds") { - if (instrument.Name == "observableLongGauge") - { - return new MetricStreamConfiguration - { - Name = "renamedobservableLongGauge", - Description = "modifiedDescription", - TagKeys = new string[] { "tag1" }, - }; - } + return new ExplicitBucketHistogramConfiguration { Boundaries = new double[] { } }; + } - return null; - }) - .AddView(instrument => + return null; + }) + .AddView("observableLongCounter", MetricStreamConfiguration.Drop) + .AddView("observableDoubleCounter", new MetricStreamConfiguration { TagKeys = new string[] { } }) + .AddView(instrument => + { + if (instrument.Name == "observableLongGauge") { - if (instrument.Name == "observableDoubleGauge") + return new MetricStreamConfiguration { - return MetricStreamConfiguration.Drop; - } - - return null; - }) - .AddReader(inMemoryReader) - .Build(); - - longCounter.Add( - 123, new("tag1", "value1"), new("tag2", "value2")); - - doubleCounter.Add( - 123.45, new("tag1", "value1"), new("tag2", "value2")); + Name = "renamedobservableLongGauge", + Description = "modifiedDescription", + TagKeys = new string[] { "tag1" }, + }; + } - meter.CreateObservableCounter( - "observableLongCounter", - () => new List>() + return null; + }) + .AddView(instrument => + { + if (instrument.Name == "observableDoubleGauge") { - new(123, new("tag1", "value1"), new("tag2", "value2")), - }); + return MetricStreamConfiguration.Drop; + } - meter.CreateObservableCounter( - "observableDoubleCounter", - () => new List>() - { - new(123.45, new("tag1", "value1"), new("tag2", "value2")), - }); + return null; + }) + .AddReader(inMemoryReader) + .Build(); - meter.CreateObservableGauge( - "observableLongGauge", - () => new List>() - { - new(123, new("tag1", "value1"), new("tag2", "value2")), - }); + longCounter.Add( + 123, new("tag1", "value1"), new("tag2", "value2")); - meter.CreateObservableGauge( - "observableDoubleGauge", - () => new List>() - { - new(123.45, new("tag1", "value1"), new("tag2", "value2")), - }); + doubleCounter.Add( + 123.45, new("tag1", "value1"), new("tag2", "value2")); - // Record the following values for histogramWithCustomBounds: - // (-inf - 500] : 3 - // (500 - 1000] : 1 - // (1000 - +inf) : 1 - // - // The corresponding value-count pairs to be sent for histogramWithCustomBounds: - // 500: 3 - // 1000: 1 - // 1001: 1 (We use one greater than the last bound provided (1000 + 1) as the value for the overflow bucket) + meter.CreateObservableCounter( + "observableLongCounter", + () => new List>() + { + new(123, new("tag1", "value1"), new("tag2", "value2")), + }); - histogramWithCustomBounds.Record(-1, new("tag1", "value1"), new("tag2", "value2")); - histogramWithCustomBounds.Record(150, new("tag1", "value1"), new("tag2", "value2")); - histogramWithCustomBounds.Record(150, new("tag1", "value1"), new("tag2", "value2")); - histogramWithCustomBounds.Record(750, new("tag1", "value1"), new("tag2", "value2")); - histogramWithCustomBounds.Record(2500, new("tag1", "value1"), new("tag2", "value2")); + meter.CreateObservableCounter( + "observableDoubleCounter", + () => new List>() + { + new(123.45, new("tag1", "value1"), new("tag2", "value2")), + }); - // Record the following values for histogramWithNoBounds: - // (-inf - 500] : 3 - // (500 - 1000] : 1 - // (1000 - +inf) : 1 - // - // Only `sum` and `count` are sent for histogramWithNoBounds - // No value-count pairs are sent for histogramWithNoBounds + meter.CreateObservableGauge( + "observableLongGauge", + () => new List>() + { + new(123, new("tag1", "value1"), new("tag2", "value2")), + }); - histogramWithNoBounds.Record(-1, new("tag1", "value1"), new("tag2", "value2")); - histogramWithNoBounds.Record(150, new("tag1", "value1"), new("tag2", "value2")); - histogramWithNoBounds.Record(150, new("tag1", "value1"), new("tag2", "value2")); - histogramWithNoBounds.Record(750, new("tag1", "value1"), new("tag2", "value2")); - histogramWithNoBounds.Record(2500, new("tag1", "value1"), new("tag2", "value2")); + meter.CreateObservableGauge( + "observableDoubleGauge", + () => new List>() + { + new(123.45, new("tag1", "value1"), new("tag2", "value2")), + }); - string path = string.Empty; - Socket server = null; - try + // Record the following values for histogramWithCustomBounds: + // (-inf - 500] : 3 + // (500 - 1000] : 1 + // (1000 - +inf) : 1 + // + // The corresponding value-count pairs to be sent for histogramWithCustomBounds: + // 500: 3 + // 1000: 1 + // 1001: 1 (We use one greater than the last bound provided (1000 + 1) as the value for the overflow bucket) + + histogramWithCustomBounds.Record(-1, new("tag1", "value1"), new("tag2", "value2")); + histogramWithCustomBounds.Record(150, new("tag1", "value1"), new("tag2", "value2")); + histogramWithCustomBounds.Record(150, new("tag1", "value1"), new("tag2", "value2")); + histogramWithCustomBounds.Record(750, new("tag1", "value1"), new("tag2", "value2")); + histogramWithCustomBounds.Record(2500, new("tag1", "value1"), new("tag2", "value2")); + + // Record the following values for histogramWithNoBounds: + // (-inf - 500] : 3 + // (500 - 1000] : 1 + // (1000 - +inf) : 1 + // + // Only `sum` and `count` are sent for histogramWithNoBounds + // No value-count pairs are sent for histogramWithNoBounds + + histogramWithNoBounds.Record(-1, new("tag1", "value1"), new("tag2", "value2")); + histogramWithNoBounds.Record(150, new("tag1", "value1"), new("tag2", "value2")); + histogramWithNoBounds.Record(150, new("tag1", "value1"), new("tag2", "value2")); + histogramWithNoBounds.Record(750, new("tag1", "value1"), new("tag2", "value2")); + histogramWithNoBounds.Record(2500, new("tag1", "value1"), new("tag2", "value2")); + + string path = string.Empty; + Socket server = null; + try + { + var exporterOptions = new GenevaMetricExporterOptions(); + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - var exporterOptions = new GenevaMetricExporterOptions(); - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - exporterOptions.ConnectionString = "Account=OTelMonitoringAccount;Namespace=OTelMetricNamespace"; - } - else - { - path = GenerateTempFilePath(); - exporterOptions.ConnectionString = $"Endpoint=unix:{path};Account=OTelMonitoringAccount;Namespace=OTelMetricNamespace"; - var endpoint = new UnixDomainSocketEndPoint(path); - server = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); - server.Bind(endpoint); - server.Listen(1); - } + exporterOptions.ConnectionString = "Account=OTelMonitoringAccount;Namespace=OTelMetricNamespace"; + } + else + { + path = GenerateTempFilePath(); + exporterOptions.ConnectionString = $"Endpoint=unix:{path};Account=OTelMonitoringAccount;Namespace=OTelMetricNamespace"; + var endpoint = new UnixDomainSocketEndPoint(path); + server = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); + server.Bind(endpoint); + server.Listen(1); + } - exporterOptions.PrepopulatedMetricDimensions = new Dictionary - { - ["cloud.role"] = "BusyWorker", - ["cloud.roleInstance"] = "CY1SCH030021417", - ["cloud.roleVer"] = "9.0.15289.2", - }; + exporterOptions.PrepopulatedMetricDimensions = new Dictionary + { + ["cloud.role"] = "BusyWorker", + ["cloud.roleInstance"] = "CY1SCH030021417", + ["cloud.roleVer"] = "9.0.15289.2", + }; - using var exporter = new GenevaMetricExporter(exporterOptions); + using var exporter = new GenevaMetricExporter(exporterOptions); - inMemoryReader.Collect(); + inMemoryReader.Collect(); - Assert.Equal(6, exportedItems.Count); + Assert.Equal(6, exportedItems.Count); - // observableLongCounter and observableDoubleGauge are dropped - Assert.Empty(exportedItems.Where(item => item.Name == "observableLongCounter" || item.Name == "observableDoubleGauge")); + // observableLongCounter and observableDoubleGauge are dropped + Assert.Empty(exportedItems.Where(item => item.Name == "observableLongCounter" || item.Name == "observableDoubleGauge")); - // check serialization for longCounter - this.CheckSerializationForSingleMetricPoint(exportedItems[0], exporter, exporterOptions); + // check serialization for longCounter + this.CheckSerializationForSingleMetricPoint(exportedItems[0], exporter, exporterOptions); - // check serialization for doubleCounter - this.CheckSerializationForSingleMetricPoint(exportedItems[1], exporter, exporterOptions); + // check serialization for doubleCounter + this.CheckSerializationForSingleMetricPoint(exportedItems[1], exporter, exporterOptions); - // check serialization for histogramWithCustomBounds - this.CheckSerializationForSingleMetricPoint(exportedItems[2], exporter, exporterOptions); + // check serialization for histogramWithCustomBounds + this.CheckSerializationForSingleMetricPoint(exportedItems[2], exporter, exporterOptions); - // check serialization for histogramWithNoBounds - this.CheckSerializationForSingleMetricPoint(exportedItems[3], exporter, exporterOptions); + // check serialization for histogramWithNoBounds + this.CheckSerializationForSingleMetricPoint(exportedItems[3], exporter, exporterOptions); - // check serialization for observableDoubleCounter - this.CheckSerializationForSingleMetricPoint(exportedItems[4], exporter, exporterOptions); + // check serialization for observableDoubleCounter + this.CheckSerializationForSingleMetricPoint(exportedItems[4], exporter, exporterOptions); - // check serialization for observableLongGauge - this.CheckSerializationForSingleMetricPoint(exportedItems[5], exporter, exporterOptions); + // check serialization for observableLongGauge + this.CheckSerializationForSingleMetricPoint(exportedItems[5], exporter, exporterOptions); + } + finally + { + server?.Dispose(); + try + { + File.Delete(path); } - finally + catch { - server?.Dispose(); - try - { - File.Delete(path); - } - catch - { - } } } + } - [Fact] - public void SuccessfulExportOnLinux() + [Fact] + public void SuccessfulExportOnLinux() + { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - string path = GenerateTempFilePath(); - var exportedItems = new List(); + string path = GenerateTempFilePath(); + var exportedItems = new List(); - using var meter = new Meter("SuccessfulExportOnLinux", "0.0.1"); - var counter = meter.CreateCounter("counter"); + using var meter = new Meter("SuccessfulExportOnLinux", "0.0.1"); + var counter = meter.CreateCounter("counter"); - using var inMemoryMeter = new Meter("InMemoryExportOnLinux", "0.0.1"); - var inMemoryCounter = inMemoryMeter.CreateCounter("counter"); + using var inMemoryMeter = new Meter("InMemoryExportOnLinux", "0.0.1"); + var inMemoryCounter = inMemoryMeter.CreateCounter("counter"); - try + try + { + var endpoint = new UnixDomainSocketEndPoint(path); + using var server = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); + server.Bind(endpoint); + server.Listen(1); + + using var inMemoryReader = new BaseExportingMetricReader(new InMemoryExporter(exportedItems)) { - var endpoint = new UnixDomainSocketEndPoint(path); - using var server = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); - server.Bind(endpoint); - server.Listen(1); + TemporalityPreference = MetricReaderTemporalityPreference.Delta, + }; - using var inMemoryReader = new BaseExportingMetricReader(new InMemoryExporter(exportedItems)) + // Set up two different providers as only one Metric Processor is allowed. + // TODO: Simplify the setup when multiple Metric processors are allowed. + using var meterProvider = Sdk.CreateMeterProviderBuilder() + .AddMeter("SuccessfulExportOnLinux") + .AddGenevaMetricExporter(options => { - TemporalityPreference = MetricReaderTemporalityPreference.Delta, - }; + options.ConnectionString = $"Endpoint=unix:{path};Account=OTelMonitoringAccount;Namespace=OTelMetricNamespace"; + options.MetricExportIntervalMilliseconds = 5000; + }) + .Build(); - // Set up two different providers as only one Metric Processor is allowed. - // TODO: Simplify the setup when multiple Metric processors are allowed. - using var meterProvider = Sdk.CreateMeterProviderBuilder() - .AddMeter("SuccessfulExportOnLinux") - .AddGenevaMetricExporter(options => - { - options.ConnectionString = $"Endpoint=unix:{path};Account=OTelMonitoringAccount;Namespace=OTelMetricNamespace"; - options.MetricExportIntervalMilliseconds = 5000; - }) - .Build(); - - using var inMemoryMeterProvider = Sdk.CreateMeterProviderBuilder() - .AddMeter("InMemoryExportOnLinux") - .AddReader(inMemoryReader) - .Build(); - - using var serverSocket = server.Accept(); - serverSocket.ReceiveTimeout = 15000; - - // Create a test exporter to get byte data for validation of the data received via Socket. - var exporterOptions = new GenevaMetricExporterOptions() { ConnectionString = $"Endpoint=unix:{path};Account=OTelMonitoringAccount;Namespace=OTelMetricNamespace" }; - using var exporter = new GenevaMetricExporter(exporterOptions); - - // Emit a metric and grab a copy of internal buffer for validation. - counter.Add( - 123, - new KeyValuePair("tag1", "value1"), - new KeyValuePair("tag2", "value2")); - - inMemoryCounter.Add( - 123, - new KeyValuePair("tag1", "value1"), - new KeyValuePair("tag2", "value2")); - - // exportedItems list should have a single entry after the MetricReader.Collect call - inMemoryReader.Collect(); - - Assert.Single(exportedItems); - - var metric = exportedItems[0]; - var metricPointsEnumerator = metric.GetMetricPoints().GetEnumerator(); - metricPointsEnumerator.MoveNext(); - var metricPoint = metricPointsEnumerator.Current; - var metricDataValue = Convert.ToUInt64(metricPoint.GetSumLong()); - var metricData = new MetricData { UInt64Value = metricDataValue }; - var bodyLength = exporter.SerializeMetric( - MetricEventType.ULongMetric, - metric.Name, - metricPoint.EndTime.ToFileTime(), - metricPoint.Tags, - metricData); - - // Wait a little more than the ExportInterval for the exporter to export the data. - Task.Delay(5500).Wait(); - - // Read the data sent via socket. - var receivedData = new byte[1024]; - int receivedDataSize = serverSocket.Receive(receivedData); - - var fixedPayloadLength = (int)typeof(GenevaMetricExporter).GetField("fixedPayloadStartIndex", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(exporter); - - // The whole payload is sent to the Unix Domain Socket - // BinaryHeader (fixed payload) + variable payload which starts with MetricPayload - Assert.Equal(bodyLength + fixedPayloadLength, receivedDataSize); - - var stream = new KaitaiStream(receivedData); - var data = new MetricsContract(stream); - - Assert.Equal(metric.Name, data.Body.MetricName.Value); - Assert.Equal("OTelMonitoringAccount", data.Body.MetricAccount.Value); - Assert.Equal("OTelMetricNamespace", data.Body.MetricNamespace.Value); - - var valueSection = data.Body.ValueSection as SingleUint64Value; - Assert.Equal(metricDataValue, valueSection.Value); - - Assert.Equal(2, data.Body.NumDimensions); - - int i = 0; - foreach (var tag in metricPoint.Tags) - { - Assert.Equal(tag.Key, data.Body.DimensionsNames[i].Value); - Assert.Equal(tag.Value, data.Body.DimensionsValues[i].Value); - i++; - } + using var inMemoryMeterProvider = Sdk.CreateMeterProviderBuilder() + .AddMeter("InMemoryExportOnLinux") + .AddReader(inMemoryReader) + .Build(); - Assert.Equal((ushort)MetricEventType.ULongMetric, data.EventId); - Assert.Equal(bodyLength, data.LenBody); - } - finally - { - try - { - File.Delete(path); - } - catch - { - } - } - } - } + using var serverSocket = server.Accept(); + serverSocket.ReceiveTimeout = 15000; - private static string GenerateTempFilePath() - { - while (true) - { - string path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); - if (!File.Exists(path)) - { - return path; - } - } - } + // Create a test exporter to get byte data for validation of the data received via Socket. + var exporterOptions = new GenevaMetricExporterOptions() { ConnectionString = $"Endpoint=unix:{path};Account=OTelMonitoringAccount;Namespace=OTelMetricNamespace" }; + using var exporter = new GenevaMetricExporter(exporterOptions); - private void CheckSerializationForSingleMetricPoint(Metric metric, GenevaMetricExporter exporter, GenevaMetricExporterOptions exporterOptions) - { - var metricType = metric.MetricType; - var metricPointsEnumerator = metric.GetMetricPoints().GetEnumerator(); - metricPointsEnumerator.MoveNext(); - var metricPoint = metricPointsEnumerator.Current; - MetricsContract data = null; - - // Check metric value, timestamp, eventId, and length of payload - if (metricType == MetricType.LongSum || metricType == MetricType.LongGauge) - { - var metricDataValue = metricType == MetricType.LongSum ? - Convert.ToUInt64(metricPoint.GetSumLong()) : - Convert.ToUInt64(metricPoint.GetGaugeLastValueLong()); + // Emit a metric and grab a copy of internal buffer for validation. + counter.Add( + 123, + new KeyValuePair("tag1", "value1"), + new KeyValuePair("tag2", "value2")); + + inMemoryCounter.Add( + 123, + new KeyValuePair("tag1", "value1"), + new KeyValuePair("tag2", "value2")); + + // exportedItems list should have a single entry after the MetricReader.Collect call + inMemoryReader.Collect(); + + Assert.Single(exportedItems); + + var metric = exportedItems[0]; + var metricPointsEnumerator = metric.GetMetricPoints().GetEnumerator(); + metricPointsEnumerator.MoveNext(); + var metricPoint = metricPointsEnumerator.Current; + var metricDataValue = Convert.ToUInt64(metricPoint.GetSumLong()); var metricData = new MetricData { UInt64Value = metricDataValue }; var bodyLength = exporter.SerializeMetric( MetricEventType.ULongMetric, @@ -611,128 +527,210 @@ private void CheckSerializationForSingleMetricPoint(Metric metric, GenevaMetricE metricPoint.EndTime.ToFileTime(), metricPoint.Tags, metricData); - var buffer = typeof(GenevaMetricExporter).GetField("bufferForNonHistogramMetrics", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(exporter) as byte[]; - var stream = new KaitaiStream(buffer); - data = new MetricsContract(stream); + + // Wait a little more than the ExportInterval for the exporter to export the data. + Task.Delay(5500).Wait(); + + // Read the data sent via socket. + var receivedData = new byte[1024]; + int receivedDataSize = serverSocket.Receive(receivedData); + + var fixedPayloadLength = (int)typeof(GenevaMetricExporter).GetField("fixedPayloadStartIndex", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(exporter); + + // The whole payload is sent to the Unix Domain Socket + // BinaryHeader (fixed payload) + variable payload which starts with MetricPayload + Assert.Equal(bodyLength + fixedPayloadLength, receivedDataSize); + + var stream = new KaitaiStream(receivedData); + var data = new MetricsContract(stream); + + Assert.Equal(metric.Name, data.Body.MetricName.Value); + Assert.Equal("OTelMonitoringAccount", data.Body.MetricAccount.Value); + Assert.Equal("OTelMetricNamespace", data.Body.MetricNamespace.Value); + var valueSection = data.Body.ValueSection as SingleUint64Value; Assert.Equal(metricDataValue, valueSection.Value); - Assert.Equal((ulong)metricPoint.EndTime.ToFileTime(), valueSection.Timestamp); + + Assert.Equal(2, data.Body.NumDimensions); + + int i = 0; + foreach (var tag in metricPoint.Tags) + { + Assert.Equal(tag.Key, data.Body.DimensionsNames[i].Value); + Assert.Equal(tag.Value, data.Body.DimensionsValues[i].Value); + i++; + } + Assert.Equal((ushort)MetricEventType.ULongMetric, data.EventId); Assert.Equal(bodyLength, data.LenBody); } - else if (metricType == MetricType.DoubleSum || metricType == MetricType.DoubleGauge) + finally { - var metricDataValue = metricType == MetricType.DoubleSum ? - metricPoint.GetSumDouble() : - metricPoint.GetGaugeLastValueDouble(); - var metricData = new MetricData { DoubleValue = metricDataValue }; - var bodyLength = exporter.SerializeMetric( - MetricEventType.DoubleMetric, - metric.Name, - metricPoint.EndTime.ToFileTime(), - metricPoint.Tags, - metricData); - var buffer = typeof(GenevaMetricExporter).GetField("bufferForNonHistogramMetrics", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(exporter) as byte[]; - var stream = new KaitaiStream(buffer); - data = new MetricsContract(stream); - var valueSection = data.Body.ValueSection as SingleDoubleValue; - Assert.Equal(metricDataValue, valueSection.Value); - Assert.Equal((ulong)metricPoint.EndTime.ToFileTime(), valueSection.Timestamp); - Assert.Equal((ushort)MetricEventType.DoubleMetric, data.EventId); - Assert.Equal(bodyLength, data.LenBody); + try + { + File.Delete(path); + } + catch + { + } + } + } + } + + private static string GenerateTempFilePath() + { + while (true) + { + string path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + if (!File.Exists(path)) + { + return path; } - else if (metricType == MetricType.Histogram) + } + } + + private void CheckSerializationForSingleMetricPoint(Metric metric, GenevaMetricExporter exporter, GenevaMetricExporterOptions exporterOptions) + { + var metricType = metric.MetricType; + var metricPointsEnumerator = metric.GetMetricPoints().GetEnumerator(); + metricPointsEnumerator.MoveNext(); + var metricPoint = metricPointsEnumerator.Current; + MetricsContract data = null; + + // Check metric value, timestamp, eventId, and length of payload + if (metricType == MetricType.LongSum || metricType == MetricType.LongGauge) + { + var metricDataValue = metricType == MetricType.LongSum ? + Convert.ToUInt64(metricPoint.GetSumLong()) : + Convert.ToUInt64(metricPoint.GetGaugeLastValueLong()); + var metricData = new MetricData { UInt64Value = metricDataValue }; + var bodyLength = exporter.SerializeMetric( + MetricEventType.ULongMetric, + metric.Name, + metricPoint.EndTime.ToFileTime(), + metricPoint.Tags, + metricData); + var buffer = typeof(GenevaMetricExporter).GetField("bufferForNonHistogramMetrics", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(exporter) as byte[]; + var stream = new KaitaiStream(buffer); + data = new MetricsContract(stream); + var valueSection = data.Body.ValueSection as SingleUint64Value; + Assert.Equal(metricDataValue, valueSection.Value); + Assert.Equal((ulong)metricPoint.EndTime.ToFileTime(), valueSection.Timestamp); + Assert.Equal((ushort)MetricEventType.ULongMetric, data.EventId); + Assert.Equal(bodyLength, data.LenBody); + } + else if (metricType == MetricType.DoubleSum || metricType == MetricType.DoubleGauge) + { + var metricDataValue = metricType == MetricType.DoubleSum ? + metricPoint.GetSumDouble() : + metricPoint.GetGaugeLastValueDouble(); + var metricData = new MetricData { DoubleValue = metricDataValue }; + var bodyLength = exporter.SerializeMetric( + MetricEventType.DoubleMetric, + metric.Name, + metricPoint.EndTime.ToFileTime(), + metricPoint.Tags, + metricData); + var buffer = typeof(GenevaMetricExporter).GetField("bufferForNonHistogramMetrics", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(exporter) as byte[]; + var stream = new KaitaiStream(buffer); + data = new MetricsContract(stream); + var valueSection = data.Body.ValueSection as SingleDoubleValue; + Assert.Equal(metricDataValue, valueSection.Value); + Assert.Equal((ulong)metricPoint.EndTime.ToFileTime(), valueSection.Timestamp); + Assert.Equal((ushort)MetricEventType.DoubleMetric, data.EventId); + Assert.Equal(bodyLength, data.LenBody); + } + else if (metricType == MetricType.Histogram) + { + var sum = new MetricData { UInt64Value = Convert.ToUInt64(metricPoint.GetHistogramSum()) }; + var count = Convert.ToUInt32(metricPoint.GetHistogramCount()); + var bodyLength = exporter.SerializeHistogramMetric( + metric.Name, + metricPoint.EndTime.ToFileTime(), + metricPoint.Tags, + metricPoint.GetHistogramBuckets(), + sum, + count); + var buffer = typeof(GenevaMetricExporter).GetField("bufferForHistogramMetrics", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(exporter) as byte[]; + var stream = new KaitaiStream(buffer); + data = new MetricsContract(stream); + var valueSection = data.Body.ValueSection as ExtAggregatedUint64Value; + var valueCountPairs = data.Body.Histogram.Body as HistogramValueCountPairs; + + Assert.Equal(0, data.Body.Histogram.Version); + Assert.Equal(2, (int)data.Body.Histogram.Type); + + int listIterator = 0; + int bucketsWithPositiveCount = 0; + double lastExplicitBound = default; + foreach (var bucket in metricPoint.GetHistogramBuckets()) { - var sum = new MetricData { UInt64Value = Convert.ToUInt64(metricPoint.GetHistogramSum()) }; - var count = Convert.ToUInt32(metricPoint.GetHistogramCount()); - var bodyLength = exporter.SerializeHistogramMetric( - metric.Name, - metricPoint.EndTime.ToFileTime(), - metricPoint.Tags, - metricPoint.GetHistogramBuckets(), - sum, - count); - var buffer = typeof(GenevaMetricExporter).GetField("bufferForHistogramMetrics", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(exporter) as byte[]; - var stream = new KaitaiStream(buffer); - data = new MetricsContract(stream); - var valueSection = data.Body.ValueSection as ExtAggregatedUint64Value; - var valueCountPairs = data.Body.Histogram.Body as HistogramValueCountPairs; - - Assert.Equal(0, data.Body.Histogram.Version); - Assert.Equal(2, (int)data.Body.Histogram.Type); - - int listIterator = 0; - int bucketsWithPositiveCount = 0; - double lastExplicitBound = default; - foreach (var bucket in metricPoint.GetHistogramBuckets()) + if (bucket.BucketCount > 0) { - if (bucket.BucketCount > 0) + if (bucket.ExplicitBound != double.PositiveInfinity) { - if (bucket.ExplicitBound != double.PositiveInfinity) - { - Assert.Equal(bucket.ExplicitBound, valueCountPairs.Columns[listIterator].Value); - lastExplicitBound = bucket.ExplicitBound; - } - else - { - Assert.Equal((ulong)lastExplicitBound + 1, valueCountPairs.Columns[listIterator].Value); - } - - Assert.Equal(bucket.BucketCount, valueCountPairs.Columns[listIterator].Count); - - listIterator++; - bucketsWithPositiveCount++; + Assert.Equal(bucket.ExplicitBound, valueCountPairs.Columns[listIterator].Value); + lastExplicitBound = bucket.ExplicitBound; + } + else + { + Assert.Equal((ulong)lastExplicitBound + 1, valueCountPairs.Columns[listIterator].Value); } - } - Assert.Equal(bucketsWithPositiveCount, valueCountPairs.DistributionSize); + Assert.Equal(bucket.BucketCount, valueCountPairs.Columns[listIterator].Count); - Assert.Equal(count, valueSection.Count); - Assert.Equal(Convert.ToUInt64(metricPoint.GetHistogramSum()), valueSection.Sum); - Assert.Equal(0UL, valueSection.Min); - Assert.Equal(0UL, valueSection.Max); - Assert.Equal((ulong)metricPoint.EndTime.ToFileTime(), valueSection.Timestamp); - Assert.Equal((ushort)MetricEventType.ExternallyAggregatedULongDistributionMetric, data.EventId); - Assert.Equal(bodyLength, data.LenBody); + listIterator++; + bucketsWithPositiveCount++; + } } - // Check metric name, account, and namespace - var connectionStringBuilder = new ConnectionStringBuilder(exporterOptions.ConnectionString); - Assert.Equal(metric.Name, data.Body.MetricName.Value); - Assert.Equal(connectionStringBuilder.Account, data.Body.MetricAccount.Value); - Assert.Equal(connectionStringBuilder.Namespace, data.Body.MetricNamespace.Value); + Assert.Equal(bucketsWithPositiveCount, valueCountPairs.DistributionSize); - var dimensionsCount = 0; - if (exporterOptions.PrepopulatedMetricDimensions != null) - { - foreach (var entry in exporterOptions.PrepopulatedMetricDimensions) - { - Assert.Contains(data.Body.DimensionsNames, dim => dim.Value == entry.Key); - Assert.Contains(data.Body.DimensionsValues, dim => dim.Value == Convert.ToString(entry.Value, CultureInfo.InvariantCulture)); - } + Assert.Equal(count, valueSection.Count); + Assert.Equal(Convert.ToUInt64(metricPoint.GetHistogramSum()), valueSection.Sum); + Assert.Equal(0UL, valueSection.Min); + Assert.Equal(0UL, valueSection.Max); + Assert.Equal((ulong)metricPoint.EndTime.ToFileTime(), valueSection.Timestamp); + Assert.Equal((ushort)MetricEventType.ExternallyAggregatedULongDistributionMetric, data.EventId); + Assert.Equal(bodyLength, data.LenBody); + } - dimensionsCount += exporterOptions.PrepopulatedMetricDimensions.Count; - } + // Check metric name, account, and namespace + var connectionStringBuilder = new ConnectionStringBuilder(exporterOptions.ConnectionString); + Assert.Equal(metric.Name, data.Body.MetricName.Value); + Assert.Equal(connectionStringBuilder.Account, data.Body.MetricAccount.Value); + Assert.Equal(connectionStringBuilder.Namespace, data.Body.MetricNamespace.Value); - // Check metric dimensions - int i = 0; - foreach (var item in exporterOptions.PrepopulatedMetricDimensions) + var dimensionsCount = 0; + if (exporterOptions.PrepopulatedMetricDimensions != null) + { + foreach (var entry in exporterOptions.PrepopulatedMetricDimensions) { - Assert.Equal(item.Key, data.Body.DimensionsNames[i].Value); - Assert.Equal(item.Value, data.Body.DimensionsValues[i].Value); - i++; + Assert.Contains(data.Body.DimensionsNames, dim => dim.Value == entry.Key); + Assert.Contains(data.Body.DimensionsValues, dim => dim.Value == Convert.ToString(entry.Value, CultureInfo.InvariantCulture)); } - foreach (var tag in metricPoint.Tags) - { - Assert.Equal(tag.Key, data.Body.DimensionsNames[i].Value); - Assert.Equal(tag.Value, data.Body.DimensionsValues[i].Value); - i++; - } + dimensionsCount += exporterOptions.PrepopulatedMetricDimensions.Count; + } - dimensionsCount += metricPoint.Tags.Count; + // Check metric dimensions + int i = 0; + foreach (var item in exporterOptions.PrepopulatedMetricDimensions) + { + Assert.Equal(item.Key, data.Body.DimensionsNames[i].Value); + Assert.Equal(item.Value, data.Body.DimensionsValues[i].Value); + i++; + } - Assert.Equal(dimensionsCount, data.Body.NumDimensions); + foreach (var tag in metricPoint.Tags) + { + Assert.Equal(tag.Key, data.Body.DimensionsNames[i].Value); + Assert.Equal(tag.Value, data.Body.DimensionsValues[i].Value); + i++; } + + dimensionsCount += metricPoint.Tags.Count; + + Assert.Equal(dimensionsCount, data.Body.NumDimensions); } } diff --git a/test/OpenTelemetry.Exporter.Geneva.Tests/GenevaTraceExporterTests.cs b/test/OpenTelemetry.Exporter.Geneva.Tests/GenevaTraceExporterTests.cs index a75d66c5f6..0db23b09b7 100644 --- a/test/OpenTelemetry.Exporter.Geneva.Tests/GenevaTraceExporterTests.cs +++ b/test/OpenTelemetry.Exporter.Geneva.Tests/GenevaTraceExporterTests.cs @@ -24,268 +24,267 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; -using System.Threading.Tasks; using OpenTelemetry.Trace; using Xunit; -namespace OpenTelemetry.Exporter.Geneva.Tests +namespace OpenTelemetry.Exporter.Geneva.Tests; + +public class GenevaTraceExporterTests { - public class GenevaTraceExporterTests + public GenevaTraceExporterTests() { - public GenevaTraceExporterTests() + Activity.DefaultIdFormat = ActivityIdFormat.W3C; + } + + [Fact] + public void GenevaTraceExporter_constructor_Invalid_Input() + { + // no connection string + Assert.Throws(() => { - Activity.DefaultIdFormat = ActivityIdFormat.W3C; - } + using var exporter = new GenevaTraceExporter(new GenevaExporterOptions()); + }); - [Fact] - public void GenevaTraceExporter_constructor_Invalid_Input() + // null connection string + Assert.Throws(() => { - // no connection string - Assert.Throws(() => + using var exporter = new GenevaTraceExporter(new GenevaExporterOptions { - using var exporter = new GenevaTraceExporter(new GenevaExporterOptions()); + ConnectionString = null, }); + }); - // null connection string - Assert.Throws(() => - { - using var exporter = new GenevaTraceExporter(new GenevaExporterOptions - { - ConnectionString = null, - }); - }); - - // null value in the PrepopulatedFields - Assert.Throws(() => + // null value in the PrepopulatedFields + Assert.Throws(() => + { + using var exporter = new GenevaTraceExporter(new GenevaExporterOptions { - using var exporter = new GenevaTraceExporter(new GenevaExporterOptions + ConnectionString = "EtwSession=OpenTelemetry", + PrepopulatedFields = new Dictionary { - ConnectionString = "EtwSession=OpenTelemetry", - PrepopulatedFields = new Dictionary - { - ["cloud.roleVer"] = null, - }, - }); + ["cloud.roleVer"] = null, + }, }); + }); - // unsupported types(char) for PrepopulatedFields - Assert.Throws(() => + // unsupported types(char) for PrepopulatedFields + Assert.Throws(() => + { + using var exporter = new GenevaTraceExporter(new GenevaExporterOptions { - using var exporter = new GenevaTraceExporter(new GenevaExporterOptions + ConnectionString = "EtwSession=OpenTelemetry", + PrepopulatedFields = new Dictionary { - ConnectionString = "EtwSession=OpenTelemetry", - PrepopulatedFields = new Dictionary - { - ["cloud.role"] = "BusyWorker", - ["cloud.roleInstance"] = "CY1SCH030021417", - ["cloud.roleVer"] = (char)106, - }, - }); + ["cloud.role"] = "BusyWorker", + ["cloud.roleInstance"] = "CY1SCH030021417", + ["cloud.roleVer"] = (char)106, + }, }); + }); - // Supported types for PrepopulatedFields should not throw an exception - var exception = Record.Exception(() => + // Supported types for PrepopulatedFields should not throw an exception + var exception = Record.Exception(() => + { + new GenevaExporterOptions { - new GenevaExporterOptions - { - ConnectionString = "EtwSession=OpenTelemetry", - PrepopulatedFields = new Dictionary - { - ["bool"] = true, - ["byte"] = byte.MaxValue, - ["sbyte"] = sbyte.MaxValue, - ["short"] = short.MaxValue, - ["ushort"] = ushort.MaxValue, - ["int"] = int.MaxValue, - ["uint"] = uint.MaxValue, - ["long"] = long.MaxValue, - ["ulong"] = ulong.MaxValue, - ["float"] = float.MaxValue, - ["double"] = double.MaxValue, - ["string"] = string.Empty, - }, - }; - }); - - Assert.Null(exception); - } + ConnectionString = "EtwSession=OpenTelemetry", + PrepopulatedFields = new Dictionary + { + ["bool"] = true, + ["byte"] = byte.MaxValue, + ["sbyte"] = sbyte.MaxValue, + ["short"] = short.MaxValue, + ["ushort"] = ushort.MaxValue, + ["int"] = int.MaxValue, + ["uint"] = uint.MaxValue, + ["long"] = long.MaxValue, + ["ulong"] = ulong.MaxValue, + ["float"] = float.MaxValue, + ["double"] = double.MaxValue, + ["string"] = string.Empty, + }, + }; + }); + + Assert.Null(exception); + } - [Fact] - public void GenevaTraceExporter_constructor_Invalid_Input_Windows() + [Fact] + public void GenevaTraceExporter_constructor_Invalid_Input_Windows() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + // no ETW session name + Assert.Throws(() => { - // no ETW session name - Assert.Throws(() => - { - using var exporter = new GenevaTraceExporter(new GenevaExporterOptions - { - ConnectionString = "key=value", - }); - }); - - // empty ETW session name - Assert.Throws(() => + using var exporter = new GenevaTraceExporter(new GenevaExporterOptions { - using var exporter = new GenevaTraceExporter(new GenevaExporterOptions - { - ConnectionString = "EtwSession=", - }); + ConnectionString = "key=value", }); - } - } + }); - [Fact] - public void GenevaTraceExporter_TableNameMappings_SpecialCharacters() - { + // empty ETW session name Assert.Throws(() => { using var exporter = new GenevaTraceExporter(new GenevaExporterOptions { - TableNameMappings = new Dictionary { ["Span"] = "\u0418" }, + ConnectionString = "EtwSession=", }); }); } + } - [Fact] - public void GenevaTraceExporter_Success_Windows() + [Fact] + public void GenevaTraceExporter_TableNameMappings_SpecialCharacters() + { + Assert.Throws(() => { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + using var exporter = new GenevaTraceExporter(new GenevaExporterOptions { - // Set the ActivitySourceName to the unique value of the test method name to avoid interference with - // the ActivitySource used by other unit tests. - var sourceName = GetTestMethodName(); + TableNameMappings = new Dictionary { ["Span"] = "\u0418" }, + }); + }); + } - // TODO: Setup a mock or spy for eventLogger to assert that eventLogger.LogInformationalEvent is actually called. - using var tracerProvider = Sdk.CreateTracerProviderBuilder() - .SetSampler(new AlwaysOnSampler()) - .AddSource(sourceName) - .AddGenevaTraceExporter(options => + [Fact] + public void GenevaTraceExporter_Success_Windows() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + // Set the ActivitySourceName to the unique value of the test method name to avoid interference with + // the ActivitySource used by other unit tests. + var sourceName = GetTestMethodName(); + + // TODO: Setup a mock or spy for eventLogger to assert that eventLogger.LogInformationalEvent is actually called. + using var tracerProvider = Sdk.CreateTracerProviderBuilder() + .SetSampler(new AlwaysOnSampler()) + .AddSource(sourceName) + .AddGenevaTraceExporter(options => + { + options.ConnectionString = "EtwSession=OpenTelemetry"; + options.PrepopulatedFields = new Dictionary { - options.ConnectionString = "EtwSession=OpenTelemetry"; - options.PrepopulatedFields = new Dictionary - { - ["cloud.role"] = "BusyWorker", - ["cloud.roleInstance"] = "CY1SCH030021417", - ["cloud.roleVer"] = "9.0.15289.2", - }; - }) - .Build(); + ["cloud.role"] = "BusyWorker", + ["cloud.roleInstance"] = "CY1SCH030021417", + ["cloud.roleVer"] = "9.0.15289.2", + }; + }) + .Build(); - var source = new ActivitySource(sourceName); - using (var parent = source.StartActivity("HttpIn", ActivityKind.Server)) + var source = new ActivitySource(sourceName); + using (var parent = source.StartActivity("HttpIn", ActivityKind.Server)) + { + parent?.SetTag("http.method", "GET"); + parent?.SetTag("http.url", "https://localhost/wiki/Rabbit"); + using (var child = source.StartActivity("HttpOut", ActivityKind.Client)) { - parent?.SetTag("http.method", "GET"); - parent?.SetTag("http.url", "https://localhost/wiki/Rabbit"); - using (var child = source.StartActivity("HttpOut", ActivityKind.Client)) - { - child?.SetTag("http.method", "GET"); - child?.SetTag("http.url", "https://www.wikipedia.org/wiki/Rabbit"); - child?.SetTag("http.status_code", 404); - } - - parent?.SetTag("http.status_code", 200); + child?.SetTag("http.method", "GET"); + child?.SetTag("http.url", "https://www.wikipedia.org/wiki/Rabbit"); + child?.SetTag("http.status_code", 404); } - var link = new ActivityLink(new ActivityContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.Recorded)); - using (var activity = source.StartActivity("Foo", ActivityKind.Internal, null, null, new ActivityLink[] { link })) - { - } + parent?.SetTag("http.status_code", 200); + } - using (var activity = source.StartActivity("Bar")) - { - activity.SetStatus(Status.Error); - } + var link = new ActivityLink(new ActivityContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.Recorded)); + using (var activity = source.StartActivity("Foo", ActivityKind.Internal, null, null, new ActivityLink[] { link })) + { + } - using (var activity = source.StartActivity("Baz")) - { - activity.SetStatus(Status.Ok); - } + using (var activity = source.StartActivity("Bar")) + { + activity.SetStatus(Status.Error); + } + + using (var activity = source.StartActivity("Baz")) + { + activity.SetStatus(Status.Ok); } } + } - [Theory] - [InlineData(false, false)] - [InlineData(false, true)] - [InlineData(true, false)] - [InlineData(true, true)] - public void GenevaTraceExporter_Serialization_Success(bool hasTableNameMapping, bool hasCustomFields) + [Theory] + [InlineData(false, false)] + [InlineData(false, true)] + [InlineData(true, false)] + [InlineData(true, true)] + public void GenevaTraceExporter_Serialization_Success(bool hasTableNameMapping, bool hasCustomFields) + { + string path = string.Empty; + Socket server = null; + try { - string path = string.Empty; - Socket server = null; - try + int invocationCount = 0; + var exporterOptions = new GenevaExporterOptions { - int invocationCount = 0; - var exporterOptions = new GenevaExporterOptions - { - PrepopulatedFields = new Dictionary - { - ["cloud.role"] = "BusyWorker", - ["cloud.roleInstance"] = "CY1SCH030021417", - ["cloud.roleVer"] = "9.0.15289.2", - }, - }; - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + PrepopulatedFields = new Dictionary { - exporterOptions.ConnectionString = "EtwSession=OpenTelemetry"; - } - else - { - path = GetRandomFilePath(); - exporterOptions.ConnectionString = "Endpoint=unix:" + path; - var endpoint = new UnixDomainSocketEndPoint(path); - server = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); - server.Bind(endpoint); - server.Listen(1); - } - - if (hasTableNameMapping) - { - exporterOptions.TableNameMappings = new Dictionary { { "Span", "CustomActivity" } }; - } + ["cloud.role"] = "BusyWorker", + ["cloud.roleInstance"] = "CY1SCH030021417", + ["cloud.roleVer"] = "9.0.15289.2", + }, + }; + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + exporterOptions.ConnectionString = "EtwSession=OpenTelemetry"; + } + else + { + path = GetRandomFilePath(); + exporterOptions.ConnectionString = "Endpoint=unix:" + path; + var endpoint = new UnixDomainSocketEndPoint(path); + server = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); + server.Bind(endpoint); + server.Listen(1); + } - if (hasCustomFields) - { - // The tag "clientRequestId" should be present in the mapping as a separate key. Other tags which are not present - // in the m_dedicatedFields should be added in the mapping under "env_properties" - exporterOptions.CustomFields = new string[] { "clientRequestId" }; - } + if (hasTableNameMapping) + { + exporterOptions.TableNameMappings = new Dictionary { { "Span", "CustomActivity" } }; + } - using var exporter = new GenevaTraceExporter(exporterOptions); - var dedicatedFields = typeof(GenevaTraceExporter).GetField("m_dedicatedFields", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(exporter) as IReadOnlyDictionary; - var CS40_PART_B_MAPPING = typeof(GenevaTraceExporter).GetField("CS40_PART_B_MAPPING", BindingFlags.NonPublic | BindingFlags.Static).GetValue(exporter) as IReadOnlyDictionary; - var m_buffer = typeof(GenevaTraceExporter).GetField("m_buffer", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(exporter) as ThreadLocal; + if (hasCustomFields) + { + // The tag "clientRequestId" should be present in the mapping as a separate key. Other tags which are not present + // in the m_dedicatedFields should be added in the mapping under "env_properties" + exporterOptions.CustomFields = new string[] { "clientRequestId" }; + } - // Add an ActivityListener to serialize the activity and assert that it was valid on ActivityStopped event + using var exporter = new GenevaTraceExporter(exporterOptions); + var dedicatedFields = typeof(GenevaTraceExporter).GetField("m_dedicatedFields", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(exporter) as IReadOnlyDictionary; + var CS40_PART_B_MAPPING = typeof(GenevaTraceExporter).GetField("CS40_PART_B_MAPPING", BindingFlags.NonPublic | BindingFlags.Static).GetValue(exporter) as IReadOnlyDictionary; + var m_buffer = typeof(GenevaTraceExporter).GetField("m_buffer", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(exporter) as ThreadLocal; - // Set the ActivitySourceName to the unique value of the test method name to avoid interference with - // the ActivitySource used by other unit tests. - var sourceName = GetTestMethodName(); - Action> customChecksForActivity = null; + // Add an ActivityListener to serialize the activity and assert that it was valid on ActivityStopped event - using var listener = new ActivityListener(); - listener.ShouldListenTo = (activitySource) => activitySource.Name == sourceName; - listener.Sample = (ref ActivityCreationOptions options) => ActivitySamplingResult.AllDataAndRecorded; - listener.ActivityStopped = (activity) => - { - _ = exporter.SerializeActivity(activity); - object fluentdData = MessagePack.MessagePackSerializer.Deserialize(m_buffer.Value, MessagePack.Resolvers.ContractlessStandardResolver.Instance); - this.AssertFluentdForwardModeForActivity(exporterOptions, fluentdData, activity, CS40_PART_B_MAPPING, dedicatedFields, customChecksForActivity); - invocationCount++; - }; - ActivitySource.AddActivityListener(listener); + // Set the ActivitySourceName to the unique value of the test method name to avoid interference with + // the ActivitySource used by other unit tests. + var sourceName = GetTestMethodName(); + Action> customChecksForActivity = null; - using var source = new ActivitySource(sourceName); - using (var parentActivity = source.StartActivity("ParentActivity")) - { - var linkedtraceId1 = ActivityTraceId.CreateFromString("e8ea7e9ac72de94e91fabc613f9686a1".AsSpan()); - var linkedSpanId1 = ActivitySpanId.CreateFromString("888915b6286b9c01".AsSpan()); + using var listener = new ActivityListener(); + listener.ShouldListenTo = (activitySource) => activitySource.Name == sourceName; + listener.Sample = (ref ActivityCreationOptions options) => ActivitySamplingResult.AllDataAndRecorded; + listener.ActivityStopped = (activity) => + { + _ = exporter.SerializeActivity(activity); + object fluentdData = MessagePack.MessagePackSerializer.Deserialize(m_buffer.Value, MessagePack.Resolvers.ContractlessStandardResolver.Instance); + this.AssertFluentdForwardModeForActivity(exporterOptions, fluentdData, activity, CS40_PART_B_MAPPING, dedicatedFields, customChecksForActivity); + invocationCount++; + }; + ActivitySource.AddActivityListener(listener); + + using var source = new ActivitySource(sourceName); + using (var parentActivity = source.StartActivity("ParentActivity")) + { + var linkedtraceId1 = ActivityTraceId.CreateFromString("e8ea7e9ac72de94e91fabc613f9686a1".AsSpan()); + var linkedSpanId1 = ActivitySpanId.CreateFromString("888915b6286b9c01".AsSpan()); - var linkedtraceId2 = ActivityTraceId.CreateFromString("e8ea7e9ac72de94e91fabc613f9686a2".AsSpan()); - var linkedSpanId2 = ActivitySpanId.CreateFromString("888915b6286b9c02".AsSpan()); + var linkedtraceId2 = ActivityTraceId.CreateFromString("e8ea7e9ac72de94e91fabc613f9686a2".AsSpan()); + var linkedSpanId2 = ActivitySpanId.CreateFromString("888915b6286b9c02".AsSpan()); - var links = new[] - { + var links = new[] + { new ActivityLink(new ActivityContext( linkedtraceId1, linkedSpanId1, @@ -294,356 +293,355 @@ public void GenevaTraceExporter_Serialization_Success(bool hasTableNameMapping, linkedtraceId2, linkedSpanId2, ActivityTraceFlags.Recorded)), - }; - - using (var activity = source.StartActivity("SayHello", ActivityKind.Internal, parentActivity.Context, null, links)) - { - activity?.SetTag("http.status_code", 500); // This should be added as httpStatusCode in the mapping - activity?.SetTag("azureResourceProvider", "Microsoft.AAD"); - activity?.SetTag("clientRequestId", "58a37988-2c05-427a-891f-5e0e1266fcc5"); - activity?.SetTag("foo", 1); - activity?.SetTag("bar", 2); - activity?.SetStatus(Status.Error.WithDescription("Error description from OTel API")); - } - } - - using (var activity = source.StartActivity("TestActivityForSetStatusAPI")) - { - activity?.SetStatus(ActivityStatusCode.Error, "Error description from .NET API"); - } + }; - // If the activity Status is set using both the OTel API and the .NET API, the `Status` and `StatusDescription` set by - // the .NET API is chosen - using (var activity = source.StartActivity("PreferStatusFromDotnetAPI")) + using (var activity = source.StartActivity("SayHello", ActivityKind.Internal, parentActivity.Context, null, links)) { + activity?.SetTag("http.status_code", 500); // This should be added as httpStatusCode in the mapping + activity?.SetTag("azureResourceProvider", "Microsoft.AAD"); + activity?.SetTag("clientRequestId", "58a37988-2c05-427a-891f-5e0e1266fcc5"); + activity?.SetTag("foo", 1); + activity?.SetTag("bar", 2); activity?.SetStatus(Status.Error.WithDescription("Error description from OTel API")); - activity?.SetStatus(ActivityStatusCode.Error, "Error description from .NET API"); - customChecksForActivity = mapping => - { - Assert.Equal("Error description from .NET API", mapping["statusMessage"]); - }; } + } - Assert.Equal(4, invocationCount); + using (var activity = source.StartActivity("TestActivityForSetStatusAPI")) + { + activity?.SetStatus(ActivityStatusCode.Error, "Error description from .NET API"); } - finally + + // If the activity Status is set using both the OTel API and the .NET API, the `Status` and `StatusDescription` set by + // the .NET API is chosen + using (var activity = source.StartActivity("PreferStatusFromDotnetAPI")) { - server?.Dispose(); - try - { - File.Delete(path); - } - catch + activity?.SetStatus(Status.Error.WithDescription("Error description from OTel API")); + activity?.SetStatus(ActivityStatusCode.Error, "Error description from .NET API"); + customChecksForActivity = mapping => { - } + Assert.Equal("Error description from .NET API", mapping["statusMessage"]); + }; } - } - [Fact] - public void GenevaTraceExporter_Constructor_Missing_Agent_Linux() + Assert.Equal(4, invocationCount); + } + finally { - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + server?.Dispose(); + try { - string path = GetRandomFilePath(); + File.Delete(path); + } + catch + { + } + } + } - // System.Net.Internals.SocketExceptionFactory+ExtendedSocketException : Cannot assign requested address - try - { - // Set the ActivitySourceName to the unique value of the test method name to avoid interference with - // the ActivitySource used by other unit tests. - var sourceName = GetTestMethodName(); - using var tracerProvider = Sdk.CreateTracerProviderBuilder() - .SetSampler(new AlwaysOnSampler()) - .AddSource(sourceName) - .AddGenevaTraceExporter(options => - { - options.ConnectionString = "Endpoint=unix:" + path; - }) - .Build(); - Assert.True(false, "Should never reach here. GenevaTraceExporter should fail in constructor."); - } - catch (SocketException ex) - { - // There is no one to listent to the socket. - Assert.Contains("Cannot assign requested address", ex.Message); - } + [Fact] + public void GenevaTraceExporter_Constructor_Missing_Agent_Linux() + { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + string path = GetRandomFilePath(); - try - { - var exporter = new GenevaTraceExporter(new GenevaExporterOptions + // System.Net.Internals.SocketExceptionFactory+ExtendedSocketException : Cannot assign requested address + try + { + // Set the ActivitySourceName to the unique value of the test method name to avoid interference with + // the ActivitySource used by other unit tests. + var sourceName = GetTestMethodName(); + using var tracerProvider = Sdk.CreateTracerProviderBuilder() + .SetSampler(new AlwaysOnSampler()) + .AddSource(sourceName) + .AddGenevaTraceExporter(options => { - ConnectionString = "Endpoint=unix:" + path, - }); - Assert.True(false, "Should never reach here. GenevaTraceExporter should fail in constructor."); - } - catch (SocketException ex) + options.ConnectionString = "Endpoint=unix:" + path; + }) + .Build(); + Assert.True(false, "Should never reach here. GenevaTraceExporter should fail in constructor."); + } + catch (SocketException ex) + { + // There is no one to listent to the socket. + Assert.Contains("Cannot assign requested address", ex.Message); + } + + try + { + var exporter = new GenevaTraceExporter(new GenevaExporterOptions { - // There is no one to listent to the socket. - Assert.Contains("Cannot assign requested address", ex.Message); - } + ConnectionString = "Endpoint=unix:" + path, + }); + Assert.True(false, "Should never reach here. GenevaTraceExporter should fail in constructor."); + } + catch (SocketException ex) + { + // There is no one to listent to the socket. + Assert.Contains("Cannot assign requested address", ex.Message); } } + } - [Fact] - public void GenevaTraceExporter_Success_Linux() + [Fact] + public void GenevaTraceExporter_Success_Linux() + { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + string path = GetRandomFilePath(); + try { - string path = GetRandomFilePath(); - try - { - var endpoint = new UnixDomainSocketEndPoint(path); - using var server = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); - server.Bind(endpoint); - server.Listen(1); - - // Set the ActivitySourceName to the unique value of the test method name to avoid interference with - // the ActivitySource used by other unit tests. - var sourceName = GetTestMethodName(); - using var tracerProvider = Sdk.CreateTracerProviderBuilder() - .SetSampler(new AlwaysOnSampler()) - .AddSource(sourceName) - .AddGenevaTraceExporter(options => - { - options.ConnectionString = "Endpoint=unix:" + path; - options.PrepopulatedFields = new Dictionary - { - ["cloud.role"] = "BusyWorker", - ["cloud.roleInstance"] = "CY1SCH030021417", - ["cloud.roleVer"] = "9.0.15289.2", - }; - }) - .Build(); - using Socket serverSocket = server.Accept(); - serverSocket.ReceiveTimeout = 10000; - - // Create a test exporter to get MessagePack byte data for validation of the data received via Socket. - var exporter = new GenevaTraceExporter(new GenevaExporterOptions + var endpoint = new UnixDomainSocketEndPoint(path); + using var server = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); + server.Bind(endpoint); + server.Listen(1); + + // Set the ActivitySourceName to the unique value of the test method name to avoid interference with + // the ActivitySource used by other unit tests. + var sourceName = GetTestMethodName(); + using var tracerProvider = Sdk.CreateTracerProviderBuilder() + .SetSampler(new AlwaysOnSampler()) + .AddSource(sourceName) + .AddGenevaTraceExporter(options => { - ConnectionString = "Endpoint=unix:" + path, - PrepopulatedFields = new Dictionary + options.ConnectionString = "Endpoint=unix:" + path; + options.PrepopulatedFields = new Dictionary { ["cloud.role"] = "BusyWorker", ["cloud.roleInstance"] = "CY1SCH030021417", ["cloud.roleVer"] = "9.0.15289.2", - }, - }); - - // Emit trace and grab a copy of internal buffer for validation. - var source = new ActivitySource(sourceName); - int messagePackDataSize = 0; + }; + }) + .Build(); + using Socket serverSocket = server.Accept(); + serverSocket.ReceiveTimeout = 10000; - using (var activity = source.StartActivity("Foo", ActivityKind.Internal)) + // Create a test exporter to get MessagePack byte data for validation of the data received via Socket. + var exporter = new GenevaTraceExporter(new GenevaExporterOptions + { + ConnectionString = "Endpoint=unix:" + path, + PrepopulatedFields = new Dictionary { - messagePackDataSize = exporter.SerializeActivity(activity); - } - - // Read the data sent via socket. - var receivedData = new byte[1024]; - int receivedDataSize = serverSocket.Receive(receivedData); + ["cloud.role"] = "BusyWorker", + ["cloud.roleInstance"] = "CY1SCH030021417", + ["cloud.roleVer"] = "9.0.15289.2", + }, + }); - // Validation - Assert.Equal(messagePackDataSize, receivedDataSize); + // Emit trace and grab a copy of internal buffer for validation. + var source = new ActivitySource(sourceName); + int messagePackDataSize = 0; - // Create activity on a different thread to test for multithreading scenarios - var thread = new Thread(() => - { - using (var activity = source.StartActivity("ActivityFromAnotherThread", ActivityKind.Internal)) - { - messagePackDataSize = exporter.SerializeActivity(activity); - } - }); - thread.Start(); - thread.Join(); - - receivedDataSize = serverSocket.Receive(receivedData); - Assert.Equal(messagePackDataSize, receivedDataSize); - } - catch (Exception) + using (var activity = source.StartActivity("Foo", ActivityKind.Internal)) { - throw; + messagePackDataSize = exporter.SerializeActivity(activity); } - finally + + // Read the data sent via socket. + var receivedData = new byte[1024]; + int receivedDataSize = serverSocket.Receive(receivedData); + + // Validation + Assert.Equal(messagePackDataSize, receivedDataSize); + + // Create activity on a different thread to test for multithreading scenarios + var thread = new Thread(() => { - try - { - File.Delete(path); - } - catch + using (var activity = source.StartActivity("ActivityFromAnotherThread", ActivityKind.Internal)) { + messagePackDataSize = exporter.SerializeActivity(activity); } + }); + thread.Start(); + thread.Join(); + + receivedDataSize = serverSocket.Receive(receivedData); + Assert.Equal(messagePackDataSize, receivedDataSize); + } + catch (Exception) + { + throw; + } + finally + { + try + { + File.Delete(path); + } + catch + { } } } + } - private static string GetRandomFilePath() + private static string GetRandomFilePath() + { + while (true) { - while (true) + string path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + if (!File.Exists(path)) { - string path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); - if (!File.Exists(path)) - { - return path; - } + return path; } } + } - private static string GetTestMethodName([CallerMemberName] string callingMethodName = "") + private static string GetTestMethodName([CallerMemberName] string callingMethodName = "") + { + return callingMethodName; + } + + private void AssertFluentdForwardModeForActivity(GenevaExporterOptions exporterOptions, object fluentdData, Activity activity, IReadOnlyDictionary CS40_PART_B_MAPPING, IReadOnlyDictionary dedicatedFields, Action> customChecksForActivity) + { + /* Fluentd Forward Mode: + [ + "Span", + [ + [ , { "env_ver": "4.0", ... } ] + ], + { "TimeFormat": "DateTime" } + ] + */ + + var signal = (fluentdData as object[])[0] as string; + var TimeStampAndMappings = ((fluentdData as object[])[1] as object[])[0]; + var timeStamp = (DateTime)(TimeStampAndMappings as object[])[0]; + var mapping = (TimeStampAndMappings as object[])[1] as Dictionary; + var timeFormat = (fluentdData as object[])[2] as Dictionary; + + var partAName = "Span"; + if (exporterOptions.TableNameMappings != null) { - return callingMethodName; + partAName = exporterOptions.TableNameMappings["Span"]; } - private void AssertFluentdForwardModeForActivity(GenevaExporterOptions exporterOptions, object fluentdData, Activity activity, IReadOnlyDictionary CS40_PART_B_MAPPING, IReadOnlyDictionary dedicatedFields, Action> customChecksForActivity) - { - /* Fluentd Forward Mode: - [ - "Span", - [ - [ , { "env_ver": "4.0", ... } ] - ], - { "TimeFormat": "DateTime" } - ] - */ - - var signal = (fluentdData as object[])[0] as string; - var TimeStampAndMappings = ((fluentdData as object[])[1] as object[])[0]; - var timeStamp = (DateTime)(TimeStampAndMappings as object[])[0]; - var mapping = (TimeStampAndMappings as object[])[1] as Dictionary; - var timeFormat = (fluentdData as object[])[2] as Dictionary; - - var partAName = "Span"; - if (exporterOptions.TableNameMappings != null) - { - partAName = exporterOptions.TableNameMappings["Span"]; - } + Assert.Equal(partAName, signal); - Assert.Equal(partAName, signal); + // Timestamp check + var dtBegin = activity.StartTimeUtc; + var tsBegin = dtBegin.Ticks; + var tsEnd = tsBegin + activity.Duration.Ticks; + Assert.Equal(tsEnd, timeStamp.Ticks); - // Timestamp check - var dtBegin = activity.StartTimeUtc; - var tsBegin = dtBegin.Ticks; - var tsEnd = tsBegin + activity.Duration.Ticks; - Assert.Equal(tsEnd, timeStamp.Ticks); + // Part A core envelope fields - // Part A core envelope fields + var nameKey = GenevaBaseExporter.V40_PART_A_MAPPING[Schema.V40.PartA.Name]; - var nameKey = GenevaBaseExporter.V40_PART_A_MAPPING[Schema.V40.PartA.Name]; + // Check if the user has configured a custom table mapping + Assert.Equal(partAName, mapping[nameKey]); - // Check if the user has configured a custom table mapping - Assert.Equal(partAName, mapping[nameKey]); + // TODO: Update this when we support multiple Schema formats + var partAVer = "4.0"; + var verKey = GenevaBaseExporter.V40_PART_A_MAPPING[Schema.V40.PartA.Ver]; + Assert.Equal(partAVer, mapping[verKey]); - // TODO: Update this when we support multiple Schema formats - var partAVer = "4.0"; - var verKey = GenevaBaseExporter.V40_PART_A_MAPPING[Schema.V40.PartA.Ver]; - Assert.Equal(partAVer, mapping[verKey]); + foreach (var item in exporterOptions.PrepopulatedFields) + { + var partAValue = item.Value as string; + var partAKey = GenevaBaseExporter.V40_PART_A_MAPPING[item.Key]; + Assert.Equal(partAValue, mapping[partAKey]); + } - foreach (var item in exporterOptions.PrepopulatedFields) - { - var partAValue = item.Value as string; - var partAKey = GenevaBaseExporter.V40_PART_A_MAPPING[item.Key]; - Assert.Equal(partAValue, mapping[partAKey]); - } + var timeKey = GenevaBaseExporter.V40_PART_A_MAPPING[Schema.V40.PartA.Time]; + Assert.Equal(tsEnd, ((DateTime)mapping[timeKey]).Ticks); + + // Part A dt extensions + Assert.Equal(activity.TraceId.ToString(), mapping["env_dt_traceId"]); + Assert.Equal(activity.SpanId.ToString(), mapping["env_dt_spanId"]); - var timeKey = GenevaBaseExporter.V40_PART_A_MAPPING[Schema.V40.PartA.Time]; - Assert.Equal(tsEnd, ((DateTime)mapping[timeKey]).Ticks); + // Part B Span - required fields + Assert.Equal(activity.DisplayName, mapping["name"]); + Assert.Equal((byte)activity.Kind, mapping["kind"]); + Assert.Equal(activity.StartTimeUtc, mapping["startTime"]); - // Part A dt extensions - Assert.Equal(activity.TraceId.ToString(), mapping["env_dt_traceId"]); - Assert.Equal(activity.SpanId.ToString(), mapping["env_dt_spanId"]); + var activityStatusCode = activity.GetStatus().StatusCode; - // Part B Span - required fields - Assert.Equal(activity.DisplayName, mapping["name"]); - Assert.Equal((byte)activity.Kind, mapping["kind"]); - Assert.Equal(activity.StartTimeUtc, mapping["startTime"]); + if (activity.Status == ActivityStatusCode.Error) + { + Assert.False((bool)mapping["success"]); + Assert.Equal(activity.StatusDescription, mapping["statusMessage"]); + } + else if (activityStatusCode == StatusCode.Error) + { + Assert.False((bool)mapping["success"]); + var activityStatusDesc = activity.GetStatus().Description; + Assert.Equal(activityStatusDesc, mapping["statusMessage"]); + } + else + { + Assert.True((bool)mapping["success"]); + } - var activityStatusCode = activity.GetStatus().StatusCode; + // Part B Span optional fields and Part C fields + if (activity.ParentSpanId != default) + { + Assert.Equal(activity.ParentSpanId.ToHexString(), mapping["parentId"]); + } - if (activity.Status == ActivityStatusCode.Error) - { - Assert.False((bool)mapping["success"]); - Assert.Equal(activity.StatusDescription, mapping["statusMessage"]); - } - else if (activityStatusCode == StatusCode.Error) - { - Assert.False((bool)mapping["success"]); - var activityStatusDesc = activity.GetStatus().Description; - Assert.Equal(activityStatusDesc, mapping["statusMessage"]); - } - else + #region Assert Activity Links + if (activity.Links.Any()) + { + Assert.Contains(mapping, m => m.Key as string == "links"); + var mappingLinks = mapping["links"] as IEnumerable; + using IEnumerator activityLinksEnumerator = activity.Links.GetEnumerator(); + using IEnumerator mappingLinksEnumerator = mappingLinks.GetEnumerator(); + while (activityLinksEnumerator.MoveNext() && mappingLinksEnumerator.MoveNext()) { - Assert.True((bool)mapping["success"]); + var activityLink = activityLinksEnumerator.Current; + var mappingLink = mappingLinksEnumerator.Current as Dictionary; + + Assert.Equal(activityLink.Context.TraceId.ToHexString(), mappingLink["toTraceId"]); + Assert.Equal(activityLink.Context.SpanId.ToHexString(), mappingLink["toSpanId"]); } - // Part B Span optional fields and Part C fields - if (activity.ParentSpanId != default) + // Assert that mapping contains exactly the same number of ActivityLinks as present in the activity + // MoveNext() on both the enumerators should return false as we should have enumerated till the last element for both the Enumerables + Assert.Equal(activityLinksEnumerator.MoveNext(), mappingLinksEnumerator.MoveNext()); + } + else + { + Assert.DoesNotContain(mapping, m => m.Key as string == "links"); + } + #endregion + + #region Assert Activity Tags + _ = mapping.TryGetValue("env_properties", out object envProprties); + var envPropertiesMapping = envProprties as IDictionary; + foreach (var tag in activity.TagObjects) + { + if (CS40_PART_B_MAPPING.TryGetValue(tag.Key, out string replacementKey)) { - Assert.Equal(activity.ParentSpanId.ToHexString(), mapping["parentId"]); + Assert.Equal(tag.Value.ToString(), mapping[replacementKey].ToString()); } - - #region Assert Activity Links - if (activity.Links.Any()) + else if (string.Equals(tag.Key, "otel.status_code", StringComparison.Ordinal)) { - Assert.Contains(mapping, m => m.Key as string == "links"); - var mappingLinks = mapping["links"] as IEnumerable; - using IEnumerator activityLinksEnumerator = activity.Links.GetEnumerator(); - using IEnumerator mappingLinksEnumerator = mappingLinks.GetEnumerator(); - while (activityLinksEnumerator.MoveNext() && mappingLinksEnumerator.MoveNext()) - { - var activityLink = activityLinksEnumerator.Current; - var mappingLink = mappingLinksEnumerator.Current as Dictionary; - - Assert.Equal(activityLink.Context.TraceId.ToHexString(), mappingLink["toTraceId"]); - Assert.Equal(activityLink.Context.SpanId.ToHexString(), mappingLink["toSpanId"]); - } - - // Assert that mapping contains exactly the same number of ActivityLinks as present in the activity - // MoveNext() on both the enumerators should return false as we should have enumerated till the last element for both the Enumerables - Assert.Equal(activityLinksEnumerator.MoveNext(), mappingLinksEnumerator.MoveNext()); + // Status code check is already done when we check for "success" key in the mapping + continue; } - else + else if (string.Equals(tag.Key, "otel.status_description", StringComparison.Ordinal)) { - Assert.DoesNotContain(mapping, m => m.Key as string == "links"); + // Status description check is already done when we check for "statusMessage" key in the mapping + continue; } - #endregion - - #region Assert Activity Tags - _ = mapping.TryGetValue("env_properties", out object envProprties); - var envPropertiesMapping = envProprties as IDictionary; - foreach (var tag in activity.TagObjects) + else { - if (CS40_PART_B_MAPPING.TryGetValue(tag.Key, out string replacementKey)) + // If CustomFields are proivded, dedicatedFields will be populated + if (exporterOptions.CustomFields == null || dedicatedFields.ContainsKey(tag.Key)) { - Assert.Equal(tag.Value.ToString(), mapping[replacementKey].ToString()); - } - else if (string.Equals(tag.Key, "otel.status_code", StringComparison.Ordinal)) - { - // Status code check is already done when we check for "success" key in the mapping - continue; - } - else if (string.Equals(tag.Key, "otel.status_description", StringComparison.Ordinal)) - { - // Status description check is already done when we check for "statusMessage" key in the mapping - continue; + Assert.Equal(tag.Value.ToString(), mapping[tag.Key].ToString()); } else { - // If CustomFields are proivded, dedicatedFields will be populated - if (exporterOptions.CustomFields == null || dedicatedFields.ContainsKey(tag.Key)) - { - Assert.Equal(tag.Value.ToString(), mapping[tag.Key].ToString()); - } - else - { - Assert.Equal(tag.Value.ToString(), envPropertiesMapping[tag.Key].ToString()); - } + Assert.Equal(tag.Value.ToString(), envPropertiesMapping[tag.Key].ToString()); } } - #endregion + } + #endregion - // Epilouge - Assert.Equal("DateTime", timeFormat["TimeFormat"]); + // Epilouge + Assert.Equal("DateTime", timeFormat["TimeFormat"]); - customChecksForActivity?.Invoke(mapping); - } + customChecksForActivity?.Invoke(mapping); } } diff --git a/test/OpenTelemetry.Exporter.Geneva.Tests/MessagePackSerializerTests.cs b/test/OpenTelemetry.Exporter.Geneva.Tests/MessagePackSerializerTests.cs index a4b8dfda30..bb6e9ba212 100644 --- a/test/OpenTelemetry.Exporter.Geneva.Tests/MessagePackSerializerTests.cs +++ b/test/OpenTelemetry.Exporter.Geneva.Tests/MessagePackSerializerTests.cs @@ -20,376 +20,375 @@ using Xunit; using Xunit.Sdk; -namespace OpenTelemetry.Exporter.Geneva.Tests +namespace OpenTelemetry.Exporter.Geneva.Tests; + +public class MessagePackSerializerTests { - public class MessagePackSerializerTests + private void AssertBytes(byte[] expected, byte[] actual, int length) { - private void AssertBytes(byte[] expected, byte[] actual, int length) + Assert.Equal(expected.Length, length); + for (int i = 0; i < length; i++) { - Assert.Equal(expected.Length, length); - for (int i = 0; i < length; i++) - { - byte expectedByte = expected[i]; - byte actualByte = actual[i]; + byte expectedByte = expected[i]; + byte actualByte = actual[i]; - Assert.True( - expectedByte == actualByte, - string.Format($"Expected: '{(byte)expectedByte}', Actual: '{(byte)actualByte}' at offset {i}.")); - } + Assert.True( + expectedByte == actualByte, + string.Format($"Expected: '{(byte)expectedByte}', Actual: '{(byte)actualByte}' at offset {i}.")); } + } - private void MessagePackSerializer_TestSerialization(object obj) - { - var buffer = new byte[64 * 1024]; - var length = MessagePackSerializer.Serialize(buffer, 0, obj); - this.AssertBytes(MessagePack.MessagePackSerializer.Serialize(obj), buffer, length); - } + private void MessagePackSerializer_TestSerialization(object obj) + { + var buffer = new byte[64 * 1024]; + var length = MessagePackSerializer.Serialize(buffer, 0, obj); + this.AssertBytes(MessagePack.MessagePackSerializer.Serialize(obj), buffer, length); + } - private void MessagePackSerializer_TestASCIIStringSerialization(string input) + private void MessagePackSerializer_TestASCIIStringSerialization(string input) + { + var sizeLimit = (1 << 14) - 1; // // Max length of string allowed + var buffer = new byte[64 * 1024]; + var length = MessagePackSerializer.SerializeAsciiString(buffer, 0, input); + var deserializedString = MessagePack.MessagePackSerializer.Deserialize(buffer); + if (!string.IsNullOrEmpty(input) && input.Length > sizeLimit) { - var sizeLimit = (1 << 14) - 1; // // Max length of string allowed - var buffer = new byte[64 * 1024]; - var length = MessagePackSerializer.SerializeAsciiString(buffer, 0, input); - var deserializedString = MessagePack.MessagePackSerializer.Deserialize(buffer); - if (!string.IsNullOrEmpty(input) && input.Length > sizeLimit) - { - // We truncate the string using `.` in the last three characters which takes 3 bytes of memort - var byteCount = Encoding.ASCII.GetByteCount(input.Substring(0, sizeLimit - 3)) + 3; - Assert.Equal(0xDA, buffer[0]); - Assert.Equal(byteCount, (buffer[1] << 8) | buffer[2]); - Assert.Equal(byteCount, length - 3); // First three bytes are metadata - - Assert.NotEqual(input, deserializedString); + // We truncate the string using `.` in the last three characters which takes 3 bytes of memort + var byteCount = Encoding.ASCII.GetByteCount(input.Substring(0, sizeLimit - 3)) + 3; + Assert.Equal(0xDA, buffer[0]); + Assert.Equal(byteCount, (buffer[1] << 8) | buffer[2]); + Assert.Equal(byteCount, length - 3); // First three bytes are metadata - int i; - for (i = 0; i < sizeLimit - 3; i++) - { - Assert.Equal(input[i], deserializedString[i]); - } + Assert.NotEqual(input, deserializedString); - Assert.Equal('.', deserializedString[i++]); - Assert.Equal('.', deserializedString[i++]); - Assert.Equal('.', deserializedString[i++]); - } - else + int i; + for (i = 0; i < sizeLimit - 3; i++) { - if (input != null) - { - var byteCount = Encoding.ASCII.GetByteCount(input); - if (input.Length <= 31) - { - Assert.Equal(0xA0 | byteCount, buffer[0]); - Assert.Equal(byteCount, length - 1); // First one byte is metadata - } - else if (input.Length <= 255) - { - Assert.Equal(0xD9, buffer[0]); - Assert.Equal(byteCount, buffer[1]); - Assert.Equal(byteCount, length - 2); // First two bytes are metadata - } - else if (input.Length <= sizeLimit) - { - Assert.Equal(0xDA, buffer[0]); - Assert.Equal(byteCount, (buffer[1] << 8) | buffer[2]); - Assert.Equal(byteCount, length - 3); // First three bytes are metadata - } - } - - Assert.Equal(input, deserializedString); + Assert.Equal(input[i], deserializedString[i]); } - } - private void MessagePackSerializer_TestUnicodeStringSerialization(string input) + Assert.Equal('.', deserializedString[i++]); + Assert.Equal('.', deserializedString[i++]); + Assert.Equal('.', deserializedString[i++]); + } + else { - var sizeLimit = (1 << 14) - 1; // // Max length of string allowed - var buffer = new byte[64 * 1024]; - var length = MessagePackSerializer.SerializeUnicodeString(buffer, 0, input); - - var deserializedString = MessagePack.MessagePackSerializer.Deserialize(buffer); - if (!string.IsNullOrEmpty(input) && input.Length > sizeLimit) + if (input != null) { - // We truncate the string using `.` in the last three characters which takes 3 bytes of memory - var byteCount = Encoding.UTF8.GetByteCount(input.Substring(0, sizeLimit - 3)) + 3; - Assert.Equal(0xDA, buffer[0]); - Assert.Equal(byteCount, (buffer[1] << 8) | buffer[2]); - Assert.Equal(byteCount, length - 3); // First three bytes are metadata - - Assert.NotEqual(input, deserializedString); - - int i; - for (i = 0; i < sizeLimit - 3; i++) + var byteCount = Encoding.ASCII.GetByteCount(input); + if (input.Length <= 31) { - Assert.Equal(input[i], deserializedString[i]); + Assert.Equal(0xA0 | byteCount, buffer[0]); + Assert.Equal(byteCount, length - 1); // First one byte is metadata } - - Assert.Equal('.', deserializedString[i++]); - Assert.Equal('.', deserializedString[i++]); - Assert.Equal('.', deserializedString[i++]); - } - else - { - Assert.Equal(input, deserializedString); - - if (input != null) + else if (input.Length <= 255) + { + Assert.Equal(0xD9, buffer[0]); + Assert.Equal(byteCount, buffer[1]); + Assert.Equal(byteCount, length - 2); // First two bytes are metadata + } + else if (input.Length <= sizeLimit) { - var byteCount = Encoding.UTF8.GetByteCount(input); Assert.Equal(0xDA, buffer[0]); Assert.Equal(byteCount, (buffer[1] << 8) | buffer[2]); Assert.Equal(byteCount, length - 3); // First three bytes are metadata } } - } - [Fact] - public void MessagePackSerializer_Null() - { - this.MessagePackSerializer_TestSerialization(null); + Assert.Equal(input, deserializedString); } + } - [Fact] - public void MessagePackSerializer_Boolean() - { - this.MessagePackSerializer_TestSerialization(true); - this.MessagePackSerializer_TestSerialization(false); - } + private void MessagePackSerializer_TestUnicodeStringSerialization(string input) + { + var sizeLimit = (1 << 14) - 1; // // Max length of string allowed + var buffer = new byte[64 * 1024]; + var length = MessagePackSerializer.SerializeUnicodeString(buffer, 0, input); - [Fact] - public void MessagePackSerializer_Int() + var deserializedString = MessagePack.MessagePackSerializer.Deserialize(buffer); + if (!string.IsNullOrEmpty(input) && input.Length > sizeLimit) { - // 8 bits - for (sbyte value = sbyte.MinValue; value < sbyte.MaxValue; value++) - { - this.MessagePackSerializer_TestSerialization(value); - } + // We truncate the string using `.` in the last three characters which takes 3 bytes of memory + var byteCount = Encoding.UTF8.GetByteCount(input.Substring(0, sizeLimit - 3)) + 3; + Assert.Equal(0xDA, buffer[0]); + Assert.Equal(byteCount, (buffer[1] << 8) | buffer[2]); + Assert.Equal(byteCount, length - 3); // First three bytes are metadata - this.MessagePackSerializer_TestSerialization(sbyte.MaxValue); + Assert.NotEqual(input, deserializedString); - // 16 bits - for (short value = short.MinValue; value < short.MaxValue; value++) + int i; + for (i = 0; i < sizeLimit - 3; i++) { - this.MessagePackSerializer_TestSerialization(value); + Assert.Equal(input[i], deserializedString[i]); } - this.MessagePackSerializer_TestSerialization(short.MaxValue); + Assert.Equal('.', deserializedString[i++]); + Assert.Equal('.', deserializedString[i++]); + Assert.Equal('.', deserializedString[i++]); + } + else + { + Assert.Equal(input, deserializedString); - // 32 bits - this.MessagePackSerializer_TestSerialization(int.MinValue); - this.MessagePackSerializer_TestSerialization(int.MinValue + 1); - this.MessagePackSerializer_TestSerialization((int)short.MinValue - 1); - this.MessagePackSerializer_TestSerialization((int)short.MinValue); - this.MessagePackSerializer_TestSerialization((int)short.MinValue + 1); - this.MessagePackSerializer_TestSerialization((int)sbyte.MinValue - 1); - for (sbyte value = sbyte.MinValue; value < sbyte.MaxValue; value++) + if (input != null) { - this.MessagePackSerializer_TestSerialization((int)value); + var byteCount = Encoding.UTF8.GetByteCount(input); + Assert.Equal(0xDA, buffer[0]); + Assert.Equal(byteCount, (buffer[1] << 8) | buffer[2]); + Assert.Equal(byteCount, length - 3); // First three bytes are metadata } + } + } - this.MessagePackSerializer_TestSerialization((int)sbyte.MaxValue); - this.MessagePackSerializer_TestSerialization((int)sbyte.MaxValue + 1); - this.MessagePackSerializer_TestSerialization((int)short.MaxValue - 1); - this.MessagePackSerializer_TestSerialization((int)short.MaxValue); - this.MessagePackSerializer_TestSerialization((int)short.MaxValue + 1); - this.MessagePackSerializer_TestSerialization(int.MaxValue - 1); - this.MessagePackSerializer_TestSerialization(int.MaxValue); - - // 64 bits - this.MessagePackSerializer_TestSerialization(long.MinValue); - this.MessagePackSerializer_TestSerialization(long.MinValue + 1); - this.MessagePackSerializer_TestSerialization((long)int.MinValue - 1); - this.MessagePackSerializer_TestSerialization((long)int.MinValue); - this.MessagePackSerializer_TestSerialization((long)int.MinValue + 1); - this.MessagePackSerializer_TestSerialization((long)short.MinValue - 1); - this.MessagePackSerializer_TestSerialization((long)short.MinValue); - this.MessagePackSerializer_TestSerialization((long)short.MinValue + 1); - this.MessagePackSerializer_TestSerialization((long)sbyte.MinValue - 1); - for (sbyte value = sbyte.MinValue; value < sbyte.MaxValue; value++) - { - this.MessagePackSerializer_TestSerialization((long)value); - } + [Fact] + public void MessagePackSerializer_Null() + { + this.MessagePackSerializer_TestSerialization(null); + } - this.MessagePackSerializer_TestSerialization((long)sbyte.MaxValue); - this.MessagePackSerializer_TestSerialization((long)sbyte.MaxValue + 1); - this.MessagePackSerializer_TestSerialization((long)short.MaxValue - 1); - this.MessagePackSerializer_TestSerialization((long)short.MaxValue); - this.MessagePackSerializer_TestSerialization((long)short.MaxValue + 1); - this.MessagePackSerializer_TestSerialization((long)int.MaxValue - 1); - this.MessagePackSerializer_TestSerialization((long)int.MaxValue); - this.MessagePackSerializer_TestSerialization((long)int.MaxValue + 1); - this.MessagePackSerializer_TestSerialization(long.MaxValue - 1); - this.MessagePackSerializer_TestSerialization(long.MaxValue); - } + [Fact] + public void MessagePackSerializer_Boolean() + { + this.MessagePackSerializer_TestSerialization(true); + this.MessagePackSerializer_TestSerialization(false); + } - [Fact] - public void MessagePackSerializer_UInt() + [Fact] + public void MessagePackSerializer_Int() + { + // 8 bits + for (sbyte value = sbyte.MinValue; value < sbyte.MaxValue; value++) { - // 8 bits - for (byte value = byte.MinValue; value < byte.MaxValue; value++) - { - this.MessagePackSerializer_TestSerialization(value); - } - - this.MessagePackSerializer_TestSerialization(byte.MaxValue); + this.MessagePackSerializer_TestSerialization(value); + } - // 16 bits - for (ushort value = ushort.MinValue; value < ushort.MaxValue; value++) - { - this.MessagePackSerializer_TestSerialization(value); - } + this.MessagePackSerializer_TestSerialization(sbyte.MaxValue); - this.MessagePackSerializer_TestSerialization(ushort.MaxValue); - - // 32 bits - this.MessagePackSerializer_TestSerialization(uint.MinValue); - this.MessagePackSerializer_TestSerialization((uint)byte.MaxValue - 1); - this.MessagePackSerializer_TestSerialization((uint)byte.MaxValue); - this.MessagePackSerializer_TestSerialization((uint)byte.MaxValue + 1); - this.MessagePackSerializer_TestSerialization((uint)ushort.MaxValue - 1); - this.MessagePackSerializer_TestSerialization((uint)ushort.MaxValue); - this.MessagePackSerializer_TestSerialization((uint)ushort.MaxValue + 1); - this.MessagePackSerializer_TestSerialization(uint.MaxValue - 1); - this.MessagePackSerializer_TestSerialization(uint.MaxValue); - - // 64 bits - this.MessagePackSerializer_TestSerialization(ulong.MinValue); - this.MessagePackSerializer_TestSerialization((ulong)byte.MaxValue - 1); - this.MessagePackSerializer_TestSerialization((ulong)byte.MaxValue); - this.MessagePackSerializer_TestSerialization((ulong)byte.MaxValue + 1); - this.MessagePackSerializer_TestSerialization((ulong)ushort.MaxValue - 1); - this.MessagePackSerializer_TestSerialization((ulong)ushort.MaxValue); - this.MessagePackSerializer_TestSerialization((ulong)ushort.MaxValue + 1); - this.MessagePackSerializer_TestSerialization((ulong)uint.MaxValue - 1); - this.MessagePackSerializer_TestSerialization((ulong)uint.MaxValue); - this.MessagePackSerializer_TestSerialization((ulong)uint.MaxValue + 1); - this.MessagePackSerializer_TestSerialization(ulong.MaxValue - 1); - this.MessagePackSerializer_TestSerialization(ulong.MaxValue); + // 16 bits + for (short value = short.MinValue; value < short.MaxValue; value++) + { + this.MessagePackSerializer_TestSerialization(value); } - [Fact] - public void MessagePackSerializer_Float() + this.MessagePackSerializer_TestSerialization(short.MaxValue); + + // 32 bits + this.MessagePackSerializer_TestSerialization(int.MinValue); + this.MessagePackSerializer_TestSerialization(int.MinValue + 1); + this.MessagePackSerializer_TestSerialization((int)short.MinValue - 1); + this.MessagePackSerializer_TestSerialization((int)short.MinValue); + this.MessagePackSerializer_TestSerialization((int)short.MinValue + 1); + this.MessagePackSerializer_TestSerialization((int)sbyte.MinValue - 1); + for (sbyte value = sbyte.MinValue; value < sbyte.MaxValue; value++) { - this.MessagePackSerializer_TestSerialization(0.0f); - this.MessagePackSerializer_TestSerialization(1.0f); - this.MessagePackSerializer_TestSerialization(-123.45f); - this.MessagePackSerializer_TestSerialization(float.MaxValue); - this.MessagePackSerializer_TestSerialization(float.MinValue); - this.MessagePackSerializer_TestSerialization(float.PositiveInfinity); - this.MessagePackSerializer_TestSerialization(float.NegativeInfinity); - - this.MessagePackSerializer_TestSerialization(0.0d); - this.MessagePackSerializer_TestSerialization(3.1415926d); - this.MessagePackSerializer_TestSerialization(-67.89f); - this.MessagePackSerializer_TestSerialization(double.MaxValue); - this.MessagePackSerializer_TestSerialization(double.MinValue); - this.MessagePackSerializer_TestSerialization(double.PositiveInfinity); - this.MessagePackSerializer_TestSerialization(double.NegativeInfinity); + this.MessagePackSerializer_TestSerialization((int)value); } - [Fact] - public void MessagePackSerializer_SerializeAsciiString() + this.MessagePackSerializer_TestSerialization((int)sbyte.MaxValue); + this.MessagePackSerializer_TestSerialization((int)sbyte.MaxValue + 1); + this.MessagePackSerializer_TestSerialization((int)short.MaxValue - 1); + this.MessagePackSerializer_TestSerialization((int)short.MaxValue); + this.MessagePackSerializer_TestSerialization((int)short.MaxValue + 1); + this.MessagePackSerializer_TestSerialization(int.MaxValue - 1); + this.MessagePackSerializer_TestSerialization(int.MaxValue); + + // 64 bits + this.MessagePackSerializer_TestSerialization(long.MinValue); + this.MessagePackSerializer_TestSerialization(long.MinValue + 1); + this.MessagePackSerializer_TestSerialization((long)int.MinValue - 1); + this.MessagePackSerializer_TestSerialization((long)int.MinValue); + this.MessagePackSerializer_TestSerialization((long)int.MinValue + 1); + this.MessagePackSerializer_TestSerialization((long)short.MinValue - 1); + this.MessagePackSerializer_TestSerialization((long)short.MinValue); + this.MessagePackSerializer_TestSerialization((long)short.MinValue + 1); + this.MessagePackSerializer_TestSerialization((long)sbyte.MinValue - 1); + for (sbyte value = sbyte.MinValue; value < sbyte.MaxValue; value++) { - this.MessagePackSerializer_TestASCIIStringSerialization(null); - this.MessagePackSerializer_TestASCIIStringSerialization(string.Empty); - this.MessagePackSerializer_TestASCIIStringSerialization("Hello world!"); - - // fixstr stores a byte array whose length is upto 31 bytes - this.MessagePackSerializer_TestASCIIStringSerialization("1234567890123456789012345678901"); - - // str 8 stores a byte array whose length is upto (2^8)-1 bytes - this.MessagePackSerializer_TestASCIIStringSerialization("12345678901234567890123456789012"); - this.MessagePackSerializer_TestASCIIStringSerialization(new string('A', byte.MaxValue)); - this.MessagePackSerializer_TestASCIIStringSerialization(new string('B', byte.MaxValue + 1)); - this.MessagePackSerializer_TestASCIIStringSerialization(new string('Z', (1 << 14) - 1)); - this.MessagePackSerializer_TestASCIIStringSerialization(new string('Z', 1 << 14)); - - // Unicode special characters - // SerializeAsciiString will encode non-ASCII characters with '?' - Assert.Throws(() => this.MessagePackSerializer_TestASCIIStringSerialization("\u0418")); + this.MessagePackSerializer_TestSerialization((long)value); } - [Fact] - public void MessagePackSerializer_SerializeUnicodeString() + this.MessagePackSerializer_TestSerialization((long)sbyte.MaxValue); + this.MessagePackSerializer_TestSerialization((long)sbyte.MaxValue + 1); + this.MessagePackSerializer_TestSerialization((long)short.MaxValue - 1); + this.MessagePackSerializer_TestSerialization((long)short.MaxValue); + this.MessagePackSerializer_TestSerialization((long)short.MaxValue + 1); + this.MessagePackSerializer_TestSerialization((long)int.MaxValue - 1); + this.MessagePackSerializer_TestSerialization((long)int.MaxValue); + this.MessagePackSerializer_TestSerialization((long)int.MaxValue + 1); + this.MessagePackSerializer_TestSerialization(long.MaxValue - 1); + this.MessagePackSerializer_TestSerialization(long.MaxValue); + } + + [Fact] + public void MessagePackSerializer_UInt() + { + // 8 bits + for (byte value = byte.MinValue; value < byte.MaxValue; value++) { - this.MessagePackSerializer_TestUnicodeStringSerialization(null); - this.MessagePackSerializer_TestUnicodeStringSerialization(string.Empty); - this.MessagePackSerializer_TestUnicodeStringSerialization("Hello world!"); - - // fixstr stores a byte array whose length is upto 31 bytes - this.MessagePackSerializer_TestUnicodeStringSerialization("1234567890123456789012345678901"); - - // str 8 stores a byte array whose length is upto (2^8)-1 bytes - this.MessagePackSerializer_TestUnicodeStringSerialization("12345678901234567890123456789012"); - this.MessagePackSerializer_TestUnicodeStringSerialization(new string('A', byte.MaxValue)); - this.MessagePackSerializer_TestUnicodeStringSerialization(new string('B', byte.MaxValue + 1)); - this.MessagePackSerializer_TestUnicodeStringSerialization(new string('Z', (1 << 14) - 1)); - this.MessagePackSerializer_TestUnicodeStringSerialization(new string('Z', 1 << 14)); - - // ill-formed UTF-8 sequence - // This is replaced by `U+FFFD REPLACEMENT CHARACTER` in the returned string instance constructed from the byte array - // TODO: Update this test case once the serializer starts to throw exception for ill-formed UTF-8 sequence. - Assert.Throws(() => this.MessagePackSerializer_TestUnicodeStringSerialization("\uD801\uD802")); - - // Unicode special characters - this.MessagePackSerializer_TestUnicodeStringSerialization("\u0418"); - this.MessagePackSerializer_TestUnicodeStringSerialization(new string('\u0418', 31)); - this.MessagePackSerializer_TestUnicodeStringSerialization(new string('\u0418', 50)); - this.MessagePackSerializer_TestUnicodeStringSerialization(new string('\u0418', (1 << 8) - 1)); - this.MessagePackSerializer_TestUnicodeStringSerialization(new string('\u0418', 1 << 10)); - this.MessagePackSerializer_TestUnicodeStringSerialization(new string('\u0418', (1 << 14) - 1)); - this.MessagePackSerializer_TestUnicodeStringSerialization(new string('\u0418', 1 << 14)); - - // Unicode regular and special characters - this.MessagePackSerializer_TestUnicodeStringSerialization("\u0418TestString"); - this.MessagePackSerializer_TestUnicodeStringSerialization("TestString\u0418"); - this.MessagePackSerializer_TestUnicodeStringSerialization("Test\u0418String"); + this.MessagePackSerializer_TestSerialization(value); } - [Fact] - public void MessagePackSerializer_Array() - { - this.MessagePackSerializer_TestSerialization((object[])null); - this.MessagePackSerializer_TestSerialization(new object[0]); + this.MessagePackSerializer_TestSerialization(byte.MaxValue); - // This object array has a custom string which will be serialized as STR16 - var objectArrayWithString = new object[] - { - "foo", - 1, - 0.6180340f, - 3.14159265358979323846264d, - }; - - var buffer = new byte[64 * 1024]; - _ = MessagePackSerializer.Serialize(buffer, 0, objectArrayWithString); - var objectArrayWithStringDeserialized = MessagePack.MessagePackSerializer.Deserialize(buffer); - Assert.Equal(objectArrayWithString.Length, objectArrayWithStringDeserialized.Length); - Assert.Equal(objectArrayWithString[0], objectArrayWithStringDeserialized[0]); - Assert.Equal(objectArrayWithString[1], Convert.ToInt32(objectArrayWithStringDeserialized[1])); - Assert.Equal(objectArrayWithString[2], objectArrayWithStringDeserialized[2]); - Assert.Equal(objectArrayWithString[3], objectArrayWithStringDeserialized[3]); + // 16 bits + for (ushort value = ushort.MinValue; value < ushort.MaxValue; value++) + { + this.MessagePackSerializer_TestSerialization(value); } - [Fact] - public void MessagePackSerializer_Map() + this.MessagePackSerializer_TestSerialization(ushort.MaxValue); + + // 32 bits + this.MessagePackSerializer_TestSerialization(uint.MinValue); + this.MessagePackSerializer_TestSerialization((uint)byte.MaxValue - 1); + this.MessagePackSerializer_TestSerialization((uint)byte.MaxValue); + this.MessagePackSerializer_TestSerialization((uint)byte.MaxValue + 1); + this.MessagePackSerializer_TestSerialization((uint)ushort.MaxValue - 1); + this.MessagePackSerializer_TestSerialization((uint)ushort.MaxValue); + this.MessagePackSerializer_TestSerialization((uint)ushort.MaxValue + 1); + this.MessagePackSerializer_TestSerialization(uint.MaxValue - 1); + this.MessagePackSerializer_TestSerialization(uint.MaxValue); + + // 64 bits + this.MessagePackSerializer_TestSerialization(ulong.MinValue); + this.MessagePackSerializer_TestSerialization((ulong)byte.MaxValue - 1); + this.MessagePackSerializer_TestSerialization((ulong)byte.MaxValue); + this.MessagePackSerializer_TestSerialization((ulong)byte.MaxValue + 1); + this.MessagePackSerializer_TestSerialization((ulong)ushort.MaxValue - 1); + this.MessagePackSerializer_TestSerialization((ulong)ushort.MaxValue); + this.MessagePackSerializer_TestSerialization((ulong)ushort.MaxValue + 1); + this.MessagePackSerializer_TestSerialization((ulong)uint.MaxValue - 1); + this.MessagePackSerializer_TestSerialization((ulong)uint.MaxValue); + this.MessagePackSerializer_TestSerialization((ulong)uint.MaxValue + 1); + this.MessagePackSerializer_TestSerialization(ulong.MaxValue - 1); + this.MessagePackSerializer_TestSerialization(ulong.MaxValue); + } + + [Fact] + public void MessagePackSerializer_Float() + { + this.MessagePackSerializer_TestSerialization(0.0f); + this.MessagePackSerializer_TestSerialization(1.0f); + this.MessagePackSerializer_TestSerialization(-123.45f); + this.MessagePackSerializer_TestSerialization(float.MaxValue); + this.MessagePackSerializer_TestSerialization(float.MinValue); + this.MessagePackSerializer_TestSerialization(float.PositiveInfinity); + this.MessagePackSerializer_TestSerialization(float.NegativeInfinity); + + this.MessagePackSerializer_TestSerialization(0.0d); + this.MessagePackSerializer_TestSerialization(3.1415926d); + this.MessagePackSerializer_TestSerialization(-67.89f); + this.MessagePackSerializer_TestSerialization(double.MaxValue); + this.MessagePackSerializer_TestSerialization(double.MinValue); + this.MessagePackSerializer_TestSerialization(double.PositiveInfinity); + this.MessagePackSerializer_TestSerialization(double.NegativeInfinity); + } + + [Fact] + public void MessagePackSerializer_SerializeAsciiString() + { + this.MessagePackSerializer_TestASCIIStringSerialization(null); + this.MessagePackSerializer_TestASCIIStringSerialization(string.Empty); + this.MessagePackSerializer_TestASCIIStringSerialization("Hello world!"); + + // fixstr stores a byte array whose length is upto 31 bytes + this.MessagePackSerializer_TestASCIIStringSerialization("1234567890123456789012345678901"); + + // str 8 stores a byte array whose length is upto (2^8)-1 bytes + this.MessagePackSerializer_TestASCIIStringSerialization("12345678901234567890123456789012"); + this.MessagePackSerializer_TestASCIIStringSerialization(new string('A', byte.MaxValue)); + this.MessagePackSerializer_TestASCIIStringSerialization(new string('B', byte.MaxValue + 1)); + this.MessagePackSerializer_TestASCIIStringSerialization(new string('Z', (1 << 14) - 1)); + this.MessagePackSerializer_TestASCIIStringSerialization(new string('Z', 1 << 14)); + + // Unicode special characters + // SerializeAsciiString will encode non-ASCII characters with '?' + Assert.Throws(() => this.MessagePackSerializer_TestASCIIStringSerialization("\u0418")); + } + + [Fact] + public void MessagePackSerializer_SerializeUnicodeString() + { + this.MessagePackSerializer_TestUnicodeStringSerialization(null); + this.MessagePackSerializer_TestUnicodeStringSerialization(string.Empty); + this.MessagePackSerializer_TestUnicodeStringSerialization("Hello world!"); + + // fixstr stores a byte array whose length is upto 31 bytes + this.MessagePackSerializer_TestUnicodeStringSerialization("1234567890123456789012345678901"); + + // str 8 stores a byte array whose length is upto (2^8)-1 bytes + this.MessagePackSerializer_TestUnicodeStringSerialization("12345678901234567890123456789012"); + this.MessagePackSerializer_TestUnicodeStringSerialization(new string('A', byte.MaxValue)); + this.MessagePackSerializer_TestUnicodeStringSerialization(new string('B', byte.MaxValue + 1)); + this.MessagePackSerializer_TestUnicodeStringSerialization(new string('Z', (1 << 14) - 1)); + this.MessagePackSerializer_TestUnicodeStringSerialization(new string('Z', 1 << 14)); + + // ill-formed UTF-8 sequence + // This is replaced by `U+FFFD REPLACEMENT CHARACTER` in the returned string instance constructed from the byte array + // TODO: Update this test case once the serializer starts to throw exception for ill-formed UTF-8 sequence. + Assert.Throws(() => this.MessagePackSerializer_TestUnicodeStringSerialization("\uD801\uD802")); + + // Unicode special characters + this.MessagePackSerializer_TestUnicodeStringSerialization("\u0418"); + this.MessagePackSerializer_TestUnicodeStringSerialization(new string('\u0418', 31)); + this.MessagePackSerializer_TestUnicodeStringSerialization(new string('\u0418', 50)); + this.MessagePackSerializer_TestUnicodeStringSerialization(new string('\u0418', (1 << 8) - 1)); + this.MessagePackSerializer_TestUnicodeStringSerialization(new string('\u0418', 1 << 10)); + this.MessagePackSerializer_TestUnicodeStringSerialization(new string('\u0418', (1 << 14) - 1)); + this.MessagePackSerializer_TestUnicodeStringSerialization(new string('\u0418', 1 << 14)); + + // Unicode regular and special characters + this.MessagePackSerializer_TestUnicodeStringSerialization("\u0418TestString"); + this.MessagePackSerializer_TestUnicodeStringSerialization("TestString\u0418"); + this.MessagePackSerializer_TestUnicodeStringSerialization("Test\u0418String"); + } + + [Fact] + public void MessagePackSerializer_Array() + { + this.MessagePackSerializer_TestSerialization((object[])null); + this.MessagePackSerializer_TestSerialization(new object[0]); + + // This object array has a custom string which will be serialized as STR16 + var objectArrayWithString = new object[] { - this.MessagePackSerializer_TestSerialization((Dictionary)null); - this.MessagePackSerializer_TestSerialization(new Dictionary()); + "foo", + 1, + 0.6180340f, + 3.14159265358979323846264d, + }; + + var buffer = new byte[64 * 1024]; + _ = MessagePackSerializer.Serialize(buffer, 0, objectArrayWithString); + var objectArrayWithStringDeserialized = MessagePack.MessagePackSerializer.Deserialize(buffer); + Assert.Equal(objectArrayWithString.Length, objectArrayWithStringDeserialized.Length); + Assert.Equal(objectArrayWithString[0], objectArrayWithStringDeserialized[0]); + Assert.Equal(objectArrayWithString[1], Convert.ToInt32(objectArrayWithStringDeserialized[1])); + Assert.Equal(objectArrayWithString[2], objectArrayWithStringDeserialized[2]); + Assert.Equal(objectArrayWithString[3], objectArrayWithStringDeserialized[3]); + } - // This dictionary has custom strings which will be serialized as STR16 - var dictionaryWithStrings = new Dictionary - { - ["foo"] = 1, - ["bar"] = "baz", - ["golden ratio"] = 0.6180340f, - ["pi"] = 3.14159265358979323846264d, - }; - var buffer = new byte[64 * 1024]; - _ = MessagePackSerializer.Serialize(buffer, 0, dictionaryWithStrings); - var dictionaryWithStringsDeserialized = MessagePack.MessagePackSerializer.Deserialize>(buffer); - Assert.Equal(dictionaryWithStrings.Count, dictionaryWithStringsDeserialized.Count); - Assert.Equal(dictionaryWithStrings["foo"], Convert.ToInt32(dictionaryWithStringsDeserialized["foo"])); - Assert.Equal(dictionaryWithStrings["bar"], dictionaryWithStringsDeserialized["bar"]); - Assert.Equal(dictionaryWithStrings["golden ratio"], dictionaryWithStringsDeserialized["golden ratio"]); - Assert.Equal(dictionaryWithStrings["pi"], dictionaryWithStringsDeserialized["pi"]); - } + [Fact] + public void MessagePackSerializer_Map() + { + this.MessagePackSerializer_TestSerialization((Dictionary)null); + this.MessagePackSerializer_TestSerialization(new Dictionary()); + + // This dictionary has custom strings which will be serialized as STR16 + var dictionaryWithStrings = new Dictionary + { + ["foo"] = 1, + ["bar"] = "baz", + ["golden ratio"] = 0.6180340f, + ["pi"] = 3.14159265358979323846264d, + }; + var buffer = new byte[64 * 1024]; + _ = MessagePackSerializer.Serialize(buffer, 0, dictionaryWithStrings); + var dictionaryWithStringsDeserialized = MessagePack.MessagePackSerializer.Deserialize>(buffer); + Assert.Equal(dictionaryWithStrings.Count, dictionaryWithStringsDeserialized.Count); + Assert.Equal(dictionaryWithStrings["foo"], Convert.ToInt32(dictionaryWithStringsDeserialized["foo"])); + Assert.Equal(dictionaryWithStrings["bar"], dictionaryWithStringsDeserialized["bar"]); + Assert.Equal(dictionaryWithStrings["golden ratio"], dictionaryWithStringsDeserialized["golden ratio"]); + Assert.Equal(dictionaryWithStrings["pi"], dictionaryWithStringsDeserialized["pi"]); } } diff --git a/test/OpenTelemetry.Exporter.Geneva.Tests/MetricsContract.cs b/test/OpenTelemetry.Exporter.Geneva.Tests/MetricsContract.cs index c03dda9252..d14dcbf93f 100644 --- a/test/OpenTelemetry.Exporter.Geneva.Tests/MetricsContract.cs +++ b/test/OpenTelemetry.Exporter.Geneva.Tests/MetricsContract.cs @@ -1,665 +1,664 @@ -// +// using System.Collections.Generic; using Kaitai; -namespace OpenTelemetry.Exporter.Geneva.Tests +namespace OpenTelemetry.Exporter.Geneva.Tests; + +public partial class MetricsContract : KaitaiStruct { - public partial class MetricsContract : KaitaiStruct + public static MetricsContract FromFile(string fileName) { - public static MetricsContract FromFile(string fileName) - { - return new MetricsContract(new KaitaiStream(fileName)); - } + return new MetricsContract(new KaitaiStream(fileName)); + } - public enum MetricEventType - { - Old = 0, - Uint64Metric = 50, - DoubleScaledToLongMetric = 51, - BatchMetric = 52, - ExternallyAggregatedUlongMetric = 53, - ExternallyAggregatedDoubleMetric = 54, - DoubleMetric = 55, - ExternallyAggregatedUlongDistributionMetric = 56, - ExternallyAggregatedDoubleDistributionMetric = 57, - ExternallyAggregatedDoubleScaledToLongDistributionMetric = 58, - } + public enum MetricEventType + { + Old = 0, + Uint64Metric = 50, + DoubleScaledToLongMetric = 51, + BatchMetric = 52, + ExternallyAggregatedUlongMetric = 53, + ExternallyAggregatedDoubleMetric = 54, + DoubleMetric = 55, + ExternallyAggregatedUlongDistributionMetric = 56, + ExternallyAggregatedDoubleDistributionMetric = 57, + ExternallyAggregatedDoubleScaledToLongDistributionMetric = 58, + } - public enum DistributionType - { - Bucketed = 0, - MonBucketed = 1, - ValueCountPairs = 2, - } - public MetricsContract(KaitaiStream p__io, KaitaiStruct p__parent = null, MetricsContract p__root = null) + public enum DistributionType + { + Bucketed = 0, + MonBucketed = 1, + ValueCountPairs = 2, + } + public MetricsContract(KaitaiStream p__io, KaitaiStruct p__parent = null, MetricsContract p__root = null) + : base(p__io) + { + this.m_parent = p__parent; + this.m_root = p__root ?? this; + this._read(); + } + private void _read() + { + this._eventId = this.m_io.ReadU2le(); + this._lenBody = this.m_io.ReadU2le(); + this.__raw_body = this.m_io.ReadBytes(this.LenBody); + var io___raw_body = new KaitaiStream(this.__raw_body); + this._body = new Userdata(this.EventId, io___raw_body, this, this.m_root); + } + + /// + /// This type represents "UserData" or "body" portion of Metrics message. + /// + public partial class Userdata : KaitaiStruct + { + public Userdata(ushort p_eventId, KaitaiStream p__io, MetricsContract p__parent = null, MetricsContract p__root = null) : base(p__io) { this.m_parent = p__parent; - this.m_root = p__root ?? this; + this.m_root = p__root; + this._eventId = p_eventId; + this.f_eventType = false; this._read(); } private void _read() { - this._eventId = this.m_io.ReadU2le(); - this._lenBody = this.m_io.ReadU2le(); - this.__raw_body = this.m_io.ReadBytes(this.LenBody); - var io___raw_body = new KaitaiStream(this.__raw_body); - this._body = new Userdata(this.EventId, io___raw_body, this, this.m_root); - } - - /// - /// This type represents "UserData" or "body" portion of Metrics message. - /// - public partial class Userdata : KaitaiStruct - { - public Userdata(ushort p_eventId, KaitaiStream p__io, MetricsContract p__parent = null, MetricsContract p__root = null) - : base(p__io) - { - this.m_parent = p__parent; - this.m_root = p__root; - this._eventId = p_eventId; - this.f_eventType = false; - this._read(); - } - private void _read() + this._numDimensions = this.m_io.ReadU2le(); + this._padding = this.m_io.ReadBytes(2); + switch (this.EventType) { - this._numDimensions = this.m_io.ReadU2le(); - this._padding = this.m_io.ReadBytes(2); - switch (this.EventType) + case MetricsContract.MetricEventType.ExternallyAggregatedDoubleScaledToLongDistributionMetric: { - case MetricsContract.MetricEventType.ExternallyAggregatedDoubleScaledToLongDistributionMetric: - { - this._valueSection = new ExtAggregatedDoubleValue(this.m_io, this, this.m_root); - break; - } - case MetricsContract.MetricEventType.DoubleMetric: - { - this._valueSection = new SingleDoubleValue(this.m_io, this, this.m_root); - break; - } - case MetricsContract.MetricEventType.ExternallyAggregatedUlongMetric: - { - this._valueSection = new ExtAggregatedUint64Value(this.m_io, this, this.m_root); - break; - } - case MetricsContract.MetricEventType.ExternallyAggregatedUlongDistributionMetric: - { - this._valueSection = new ExtAggregatedUint64Value(this.m_io, this, this.m_root); - break; - } - case MetricsContract.MetricEventType.ExternallyAggregatedDoubleDistributionMetric: - { - this._valueSection = new ExtAggregatedDoubleValue(this.m_io, this, this.m_root); - break; - } - case MetricsContract.MetricEventType.DoubleScaledToLongMetric: - { - this._valueSection = new SingleDoubleValue(this.m_io, this, this.m_root); - break; - } - case MetricsContract.MetricEventType.Uint64Metric: - { - this._valueSection = new SingleUint64Value(this.m_io, this, this.m_root); - break; - } - case MetricsContract.MetricEventType.ExternallyAggregatedDoubleMetric: - { - this._valueSection = new ExtAggregatedDoubleValue(this.m_io, this, this.m_root); - break; - } - case MetricsContract.MetricEventType.Old: - { - this._valueSection = new SingleUint64Value(this.m_io, this, this.m_root); - break; - } + this._valueSection = new ExtAggregatedDoubleValue(this.m_io, this, this.m_root); + break; } - this._metricAccount = new LenString(this.m_io, this, this.m_root); - this._metricNamespace = new LenString(this.m_io, this, this.m_root); - this._metricName = new LenString(this.m_io, this, this.m_root); - this._dimensionsNames = new List((int)this.NumDimensions); - for (var i = 0; i < this.NumDimensions; i++) + case MetricsContract.MetricEventType.DoubleMetric: { - this._dimensionsNames.Add(new LenString(this.m_io, this, this.m_root)); + this._valueSection = new SingleDoubleValue(this.m_io, this, this.m_root); + break; } - this._dimensionsValues = new List((int)this.NumDimensions); - for (var i = 0; i < this.NumDimensions; i++) + case MetricsContract.MetricEventType.ExternallyAggregatedUlongMetric: { - this._dimensionsValues.Add(new LenString(this.m_io, this, this.m_root)); + this._valueSection = new ExtAggregatedUint64Value(this.m_io, this, this.m_root); + break; } - if (!this.M_Io.IsEof) + case MetricsContract.MetricEventType.ExternallyAggregatedUlongDistributionMetric: { - this._apContainer = new LenString(this.m_io, this, this.m_root); + this._valueSection = new ExtAggregatedUint64Value(this.m_io, this, this.m_root); + break; } - if (((this.EventType == MetricsContract.MetricEventType.ExternallyAggregatedUlongDistributionMetric) || (this.EventType == MetricsContract.MetricEventType.ExternallyAggregatedDoubleDistributionMetric) || (this.EventType == MetricsContract.MetricEventType.ExternallyAggregatedDoubleScaledToLongDistributionMetric)) && (!this.M_Io.IsEof)) + case MetricsContract.MetricEventType.ExternallyAggregatedDoubleDistributionMetric: { - this._histogram = new Histogram(this.m_io, this, this.m_root); + this._valueSection = new ExtAggregatedDoubleValue(this.m_io, this, this.m_root); + break; } - } - private bool f_eventType; - private MetricEventType _eventType; - public MetricEventType EventType - { - get + case MetricsContract.MetricEventType.DoubleScaledToLongMetric: { - if (this.f_eventType) - return this._eventType; - this._eventType = (MetricEventType)(MetricsContract.MetricEventType)this.EventId; - this.f_eventType = true; - return this._eventType; + this._valueSection = new SingleDoubleValue(this.m_io, this, this.m_root); + break; + } + case MetricsContract.MetricEventType.Uint64Metric: + { + this._valueSection = new SingleUint64Value(this.m_io, this, this.m_root); + break; + } + case MetricsContract.MetricEventType.ExternallyAggregatedDoubleMetric: + { + this._valueSection = new ExtAggregatedDoubleValue(this.m_io, this, this.m_root); + break; + } + case MetricsContract.MetricEventType.Old: + { + this._valueSection = new SingleUint64Value(this.m_io, this, this.m_root); + break; } } - private ushort _numDimensions; - private byte[] _padding; - private KaitaiStruct _valueSection; - private LenString _metricAccount; - private LenString _metricNamespace; - private LenString _metricName; - private List _dimensionsNames; - private List _dimensionsValues; - private LenString _apContainer; - private Histogram _histogram; - private ushort _eventId; - private MetricsContract m_root; - private MetricsContract m_parent; - - /// - /// Number of dimensions specified in this event. - /// - public ushort NumDimensions { get { return this._numDimensions; } } - public byte[] Padding { get { return this._padding; } } - - /// - /// Value section of the body, stores fixed numeric metric value(s), as per event type. - /// - public KaitaiStruct ValueSection { get { return this._valueSection; } } - - /// - /// Geneva Metrics account name to be used for this metric. - /// - public LenString MetricAccount { get { return this._metricAccount; } } - - /// - /// Geneva Metrics namespace name to be used for this metric. - /// - public LenString MetricNamespace { get { return this._metricNamespace; } } - - /// - /// Geneva Metrics metric name to be used. - /// - public LenString MetricName { get { return this._metricName; } } - - /// - /// Dimension names strings ("key" parts of key-value pairs). Must be sorted, - /// unless MetricsExtenion's option `enableDimensionSortingOnIngestion` is - /// enabled. - /// - public List DimensionsNames { get { return this._dimensionsNames; } } - - /// - /// Dimension values strings ("value" parts of key-value pairs). - /// - public List DimensionsValues { get { return this._dimensionsValues; } } - - /// - /// AutoPilot container string, required for correct AP PKI certificate loading - /// in AutoPilot containers environment. - /// - public LenString ApContainer { get { return this._apContainer; } } - public Histogram Histogram { get { return this._histogram; } } - - /// - /// Type of message, affects format of the body. - /// - public ushort EventId { get { return this._eventId; } } - public MetricsContract M_Root { get { return this.m_root; } } - public MetricsContract M_Parent { get { return this.m_parent; } } - } - - /// - /// Bucket with an explicitly-defined value coordinate `value`, claiming to - /// hold `count` hits. Normally used to represent non-linear (e.g. exponential) - /// histograms payloads. - /// - public partial class PairValueCount : KaitaiStruct - { - public static PairValueCount FromFile(string fileName) + this._metricAccount = new LenString(this.m_io, this, this.m_root); + this._metricNamespace = new LenString(this.m_io, this, this.m_root); + this._metricName = new LenString(this.m_io, this, this.m_root); + this._dimensionsNames = new List((int)this.NumDimensions); + for (var i = 0; i < this.NumDimensions; i++) { - return new PairValueCount(new KaitaiStream(fileName)); + this._dimensionsNames.Add(new LenString(this.m_io, this, this.m_root)); } - - public PairValueCount(KaitaiStream p__io, MetricsContract.HistogramValueCountPairs p__parent = null, MetricsContract p__root = null) - : base(p__io) + this._dimensionsValues = new List((int)this.NumDimensions); + for (var i = 0; i < this.NumDimensions; i++) + { + this._dimensionsValues.Add(new LenString(this.m_io, this, this.m_root)); + } + if (!this.M_Io.IsEof) + { + this._apContainer = new LenString(this.m_io, this, this.m_root); + } + if (((this.EventType == MetricsContract.MetricEventType.ExternallyAggregatedUlongDistributionMetric) || (this.EventType == MetricsContract.MetricEventType.ExternallyAggregatedDoubleDistributionMetric) || (this.EventType == MetricsContract.MetricEventType.ExternallyAggregatedDoubleScaledToLongDistributionMetric)) && (!this.M_Io.IsEof)) { - this.m_parent = p__parent; - this.m_root = p__root; - this._read(); + this._histogram = new Histogram(this.m_io, this, this.m_root); } - private void _read() + } + private bool f_eventType; + private MetricEventType _eventType; + public MetricEventType EventType + { + get { - this._value = this.m_io.ReadU8le(); - this._count = this.m_io.ReadU4le(); + if (this.f_eventType) + return this._eventType; + this._eventType = (MetricEventType)(MetricsContract.MetricEventType)this.EventId; + this.f_eventType = true; + return this._eventType; } - private ulong _value; - private uint _count; - private MetricsContract m_root; - private MetricsContract.HistogramValueCountPairs m_parent; - public ulong Value { get { return this._value; } } - public uint Count { get { return this._count; } } - public MetricsContract M_Root { get { return this.m_root; } } - public MetricsContract.HistogramValueCountPairs M_Parent { get { return this.m_parent; } } } + private ushort _numDimensions; + private byte[] _padding; + private KaitaiStruct _valueSection; + private LenString _metricAccount; + private LenString _metricNamespace; + private LenString _metricName; + private List _dimensionsNames; + private List _dimensionsValues; + private LenString _apContainer; + private Histogram _histogram; + private ushort _eventId; + private MetricsContract m_root; + private MetricsContract m_parent; /// - /// Payload of a histogram with linear distribution of buckets. Such histogram - /// is defined by the parameters specified in `min`, `bucket_size` and - /// `bucket_count`. It is modelled as a series of buckets. First (index 0) and - /// last (indexed `bucket_count - 1`) buckets are special and are supposed to - /// catch all "underflow" and "overflow" values. Buckets with indexes 1 up to - /// `bucket_count - 2` are regular buckets of size `bucket_size`. + /// Number of dimensions specified in this event. /// - public partial class HistogramUint16Bucketed : KaitaiStruct + public ushort NumDimensions { get { return this._numDimensions; } } + public byte[] Padding { get { return this._padding; } } + + /// + /// Value section of the body, stores fixed numeric metric value(s), as per event type. + /// + public KaitaiStruct ValueSection { get { return this._valueSection; } } + + /// + /// Geneva Metrics account name to be used for this metric. + /// + public LenString MetricAccount { get { return this._metricAccount; } } + + /// + /// Geneva Metrics namespace name to be used for this metric. + /// + public LenString MetricNamespace { get { return this._metricNamespace; } } + + /// + /// Geneva Metrics metric name to be used. + /// + public LenString MetricName { get { return this._metricName; } } + + /// + /// Dimension names strings ("key" parts of key-value pairs). Must be sorted, + /// unless MetricsExtenion's option `enableDimensionSortingOnIngestion` is + /// enabled. + /// + public List DimensionsNames { get { return this._dimensionsNames; } } + + /// + /// Dimension values strings ("value" parts of key-value pairs). + /// + public List DimensionsValues { get { return this._dimensionsValues; } } + + /// + /// AutoPilot container string, required for correct AP PKI certificate loading + /// in AutoPilot containers environment. + /// + public LenString ApContainer { get { return this._apContainer; } } + public Histogram Histogram { get { return this._histogram; } } + + /// + /// Type of message, affects format of the body. + /// + public ushort EventId { get { return this._eventId; } } + public MetricsContract M_Root { get { return this.m_root; } } + public MetricsContract M_Parent { get { return this.m_parent; } } + } + + /// + /// Bucket with an explicitly-defined value coordinate `value`, claiming to + /// hold `count` hits. Normally used to represent non-linear (e.g. exponential) + /// histograms payloads. + /// + public partial class PairValueCount : KaitaiStruct + { + public static PairValueCount FromFile(string fileName) + { + return new PairValueCount(new KaitaiStream(fileName)); + } + + public PairValueCount(KaitaiStream p__io, MetricsContract.HistogramValueCountPairs p__parent = null, MetricsContract p__root = null) + : base(p__io) { - public static HistogramUint16Bucketed FromFile(string fileName) + this.m_parent = p__parent; + this.m_root = p__root; + this._read(); + } + private void _read() + { + this._value = this.m_io.ReadU8le(); + this._count = this.m_io.ReadU4le(); + } + private ulong _value; + private uint _count; + private MetricsContract m_root; + private MetricsContract.HistogramValueCountPairs m_parent; + public ulong Value { get { return this._value; } } + public uint Count { get { return this._count; } } + public MetricsContract M_Root { get { return this.m_root; } } + public MetricsContract.HistogramValueCountPairs M_Parent { get { return this.m_parent; } } + } + + /// + /// Payload of a histogram with linear distribution of buckets. Such histogram + /// is defined by the parameters specified in `min`, `bucket_size` and + /// `bucket_count`. It is modelled as a series of buckets. First (index 0) and + /// last (indexed `bucket_count - 1`) buckets are special and are supposed to + /// catch all "underflow" and "overflow" values. Buckets with indexes 1 up to + /// `bucket_count - 2` are regular buckets of size `bucket_size`. + /// + public partial class HistogramUint16Bucketed : KaitaiStruct + { + public static HistogramUint16Bucketed FromFile(string fileName) + { + return new HistogramUint16Bucketed(new KaitaiStream(fileName)); + } + + public HistogramUint16Bucketed(KaitaiStream p__io, MetricsContract.Histogram p__parent = null, MetricsContract p__root = null) + : base(p__io) + { + this.m_parent = p__parent; + this.m_root = p__root; + this._read(); + } + private void _read() + { + this._min = this.m_io.ReadU8le(); + this._bucketSize = this.m_io.ReadU4le(); + this._bucketCount = this.m_io.ReadU4le(); + this._distributionSize = this.m_io.ReadU2le(); + this._columns = new List((int)this.DistributionSize); + for (var i = 0; i < this.DistributionSize; i++) { - return new HistogramUint16Bucketed(new KaitaiStream(fileName)); + this._columns.Add(new PairUint16(this.m_io, this, this.m_root)); } + } + private ulong _min; + private uint _bucketSize; + private uint _bucketCount; + private ushort _distributionSize; + private List _columns; + private MetricsContract m_root; + private MetricsContract.Histogram m_parent; + public ulong Min { get { return this._min; } } + public uint BucketSize { get { return this._bucketSize; } } + public uint BucketCount { get { return this._bucketCount; } } + public ushort DistributionSize { get { return this._distributionSize; } } + public List Columns { get { return this._columns; } } + public MetricsContract M_Root { get { return this.m_root; } } + public MetricsContract.Histogram M_Parent { get { return this.m_parent; } } + } + public partial class HistogramValueCountPairs : KaitaiStruct + { + public static HistogramValueCountPairs FromFile(string fileName) + { + return new HistogramValueCountPairs(new KaitaiStream(fileName)); + } - public HistogramUint16Bucketed(KaitaiStream p__io, MetricsContract.Histogram p__parent = null, MetricsContract p__root = null) - : base(p__io) + public HistogramValueCountPairs(KaitaiStream p__io, MetricsContract.Histogram p__parent = null, MetricsContract p__root = null) + : base(p__io) + { + this.m_parent = p__parent; + this.m_root = p__root; + this._read(); + } + private void _read() + { + this._distributionSize = this.m_io.ReadU2le(); + this._columns = new List((int)this.DistributionSize); + for (var i = 0; i < this.DistributionSize; i++) { - this.m_parent = p__parent; - this.m_root = p__root; - this._read(); + this._columns.Add(new PairValueCount(this.m_io, this, this.m_root)); } - private void _read() + } + private ushort _distributionSize; + private List _columns; + private MetricsContract m_root; + private MetricsContract.Histogram m_parent; + public ushort DistributionSize { get { return this._distributionSize; } } + public List Columns { get { return this._columns; } } + public MetricsContract M_Root { get { return this.m_root; } } + public MetricsContract.Histogram M_Parent { get { return this.m_parent; } } + } + public partial class Histogram : KaitaiStruct + { + public static Histogram FromFile(string fileName) + { + return new Histogram(new KaitaiStream(fileName)); + } + + public Histogram(KaitaiStream p__io, MetricsContract.Userdata p__parent = null, MetricsContract p__root = null) + : base(p__io) + { + this.m_parent = p__parent; + this.m_root = p__root; + this._read(); + } + private void _read() + { + this._version = this.m_io.ReadU1(); + this._type = (MetricsContract.DistributionType)this.m_io.ReadU1(); + switch (this.Type) { - this._min = this.m_io.ReadU8le(); - this._bucketSize = this.m_io.ReadU4le(); - this._bucketCount = this.m_io.ReadU4le(); - this._distributionSize = this.m_io.ReadU2le(); - this._columns = new List((int)this.DistributionSize); - for (var i = 0; i < this.DistributionSize; i++) + case MetricsContract.DistributionType.Bucketed: { - this._columns.Add(new PairUint16(this.m_io, this, this.m_root)); + this._body = new HistogramUint16Bucketed(this.m_io, this, this.m_root); + break; } - } - private ulong _min; - private uint _bucketSize; - private uint _bucketCount; - private ushort _distributionSize; - private List _columns; - private MetricsContract m_root; - private MetricsContract.Histogram m_parent; - public ulong Min { get { return this._min; } } - public uint BucketSize { get { return this._bucketSize; } } - public uint BucketCount { get { return this._bucketCount; } } - public ushort DistributionSize { get { return this._distributionSize; } } - public List Columns { get { return this._columns; } } - public MetricsContract M_Root { get { return this.m_root; } } - public MetricsContract.Histogram M_Parent { get { return this.m_parent; } } - } - public partial class HistogramValueCountPairs : KaitaiStruct - { - public static HistogramValueCountPairs FromFile(string fileName) - { - return new HistogramValueCountPairs(new KaitaiStream(fileName)); - } - - public HistogramValueCountPairs(KaitaiStream p__io, MetricsContract.Histogram p__parent = null, MetricsContract p__root = null) - : base(p__io) - { - this.m_parent = p__parent; - this.m_root = p__root; - this._read(); - } - private void _read() - { - this._distributionSize = this.m_io.ReadU2le(); - this._columns = new List((int)this.DistributionSize); - for (var i = 0; i < this.DistributionSize; i++) + case MetricsContract.DistributionType.MonBucketed: { - this._columns.Add(new PairValueCount(this.m_io, this, this.m_root)); + this._body = new HistogramUint16Bucketed(this.m_io, this, this.m_root); + break; } - } - private ushort _distributionSize; - private List _columns; - private MetricsContract m_root; - private MetricsContract.Histogram m_parent; - public ushort DistributionSize { get { return this._distributionSize; } } - public List Columns { get { return this._columns; } } - public MetricsContract M_Root { get { return this.m_root; } } - public MetricsContract.Histogram M_Parent { get { return this.m_parent; } } - } - public partial class Histogram : KaitaiStruct - { - public static Histogram FromFile(string fileName) - { - return new Histogram(new KaitaiStream(fileName)); - } - - public Histogram(KaitaiStream p__io, MetricsContract.Userdata p__parent = null, MetricsContract p__root = null) - : base(p__io) - { - this.m_parent = p__parent; - this.m_root = p__root; - this._read(); - } - private void _read() - { - this._version = this.m_io.ReadU1(); - this._type = (MetricsContract.DistributionType)this.m_io.ReadU1(); - switch (this.Type) + case MetricsContract.DistributionType.ValueCountPairs: { - case MetricsContract.DistributionType.Bucketed: - { - this._body = new HistogramUint16Bucketed(this.m_io, this, this.m_root); - break; - } - case MetricsContract.DistributionType.MonBucketed: - { - this._body = new HistogramUint16Bucketed(this.m_io, this, this.m_root); - break; - } - case MetricsContract.DistributionType.ValueCountPairs: - { - this._body = new HistogramValueCountPairs(this.m_io, this, this.m_root); - break; - } + this._body = new HistogramValueCountPairs(this.m_io, this, this.m_root); + break; } } - private byte _version; - private DistributionType _type; - private KaitaiStruct _body; - private MetricsContract m_root; - private MetricsContract.Userdata m_parent; - public byte Version { get { return this._version; } } - public DistributionType Type { get { return this._type; } } - public KaitaiStruct Body { get { return this._body; } } - public MetricsContract M_Root { get { return this.m_root; } } - public MetricsContract.Userdata M_Parent { get { return this.m_parent; } } + } + private byte _version; + private DistributionType _type; + private KaitaiStruct _body; + private MetricsContract m_root; + private MetricsContract.Userdata m_parent; + public byte Version { get { return this._version; } } + public DistributionType Type { get { return this._type; } } + public KaitaiStruct Body { get { return this._body; } } + public MetricsContract M_Root { get { return this.m_root; } } + public MetricsContract.Userdata M_Parent { get { return this.m_parent; } } + } + + /// + /// Bucket #index, claiming to hold exactly `count` hits. See notes in + /// `histogram_uint16_bucketed` for interpreting index. + /// + public partial class PairUint16 : KaitaiStruct + { + public static PairUint16 FromFile(string fileName) + { + return new PairUint16(new KaitaiStream(fileName)); } + public PairUint16(KaitaiStream p__io, MetricsContract.HistogramUint16Bucketed p__parent = null, MetricsContract p__root = null) + : base(p__io) + { + this.m_parent = p__parent; + this.m_root = p__root; + this._read(); + } + private void _read() + { + this._index = this.m_io.ReadU2le(); + this._count = this.m_io.ReadU2le(); + } + private ushort _index; + private ushort _count; + private MetricsContract m_root; + private MetricsContract.HistogramUint16Bucketed m_parent; + public ushort Index { get { return this._index; } } + public ushort Count { get { return this._count; } } + public MetricsContract M_Root { get { return this.m_root; } } + public MetricsContract.HistogramUint16Bucketed M_Parent { get { return this.m_parent; } } + } + public partial class SingleUint64Value : KaitaiStruct + { + public static SingleUint64Value FromFile(string fileName) + { + return new SingleUint64Value(new KaitaiStream(fileName)); + } + + public SingleUint64Value(KaitaiStream p__io, MetricsContract.Userdata p__parent = null, MetricsContract p__root = null) + : base(p__io) + { + this.m_parent = p__parent; + this.m_root = p__root; + this._read(); + } + private void _read() + { + this._padding = this.m_io.ReadBytes(4); + this._timestamp = this.m_io.ReadU8le(); + this._value = this.m_io.ReadU8le(); + } + private byte[] _padding; + private ulong _timestamp; + private ulong _value; + private MetricsContract m_root; + private MetricsContract.Userdata m_parent; + public byte[] Padding { get { return this._padding; } } + + /// + /// Timestamp in Windows FILETIME format, i.e. number of 100 ns ticks passed since 1601-01-01 00:00:00 UTC. + /// + public ulong Timestamp { get { return this._timestamp; } } + /// - /// Bucket #index, claiming to hold exactly `count` hits. See notes in - /// `histogram_uint16_bucketed` for interpreting index. + /// Metric value as 64-bit unsigned integer. /// - public partial class PairUint16 : KaitaiStruct + public ulong Value { get { return this._value; } } + public MetricsContract M_Root { get { return this.m_root; } } + public MetricsContract.Userdata M_Parent { get { return this.m_parent; } } + } + public partial class ExtAggregatedDoubleValue : KaitaiStruct + { + public static ExtAggregatedDoubleValue FromFile(string fileName) { - public static PairUint16 FromFile(string fileName) - { - return new PairUint16(new KaitaiStream(fileName)); - } + return new ExtAggregatedDoubleValue(new KaitaiStream(fileName)); + } - public PairUint16(KaitaiStream p__io, MetricsContract.HistogramUint16Bucketed p__parent = null, MetricsContract p__root = null) - : base(p__io) - { - this.m_parent = p__parent; - this.m_root = p__root; - this._read(); - } - private void _read() - { - this._index = this.m_io.ReadU2le(); - this._count = this.m_io.ReadU2le(); - } - private ushort _index; - private ushort _count; - private MetricsContract m_root; - private MetricsContract.HistogramUint16Bucketed m_parent; - public ushort Index { get { return this._index; } } - public ushort Count { get { return this._count; } } - public MetricsContract M_Root { get { return this.m_root; } } - public MetricsContract.HistogramUint16Bucketed M_Parent { get { return this.m_parent; } } - } - public partial class SingleUint64Value : KaitaiStruct - { - public static SingleUint64Value FromFile(string fileName) - { - return new SingleUint64Value(new KaitaiStream(fileName)); - } + public ExtAggregatedDoubleValue(KaitaiStream p__io, MetricsContract.Userdata p__parent = null, MetricsContract p__root = null) + : base(p__io) + { + this.m_parent = p__parent; + this.m_root = p__root; + this._read(); + } + private void _read() + { + this._count = this.m_io.ReadU4le(); + this._timestamp = this.m_io.ReadU8le(); + this._sum = this.m_io.ReadF8le(); + this._min = this.m_io.ReadF8le(); + this._max = this.m_io.ReadF8le(); + } + private uint _count; + private ulong _timestamp; + private double _sum; + private double _min; + private double _max; + private MetricsContract m_root; + private MetricsContract.Userdata m_parent; - public SingleUint64Value(KaitaiStream p__io, MetricsContract.Userdata p__parent = null, MetricsContract p__root = null) - : base(p__io) - { - this.m_parent = p__parent; - this.m_root = p__root; - this._read(); - } - private void _read() - { - this._padding = this.m_io.ReadBytes(4); - this._timestamp = this.m_io.ReadU8le(); - this._value = this.m_io.ReadU8le(); - } - private byte[] _padding; - private ulong _timestamp; - private ulong _value; - private MetricsContract m_root; - private MetricsContract.Userdata m_parent; - public byte[] Padding { get { return this._padding; } } - - /// - /// Timestamp in Windows FILETIME format, i.e. number of 100 ns ticks passed since 1601-01-01 00:00:00 UTC. - /// - public ulong Timestamp { get { return this._timestamp; } } - - /// - /// Metric value as 64-bit unsigned integer. - /// - public ulong Value { get { return this._value; } } - public MetricsContract M_Root { get { return this.m_root; } } - public MetricsContract.Userdata M_Parent { get { return this.m_parent; } } - } - public partial class ExtAggregatedDoubleValue : KaitaiStruct - { - public static ExtAggregatedDoubleValue FromFile(string fileName) - { - return new ExtAggregatedDoubleValue(new KaitaiStream(fileName)); - } + /// + /// Count of events aggregated in this event. + /// + public uint Count { get { return this._count; } } - public ExtAggregatedDoubleValue(KaitaiStream p__io, MetricsContract.Userdata p__parent = null, MetricsContract p__root = null) - : base(p__io) - { - this.m_parent = p__parent; - this.m_root = p__root; - this._read(); - } - private void _read() - { - this._count = this.m_io.ReadU4le(); - this._timestamp = this.m_io.ReadU8le(); - this._sum = this.m_io.ReadF8le(); - this._min = this.m_io.ReadF8le(); - this._max = this.m_io.ReadF8le(); - } - private uint _count; - private ulong _timestamp; - private double _sum; - private double _min; - private double _max; - private MetricsContract m_root; - private MetricsContract.Userdata m_parent; - - /// - /// Count of events aggregated in this event. - /// - public uint Count { get { return this._count; } } - - /// - /// Timestamp in Windows FILETIME format, i.e. number of 100 ns ticks passed since 1601-01-01 00:00:00 UTC. - /// - public ulong Timestamp { get { return this._timestamp; } } - - /// - /// Sum of all metric values aggregated in this event. - /// - public double Sum { get { return this._sum; } } - - /// - /// Minimum of all metric values aggregated in this event. - /// - public double Min { get { return this._min; } } - - /// - /// Maximum of all metric values aggregated in this event. - /// - public double Max { get { return this._max; } } - public MetricsContract M_Root { get { return this.m_root; } } - public MetricsContract.Userdata M_Parent { get { return this.m_parent; } } - } - public partial class ExtAggregatedUint64Value : KaitaiStruct - { - public static ExtAggregatedUint64Value FromFile(string fileName) - { - return new ExtAggregatedUint64Value(new KaitaiStream(fileName)); - } + /// + /// Timestamp in Windows FILETIME format, i.e. number of 100 ns ticks passed since 1601-01-01 00:00:00 UTC. + /// + public ulong Timestamp { get { return this._timestamp; } } - public ExtAggregatedUint64Value(KaitaiStream p__io, MetricsContract.Userdata p__parent = null, MetricsContract p__root = null) - : base(p__io) - { - this.m_parent = p__parent; - this.m_root = p__root; - this._read(); - } - private void _read() - { - this._count = this.m_io.ReadU4le(); - this._timestamp = this.m_io.ReadU8le(); - this._sum = this.m_io.ReadU8le(); - this._min = this.m_io.ReadU8le(); - this._max = this.m_io.ReadU8le(); - } - private uint _count; - private ulong _timestamp; - private ulong _sum; - private ulong _min; - private ulong _max; - private MetricsContract m_root; - private MetricsContract.Userdata m_parent; - - /// - /// Count of events aggregated in this event. - /// - public uint Count { get { return this._count; } } - - /// - /// Timestamp in Windows FILETIME format, i.e. number of 100 ns ticks passed since 1601-01-01 00:00:00 UTC. - /// - public ulong Timestamp { get { return this._timestamp; } } - - /// - /// Sum of all metric values aggregated in this event. - /// - public ulong Sum { get { return this._sum; } } - - /// - /// Minimum of all metric values aggregated in this event. - /// - public ulong Min { get { return this._min; } } - - /// - /// Maximum of all metric values aggregated in this event. - /// - public ulong Max { get { return this._max; } } - public MetricsContract M_Root { get { return this.m_root; } } - public MetricsContract.Userdata M_Parent { get { return this.m_parent; } } - } - public partial class SingleDoubleValue : KaitaiStruct - { - public static SingleDoubleValue FromFile(string fileName) - { - return new SingleDoubleValue(new KaitaiStream(fileName)); - } + /// + /// Sum of all metric values aggregated in this event. + /// + public double Sum { get { return this._sum; } } - public SingleDoubleValue(KaitaiStream p__io, MetricsContract.Userdata p__parent = null, MetricsContract p__root = null) - : base(p__io) - { - this.m_parent = p__parent; - this.m_root = p__root; - this._read(); - } - private void _read() - { - this._padding = this.m_io.ReadBytes(4); - this._timestamp = this.m_io.ReadU8le(); - this._value = this.m_io.ReadF8le(); - } - private byte[] _padding; - private ulong _timestamp; - private double _value; - private MetricsContract m_root; - private MetricsContract.Userdata m_parent; - public byte[] Padding { get { return this._padding; } } - - /// - /// Timestamp in Windows FILETIME format, i.e. number of 100 ns ticks passed since 1601-01-01 00:00:00 UTC. - /// - public ulong Timestamp { get { return this._timestamp; } } - - /// - /// Metric value as double. - /// - public double Value { get { return this._value; } } - public MetricsContract M_Root { get { return this.m_root; } } - public MetricsContract.Userdata M_Parent { get { return this.m_parent; } } - } + /// + /// Minimum of all metric values aggregated in this event. + /// + public double Min { get { return this._min; } } /// - /// A simple string, length-prefixed with a 2-byte integer. + /// Maximum of all metric values aggregated in this event. /// - public partial class LenString : KaitaiStruct + public double Max { get { return this._max; } } + public MetricsContract M_Root { get { return this.m_root; } } + public MetricsContract.Userdata M_Parent { get { return this.m_parent; } } + } + public partial class ExtAggregatedUint64Value : KaitaiStruct + { + public static ExtAggregatedUint64Value FromFile(string fileName) { - public static LenString FromFile(string fileName) - { - return new LenString(new KaitaiStream(fileName)); - } + return new ExtAggregatedUint64Value(new KaitaiStream(fileName)); + } - public LenString(KaitaiStream p__io, MetricsContract.Userdata p__parent = null, MetricsContract p__root = null) - : base(p__io) - { - this.m_parent = p__parent; - this.m_root = p__root; - this._read(); - } - private void _read() - { - this._lenValue = this.m_io.ReadU2le(); - this._value = System.Text.Encoding.GetEncoding("UTF-8").GetString(this.m_io.ReadBytes(this.LenValue)); - } - private ushort _lenValue; - private string _value; - private MetricsContract m_root; - private MetricsContract.Userdata m_parent; - public ushort LenValue { get { return this._lenValue; } } - public string Value { get { return this._value; } } - public MetricsContract M_Root { get { return this.m_root; } } - public MetricsContract.Userdata M_Parent { get { return this.m_parent; } } + public ExtAggregatedUint64Value(KaitaiStream p__io, MetricsContract.Userdata p__parent = null, MetricsContract p__root = null) + : base(p__io) + { + this.m_parent = p__parent; + this.m_root = p__root; + this._read(); } - private ushort _eventId; - private ushort _lenBody; - private Userdata _body; + private void _read() + { + this._count = this.m_io.ReadU4le(); + this._timestamp = this.m_io.ReadU8le(); + this._sum = this.m_io.ReadU8le(); + this._min = this.m_io.ReadU8le(); + this._max = this.m_io.ReadU8le(); + } + private uint _count; + private ulong _timestamp; + private ulong _sum; + private ulong _min; + private ulong _max; private MetricsContract m_root; - private KaitaiStruct m_parent; - private byte[] __raw_body; + private MetricsContract.Userdata m_parent; /// - /// Type of message, affects format of the body. + /// Count of events aggregated in this event. /// - public ushort EventId { get { return this._eventId; } } + public uint Count { get { return this._count; } } + + /// + /// Timestamp in Windows FILETIME format, i.e. number of 100 ns ticks passed since 1601-01-01 00:00:00 UTC. + /// + public ulong Timestamp { get { return this._timestamp; } } + + /// + /// Sum of all metric values aggregated in this event. + /// + public ulong Sum { get { return this._sum; } } /// - /// Size of body in bytes. + /// Minimum of all metric values aggregated in this event. /// - public ushort LenBody { get { return this._lenBody; } } + public ulong Min { get { return this._min; } } /// - /// Body of Metrics binary protocol message. + /// Maximum of all metric values aggregated in this event. /// - public Userdata Body { get { return this._body; } } + public ulong Max { get { return this._max; } } + public MetricsContract M_Root { get { return this.m_root; } } + public MetricsContract.Userdata M_Parent { get { return this.m_parent; } } + } + public partial class SingleDoubleValue : KaitaiStruct + { + public static SingleDoubleValue FromFile(string fileName) + { + return new SingleDoubleValue(new KaitaiStream(fileName)); + } + + public SingleDoubleValue(KaitaiStream p__io, MetricsContract.Userdata p__parent = null, MetricsContract p__root = null) + : base(p__io) + { + this.m_parent = p__parent; + this.m_root = p__root; + this._read(); + } + private void _read() + { + this._padding = this.m_io.ReadBytes(4); + this._timestamp = this.m_io.ReadU8le(); + this._value = this.m_io.ReadF8le(); + } + private byte[] _padding; + private ulong _timestamp; + private double _value; + private MetricsContract m_root; + private MetricsContract.Userdata m_parent; + public byte[] Padding { get { return this._padding; } } + + /// + /// Timestamp in Windows FILETIME format, i.e. number of 100 ns ticks passed since 1601-01-01 00:00:00 UTC. + /// + public ulong Timestamp { get { return this._timestamp; } } + + /// + /// Metric value as double. + /// + public double Value { get { return this._value; } } + public MetricsContract M_Root { get { return this.m_root; } } + public MetricsContract.Userdata M_Parent { get { return this.m_parent; } } + } + + /// + /// A simple string, length-prefixed with a 2-byte integer. + /// + public partial class LenString : KaitaiStruct + { + public static LenString FromFile(string fileName) + { + return new LenString(new KaitaiStream(fileName)); + } + + public LenString(KaitaiStream p__io, MetricsContract.Userdata p__parent = null, MetricsContract p__root = null) + : base(p__io) + { + this.m_parent = p__parent; + this.m_root = p__root; + this._read(); + } + private void _read() + { + this._lenValue = this.m_io.ReadU2le(); + this._value = System.Text.Encoding.GetEncoding("UTF-8").GetString(this.m_io.ReadBytes(this.LenValue)); + } + private ushort _lenValue; + private string _value; + private MetricsContract m_root; + private MetricsContract.Userdata m_parent; + public ushort LenValue { get { return this._lenValue; } } + public string Value { get { return this._value; } } public MetricsContract M_Root { get { return this.m_root; } } - public KaitaiStruct M_Parent { get { return this.m_parent; } } - public byte[] M_RawBody { get { return this.__raw_body; } } + public MetricsContract.Userdata M_Parent { get { return this.m_parent; } } } + private ushort _eventId; + private ushort _lenBody; + private Userdata _body; + private MetricsContract m_root; + private KaitaiStruct m_parent; + private byte[] __raw_body; + + /// + /// Type of message, affects format of the body. + /// + public ushort EventId { get { return this._eventId; } } + + /// + /// Size of body in bytes. + /// + public ushort LenBody { get { return this._lenBody; } } + + /// + /// Body of Metrics binary protocol message. + /// + public Userdata Body { get { return this._body; } } + public MetricsContract M_Root { get { return this.m_root; } } + public KaitaiStruct M_Parent { get { return this.m_parent; } } + public byte[] M_RawBody { get { return this.__raw_body; } } } diff --git a/test/OpenTelemetry.Exporter.Geneva.Tests/UnixDomainSocketDataTransportTests.cs b/test/OpenTelemetry.Exporter.Geneva.Tests/UnixDomainSocketDataTransportTests.cs index 021fb55140..03f9f297c2 100644 --- a/test/OpenTelemetry.Exporter.Geneva.Tests/UnixDomainSocketDataTransportTests.cs +++ b/test/OpenTelemetry.Exporter.Geneva.Tests/UnixDomainSocketDataTransportTests.cs @@ -21,197 +21,196 @@ using System.Runtime.InteropServices; using Xunit; -namespace OpenTelemetry.Exporter.Geneva.Tests +namespace OpenTelemetry.Exporter.Geneva.Tests; + +public class UnixDomainSocketDataTransportTests { - public class UnixDomainSocketDataTransportTests + [Fact] + public void UnixDomainSocketDataTransport_Success_Linux() { - [Fact] - public void UnixDomainSocketDataTransport_Success_Linux() + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + string path = GetRandomFilePath(); + var endpoint = new UnixDomainSocketEndPoint(path); + try + { + using var server = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); + server.Bind(endpoint); + server.Listen(1); + + // Client + using var dataTransport = new UnixDomainSocketDataTransport(path); + using Socket serverSocket = server.Accept(); + var data = new byte[] { 12, 34, 56 }; + dataTransport.Send(data, data.Length); + var receivedData = new byte[5]; + serverSocket.Receive(receivedData); + Assert.Equal(data[0], receivedData[0]); + Assert.Equal(data[1], receivedData[1]); + Assert.Equal(data[2], receivedData[2]); + } + catch (Exception) + { + throw; + } + finally { - string path = GetRandomFilePath(); - var endpoint = new UnixDomainSocketEndPoint(path); try { - using var server = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); - server.Bind(endpoint); - server.Listen(1); - - // Client - using var dataTransport = new UnixDomainSocketDataTransport(path); - using Socket serverSocket = server.Accept(); - var data = new byte[] { 12, 34, 56 }; - dataTransport.Send(data, data.Length); - var receivedData = new byte[5]; - serverSocket.Receive(receivedData); - Assert.Equal(data[0], receivedData[0]); - Assert.Equal(data[1], receivedData[1]); - Assert.Equal(data[2], receivedData[2]); - } - catch (Exception) - { - throw; + File.Delete(path); } - finally + catch { - try - { - File.Delete(path); - } - catch - { - } } } } + } - [Fact] - public void UnixDomainSocketDataTransport_SendTimesOutIfSocketBufferFull_Linux() + [Fact] + public void UnixDomainSocketDataTransport_SendTimesOutIfSocketBufferFull_Linux() + { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + string path = GetRandomFilePath(); + var endpoint = new UnixDomainSocketEndPoint(path); + using var server = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); + server.Bind(endpoint); + server.Listen(1); + var data = new byte[1024]; + var i = 0; + using var dataTransport = new UnixDomainSocketDataTransport(path, 5000); // Set low timeout for faster tests + var socket = typeof(UnixDomainSocketDataTransport).GetField("socket", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(dataTransport) as Socket; + try { - string path = GetRandomFilePath(); - var endpoint = new UnixDomainSocketEndPoint(path); - using var server = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); - server.Bind(endpoint); - server.Listen(1); - var data = new byte[1024]; - var i = 0; - using var dataTransport = new UnixDomainSocketDataTransport(path, 5000); // Set low timeout for faster tests - var socket = typeof(UnixDomainSocketDataTransport).GetField("socket", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(dataTransport) as Socket; - try + // Client + using Socket serverSocket = server.Accept(); + while (true) { - // Client - using Socket serverSocket = server.Accept(); - while (true) - { - Console.WriteLine($"Sending request #{i++}."); - socket.Send(data, data.Length, SocketFlags.None); - } - - // The server is not processing sent data (because of heavy load, etc.) + Console.WriteLine($"Sending request #{i++}."); + socket.Send(data, data.Length, SocketFlags.None); } - catch (Exception) + + // The server is not processing sent data (because of heavy load, etc.) + } + catch (Exception) + { + // At this point, the outgoing buffer for the socket must be full, + // because the last Send failed. + // Send again and assert the exception to confirm: + Assert.Throws(() => + { + Console.WriteLine($"Sending request #{i}."); + socket.Send(data, data.Length, SocketFlags.None); + }); + } + finally + { + try { - // At this point, the outgoing buffer for the socket must be full, - // because the last Send failed. - // Send again and assert the exception to confirm: - Assert.Throws(() => - { - Console.WriteLine($"Sending request #{i}."); - socket.Send(data, data.Length, SocketFlags.None); - }); + File.Delete(path); } - finally + catch { - try - { - File.Delete(path); - } - catch - { - } } } } + } - [Fact] - public void UnixDomainSocketDataTransport_ServerRestart_Linux() + [Fact] + public void UnixDomainSocketDataTransport_ServerRestart_Linux() + { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + Console.WriteLine("Test starts."); + string path = GetRandomFilePath(); + var endpoint = new UnixDomainSocketEndPoint(path); + try { - Console.WriteLine("Test starts."); - string path = GetRandomFilePath(); - var endpoint = new UnixDomainSocketEndPoint(path); + var server = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); + + // LingerOption lo = new LingerOption(false, 0); + // server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, lo); + server.Bind(endpoint); + server.Listen(1); + + // Client + using var dataTransport = new UnixDomainSocketDataTransport(path); + Socket serverSocket = server.Accept(); + var data = new byte[] { 12, 34, 56 }; + dataTransport.Send(data, data.Length); + var receivedData = new byte[5]; + serverSocket.Receive(receivedData); + Assert.Equal(data[0], receivedData[0]); + Assert.Equal(data[1], receivedData[1]); + Assert.Equal(data[2], receivedData[2]); + + Console.WriteLine("Successfully sent a message."); + + // Emulate server stops + serverSocket.Shutdown(SocketShutdown.Both); + serverSocket.Disconnect(false); + serverSocket.Dispose(); + server.Shutdown(SocketShutdown.Both); + server.Disconnect(false); + server.Dispose(); try { - var server = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); - - // LingerOption lo = new LingerOption(false, 0); - // server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, lo); - server.Bind(endpoint); - server.Listen(1); - - // Client - using var dataTransport = new UnixDomainSocketDataTransport(path); - Socket serverSocket = server.Accept(); - var data = new byte[] { 12, 34, 56 }; - dataTransport.Send(data, data.Length); - var receivedData = new byte[5]; - serverSocket.Receive(receivedData); - Assert.Equal(data[0], receivedData[0]); - Assert.Equal(data[1], receivedData[1]); - Assert.Equal(data[2], receivedData[2]); - - Console.WriteLine("Successfully sent a message."); - - // Emulate server stops - serverSocket.Shutdown(SocketShutdown.Both); - serverSocket.Disconnect(false); - serverSocket.Dispose(); - server.Shutdown(SocketShutdown.Both); - server.Disconnect(false); - server.Dispose(); - try - { - File.Delete(path); - } - catch - { - } - - Console.WriteLine("Destroyed server."); - - Console.WriteLine("Client will fail during Send, and should throw an Exception"); - Assert.ThrowsAny(() => dataTransport.Send(data, data.Length)); - Console.WriteLine("Client will fail during Reconnect, and should throw an Exception"); - Assert.ThrowsAny(() => dataTransport.Send(data, data.Length)); - - using var server2 = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); - server2.Bind(endpoint); - server2.Listen(1); - Console.WriteLine("Started a new server and listening."); - - var data2 = new byte[] { 34, 56, 78 }; - dataTransport.Send(data2, data2.Length); - Console.WriteLine("The same client sent a new message. Internally it should reconnect if server ever stopped and the socket is not connected anymore."); - - using Socket serverSocket2 = server2.Accept(); - Console.WriteLine("The new server is ready and accepting connections."); - var receivedData2 = new byte[5]; - serverSocket2.Receive(receivedData2); - Console.WriteLine("Server received a messge."); - Assert.Equal(data2[0], receivedData2[0]); - Assert.Equal(data2[1], receivedData2[1]); - Assert.Equal(data2[2], receivedData2[2]); + File.Delete(path); } - catch (Exception) + catch { - throw; } - finally + + Console.WriteLine("Destroyed server."); + + Console.WriteLine("Client will fail during Send, and should throw an Exception"); + Assert.ThrowsAny(() => dataTransport.Send(data, data.Length)); + Console.WriteLine("Client will fail during Reconnect, and should throw an Exception"); + Assert.ThrowsAny(() => dataTransport.Send(data, data.Length)); + + using var server2 = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP); + server2.Bind(endpoint); + server2.Listen(1); + Console.WriteLine("Started a new server and listening."); + + var data2 = new byte[] { 34, 56, 78 }; + dataTransport.Send(data2, data2.Length); + Console.WriteLine("The same client sent a new message. Internally it should reconnect if server ever stopped and the socket is not connected anymore."); + + using Socket serverSocket2 = server2.Accept(); + Console.WriteLine("The new server is ready and accepting connections."); + var receivedData2 = new byte[5]; + serverSocket2.Receive(receivedData2); + Console.WriteLine("Server received a messge."); + Assert.Equal(data2[0], receivedData2[0]); + Assert.Equal(data2[1], receivedData2[1]); + Assert.Equal(data2[2], receivedData2[2]); + } + catch (Exception) + { + throw; + } + finally + { + try + { + File.Delete(path); + } + catch { - try - { - File.Delete(path); - } - catch - { - } } } } + } - private static string GetRandomFilePath() + private static string GetRandomFilePath() + { + while (true) { - while (true) + string path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + if (!File.Exists(path)) { - string path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); - if (!File.Exists(path)) - { - return path; - } + return path; } } } diff --git a/test/OpenTelemetry.Exporter.Geneva.Tests/UnixDomainSocketEndPointTests.cs b/test/OpenTelemetry.Exporter.Geneva.Tests/UnixDomainSocketEndPointTests.cs index 30b1538f2d..fe023e36b9 100644 --- a/test/OpenTelemetry.Exporter.Geneva.Tests/UnixDomainSocketEndPointTests.cs +++ b/test/OpenTelemetry.Exporter.Geneva.Tests/UnixDomainSocketEndPointTests.cs @@ -20,65 +20,64 @@ using System.Text; using Xunit; -namespace OpenTelemetry.Exporter.Geneva.Tests +namespace OpenTelemetry.Exporter.Geneva.Tests; + +public class UnixDomainSocketEndPointTests { - public class UnixDomainSocketEndPointTests + [Fact] + public void UnixDomainSocketEndPoint_constructor_InvalidArgument() { - [Fact] - public void UnixDomainSocketEndPoint_constructor_InvalidArgument() - { - Assert.Throws(() => _ = new UnixDomainSocketEndPoint(null)); - Assert.Throws(() => _ = new UnixDomainSocketEndPoint(string.Empty)); - Assert.Throws(() => _ = new UnixDomainSocketEndPoint(new string('a', 100))); - } + Assert.Throws(() => _ = new UnixDomainSocketEndPoint(null)); + Assert.Throws(() => _ = new UnixDomainSocketEndPoint(string.Empty)); + Assert.Throws(() => _ = new UnixDomainSocketEndPoint(new string('a', 100))); + } - [Fact] - public void UnixDomainSocketEndPoint_constructor_Success() - { - var endpoint = new UnixDomainSocketEndPoint("abc"); - Assert.Equal("abc", endpoint.ToString()); - } + [Fact] + public void UnixDomainSocketEndPoint_constructor_Success() + { + var endpoint = new UnixDomainSocketEndPoint("abc"); + Assert.Equal("abc", endpoint.ToString()); + } - [Fact] - public void UnixDomainSocketEndPoint_Create_InvalidArgument() - { - var endpoint = new UnixDomainSocketEndPoint("abc"); - Assert.Throws(() => _ = endpoint.Create(null)); - Assert.Throws(() => _ = endpoint.Create(this.CreateSocketAddress(new string('a', 100)))); - } + [Fact] + public void UnixDomainSocketEndPoint_Create_InvalidArgument() + { + var endpoint = new UnixDomainSocketEndPoint("abc"); + Assert.Throws(() => _ = endpoint.Create(null)); + Assert.Throws(() => _ = endpoint.Create(this.CreateSocketAddress(new string('a', 100)))); + } - [Fact] - public void UnixDomainSocketEndPoint_Create_Success() - { - var endpoint = new UnixDomainSocketEndPoint("abc"); + [Fact] + public void UnixDomainSocketEndPoint_Create_Success() + { + var endpoint = new UnixDomainSocketEndPoint("abc"); - var sa = new SocketAddress(AddressFamily.Unix, 2); // SocketAddress size is 2 - Assert.Equal(string.Empty, endpoint.Create(sa).ToString()); + var sa = new SocketAddress(AddressFamily.Unix, 2); // SocketAddress size is 2 + Assert.Equal(string.Empty, endpoint.Create(sa).ToString()); - Assert.Equal("\0", endpoint.Create(this.CreateSocketAddress(string.Empty)).ToString()); - Assert.Equal("test\0", endpoint.Create(this.CreateSocketAddress("test")).ToString()); - } + Assert.Equal("\0", endpoint.Create(this.CreateSocketAddress(string.Empty)).ToString()); + Assert.Equal("test\0", endpoint.Create(this.CreateSocketAddress("test")).ToString()); + } - [Fact] - public void UnixDomainSocketEndPoint_Serialize() - { - var path = "abc"; - var endpoint = new UnixDomainSocketEndPoint(path); - Assert.Equal(this.CreateSocketAddress(path), endpoint.Serialize()); - } + [Fact] + public void UnixDomainSocketEndPoint_Serialize() + { + var path = "abc"; + var endpoint = new UnixDomainSocketEndPoint(path); + Assert.Equal(this.CreateSocketAddress(path), endpoint.Serialize()); + } - private SocketAddress CreateSocketAddress(string path) + private SocketAddress CreateSocketAddress(string path) + { + int NativePathOffset = 2; + var nativePath = Encoding.UTF8.GetBytes(path); + var sa = new SocketAddress(AddressFamily.Unix, NativePathOffset + nativePath.Length + 1); + for (int i = 0; i < nativePath.Length; ++i) { - int NativePathOffset = 2; - var nativePath = Encoding.UTF8.GetBytes(path); - var sa = new SocketAddress(AddressFamily.Unix, NativePathOffset + nativePath.Length + 1); - for (int i = 0; i < nativePath.Length; ++i) - { - sa[NativePathOffset + i] = nativePath[i]; - } - - sa[NativePathOffset + nativePath.Length] = 0; - return sa; + sa[NativePathOffset + i] = nativePath[i]; } + + sa[NativePathOffset + nativePath.Length] = 0; + return sa; } } diff --git a/test/OpenTelemetry.Extensions.Docker.Tests/Resources/TempFile.cs b/test/OpenTelemetry.Extensions.Docker.Tests/Resources/TempFile.cs index 592c128152..61bb38d80f 100644 --- a/test/OpenTelemetry.Extensions.Docker.Tests/Resources/TempFile.cs +++ b/test/OpenTelemetry.Extensions.Docker.Tests/Resources/TempFile.cs @@ -18,49 +18,48 @@ using System.IO; using System.Threading; -namespace OpenTelemetry.Extensions.Docker.Tests +namespace OpenTelemetry.Extensions.Docker.Tests; + +internal class TempFile : IDisposable { - internal class TempFile : IDisposable - { - private string filePath; + private string filePath; - public TempFile() - { - this.filePath = Path.GetTempFileName(); - } + public TempFile() + { + this.filePath = Path.GetTempFileName(); + } - public string FilePath - { - get { return this.filePath; } - set { this.filePath = value; } - } + public string FilePath + { + get { return this.filePath; } + set { this.filePath = value; } + } - public void Write(string data) + public void Write(string data) + { + using (FileStream stream = new FileStream(this.filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite | FileShare.Delete)) { - using (FileStream stream = new FileStream(this.filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite | FileShare.Delete)) + using (StreamWriter sw = new StreamWriter(stream)) { - using (StreamWriter sw = new StreamWriter(stream)) - { - sw.Write(data); - } + sw.Write(data); } } + } - public void Dispose() + public void Dispose() + { + for (int tries = 0; ; tries++) { - for (int tries = 0; ; tries++) + try + { + File.Delete(this.filePath); + return; + } + catch (IOException) when (tries < 3) { - try - { - File.Delete(this.filePath); - return; - } - catch (IOException) when (tries < 3) - { - // the file is unavailable because it is: still being written to or being processed by another thread - // sleep for sometime before deleting - Thread.Sleep(1000); - } + // the file is unavailable because it is: still being written to or being processed by another thread + // sleep for sometime before deleting + Thread.Sleep(1000); } } }