【问题标题】:how to customize output serilog如何自定义输出serilog
【发布时间】:2020-11-04 22:37:57
【问题描述】:

大家好,我怎样才能得到这个输出

{
    "@t": "2020-11-03T16:40:21.6133998Z",
    "@m": "HTTP \"POST\" \"/api/Email/SendEmail\" responded 200 in 1.0358 ms",
    "@i": "62d0885c",
    "CorrelationId": "",
    "Host": "localhost:32768",
    "Protocol": "HTTP/1.1",
    "Scheme": "http",
    "ContentType": null,
    "EndpointName": "Email.Controllers.EmailController.SendEmail (Email)",
    "RequestMethod": "POST",
    "RequestPath": "/api/Email/SendEmail",
    "StatusCode": 200,
    "Elapsed": 1.0358,
    "SourceContext": "Serilog.AspNetCore.RequestLoggingMiddleware",
    "RequestId": "",
    "SpanId": "|55f14a36-4918a3efd4f265b9.",
    "TraceId": "55f14a36-4918a3efd4f265b9",
    "ParentId": "",
    "ConnectionId": "0HM402S7EC249"
}

但是当我调用我的控制器时,我看到并运行应用程序,我看到了

这就是我如何设置我的 Serilog,我做错了什么

 public class LogConfig
    {
        public static void Configure()
        {
            Log.Logger = new LoggerConfiguration()
               .WriteTo.Console(new RenderedCompactJsonFormatter())
              .CreateLogger();
        }

        public static void EnrichFromRequest(IDiagnosticContext diagnosticContext, HttpContext httpContext)
        {
            diagnosticContext.Set("RequestScheme", httpContext.Request.Host.Value);
            diagnosticContext.Set("Headers", httpContext.Request.Scheme);
        } 
    }

PS

提前致谢:)

【问题讨论】:

  • 以下是您需要遵循的所有步骤:link

标签: c# asp.net-core


【解决方案1】:

Serilog 项目提供了三种 JSON 格式化程序:

  • Serilog.Formatting.Json.JsonFormatter - 这是 Serilog 包中的历史默认值。它会生成日志事件的完整呈现并支持一些配置选项。
  • Serilog.Formatting.Compact.CompactJsonFormatter - Serilog.Formatting.Compact 中提供了更新、更节省空间的 JSON 格式化程序。
  • Serilog.Formatting.Compact.RenderedCompactJsonFormatter - 同样在 Serilog.Formatting.Compact 中提供,此格式化程序将消息模板预渲染为文本。

