NLog LogEventInfo.Message 是 {0} 而不是自定义 LayoutRenderer 上的 null 或空

NLog LogEventInfo.Message is {0} instead of null or empty on custom LayoutRenderer

我有一个习惯LayoutRenderer

如果我调用下面的语句,那么我总是得到 LogEventInfo.Message = {0} 而不是 null""。我是不是误会了什么?

try
{
    int a = 1;
    int b = 0;
    var c = a / b;
}
catch (Exception e)
{
    var logger = LogManager.GetCurrentClassLogger();

    logger.Error(e);
}

public class HtLayoutRenderer : LayoutRenderer
{
    protected override void Append(StringBuilder builder, LogEventInfo logEvent)
    {
        // logEvent.Message is {0} instead of being null or empty ""
    }
}

更新 1 - 添加了完整的示例代码

我只发布了一个非常小的例子。

我有两个习惯 ExceptionsHtReturnStatusHtExceptions。两者都是Exception类型。 HtReturnStatus 可以包含 HtExceptionsHtLayoutRenderer 正在解压缩对象并制作方便的日志记录布局。提供什么 class/object 类型无关紧要。

我的问题是{0}。当这是 正常行为 时,我会检查 logEvent.Message 是否为 {0} 并忽略它。

try
{
    int a = 1;
    int b = 0;
    var c = a / b;
}
catch (Exception e)
{
    LayoutRenderer.Register<HtLayoutRenderer>("htmessage");

    TraceTarget target = new TraceTarget();
    target.Name = "console";
    target.Layout = Layout.FromString("${longdate} | ${level:uppercase=true} | ${logger} | ${htmessage}");
    LogManager.Configuration = new LoggingConfiguration();
    LogManager.Configuration.AddTarget(target);
    LogManager.Configuration.LoggingRules.Insert(0, new LoggingRule("*", LogLevel.FromString("Trace"), target));
    LogManager.ReconfigExistingLoggers();

    var logger = LogManager.GetCurrentClassLogger();

    logger.Error("1");
    logger.Error(e);
    logger.Error("2");
    logger.Error(e, "Hello World");
    logger.Error("");
    logger.Error("3");
    logger.Error(HtReturnStatus.Failed(e), "Lorem Ipsum");
    logger.Error("");
    logger.Error("4");
    logger.Error(HtReturnStatus.Failed(e, "Error on division"));
    logger.Error("");
    logger.Error("5");
    logger.Error(HtReturnStatus.Failed(HtErrorCode.OPC_BAD_CERTIFICATE_INVALID));
    logger.Error("");
    logger.Error("6");
    logger.Error(HtReturnStatus.Failed(HtErrorCode.OPC_BAD_UNEXPECTED_ERROR, "Error on division #2"));

    logger.Error("");
    logger.Error("7");
    logger.Error(new HtException(HtErrorCode.CODE_READER_DMC_MultipleMatches));
    logger.Error("");
    logger.Error("8");
    logger.Error(new HtException(HtErrorCode.CODE_READER_DMC_MultipleMatches, "hello world"));
    logger.Error("");
    logger.Error("9");
    logger.Error(new HtException(HtErrorCode.CODE_READER_DMC_MultipleMatches, "lorem ipsum", e));
}
testhost Error: 0 : 2020-01-21 10:14:01.1168 | ERROR | Haprotec.Error.NLogOutputTest | 1
testhost Error: 0 : 2020-01-21 10:14:01.1383 | ERROR | Haprotec.Error.NLogOutputTest | {0} - Attempted to divide by zero. - System.DivideByZeroException: Attempted to divide by zero.
StackTrace:    at Haprotec.Error.NLogOutputTest.HtReturnStatusOutputTest() in D:\Repositories\gitlab.haprotec\dotNet\HtCore\src\HtCore.Tests\Error\NLogOutputTest.cs:line 26
testhost Error: 0 : 2020-01-21 10:14:01.1572 | ERROR | Haprotec.Error.NLogOutputTest | 2
testhost Error: 0 : 2020-01-21 10:14:01.1572 | ERROR | Haprotec.Error.NLogOutputTest | Hello World - Attempted to divide by zero. - System.DivideByZeroException: Attempted to divide by zero.
StackTrace:    at Haprotec.Error.NLogOutputTest.HtReturnStatusOutputTest() in D:\Repositories\gitlab.haprotec\dotNet\HtCore\src\HtCore.Tests\Error\NLogOutputTest.cs:line 26
testhost Error: 0 : 2020-01-21 10:14:01.1572 | ERROR | Haprotec.Error.NLogOutputTest | 
testhost Error: 0 : 2020-01-21 10:14:01.1572 | ERROR | Haprotec.Error.NLogOutputTest | 3
testhost Error: 0 : 2020-01-21 10:14:01.1742 | ERROR | Haprotec.Error.NLogOutputTest | Lorem Ipsum - System.DivideByZeroException: Attempted to divide by zero.
StackTrace:    at Haprotec.Error.NLogOutputTest.HtReturnStatusOutputTest() in D:\Repositories\gitlab.haprotec\dotNet\HtCore\src\HtCore.Tests\Error\NLogOutputTest.cs:line 26
testhost Error: 0 : 2020-01-21 10:14:01.1742 | ERROR | Haprotec.Error.NLogOutputTest | 
testhost Error: 0 : 2020-01-21 10:14:01.1742 | ERROR | Haprotec.Error.NLogOutputTest | 4
testhost Error: 0 : 2020-01-21 10:14:01.1742 | ERROR | Haprotec.Error.NLogOutputTest | {0} - Error on division - System.DivideByZeroException: Attempted to divide by zero.
StackTrace:    at Haprotec.Error.NLogOutputTest.HtReturnStatusOutputTest() in D:\Repositories\gitlab.haprotec\dotNet\HtCore\src\HtCore.Tests\Error\NLogOutputTest.cs:line 26
testhost Error: 0 : 2020-01-21 10:14:01.1905 | ERROR | Haprotec.Error.NLogOutputTest | 
testhost Error: 0 : 2020-01-21 10:14:01.1905 | ERROR | Haprotec.Error.NLogOutputTest | 5
testhost Error: 0 : 2020-01-21 10:14:01.2166 | ERROR | Haprotec.Error.NLogOutputTest | {0} - Haprotec.Error.HtException: 563021 (OPC_BAD_CERTIFICATE_INVALID)
StackTrace:    at Haprotec.Error.NLogOutputTest.HtReturnStatusOutputTest() in D:\Repositories\gitlab.haprotec\dotNet\HtCore\src\HtCore.Tests\Error\NLogOutputTest.cs:line 26
testhost Error: 0 : 2020-01-21 10:14:01.2204 | ERROR | Haprotec.Error.NLogOutputTest | 
testhost Error: 0 : 2020-01-21 10:14:01.2204 | ERROR | Haprotec.Error.NLogOutputTest | 6
testhost Error: 0 : 2020-01-21 10:14:01.2204 | ERROR | Haprotec.Error.NLogOutputTest | {0} - Error on division #2 - Haprotec.Error.HtException: 563001 (OPC_BAD_UNEXPECTED_ERROR)
StackTrace:    at Haprotec.Error.NLogOutputTest.HtReturnStatusOutputTest() in D:\Repositories\gitlab.haprotec\dotNet\HtCore\src\HtCore.Tests\Error\NLogOutputTest.cs:line 26
testhost Error: 0 : 2020-01-21 10:14:01.2204 | ERROR | Haprotec.Error.NLogOutputTest | 
testhost Error: 0 : 2020-01-21 10:14:01.2204 | ERROR | Haprotec.Error.NLogOutputTest | 7
testhost Error: 0 : 2020-01-21 10:14:01.2374 | ERROR | Haprotec.Error.NLogOutputTest | {0} - Haprotec.Error.HtException: 500251 (CODE_READER_DMC_MultipleMatches)
StackTrace:    at Haprotec.Error.NLogOutputTest.HtReturnStatusOutputTest() in D:\Repositories\gitlab.haprotec\dotNet\HtCore\src\HtCore.Tests\Error\NLogOutputTest.cs:line 26
testhost Error: 0 : 2020-01-21 10:14:01.2374 | ERROR | Haprotec.Error.NLogOutputTest | 
testhost Error: 0 : 2020-01-21 10:14:01.2374 | ERROR | Haprotec.Error.NLogOutputTest | 8
testhost Error: 0 : 2020-01-21 10:14:01.2374 | ERROR | Haprotec.Error.NLogOutputTest | {0} - hello world - Haprotec.Error.HtException: 500251 (CODE_READER_DMC_MultipleMatches)
StackTrace:    at Haprotec.Error.NLogOutputTest.HtReturnStatusOutputTest() in D:\Repositories\gitlab.haprotec\dotNet\HtCore\src\HtCore.Tests\Error\NLogOutputTest.cs:line 26
testhost Error: 0 : 2020-01-21 10:14:01.2374 | ERROR | Haprotec.Error.NLogOutputTest | 
testhost Error: 0 : 2020-01-21 10:14:01.2506 | ERROR | Haprotec.Error.NLogOutputTest | 9
testhost Error: 0 : 2020-01-21 10:14:01.2506 | ERROR | Haprotec.Error.NLogOutputTest | {0} - lorem ipsum - System.DivideByZeroException: Attempted to divide by zero.
StackTrace:    at Haprotec.Error.NLogOutputTest.HtReturnStatusOutputTest() in D:\Repositories\gitlab.haprotec\dotNet\HtCore\src\HtCore.Tests\Error\NLogOutputTest.cs:line 26

这完全是故意的。您正在调用此记录器方法,其中一个正在记录一个随机对象:

Logger.Error<T>(T value);

为此 shorthand,以确保 string.Format 有效:

Logger.Error("{0}", value);

但是您可能已经注意到 Exception 已经实施了特殊处理。 NLog 执行额外检查以捕获 ${exception} 的异常参数,但不会更改格式字符串。

在你的HtLayoutRenderer中,你可以这样识别它:

public class HtLayoutRenderer : LayoutRenderer
{
    protected override void Append(StringBuilder builder, LogEventInfo logEvent)
    {
       if ( logevent.Exception != null
         && logevent.Message == "{0}"
         && logevent.Parameters?.Length == 1
         && ReferenceEquals(logevent.Exception, logevent.Parameters[0])
       {
          // Exception given as single parameter without any message
       }
    }
}

请注意 LogEventInfo.MessageLogEventInfo.FormattedMessage

之间存在差异