Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to log to separate log file per thread using log4net

Yes this question is similar to: How to log into separate files per thread with Log4Net? except I don't know the number of threads or their names until runtime. My windows app spawns a thread per user to do long running work for that user. I want a separate log file for every user/thread.

  1. What would the log4net config file look like (if one can be used for this type of thing)?
  2. What would the code look like to use the logger?
  3. When would I call log4net.Config.XmlConfigurator.Configure()?

(Please give details on how to implement the logging.)

Here's a sample config (I can't get the thread_name property to work with multiple threads):

<log4net debug="false">
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
  <!--need to replace LogDir in code like this:  log4net.GlobalContext.Properties["LogDir"] = "c:\programdata\myapp"-->
  <file type="log4net.Util.PatternString" value="%property{LogDir}\logs\mylogfile_%property{thread_name}.log" />
  ...

And the code:

public class MyMultiThreadedClassForUsers
{
    private log4net.ILog Log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
    public void Start()
    {
        log4net.GlobalContext.Properties("LogDir") = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData)        
        log4net.Config.XmlConfigurator.Configure()

        List<IUser> users = GetAllUsersFromDB();

        foreach (IUser user in users) {
            System.Threading.Thread t = new System.Threading.Thread(CallBackMethod);
            t.Name = user.FirstName;
            t.Start();
        }
    }

    private void CallBackMethod()
    {
        // this log message should be sent to a log file named after the current thread System.Threading.Thread.CurrentThread.Name
        // Examples: mylogfile_bob.log, and mylogfile_fred.log, etc...
        Log.Info("Starting work on thread " + System.Threading.Thread.CurrentThread.Name);

        // do long running work here
    }
}

If this is not easily done with log4net I may switch logging frameworks to Nlog and use their %threadname keyword as part of the log file name which is stored in the config file.

like image 874
goku_da_master Avatar asked Mar 08 '12 18:03

goku_da_master


1 Answers

Please try this:

http://geekswithblogs.net/rgupta/archive/2009/03/03/dynamic-log-filenames-with-log4net.aspx

If you needed to generate dynamic logfile names with log4net then you can use the following config

<appender name="RollingFileAppenderV1" type="log4net.Appender.RollingFileAppender">
  <file type="log4net.Util.PatternString" value="F:\HornetFeed\%property{LogName}" />
  <appendToFile value="true" />
  <rollingStyle value="Size" />
  ...
  <filter type="log4net.Filter.PropertyFilter">
    <Key value="Version" />
    <StringToMatch value="1" />
    ...
    <= Note the "%property{LogName}" syntax

Note the %property{LogName} this is a log4net Property which we can set at runtime using C# code.

log4net.GlobalContext.Properties["LogName"] = "file1.log";

Remember to set the GlobalContext Properties before instantiating the log4net logger. i.e. before this call:

log4net.ILog log = LogManager.GetLogger(typeof(Program));

Then:

  ///Helper method to log errors:
  internal static void LogError(Exception ex)
  {
    string state = "1";
    if (log4net.ThreadContext.Properties["Version"] != null)
      state = log4net.ThreadContext.Properties["Version"].ToString();
    log4net.ThreadContext.Properties["Version"] = "0";
    logger.HandleException(ex, "Error");
    log4net.ThreadContext.Properties["Version"] = state;
  }

'Hope that helps

like image 183
paulsm4 Avatar answered Oct 10 '22 05:10

paulsm4