28

Description

I have a config file as a resource in my assembly and want to change the ConnectionString programmatically in my application.

I load the configuration using log4net.Config.XmlConfigurator.Configure.

I have some breakpoints and see that the configuration is loaded successfuly and the connectionstring is Data Source=localhost\SQLExpress;Initial Catalog=Log;Integrated Security=SSPI; (local SQLExpress).

Problem

Nothing happens, no exception and no log entry. Any ideas.

using (Stream stream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("MyNamespace.Properties.log4net.config"))
{ 
    // stream is NOT null
    log4net.Config.XmlConfigurator.Configure(stream);
}

Hierarchy hier = LogManager.GetRepository() as Hierarchy;

if (hier != null)
{
    //get ADONetAppender
    var adoAppender = (AdoNetAppender)hier.GetAppenders().Where(appender => appender.Name.Equals("AdoNetAppender", StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault();

    if (adoAppender != null)
    {
        // update connectionstring
        adoAppender.ConnectionString = configuration.GetConnectionString(ConnectionStringNames.Log).ConnectionString;
        //refresh settings of appender
        adoAppender.ActivateOptions(); 
    }
}

ILog logger = LogManager.GetLogger("MyProject"); 
logger.Warn("Test");

content of the log4net.config file

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

  <log4net>
    <appender name="AdoNetAppender" type="log4net.Appender.ADONetAppender">
      <bufferSize value="1" />
      <connectionType value="System.Data.SqlClient.SqlConnection, System.Data,
  Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
      <connectionString value="[we will set this automatically at runtime]" />
      <commandText value="INSERT INTO Log ([Date],[Level],[Logger],[Message],[Exception])
  VALUES (@log_date, @log_level, @logger, @message, @exception)" />
      <parameter>
        <parameterName value="@log_date" />
        <dbType value="DateTime" />
        <layout type="log4net.Layout.RawTimeStampLayout" />
      </parameter>
      <parameter>
        <parameterName value="@log_level" />
        <dbType value="String" />
        <size value="50" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%p" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@logger" />
        <dbType value="String" />
        <size value="255" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%c" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@message" />
        <dbType value="String" />
        <size value="4000" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%m" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@exception" />
        <dbType value="String" />
        <size value="2000" />
        <layout type="log4net.Layout.ExceptionLayout" />
      </parameter>
    </appender>

    <root>
      <level value="ALL" />
      <appender-ref ref="AdoNetAppender" />
    </root>
  </log4net>
</configuration>
Dominic Zukiewicz
  • 8,258
  • 8
  • 43
  • 61
dknaack
  • 60,192
  • 27
  • 155
  • 202
  • Total side-note, but isn't it a lot better for the config file to exist side-by-side with your assembly, rather than being baked in? After all, the main reason it's in a config file (and not defined in C# code) is so you can tweak it without recompiling your app. – Kirk Woll May 31 '12 at 13:51
  • In general, yes. But in my situation, i need it from a resource. – dknaack May 31 '12 at 13:55

3 Answers3

75

You can debug log4net by hooking into the log4net DebugAppender:

Add a log4net app setting in your app.config file:

<appSettings>
  <!-- log4net configuration when running in debug mode. -->    
  <add key="log4net.Internal.Debug" value="true" />   
</appSettings>

Add a debug appender in the log4net config:

<appender name="DebugAppender" type="log4net.Appender.DebugAppender">
  <immediateFlush value="true" />
  <layout type="log4net.Layout.SimpleLayout" />
</appender>

Add the appender to the log4net config root:

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

When you run your application, look in the output window of Visual Studio and you should see all the internal logging for log4net. If not, then the log4net config file is never loading.

Edit

If you can use a connection string from your app.config file, then remove the connection string from the log4net AdoNetAppender and just call the connection string by name:

<appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
  <bufferSize value="1" />
  <!-- note: you can use the 4.0 assembly -->
  <connectionType value="System.Data.SqlClient.SqlConnection,
              System.Data, 
              Version=4.0.0.0, 
              Culture=neutral, 
              PublicKeyToken=b77a5c561934e089" />
  <!-- This will retrieve a connection string by name from the app.config -->
  <connectionStringName value="ConnectionStringNameFromAppConfig" />
  <!-- snip -->
</appender>
Dominic Zukiewicz
  • 8,258
  • 8
  • 43
  • 61
Metro Smurf
  • 37,266
  • 20
  • 108
  • 140
  • Thank you, the exception is that log4net cant connect the database with the connectionstring "[we will set this automatically at runtime]". Thats ok, i change the connectionstring in code. Any other idea ? – dknaack May 31 '12 at 14:22
  • Are you using the same connection string that is defined in the app.config file? And is the actual error from the output window: "log4net cant connect the database with the connectionstring '[we will set this automatically at runtime]'"? – Metro Smurf May 31 '12 at 14:26
  • this message comes before i call the first `Warn` message. – dknaack May 31 '12 at 14:38
  • You say that you change the connection string in code/runtime, but the log4net debugger is clearly stating that it can not connect to the database with a connection string of "we will set this automatically at runtime". Are there any errors after the first Warn message? – Metro Smurf May 31 '12 at 14:48
  • The message comes on `log4net.Config.XmlConfigurator.Configure`, after this no other messages comes. – dknaack May 31 '12 at 14:57
  • 1
    See my edit for using a connection string by name from the app.config. If that is not an option, then try hard-coding the connection string in the log4net config file to verify the connection is working correctly, if it is, then there is something wrong with how the connection string is being updated in code. – Metro Smurf May 31 '12 at 15:09
  • 3
    Highly useful answer; excellent instructions, and works great. – Shawn J. Molloy Jun 19 '13 at 00:39
  • 1
    I have tried a hand full of other debugging steps others have mentioned, this is the only one that allowed me to see what i needed to see :) forgot to set me ID column as an Identity :( there went my morning lol. Thanks!! – Tony Sep 24 '13 at 16:39
  • 1
    Plus 1 for the DebugAppender – Johnie Karr Aug 13 '15 at 14:51
  • I've done all of this and I'm not getting any feedback from the debugAppender. I am calling Log.error("write this error"); and that writes to the output window but i still get nothing in the sql table. any ideas? – Moi Hawk Apr 04 '19 at 19:44
21

Here are some things that I tried that worked out for me...

  • I wasn't seeing anything because my <appender-ref ref="AdoNetAppender" /> didn't properly reference my <appender name="AdoNetAppender" ... /> in the Web.config. The 'AdoNetAppender' names need to match.

  • Added <bufferSize value="1" /> to the <appender name="AdoNetAppender" /> section of the Web.config

  • I created a user account with a password on the SQL server instead of using windows authentication. Granted user access to perform selects and inserts on the table

  • In Global.asax.cs I initialize log4net using log4net.Config.XmlConfigurator.Configure();

  • In my C# code I instantiate a new adoAppender object and call logger.Info("save to db");

The documentation on Apache's website is helpful as well ... http://logging.apache.org/log4net/release/config-examples.html#MS%20SQL%20Server

Hope that saves somebody some time and frustration. Thanks!

Robert Bolton
  • 667
  • 3
  • 8
  • 22
  • 7
    Your second point (buffer size) was the key for me. My bufferSize was 100, and so I was not seeing any output for a few minutes and assumed it was not working. Thanks. – Whatever Man May 22 '15 at 14:34
  • 4
    Buffer size did it for me too. The documentation of config files by log4net really lacks... – Alexander Derck Dec 23 '15 at 13:16
  • 3
    Here is the documentation for [BufferSize](https://logging.apache.org/log4net/log4net-1.2.13/release/sdk/log4net.Appender.BufferingAppenderSkeleton.BufferSize.html). – techvice May 24 '16 at 21:48
  • 1
    I tried everything until I found the buffer size was preventing the database write for a long time. Thanks for pointing out this – Maximiliano Rios Jul 03 '16 at 16:11
0

I had a log4net configuration running for years, that stopped logging to database this spring 2022. I solved it by specifying: size value="7" to a DateTime2 database parameter in the log4net configuration. Type in database: datetime2(7), not null. Why size on that type suddenly is madatory in log4net I don't know.