简体   繁体   中英

Using different ConnectionString in a Custom AdoNetAppender with log4net

I want to use a ConnectionString that I will define during runtime. I found alot of example, but I can't make it work.

I created a custom AdoNetAppender:

 public class AdoNetMultiTenantAppender : AdoNetAppender
{
    public new string ConnectionString
    {
        get
        {
            return base.ConnectionString;
        }

        set
        {
            base.ConnectionString = Tenant.Current.DataSource.ConnectionString; // Return the connection string
        }
    }
}

I have the following configuration:

<appender name="AdoNetMultiTenantAppender" type="MyNameSpace.AdoNetMultiTenantAppender">
    <bufferSize value="1" />
    <connectionstring value="" />
    <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
    <commandText value="[...]" />
    <parameter>
        [...]
    </parameter>
</appender>

my logger is define like this in the config file:

  <logger name="ProcessLogger" additivity="false">
    <level value="INFO"/>
    <appender-ref ref="AdoNetMultiTenantAppender"/>
  </logger>

And finally, to get my Logger on my code i'm doing:

[...]    
private static readonly ILog Logger = LogManager.GetLogger("ProcessLogger");
[...]
ProcessLogger.Logger.Info(message);
[...]

When i'm trying to "hard code" the Connection string into my config it's working. But I can't do this because I need a different ConnectionString depending on some variables. The property ConnectionString that I put in my custom appender is just never call. Any idea where i'm missing something?

What version of log4net are you using?

In any case, a new ConnectionString property in your derived class isn't going to be called automatically from the existing infrastructure.

You might have more success by overriding a suitable virtual member: for example, if you're using log4net 1.2.11 you could override the CreateConnection or ResolveConnectionString method.

UPDATE in respone to comment:

But the CreateConnection is only used once, so I can't use the same appender for multiple ConnectionString

Yes, the log4net AdoNetAppender has an unusual design, in that a connection object is left open and reused for each logging request. The contrasts with the usual recommended approach, which is to create/open a db connection as late as possible, and close it immediately after use. The recommended approach allows an application to take advantage for ADO.NET's built-in connection pooling.

One thing you could try might be to override SendBuffer(LoggingEvent[] events) , and in your override call the base class then close the connection. This will force the connection to be reopened each time SendBuffer is called.

I'm not sure if this will give you everything you want though - you talk of a Multitenant application using multiple connection strings. In this case the array of LoggingEvent passed to SendBuffer may contain events that should be sent to different connections. Perhaps you would need to use some attribute of LoggingEvent to split the input array by target connection, then for each target connection, open the connection, call base.SendBuffer then close the connection.

This will work on an existing AdoNetAppender:

public static void SetConnectionString(string connectionString)
{
    Hierarchy logHierarchy = log4net.LogManager.GetRepository() as Hierarchy;

    if (logHierarchy == null)
    {
        throw new InvalidOperationException("Can't set connection string as hierarchy is null. Has logging been initialised?");
    }

    // Assumes there is only one appender to be configured
    var appender = logHierarchy.GetAppenders().OfType<AdoNetAppender>().SingleOrDefault();

    if (appender == null)
    {
        throw new InvalidOperationException("Can't set connection string as can't locate a database appender");
    }

    appender.ConnectionString = connectionString;
    appender.ActivateOptions();
}

Note that the AdoNetAppender will complain on configuration that the connection string value has not been set, but it doesn't matter, and you probably won't notice anyway unless you turn on breaking on all exceptions.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM