This commit is contained in:
Flaminel
2025-05-19 19:30:12 +03:00
parent eb0f782f53
commit 701a7dc417
24 changed files with 322 additions and 252 deletions

View File

@@ -1,15 +1,9 @@
using Common.Configuration.General;
using Common.Configuration.Logging;
using Domain.Enums;
using Infrastructure.Configuration;
using Infrastructure.Logging;
using Infrastructure.Verticals.ContentBlocker;
using Infrastructure.Verticals.DownloadCleaner;
using Infrastructure.Verticals.QueueCleaner;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.AspNetCore.SignalR;
using Serilog;
using Serilog.Core;
using Serilog.Events;
using Serilog.Templates;
using Serilog.Templates.Themes;
@@ -18,40 +12,15 @@ namespace Executable.DependencyInjection;
public static class LoggingDI
{
public static ILoggingBuilder AddLogging(this ILoggingBuilder builder, IServiceProvider serviceProvider)
public static ILoggingBuilder AddLogging(this ILoggingBuilder builder)
{
// Register LoggingConfigManager as a singleton
serviceProvider.GetRequiredService<IServiceCollection>()
.TryAddSingleton<LoggingConfigManager>();
Log.Logger = GetDefaultLoggerConfiguration().CreateLogger();
// Get LoggingConfigManager (will be created if not already registered)
var configManager = serviceProvider.GetRequiredService<LoggingConfigManager>();
// Get the dynamic level switch for controlling log levels
var levelSwitch = configManager.GetLevelSwitch();
// Get the configuration path provider
var pathProvider = serviceProvider.GetRequiredService<ConfigurationPathProvider>();
// Get logging config from the config manager
var config = serviceProvider.GetRequiredService<ConfigManager>()
.GetConfiguration<GeneralConfig>().Logging;
// Create the logs directory
string logsPath = Path.Combine(pathProvider.GetConfigPath(), "logs");
if (!Directory.Exists(logsPath))
{
try
{
Directory.CreateDirectory(logsPath);
}
catch (Exception exception)
{
throw new Exception($"Failed to create log directory | {logsPath}", exception);
}
}
return builder.ClearProviders().AddSerilog();
}
public static LoggerConfiguration GetDefaultLoggerConfiguration()
{
LoggerConfiguration logConfig = new();
const string categoryTemplate = "{#if Category is not null} {Concat('[',Category,']'),CAT_PAD}{#end}";
const string jobNameTemplate = "{#if JobName is not null} {Concat('[',JobName,']'),JOB_PAD}{#end}";
@@ -87,9 +56,24 @@ public static class LoggingDI
// Configure base logger with dynamic level control
logConfig
.MinimumLevel.ControlledBy(levelSwitch)
// .MinimumLevel.ControlledBy(levelSwitch)
.MinimumLevel.Is(LogEventLevel.Information)
.Enrich.FromLogContext()
.WriteTo.Console(new ExpressionTemplate(consoleTemplate, theme: TemplateTheme.Literate));
// Create the logs directory
string logsPath = Path.Combine(ConfigurationPathProvider.GetConfigPath(), "logs");
if (!Directory.Exists(logsPath))
{
try
{
Directory.CreateDirectory(logsPath);
}
catch (Exception exception)
{
throw new Exception($"Failed to create log directory | {logsPath}", exception);
}
}
// Add main log file
logConfig.WriteTo.File(
@@ -100,47 +84,14 @@ public static class LoggingDI
rollOnFileSizeLimit: true
);
// Add category-specific log files
foreach (var category in categories)
{
logConfig.WriteTo.Logger(lc => lc
.Filter.ByIncludingOnly(e =>
e.Properties.TryGetValue("Category", out var prop) &&
prop.ToString().Contains(category, StringComparison.OrdinalIgnoreCase))
.WriteTo.File(
path: Path.Combine(logsPath, $"{category.ToLower()}-.txt"),
formatter: new ExpressionTemplate(fileTemplate),
fileSizeLimitBytes: 5L * 1024 * 1024,
rollingInterval: RollingInterval.Day,
rollOnFileSizeLimit: true
)
);
}
// Configure SignalR log sink if enabled
if (config?.SignalR?.Enabled != false)
{
var bufferSize = config?.SignalR?.BufferSize ?? 100;
// Create and register LogBuffer
var logBuffer = new LogBuffer(bufferSize);
serviceProvider.GetRequiredService<IServiceCollection>().AddSingleton(logBuffer);
// Create a log sink for SignalR
logConfig.WriteTo.Sink(new DeferredSignalRSink());
}
Log.Logger = logConfig
logConfig
.MinimumLevel.Override("MassTransit", LogEventLevel.Warning)
.MinimumLevel.Override("Microsoft.Hosting.Lifetime", LogEventLevel.Information)
.MinimumLevel.Override("Microsoft.Extensions.Http", LogEventLevel.Warning)
.MinimumLevel.Override("Quartz", LogEventLevel.Warning)
.MinimumLevel.Override("System.Net.Http.HttpClient", LogEventLevel.Error)
.Enrich.WithProperty("ApplicationName", "cleanuperr")
.CreateLogger();
return builder
.ClearProviders()
.AddSerilog(dispose: true);
.Enrich.WithProperty("ApplicationName", "cleanuperr");
return logConfig;
}
}