您可以参考以下步骤并使用Serilog.Formatting.Compact 自定义 Serilog 输出:

  1. 通过 Nuget 安装 Serilog.AspNetCore

  2. 配置使用Serilog:

     public class Program
     {
         public static int Main(string[] args)
         {
             // CreateHostBuilder(args).Build().Run();
    
             Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Debug()
            .MinimumLevel.Override("Microsoft", LogEventLevel.Information)
            .Enrich.FromLogContext()
            .WriteTo.File(new CompactJsonFormatter(), "log20201104.json")
            .CreateLogger();
    
             try
             {
                 Log.Information("Starting web host");
                 CreateHostBuilder(args).Build().Run();
                 return 0;
             }
             catch (Exception ex)
             {
                 Log.Fatal(ex, "Host terminated unexpectedly");
                 return 1;
             }
             finally
             {
                 Log.CloseAndFlush();
             }
         }
    
         public static IHostBuilder CreateHostBuilder(string[] args) =>
             Host.CreateDefaultBuilder(args)
                 .UseSerilog()
                 .ConfigureWebHostDefaults(webBuilder =>
                 {
                     webBuilder.UseStartup<Startup>();
                 });
     }
    

    记得添加以下引用:

     using Serilog;
     using Serilog.Events;
     using Serilog.Formatting.Compact;
    
  3. 根据您的代码,您似乎想要记录请求和响应信息,如果是这种情况,您还可以创建一个SerilogRequestLogger 中间件。像这样:

     public class SerilogRequestLogger
     {
         readonly RequestDelegate _next;
    
         public SerilogRequestLogger(RequestDelegate next)
         {
             if (next == null) throw new ArgumentNullException(nameof(next));
             _next = next;
         }
    
         public async Task Invoke(HttpContext httpContext)
         {
             if (httpContext == null) throw new ArgumentNullException(nameof(httpContext));
    
             // Push the user name into the log context so that it is included in all log entries
             LogContext.PushProperty("UserName", httpContext.User.Identity.Name);
    
             // Getting the request body is a little tricky because it's a stream
             // So, we need to read the stream and then rewind it back to the beginning
             string requestBody = "";
             HttpRequestRewindExtensions.EnableBuffering(httpContext.Request);
             Stream body = httpContext.Request.Body;
             byte[] buffer = new byte[Convert.ToInt32(httpContext.Request.ContentLength)];
             await httpContext.Request.Body.ReadAsync(buffer, 0, buffer.Length);
             requestBody = Encoding.UTF8.GetString(buffer);
             body.Seek(0, SeekOrigin.Begin);
             httpContext.Request.Body = body;
    
             Log.ForContext("RequestHeaders", httpContext.Request.Headers.ToDictionary(h => h.Key, h => h.Value.ToString()), destructureObjects: true)
                .ForContext("RequestBody", requestBody)
                .Debug("Request information {RequestMethod} {RequestPath} information", httpContext.Request.Method, httpContext.Request.Path);
    
             Log.Information(string.Format("Request Body: {0} ", requestBody));
    
             var exampleUser = new WebApplication2User { Id = "1001", UserName = "Adam", SecurityStamp = DateTime.Now.ToString() };
             Log.Information("Created {@User} on {Created}", exampleUser, DateTime.Now);
             // The reponse body is also a stream so we need to:
             // - hold a reference to the original response body stream
             // - re-point the response body to a new memory stream
             // - read the response body after the request is handled into our memory stream
             // - copy the response in the memory stream out to the original response stream
             using (var responseBodyMemoryStream = new MemoryStream())
             {
                 var originalResponseBodyReference = httpContext.Response.Body;
                 httpContext.Response.Body = responseBodyMemoryStream;
    
                 await _next(httpContext);
    
                 httpContext.Response.Body.Seek(0, SeekOrigin.Begin);
                 var responseBody = await new StreamReader(httpContext.Response.Body).ReadToEndAsync();
                 httpContext.Response.Body.Seek(0, SeekOrigin.Begin);
    
                 Log.ForContext("RequestBody", requestBody)
                    .ForContext("ResponseBody", responseBody)
                    .Debug("Response information {RequestMethod} {RequestPath} {statusCode}", httpContext.Request.Method, httpContext.Request.Path, httpContext.Response.StatusCode);
    
                 await responseBodyMemoryStream.CopyToAsync(originalResponseBodyReference);
             }
         }
     }
    
  4. Configure方法中配置SerilogRequestLogger中间件:

      app.UseMiddleware<SerilogRequestLogger>();
    

然后,您可以使用以下代码来记录信息:

            var exampleUser = new WebApplication2User { Id = "1001", UserName = "Adam", SecurityStamp = DateTime.Now.ToString() };
            Log.Information("Created {@User} on {Created}", exampleUser, DateTime.Now);

结果如下:

{"@t":"2020-11-04T14:19:23.2065796Z","@mt":"创建于 {@User} {Created}","User":{"Id":"1001","Age":0,"UserName":"Adam","NormalizedUserName":null,"Email":null,"NormalizedEmail":null, "EmailConfirmed":false,"PasswordHash":null,"SecurityStamp":"2020 年 11 月 4 日 10:19:23 PM","ConcurrencyStamp":"ca564733-9524-446f-8103-dd211cf8b44c","PhoneNumber":null,"PhoneNumberConfirmed":false,"TwoFactorEnabled":false,"LockoutEnd":null,"LockoutEnabled":false," AccessFailedCount":0,"$type":"WebApplication2User"},"Created":"2020-11-04T22:19:23.2060830+08:00","UserName":null,"RequestId":"80000080-0005- fd00-b63f-84710c7967bb","RequestPath":"/Home/Privacy","SpanId":"|e29bfdb0-4bd9f6a34acb24d8.","TraceId":"e29bfdb0-4bd9f6a34acb24d8","ParentId":""}

参考:

Formatting JSON

Serilog.Formatting.Compact

How to add 'request body' in serilog's output .net core?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-08
    • 2018-10-04
    • 2012-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-12
    相关资源
    最近更新 更多