Uncategorized

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