Dynamic Log4Net Filename

Where I am working now we use Log4Net for our logging, where we usually configure it using
a custom Log4Net> config section in our App.Config something like this. 

 

<?xml version="1.0"?>
<configuration>
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
  </configSections>

  <log4net>
    <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
      <file  value="C:\Temp\SomeLogFile.log" />
      <appendToFile value="true" />
      <maxSizeRollBackups value="10" />
      <maximumFileSize value="10485760" />
      <rollingStyle value="Size" />
      <staticLogFileName value="true" />
      <layout type="log4net.Layout.PatternLayout">
        <header value="[Header]
"/>
        <footer value="[Footer]
"/>
        <conversionPattern value="%date [%thread] %-5level %logger [%ndc] - %message%newline" />
      </layout>
    </appender>

    <root>
      <level value="ALL" />
      <appender-ref ref="RollingLogFileAppender" />

    </root>

  </log4net>

</configuration>

Ok this could be done in code, but its just more convenient for me to do this in XML in the config file, so lets assume you too would use a App.Config to configure your installation of Log4Net

 


Which works fine. You may note that the file elements value is hardcoded to C:\Temp\SomeLogFile.log, which means the logging file
will be stored at “C:\Temp\SomeLogFile.log”. That’s fine.

However the other day we needed to have a dynamically created Log4Net filename
depending on a variable. This variable for us was a command line argument. It took me a little while to figure out how to get Log4Net
to create a filename of my choosing. We even had to delve into how the XmlConfigurator that I would normally use works, such that we could do what it does, but only after we had changed the name of the FileAppender file name. I admit we did have to use a .NET Decompiler to get on our way

The basic idea is as follows (NOTE this is the 1st thing we do before we use the Logger this MUST be done)

  • Change the App.Config FileAppender file element value attribute to a string value that will be replaced
  • Get the current Log4Net repository, which will will configure later
  • Look for all FileAppenders, and grab the file element value attribute to a string value and change it to desired value
  • Now tell the current Log4Net repository to configure itself using our in memory modified XML data

This may sound confusing, but its quite ok once you see the code, which is as shown below

App.Config

<?xml version="1.0"?>
<configuration>
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
  </configSections>

  <log4net>
    <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
      <file  value="C:\Temp\{0}.log" />
      <appendToFile value="true" />
      <maxSizeRollBackups value="10" />
      <maximumFileSize value="10485760" />
      <rollingStyle value="Size" />
      <staticLogFileName value="true" />
      <layout type="log4net.Layout.PatternLayout">
        <header value="[Header]
"/>
        <footer value="[Footer]
"/>
        <conversionPattern value="%date [%thread] %-5level %logger [%ndc] - %message%newline" />
      </layout>
    </appender>

    <root>
      <level value="ALL" />
      <appender-ref ref="RollingLogFileAppender" />

    </root>

  </log4net>

</configuration>

Code That is Run 1st Thing

namespace Demo
{
    public static class Program
    {

        private static void ChangeLogFileName(string name)
        {
            log4net.Repository.ILoggerRepository RootRep;
            RootRep = LogManager.GetRepository(Assembly.GetCallingAssembly());

            XmlElement section = ConfigurationManager.GetSection("log4net") as XmlElement;

            XPathNavigator navigator = section.CreateNavigator();
            XPathNodeIterator nodes = navigator.Select("appender/file");
            foreach (XPathNavigator appender in nodes)
            {
                appender.MoveToAttribute("value", string.Empty);
                appender.SetValue(string.Format(appender.Value, name));
            }

            IXmlRepositoryConfigurator xmlCon = RootRep as IXmlRepositoryConfigurator;
            xmlCon.Configure(section);
        }

        [STAThread]
        public static void Main(string[] args)
        {

	    ChangeLogFileName("error");

            if (args.Length != 1)
            {
                ChangeLogFileName("error");
                PopProcessor.Logger.Error("Error starting invalid command line arguments");
                Environment.Exit(-1);
            }

            ChangeLogFileName(args[0]);
	    ....
	    ....
	    ....
	    ....
	    ....

        }
    }
}

Hope that helps you out somehow…Enjoy

Advertisements

7 thoughts on “Dynamic Log4Net Filename

  1. simon whale says:

    Oh yes Sacha

    That helps me out as I have to add a converting console application to my current project and the ability of being able to log to different files is fantastic news

    Thanks
    Simon

  2. sachabarber says:

    Cool glad it helped you out

  3. aarty says:

    Worked great for me. Thanks.

    Only thing that was a bit annoying was that I had to look up where to locate some of the classes you reference, since you haven’t included your “using” statements at the top. Maybe you can include them, or just fully qualify all of your class names?

    Either way, thanks a lot for the help!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: