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",