diff --git a/docs/Server.md b/docs/Server.md index f7aca65..8c06397 100644 --- a/docs/Server.md +++ b/docs/Server.md @@ -3,7 +3,9 @@ The server by default - runs on port 5146 - Uses Swagger UI in development mode (`/swagger/index.html`) - Ignores API keys when in development mode - +- Uses Elmah error logging (endpoint: `/elmah`, local files: `~/logs`) +- Uses serilog logging (local files: `~/logs`) +- Uses HealthChecks (endpoint: `/healthz`) # Installing the dependencies ## Ubuntu 24.04 1. Install the .NET SDK: `sudo apt update && sudo apt install dotnet-sdk-8.0 -y` diff --git a/src/Server/HealthChecks/AIProviderHealthChecks.cs b/src/Server/HealthChecks/AIProviderHealthChecks.cs new file mode 100644 index 0000000..bd8a0fc --- /dev/null +++ b/src/Server/HealthChecks/AIProviderHealthChecks.cs @@ -0,0 +1,31 @@ +using Microsoft.Extensions.Diagnostics.HealthChecks; +using Server.Migrations; + +namespace Server.HealthChecks; + +public class AIProviderHealthCheck : IHealthCheck +{ + private readonly SearchdomainManager _searchdomainManager; + private readonly ILogger _logger; + public AIProviderHealthCheck(SearchdomainManager searchdomainManager, ILogger logger) + { + _searchdomainManager = searchdomainManager; + _logger = logger; + } + public Task CheckHealthAsync( + HealthCheckContext context, CancellationToken cancellationToken = default) + { + try + { + var _ = _searchdomainManager.client.ListLocalModelsAsync(cancellationToken).Result; + } + catch (Exception ex) + { + _logger.LogCritical("AIProviderHealthCheck - Exception occurred when listing local models: {ex}", ex.Message); + return Task.FromResult( + HealthCheckResult.Unhealthy()); + } + return Task.FromResult( + HealthCheckResult.Healthy()); + } +} diff --git a/src/Server/HealthChecks/ServerHealthChecks.cs b/src/Server/HealthChecks/ServerHealthChecks.cs new file mode 100644 index 0000000..4fc021b --- /dev/null +++ b/src/Server/HealthChecks/ServerHealthChecks.cs @@ -0,0 +1,44 @@ +using Microsoft.Extensions.Diagnostics.HealthChecks; +using Server.Migrations; + +namespace Server.HealthChecks; + +public class DatabaseHealthCheck : IHealthCheck +{ + private readonly SearchdomainManager _searchdomainManager; + private readonly ILogger _logger; + public DatabaseHealthCheck(SearchdomainManager searchdomainManager, ILogger logger) + { + _searchdomainManager = searchdomainManager; + _logger = logger; + } + public Task CheckHealthAsync( + HealthCheckContext context, CancellationToken cancellationToken = default) + { + try + { + DatabaseMigrations.DatabaseGetVersion(_searchdomainManager.helper); + } + catch (Exception ex) + { + _logger.LogCritical("DatabaseHealthCheck - Exception occurred when retrieving and parsing database version: {ex}", ex.Message); + return Task.FromResult( + HealthCheckResult.Unhealthy()); + } + + try + { + _searchdomainManager.helper.ExecuteSQLNonQuery("INSERT INTO settings (name, value) VALUES ('test', 'x');", []); + _searchdomainManager.helper.ExecuteSQLNonQuery("DELETE FROM settings WHERE name = 'test';", []); + } + catch (Exception ex) + { + _logger.LogCritical("DatabaseHealthCheck - Exception occurred when executing INSERT/DELETE query: {ex}", ex.Message); + return Task.FromResult( + HealthCheckResult.Unhealthy()); + } + + return Task.FromResult( + HealthCheckResult.Healthy()); + } +} diff --git a/src/Server/Program.cs b/src/Server/Program.cs index 4d8a90b..5b08e35 100644 --- a/src/Server/Program.cs +++ b/src/Server/Program.cs @@ -2,6 +2,7 @@ using ElmahCore; using ElmahCore.Mvc; using Serilog; using Server; +using Server.HealthChecks; var builder = WebApplication.CreateBuilder(args); @@ -16,6 +17,9 @@ Log.Logger = new LoggerConfiguration() .CreateLogger(); builder.Logging.AddSerilog(); builder.Services.AddSingleton(); +builder.Services.AddHealthChecks() + .AddCheck("DatabaseHealthCheck") + .AddCheck("AIProviderHealthChecck"); builder.Services.AddElmah(Options => { @@ -48,6 +52,8 @@ app.Use(async (context, next) => app.UseElmah(); +app.MapHealthChecks("/healthz"); + // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) {