在带有 log4net 的自定义 AdoNetAppender 中使用不同的 ConnectionString

Using different ConnectionString in a Custom AdoNetAppender with 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);
[...]

当我尝试 "hard code" 连接字符串进入我的配置时,它正在工作。但我不能这样做,因为我需要根据某些变量使用不同的 ConnectionString。我放在自定义附加程序中的 属性 ConnectionString 永远不会调用。知道我遗漏了什么吗?

您使用的是什么版本的 log4net?

在任何情况下,派生的 class 中的 new ConnectionString 属性 都不会从现有基础结构中自动调用。

您可以通过覆盖合适的虚拟成员获得更多成功:例如,如果您使用的是 log4net 1.2.11,则可以覆盖 CreateConnectionResolveConnectionString 方法。

更新 回复评论:

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

是的,log4net AdoNetAppender 有一个不寻常的设计,因为连接对象保持打开状态并为每个日志记录请求重用。这与通常推荐的方法形成对比,后者是 create/open 尽可能晚地建立数据库连接,并在使用后立即关闭它。推荐的方法允许应用程序利用 ADO.NET 的内置连接池。

您可以尝试的一件事是覆盖 SendBuffer(LoggingEvent[] events),并在您的覆盖中调用基础 class,然后关闭连接。这将在每次调用 SendBuffer 时强制重新打开连接。

我不确定这是否会为您提供您想要的一切 - 您谈到了使用多个连接字符串的多租户应用程序。在这种情况下,传递给 SendBufferLoggingEvent 数组可能包含应该发送到不同连接的事件。也许您需要使用 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 会在配置中抱怨未设置连接字符串值,但这并不重要,除非您打开所有异常中断,否则您可能不会注意到。