我想使用 Serilog 进行日志记录。我希望日志记录仅记录错误或更高级别的错误,这样当记录错误时,它会包含最后 10 个日志。
我已经做了一个适用于控制台的概念证明。这是代码。 Circular buffer是一个nuget包。
using CircularBuffer;
using Serilog.Core;
using Serilog.Events;
namespace ProminentMediaserilog;
public class ErrorWithRecentLogsSink : ILogEventSink
{
private readonly CircularBuffer<LogEvent> _recentLogs;
public ErrorWithRecentLogsSink(int capacity)
{
_recentLogs = new CircularBuffer<LogEvent>(capacity);
}
public void Emit(LogEvent logEvent)
{
if (logEvent.Level < LogEventLevel.Error)
{
_recentLogs.PushBack(logEvent);
return;
}
var recentLogs = string.Join(",", GetRecentLogs().Select(rl => GetLogMessage(rl)));
var message = $"{GetLogMessage(logEvent)}{Environment.NewLine}Recent Logs: {recentLogs}";
Console.WriteLine(message);
}
private string GetLogMessage(LogEvent logEvent)
{
return $"{logEvent.Timestamp:HH:mm:ss} {logEvent.Level} {logEvent.RenderMessage()}{Environment.NewLine}";
}
public LogEvent[] GetRecentLogs()
{
return _recentLogs.ToArray();
}
}
从代码中可以看到,当日志级别低于错误时,logEvent 会添加到保留最后 10 条日志的循环缓冲区中。当日志出错时,它会记录错误和缓冲区中的最后 10 个日志。
但是我想要的是相同的代码可以工作,但将日志保存到文件中而不是将它们写入控制台。我可以执行与上面类似的操作,并添加自己的逻辑以将日志消息保存到文件中,但理想情况下,我希望使用已经存在的接收器(例如 file)来实现此目的,这样我就可以利用它拥有的所有文件选项例如为每个时间单位创建一个新文件。
这可以做到吗?如果可以的话,你会怎么做?
为了实现这一点,您可以创建一个自定义 Serilog 接收器,它结合了文件接收器和循环缓冲区逻辑的功能。以下是如何使用 Serilog 的较新
RollingFileSink
以及循环缓冲区来执行此操作的示例。确保您已安装所需的软件包:
dotnet add package Serilog.Sinks.Console
dotnet add package Serilog.Sinks.File
通过扩展
ILogEventSink
创建自定义接收器类。在本课程中,您将管理控制台和文件日志记录,以及维护最近日志事件的循环缓冲区:
using CircularBuffer;
using Serilog.Core;
using Serilog.Events;
using Serilog.Sinks.Console;
using Serilog.Sinks.File;
using System;
using System.IO;
using System.Linq;
namespace YourNamespace
{
public class CustomErrorWithRecentLogsSink : ILogEventSink
{
private readonly ConsoleSink _consoleSink;
private readonly RollingFileSink _fileSink;
private readonly CircularBuffer<LogEvent> _recentLogs;
public CustomErrorWithRecentLogsSink(int capacity, string logFilePath, string logFileNameTemplate)
{
_consoleSink = new ConsoleSink(formatProvider: null);
_fileSink = new RollingFileSink(
logFilePath,
new JsonFormatter(),
logFileNameTemplate: logFileNameTemplate,
fileSizeLimitBytes: null,
retainedFileCountLimit: null);
_recentLogs = new CircularBuffer<LogEvent>(capacity);
}
public void Emit(LogEvent logEvent)
{
if (logEvent.Level < LogEventLevel.Error)
{
_recentLogs.PushBack(logEvent);
_consoleSink.Emit(logEvent); // Log to console
return;
}
var recentLogs = string.Join(Environment.NewLine, GetRecentLogs().Select(GetLogMessage));
var message = $"{GetLogMessage(logEvent)}{Environment.NewLine}Recent Logs: {recentLogs}";
_consoleSink.Emit(logEvent); // Log to console
_fileSink.Emit(logEvent); // Log to file
}
private string GetLogMessage(LogEvent logEvent)
{
return $"{logEvent.Timestamp:HH:mm:ss} {logEvent.Level} {logEvent.RenderMessage()}{Environment.NewLine}";
}
public LogEvent[] GetRecentLogs()
{
return _recentLogs.ToArray();
}
}
}
在此自定义接收器中,您可以使用 Serilog 内置接收器中的
ConsoleSink
和 RollingFileSink
来处理控制台和文件日志记录。您可以指定将写入日志的 logFilePath
以及用于生成日志文件名的 logFileNameTemplate
。配置 Serilog 以在应用程序的启动代码中使用自定义接收器,利用更高级的文件接收器选项:
using Serilog;
using Serilog.Events;
using System;
class Program
{
static void Main()
{
// Set up Serilog with your custom sink
Log.Logger = new LoggerConfiguration()
.WriteTo.Sink(new CustomErrorWithRecentLogsSink(
capacity: 10,
logFilePath: "your_log_file.log",
logFileNameTemplate: "your_log_{Date}.log")) // Customize log file names
.MinimumLevel.Error()
.CreateLogger();
// Sample log messages
Log.Information("This is an informational message.");
Log.Error("This is an error message.");
// Close and flush the log
Log.CloseAndFlush();
Console.WriteLine("Logging complete. Press any key to exit...");
Console.ReadKey();
}
}
通过此设置,日志将写入控制台和单独的日志文件,并根据日期生成日志文件。发生错误时会包含最近 10 条日志。