实现.NetCore集成Serilog,写入日志文件,并按日期拆分文件夹
“之前使用的log4net,遇到一个问题就是导致日志文件夹循环嵌套,未找到确切原因,自己猜想可能在高并发情况下会资源竞争导致,要解决,可能需要自行编码实现日志队列”。所以尝试使用Serilog。习惯了log4net的日志目录结构,首先按日期分文件夹,然后按日志界别拆分日志文件,在Serilog中需要自行实现。
实现效果如下:
文章目录
- 一、引入Serilog的类库
- 二、封装Serilog扩展方法
- 三、NetCore项目中使用
- 1、`Program`中使用
- 2、测试Controller
一、引入Serilog的类库
Serilog.AspNetCore
– 基础库
Serilog.Sinks.Async
– 异步写日志
Serilog.Sinks.File
– 写入日志到文件
二、封装Serilog扩展方法
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Serilog;
using Serilog.Events;
using Serilog.Formatting.Display;namespace HJMinimally.Serilog
{public static class SerilogServiceCollectionExtensions{public static IServiceCollection AddSerilogToFile(this IServiceCollection services, IConfiguration configuration, LogEventLevel minimumLevel = LogEventLevel.Debug, int retainedFileCountLimit = 14){// 配置 SerilogLog.Logger = new LoggerConfiguration().MinimumLevel.Is(minimumLevel).Enrich.FromLogContext().WriteTo.Logger(lc => lc.Filter.ByIncludingOnly(e => e.Level == LogEventLevel.Verbose).WriteTo.Async(wt => wt.File(path: GenerateLogPath(LogEventLevel.Verbose),rollingInterval: RollingInterval.Day,formatter: new MessageTemplateTextFormatter("{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {SourceContext}: {Message}{NewLine}{Exception}"),fileSizeLimitBytes: 1024 * 1024 * 10,encoding: System.Text.Encoding.UTF8,rollOnFileSizeLimit: true,retainedFileCountLimit: retainedFileCountLimit))).WriteTo.Logger(lc => lc.Filter.ByIncludingOnly(e => e.Level == LogEventLevel.Debug).WriteTo.Async(wt => wt.File(path: GenerateLogPath(LogEventLevel.Debug),rollingInterval: RollingInterval.Day,formatter: new MessageTemplateTextFormatter("{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {SourceContext}: {Message}{NewLine}{Exception}"),fileSizeLimitBytes: 1024 * 1024 * 10,encoding: System.Text.Encoding.UTF8,rollOnFileSizeLimit: true,retainedFileCountLimit: retainedFileCountLimit))).WriteTo.Logger(lc => lc.Filter.ByIncludingOnly(e => e.Level == LogEventLevel.Information).WriteTo.Async(wt => wt.File(path: GenerateLogPath(LogEventLevel.Information),rollingInterval: RollingInterval.Day,formatter: new MessageTemplateTextFormatter("{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {SourceContext}: {Message}{NewLine}{Exception}"),fileSizeLimitBytes: 1024 * 1024 * 10,encoding: System.Text.Encoding.UTF8,rollOnFileSizeLimit: true,retainedFileCountLimit: retainedFileCountLimit))).WriteTo.Logger(lc => lc.Filter.ByIncludingOnly(e => e.Level == LogEventLevel.Warning).WriteTo.Async(wt => wt.File(path: GenerateLogPath(LogEventLevel.Warning),rollingInterval: RollingInterval.Day,formatter: new MessageTemplateTextFormatter("{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {SourceContext}: {Message}{NewLine}{Exception}"),fileSizeLimitBytes: 1024 * 1024 * 10,encoding: System.Text.Encoding.UTF8,rollOnFileSizeLimit: true,retainedFileCountLimit: retainedFileCountLimit))).WriteTo.Logger(lc => lc.Filter.ByIncludingOnly(e => e.Level == LogEventLevel.Error).WriteTo.Async(wt => wt.File(path: GenerateLogPath(LogEventLevel.Error),rollingInterval: RollingInterval.Day,formatter: new MessageTemplateTextFormatter("{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {SourceContext}: {Message}{NewLine}{Exception}"),fileSizeLimitBytes: 1024 * 1024 * 10,encoding: System.Text.Encoding.UTF8,rollOnFileSizeLimit: true,retainedFileCountLimit: retainedFileCountLimit))).WriteTo.Logger(lc => lc.Filter.ByIncludingOnly(e => e.Level == LogEventLevel.Fatal).WriteTo.Async(wt => wt.File(path: GenerateLogPath(LogEventLevel.Fatal),rollingInterval: RollingInterval.Day,formatter: new MessageTemplateTextFormatter("{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {SourceContext}: {Message}{NewLine}{Exception}"),fileSizeLimitBytes: 1024 * 1024 * 10,encoding: System.Text.Encoding.UTF8,rollOnFileSizeLimit: true,retainedFileCountLimit: retainedFileCountLimit)))// 控制台输出.WriteTo.Console(outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {SourceContext}: {Message}{NewLine}{Exception}").CreateLogger();// 将 Serilog 集成到 ASP.NET Core 日志系统中services.AddLogging(loggingBuilder =>{loggingBuilder.ClearProviders(); // 清除默认的日志提供程序//控制台/桌面/自托管服务:建议在程序结束前加 Log.CloseAndFlush();//如果你用的是 loggingBuilder.AddSerilog(dispose: true),Serilog 会在应用关闭时自动处理资源释放,通常不需要手动调用 Log.CloseAndFlush()。loggingBuilder.AddSerilog(dispose: true); // 添加 Serilog 作为日志提供程序});return services;}private static string GenerateLogPath(LogEventLevel logEventLevel){var now = DateTimeOffset.Now;return $"Logs/{now:yyyy}-{now:MM}-{now:dd}/{logEventLevel}-.txt";}}
}
三、NetCore项目中使用
1、Program
中使用
builder.Services.AddSerilogToFile(builder.Configuration, retainedFileCountLimit: 7); // 保留最近7个日志文件
2、测试Controller
[ApiController]
[Route("[controller]")]
public class LogController : ControllerBase
{private readonly ILogger<LogController> _logger;public LogController(ILogger<LogController> logger){_logger = logger;}[HttpGet]public IActionResult Get(){// 记录不同级别的日志_logger.LogTrace("这是一条Trace级别的日志");_logger.LogCritical("这是一条Critical级别的日志");_logger.LogDebug("这是一条Debug级别的日志");_logger.LogInformation("这是一条Information级别的日志,用户访问了Get方法");_logger.LogWarning("这是一条Warning级别的日志");try{int c = 0;// 模拟异常int result = 1 / c;return Ok(result);}catch (Exception ex){// 记录错误日志,包含异常信息_logger.LogError(ex, "发生了一个错误");return BadRequest("操作失败");}}
}