从消息和例外

时间:2018-04-06 20:04:51

标签: serilog

我在Asp dot net core应用程序中使用Serilog。我希望我的日志文件是人类可读的,但也能够轻松解析。

我遇到的问题是使用换行符记录异常。某些Microsoft事件包含包含新行的消息。

我希望能够解析每行一个事件的日志文件。

我可以编写自己的ITextFormatter实现,用\ r \ n替换新行,但我们的意思是我需要复制MessageTemplateTextFormatter和其他类中的大部分逻辑。

4 个答案:

答案 0 :(得分:2)

在深入研究这一段时间后,我能够得出答案。 Andy West的回答指出了我正确的方向。

这里有两个不同的问题:消息中的CRLF和异常中的CRLF。

我能够通过更改" {Message}"来解决邮件问题。到" {消息:j}"在outputTemplate中。

更改异常有点棘手。我不得不添加一个浓缩器:

class ExceptionEnricher : ILogEventEnricher
{
    public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
    {
        if (logEvent.Exception == null)
            return;

        var logEventProperty = propertyFactory.CreateProperty("EscapedException", logEvent.Exception.ToString().Replace("\r\n", "\\r\\n"));
        logEvent.AddPropertyIfAbsent(logEventProperty);
    }        
}

这会添加名为EscapedException的新属性。必须使用.Enrich.With()。

将其添加到配置中

然后我更换了#34; {Exception}"用" {EscapedException}"在outputTemplate中。

答案 1 :(得分:1)

您没有指定如何记录异常,但假设您使用的是:

Log.Error("An error occurred: {Exception}", exception);

然后将使用ToString()呈现异常。在这种情况下,你不能简单地这样做:

Log.Error("An error occurred: {Exception}", exception.ToString().Replace(System.Environment.NewLine, "\\r\\n"));

当然,如果你需要在一个以上的地方进行,你可以将它重构为一个方法(可能是一个扩展方法)。

答案 2 :(得分:0)

此技术将删除所有 CRLF。首先是一个新的 ITextFormatter。

    public class RemoveCrLf : ITextFormatter
    {
        private const int DefaultWriteBuffer = 256;

        private readonly ITextFormatter _textFormatter;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="textFormatter"></param>
        public RemoveCrLf(ITextFormatter textFormatter)
        {
            _textFormatter = textFormatter;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="logEvent"></param>
        /// <param name="output"></param>
        public void Format(LogEvent logEvent, TextWriter output)
        {
            var buffer = new StringWriter(new StringBuilder(DefaultWriteBuffer));

            _textFormatter.Format(logEvent, buffer);

            var logText = buffer.ToString();

            output.WriteLine(logText.Trim().Replace("\n","\\n").Replace("\r","\\r"));
            output.Flush();
        }
    }

像这样使用

configuration.WriteTo.Console(new RemoveCrLf(new MessageTemplateTextFormatter("[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} {Exception}")));

当然,根据需要自定义输出模板。

答案 3 :(得分:0)

参考@Andrew Radford 的解决方案,该解决方案仅适用于 Windows,但不适用于 linux docker 环境。所以 我增强了消息和异常的解决方案。

我在 Regex 中使用 Environment.NewLine 进行案例匹配,它将根据托管环境选择案例。

为消息添加以下类。

public class MessageEnricher : ILogEventEnricher
{
    public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
    {
        if (logEvent.MessageTemplate == null)
            return;

        var logEventProperty = propertyFactory.CreateProperty("EscapedMessage", Regex.Replace(logEvent.MessageTemplate.ToString(), Environment.NewLine, "[Newline]"));
        logEvent.AddPropertyIfAbsent(logEventProperty);
    }
}

对异常使用以下类。

    public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
    {
        if (logEvent.Exception == null)
            return;

        var logEventProperty = propertyFactory.CreateProperty("EscapedException", Regex.Replace(logEvent.Exception.ToString(), Environment.NewLine, "[Newline]"));
        logEvent.AddPropertyIfAbsent(logEventProperty);
    }

然后将这两个辅助类添加到 program.cs

           Log.Logger = new LoggerConfiguration()
          .ReadFrom.Configuration(Configuration)
          .Enrich.With(new ExceptionEnricher())
          .Enrich.With(new MessageEnricher())
          .Enrich.FromLogContext()
          .CreateLogger();

更新 appsettings 输出模板

 "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} {Level:u4} {SourceContext:l} : {EscapedMessage}{NewLine}{EscapedException}{NewLine}"