2

我在我的 MVC5 应用程序中使用SerilogSerilog.Exceptions用于结构化日志记录。

我想从日志中“异常”字段的值中删除堆栈跟踪。我知道我new JsonFormatter()在接收RollingFile器中使用 ,因此异常对象(例如ex)被格式化为ex.ToString()并且整个对象被按原样写入。

new DestructuringOptionsBuilder().WithDefaultDestructurers()用来在“ExceptionDetails”部分显示堆栈跟踪,作为一个单独的字段看起来要好得多。

是否可以仅将异常名称视为日志中“异常”字段的值,而不是在ex.ToString()写入 JSON 文件接收器时查看整个堆栈跟踪和其他详细信息?

这是我的异常日志:

{
  "Timestamp": "2021-09-02T15:04:02.4469999+05:00",
  "Level": "Error",
  "MessageTemplate": "Unhandled Exception",
  "Exception": "System.NullReferenceException: Object reference not set to an instance of an object.\r\n   at AppV2.Controllers.BaseController.Initialize(RequestContext requestContext) in E:\\Workspace\\AppV2\\AppV2\\Controllers\\BaseController.cs:line 115\r\n   at System.Web.Mvc.Controller.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state)\r\n   at System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state)\r\n   at System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__4(AsyncCallback asyncCallback, Object asyncState, ProcessRequestState innerState)\r\n   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallBeginDelegate(AsyncCallback callback, Object callbackState)\r\n   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout)\r\n   at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state)\r\n   at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state)\r\n   at System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData)\r\n   at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()\r\n   at System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step)\r\n   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)",
  "Properties": {
    "UserName": "adminuser@mail.com",
    "ThreadId": 5,
    "Caller": "AppV2.Extensions.Logger.LogError(System.Exception, System.String, System.Object[])",
    "MachineName": "DESKTOP-GHV3V41",
    "HttpRequestId": "e9922caf-7e25-47f8-9941-263ba1ec4278",
    "HttpRequestNumber": 1,
    "HttpRequestClientHostIP": "::1",
    "HttpRequestType": "GET",
    "HttpRequestRawUrl": "/",
    "ExceptionDetails": {
      "Type": "System.NullReferenceException",
      "HResult": -2147467261,
      "Message": "Object reference not set to an instance of an object.",
      "Source": "Boilerplate.Web.Mvc5.Sample",
      "StackTrace": "   at AppV2.Controllers.BaseController.Initialize(RequestContext requestContext) in E:\\Workspace\\AppV2\\AppV2\\Controllers\\BaseController.cs:line 115\r\n   at System.Web.Mvc.Controller.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state)\r\n   at System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state)\r\n   at System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__4(AsyncCallback asyncCallback, Object asyncState, ProcessRequestState innerState)\r\n   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallBeginDelegate(AsyncCallback callback, Object callbackState)\r\n   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout)\r\n   at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state)\r\n   at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state)\r\n   at System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData)\r\n   at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()\r\n   at System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step)\r\n   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)",
      "TargetSite": "Void Initialize(System.Web.Routing.RequestContext)"
    }
  }
}

这是我的Logger课:

public class Logger
{
    private static readonly ILogger logger;

    static Logger()
    {
        logger = new LoggerConfiguration()
            .Enrich.WithUserName(anonymousUsername: "Not Authenticated")
            .Enrich.FromLogContext()
            .Enrich.With(new ThreadEnrich())
            .Enrich.WithCaller()
            .Enrich.WithMachineName()
            .Enrich.WithHttpRequestId()
            .Enrich.WithHttpRequestNumber()
            .Enrich.WithHttpRequestClientHostIP()
            .Enrich.WithHttpRequestType()
            .Enrich.WithHttpRequestRawUrl()
            .Enrich.WithMvcRouteData()
            .Enrich.WithExceptionDetails(
                new DestructuringOptionsBuilder()
                .WithDefaultDestructurers())
            .Enrich.WithDemystifiedStackTraces()
            .WriteTo.RollingFile(new JsonFormatter(),
                HttpContext.Current.Server.MapPath($"~/logs/log-.json"),
                LogEventLevel.Debug,
                fileSizeLimitBytes: 655360)
            .CreateLogger();
    }

    public static void LogInformation(string info, object[] data = null)
    {
        logger.Information(info, data);
    }

    public static void LogDebug(string debug, object[] data = null)
    {
        logger.Debug(debug, data);
    }

    public static void LogWarning(string warning, object[] data = null, Exception e = null)
    {
        logger.Warning(e, warning, data);
    }

    public static void LogError(Exception e, string error, object[] data = null)
    {
        logger.Error(e, error, data);
    }
}

Logger也欢迎对我的课程提出任何建议。

4

2 回答 2

0

