使用 Serilog 记录到文件,包括每个错误日志的最后 10 个其他日志

问题描述 投票:0回答:1

我想使用 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)来实现此目的,这样我就可以利用它拥有的所有文件选项例如为每个时间单位创建一个新文件。

这可以做到吗?如果可以的话,你会怎么做?

c# serilog serilog-sinks-file
1个回答
1
投票

为了实现这一点,您可以创建一个自定义 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 条日志。

© www.soinside.com 2019 - 2024. All rights reserved.