.Net Core3.0 WebApi 目錄
為什么使用Serilog
Serilog 是一個用於.NET應用程序的日志記錄開源庫,配置簡單,接口干凈,並可運行在最新的.NET平台上,與其他日志庫不同, Serilog 是以功能強大的結構化事件數據為基礎構建的, 支持將日志輸出到控制台、文件、數據庫和其它更多的方式,支持參數化日志模板,非常靈活。
之前我們項目使用的是Log4j來記錄用戶日志的,在開發的過程中,慢慢的發現Log4j好像並不能滿足我們的需求,比如結構化,日志分析等,於是決定使用serilog來替換掉Log4j,在使用的過程中發現Serilog還是很強大的。
刪除原有的Log4j
1.卸載log4j包

點擊卸載
2.刪除log4j文件夾
3.刪除startup中關於log4net的代碼


4.將log4j相關的代碼刪除
安裝Serilog包
nuget安裝以下幾個包

配置Serilog
編輯Appsetting.json
"Serilog": { "MinimumLevel": { "Default": "Debug", //最小日志記錄級別 "Override": { //系統日志最小記錄級別 "Default": "Warning", "System": "Warning", "Microsoft": "Warning" } }, "WriteTo": [ { "Name": "Console" }//輸出到控制台 ] },
program.cs將系統的logger替換為serilog
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .UseServiceProviderFactory(new AutofacServiceProviderFactory()) //<--NOTE THIS .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>() .UseSerilog((context, logger) =>//注冊Serilog { logger.ReadFrom.Configuration(context.Configuration); logger.Enrich.FromLogContext(); }); });
Test控制器注入logger,並修改LogTest方法。
private readonly ILogger<TestController> _logger;//using Microsoft.Extensions.Logging; public TestController(ILogger<TestController> logger) { _logger = logger; }
/// <summary> /// 測試日志 /// </summary> /// <returns></returns> [HttpGet] public IActionResult LogTest() { //_logger.Error(typeof(TestController), "這是錯誤日志", new Exception("123")); //_logger.Debug(typeof(TestController), "這是bug日志"); //throw new System.IO.IOException(); _logger.LogInformation("info 日志"); _logger.LogDebug("debug 日志"); _logger.LogError(new System.IO.IOException(), "io 錯誤"); return Ok(); }
運行調用接口,可以看到日志輸出到控制台了:

配置Serilog輸出到文件
appsetting.json增加配置
"WriteTo": [ { "Name": "Console" }, //輸出到控制台 { "Name": "Async", //Serilog.Sinks.Async "Args": { "configure": [ { "Name": "File", //輸出文件 "Args": { "path": "log/log.txt", "outputTemplate": "{NewLine}Date:{Timestamp:yyyy-MM-dd HH:mm:ss.fff}{NewLine}LogLevel:{Level}{NewLine}Message:{Message}{NewLine}{Exception}", "rollingInterval": "3" //按天記錄 } } ] } } ]
啟動項目測試,就有了日志文件:

這里邊,亂碼的地方,其實是 : ,至於為什么亂碼,等到找到解決方案再更新。有知道的小伙伴也可以評論下。
【補充】將配置中的:(中文狀態)修改成英文下的:(英文狀態)就不會出現亂碼的問題了。

配置Serilog輸出到數據庫
{"Name": "Async", //Serilog.Sinks.Async
"Args": {
"configure": [
{
"Name": "File", //輸出文件
"Args": {
"path": "log/log.txt",
"outputTemplate": "{NewLine}Date:{Timestamp:yyyy-MM-dd HH:mm:ss.fff}{NewLine}LogLevel:{Level}{NewLine}Message:{Message}{NewLine}{Exception}",
"rollingInterval": "3" //按天記錄
}
},
{
"Name": "MSSqlServer", //輸出到sqlserver
"Args": {
"connectionString": "數據庫",
"schemaName": "dbo", //數據庫所有者,默認dbo
"tableName": "Logs", // 記錄日志的表名
"autoCreateSqlTable": true, // 是否自動創建表
"restrictedToMinimumLevel": "Information", // 記錄日志的最小level
"batchPostingLimit": 100, //單次批量處理中提交的最大日志數量
"period": "0.00:00:30", //進行批量提交的間隔
"columnOptionsSection": {
"disableTriggers": true,
"clusteredColumnstoreIndex": false,
"primaryKeyColumnName": "Id",
"addStandardColumns": [ "LogEvent" ],
"removeStandardColumns": [ "MessageTemplate" ],
"additionalColumns": [ //自定義列
{
"ColumnName": "Ip",
"DataType": "varchar",
"DataLength": 20
},
{
"ColumnName": "UserName",
"DataType": "varchar",
"DataLength": 30
},
{
"ColumnName": "UserId",
"DataType": "varchar",
"DataLength": 50
},
{
"ColumnName": "LogType",
"DataType": "tinyint"
},
{
"ColumnName": "Parameter"
},
{
"ColumnName": "Result"
}
],
"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" }
}
}
}
]
}
}
Test控制器修改Aoptest方法,添加以下語句
_logger.LogInformation("ip:{IP},username{UserName},userid:{UserId}","127.0.0.1","admin","1");
啟動項目,測試接口,數據庫已經插入數據。

配置Serilog輸出到Seq
Seq組件,通過網頁UI的形式將日志展現出來,內容更加多樣化,並賦予了更多功能日志搜索。
首先,安裝Seq組件,Seq下載地址:https://getseq.net/Download
本地開發情形下是免費使用的,如果需要在生產環境中使用,需要商業許可(你懂的,money).在目前的版本中,4.2是只能夠在windows下跑,也就是說我們如果是在windows下開發,在測試時可以借助這個方便的查看日志信息,按照給定的安裝步驟完成安裝。
安裝完成之后,瀏覽器輸出localhost:5341,會看到以下頁面

appsetting.json配置輸出到seq
{ "Name": "Seq", //輸出到seq "Args": { "serverUrl": "http://127.0.0.1:5341" } },
啟動項目,測試接口,可以通過頁面看到數據。

全局使用Serilog記錄日志
在CustomExceptionMiddleware.cs直接這樣
namespace WebApi.Core.Api.Middleware { public class CustomExceptionMiddleware { private readonly RequestDelegate _next; private readonly ILogger<CustomExceptionMiddleware> _logger; public CustomExceptionMiddleware(RequestDelegate next, ILogger<CustomExceptionMiddleware> logger) { _next = next; _logger = logger; } public async Task Invoke(HttpContext httpContext) { try { await _next(httpContext); } catch (Exception ex) { _logger.LogError(ex.Message, ex); // 日志記錄 await HandleExceptionAsync(httpContext, ex.Message); } finally
GlobalExceptionsFilter中也一樣
namespace WebApi.Core.Api.Filters { public class GlobalExceptionsFilter : IExceptionFilter { private readonly IHostEnvironment _env; private readonly ILogger<GlobalExceptionsFilter> _logger; public GlobalExceptionsFilter(IHostEnvironment env, ILogger<GlobalExceptionsFilter> logger) { _env = env; _logger = logger; } public void OnException(ExceptionContext context) { var json = new JsonErrorResponse(); json.Message = context.Exception.Message;//錯誤信息 if (_env.IsDevelopment()) { json.DevelopmentMessage = context.Exception.StackTrace;//堆棧信息 } context.Result = new InternalServerErrorObjectResult(json); _logger.LogError(context.Exception, context.Exception.Message); //采用log4net 進行錯誤日志記錄 //_loggerHelper.Error(json.Message, "出現未知異常", context.Exception); }
如果想在服務層或倉儲層用的話,安裝這個包 Microsoft.Extensions.Logging.Abstractions,引用下 using Microsoft.Extensions.Logging;

然后直接代碼里用就行了
[Caching(AbsoluteExpiration = 1)] public async Task<UserResponse> GetUserDetails(int id) { //var userinfo = await userDal.QueryByID(id); _logger.LogError("錯誤日志!"); var userinfo = new UserNew { UserId = id, UserName = "bingle", Age = 18 }; if (userinfo != null) { //UserResponse model = new UserResponse() //{ // UserId = userinfo.UserId, // UserName = userinfo.UserName, // Address = "xx市xx區xx小區", // Age = userinfo.Age, // Birthday = "1996-06-26", // Phone = "13888888888" //}; UserResponse model = iMapper.Map<UserResponse>(userinfo); model.Address = "xx市xx區xx小區"; model.Birthday = "1996-06-26"; model.Phone = "13888888888"; return model; } else { return null; } }
然后調試接口,這樣就有了日志:

