Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed a problem with a non disposed built service provider. #131

Merged
merged 1 commit into from
Jan 3, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@

<PackageId>JGUZDV.AspNetCore.Extensions.OpenTelemetry</PackageId>
<IsPackable>true</IsPackable>
<Version>1.1.1</Version>
<Version>1.1.2</Version>
<Authors>Tobias Beckhoff</Authors>
<Company>Zentrum für Datenverarbeitung - JGU Mainz</Company>
<PackageDescription>Opinionated extensions to observe ASP.NET Core applications via Azure Monitor and OpenTelemetry.</PackageDescription>
Original file line number Diff line number Diff line change
@@ -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<ILoggerFactory>();
var logger = loggerFactory.CreateLogger("JGUZDV.AspNetCore.OpenTelemetry.Extensions");
using (var sp = builder.Services.BuildServiceProvider())
{
using var loggerFactory = sp.GetRequiredService<ILoggerFactory>();

// 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<string>("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<AspNetCoreOpenTelemetryOptions>()
?? 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<string, object>() {
{ "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<string>("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<AspNetCoreOpenTelemetryOptions>()
?? 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<string, object>() {
{ "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<AspNetCoreOpenTelemetryOptions>()
.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<AspNetCoreOpenTelemetryOptions>()
.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;
}

Loading