refactor: switch to serilog
This commit is contained in:
parent
ad59c3190a
commit
58799594ae
|
@ -3,9 +3,18 @@ using OliverBooth.Blog.Middleware;
|
||||||
using OliverBooth.Blog.Services;
|
using OliverBooth.Blog.Services;
|
||||||
using OliverBooth.Common;
|
using OliverBooth.Common;
|
||||||
using OliverBooth.Common.Extensions;
|
using OliverBooth.Common.Extensions;
|
||||||
|
using Serilog;
|
||||||
|
using X10D.Hosting.DependencyInjection;
|
||||||
|
|
||||||
|
Log.Logger = new LoggerConfiguration()
|
||||||
|
.WriteTo.Console()
|
||||||
|
.WriteTo.File("logs/latest.log", rollingInterval: RollingInterval.Day)
|
||||||
|
.CreateLogger();
|
||||||
|
|
||||||
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
|
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
|
||||||
builder.Configuration.AddTomlFile("data/config.toml", true, true);
|
builder.Configuration.AddTomlFile("data/config.toml", true, true);
|
||||||
|
builder.Logging.ClearProviders();
|
||||||
|
builder.Logging.AddSerilog();
|
||||||
|
|
||||||
builder.Services.ConfigureOptions<OliverBoothConfigureOptions>();
|
builder.Services.ConfigureOptions<OliverBoothConfigureOptions>();
|
||||||
builder.Services.AddDbContextFactory<BlogContext>();
|
builder.Services.AddDbContextFactory<BlogContext>();
|
||||||
|
|
|
@ -21,6 +21,11 @@
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="7.0.10"/>
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="7.0.10"/>
|
||||||
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="7.0.10"/>
|
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="7.0.10"/>
|
||||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="7.0.0"/>
|
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="7.0.0"/>
|
||||||
|
<PackageReference Include="Serilog" Version="3.0.1"/>
|
||||||
|
<PackageReference Include="Serilog.AspNetCore" Version="7.0.0"/>
|
||||||
|
<PackageReference Include="Serilog.Extensions.Logging" Version="7.0.0"/>
|
||||||
|
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0"/>
|
||||||
|
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0"/>
|
||||||
<PackageReference Include="SmartFormat.NET" Version="3.2.2"/>
|
<PackageReference Include="SmartFormat.NET" Version="3.2.2"/>
|
||||||
<PackageReference Include="X10D" Version="3.2.2"/>
|
<PackageReference Include="X10D" Version="3.2.2"/>
|
||||||
<PackageReference Include="X10D.Hosting" Version="3.2.2"/>
|
<PackageReference Include="X10D.Hosting" Version="3.2.2"/>
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
using System.Text;
|
|
||||||
using NLog;
|
|
||||||
using NLog.Targets;
|
|
||||||
using LogLevel = NLog.LogLevel;
|
|
||||||
|
|
||||||
namespace OliverBooth.Logging;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents an NLog target which supports colorful output to stdout.
|
|
||||||
/// </summary>
|
|
||||||
internal sealed class ColorfulConsoleTarget : TargetWithLayout
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="ColorfulConsoleTarget" /> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name">The name of the log target.</param>
|
|
||||||
public ColorfulConsoleTarget(string name)
|
|
||||||
{
|
|
||||||
Name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void Write(LogEventInfo logEvent)
|
|
||||||
{
|
|
||||||
var message = new StringBuilder();
|
|
||||||
message.Append(Layout.Render(logEvent));
|
|
||||||
|
|
||||||
if (logEvent.Level == LogLevel.Warn)
|
|
||||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
|
||||||
else if (logEvent.Level == LogLevel.Error || logEvent.Level == LogLevel.Fatal)
|
|
||||||
Console.ForegroundColor = ConsoleColor.Red;
|
|
||||||
|
|
||||||
if (logEvent.Exception is { } exception)
|
|
||||||
message.Append($": {exception}");
|
|
||||||
|
|
||||||
Console.WriteLine(message);
|
|
||||||
Console.ResetColor();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
using System.Text;
|
|
||||||
using NLog;
|
|
||||||
using NLog.Targets;
|
|
||||||
using OliverBooth.Services;
|
|
||||||
|
|
||||||
namespace OliverBooth.Logging;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents an NLog target which writes its output to a log file on disk.
|
|
||||||
/// </summary>
|
|
||||||
internal sealed class LogFileTarget : TargetWithLayout
|
|
||||||
{
|
|
||||||
private readonly LoggingService _loggingService;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="LogFileTarget" /> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name">The name of the log target.</param>
|
|
||||||
/// <param name="loggingService">The <see cref="LoggingService" />.</param>
|
|
||||||
public LogFileTarget(string name, LoggingService loggingService)
|
|
||||||
{
|
|
||||||
_loggingService = loggingService;
|
|
||||||
Name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void Write(LogEventInfo logEvent)
|
|
||||||
{
|
|
||||||
_loggingService.ArchiveLogFilesAsync(false).GetAwaiter().GetResult();
|
|
||||||
|
|
||||||
using FileStream stream = _loggingService.LogFile.Open(FileMode.Append, FileAccess.Write);
|
|
||||||
using var writer = new StreamWriter(stream, Encoding.UTF8);
|
|
||||||
writer.Write(Layout.Render(logEvent));
|
|
||||||
|
|
||||||
if (logEvent.Exception is { } exception)
|
|
||||||
writer.Write($": {exception}");
|
|
||||||
|
|
||||||
writer.WriteLine();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,10 +7,6 @@
|
||||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="NLog.Extensions.Logging" Version="5.3.3"/>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\OliverBooth.Common\OliverBooth.Common.csproj"/>
|
<ProjectReference Include="..\OliverBooth.Common\OliverBooth.Common.csproj"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -1,22 +1,23 @@
|
||||||
using Markdig;
|
using Markdig;
|
||||||
using NLog;
|
|
||||||
using NLog.Extensions.Logging;
|
|
||||||
using OliverBooth.Common;
|
using OliverBooth.Common;
|
||||||
using OliverBooth.Common.Extensions;
|
using OliverBooth.Common.Extensions;
|
||||||
using OliverBooth.Data;
|
using OliverBooth.Data;
|
||||||
using OliverBooth.Markdown.Template;
|
using OliverBooth.Markdown.Template;
|
||||||
using OliverBooth.Markdown.Timestamp;
|
using OliverBooth.Markdown.Timestamp;
|
||||||
using OliverBooth.Services;
|
using OliverBooth.Services;
|
||||||
using X10D.Hosting.DependencyInjection;
|
using Serilog;
|
||||||
|
|
||||||
|
Log.Logger = new LoggerConfiguration()
|
||||||
|
.WriteTo.Console()
|
||||||
|
.WriteTo.File("logs/latest.log", rollingInterval: RollingInterval.Day)
|
||||||
|
.CreateLogger();
|
||||||
|
|
||||||
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
|
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
|
||||||
builder.Configuration.AddTomlFile("data/config.toml", true, true);
|
builder.Configuration.AddTomlFile("data/config.toml", true, true);
|
||||||
|
|
||||||
builder.Logging.ClearProviders();
|
builder.Logging.ClearProviders();
|
||||||
builder.Logging.AddNLog();
|
builder.Logging.AddSerilog();
|
||||||
|
|
||||||
builder.Services.ConfigureOptions<OliverBoothConfigureOptions>();
|
builder.Services.ConfigureOptions<OliverBoothConfigureOptions>();
|
||||||
builder.Services.AddHostedSingleton<LoggingService>();
|
|
||||||
builder.Services.AddSingleton<ConfigurationService>();
|
builder.Services.AddSingleton<ConfigurationService>();
|
||||||
builder.Services.AddSingleton<TemplateService>();
|
builder.Services.AddSingleton<TemplateService>();
|
||||||
|
|
||||||
|
@ -60,5 +61,3 @@ app.MapControllers();
|
||||||
app.MapRazorPages();
|
app.MapRazorPages();
|
||||||
|
|
||||||
app.Run();
|
app.Run();
|
||||||
|
|
||||||
LogManager.Shutdown();
|
|
||||||
|
|
|
@ -1,95 +0,0 @@
|
||||||
using System.IO.Compression;
|
|
||||||
using NLog;
|
|
||||||
using NLog.Config;
|
|
||||||
using NLog.Layouts;
|
|
||||||
using OliverBooth.Logging;
|
|
||||||
using LogLevel = NLog.LogLevel;
|
|
||||||
|
|
||||||
namespace OliverBooth.Services;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a class which implements a logging service that supports multiple log targets.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// This class implements a logging structure similar to that of Minecraft, where historic logs are compressed to a .gz and
|
|
||||||
/// the latest log is found in <c>logs/latest.log</c>.
|
|
||||||
/// </remarks>
|
|
||||||
internal sealed class LoggingService : BackgroundService
|
|
||||||
{
|
|
||||||
private const string LogFileName = "logs/latest.log";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="LoggingService" /> class.
|
|
||||||
/// </summary>
|
|
||||||
public LoggingService()
|
|
||||||
{
|
|
||||||
LogFile = new FileInfo(LogFileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the log file.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The log file.</value>
|
|
||||||
public FileInfo LogFile { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Archives any existing log files.
|
|
||||||
/// </summary>
|
|
||||||
public async Task ArchiveLogFilesAsync(bool archiveToday = true)
|
|
||||||
{
|
|
||||||
var latestFile = new FileInfo(LogFile.FullName);
|
|
||||||
if (!latestFile.Exists) return;
|
|
||||||
|
|
||||||
DateTime lastWrite = latestFile.LastWriteTime;
|
|
||||||
string lastWriteDate = $"{lastWrite:yyyy-MM-dd}";
|
|
||||||
var version = 0;
|
|
||||||
string name;
|
|
||||||
|
|
||||||
if (!archiveToday && lastWrite.Date == DateTime.Today) return;
|
|
||||||
|
|
||||||
while (File.Exists(name = Path.Combine(LogFile.Directory!.FullName, $"{lastWriteDate}-{++version}.log.gz")))
|
|
||||||
{
|
|
||||||
// body ignored
|
|
||||||
}
|
|
||||||
|
|
||||||
await using (FileStream source = latestFile.OpenRead())
|
|
||||||
{
|
|
||||||
await using FileStream output = File.Create(name);
|
|
||||||
await using var gzip = new GZipStream(output, CompressionMode.Compress);
|
|
||||||
await source.CopyToAsync(gzip);
|
|
||||||
}
|
|
||||||
|
|
||||||
latestFile.Delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override Task ExecuteAsync(CancellationToken stoppingToken)
|
|
||||||
{
|
|
||||||
LogFile.Directory?.Create();
|
|
||||||
|
|
||||||
LogManager.Setup(builder => builder.SetupExtensions(extensions =>
|
|
||||||
{
|
|
||||||
extensions.RegisterLayoutRenderer("TheTime", info => info.TimeStamp.ToString("HH:mm:ss"));
|
|
||||||
extensions.RegisterLayoutRenderer("ServiceName", info => info.LoggerName);
|
|
||||||
}));
|
|
||||||
|
|
||||||
Layout? layout = Layout.FromString("[${TheTime} ${level:uppercase=true}] [${ServiceName}] ${message}");
|
|
||||||
var config = new LoggingConfiguration();
|
|
||||||
var fileLogger = new LogFileTarget("FileLogger", this) { Layout = layout };
|
|
||||||
var consoleLogger = new ColorfulConsoleTarget("ConsoleLogger") { Layout = layout };
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
LogLevel minLevel = LogLevel.Debug;
|
|
||||||
#else
|
|
||||||
LogLevel minLevel = LogLevel.Info;
|
|
||||||
if (!string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("ENABLE_DEBUG_LOGGING")))
|
|
||||||
minLevel = LogLevel.Debug;
|
|
||||||
#endif
|
|
||||||
config.AddRule(minLevel, LogLevel.Fatal, consoleLogger);
|
|
||||||
config.AddRule(minLevel, LogLevel.Fatal, fileLogger);
|
|
||||||
|
|
||||||
LogManager.Configuration = config;
|
|
||||||
|
|
||||||
return ArchiveLogFilesAsync();
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue