Serilog多日志文件合并及筛选需求:求可用工具或方案
Serilog多日志文件合并与筛选方案
现有日志文件的合并与筛选实现
目前没有专门开箱即用的库直接实现你要的功能,但可以基于.NET的文本处理能力快速编写工具完成需求,核心思路是解析日志结构、合并条目后排序筛选:
- 日志结构解析:用正则匹配日志的起始行(格式为
^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3} \[\w{3}\]),区分日志条目头和后续的多行消息内容,将每个完整的日志条目(包括多行消息)与来源文件关联。 - 排序与筛选:收集所有日志条目后,按时间戳排序,同时可根据
[ERR]/[INF]等级别标签过滤指定级别的内容。 - 输出格式化:按你需要的格式输出,在消息前加上来源文件名标识。
示例代码片段(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
相关产品推荐
相关产品推荐

