diff --git a/ReadMe.md b/ReadMe.md index 2a44d7e8..7507a853 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -1190,21 +1190,12 @@ public class CommandTracingFilter(ConsoleAppFilter next) : ConsoleAppFilter(next For visualization, if your solution includes a web application, using .NET Aspire would be convenient during development. For production environments, there are solutions like Datadog and New Relic, as well as OSS tools from Grafana Labs. However, especially for local development, I think OpenTelemetry native all-in-one solutions are convenient. Here, let's look at tracing using the OSS [SigNoz](https://signoz.io/). ```csharp -using ConsoleAppFramework; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using OpenTelemetry.Logs; -using OpenTelemetry.Metrics; -using OpenTelemetry.Resources; -using OpenTelemetry.Trace; -using System.Diagnostics; - // git clone https://github.com/SigNoz/signoz.git // cd signoz/deploy/docker // docker compose up Environment.SetEnvironmentVariable("OTEL_EXPORTER_OTLP_ENDPOINT", "http://localhost:4317"); // 4317 or 4318 +// crate builder from Microsoft.Extensions.Hosting.Host var builder = Host.CreateApplicationBuilder(args); builder.Logging.AddOpenTelemetry(logging => @@ -1214,55 +1205,58 @@ builder.Logging.AddOpenTelemetry(logging => }); builder.Services.AddOpenTelemetry() + .UseOtlpExporter() .ConfigureResource(resource => { resource.AddService("ConsoleAppFramework Telemetry Sample"); }) .WithMetrics(metrics => { + // configure for metrics metrics.AddRuntimeInstrumentation() - .AddHttpClientInstrumentation() - .AddOtlpExporter(); + .AddHttpClientInstrumentation(); }) .WithTracing(tracing => { + // configure for tracing tracing.SetSampler(new AlwaysOnSampler()) .AddHttpClientInstrumentation() - .AddSource(ConsoleAppFrameworkSampleActivitySource.Name) // add trace source - .AddOtlpExporter(); + .AddSource(ConsoleAppFrameworkSampleActivitySource.Name); }) .WithLogging(logging => { - logging.AddOtlpExporter(); + // configure for logging }); var app = builder.ToConsoleAppBuilder(); -var consoleAppLoger = ConsoleApp.ServiceProvider.GetRequiredService>(); // already built service provider. -ConsoleApp.Log = msg => consoleAppLoger.LogDebug(msg); -ConsoleApp.LogError = msg => consoleAppLoger.LogError(msg); +app.Add(); -app.UseFilter(); // use root Trace filter +// setup filter +app.UseFilter(); -app.Add("", async ([FromServices] ILogger logger, CancellationToken cancellationToken) => +await app.RunAsync(args); // Run + +public class SampleCommand(ILogger logger) { - using var httpClient = new HttpClient(); - var ms = await httpClient.GetStringAsync("https://www.microsoft.com", cancellationToken); - logger.LogInformation(ms); - var google = await httpClient.GetStringAsync("https://www.google.com", cancellationToken); - logger.LogInformation(google); + [Command("")] + public async Task Run(CancellationToken cancellationToken) + { + using var httpClient = new HttpClient(); - var ms2 = httpClient.GetStringAsync("https://www.microsoft.com", cancellationToken); - var google2 = httpClient.GetStringAsync("https://www.google.com", cancellationToken); - var apple2 = httpClient.GetStringAsync("https://www.apple.com", cancellationToken); - await Task.WhenAll(ms2, google2, apple2); + var ms = await httpClient.GetStringAsync("https://www.microsoft.com", cancellationToken); + var google = await httpClient.GetStringAsync("https://www.google.com", cancellationToken); - logger.LogInformation(apple2.Result); + logger.LogInformation("Sequential Query done."); - logger.LogInformation("OK"); -}); + var ms2 = httpClient.GetStringAsync("https://www.microsoft.com", cancellationToken); + var google2 = httpClient.GetStringAsync("https://www.google.com", cancellationToken); + var apple2 = httpClient.GetStringAsync("https://www.apple.com", cancellationToken); + await Task.WhenAll(ms2, google2, apple2); -await app.RunAsync(args); // Run + logger.LogInformation("Parallel Query done."); + } +} ``` When you launch `SigNoz` with docker, the view will be available at `http://localhost:8080/` and the collector at `http://localhost:4317`. diff --git a/sandbox/GeneratorSandbox/Program.cs b/sandbox/GeneratorSandbox/Program.cs index 2e49a058..d42a98b5 100644 --- a/sandbox/GeneratorSandbox/Program.cs +++ b/sandbox/GeneratorSandbox/Program.cs @@ -2,6 +2,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; +using OpenTelemetry; using OpenTelemetry.Logs; using OpenTelemetry.Metrics; using OpenTelemetry.Resources; @@ -14,6 +15,7 @@ // docker compose up Environment.SetEnvironmentVariable("OTEL_EXPORTER_OTLP_ENDPOINT", "http://localhost:4317"); // 4317 or 4318 +// crate builder from Microsoft.Extensions.Hosting.Host var builder = Host.CreateApplicationBuilder(args); builder.Logging.AddOpenTelemetry(logging => @@ -23,55 +25,60 @@ }); builder.Services.AddOpenTelemetry() + .UseOtlpExporter() .ConfigureResource(resource => { resource.AddService("ConsoleAppFramework Telemetry Sample"); }) .WithMetrics(metrics => { + // configure for metrics metrics.AddRuntimeInstrumentation() - .AddHttpClientInstrumentation() - .AddOtlpExporter(); + .AddHttpClientInstrumentation(); }) .WithTracing(tracing => { + // configure for tracing tracing.SetSampler(new AlwaysOnSampler()) .AddHttpClientInstrumentation() - .AddSource(ConsoleAppFrameworkSampleActivitySource.Name) - .AddOtlpExporter(); + .AddSource(ConsoleAppFrameworkSampleActivitySource.Name); }) .WithLogging(logging => { - logging.AddOtlpExporter(); + // configure for logging }); var app = builder.ToConsoleAppBuilder(); -var consoleAppLoger = ConsoleApp.ServiceProvider.GetRequiredService>(); // already built service provider. -ConsoleApp.Log = msg => consoleAppLoger.LogDebug(msg); -ConsoleApp.LogError = msg => consoleAppLoger.LogError(msg); +app.Add(); +// setup filter app.UseFilter(); -app.Add("", async ([FromServices] ILogger logger, CancellationToken cancellationToken) => +await app.RunAsync(args); // Run + +public class SampleCommand(ILogger logger) { - using var httpClient = new HttpClient(); - var ms = await httpClient.GetStringAsync("https://www.microsoft.com", cancellationToken); - logger.LogInformation(ms); - var google = await httpClient.GetStringAsync("https://www.google.com", cancellationToken); - logger.LogInformation(google); + [Command("")] + public async Task Run(CancellationToken cancellationToken) + { + using var httpClient = new HttpClient(); - var ms2 = httpClient.GetStringAsync("https://www.microsoft.com", cancellationToken); - var google2 = httpClient.GetStringAsync("https://www.google.com", cancellationToken); - var apple2 = httpClient.GetStringAsync("https://www.apple.com", cancellationToken); - await Task.WhenAll(ms2, google2, apple2); + var ms = await httpClient.GetStringAsync("https://www.microsoft.com", cancellationToken); + var google = await httpClient.GetStringAsync("https://www.google.com", cancellationToken); - logger.LogInformation(apple2.Result); + logger.LogInformation("Sequential Query done."); + + var ms2 = httpClient.GetStringAsync("https://www.microsoft.com", cancellationToken); + var google2 = httpClient.GetStringAsync("https://www.google.com", cancellationToken); + var apple2 = httpClient.GetStringAsync("https://www.apple.com", cancellationToken); + await Task.WhenAll(ms2, google2, apple2); + + logger.LogInformation("Parallel Query done."); + } +} - logger.LogInformation("OK"); -}); -await app.RunAsync(args); // Run public static class ConsoleAppFrameworkSampleActivitySource { diff --git a/src/ConsoleAppFramework/ConsoleAppBaseCode.cs b/src/ConsoleAppFramework/ConsoleAppBaseCode.cs index 8d13678c..fa482791 100644 --- a/src/ConsoleAppFramework/ConsoleAppBaseCode.cs +++ b/src/ConsoleAppFramework/ConsoleAppBaseCode.cs @@ -632,17 +632,17 @@ public void Run(string[] args, bool startHost, bool stopHost, bool disposeServic Microsoft.Extensions.Hosting.IHost? host = ConsoleApp.ServiceProvider?.GetService(typeof(Microsoft.Extensions.Hosting.IHost)) as Microsoft.Extensions.Hosting.IHost; try { - if (startHost) + if (startHost && host != null) { - host?.StartAsync().GetAwaiter().GetResult(); + host.StartAsync().GetAwaiter().GetResult(); } RunCore(args, cancellationToken); } finally { - if (stopHost) + if (stopHost && host != null) { - host?.StopAsync().GetAwaiter().GetResult(); + host.StopAsync().GetAwaiter().GetResult(); } if (disposeServiceProvider) { @@ -663,9 +663,9 @@ public async Task RunAsync(string[] args, bool startHost, bool stopHost, bool di Microsoft.Extensions.Hosting.IHost? host = ConsoleApp.ServiceProvider?.GetService(typeof(Microsoft.Extensions.Hosting.IHost)) as Microsoft.Extensions.Hosting.IHost; try { - if (startHost) + if (startHost && host != null) { - await host?.StartAsync(); + await host.StartAsync(); } Task? task = null; RunAsyncCore(args, cancellationToken, ref task!); @@ -676,9 +676,9 @@ public async Task RunAsync(string[] args, bool startHost, bool stopHost, bool di } finally { - if (stopHost) + if (stopHost && host != null) { - await host?.StopAsync(); + await host.StopAsync(); } if (disposeServiceProvider) {