跨appdomains的log4net

跨appdomains的log4net,log4net,appdomain,Log4net,Appdomain,我有一个从一个appdomain初始化log4net的应用程序,需要在另一个appdomain中使用它。支持吗 如果不是,我应该从每个appdomain初始化log4net吗?在同一应用程序中多次初始化是否存在风险?我应该使用相同的log4net.config吗?记录器应该在每个应用程序域初始化一次。同意darin的意见,每个应用程序域初始化一次。如果您希望这些应用程序使用合并日志记录,那么您需要选择一个不会引起争用的日志记录目标(即不是FileAppender或RollingFileAppen

我有一个从一个appdomain初始化log4net的应用程序,需要在另一个appdomain中使用它。支持吗


如果不是,我应该从每个appdomain初始化log4net吗?在同一应用程序中多次初始化是否存在风险?我应该使用相同的log4net.config吗?

记录器应该在每个应用程序域初始化一次。

同意darin的意见,每个应用程序域初始化一次。如果您希望这些应用程序使用合并日志记录,那么您需要选择一个不会引起争用的日志记录目标(即不是FileAppender或RollingFileAppender)。

邮件列表中有一个与RollingFileAppender一起使用的答案。将以下行添加到log4net.config中的appender:

<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />

尽管这个问题已经提出了好几年了,但它可能对某些人有所帮助:

可以使用在父AppDomain中配置的记录器。 需要做的是将
LoggingEvent
s从子AppDomain路由到父AppDomain。为此,您需要创建一个自定义附加器,将记录转发出子域

/// <summary>
/// Represents an <see cref="IAppender"/> implementation that forwards a <see cref="LoggingEvent"/> to a given Receiver.
/// Instances of this class should be created in the child domain.
/// </summary>
public class CrossDomainOutboundAppender : AppenderSkeleton
{
    private readonly CrossDomainParentAppender crossDomainParentAppender;
    public CrossDomainOutboundAppender(CrossDomainParentAppender crossDomainParentAppender)
    {
        if (crossDomainParentAppender == null)
        {
            throw new ArgumentNullException("crossDomainParentAppender");
        }
        this.crossDomainParentAppender = crossDomainParentAppender;

    }

    protected override void Append(LoggingEvent loggingEvent)
    {
        LoggingEvent copied = new LoggingEvent(loggingEvent.GetLoggingEventData());
        crossDomainParentAppender.Append(copied);
    }
}
最后是一个将两者联系起来并配置log4net的设置类:

public class CrossDomainChildLoggingSetup : MarshalByRefObject
{
    private CrossDomainParentAppender parentAppender;

    public void ConfigureAppender(CrossDomainParentAppender crossDomainParentAppender)
    {
       parentAppender = crossDomainParentAppender;
       CrossDomainOutboundAppender outboundAppender = new CrossDomainOutboundAppender(parentAppender);
       log4net.Config.BasicConfigurator.Configure(outboundAppender);
    }
}
现在-设置AppDomain时,可以添加以下代码

CrossDomainParentAppender crossDomainParentAppender = new CrossDomainParentAppender();
Type crossDomainType = typeof(CrossDomainChildLoggingSetup);
CrossDomainChildLoggingSetup crossDomainChildLoggingSetup = (CrossDomainChildLoggingSetup)domain.CreateInstanceFrom(crossDomainType.Assembly.Location, crossDomainType.FullName).Unwrap();
crossDomainChildLoggingSetup.ConfigureAppender(crossDomainParentAppender);
…并且在子域中记录的所有内容都会出现在父域日志中。 (请注意:我使用了
CreateInstaceFrom(assemblyFilePath,…)
-根据您的设置,您可能不需要按filePath加载)


虽然我没有发现任何bug或问题:如果您看到任何可能出现的缺陷或问题,请告诉我。

我的答案补充了Linky的答案

回答杰克·艾伦的问题。您可以通过解决以下问题来解决此问题:更改CrossDomainOutboundAppender类:

/// <summary>
/// Represents an <see cref="IAppender"/> implementation that forwards a <see cref="LoggingEvent"/> to a given Receiver.
/// Instances of this class should be created in the child domain.
/// </summary>
public class CrossDomainOutboundAppender : AppenderSkeleton
{
    private readonly CrossDomainParentAppender crossDomainParentAppender;
    public CrossDomainOutboundAppender(CrossDomainParentAppender crossDomainParentAppender)
    {
        if (crossDomainParentAppender == null)
        {
            throw new ArgumentNullException("crossDomainParentAppender");
        }
        this.crossDomainParentAppender = crossDomainParentAppender;

    }

    protected override void Append(LoggingEvent loggingEvent)
    {
        LoggingEvent copied = new LoggingEvent(loggingEvent.GetLoggingEventData(FixFlags.All));
        crossDomainParentAppender.Append(copied);
    }
}
//
///表示将消息转发给给定接收器的实现。
///此类的实例应在子域中创建。
/// 
公共类CrossDomainOutboundAppender:AppenderSkleton
{
私有只读CrossDomainParentAppender CrossDomainParentAppender;
公共CrossDomainOutboundAppender(CrossDomainParentAppender CrossDomainParentAppender)
{
if(crossDomainParentAppender==null)
{
抛出新ArgumentNullException(“crossDomainParentAppender”);
}
this.crossDomainParentAppender=crossDomainParentAppender;
}
受保护的覆盖无效附加(LoggingEvent LoggingEvent)
{
LoggingEvent copied=新的LoggingEvent(LoggingEvent.GetLoggingEventData(FixFlags.All));
crossDomainParentAppender.Append(已复制);
}
}
注意FixFlags。所有

当前版本的。。。。有一个导致所有附加器记录消息的缺陷,这就像破坏log4net的目的一样,因为不同的记录器可以在不同的级别进行记录。我的课程改进版:

/// <summary>
/// Represents a Receiver that sends Log4Nets <see cref="LoggingEvent"/> to all available <see cref="IAppender"/>s.
/// Instances of this class should be created in the ParentDomain.
/// </summary>
[Serializable]
public class CrossDomainParentAppender : MarshalByRefObject
{
    public void Append(LoggingEvent loggingEvent)
    {
        LogManager.GetRepository().Log(loggingEvent);
    }
}
//
///表示将Log4Nets发送到所有可用s的接收器。
///此类的实例应在ParentDomain中创建。
/// 
[可序列化]
公共类CrossDomainParentAppender:MarshalByRefObject
{
公共作废附加(LoggingEvent LoggingEvent)
{
LogManager.GetRepository().Log(loggingEvent);
}
}

这会将日志分发给logmanager,这将找出日志的放置位置、由哪个记录器负责等。

正是我所寻找的方法类型。谢谢。如果我可以建议改进的话-而不是BasicConfigurator.Configure(outputAppender),更改为以下内容以选择父域配置:var hierarchy=(hierarchy)LogManager.GetRepository();hierarchy.Root.AddAppender(outboundAppender);hierarchy.Configured=true;使用此选项时,您是否遇到远程处理异常?我会得到一个异常,说“Object'/a0720457_c9e6_4edf_bde5_86d96058cb4e/+mauadzsfpiaad3bjv4uss_264.rem'已断开连接或在服务器上不存在。”我认为这是因为垃圾收集。有没有办法解决这个问题?我想出来了。我重写了CrossDomainChildLoggingSetup.InitializeLifetimeService以返回null,因为每个应用程序域只有一个,并且在卸载AppDomain时会被清除。然后,我实现了ISponsor来处理CrossDomainParentAppender的生存期,并使用以下代码对其进行初始化:var-shandor=new-MySponsor(this,k);var lease=(ILease)RemotingServices.GetLifetimeService(crossDomainParentAppender);租赁、登记(发起人);这很好,但似乎在日志中丢失了方法名称,只是显示?相反,当两个记录器试图附加到同一个文件时,它不会导致锁问题吗?
/// <summary>
/// Represents a Receiver that sends Log4Nets <see cref="LoggingEvent"/> to all available <see cref="IAppender"/>s.
/// Instances of this class should be created in the ParentDomain.
/// </summary>
[Serializable]
public class CrossDomainParentAppender : MarshalByRefObject
{
    public void Append(LoggingEvent loggingEvent)
    {
        LogManager.GetRepository().Log(loggingEvent);
    }
}