nlog:使用" Trace"输出使Logger.Error()抛出异常 - 如何修复?

时间:2012-09-28 11:18:39

标签: c# trace nlog system.diagnostics

我正在使用NLog进行日志记录。我正在尝试设置一种方法来将其输出到System.Diagnostics.Trace(),所以我按如下方式设置NLog.config文件:

  

<targets>
  <target name="debugOutput" xsi:type="Trace" />
</targets>
<rules>
  <logger name="*" minlevel="Debug" writeTo="debugOutput" />
</rules>

这适用于所有日志记录级别,除了Error()和Fatal()。

例如,以下代码:

private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
...
_logger.Trace("Sample trace message\n");
_logger.Debug("Sample debug message\n");
_logger.Info("Sample informational message\n");
_logger.Warn("Sample warning message\n");
_logger.Error("Sample error message\n");
_logger.Fatal("Sample fatal error message\n");

在调用_logger.Error()和_logger.Fatal()时抛出异常:

2012-09-28 12:08:04.9296|DEBUG|ClassLibraryUsingNLog.Test|Sample debug message

2012-09-28 12:08:04.9636|INFO|ClassLibraryUsingNLog.Test|Sample informational message

2012-09-28 12:08:04.9906|WARN|ClassLibraryUsingNLog.Test|Sample warning message

---- DEBUG ASSERTION FAILED ----
---- Assert Short Message ----
2012-09-28 12:08:05.0176|ERROR|ClassLibraryUsingNLog.Test|Sample error message

---- Assert Long Message ----

   at NLog.Targets.TraceTarget.Write(LogEventInfo logEvent)
   at NLog.Targets.Target.Write(AsyncLogEventInfo logEvent)
   at NLog.Targets.Target.WriteAsyncLogEvent(AsyncLogEventInfo logEvent)
   at NLog.LoggerImpl.WriteToTargetWithFilterChain(TargetWithFilterChain targetListHead, LogEventInfo logEvent, AsyncContinuation onException)
   at NLog.LoggerImpl.Write(Type loggerType, TargetWithFilterChain targets, LogEventInfo logEvent, LogFactory factory)
   at NLog.Logger.WriteToTargets[T](LogLevel level, IFormatProvider formatProvider, T value)
   at NLog.Logger.Error(String message)
   at ClassLibraryUsingNLog.Test.Func() in c:\Test\CS4.x\ClassLibraryUsingNLog\Test.cs:line 15
   at ConsoleAppIndirectlyUsesNLog.Program.Main(String[] args) in C:\Test\CS4.x\ConsoleAppIndirectlyUsesNLog\Program.cs:line 11

First-chance exception at 0x7686b9bc in ConsoleAppIndirectlyUsesNLog.exe: Microsoft C++ exception: EEMessageException at memory location 0x0053e8d4..
---- DEBUG ASSERTION FAILED ----
---- Assert Short Message ----
2012-09-28 12:08:06.7936|FATAL|ClassLibraryUsingNLog.Test|Sample fatal error message

---- Assert Long Message ----

   at NLog.Targets.TraceTarget.Write(LogEventInfo logEvent)
   at NLog.Targets.Target.Write(AsyncLogEventInfo logEvent)
   at NLog.Targets.Target.WriteAsyncLogEvent(AsyncLogEventInfo logEvent)
   at NLog.LoggerImpl.WriteToTargetWithFilterChain(TargetWithFilterChain targetListHead, LogEventInfo logEvent, AsyncContinuation onException)
   at NLog.LoggerImpl.Write(Type loggerType, TargetWithFilterChain targets, LogEventInfo logEvent, LogFactory factory)
   at NLog.Logger.WriteToTargets[T](LogLevel level, IFormatProvider formatProvider, T value)
   at NLog.Logger.Fatal(String message)
   at ClassLibraryUsingNLog.Test.Func() in c:\Test\CS4.x\ClassLibraryUsingNLog\Test.cs:line 16
   at ConsoleAppIndirectlyUsesNLog.Program.Main(String[] args) in C:\Test\CS4.x\ConsoleAppIndirectlyUsesNLog\Program.cs:line 11

但是,如果我将配置文件更改为输出到OutputDebugString,则将xsi:type更改为“OutputDebugString”,如下所示:

  

<targets>
  <target name="debugOutput" xsi:type="OutputDebugString" />
