Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Editing Log4NET Configuration Programatically

0.00/5 (No votes)
19 Apr 2016 1  
This article and associated project demonstrate how to use XDocument to edit log4net config files.

Introduction

I have a situation where I need to output logs generated by a specific class in a separate file. And there are lot of services in which it needs to be changed across many machines. So I need a utility which can do so programmatically. We basically need to add an appender and a logger to all log4net configuration files.

I will specifically focus on how to change config files, this is part of a larger utility.

Background

The approach here is to use XML editing to change log4net logging behavior across many components. The other approach of using string manipulation does not work reliably and sometimes renders log4net config corrupted and logging fails altogether.

Using the Code

There are two input Xelements provided, the first one doesn’t exist in the source and the other one exists but with different attribute values. The output will have all the existing elements and will include the updated values provided in inputs.

XML
<logger name = "LoggerName" >

< level value="DEBUG" />

<appender-ref ref="ConsoleAppender" /></logger>

    <appender name="RollingLogFileAppender" 
    type="log4net.Appender.RollingFileAppender">
  < file value = "C:\\TestProj\\TestLog.txt" /> 
   < appendToFile value = "true" />  
    < rollingStyle value = "Size" />   
     < maxSizeRollBackups value = "10" />    
      < maximumFileSize value = "10MB" />     
       < staticLogFileName value = "true" />      
        < layout type = "log4net.Layout.PatternLayout" >       
           < conversionPattern value = "%-5p %d %5rms %-22.22c{1} %-18.18M - %m%n" />        
          </layout >
        </appender>

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

            txtInput2.Text = @"<logger name="LoggerName">
    < level value = "DEBUG" />
 
     < appender-ref ref= "RollingLogFileAppender" />
   
     </ logger >

First, we create XmlDocument from the input string. And then, we extract attributes which need to be updated.

C#
private void AppendConfigLog4net(string text1nput)
{
    text1nput = ClearTextFromInvalidChars(text1nput);

    XDocument xmlDoc1 = XDocument.Parse(text1nput, LoadOptions.None);

    foreach (var v1 in xmlDoc1.Descendants())
    {
        if (string.Compare(v1.Name.LocalName, "appender", true) == 0)
        {
            AddAndReplaceAppenderElementInExisitngConfig(v1, v1.Attribute("name").Value,
            v1.Element("file").Attribute("value").Value);
        }
        else if (string.Compare(v1.Name.LocalName, "logger", true) == 0)
        {
            AddorReplaceLoggerElementInExisitngConfig(v1, v1.Attribute("name").Value,
            v1.Element("appender-ref").Attribute("ref").Value);
        }
    }
}

Then, in the existing config file, we load in XmlDocument and replace attributes or add new element if it weren’t existing.

C#
private void AddorReplaceLoggerElementInExisitngConfig(XElement v1, string localName, string value)
{
    var query = from c in xDoc.Root.Descendants("logger")
                where (string)c.Attribute("name") == localName
                select c;
    if (query.Count() <= 0)
    {
        var v2 = xDoc.Root.Descendants("logger").LastOrDefault();
        xDoc.Root.Add(new XElement(v1));
    }
    else
        foreach (XElement node in query)
        {
            if ((string)node.Element("appender-ref").Attribute("ref") != value)
            {
                node.Element("appender-ref").Attribute("ref").Value = value;
            }
        }
}

private void AddAndReplaceAppenderElementInExisitngConfig
    (XElement xmlDoc1, string rfaAppender, string filePath)
{
    var query = from c in xDoc.Root.Descendants("appender")
                where (string)c.Attribute("name") == rfaAppender
                select c;
    if (query.Count() <= 0)
    {
        xDoc.Root.AddFirst(xmlDoc1);
    }
    else
        foreach (XElement node in query)
        {
            if ((string)node.Element("file").Attribute("value") != filePath)
            {
                node.Element("file").Attribute("value").Value = filePath;
            }
        }
}

private string ClearTextFromInvalidChars(string text1)
{
    text1 = text1.Replace(((char)0xFEFF), '\0');
    text1 = text1.Replace("< ", "<");
    text1 = text1.Replace(" >", ">");
    text1 = text1.Replace("</ ", "</");
    return text1;
}

I have attached the working project which has all the details.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here