Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 43a11f0e4c | |||
| a5a54e324d |
@@ -88,8 +88,12 @@ docker run -d \
|
|||||||
version: "3.3"
|
version: "3.3"
|
||||||
services:
|
services:
|
||||||
cleanuperr:
|
cleanuperr:
|
||||||
|
volumes:
|
||||||
|
- ./cleanuperr/logs:/var/logs
|
||||||
environment:
|
environment:
|
||||||
- LOGGING__LOGLEVEL__DEFAULT=Information
|
- LOGGING__LOGLEVEL=Information
|
||||||
|
- LOGGING__FILE__ENABLED=false
|
||||||
|
- LOGGING__FILE__PATH=/var/logs/
|
||||||
|
|
||||||
- TRIGGERS__QUEUECLEANER=0 0/5 * * * ?
|
- TRIGGERS__QUEUECLEANER=0 0/5 * * * ?
|
||||||
- TRIGGERS__CONTENTBLOCKER=0 0/5 * * * ?
|
- TRIGGERS__CONTENTBLOCKER=0 0/5 * * * ?
|
||||||
@@ -137,7 +141,9 @@ services:
|
|||||||
|
|
||||||
| Variable | Required | Description | Default value |
|
| Variable | Required | Description | Default value |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| LOGGING__LOGLEVEL__DEFAULT | No | Can be `Debug`, `Information`, `Warning` or `Error` | Information |
|
| LOGGING__LOGLEVEL | No | Can be `Verbose`, `Debug`, `Information`, `Warning`, `Error` or `Fatal` | `Information` |
|
||||||
|
| LOGGING__FILE__ENABLED | No | Enable or disable logging to file | false |
|
||||||
|
| LOGGING__FILE__PATH | No | Directory where to save the log files | empty |
|
||||||
|||||
|
|||||
|
||||||
| TRIGGERS__QUEUECLEANER | Yes if queue cleaner is enabled | [Quartz cron trigger](https://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/crontrigger.html) | 0 0/5 * * * ? |
|
| TRIGGERS__QUEUECLEANER | Yes if queue cleaner is enabled | [Quartz cron trigger](https://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/crontrigger.html) | 0 0/5 * * * ? |
|
||||||
| TRIGGERS__CONTENTBLOCKER | Yes if content blocker is enabled | [Quartz cron trigger](https://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/crontrigger.html) | 0 0/5 * * * ? |
|
| TRIGGERS__CONTENTBLOCKER | Yes if content blocker is enabled | [Quartz cron trigger](https://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/crontrigger.html) | 0 0/5 * * * ? |
|
||||||
@@ -165,11 +171,11 @@ services:
|
|||||||
| TRANSMISSION__USERNAME | No | Transmission user | empty |
|
| TRANSMISSION__USERNAME | No | Transmission user | empty |
|
||||||
| TRANSMISSION__PASSWORD | No | Transmission password | empty |
|
| TRANSMISSION__PASSWORD | No | Transmission password | empty |
|
||||||
|||||
|
|||||
|
||||||
| SONARR__ENABLED | No | Whether Sonarr cleanup is enabled or not | true |
|
| SONARR__ENABLED | No | Enable or disable Sonarr cleanup | true |
|
||||||
| SONARR__INSTANCES__0__URL | Yes | First Sonarr instance url | http://localhost:8989 |
|
| SONARR__INSTANCES__0__URL | Yes | First Sonarr instance url | http://localhost:8989 |
|
||||||
| SONARR__INSTANCES__0__APIKEY | Yes | First Sonarr instance API key | empty |
|
| SONARR__INSTANCES__0__APIKEY | Yes | First Sonarr instance API key | empty |
|
||||||
|||||
|
|||||
|
||||||
| RADARR__ENABLED | No | Whether Radarr cleanup is enabled or not | false |
|
| RADARR__ENABLED | No | Enable or disable Radarr cleanup | false |
|
||||||
| RADARR__INSTANCES__0__URL | Yes | First Radarr instance url | http://localhost:8989 |
|
| RADARR__INSTANCES__0__URL | Yes | First Radarr instance url | http://localhost:8989 |
|
||||||
| RADARR__INSTANCES__0__APIKEY | Yes | First Radarr instance API key | empty |
|
| RADARR__INSTANCES__0__APIKEY | Yes | First Radarr instance API key | empty |
|
||||||
|
|
||||||
@@ -185,7 +191,7 @@ services:
|
|||||||
example* // file name starts with "example"
|
example* // file name starts with "example"
|
||||||
*example* // file name has "example" in the name
|
*example* // file name has "example" in the name
|
||||||
example // file name is exactly the word "example"
|
example // file name is exactly the word "example"
|
||||||
<ANY_REGEX> // regex
|
regex:<ANY_REGEX> // regex that needs to be marked at the start of the line with "regex:"
|
||||||
```
|
```
|
||||||
5. Multiple Sonarr/Radarr instances can be specified using this format, where `<NUMBER>` starts from 0:
|
5. Multiple Sonarr/Radarr instances can be specified using this format, where `<NUMBER>` starts from 0:
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -6,4 +6,8 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Serilog" Version="4.1.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
namespace Common.Configuration.Logging;
|
||||||
|
|
||||||
|
public class FileLogConfig : IConfig
|
||||||
|
{
|
||||||
|
public bool Enabled { get; set; }
|
||||||
|
|
||||||
|
public string Path { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public void Validate()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
using Serilog.Events;
|
||||||
|
|
||||||
|
namespace Common.Configuration.Logging;
|
||||||
|
|
||||||
|
public class LoggingConfig : IConfig
|
||||||
|
{
|
||||||
|
public const string SectionName = "Logging";
|
||||||
|
|
||||||
|
public LogEventLevel LogLevel { get; set; }
|
||||||
|
|
||||||
|
public FileLogConfig? File { get; set; }
|
||||||
|
|
||||||
|
public void Validate()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
using Common.Configuration.Logging;
|
||||||
|
using Infrastructure.Verticals.ContentBlocker;
|
||||||
|
using Infrastructure.Verticals.QueueCleaner;
|
||||||
|
using Serilog;
|
||||||
|
using Serilog.Events;
|
||||||
|
using Serilog.Templates;
|
||||||
|
using Serilog.Templates.Themes;
|
||||||
|
|
||||||
|
namespace Executable.DependencyInjection;
|
||||||
|
|
||||||
|
public static class LoggingDI
|
||||||
|
{
|
||||||
|
public static ILoggingBuilder AddLogging(this ILoggingBuilder builder, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
LoggingConfig? config = configuration.GetSection(LoggingConfig.SectionName).Get<LoggingConfig>();
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(config?.File?.Path) && !Directory.Exists(config.File.Path))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(config.File.Path);
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
throw new Exception($"log file path is not a valid directory | {config.File.Path}", exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LoggerConfiguration logConfig = new();
|
||||||
|
const string consoleOutputTemplate = "[{@t:yyyy-MM-dd HH:mm:ss.fff} {@l:u3}]{#if JobName is not null} {Concat('[',JobName,']'),PAD}{#end} {@m}\n{@x}";
|
||||||
|
const string fileOutputTemplate = "{@t:yyyy-MM-dd HH:mm:ss.fff zzz} [{@l:u3}]{#if JobName is not null} {Concat('[',JobName,']'),PAD}{#end} {@m:lj}\n{@x}";
|
||||||
|
LogEventLevel level = LogEventLevel.Information;
|
||||||
|
List<string> jobNames = [nameof(ContentBlocker), nameof(QueueCleaner)];
|
||||||
|
int padding = jobNames.Max(x => x.Length) + 2;
|
||||||
|
|
||||||
|
if (config is not null)
|
||||||
|
{
|
||||||
|
level = config.LogLevel;
|
||||||
|
|
||||||
|
if (config.File?.Enabled is true)
|
||||||
|
{
|
||||||
|
logConfig.WriteTo.File(
|
||||||
|
path: Path.Combine(config.File.Path, "cleanuperr-.txt"),
|
||||||
|
formatter: new ExpressionTemplate(fileOutputTemplate.Replace("PAD", padding.ToString())),
|
||||||
|
fileSizeLimitBytes: 10L * 1024 * 1024,
|
||||||
|
rollingInterval: RollingInterval.Day,
|
||||||
|
rollOnFileSizeLimit: true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.Logger = logConfig
|
||||||
|
.MinimumLevel.Is(level)
|
||||||
|
.MinimumLevel.Override("Microsoft.Hosting.Lifetime", LogEventLevel.Information)
|
||||||
|
.MinimumLevel.Override("Quartz", LogEventLevel.Warning)
|
||||||
|
.MinimumLevel.Override("System.Net.Http.HttpClient", LogEventLevel.Error)
|
||||||
|
.WriteTo.Console(new ExpressionTemplate(consoleOutputTemplate.Replace("PAD", padding.ToString())))
|
||||||
|
.Enrich.FromLogContext()
|
||||||
|
.Enrich.WithProperty("ApplicationName", "cleanuperr")
|
||||||
|
.CreateLogger();
|
||||||
|
|
||||||
|
return builder
|
||||||
|
.ClearProviders()
|
||||||
|
.AddSerilog();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,11 +9,17 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.1"/>
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.1" />
|
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.1" />
|
||||||
<PackageReference Include="Quartz" Version="3.13.1" />
|
<PackageReference Include="Quartz" Version="3.13.1" />
|
||||||
<PackageReference Include="Quartz.Extensions.DependencyInjection" Version="3.13.1" />
|
<PackageReference Include="Quartz.Extensions.DependencyInjection" Version="3.13.1" />
|
||||||
<PackageReference Include="Quartz.Extensions.Hosting" Version="3.13.1" />
|
<PackageReference Include="Quartz.Extensions.Hosting" Version="3.13.1" />
|
||||||
|
<PackageReference Include="Serilog" Version="4.1.0" />
|
||||||
|
<PackageReference Include="Serilog.Expressions" Version="5.0.0" />
|
||||||
|
<PackageReference Include="Serilog.Extensions.Hosting" Version="8.0.0" />
|
||||||
|
<PackageReference Include="Serilog.Settings.Configuration" Version="8.0.4" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Infrastructure.Verticals.Jobs;
|
using Infrastructure.Verticals.Jobs;
|
||||||
using Quartz;
|
using Quartz;
|
||||||
|
using Serilog.Context;
|
||||||
|
|
||||||
namespace Executable.Jobs;
|
namespace Executable.Jobs;
|
||||||
|
|
||||||
@@ -19,6 +20,8 @@ public sealed class GenericJob<T> : IJob
|
|||||||
|
|
||||||
public async Task Execute(IJobExecutionContext context)
|
public async Task Execute(IJobExecutionContext context)
|
||||||
{
|
{
|
||||||
|
using var _ = LogContext.PushProperty("JobName", typeof(T).Name);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _handler.ExecuteAsync();
|
await _handler.ExecuteAsync();
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Executable.DependencyInjection;
|
|||||||
var builder = Host.CreateApplicationBuilder(args);
|
var builder = Host.CreateApplicationBuilder(args);
|
||||||
|
|
||||||
builder.Services.AddInfrastructure(builder.Configuration);
|
builder.Services.AddInfrastructure(builder.Configuration);
|
||||||
|
builder.Logging.AddLogging(builder.Configuration);
|
||||||
|
|
||||||
var host = builder.Build();
|
var host = builder.Build();
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
{
|
{
|
||||||
"Logging": {
|
"Logging": {
|
||||||
"LogLevel": {
|
"LogLevel": "Debug",
|
||||||
"Default": "Debug",
|
"File": {
|
||||||
"Microsoft.Hosting.Lifetime": "Information",
|
"Enabled": false,
|
||||||
"Quartz": "Warning",
|
"Path": ""
|
||||||
"System.Net.Http.HttpClient": "Error"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Triggers": {
|
"Triggers": {
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
{
|
{
|
||||||
"Logging": {
|
"Logging": {
|
||||||
"LogLevel": {
|
"LogLevel": "Information",
|
||||||
"Default": "Information",
|
"File": {
|
||||||
"Microsoft.Hosting.Lifetime": "Information",
|
"Enabled": false,
|
||||||
"Quartz": "Warning",
|
"Path": ""
|
||||||
"System.Net.Http.HttpClient": "Error"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Triggers": {
|
"Triggers": {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Diagnostics;
|
using System.Collections.Concurrent;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Common.Configuration.ContentBlocker;
|
using Common.Configuration.ContentBlocker;
|
||||||
using Domain.Enums;
|
using Domain.Enums;
|
||||||
@@ -15,9 +16,9 @@ public sealed class BlocklistProvider
|
|||||||
|
|
||||||
public BlocklistType BlocklistType { get; }
|
public BlocklistType BlocklistType { get; }
|
||||||
|
|
||||||
public List<string> Patterns { get; } = [];
|
public ConcurrentBag<string> Patterns { get; } = [];
|
||||||
|
|
||||||
public List<Regex> Regexes { get; } = [];
|
public ConcurrentBag<Regex> Regexes { get; } = [];
|
||||||
|
|
||||||
public BlocklistProvider(
|
public BlocklistProvider(
|
||||||
ILogger<BlocklistProvider> logger,
|
ILogger<BlocklistProvider> logger,
|
||||||
@@ -75,9 +76,18 @@ public sealed class BlocklistProvider
|
|||||||
|
|
||||||
long startTime = Stopwatch.GetTimestamp();
|
long startTime = Stopwatch.GetTimestamp();
|
||||||
ParallelOptions options = new() { MaxDegreeOfParallelism = 5 };
|
ParallelOptions options = new() { MaxDegreeOfParallelism = 5 };
|
||||||
|
const string regexId = "regex:";
|
||||||
|
|
||||||
Parallel.ForEach(patterns, options, pattern =>
|
Parallel.ForEach(patterns, options, pattern =>
|
||||||
{
|
{
|
||||||
|
if (!pattern.StartsWith(regexId))
|
||||||
|
{
|
||||||
|
Patterns.Add(pattern);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pattern = pattern[regexId.Length..];
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Regex regex = new(pattern, RegexOptions.Compiled);
|
Regex regex = new(pattern, RegexOptions.Compiled);
|
||||||
@@ -85,7 +95,7 @@ public sealed class BlocklistProvider
|
|||||||
}
|
}
|
||||||
catch (ArgumentException)
|
catch (ArgumentException)
|
||||||
{
|
{
|
||||||
Patterns.Add(pattern);
|
_logger.LogWarning("invalid regex | {pattern}", pattern);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -171,7 +171,9 @@ services:
|
|||||||
image: flaminel/cleanuperr:latest
|
image: flaminel/cleanuperr:latest
|
||||||
container_name: cleanuperr
|
container_name: cleanuperr
|
||||||
environment:
|
environment:
|
||||||
- LOGGING__LOGLEVEL__DEFAULT=Debug
|
- LOGGING__LOGLEVEL=Debug
|
||||||
|
- LOGGING__FILE__ENABLED=false
|
||||||
|
- LOGGING__FILE__PATH=/var/logs
|
||||||
|
|
||||||
- TRIGGERS__QUEUECLEANER=0/30 * * * * ?
|
- TRIGGERS__QUEUECLEANER=0/30 * * * * ?
|
||||||
- TRIGGERS__CONTENTBLOCKER=0/30 * * * * ?
|
- TRIGGERS__CONTENTBLOCKER=0/30 * * * * ?
|
||||||
@@ -207,6 +209,8 @@ services:
|
|||||||
- RADARR__ENABLED=true
|
- RADARR__ENABLED=true
|
||||||
- RADARR__INSTANCES__0__URL=http://radarr:7878
|
- RADARR__INSTANCES__0__URL=http://radarr:7878
|
||||||
- RADARR__INSTANCES__0__APIKEY=705b553732ab4167ab23909305d60600
|
- RADARR__INSTANCES__0__APIKEY=705b553732ab4167ab23909305d60600
|
||||||
|
volumes:
|
||||||
|
- ./data/cleanuperr/logs:/var/logs
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
depends_on:
|
depends_on:
|
||||||
- qbittorrent
|
- qbittorrent
|
||||||
|
|||||||
Reference in New Issue
Block a user