Использование различных ConnectionString в пользовательском AdoNetAppender с log4net

Я хочу использовать ConnectionString, которую я определю во время выполнения. Я нашел много примеров, но я не могу заставить его работать.

Я создал собственный AdoNetAppender:

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

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

У меня есть следующая конфигурация:

<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>

мой регистратор определяется как это в файле конфигурации:

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

И наконец, чтобы получить мой Logger на мой код, я делаю:

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

Когда я пытаюсь "жестко кодировать" строку подключения в моей конфигурации, это работает. Но я не могу этого сделать, потому что мне нужна другая ConnectionString в зависимости от некоторых переменных. Свойство ConnectionString, которое я добавляю в свой пользовательский appender, просто никогда не вызывается. Есть идеи, где я что-то упускаю?

2 ответа

Решение

Какую версию log4net вы используете?

В любом случае, new Свойство ConnectionString в вашем производном классе не будет вызываться автоматически из существующей инфраструктуры.

Вы можете добиться большего успеха, переопределив подходящий виртуальный элемент: например, если вы используете log4net 1.2.11, вы можете переопределить CreateConnection или же ResolveConnectionString метод.

ОБНОВЛЕНИЕ в ответ на комментарий:

Но CreateConnection используется только один раз, поэтому я не могу использовать один и тот же appender для нескольких ConnectionString

Да, лог4нет AdoNetAppender имеет необычный дизайн, в котором объект соединения остается открытым и повторно используется для каждого запроса на регистрацию. В отличие от обычного рекомендуемого подхода, который заключается в создании / открытии соединения БД как можно позже и закрытии его сразу после использования. Рекомендуемый подход позволяет приложению использовать преимущества встроенного пула соединений ADO.NET.

Одна вещь, которую вы могли бы попробовать, может быть переопределить SendBuffer(LoggingEvent[] events)и в вашем переопределении вызовите базовый класс, а затем закройте соединение. Это заставит соединение открываться каждый раз SendBuffer называется.

Хотя я не уверен, что это даст вам все, что вы хотите - вы говорите о приложении Multitenant, использующем несколько строк подключения. В этом случае массив LoggingEvent перешел к SendBuffer может содержать события, которые должны быть отправлены на разные соединения. Возможно, вам нужно будет использовать какой-то атрибут LoggingEvent разделить входной массив по целевому соединению, затем для каждого целевого соединения открыть соединение, вызвать base.SendBuffer затем закройте соединение.

Это будет работать на существующем 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();
}

Обратите внимание, что AdoNetAppender будет жаловаться на конфигурацию, что значение строки подключения не было задано, но это не имеет значения, и вы, вероятно, в любом случае не заметите, если не включите разрыв всех исключений.

Другие вопросы по тегам