asp.net core中使用Serilog以及自定义Enricher

  • A+
所属分类:.NET技术
摘要

与其他许多.NET库一样,Serilog还提供了对文件,控制台等的基本诊断日志记录。它易于设置,具有简洁的API,并且可以在最新的.NET平台之间移植。


Serilog简介

与其他许多.NET库一样,Serilog还提供了对文件,控制台等的基本诊断日志记录。它易于设置,具有简洁的API,并且可以在最新的.NET平台之间移植。

使用和配置、自定义Enricher

由于 serilog 配置信息比较多,避免硬编码代码中,我们在 appsetting.jgon 同级目录中新建一个 serilogsetting.json 的日志配置文件,简单内容如下:

{ 	"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 文档

接下来,在 Program.cs 中添加一个方法,初始化这些配置,然后重写下构建主机的代码:

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,请求路径,请求方法,和返回响应码:

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中间件:

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 CORE的中间件介绍

这样,我们就添加了一个自定义的Enricher来记录请求的上下文信息。启动应用程序,看下输出结果:
asp.net core中使用Serilog以及自定义Enricher