我进行了研究,我认为您应该检查 Serilog 过滤器。例如,您可以过滤事件字段、源甚至过滤具有特定值的数据。您可以通过在代码或 JSON 文件中的记录器配置中配置相应的过滤器来做到这一点。

有关更多信息,请参阅此链接https://github.com/serilog/serilog-filters-expressions

于 2021-10-26T10:29:14.953 回答
0

无论存在哪些日志属性,“格式化程序”都是 Serilog 将标准日志信息(包括异常)转换为文本的方式。

要摆脱冗余,您需要使用JsonFormatter. 这是我使用的一个,它只是将“ExceptionDetails”移动到顶级“Exception”的位置。

namespace Serilog.Exceptions.Formatting;

using System.IO;
using Serilog.Events;
using Serilog.Exceptions.Core;
using Serilog.Formatting;
using Serilog.Formatting.Json;

/// <summary>
/// A JSON text formatter using structured properties for exceptions.
/// </summary>
/// <remarks>
/// Avoids the redundancy of <see cref="JsonFormatter"/> when used with <see cref="ExceptionEnricher"/>.
/// </remarks>
public class StructuredExceptionFormatter : ITextFormatter
{
    private readonly string rootName;
    private readonly JsonValueFormatter valueFormatter = new(typeTagName: null);

    /// <summary>
    /// Initializes a new instance of the <see cref="StructuredExceptionFormatter"/> class.
    /// </summary>
    /// <param name="rootName">The root name used by the enricher, if different from the default.</param>
    public StructuredExceptionFormatter(string? rootName = null)
    {
        this.rootName = rootName ?? new DestructuringOptionsBuilder().RootName;
    }

    public void Format(LogEvent logEvent, TextWriter output)
    {
        output.Write("{\"Timestamp\":\"");
        output.Write(logEvent.Timestamp.UtcDateTime.ToString("O"));

        output.Write("\",\"Message\":");
        var message = logEvent.MessageTemplate.Render(logEvent.Properties);
        JsonValueFormatter.WriteQuotedJsonString(message, output);

        output.Write(",\"Level\":\"");
        output.Write(logEvent.Level);
        output.Write('\"');

        var propCount = logEvent.Properties.Count;

        if (logEvent.Properties.TryGetValue(this.rootName, out var exceptionProperty))
        {
            output.Write(",\"Exception\":");
            this.valueFormatter.Format(exceptionProperty, output);
            propCount--;
        }

        if (propCount > 0)
        {
            output.Write(",\"Properties\":{");
            var comma = false;

            foreach (var property in logEvent.Properties)
            {
                if (property.Key == this.rootName)
                {
                    continue;
                }

                if (comma)
                {
                    output.Write(',');
                }
                else
                {
                    comma = true;
                }

                JsonValueFormatter.WriteQuotedJsonString(property.Key, output);
                output.Write(':');
                this.valueFormatter.Format(property.Value, output);
            }

            output.Write("}");
        }

        output.WriteLine('}');
    }
}

使用示例Serilog.Sinks.File(其他接收器类似):

Log.Logger = new LoggerConfiguration()
  .Enrich.WithExceptionDetails()
  .WriteTo.File(new StructuredExceptionFormatter(), "./logs.json")
  .CreateLogger();

它会使您的异常如下所示:

{
  "Timestamp": "2021-09-02T15:04:02.4469999+05:00",
  "Level": "Error",
  "Message": "Unhandled Exception",
  "Exception": {
    "Type": "System.NullReferenceException",
    "HResult": -2147467261,
    "Message": "Object reference not set to an instance of an object.",
    "Source": "Boilerplate.Web.Mvc5.Sample",
    "StackTrace": "   at AppV2.Controllers.BaseController.Initialize(RequestContext requestContext) in E:\\Workspace\\AppV2\\AppV2\\Controllers\\BaseController.cs:line 115\r\n   at System.Web.Mvc.Controller.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state)\r\n   at System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state)\r\n   at System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__4(AsyncCallback asyncCallback, Object asyncState, ProcessRequestState innerState)\r\n   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallBeginDelegate(AsyncCallback callback, Object callbackState)\r\n   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout)\r\n   at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state)\r\n   at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state)\r\n   at System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData)\r\n   at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()\r\n   at System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step)\r\n   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)",
    "TargetSite": "Void Initialize(System.Web.Routing.RequestContext)"
  },
  "Properties": {
    "UserName": "adminuser@mail.com",
    "ThreadId": 5,
    "Caller": "AppV2.Extensions.Logger.LogError(System.Exception, System.String, System.Object[])",
    "MachineName": "DESKTOP-GHV3V41",
    "HttpRequestId": "e9922caf-7e25-47f8-9941-263ba1ec4278",
    "HttpRequestNumber": 1,
    "HttpRequestClientHostIP": "::1",
    "HttpRequestType": "GET",
    "HttpRequestRawUrl": "/"
  }
}
于 2021-11-18T23:28:09.730 回答