如何使用log4net记录跟踪信息?

76

我正在使用log4net将日志信息写入滚动日志文件。

现在,我也想将所有来自System.Diagnostics.Trace的跟踪消息重定向到该日志文件中。我该如何配置呢?我试图在log4net文档中查找相关信息,但是没有成功。这是否可能实现?

我之所以这样做,是因为我对第三方库的Trace消息感兴趣。

<log4net>
    <appender name="R1" type="log4net.Appender.RollingFileAppender">
      <file value="C:\Logs\MyService.log" />
      <appendToFile value="true" />
      <rollingStyle value="Date" />
      <maxSizeRollBackups value="10" />
      <datePattern value="yyyyMMdd" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
      </layout>
    </appender>
</log4net>
4个回答

74
根据Rune的建议,我实现了一个基本的TraceListener,输出到log4net:
public class Log4netTraceListener : System.Diagnostics.TraceListener
{
    private readonly log4net.ILog _log;

    public Log4netTraceListener()
    {
        _log = log4net.LogManager.GetLogger("System.Diagnostics.Redirection");
    }

    public Log4netTraceListener(log4net.ILog log)
    {
        _log = log;
    }

    public override void Write(string message)
    {
        if (_log != null)
        {
            _log.Debug(message);
        }
    }

    public override void WriteLine(string message)
    {
        if (_log != null)
        {
            _log.Debug(message);
        }
    }
}

15
对于上面的回答点赞。但是如果log4net也设置为写入TraceAppender,那么您需要小心。虽然我没有实际测试过,但您可能会陷入这样一种情况:Trace正在写入log4net,而log4net又在写入Trace,导致无限循环。例如,您可以通过不将TraceAppender包含在名称为“System.Diagnostics.Redirection”的记录器的附加程序中来减轻这种情况。 - Jimit
1
由于这是一个跟踪侦听器,您应该在Write方法中实现try/catch块,以确保写入尝试永远不会使主机失败。我提交了代码编辑,纠正了对象构造,并使代码更易读,更不容易失败。 - Shaun Wilson
@JYL 这里是博客文章的更新链接。然而,看起来在迁移过程中可能会有一些东西丢失。该文章中的XML代码现在不正确,Log4netTraceListener的链接也无法使用。希望作者能够恢复代码。 - Jon-Eric
4
log4net中是否有内置的监听器可以监听跟踪事件? - Manjay_TBAG
4
请查看log4net.Util.LogLog类的源代码。默认情况下,它会记录到Trace中,@Jimit大部分是正确的——如果发生附加器错误,你最终会死锁。在您的TraceListener实现中,我建议您在构造函数中确保设置log4net.Util.LogLog.EmitInternalMessages = false,并可能处理LogLog.LogReceived事件并以另一种方式记录这些消息。遗憾的是,由于此设置,某些附加器错误将无法记录。源代码在这里是您的朋友。 - Steven Bone
@Jimit:在您的评论中,您描述了我在链接问题 https://stackoverflow.com/questions/63242160/log4nettracelistener-for-signalr-web-application-hangs 中遇到的问题。但很遗憾我不理解您的建议:“......您可以通过不在记录器'System.Diagnostics.Redirection'的附加程序中包含TraceAppender来减轻这种情况。” - jreichert

26

我不知道log4net是否支持此功能,但您可以实现自己的跟踪侦听器来完成此操作。

TraceListener需要实现的方法不多,您只需要将值转发到log4net即可,因此这应该很容易实现。

要添加自定义跟踪侦听器,您可以修改app.config/web.config文件或使用Trace.Listeners.Add(new Log4NetTraceListener());代码进行添加。


1
根据上面的回答,这里有一个实现(此链接不稳定,但我找到了源代码):

https://code.google.com/archive/p/cavity/

为了简单地处理(在之前一个答案的评论中提到的)来自LogLog类的内部log4net跟踪问题,我通过检查堆栈帧(这个实现已经完成了)来确定此类是否是跟踪的来源,并忽略这些跟踪消息。
    public override void WriteLine(object o, string category)
    {
        // hack to prevent log4nets own diagnostic trace getting fed back
        var method = GetTracingStackFrame(new StackTrace()).GetMethod();
        var declaringType = method.DeclaringType;
        if (declaringType == typeof(LogLog))
        {
            return;
        }
        /* rest of method writes to log4net */
    }

使用TraceAppender仍然会导致上面评论中描述的问题。

1

谢谢,

我选择了Dirk的答案,稍微简化了一下。

public class Log4netTraceListener : System.Diagnostics.TraceListener
{
    private readonly log4net.ILog _log;

    public Log4netTraceListener()
        : this(log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType))
    {

    }

    public Log4netTraceListener(log4net.ILog log)
    {
        _log = log;
    }

    public override void Write(string message) => _log?.Debug(message);

    public override void WriteLine(string message) => _log?.Debug(message);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接