You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Serilog多日志文件合并及筛选需求:求可用工具或方案

Serilog多日志文件合并与筛选方案

现有日志文件的合并与筛选实现

目前没有专门开箱即用的库直接实现你要的功能,但可以基于.NET的文本处理能力快速编写工具完成需求,核心思路是解析日志结构、合并条目后排序筛选:

  1. 日志结构解析:用正则匹配日志的起始行(格式为^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3} \[\w{3}\]),区分日志条目头和后续的多行消息内容,将每个完整的日志条目(包括多行消息)与来源文件关联。
  2. 排序与筛选:收集所有日志条目后,按时间戳排序,同时可根据[ERR]/[INF]等级别标签过滤指定级别的内容。
  3. 输出格式化:按你需要的格式输出,在消息前加上来源文件名标识。

示例代码片段(C#):

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;

public class LogEntry
{
    public DateTime Timestamp { get; set; }
    public string Level { get; set; }
    public string SourceFile { get; set; }
    public string Message { get; set; }
}

public class LogMerger
{
    private static readonly Regex LogHeaderRegex = new Regex(@"^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}) \[(\w{3})\] (.*)$");

    public List<LogEntry> ParseLogFile(string filePath)
    {
        var entries = new List<LogEntry>();
        LogEntry currentEntry = null;
        var fileName = Path.GetFileName(filePath);

        foreach (var line in File.ReadLines(filePath))
        {
            var match = LogHeaderRegex.Match(line);
            if (match.Success)
            {
                currentEntry = new LogEntry
                {
                    Timestamp = DateTime.Parse(match.Groups[1].Value),
                    Level = match.Groups[2].Value,
                    SourceFile = fileName,
                    Message = match.Groups[3].Value
                };
                entries.Add(currentEntry);
            }
            else if (currentEntry != null)
            {
                currentEntry.Message += Environment.NewLine + line;
            }
        }
        return entries;
    }

    public void MergeAndFilterLogs(string[] filePaths, string outputPath, string[] allowedLevels = null)
    {
        var allEntries = new List<LogEntry>();
        foreach (var path in filePaths)
        {
            allEntries.AddRange(ParseLogFile(path));
        }

        if (allowedLevels != null)
        {
            allEntries = allEntries.Where(e => allowedLevels.Contains(e.Level)).ToList();
        }

        var sortedEntries = allEntries.OrderBy(e => e.Timestamp);

        using (var writer = new StreamWriter(outputPath))
        {
            foreach (var entry in sortedEntries)
            {
                writer.WriteLine($"{entry.Timestamp:yyyy-MM-dd HH:mm:ss.fff} [{entry.Level}] {entry.SourceFile}|{entry.Message}");
            }
        }
    }
}

优化日志写入方式(避免事后合并)

不需要更换Serilog,调整配置即可提前解决日志分散的问题:

方案1:同时写入专属日志与合并日志

配置Serilog同时输出到服务专属文件和一个全局合并文件,合并文件中包含服务标识,这样排查时直接查看合并文件即可:

Log.Logger = new LoggerConfiguration()
    .WriteTo.File($"logs/{Environment.GetEnvironmentVariable("SERVICE_NAME")}.log", 
        rollingInterval: RollingInterval.Day)
    .WriteTo.File("logs/all-services.log",
        outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} [{Level:u3}] {ServiceName}|{Message:lj}{NewLine}{Exception}",
        rollingInterval: RollingInterval.Day,
        shared: true) // 多服务写入时启用shared避免锁问题
    .Enrich.WithProperty("ServiceName", Environment.GetEnvironmentVariable("SERVICE_NAME"))
    .CreateLogger();

方案2:使用结构化日志格式

将日志以JSON格式写入,后续合并筛选更可靠(尤其是处理多行消息):

Log.Logger = new LoggerConfiguration()
    .WriteTo.File(new Serilog.Formatting.Json.JsonFormatter(), 
        $"logs/{Environment.GetEnvironmentVariable("SERVICE_NAME")}.json",
        rollingInterval: RollingInterval.Day)
    .CreateLogger();

之后可以用jq等工具快速合并筛选:

# 合并两个JSON日志文件,按时间排序,只保留ERROR级别,输出为文本格式
jq -s 'sort_by(.Timestamp) | .[] | select(.Level == "Error") | "\(.Timestamp[:23]) [ERR] \(.SourceFile)| \(.Message)"' file1.json file2.json

内容的提问来源于stack exchange,提问作者Michiel Saelen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 18:23:10