.NET项目重构之日志服务(Serilog)
1. 目录
2. 前言
定时任务中比较重要的一个环节就是日志记录,有了日志可以记录系统的操作过程,也可以在系统异常时方便排查错误原因。
比如定时任务经常要做的一个事情,同步其它异构系统数据到本系统。大多情况下的操作过程时,定时请求对方接口返回JSON格式数据,我方把接收到的数据再转换为C#对象进行业务处理后保存至数据库。如果在这个过程中发生系统异常,没有日志记录很有可能连复现BUG都很难做到。
所以在这个过程中,比较正确的日志记录方式是:
- 接口请求,如有异常记录日志。
- 记录接口返回值。
- JSON数据转换为C#对象,如有异常记录日志。
- 其它
2.1. 日志控件的选择
之前所有项目用的基本都是老牌Log4net,而这次重构的一大主题是学习新东西嘛,所以我选择比较年轻一点的Serilog。
为什么选择Serilog? 嗯。。。。随便选的,其实用NLog也不是不行。
3. 日志配置
在Web项目下创建Extensions文件夹并添加SerilogSetup.cs文件。
添加如下NuGet包
- Serilog 3.0.1 基础包
- Serilog.Extensions.Hosting 7.0.0 ConfigureHostBuilder的扩展包
- Serilog.Enrichers.Thread 3.1.0 用于获取线程信息
- Serilog.Sinks.Async 1.5.0 用于异步打印
- Serilog.Sinks.Console 4.1.0 打印日志到控制台
- Serilog.Sinks.File 5.0.0 打印日志到文件
添加全局静态变量,用于设置打印模板,至于写法。官网是最好的老师:https://github.com/serilog/serilog/wiki/Configuration-Basics#output-templates
private static readonly string logTemplate = "{NewLine}时闻:{Timestamp:yyyy-MM-dd HH:mm:ss.fff}{NewLine}日志等级:{Level}{NewLine}线程ID:{ThreadId} 线程名:{ThreadName}{NewLine}所在类:{SourceContext}{NewLine}日志信息:{Message}{NewLine}{Exception}";
3.1. 控制台打印
接着添加静态方法AddSerilog
public static void AddSerilog(ConfigureHostBuilder builder)
{
// 打印到控制台
// 生产环境中可以不向控制台打印
builder.UseSerilog((context, logger) =>
{
// 添加此句后可以在“执行上下文”中动态添加和删除属性
logger.Enrich.FromLogContext();
logger.MinimumLevel.Information();
logger.Enrich.WithThreadId();
logger.Enrich.WithThreadName();
logger.WriteTo.Logger(lg => lg.WriteTo.Async(a =>
a.Console(outputTemplate: logTemplate)));
});
}
3.2. 文件打印
在AddSerilog方法中添加如下内容
// 打印到文件
builder.UseSerilog((context, logger) =>
{
logger.Enrich.FromLogContext();
logger.Enrich.WithThreadId();
logger.Enrich.WithThreadName();
logger.WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Debug).WriteTo.Async(a => a.File(logDebug, rollingInterval: RollingInterval.Hour, outputTemplate: logTemplate)));
logger.WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Information).WriteTo.Async(a => a.File(logInfo, rollingInterval: RollingInterval.Hour, outputTemplate: logTemplate)));
logger.WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Warning).WriteTo.Async(a => a.File(logWarn, rollingInterval: RollingInterval.Hour, outputTemplate: logTemplate)));
logger.WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Error).WriteTo.Async(a => a.File(logError, rollingInterval: RollingInterval.Hour, outputTemplate: logTemplate)));
logger.WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Fatal).WriteTo.Async(a => a.File(logFatal, rollingInterval: RollingInterval.Hour, outputTemplate: logTemplate)));
});
这里要注意的是,也可以写在一个方法内,我这样做的目的是为了可以一目了然的区分开不同日志的配置。
最后在Program.cs 中注册Serilog相关配置。
SerilogSetup.AddSerilog(builder.Host);
接下来就可以找个地方做打印测试了,比如在HomeController的Index的方法中加放入
_logger.LogInformation("控制台打印");
4. 结语
目前阶段只是做了控制台和文件打印,以后也许会接入数据库打印。
因为后期想在Web页面查看定时任务的执行状况等等。
本文原创自博客园,欢迎关注我的博客HOYU_Z
https://www.cnblogs.com/hoyu/