0
0
mirror of https://github.com/alex289/CleanArchitecture.git synced 2025-06-29 18:21:08 +00:00

feat: Improve Aspire telemetry

This commit is contained in:
Alexander Konietzko 2025-04-14 15:17:06 +02:00
parent 27c8b6064c
commit 2f494932f8
No known key found for this signature in database
GPG Key ID: BA6905F37AEC2B5B
5 changed files with 122 additions and 11 deletions

View File

@ -7,13 +7,14 @@ var rabbitPasswordParameter =
builder.AddParameter("username", rabbitPasswordRessource.Value);
var rabbitMq = builder
.AddRabbitMQ("RabbitMq", null, rabbitPasswordParameter, 5672)
.AddRabbitMQ("RabbitMQ", null, rabbitPasswordParameter, 5672)
.WithManagementPlugin();
var sqlServer = builder.AddSqlServer("SqlServer");
var db = sqlServer.AddDatabase("Database", "clean-architecture");
builder.AddProject<Projects.CleanArchitecture_Api>("CleanArchitecture-Api")
.WithEnvironment("ASPIRE_ENABLED", "true")
.WithOtlpExporter()
.WithHttpHealthCheck("/health")
.WithReference(redis)

View File

@ -4,14 +4,13 @@
"Aspire": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchBrowser": false,
"applicationUrl": "https://localhost:17270;http://localhost:15188",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21200",
"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22111",
"ASPIRE_ENABLED": "true"
"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22111"
}
}
}

View File

@ -4,5 +4,6 @@
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
},
"EnableHttpTraces": false
}

View File

@ -1,5 +1,6 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Hosting;
@ -39,6 +40,8 @@ public static class Extensions
private static void ConfigureOpenTelemetry<TBuilder>(this TBuilder builder) where TBuilder : IHostApplicationBuilder
{
var enableHttpTraces = builder.Configuration.GetValue<bool?>("APP_ENABLE_HTTP_TRACES") ?? false;
builder.Logging.AddOpenTelemetry(logging =>
{
logging.IncludeFormattedMessage = true;
@ -48,17 +51,44 @@ public static class Extensions
builder.Services.AddOpenTelemetry()
.WithMetrics(metrics =>
{
metrics.AddAspNetCoreInstrumentation()
metrics
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddRuntimeInstrumentation();
})
.WithTracing(tracing =>
{
tracing.AddSource(builder.Environment.ApplicationName)
.AddAspNetCoreInstrumentation()
.AddGrpcClientInstrumentation()
.AddEntityFrameworkCoreInstrumentation()
.AddHttpClientInstrumentation();
tracing
.AddSource(builder.Environment.ApplicationName)
.AddSource("MassTransit")
.AddAspNetCoreInstrumentation(options =>
{
options.EnableAspNetCoreSignalRSupport = true;
options.EnrichWithHttpResponse = HttpEnricher.HttpRouteEnricher;
})
.AddGrpcClientInstrumentation(options =>
{
if (enableHttpTraces)
{
options.EnrichWithHttpRequestMessage = HttpEnricher.RequestEnricher;
options.EnrichWithHttpResponseMessage = HttpEnricher.ResponseEnricher;
}
})
.AddEntityFrameworkCoreInstrumentation(options =>
{
options.EnrichWithIDbCommand = (activity, dbCommand) =>
{
activity.SetTag("sql.statement", dbCommand.CommandText);
};
})
.AddHttpClientInstrumentation(options =>
{
if (enableHttpTraces)
{
options.EnrichWithHttpRequestMessage = HttpEnricher.RequestEnricher;
options.EnrichWithHttpResponseMessage = HttpEnricher.ResponseEnricher;
}
});
});
builder.AddOpenTelemetryExporters();

View File

@ -0,0 +1,80 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Routing;
namespace CleanArchitecture.ServiceDefaults;
public static class HttpEnricher
{
public static Action<System.Diagnostics.Activity, HttpRequestMessage>? RequestEnricher = static (activity, request) =>
{
if (request.Content is not null)
{
try
{
var requestContent = request.Content.ReadAsStringAsync().Result;
activity.SetTag("http.request.body", requestContent);
}
catch (HttpRequestException)
{
}
}
else
{
activity.SetTag("http.response.body", null);
}
};
public static Action<System.Diagnostics.Activity, HttpResponseMessage>? ResponseEnricher = static (activity, response) =>
{
if (response.Content is not null)
{
try
{
var responseContent = response.Content.ReadAsStringAsync().Result;
activity.SetTag("http.response.body", responseContent);
}
catch (HttpRequestException)
{
}
catch (ObjectDisposedException)
{
}
}
else
{
activity.SetTag("http.response.body", null);
}
};
public static Action<System.Diagnostics.Activity, HttpResponse>? HttpRouteEnricher = static (activity, request) =>
{
var endpoint = request.HttpContext.GetEndpoint();
if (endpoint is RouteEndpoint routeEndpoint)
{
var descriptor = routeEndpoint.Metadata.GetMetadata<ControllerActionDescriptor>();
if (descriptor is null)
{
return;
}
var controller = descriptor.ControllerName;
var action = descriptor.ActionName;
var pathParameters = descriptor.Parameters
.Where(p => p.BindingInfo is null || p.BindingInfo.BindingSource?.Id == "Path")
.Select(p => $"{{{p.Name}}}");
var route = string.Join("/", [controller, action, .. pathParameters]);
activity.DisplayName = route;
activity.SetTag("http.route", route);
activity.SetTag("Name", route);
}
};
}