76

I'm using log4net to log write log message to a rolling log file.

Now I would also redirect all trace messages from System.Diagnostics.Trace to that log file. How can I configure that? I tried to find anything about that in the log4net documentation, but without success. Is it possible at all?

The reason I want to do that is because I am interested in the Trace messages of a 3rd party library.

<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>
svick
  • 236,525
  • 50
  • 385
  • 514
Dirk Vollmar
  • 172,527
  • 53
  • 255
  • 316

4 Answers4

74

According to Rune's suggestion I implemented a basic TraceListener which output to 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);
        }
    }
}
Shaun Wilson
  • 8,727
  • 3
  • 50
  • 48
Dirk Vollmar
  • 172,527
  • 53
  • 255
  • 316
  • 15
    +1 for the answer above. I'd be careful if log4net is also setup to write to a TraceAppender though. I haven't actually tested this but you might end up in a situation wherein Trace is writing to log4net and log4net is writing to Trace resulting in an infinite loop. Given the example above for instance, you could mitigate that by not including the TraceAppender in the appenders for logger 'System.Diagnostics.Redirection'. – Jimit Apr 21 '11 at 14:00
  • 1
    Because this is a trace listener you should implement try/catch blocks in the Write methods to ensure that a Write attempt will never fail the host. I submitted code edits which correct object construction and makes the code more readable and less likely to fail. – Shaun Wilson Jan 24 '12 at 14:44
  • @JYL Here's [an updated link to that blog post](http://www.geertvanhorrik.com/2010/06/18/log4net-tracelistener/). However it looks like some things may have gotten lost in the move. The XML code in that post is now incorrect and the link to the Log4netTraceListener doesn't work. Hopefully the author will resurrect the code. – Jon-Eric Jan 02 '14 at 17:45
  • 4
    Is there any in built listener in log4net which can listen to trace event? – Manjay_TBAG Jun 04 '15 at 06:16
  • 4
    Take a look at the source for log4net.Util.LogLog class. This logs to Trace by default, and @Jimit is mostly right - you'll end up deadlocked if an appender error happens. In your implementation of TraceListener, I'd make sure to set log4net.Util.LogLog.EmitInternalMessages = false in the constructor of your implementation, and perhaps handle the LogLog.LogReceived event and log those messages in another way. The sad part about this is that some appender errors will not be logged due to this setting. The source is your friend here. – Steven Bone Aug 19 '15 at 12:18
  • @Jimit: In your comment you are describing my problem in the linked question https://stackoverflow.com/questions/63242160/log4nettracelistener-for-signalr-web-application-hangs But sadly I don't understand your suggestion: "...you could mitigate that by not including the TraceAppender in the appenders for logger 'System.Diagnostics.Redirection'. " – jreichert Aug 04 '20 at 07:42
26

I don't know if log4net supports this, but you could implement your own trace listener that did this.

The TraceListener doesn't have too many method that needs to be implemented and all you would do is to forward the values to log4net so this should be easy to do.

To add a custom trace listener you would either modify your app.config/web.config or you would add it in code using Trace.Listeners.Add(new Log4NetTraceListener());

Rune Grimstad
  • 35,612
  • 10
  • 61
  • 76
1

As per the answers above, there's an implementation here (this link is flaky, but I did find the source code):

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

To crudely deal with the issue (described in the comments to a previous answer) of internal log4net trace issuing from the LogLog class, I checked for this class being the source of the trace by inspecting the stack frame (which this implementation did already) and ignoring those trace messages:

    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 */
    }

Using a TraceAppender will still create the problems described in the comments above.

1

Thanks,

I went with Dirk's answer slimmed down a bit.

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);
}