问题
I have an application which initializes log4net from one appdomain and needs to use it in another appdomain. Is it supported?
If not, should I initialize log4net from each appdomain? Is there a risk in multiple initializations in the same application? Should I use the same log4net.config?
回答1:
The log4net-user mailing list has an answer that works with RollingFileAppender. Add the following line to the appender in log4net.config:
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
回答2:
Although the question is several years old - maybe it helps someone:
It is possible to use the loggers configured in the parent AppDomain.
What needs to be done is route the LoggingEvent
s from the child AppDomain to the parent AppDomain. For this you need to create a custom Appender that forwards the records out of the Child domain...
/// <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);
}
}
, a custom class that receives the forwarded LoggingEvent and appends them to available 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);
}
}
}
and finally a setup class that ties the two and configures 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);
}
}
Now - when you setup up your AppDomain you can add the following code...
CrossDomainParentAppender crossDomainParentAppender = new CrossDomainParentAppender();
Type crossDomainType = typeof(CrossDomainChildLoggingSetup);
CrossDomainChildLoggingSetup crossDomainChildLoggingSetup = (CrossDomainChildLoggingSetup)domain.CreateInstanceFrom(crossDomainType.Assembly.Location, crossDomainType.FullName).Unwrap();
crossDomainChildLoggingSetup.ConfigureAppender(crossDomainParentAppender);
...and everything logged in the child domain turns up in the parent domains log.
(Please note: I used CreateInstaceFrom(assemblyFilePath,...)
- depending on your setup you may not require loading by filePath)
Although I haven't found any bugs or problems: If you see any flaws or problems that could arise please let me know.
回答3:
The logger should be initialized once per app-domain.
回答4:
Agree with darin, once per app domain. If you're looking to have these applications use consolidated logging, you'll want to choose a logging target that won't be subject to contention (i.e. not FileAppender or RollingFileAppender).
回答5:
My answer adds to Linky 's answer.
To answer, Jack Allan 's question. You can solve this by solving the changing the CrossDomainOutboundAppender class:
/// <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);
}
}
Notice the FixFlags.All
The current version of the .... has a flaw causing all appenders to log the message, thats like defeating the purpose of log4net, since different loggers can log at a different level for example. My improved version of the class:
/// <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);
}
}
This distributes the log to the logmanager, this will find out where to place the log, which logger is responsible etc.
来源:https://stackoverflow.com/questions/1091223/log4net-across-appdomains