View File

@@ -1,5 +1,7 @@
using Executable;
using Executable.DependencyInjection;
using Infrastructure.Logging;
using Serilog;
var builder = WebApplication.CreateBuilder(args);
@@ -8,15 +10,36 @@ builder.Services
.AddInfrastructure(builder.Configuration)
.AddApiServices();
// Register SignalR - ensure this is before logging initialization
builder.Services.AddSignalR();
// Register services needed for logging first
builder.Services.AddSingleton<Infrastructure.Logging.LoggingConfigManager>();
builder.Services
.AddSingleton<LoggingConfigManager>()
.AddSingleton<SignalRLogSink>();
// Add logging with proper service provider
var serviceProvider = builder.Services.BuildServiceProvider();
await builder.Logging.AddLogging(serviceProvider);
builder.Logging.AddLogging();
var app = builder.Build();
// Get LoggingConfigManager (will be created if not already registered)
var configManager = app.Services.GetRequiredService<LoggingConfigManager>();
// Get the dynamic level switch for controlling log levels
var levelSwitch = configManager.GetLevelSwitch();
// Get the SignalRLogSink instance
var signalRSink = app.Services.GetRequiredService<SignalRLogSink>();
var logConfig = LoggingDI.GetDefaultLoggerConfiguration();
logConfig.MinimumLevel.ControlledBy(levelSwitch);
// Add to Serilog pipeline
logConfig.WriteTo.Sink(signalRSink);
Log.Logger = logConfig.CreateLogger();
// Configure the HTTP request pipeline
app.ConfigureApi();

View File

@@ -1,13 +0,0 @@
{
"clients": [
{
"enabled": true,
"id": "1ded77f9-199c-4325-9de6-7758b691e5e6",
"name": "qbittorrent",
"host": "http://localhost:8080",
"username": "test",
"password": "testing",
"type": "qbittorrent"
}
]
}

View File

@@ -6,17 +6,17 @@
"ignored_downloads_path": "",
"sonarr": {
"enabled": false,
"type": 0,
"type": "Blacklist",
"path": null
},
"radarr": {
"enabled": false,
"type": 0,
"type": "Blacklist",
"path": null
},
"lidarr": {
"enabled": false,
"type": 0,
"type": "Blacklist",
"path": null
}
}

View File

@@ -0,0 +1,3 @@
{
"clients": []
}

View File

@@ -4,5 +4,6 @@
"http_timeout": 100,
"certificate_validation": "Enabled",
"search_enabled": true,
"search_delay": 30
"search_delay": 30,
"log_level": "Information"
}

View File

@@ -0,0 +1,24 @@
{
"notifiarr": {
"api_key": null,
"channel_id": null,
"on_failed_import_strike": false,
"on_stalled_strike": false,
"on_slow_strike": false,
"on_queue_item_deleted": false,
"on_download_cleaned": false,
"on_category_changed": false,
"is_enabled": false
},
"apprise": {
"url": null,
"key": null,
"on_failed_import_strike": false,
"on_stalled_strike": false,
"on_slow_strike": false,
"on_queue_item_deleted": false,
"on_download_cleaned": false,
"on_category_changed": false,
"is_enabled": false
}
}

View File

@@ -1,22 +1,22 @@
{
"enabled": true,
"cron_expression": "0/30 * * * * ?",
"enabled": false,
"cron_expression": "0 0/5 * * * ?",
"run_sequentially": false,
"ignored_downloads_path": "",
"import_failed_max_strikes": 3,
"import_failed_max_strikes": 0,
"import_failed_ignore_private": false,
"import_failed_delete_private": false,
"import_failed_ignore_patterns": [],
"stalled_max_strikes": 3,
"stalled_max_strikes": 0,
"stalled_reset_strikes_on_progress": false,
"stalled_ignore_private": false,
"stalled_delete_private": false,
"downloading_metadata_max_strikes": 3,
"slow_max_strikes": 3,
"downloading_metadata_max_strikes": 0,
"slow_max_strikes": 0,
"slow_reset_strikes_on_progress": false,
"slow_ignore_private": false,
"slow_delete_private": false,
"slow_min_speed": "1KB",
"slow_min_speed": "",
"slow_max_time": 0,
"slow_ignore_above_size": ""
}

View File

@@ -0,0 +1,6 @@
{
"search_type": "Episode",
"enabled": false,
"import_failed_max_strikes": -1,
"instances": []
}

View File

@@ -1,13 +0,0 @@
{
"enabled": true,
"search_type": "episode",
"import_failed_max_strikes": -1,
"instances": [
{
"id": "c260fdf2-5f79-4449-b40b-1dce1e8ef2ac",
"name": "sonarr1",
"url": "http://localhost:8989",
"api_key": "425d1e713f0c405cbbf359ac0502c1f4"
}
]
}