zoukankan      html  css  js  c++  java
  • asp.net core中使用Serilog以及自定义Enricher

    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来记录请求的上下文信息。启动应用程序,看下输出结果:

  • 相关阅读:
    指针、数组和结构体的一些思考
    Leetcode589.N-ary Tree Preorder TraversalN叉树的前序遍历
    Leetcode563.Binary Tree Tilt二叉树的坡度
    Leetcode559.Maximum Depth of N-ary TreeN叉树的最大深度
    Leetcode561.Array Partition I数组拆分1
    Leetcode551.Student Attendance Record I学生出勤记录1
    Leetcode543.Diameter of Binary Tree二叉树的直径
    Leetcode520Detect Capital检测大写字母
    Leetcode532.K-diff Pairs in an Array数组中的K-diff数对
    Leetcode496.Next Greater Element I下一个更大的元素1
  • 原文地址:https://www.cnblogs.com/pluto-net/p/13950919.html
Copyright © 2011-2022 走看看