與其餘許多.NET庫同樣,Serilog還提供了對文件,控制檯等的基本診斷日誌記錄。它易於設置,具備簡潔的API,而且能夠在最新的.NET平臺之間移植。git
因爲 serilog 配置信息比較多,避免硬編碼代碼中,咱們在 appsetting.jgon 同級目錄中新建一個 serilogsetting.json 的日誌配置文件,簡單內容以下:github
{ "Serilog": { "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.Seq" ], "MinimumLevel": { "Default": "Information", "Override": { "System": "Error", "Microsoft": "Error" } }, "WriteTo": [ { "Name": "Console" }, { "Name": "Seq", "Args": { "serverUrl": "http://localhost:5341/", "apiKey": "L2on8gpgjose5uldhdch" } } ] } }
更多配置內容請參考:serilog wiki 文檔web
接下來,在 Program.cs 中添加一個方法,初始化這些配置,而後重寫下構建主機的代碼:json
public class Program { public static int Main(string[] args) { var logConfig = GetLogConfig(); Log.Logger = new LoggerConfiguration() .ReadFrom.Configuration(logConfig) .Enrich.FormLogContext() .CreateLogger(); try { // web host 初始化 var host = BuildWebHost(args); host.Run(); return 0; } catch(Exception e) { Log.Fatal(ex, "{ApplicationContext} 出現錯誤:{messsage} !", AppName, ex.Message); return 1; } finally { Log.CloseAndFlush(); } } /// <summary> /// 讀取日誌配置 /// </summary> /// <returns></returns> private static IConfiguration GetLogConfig() { var builder = new ConfigurationBuilder() .AddJsonFile("serilogsetting.json", optional: false, reloadOnChange: true); return builder.Build(); } }
而後,添加一個自定義Enircher,用來記錄HttpContext,的數據。_enrichAction則能夠自定義,默認記錄ip,請求路徑,請求方法,和返回響應碼:api
public class HttpContextEnricher:ILogEventEnricher { private readonly IServiceProvider _serviceProvider; private readonly Action<LogEvent, ILogEventPropertyFactory, HttpContext> _enrichAction; public HttpContextEnricher(IServiceProvider serviceProvider) : this(serviceProvider, null) {} public HttpContextEnricher(IServiceProvider serviceProvider, Action<LogEvent, ILogEventPropertyFactory, HttpContext> enrichAction) { _serviceProvider = serviceProvider; if (enrichAction == null) { _enrichAction = (logEvent, propertyFactory, httpContext) =>{ var x_forwarded_for = new StringValues(); if (httpContext.Request.Headers.ContainsKey("X-Forwarded-For")) { x_forwarded_for = httpContext.Request.Headers["X-Forwarded-For"]; } logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("client_ip", JsonConvert.SerializeObject(x_forwarded_for))); logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("request_path", httpContext.Request.Path)); logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("request_method", httpContext.Request.Method)); if (httpContext.Response.HasStarted) { logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("response_status", httpContext.Response.StatusCode)); } } }else{ _enrichAction = enrichAction; } } public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) { var httpContext = _serviceProvider.GetService<IHttpContextAccessor>()?.HttpContext; if (null != httpContext){ _enrichAction.Invoke(logEvent, propertyFactory, httpContext); } } }
如今,咱們添加了一個記錄HttpContext的Enricher,可是怎麼用起來呢,怎麼添加到日誌對象中呢。就要靠asp.net core的中間件了。新建一個HttpContextLogMiddleware
中間件:app
public class HttpContextLogMiddleware { private readonly RequestDelegate _next; public HttpContextLogMiddleware(RequestDelegate next) { _next = next; } public async Task InvokeAsync(HttpContext context) { var serviceProvider = context.RequestServices; // 將咱們自定義的Enricher添加到LogContext中。 // LogContext功能很強大,能夠動態添加屬性,具體使用介紹,參見官方wiki文檔 using (LogContext.Push(new HttpContextEnricher(serviceProvider))) { await _next(context); } } } // 使用擴展方法形式注入中間件 public static IApplicationBuilder UseHttpContextLog( this IApplicationBuilder builder) { return builder.UseMiddleware<HttpContextLogMiddleware>(); }
這樣,咱們就創建了一箇中間件,接下來在Startup.cs的Configure方法中app.UseHttpContextLog();
便可。asp.net
此處須要注意中間件的順序,參見官方ASP.NET CORE的中間件介紹async
這樣,咱們就添加了一個自定義的Enricher來記錄請求的上下文信息。啓動應用程序,看下輸出結果:
ide