Serilog简介
Serilog
是.net中的诊断日志库,可以在所有的.net平台上面运行。Serilog
支持结构化日志记录,对复杂、分布式、异步应用程序的支持非常出色。Serilog
可以通过插件的方式把日志写入到各种终端,控制台、文本、Sqlserver、ElasticSearch,Serilog支持终端的列表:https://github.com/serilog/serilog/wiki/Provided-Sinks 。
Serilog
日志写入SqlServer
一、Sink LoggerConfiguration
connectionString
数据库连接字符串schemaName
数据库所有者,默认dbo
tableName
记录日志的表名autoCreateSqlTable
是否自动创建表,如果设置为ture
,则在Serilog
启动时检测数据库是否有对应的表,没有则创建columnOptions
日志表中的列定义restrictedToMinimumLevel
记录日志的最小level
batchPostingLimit
单次批量处理中提交的最大日志数量period
进行批量提交的间隔formatProvider
提供特定的格式化处理,https://github.com/serilog/serilog/wiki/Formatting-Output#format-providers
Serilog
为我们定义了一套标准列,默认情况下会生成如下列,当然我们也可以自定义列
StandardColumn.Id
自增IdStandardColumn.Message
日志内容StandardColumn.MessageTemplate
日志模板StandardColumn.Level
等级StandardColumn.TimeStamp
记录时间StandardColumn.Exception
异常信息StandardColumn.Properties
日志事件属性值
删除标准列:
columnOptions.Store.Remove(StandardColumn.MessageTemplate);
添加自定义列:
columnOptions.AdditionalColumns = new Collection<SqlColumn>
{
new SqlColumn { DataType = SqlDbType.NVarChar, DataLength = 32, ColumnName = "IP" }
};
完整LoggerConfiguration
示例如下:
var columnOptions = new ColumnOptions();
columnOptions.Store.Remove(StandardColumn.MessageTemplate);//删除标准列
columnOptions.Properties.ExcludeAdditionalProperties = true;//排除已经自定义列的数据
columnOptions.AdditionalColumns = new Collection<SqlColumn>//添加自定义列
{
new SqlColumn { DataType = SqlDbType.NVarChar, DataLength = 32, ColumnName = "IP" }
};
Log.Logger = new LoggerConfiguration()
.WriteTo.MSSqlServer(
connectionString: Configuration["Serilog:ConnectionString"],
tableName: Configuration["Serilog:TableName"],
batchPostingLimit: Configuration.GetValue<int>("Serilog:BatchPostingLimit"),//批量插入数据库条数
period: TimeSpan.FromSeconds(5),//执行时间间隔
restrictedToMinimumLevel: Configuration.GetValue<LogEventLevel>("Serilog:MinimumLevel"),
columnOptions: columnOptions,
autoCreateSqlTable: true
).CreateLogger();
上面的配置也可以全部从配置文件读取:
{
"Serilog": {
"Using": [ "Serilog.Sinks.MSSqlServer" ],
"MinimumLevel": "Debug",
"WriteTo": [
{
"Name": "MSSqlServer",
"Args": {
"connectionString": "NamedConnectionString",
"schemaName": "EventLogging",
"tableName": "Logs",
"autoCreateSqlTable": true,
"restrictedToMinimumLevel": "Warning",
"batchPostingLimit": 100,
"period": "0.00:00:30",
"columnOptionsSection": {
"disableTriggers": true,
"clusteredColumnstoreIndex": false,
"primaryKeyColumnName": "Id",
"addStandardColumns": [ "LogEvent" ],
"removeStandardColumns": [ "MessageTemplate"],
"additionalColumns": [
{
"ColumnName": "IP",
"DataType": "varchar",
"DataLength": 32
}
],
"id": { "nonClusteredIndex": true },
"properties": {
"columnName": "Properties",
"excludeAdditionalProperties": true,
"dictionaryElementName": "dict",
"itemElementName": "item",
"omitDictionaryContainerElement": false,
"omitSequenceContainerElement": false,
"omitStructureContainerElement": false,
"omitElementIfEmpty": true,
"propertyElementName": "prop",
"rootElementName": "root",
"sequenceElementName": "seq",
"structureElementName": "struct",
"usePropertyKeyAsElementName": false
},
"timeStamp": {
"columnName": "Timestamp",
"convertToUtc": true
},
"logEvent": {
"excludeAdditionalProperties": true,
"excludeStandardColumns": true
},
"message": { "columnName": "message" },
"exception": { "columnName": "exception" }
}
}
}
]
}
}
Log.Logger = new LoggerConfiguration().ReadFrom.Configuration(Configuration["Serilog"]);//需要引用Microsoft.Extensions.Configuration
二、Logger
使用
1、直接使用Serilog提供的静态类Log
Log.Information(“message”);
2、使用serilog-extensions-logging
替换.net core
默认日志Microsoft.Extensions.Logging
,注入Serilog
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.CaptureStartupErrors(true)//捕捉启动异常
.UseSetting("detailedErrors", "true")//指定程序应用程序会显示详细的启动错误信息
.UseStartup<Startup>()
.ConfigureLogging(builder =>
{
builder.ClearProviders();
builder.AddSerilog();
});
});
private readonly ILogger logger;
public TestController(ILogger<TestController> logger)
{
this.logger = logger;
}
logger.Information("Message")
三、怎么把数据写入自定义列
Serilog并没有提供 Log.Debug(Message,IP)
方法,在我们日常开发中可能会有如下几种需求:
1、设置全局Property
例如我需要记录当前程序服务器的ip,防伪码查询,或者我需要记录当前服务的名称,需要一个共用的字段。那么我们可以在LoggerConfiguration
的时候设置一个全局的Property
,即在相同的LoggerConfiguration
下面每条日志都可以共用,我们可以这样配置
Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext()
.Enrich.WithProperty("IP", GetIP())
.WriteTo.MSSqlServer(
connectionString: Configuration["Serilog:ConnectionString"],
tableName: Configuration["Serilog:TableName"],
batchPostingLimit: Configuration.GetValue<int>("Serilog:BatchPostingLimit"),//批量插入数据库条数
period: TimeSpan.FromSeconds(5),//执行时间间隔
restrictedToMinimumLevel: Configuration.GetValue<LogEventLevel>("Serilog:MinimumLevel"),
columnOptions: columnOptions,
autoCreateSqlTable: true
).CreateLogger();
2、设置ForContext
写入Property
例如我需要记录当前类,需要在记录日志的时候设置ForContext
Log.ForContext("Calss", GetType().FullName).Information("message");
这里只是一个例子,其实serilog
已经自动帮我们记录了Calss
的信息,在Properties
中可以找到SourceContext
节点,里面就记录了相关的命名空间和类
四、对日志进行过滤
如果系统日志太多,我们很难快速找到有用的信息,所以很多时候我们会对日志进行过滤
1、通过MinimumLevel
进行过滤
设置MinimumLevel
的等级进行过滤,Serilog
中Level
有Verbose,Debug,Information,Warning,Error,Fatal
几个等级,Serilog
只记录当前等级及比当前等级高的日志。
2、通过Override
进行过滤
原理是serilog
会记录SourceContext
,里面包含了命名空间和类的信息,这里我们把SourceContext
包含“Microsoft”的信息过滤掉,只记录Error
及Error
级别以上的信息,配置如下:
Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext()
.Enrich.WithProperty("IP", GetIP())
.MinimumLevel.Override("Microsoft", LogEventLevel.Error)
.WriteTo.MSSqlServer(
connectionString: Configuration["Serilog:ConnectionString"],
tableName: Configuration["Serilog:TableName"],
batchPostingLimit: Configuration.GetValue<int>("Serilog:BatchPostingLimit"),//批量插入数据库条数
period: TimeSpan.FromSeconds(5),//执行时间间隔
restrictedToMinimumLevel: Configuration.GetValue<LogEventLevel>("Serilog:MinimumLevel"),
columnOptions: columnOptions,
autoCreateSqlTable: true
).CreateLogger();
3、通过Filter
进行过滤
通过Filter
可以过滤Properties
中的值,比如一般我们会对数据库的错误比较重视,希望把数据库错误单独放在一个表中,这时需要用到Filter
,我们把SourceContext
中包含数据访问层命名空间的信息提取出来
string namespace = "DAL";//数据访问层命名空间
Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext()
.Enrich.WithProperty("IP", GetIP())
.MinimumLevel.Override("Microsoft", LogEventLevel.Error)
.WriteTo.Logger(lc => lc.Filter.ByIncludingOnly(Matching.WithProperty(namespace))
.WriteTo.MSSqlServer(
connectionString: Configuration["Serilog:ConnectionString"],
tableName: Configuration["Serilog:DBErrorTableName"],
batchPostingLimit: Configuration.GetValue<int>("Serilog:BatchPostingLimit"),//批量插入数据库条数
period: TimeSpan.FromSeconds(5),//执行时间间隔
columnOptions: columnOptions,
autoCreateSqlTable: true))
.WriteTo.Logger(lc => lc.Filter.ByExcluding(Matching.WithProperty(namespace))
.WriteTo.MSSqlServer(
connectionString: Configuration["Serilog:ConnectionString"],
tableName: Configuration["Serilog:DefaultTableName"],
batchPostingLimit: Configuration.GetValue<int>("Serilog:BatchPostingLimit"),//批量插入数据库条数
period: TimeSpan.FromSeconds(5),//执行时间间隔
columnOptions: columnOptions,
autoCreateSqlTable: true))
.CreateLogger();
五、Enricher
Enricher
的作用主要是增加记录的信息,比如Enrich.WithThreadId()
,可以记录线程信息,Enrich.WithProperty()
可以增加属性信息
自定义Enricher
可以参数这篇文章:https://www.cnblogs.com/weihanli/p/custom-serilog-enricher-to-record-more-info.html
在 ASP.NET Core 中使用 Serilog
进行日志记录
一、从 NuGet 安装 Serilog
核心的包是 Serilog.AspNetCore
,
里面包含了 Serilog
还有 Serilog.Sinks.Console
控制台日志打印 和 Serilog.Sinks.File
文件日志打印。
PM> Install-Package Serilog.AspNetCore
二、在 Main函数 中配置 Serilog
在 Main 函数的代码大概如下,应该是够用了,如需其他配置请参考 Serilog
官方文档。
public static void Main(string[] args)
{
// 配置 Serilog
Log.Logger = new LoggerConfiguration()
// 最小的日志输出级别
.MinimumLevel.Information()
// 日志调用类命名空间如果以 Microsoft 开头,覆盖日志输出最小级别为 Information
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
.Enrich.FromLogContext()
// 配置日志输出到控制台
.WriteTo.Console()
// 配置日志输出到文件,文件输出到当前项目的 logs 目录下
// 日记的生成周期为每天
.WriteTo.File(Path.Combine("logs", @"log.txt"), rollingInterval: RollingInterval.Day)
// 创建 logger
.CreateLogger();
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
// 将 Serilog 设置为日志记录提供程序
.UseSerilog();
或者
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder (string[] args) {
return WebHost.CreateDefaultBuilder (args)
.UseStartup<Startup> ()
.UseSerilog ((context, configuration) => {
configuration
.MinimumLevel.Information()
// 日志调用类命名空间如果以 Microsoft 开头,覆盖日志输出最小级别为 Information
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
.Enrich.FromLogContext()
// 配置日志输出到控制台
.WriteTo.Console()
// 配置日志输出到文件,文件输出到当前项目的 logs 目录下
// 日记的生成周期为每天
.WriteTo.File(Path.Combine("logs", @"log.txt"), rollingInterval: RollingInterval.Day)
// 创建 logger
.CreateLogger();
});
}
三、在项目中使用 Serilog
进行日志输出
使用 Serilog
时,直接使用 ILogger
即可,因为此服务项目应该是默认注入了,此处需要依赖关系注入知识。
如你不了解依赖关系注入,请看 微软官方文档。
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
private readonly ILogger<ValuesController> _logger;
public ValuesController(ILogger<ValuesController> logger)
{
_logger = logger;
}
// GET api/values
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
_logger.LogInformation("Serilog test info.");
_logger.LogError("Serilog test error.");
return new string[] { "value1", "value2" };
}
}
随后启动项目即可看到控制台和项目文件中出现配置所对应的控制台日志和日志文件。