简体   繁体   English

在带有log4net的自定义AdoNetAppender中使用其他ConnectionString

[英]Using different ConnectionString in a Custom AdoNetAppender with log4net

I want to use a ConnectionString that I will define during runtime. 我想使用将在运行时定义的ConnectionString。 I found alot of example, but I can't make it work. 我找到了很多例子,但是我无法使其工作。

I created a custom AdoNetAppender: 我创建了一个自定义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: 最后,要使我的Logger进入我的代码,我正在做:

[...]    
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. 但是我不能这样做,因为我需要根据某些变量使用不同的ConnectionString。 The property ConnectionString that I put in my custom appender is just never call. 我放在自定义附加程序中的属性ConnectionString永不调用。 Any idea where i'm missing something? 你知道我在想什么吗?

What version of log4net are you using? 您正在使用哪个版本的log4net?

In any case, a new ConnectionString property in your derived class isn't going to be called automatically from the existing infrastructure. 无论如何,都不会从现有基础结构中自动调用派生类中的new ConnectionString属性。

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. 通过覆盖适当的虚拟成员,您可能会获得更大的成功:例如,如果您使用的是log4net 1.2.11,则可以覆盖CreateConnectionResolveConnectionString方法。

UPDATE in respone to comment: 更新后立即发表评论:

But the CreateConnection is only used once, so I can't use the same appender for multiple ConnectionString 但是CreateConnection仅使用一次,因此我不能对多个ConnectionString使用相同的附加程序

Yes, the log4net AdoNetAppender has an unusual design, in that a connection object is left open and reused for each logging request. 是的,log4net AdoNetAppender具有不寻常的设计,其中连接对象保持打开状态,并且可用于每个日志记录请求。 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. 推荐的方法允许应用程序利用ADO.NET的内置连接池。

One thing you could try might be to override SendBuffer(LoggingEvent[] events) , and in your override call the base class then close the connection. 您可以尝试做的一件事是重写SendBuffer(LoggingEvent[] events) ,然后在您的重写调用基类中关闭连接。 This will force the connection to be reopened each time SendBuffer is called. 每次调用SendBuffer这将强制重新打开连接。

I'm not sure if this will give you everything you want though - you talk of a Multitenant application using multiple connection strings. 我不确定这是否会给您所需的一切-您谈到使用多个连接字符串的Multitenant应用程序。 In this case the array of LoggingEvent passed to SendBuffer may contain events that should be sent to different connections. 在这种情况下,传递给SendBufferLoggingEvent数组可能包含应发送到不同连接的事件。 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. 也许您需要使用LoggingEvent某些属性按目标连接拆分输入数组,然后对于每个目标连接,打开连接,调用base.SendBuffer然后关闭连接。

This will work on an existing AdoNetAppender: 这将在现有的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. 请注意,AdoNetAppender将在配置中抱怨未设置连接字符串值,但这并不重要,除非您打开所有异常,否则您可能不会注意到。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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