</targets>
<rules>
  <logger name="*" minlevel="Debug" writeTo="debugOutput" />
</rules>

然后一切正常,没有任何例外。我在调试输出窗口中获取此输出(在更改项目设置以支持非托管调试之后):

2012-09-28 12:16:13.4166|DEBUG|ClassLibraryUsingNLog.Test|Sample debug message
2012-09-28 12:16:13.4166|INFO|ClassLibraryUsingNLog.Test|Sample informational message
2012-09-28 12:16:13.4166|WARN|ClassLibraryUsingNLog.Test|Sample warning message
2012-09-28 12:16:13.4266|ERROR|ClassLibraryUsingNLog.Test|Sample error message
2012-09-28 12:16:13.4266|FATAL|ClassLibraryUsingNLog.Test|Sample fatal error message

有没有办法让输出到System.Diagnostics.Trace()而不抛出Logger.Error()和Logger.Fatal()的异常?为什么它会这样?

3 个答案:

答案 0 :(得分:3)

继第一个答案之后:

NLog TraceTarget调用Trace.Fail,LogLevel是&gt; = LogLevel.Error

此处记录了Trace.Fail方法http://msdn.microsoft.com/en-us/library/95s7fba5.aspx

问题的原因似乎是:

默认跟踪侦听器的默认行为是在应用程序以用户界面模式运行时将消息参数输出到消息框,并将其输出到Listeners集合中的TraceListener实例。

您可以在控制台应用中演示此问题

 static void Main( string[ ] args ){
  Trace.TraceInformation( "Hello world" );
  Trace.Fail("A failure");
}

您可以在添加自己的TraceListener

之前删除DefaultTraceListener来“修复”此问题
static void Main( string[ ] args ){
  Trace.Listeners.Clear();
  Trace.Listeners.Add( new ConsoleTraceListener( ) );
  Trace.TraceInformation( "Hello world" );
  Trace.Fail("A failure");
}

或者,您可以将DefaultTraceListener的AssertUiEnabled属性设置为false。

static void Main( string[ ] args ){
  Trace.Listeners.OfType<DefaultTraceListener>().First().AssertUiEnabled = false;
  Trace.TraceInformation( "Hello world" );
  Trace.Fail("A failure");
}

这会抑制断言失败对话,但跟踪输出仍然包含虚假堆栈转储

如果您只想将日志信息发送到Visual Studion Output窗口,请使用DebuggerTarget

答案 1 :(得分:2)

在内部,TraceTarget使用System.Diagnostics.Trace.Fail来编写消息。

以下是NLog TraceTarget的Write方法的代码:

protected override void Write(LogEventInfo logEvent)
{
    if (logEvent.Level >= LogLevel.Error)
    {
        Trace.Fail(this.Layout.Render(logEvent));
    }
    else
    {
        Trace.WriteLine(this.Layout.Render(logEvent));
    }
}

我对Trace.Fail显然失败的原因没有答案。但是,知道NLog使用Trace.Fail,您可以尝试使用Trace.Fail(在使用NLog登录的同一个调用站点),看看是否可以诊断Trace.Fail出了什么问题。它可能与app.config文件中的System.Diagnostics配置(或缺少相同)有关。

请注意,在Trace.Fail的MSDN文档中,它表示如果不存在DefaultTraceListener,则使用MessageBox。我在您的输出中注意到您正在使用控制台应用程序。 MessageBox在Console应用程序的上下文中是否可能无法正常工作?

Here is a link to a relatively old blog posting by Scott Hanselman可能会对您的问题有所了解。接下来,他描述了在非UI环境中Trace.Fail的问题,并提出了一个可能适合您的解决方案。

总结一下,他建议将此(特别是assertuienabled标志)放在app.config / web.config中(或通过code设置)。

<configuration>
   <system.diagnostics>
      <assert assertuienabled="false" logfilename="c:\log.txt"/>
   </system.diagnostics>
</configuration>
祝你好运!

答案 2 :(得分:1)

NLog 4.5引入了rawWrite=true设置,该设置独立于LogLevel转发到Trace.WriteLine

<targets>
  <target xsi:type="Trace" name="debugOutput" rawWrite="true" />
</targets>

另请参阅:https://github.com/nlog/nlog/wiki/Trace-target

P.S。从NLog 2.0.1开始,只有LogLevel.Fatal被映射到Trace.Fail