From d61d14145a6790036c28194ee234595ae655d574 Mon Sep 17 00:00:00 2001 From: TekH Date: Sun, 12 Jul 2026 17:33:19 +0200 Subject: [PATCH] feat: Add Serilog SQLite sink and Serilog.UI dashboard with centralized log directory configuration - Add Serilog.Sinks.SQLite v7.0.0 for structured logging to SQLite database - Add Serilog.UI v3.2.0 and Serilog.UI.SqliteProvider v1.1.0 for web-based log viewer - Add Serilog.Settings.Configuration v10.0.1 for configuration support - Configure SQLite log storage at E:\LogFiles\Digital Data\ECMJobRunner.WebCron\logs.db - Add Serilog.UI dashboard at /serilog-ui endpoint - Centralize log directory configuration in appsettings.json (Logging:LogDirectory) - Configure Serilog programmatically with Console and SQLite sinks - Remove deprecated Serilog configuration from appsettings files (now using code-based config) - Enable Serilog self-diagnostics for troubleshooting - Both Serilog sink and Serilog.UI use same SQLite database path from configuration --- .../ECMJobRunner.WebCron.csproj | 4 ++ ECMJobRunner.WebCron/Program.cs | 49 +++++++++++++++++-- .../appsettings.Development.json | 24 +++------ ECMJobRunner.WebCron/appsettings.json | 26 +--------- 4 files changed, 56 insertions(+), 47 deletions(-) diff --git a/ECMJobRunner.WebCron/ECMJobRunner.WebCron.csproj b/ECMJobRunner.WebCron/ECMJobRunner.WebCron.csproj index 71515d1..bd7960d 100644 --- a/ECMJobRunner.WebCron/ECMJobRunner.WebCron.csproj +++ b/ECMJobRunner.WebCron/ECMJobRunner.WebCron.csproj @@ -14,8 +14,12 @@ + + + + diff --git a/ECMJobRunner.WebCron/Program.cs b/ECMJobRunner.WebCron/Program.cs index fedb01b..397da17 100644 --- a/ECMJobRunner.WebCron/Program.cs +++ b/ECMJobRunner.WebCron/Program.cs @@ -5,13 +5,35 @@ using Hangfire; using Hangfire.SqlServer; using Microsoft.Data.SqlClient; using Serilog; +using Serilog.Ui.Core.Extensions; +using Serilog.Ui.SqliteDataProvider.Extensions; +using Serilog.Ui.Web.Extensions; -// Configure Serilog from appsettings.json +// Enable Serilog self-diagnostics +Serilog.Debugging.SelfLog.Enable(msg => Console.WriteLine($"[SERILOG] {msg}")); + +// Build temporary configuration to read log directory +var tempConfig = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) + .Build(); + +// Get log directory from configuration +var logDirectory = tempConfig.GetValue("Logging:LogDirectory") + ?? throw new InvalidOperationException("Logging:LogDirectory not found in configuration."); +var sqliteDbPath = Path.Combine(logDirectory, "logs.db"); + +Console.WriteLine($"[INFO] SQLite Log Database Path: {sqliteDbPath}"); + +// Configure Serilog with SQLite sink Log.Logger = new LoggerConfiguration() - .ReadFrom.Configuration(new ConfigurationBuilder() - .AddJsonFile("appsettings.json") - .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true) - .Build()) + .MinimumLevel.Information() + .MinimumLevel.Override("Microsoft.AspNetCore", Serilog.Events.LogEventLevel.Warning) + .MinimumLevel.Override("Microsoft.EntityFrameworkCore", Serilog.Events.LogEventLevel.Warning) + .MinimumLevel.Override("Hangfire", Serilog.Events.LogEventLevel.Information) + .WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}") + .WriteTo.SQLite(sqliteDbPath, storeTimestampInUtc: true) + .Enrich.FromLogContext() .CreateLogger(); try @@ -78,6 +100,20 @@ builder.Services.AddHangfireServer(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); +// Add Serilog.UI with SQLite provider - use same path from configuration +var serilogUiLogDirectory = builder.Configuration.GetValue("Logging:LogDirectory") + ?? throw new InvalidOperationException("Logging:LogDirectory not found in configuration."); +var serilogUiDbPath = Path.Combine(serilogUiLogDirectory, "logs.db"); + +builder.Services.AddSerilogUi(logUIOpt => +{ + logUIOpt.UseSqliteServer(dbOpt => + { + dbOpt.WithConnectionString($"Data Source={serilogUiDbPath}"); + dbOpt.WithTable("Logs"); + }); +}); + var app = builder.Build(); // Configure the HTTP request pipeline. @@ -97,6 +133,9 @@ app.UseHangfireDashboard("/hangfire", new DashboardOptions Authorization = new[] { new AllowAllDashboardAuthorizationFilter() } }); +// Add Serilog.UI Dashboard +app.UseSerilogUi(); + app.MapControllers(); app.Run(); diff --git a/ECMJobRunner.WebCron/appsettings.Development.json b/ECMJobRunner.WebCron/appsettings.Development.json index 1db0dc9..9173c8c 100644 --- a/ECMJobRunner.WebCron/appsettings.Development.json +++ b/ECMJobRunner.WebCron/appsettings.Development.json @@ -1,22 +1,10 @@ { - "Serilog": { - "Using": [ "Serilog.Sinks.Console" ], - "MinimumLevel": { + "Logging": { + "LogLevel": { "Default": "Debug", - "Override": { - "Microsoft.AspNetCore": "Warning", - "Microsoft.EntityFrameworkCore": "Warning", - "Hangfire": "Information" - } - }, - "WriteTo": [ - { - "Name": "Console", - "Args": { - "outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}" - } - } - ], - "Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ] + "Microsoft.AspNetCore": "Warning", + "Microsoft.EntityFrameworkCore": "Warning", + "Hangfire": "Information" + } } } diff --git a/ECMJobRunner.WebCron/appsettings.json b/ECMJobRunner.WebCron/appsettings.json index 320dc21..7899564 100644 --- a/ECMJobRunner.WebCron/appsettings.json +++ b/ECMJobRunner.WebCron/appsettings.json @@ -1,32 +1,10 @@ { - "Serilog": { - "Using": [ "Serilog.Sinks.File" ], - "MinimumLevel": { - "Default": "Information", - "Override": { - "Microsoft.AspNetCore": "Warning", - "Microsoft.EntityFrameworkCore": "Warning", - "Hangfire": "Information" - } - }, - "WriteTo": [ - { - "Name": "File", - "Args": { - "path": "Logs/log-.txt", - "rollingInterval": "Day", - "outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz}] [{Level:u3}] {Message:lj}{NewLine}{Exception}", - "retainedFileCountLimit": 30 - } - } - ], - "Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ] - }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" - } + }, + "LogDirectory": "E:\\LogFiles\\Digital Data\\ECMJobRunner.WebCron" }, "ConnectionStrings": { "SDD-VMP04-SQL17": "Server=SDD-VMP04-SQL17\\DD_DEVELOP01;Database=DD_ECM;User Id=sa;Password=dd;Encrypt=false;TrustServerCertificate=True;"