Tuesday, December 29, 2009

Configuring Log4Net AdoNetAppender with a connection string from application configuration file

I read Ben Scheirman's "Changing log4net connection string at runtime" post and wanted to leave a comment describing solution I use to solve log4net ConnectionString configuring problem. But as I wanted to show some code, it might be better to make a blog post.

So the problem I faced with was:
How to configure log4net AdoNetAppender to use connection string specified in a <connectionStrings> section of an application configuration file?
There is no obvious way to do this in a current release of log4net. But such issue is already fixed in a log4net trunk, thus it will be possible to do so in the next release.

I don't really like to use the code which not yet officially released. So I use a simple workaround - a class inherited from AdoNetAppender with a new property ConnectionStringName. The code is pretty obvious:

using System.Configuration;

using log4net.Appender;
using log4net.Core;

/// <summary>
/// Allows to use a connection string specified in the 
/// <see cref="ConfigurationManager.ConnectionStrings"/> section of an application
/// configuration file.
/// </summary>
/// <remarks>
/// Such feature is already implemented in a log4net trunk (see
/// https://issues.apache.org/jira/browse/LOG4NET-88). But it is not yet released.
/// <para/>
/// TODO: Remove this class as soon as log4net 1.2.11 will be released.
/// </remarks>
public class Log4NetConnectionStringNameAdoNetAppender : AdoNetAppender
{
    private string connectionStringName;

    /// <summary>
    /// Gets or sets the name of the connection string from the application
    /// configuration file.
    /// </summary>
    /// <value>The name of the connection string.</value>
    public string ConnectionStringName
    {
        get
        {
            return this.connectionStringName;
        }
        
        set
        {
            this.connectionStringName = value;

            if (!string.IsNullOrEmpty(this.connectionStringName))
            {
                var settings =
                    ConfigurationManager.ConnectionStrings[this.connectionStringName];
                if (settings == null)
                {
                    string msg = string.Format(
                        "Unable to find [{0}] ConfigurationManager.ConnectionStrings item",
                        this.connectionStringName);

                    throw new LogException(msg);
                }

                this.ConnectionString = settings.ConnectionString;
            }
        }
    }
}

And the log4net configuration looks like this:
<appender name="DBAppender" type="NamespaceWhereClassLives.Log4NetConnectionStringNameAdoNetAppender,AssemblyContainingClass">
    <connectionStringName value="ConnectionStringNameFromConfigFile"/>
    <!-- Other parameters -->
</appender>
This looks like a hack, but it works for me pretty well.