Modify Log4Net AdoNetAppender Connection String at run-time

Log4Net

In my every day development I always have to figure out ways to keep my connection information in sync with the environment my application is deployed to.  We currently go through 3 environments; Dev, Test, and Production.  Each with a different set of database and service connections.  Today I was working on setting up Log4Net to use the AdoNetAppender and wanted to have it’s connection string move with my ApplicationSettings so that it would point to the appropriate database for the environment.  After about 3 hours of searching and code pounding I came up with a solution and since it was so hard to find I wanted to share what I learned.

First a little background of how my application is setup.  I have created the following application settings;

  • RunEnvironment: used to show where we are deployed, valid values are Development, Test, or Production
  • Database_Development: stores the database connection for development
  • Database_Test: stores the database connection for test
  • Database_Production: stores the database connection for Production

I also have a static ApplicationSettings class like this:

   1:  using System.Collections.Specialized;      
   2:  using System.Configuration;      
   3:   
   4:  public static class ApplicationSettings
   5:  {
   6:      private static readonly NameValueCollection Settings = ConfigurationManager.AppSettings;
   7:   
   8:      public static string RunEnvironment
   9:      {
  10:          get { return Settings["RunEnvironment"]; }
  11:      }
  12:      
  13:      public static string DatabaseConnectionString
  14:      {
  15:          get { return Settings["Database_" + RunEnvironment]; }
  16:      }
  17:  }

This approach allows me to just ask ApplicationSettings for the DatabaseConnectionString and it is always adjusted for the correct RunEnvironment.

Ok, so now to the Log4Net goodness.  I used the XML Configuration in my app.config to configure Log4Net and tried several ways to get the currently active configuration and manipulate it to reflect the new database connection string.  The solution that finally worked was to implement my own AdoNetAppender derived from the AdoNetAppender and override the ConnectionString Property.

Here is the new CustomAdoNetAppender class:

   1:  using log4net.Appender;
   2:   
   3:  public class CustomAdoNetAppender : AdoNetAppender
   4:  {
   5:      public new string ConnectionString
   6:      {
   7:          get
   8:          {
   9:              return base.ConnectionString;
  10:          }
  11:          set
  12:          {
  13:              base.ConnectionString = ApplicationSettings.DatabaseConnectionString;
  14:          }
  15:      }
  16:  }

 

The next step, which was left out of many of the post regarding this matter, was to modify the Log4Net configuration in your app/web.config to use the new CustomAdoNetAppender like below:

This must be added to the Configuration->ConfigSections of you config file

<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />

After the Configuration->ConfigSections and at the same level in your config file add the Log4Net

   1:  <log4net>
   2:      <appender name="CustomAdoNetAppender" type="MyCustomNamespace.CustomAdoNetAppender">
   3:        <bufferSize value="100" />
   4:        <connectionType value="System.Data.SqlClient.SqlConnection, System.Data,  />
   5:        Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
   6:        <connectionString value="data source=[DbServer];initial catalog=[DbName]; />
   7:        integrated security=false;persist security info=True;User ID=[DB_USER];Password=[DB_PASS]"
   8:        <commandText value="INSERT INTO Log ([Date],[Thread],[Level],[Logger],[Message],[Exception])  />
   9:        VALUES (@log_date, @thread, @log_level, @logger, @message, @exception)"
  10:        <parameter>
  11:          <parameterName value="@log_date" />
  12:          <dbType value="DateTime" />
  13:          <layout type="log4net.Layout.RawTimeStampLayout" />
  14:        </parameter>
  15:        <parameter>
  16:          <parameterName value="@thread" />
  17:          <dbType value="String" />
  18:          <size value="255" />
  19:          <layout type="log4net.Layout.PatternLayout">
  20:            <conversionPattern value="%thread" />
  21:          </layout>
  22:        </parameter>
  23:        <parameter>
  24:          <parameterName value="@log_level" />
  25:          <dbType value="String" />
  26:          <size value="50" />
  27:          <layout type="log4net.Layout.PatternLayout">
  28:            <conversionPattern value="%level" />
  29:          </layout>
  30:        </parameter>
  31:        <parameter>
  32:          <parameterName value="@logger" />
  33:          <dbType value="String" />
  34:          <size value="255" />
  35:          <layout type="log4net.Layout.PatternLayout">
  36:            <conversionPattern value="%logger" />
  37:          </layout>
  38:        </parameter>
  39:        <parameter>
  40:          <parameterName value="@message" />
  41:          <dbType value="String" />
  42:          <size value="4000" />
  43:          <layout type="log4net.Layout.PatternLayout">
  44:            <conversionPattern value="%message" />
  45:          </layout>
  46:        </parameter>
  47:        <parameter>
  48:          <parameterName value="@exception" />
  49:          <dbType value="String" />
  50:          <size value="2000" />
  51:          <layout type="log4net.Layout.ExceptionLayout" />
  52:        </parameter>
  53:      </appender>
  54:      <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender" >
  55:        <layout type="log4net.Layout.PatternLayout">
  56:          <param name="Header" value="[Header]\r\n" />
  57:          <param name="Footer" value="[Footer]\r\n" />
  58:          <param name="ConversionPattern" value="%d [%t] %-5p %m%n" />
  59:        </layout>
  60:      </appender>
  61:      <root>
  62:        <level value="DEBUG" />
  63:        <appender-ref ref="CustomAdoNetAppender" />
  64:        <appender-ref ref="ConsoleAppender" />
  65:      </root>
  66:    </log4net>

You can see on line 2 that we specified our new CustomAdoNetAppender as the name and pointed the type to MyCustomNamespace.CustomAdoNetAppender.  This tells Log4Net what class to use and where to find it.

Now you have a Custom AdoNetAppender that gets the database connection from your application settings at run-time.

blog comments powered by Disqus

Calendar

<<  October 2014  >>
MonTueWedThuFriSatSun
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789

View posts in large calendar

Month List

AuthorList