add telemetry

This commit is contained in:
2025-04-16 21:28:53 -04:00
parent d3a139feb5
commit 243717fb25
7 changed files with 134 additions and 5 deletions

View File

@@ -15,6 +15,11 @@
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.8.0" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.21.2" />
<PackageReference Include="MimeTypesMap" Version="1.0.9" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.9.0" />
<PackageReference Include="OpenTelemetry.Exporter.Prometheus.AspNetCore" Version="1.9.0-beta.2" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.9.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.9.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.9.0" />
</ItemGroup>
<ItemGroup>

View File

@@ -3,7 +3,7 @@ using Microsoft.Extensions.Options;
using System.Text.Encodings.Web;
namespace AobaServer;
namespace AobaServer.Auth;
internal class AobaAuthenticationHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder) : AuthenticationHandler<AuthenticationSchemeOptions>(options, logger, encoder)
{

View File

@@ -0,0 +1,42 @@
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
namespace AobaServer.Auth;
public class MetricsTokenValidator(AuthInfo authInfo) : JwtSecurityTokenHandler
{
private readonly JwtSecurityTokenHandler _handler = new();
public override Task<TokenValidationResult> ValidateTokenAsync(string token, TokenValidationParameters validationParameters)
{
try
{
var principal = _handler.ValidateToken(token, new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(authInfo.SecureKey),
ValidateIssuer = true,
ValidIssuer = authInfo.Issuer,
ValidateAudience = true,
ValidAudience = "metrics",
ValidateLifetime = false,
ClockSkew = TimeSpan.FromMinutes(1)
}, out var validatedToken);
return Task.FromResult(new TokenValidationResult
{
IsValid = true,
SecurityToken = validatedToken,
ClaimsIdentity = new ClaimsIdentity(principal.Identity),
});
}
catch (Exception e)
{
return Task.FromResult(new TokenValidationResult
{
IsValid = false,
Exception = e
});
}
}
}

View File

@@ -0,0 +1,73 @@
#nullable enable
using AobaServer.Middleware;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using OpenTelemetry;
using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
namespace AobaServer.Middleware;
public static class OpenTelemetry
{
public static void AddObersability(this IServiceCollection services, IConfiguration configuration)
{
var otel = services.AddOpenTelemetry();
otel.ConfigureResource(res =>
{
res.AddService(serviceName: $"Breeze: {Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}");
});
// Add Metrics for ASP.NET Core and our custom metrics and export to Prometheus
otel.WithMetrics(metrics => metrics
// Metrics provider from OpenTelemetry
.AddAspNetCoreInstrumentation()
.AddCustomMetrics()
// Metrics provides by ASP.NET Core in .NET 8
.AddMeter("Microsoft.AspNetCore.Hosting")
.AddMeter("Microsoft.AspNetCore.Server.Kestrel")
// Metrics provided by System.Net libraries
.AddMeter("System.Net.Http")
.AddMeter("System.Net.NameResolution")
.AddMeter("MongoDB.Driver.Core.Extensions.DiagnosticSources")
.AddPrometheusExporter());
// Add Tracing for ASP.NET Core and our custom ActivitySource and export to Jaeger
var tracingOtlpEndpoint = configuration["OTLP_ENDPOINT_URL"];
otel.WithTracing(tracing =>
{
tracing.AddAspNetCoreInstrumentation();
tracing.AddHttpClientInstrumentation();
if (!string.IsNullOrWhiteSpace(tracingOtlpEndpoint))
{
tracing.AddOtlpExporter(otlpOptions =>
{
otlpOptions.Endpoint = new Uri(tracingOtlpEndpoint);
});
}
});
}
public static MeterProviderBuilder AddCustomMetrics(this MeterProviderBuilder builder)
{
return builder;
}
public static IEndpointRouteBuilder MapObserability(this IEndpointRouteBuilder endpoints)
{
endpoints.MapPrometheusScrapingEndpoint().RequireAuthorization(p => p.RequireRole("metrics"));
return endpoints;
}
}

View File

@@ -1,6 +1,8 @@
using AobaCore;
using AobaServer;
using AobaServer.Auth;
using AobaServer.Middleware;
using AobaServer.Models;
using Microsoft.AspNetCore.Authentication;
@@ -13,6 +15,7 @@ var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers(opt => opt.ModelBinderProviders.Add(new BsonIdModelBinderProvider()));
builder.Services.AddObersability(builder.Configuration);
var authInfo = AuthInfo.LoadOrCreate("Auth.json", "aobaV2", "aoba");
builder.Services.AddSingleton(authInfo);
@@ -37,6 +40,7 @@ builder.Services.AddAuthentication(options =>
}).AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options => //Bearer auth
{
options.TokenValidationParameters = validationParams;
options.TokenHandlers.Add(new MetricsTokenValidator(authInfo));
options.Events = new JwtBearerEvents
{
OnMessageReceived = ctx => //Retreive token from cookie if not found in headers
@@ -87,6 +91,7 @@ app.UseAuthorization();
app.MapControllers();
app.MapObserability();
app.Run();