From 65132fc7c62985bf574d5b556b6c5cc092ccf74a Mon Sep 17 00:00:00 2001 From: morbalint Date: Tue, 23 Jan 2024 13:10:16 +0100 Subject: [PATCH] add open telemetry and refactor setup --- Kemkas.Web/Config/ExternalAuthOptions.cs | 10 ++ .../Config/WebApplicationBuilderExtensions.cs | 77 +++++++++ Kemkas.Web/Kemkas.Web.csproj | 5 + Kemkas.Web/Program.cs | 29 ++-- Kemkas.Web/packages.lock.json | 158 ++++++++++++++++++ 5 files changed, 260 insertions(+), 19 deletions(-) create mode 100644 Kemkas.Web/Config/ExternalAuthOptions.cs create mode 100644 Kemkas.Web/Config/WebApplicationBuilderExtensions.cs diff --git a/Kemkas.Web/Config/ExternalAuthOptions.cs b/Kemkas.Web/Config/ExternalAuthOptions.cs new file mode 100644 index 0000000..d3e2159 --- /dev/null +++ b/Kemkas.Web/Config/ExternalAuthOptions.cs @@ -0,0 +1,10 @@ +namespace Kemkas.Web.Config; + +public class ExternalAuthOptions +{ + public string? ClientId { get; set; } + + public string? ClientSecret { get; set; } + + public bool IsValid() => ClientId != null && ClientSecret != null; +} \ No newline at end of file diff --git a/Kemkas.Web/Config/WebApplicationBuilderExtensions.cs b/Kemkas.Web/Config/WebApplicationBuilderExtensions.cs new file mode 100644 index 0000000..b685b0a --- /dev/null +++ b/Kemkas.Web/Config/WebApplicationBuilderExtensions.cs @@ -0,0 +1,77 @@ +using OpenTelemetry.Metrics; +using OpenTelemetry.Resources; +using OpenTelemetry.Trace; + +namespace Kemkas.Web.Config; + +public static class WebApplicationBuilderExtensions +{ + public static void AddAuth(this WebApplicationBuilder builder) + { + var externalAuthConfigSection = builder.Configuration.GetSection("Authentication"); + var authenticationBuilder = builder.Services.AddAuthentication(); + + var googleAuthOptions = new ExternalAuthOptions(); + externalAuthConfigSection.GetSection("Google").Bind(googleAuthOptions); + if (googleAuthOptions.IsValid()) + { + authenticationBuilder.AddGoogle(options => + { + options.ClientId = googleAuthOptions.ClientId!; + options.ClientSecret = googleAuthOptions.ClientSecret!; + }); + } + + var facebookAuthOptions = new ExternalAuthOptions(); + externalAuthConfigSection.GetSection("Facebook").Bind(facebookAuthOptions); + if (facebookAuthOptions.IsValid()) + { + authenticationBuilder.AddFacebook(options => + { + options.ClientId = facebookAuthOptions.ClientId!; + options.ClientSecret = facebookAuthOptions.ClientSecret!; + }); + } + + var discordAuthOptions = new ExternalAuthOptions(); + externalAuthConfigSection.GetSection("Discord").Bind(discordAuthOptions); + if (discordAuthOptions.IsValid()) + { + authenticationBuilder.AddDiscord(options => + { + options.ClientId = discordAuthOptions.ClientId!; + options.ClientSecret = discordAuthOptions.ClientSecret!; + }); + } + } + + public static void AddOpenTelemetry(this WebApplicationBuilder builder) + { + var otlResourceBuilder = ResourceBuilder.CreateDefault().AddService("kemkas-api"); + var openTelemetryEndpoint = builder.Configuration.GetSection("monitoring")["url"]; + + builder.Services.AddOpenTelemetry().WithTracing(tracerProviderBuilder => + { + tracerProviderBuilder + .SetResourceBuilder(otlResourceBuilder) + .AddAspNetCoreInstrumentation() + .AddConsoleExporter(); + if (openTelemetryEndpoint != null) + { + tracerProviderBuilder.AddOtlpExporter(opt => opt.Endpoint = new Uri(openTelemetryEndpoint)); + } + }) + .WithMetrics(meterProviderBuilder => + { + meterProviderBuilder + .SetResourceBuilder(otlResourceBuilder) + .AddAspNetCoreInstrumentation() + .AddConsoleExporter(); + if (openTelemetryEndpoint != null) + { + meterProviderBuilder.AddOtlpExporter(opt => opt.Endpoint = new Uri(openTelemetryEndpoint)); + } + }); + } + +} \ No newline at end of file diff --git a/Kemkas.Web/Kemkas.Web.csproj b/Kemkas.Web/Kemkas.Web.csproj index 8f23aeb..e95fe57 100644 --- a/Kemkas.Web/Kemkas.Web.csproj +++ b/Kemkas.Web/Kemkas.Web.csproj @@ -18,6 +18,7 @@ + @@ -36,6 +37,10 @@ + + + + diff --git a/Kemkas.Web/Program.cs b/Kemkas.Web/Program.cs index 7c6bb7b..603f477 100644 --- a/Kemkas.Web/Program.cs +++ b/Kemkas.Web/Program.cs @@ -11,6 +11,9 @@ using Kemkas.Web.Services.Identity; using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.HttpOverrides; using Microsoft.AspNetCore.Identity.UI.Services; +using OpenTelemetry.Metrics; +using OpenTelemetry.Resources; +using OpenTelemetry.Trace; using IPNetwork = Microsoft.AspNetCore.HttpOverrides.IPNetwork; var builder = WebApplication.CreateBuilder(args); @@ -34,25 +37,7 @@ builder.Services.AddSingleton(); builder.Services.AddDefaultIdentity(options => options.SignIn.RequireConfirmedAccount = true) .AddEntityFrameworkStores(); -builder.Services.AddAuthentication() - .AddGoogle(options => - { - var section = builder.Configuration.GetSection("Authentication:Google"); - options.ClientId = section["ClientId"]; - options.ClientSecret = section["ClientSecret"]; - }) - .AddFacebook(options => - { - var section = builder.Configuration.GetSection("Authentication:Facebook"); - options.ClientId = section["ClientId"]; - options.ClientSecret = section["ClientSecret"]; - }) - .AddDiscord(options => - { - var section = builder.Configuration.GetSection("Authentication:Discord"); - options.ClientId = section["ClientId"]; - options.ClientSecret = section["ClientSecret"]; - }); +builder.AddAuth(); builder.Services.AddControllersWithViews().AddJsonOptions(options => { @@ -62,6 +47,10 @@ builder.Services.AddControllersWithViews().AddJsonOptions(options => }); builder.Services.AddRazorPages(); +builder.AddOpenTelemetry(); + +builder.Services.AddHealthChecks(); + builder.Services.AddCharacterServices(); var app = builder.Build(); @@ -93,6 +82,8 @@ else app.UseHsts(); // TODO: check if this should be handled by proxy } +app.UseHealthChecks("/health"); + await using (var scope = app.Services.CreateAsyncScope()) { var db = scope.ServiceProvider.GetRequiredService(); diff --git a/Kemkas.Web/packages.lock.json b/Kemkas.Web/packages.lock.json index 4da6e46..957403c 100644 --- a/Kemkas.Web/packages.lock.json +++ b/Kemkas.Web/packages.lock.json @@ -8,6 +8,16 @@ "resolved": "8.0.0", "contentHash": "+MtOHPctq1QT1c03h+7g4oBWtZ/buQYUJg4AR0DG+qjmD2cQRMGWXC1J6/ITeCc6xa5BcXzJmt1L/8pVXIB4kw==" }, + "Grpc.Core": { + "type": "Direct", + "requested": "[2.46.6, )", + "resolved": "2.46.6", + "contentHash": "ZoRg3KmOJ2urTF4+u3H0b1Yv10xzz2Y/flFWS2tnRmj8dbKLeiJaSRqu4LOBD3ova90evqLkVZ85kUkC4JT4lw==", + "dependencies": { + "Grpc.Core.Api": "2.46.6", + "System.Memory": "4.5.3" + } + }, "Microsoft.AspNetCore.Authentication.Facebook": { "type": "Direct", "requested": "[8.0.0, )", @@ -124,6 +134,78 @@ "Npgsql.EntityFrameworkCore.PostgreSQL": "1.1.0" } }, + "OpenTelemetry.Exporter.Console": { + "type": "Direct", + "requested": "[1.7.0, )", + "resolved": "1.7.0", + "contentHash": "9mcwpArzG7+5cLnG6marWdVD1TyoVR03WAjShvxADqgsEeuzLMClTlgXi41bTCAgxjYyiHV5l60fJwXTekiJdQ==", + "dependencies": { + "OpenTelemetry": "1.7.0", + "System.Text.Encodings.Web": "4.7.2", + "System.Text.Json": "4.7.2" + } + }, + "OpenTelemetry.Exporter.OpenTelemetryProtocol": { + "type": "Direct", + "requested": "[1.7.0, )", + "resolved": "1.7.0", + "contentHash": "ULGTxg4HdnJD+CIuiD15Uov4xVVqwpbNGFd075J3MT3lLM9XcwU4YRz7CCNmqIlehYaiZrGhUurXrI2LgZZL1Q==", + "dependencies": { + "Google.Protobuf": "[3.22.5, 4.0.0)", + "Grpc.Net.Client": "[2.52.0, 3.0.0)", + "OpenTelemetry": "1.7.0" + } + }, + "OpenTelemetry.Extensions.Hosting": { + "type": "Direct", + "requested": "[1.7.0, )", + "resolved": "1.7.0", + "contentHash": "MbB7CWWqb7xHK0jTF9Gtvw/eLWdaKqzkE1XAwLe05xyskHuwJWAbZFax4nGLA71YkMWQNO5iPIBlirvYXOLMlg==", + "dependencies": { + "Microsoft.Extensions.Diagnostics.Abstractions": "8.0.0", + "Microsoft.Extensions.Hosting.Abstractions": "8.0.0", + "OpenTelemetry": "1.7.0" + } + }, + "OpenTelemetry.Instrumentation.AspNetCore": { + "type": "Direct", + "requested": "[1.7.0, )", + "resolved": "1.7.0", + "contentHash": "K/mjCmuR9zgrL6fMC6sbnX/y6BOJJFI3hp42O+tz8nT/w6sxbfjrLcU+fVwfct3lsnohSKdPfrq6fSrxAF5ezw==", + "dependencies": { + "OpenTelemetry.Api.ProviderBuilderExtensions": "1.7.0" + } + }, + "Google.Protobuf": { + "type": "Transitive", + "resolved": "3.22.5", + "contentHash": "tTMtDZPbLxJew8pk7NBdqhLqC4OipfkZdwPuCEUNr2AoDo1siUGcxFqJK0wDewTL8ge5Cjrb16CToMPxBUHMGA==" + }, + "Grpc.Core.Api": { + "type": "Transitive", + "resolved": "2.52.0", + "contentHash": "SQiPyBczG4vKPmI6Fd+O58GcxxDSFr6nfRAJuBDUNj+PgdokhjWJvZE/La1c09AkL2FVm/jrDloG89nkzmVF7A==", + "dependencies": { + "System.Memory": "4.5.3" + } + }, + "Grpc.Net.Client": { + "type": "Transitive", + "resolved": "2.52.0", + "contentHash": "hWVH9g/Nnjz40ni//2S8UIOyEmhueQREoZIkD0zKHEPqLxXcNlbp4eebXIOicZtkwDSx0TFz9NpkbecEDn6rBw==", + "dependencies": { + "Grpc.Net.Common": "2.52.0", + "Microsoft.Extensions.Logging.Abstractions": "3.0.3" + } + }, + "Grpc.Net.Common": { + "type": "Transitive", + "resolved": "2.52.0", + "contentHash": "di9qzpdx525IxumZdYmu6sG2y/gXJyYeZ1ruFUzB9BJ1nj4kU1/dTAioNCMt1VLRvNVDqh8S8B1oBdKhHJ4xRg==", + "dependencies": { + "Grpc.Core.Api": "2.52.0" + } + }, "Humanizer.Core": { "type": "Transitive", "resolved": "2.14.1", @@ -265,6 +347,15 @@ "Microsoft.Extensions.Primitives": "8.0.0" } }, + "Microsoft.Extensions.Configuration": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "0J/9YNXTMWSZP2p2+nvl8p71zpSwokZXZuJW+VjdErkegAnFdO1XlqtA62SJtgVYHdKu3uPxJHcMR/r35HwFBA==", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + } + }, "Microsoft.Extensions.Configuration.Abstractions": { "type": "Transitive", "resolved": "8.0.0", @@ -273,6 +364,14 @@ "Microsoft.Extensions.Primitives": "8.0.0" } }, + "Microsoft.Extensions.Configuration.Binder": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "mBMoXLsr5s1y2zOHWmKsE9veDcx8h1x/c3rz4baEdQKTeDcmQAPNbB54Pi/lhFO3K431eEq6PFbMgLaa6PHFfA==", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0" + } + }, "Microsoft.Extensions.DependencyInjection": { "type": "Transitive", "resolved": "8.0.0", @@ -371,6 +470,21 @@ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" } }, + "Microsoft.Extensions.Logging.Configuration": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "ixXXV0G/12g6MXK65TLngYN9V5hQQRuV+fZi882WIoVJT7h5JvoYoxTEwCgdqwLjSneqh1O+66gM8sMr9z/rsQ==", + "dependencies": { + "Microsoft.Extensions.Configuration": "8.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Configuration.Binder": "8.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", + "Microsoft.Extensions.Logging": "8.0.0", + "Microsoft.Extensions.Logging.Abstractions": "8.0.0", + "Microsoft.Extensions.Options": "8.0.0", + "Microsoft.Extensions.Options.ConfigurationExtensions": "8.0.0" + } + }, "Microsoft.Extensions.Options": { "type": "Transitive", "resolved": "8.0.0", @@ -380,6 +494,18 @@ "Microsoft.Extensions.Primitives": "8.0.0" } }, + "Microsoft.Extensions.Options.ConfigurationExtensions": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "0f4DMRqEd50zQh+UyJc+/HiBsZ3vhAQALgdkcQEalSH1L2isdC7Yj54M3cyo5e+BeO5fcBQ7Dxly8XiBBcvRgw==", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Configuration.Binder": "8.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", + "Microsoft.Extensions.Options": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + } + }, "Microsoft.Extensions.Primitives": { "type": "Transitive", "resolved": "8.0.0", @@ -472,6 +598,33 @@ "Microsoft.Extensions.Logging.Abstractions": "8.0.0" } }, + "OpenTelemetry": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "HNmOJg++4FtEJGCIn1dCJcDkHRLNuLKU047owrGXUOfz/C/c5oZHOPKrowKVOy2jOOh/F9+HDshzeOk5NnQEZg==", + "dependencies": { + "Microsoft.Extensions.Logging": "8.0.0", + "Microsoft.Extensions.Logging.Configuration": "8.0.0", + "OpenTelemetry.Api.ProviderBuilderExtensions": "1.7.0" + } + }, + "OpenTelemetry.Api": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "w5uDHl1Nm7R5igWu1QjewpdPzJSavua8NTI3+iThOdRNHD3cabox8JeIJ8LpBSXGHARSNFMJZ/Xr5EGRinMTMg==", + "dependencies": { + "System.Diagnostics.DiagnosticSource": "8.0.0" + } + }, + "OpenTelemetry.Api.ProviderBuilderExtensions": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "fHLmJcRJk1dAwddjBgvqi/Grmr04hPo1DoFwTa6hxtSvAFOXPU56Xe9Sh2VXqz6Gstzp6TCju8z0Sob1t7BzSg==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", + "OpenTelemetry.Api": "1.7.0" + } + }, "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": { "type": "Transitive", "resolved": "4.3.0", @@ -887,6 +1040,11 @@ "System.Threading": "4.3.0" } }, + "System.Memory": { + "type": "Transitive", + "resolved": "4.5.3", + "contentHash": "3oDzvc/zzetpTKWMShs1AADwZjQ/36HnsufHRPcOjyRAAMLDlu2iD33MBI2opxnezcVUtXyqDXXjoFMOU9c7SA==" + }, "System.Net.Http": { "type": "Transitive", "resolved": "4.3.0",