我有一个应用程序,它从一个 appdomain 初始化 log4net,并需要在另一个 appdomain 中使用它。是否支持?
如果不是,我应该从每个 appdomain 初始化 log4net 吗?在同一个应用程序中进行多次初始化是否存在风险?我应该使用相同的 log4net.config 吗?
log4net-user邮件列表有一个适用于 RollingFileAppender 的答案。将以下行添加到 log4net.config 中的 appender:
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
虽然这个问题已经有好几年了 - 也许它可以帮助某人:
可以使用在父 AppDomain 中配置的记录器。需要做的是将LoggingEvent
s从子AppDomain路由到父AppDomain。为此,您需要创建一个自定义 Appender,将记录转发出子域...
/// <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);
}
}
,一个自定义类,接收转发的 LoggingEvent 并将它们附加到可用IAppender
的 s ...
/// <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)
{
foreach (IAppender usedAppender in LogManager.GetRepository().GetAppenders())
{
usedAppender.DoAppend(loggingEvent);
}
}
}
最后是一个将两者联系起来并配置 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 加载)
虽然我没有发现任何错误或问题:如果您发现任何可能出现的缺陷或问题,请告诉我。
记录器应在每个应用程序域中初始化一次。
同意darin,每个应用程序域一次。如果您希望这些应用程序使用合并日志记录,您将需要选择不会受到争用的日志记录目标(即不是 FileAppender 或 RollingFileAppender)。
我的回答增加了 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);
}
}
注意 FixFlags.All
当前版本的 .... 有一个缺陷导致所有附加程序记录消息,这就像破坏了 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);
}
}
这会将日志分发给日志管理器,这将找出日志的放置位置、负责的记录器等。