在 .NET 开发中,日志管理是系统可维护性的关键一环。Serilog 作为一款强大的日志库,支持灵活的配置、结构化日志记录和丰富的输出方式。
本文将结合代码示例,详细介绍如何通过 本地依赖包配置、分目录日志存储 和 自定义业务日志 实现高效日志管理。
1. 依赖包配置
Serilog 的灵活性和扩展性依赖于其丰富的 NuGet 包。以下是核心依赖包列表:
NuGet 包 | 功能描述 |
---|---|
| 核心库,提供基础日志功能 |
| 文件输出支持 |
| 异步写入日志,提升性能 |
Serilog.Settings.Configuration | 从配置文件读取配置 |
| 支持表达式过滤日志 |
| 添加进程信息(如进程名) |
| 添加线程信息(如线程ID) |
2. Serilog 本地配置文件
通过 Serilog.json
配置文件,可以集中管理日志级别、输出路径、滚动策略等。以下是关键配置解析:
2.1 配置结构
{
"Serilog": {
"Using": [ "Serilog.Sinks.File", "Serilog.Expressions" ],
"MinimumLevel": {
"Default": "Debug",
"Override": {
"Microsoft": "Warning",
"System": "Warning"
}
},
"WriteTo": [
{
"Name": "Logger",
"Args": {
"configureLogger": {
"Filter": [{ "Name": "ByIncludingOnly", "Args": { "expression": "@l = 'Debug'" } }],
"WriteTo": [{
"Name": "File",
"Args": {
"path": "Logs/Debug/debug-.log",
"rollingInterval": "Day",
"fileSizeLimitBytes": 52428800,
"retainedFileCountLimit": 7,
"rollOnFileSizeLimit": true,
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} [{Level:u3}] {Message:lj}{NewLine}{Exception}"
}
}]
}
}
}
],
"Enrich": [ "FromLogContext", "WithProcessName" ]
}
}
2.2 关键参数说明
-
MinimumLevel:全局日志级别,
Override
可覆盖特定命名空间的级别。 -
WriteTo:日志输出配置,每个条目对应一个日志接收器(Sink)。
-
path
:日志文件路径,支持按级别分目录(如Logs/Debug
)。 -
rollingInterval
:日志滚动策略(按天、小时等)。 -
fileSizeLimitBytes
:单个日志文件大小限制(例如 50MB)。 -
retainedFileCountLimit
:保留的日志文件数量。
-
-
Enrich:日志丰富器,添加进程名、线程ID等上下文信息。
-
Filter: 添加日志过滤,定义不同日志输出规则
3. 自定义日志助手类
为简化日志调用,封装一个静态类 SeriLogHelper
,支持通用日志和业务日志。可以直接封装到自有工具库中,无需每次配置和开发。
3.1 初始化配置
public static class SeriLogHelper
{
private static readonly Logger? _logger;
private static readonly string _configPath = "Serilog.json";
static SeriLogHelper()
{
//本地配置初始化
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile(_configPath, optional: true, reloadOnChange: true)
.Build();
//创建日志
_logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.Enrich.WithProcessName()
.Enrich.FromLogContext()
.CreateLogger();
}
}
3.2 通用日志接口
// 示例:记录 Information 日志
public static void LogInformation(string messageTemplate, params object[] propertyValues)
{
_logger?.Information(messageTemplate, propertyValues);
}
// 示例:记录 Error 日志
public static void LogError(string messageTemplate, params object[] propertyValues)
{
_logger?.Error(messageTemplate, propertyValues);
}
//示例:输出Exception日志,异常日志输出异常详细信息,方便系统自检
public static void LogException(Exception ex, string messageTemplate, params object[] propertyValues)
{
_logger?.Error(ex, messageTemplate, propertyValues);
}
3.3 业务日志分模块处理
通过动态创建模块专属 Logger,将不同业务的日志存储到独立目录。
private static readonly Dictionary<string, Logger> _moduleLoggers = new();
public static void LogBusiness(string module, string shortName, string message)
{
Logger logger = GetModuleLogger(module, shortName);
logger?.Information(message);
}
private static Logger GetModuleLogger(string moduleName, string shortName)
{
if (_moduleLoggers.TryGetValue(moduleName, out var logger)) return logger;
var logDir = @$"{Directory.GetCurrentDirectory()}\Logs\{moduleName}";
Directory.CreateDirectory(logDir);
var logConfig = new LoggerConfiguration()
.WriteTo.Async(a => a.File(
path: @$"{logDir}\{shortName}_.log",
rollingInterval: RollingInterval.Day,
retainedFileCountLimit: 30,
fileSizeLimitBytes: 1024 * 1024 * 50
)).CreateLogger();
_moduleLoggers[moduleName] = logConfig;
return logConfig;
}
4. 日志分目录与业务日志测试
4.1 测试代码
public class TestClass
{
public void SeriologTest()
{
try
{
SeriLogHelper.LogInformation("Application Start");
SeriLogHelper.LogDebug("Debugging information");
SeriLogHelper.LogBusiness("OrderModule", "Order", "New order created: ID=1001");
}
catch (Exception ex)
{
SeriLogHelper.LogFatal(ex, "Application start failed");
}
finally
{
SeriLogHelper.Exit();
}
}
}
4.2 生成的日志结构
Logs/
├── Debug/
│ └── debug-20231001.log
├── Info/
│ └── Info-20231001.log
├── OrderModule/
│ └── Order_20231001.log
└── Error/
└── Error-20231001.log
5. 总结
-
配置文件驱动:通过
Serilog.json
集中管理日志策略,避免硬编码。 -
日志分目录:不同级别和模块的日志独立存储,便于排查问题。
-
业务日志扩展:动态创建模块专属 Logger,支持高灵活性的业务需求。
通过以上方法,可以快速搭建一个高效、可维护的日志系统。