diff --git a/libraries/JGUZDV.AspNetCore.Extensions.OpenTelemetry/src/JGUZDV.AspNetCore.Extensions.OpenTelemetry.csproj b/libraries/JGUZDV.AspNetCore.Extensions.OpenTelemetry/src/JGUZDV.AspNetCore.Extensions.OpenTelemetry.csproj index 35979e6..1e0a553 100644 --- a/libraries/JGUZDV.AspNetCore.Extensions.OpenTelemetry/src/JGUZDV.AspNetCore.Extensions.OpenTelemetry.csproj +++ b/libraries/JGUZDV.AspNetCore.Extensions.OpenTelemetry/src/JGUZDV.AspNetCore.Extensions.OpenTelemetry.csproj @@ -7,7 +7,7 @@ JGUZDV.AspNetCore.Extensions.OpenTelemetry true - 1.1.1 + 1.1.2 Tobias Beckhoff Zentrum für Datenverarbeitung - JGU Mainz Opinionated extensions to observe ASP.NET Core applications via Azure Monitor and OpenTelemetry. diff --git a/libraries/JGUZDV.AspNetCore.Extensions.OpenTelemetry/src/JGUZDVAspNetCoreOpenTelemetryExtensions.cs b/libraries/JGUZDV.AspNetCore.Extensions.OpenTelemetry/src/JGUZDVAspNetCoreOpenTelemetryExtensions.cs index 346b18d..eb89a1a 100644 --- a/libraries/JGUZDV.AspNetCore.Extensions.OpenTelemetry/src/JGUZDVAspNetCoreOpenTelemetryExtensions.cs +++ b/libraries/JGUZDV.AspNetCore.Extensions.OpenTelemetry/src/JGUZDVAspNetCoreOpenTelemetryExtensions.cs @@ -29,114 +29,117 @@ public static WebApplicationBuilder AddJGUZDVOpenTelemetry(this WebApplicationBu { // Create a logger to give some startup information. As OpenTelemetry and Azure Monitor is very 'quiet', these // are the only informations we will get during startup. - var sp = builder.Services.BuildServiceProvider(); - var loggerFactory = sp.GetRequiredService(); - var logger = loggerFactory.CreateLogger("JGUZDV.AspNetCore.OpenTelemetry.Extensions"); + using (var sp = builder.Services.BuildServiceProvider()) + { + using var loggerFactory = sp.GetRequiredService(); - // Get OpenTelemetry section from appsettings. - var settings = builder.Configuration.GetSection("OpenTelemetry"); + var logger = loggerFactory.CreateLogger("JGUZDV.AspNetCore.OpenTelemetry.Extensions"); - // Its okay if there is no OpenTelemetry settings node, but we will display a warning because this may not be indended. - if (!settings.Exists()) - { - logger?.LogWarning("The JGUZDV OpenTelemetry library is included, but there are no settings to configure it. No telemetry will be sent."); - return builder; - } + // Get OpenTelemetry section from appsettings. + var settings = builder.Configuration.GetSection("OpenTelemetry"); - // As this is the most important option to get OT working, we will "fail fast" here with an appropriate message if it is missing. - // @see also ValidateAndSetDefaults(...) - if (string.IsNullOrWhiteSpace(settings.GetValue("AzureMonitor:ConnectionString"))) - { - throw new ArgumentException("Found OpenTelemetry settings section, but no AzureMonitor:ConnectionString setting is provided."); - } - - // As the app is not built yet, we need to define our own options to use them here. - var otOptions = settings.Get() - ?? throw new ArgumentException("Cannot bind AspNetCoreOpenTelemetryOptions."); - - // Look for ServiceNamespace and ServiceName, as these properties are essential. - ValidateAndSetDefaults(builder, otOptions); - - // Configure the OpenTelemetry tracer provider to add the resource attributes to all traces. - // @see https://learn.microsoft.com/en-us/azure/azure-monitor/app/opentelemetry-configuration?tabs=aspnetcore - // Note: Attribute service.instance.id (CloudRoleInstance) defaults to host name/device name. - var attributes = new Dictionary() { - { "service.namespace", otOptions.ServiceNamespace }, - { "service.name", otOptions.ServiceName! } - }; - - // Add the OpenTelemetry telemetry service to the application. - // This service will collect and send telemetry data to Azure Monitor. - var otBuilder = builder.Services.AddOpenTelemetry(); - - // Adds tracing, which (currently?) seems to include logging. - otBuilder.WithTracing(tracing => - { - tracing.AddAspNetCoreInstrumentation(); - tracing.AddHttpClientInstrumentation(); + // Its okay if there is no OpenTelemetry settings node, but we will display a warning because this may not be indended. + if (!settings.Exists()) + { + logger?.LogWarning("The JGUZDV OpenTelemetry library is included, but there are no settings to configure it. No telemetry will be sent."); + return builder; + } - logger?.LogInformation("JGUZDV OpenTelemetry: Added tracing with AspNetCore instrumentation and HttpClient instrumentation."); - }); + // As this is the most important option to get OT working, we will "fail fast" here with an appropriate message if it is missing. + // @see also ValidateAndSetDefaults(...) + if (string.IsNullOrWhiteSpace(settings.GetValue("AzureMonitor:ConnectionString"))) + { + throw new ArgumentException("Found OpenTelemetry settings section, but no AzureMonitor:ConnectionString setting is provided."); + } + // As the app is not built yet, we need to define our own options to use them here. + var otOptions = settings.Get() + ?? throw new ArgumentException("Cannot bind AspNetCoreOpenTelemetryOptions."); - if(otOptions.UseMeter != null) - { - otBuilder.WithMetrics(metrics => + // Look for ServiceNamespace and ServiceName, as these properties are essential. + ValidateAndSetDefaults(builder, otOptions); + + // Configure the OpenTelemetry tracer provider to add the resource attributes to all traces. + // @see https://learn.microsoft.com/en-us/azure/azure-monitor/app/opentelemetry-configuration?tabs=aspnetcore + // Note: Attribute service.instance.id (CloudRoleInstance) defaults to host name/device name. + var attributes = new Dictionary() { + { "service.namespace", otOptions.ServiceNamespace }, + { "service.name", otOptions.ServiceName! } + }; + + // Add the OpenTelemetry telemetry service to the application. + // This service will collect and send telemetry data to Azure Monitor. + var otBuilder = builder.Services.AddOpenTelemetry(); + + // Adds tracing, which (currently?) seems to include logging. + otBuilder.WithTracing(tracing => { - metrics.AddMeter(otOptions.UseMeter.MeterName); + tracing.AddAspNetCoreInstrumentation(); + tracing.AddHttpClientInstrumentation(); + + logger?.LogInformation("JGUZDV OpenTelemetry: Added tracing with AspNetCore instrumentation and HttpClient instrumentation."); }); - logger?.LogInformation("JGUZDV OpenTelemetry: UseMeter active. Initialized a meter with " + - $"name {otOptions.UseMeter.MeterName}"); - } - else - { - logger?.LogInformation("JGUZDV OpenTelemetry: UseMeter not active. No metrics will be sent."); - } - // Configure the connection string. - // TODO Configure Auth? - otBuilder.UseAzureMonitor(options => - { - options.ConnectionString = otOptions.AzureMonitor.ConnectionString; - }); - - // Configure the ResourceBuilder to add the custom resource attributes to all signals. - // Custom resource attributes should be added AFTER AzureMonitor to override the default ResourceDetectors. - otBuilder.ConfigureResource(resourceBuilder => resourceBuilder.AddAttributes(attributes)); - - // Configure OpenTelemetry options for the "outside" world. Validation and defaults are set via postconfig. - builder.Services.AddOptions() - .BindConfiguration("OpenTelemetry") - .PostConfigure(c => ValidateAndSetDefaults(builder, c)); // Defacto obsolete when we came here, but we reuse it for the defaults. - - - /* This results in double log messages in the azure portal. - * It seems, that the current version 1.2.0 does not need this. - * It seems, that log transfer is configured automatically. - * But I could not find out, where to set options like in the settings below. - * It works without settings, so we use it. - * Version 1.3.0 has a "new" config function "WithLogging" (which currently exists, but only internal, I do not know why) - * Maybe this is should be used in the future? - * TODO Look into the docs when 1.3.0 is stable. - * - builder.Logging - .AddOpenTelemetry(options => + if (otOptions.UseMeter != null) { - options.SetResourceBuilder(ResourceBuilder.CreateEmpty().AddAttributes(attributes)); - options.AddAzureMonitorLogExporter(opts => + otBuilder.WithMetrics(metrics => { - opts.ConnectionString = connectionString; + metrics.AddMeter(otOptions.UseMeter.MeterName); }); - options.IncludeFormattedMessage = true; - options.IncludeScopes = true; - options.ParseStateValues = true; + logger?.LogInformation("JGUZDV OpenTelemetry: UseMeter active. Initialized a meter with " + + $"name {otOptions.UseMeter.MeterName}"); + } + else + { + logger?.LogInformation("JGUZDV OpenTelemetry: UseMeter not active. No metrics will be sent."); + } + + // Configure the connection string. + // TODO Configure Auth? + otBuilder.UseAzureMonitor(options => + { + options.ConnectionString = otOptions.AzureMonitor.ConnectionString; }); - */ - logger?.LogInformation("JGUZDV OpenTelemetry: Configuration finished. Please check traces and values in Azure Portal."); + // Configure the ResourceBuilder to add the custom resource attributes to all signals. + // Custom resource attributes should be added AFTER AzureMonitor to override the default ResourceDetectors. + otBuilder.ConfigureResource(resourceBuilder => resourceBuilder.AddAttributes(attributes)); + + // Configure OpenTelemetry options for the "outside" world. Validation and defaults are set via postconfig. + builder.Services.AddOptions() + .BindConfiguration("OpenTelemetry") + .PostConfigure(c => ValidateAndSetDefaults(builder, c)); // Defacto obsolete when we came here, but we reuse it for the defaults. + + + /* This results in double log messages in the azure portal. + * It seems, that the current version 1.2.0 does not need this. + * It seems, that log transfer is configured automatically. + * But I could not find out, where to set options like in the settings below. + * It works without settings, so we use it. + * Version 1.3.0 has a "new" config function "WithLogging" (which currently exists, but only internal, I do not know why) + * Maybe this is should be used in the future? + * TODO Look into the docs when 1.3.0 is stable. + * + builder.Logging + .AddOpenTelemetry(options => + { + options.SetResourceBuilder(ResourceBuilder.CreateEmpty().AddAttributes(attributes)); + options.AddAzureMonitorLogExporter(opts => + { + opts.ConnectionString = connectionString; + }); + + options.IncludeFormattedMessage = true; + options.IncludeScopes = true; + options.ParseStateValues = true; + }); + */ + logger?.LogInformation("JGUZDV OpenTelemetry: Configuration finished. Please check traces and values in Azure Portal."); + } + return builder; }