Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

log4net across appdomains

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?

like image 653
Yaron Naveh Avatar asked Jul 07 '09 09:07

Yaron Naveh


People also ask

Is log4net dependent on log4j?

Log4net is a logging utility for . NET applications. It's based on log4j, which is for Java applications. Log4net is highly configurable, so you can use it in many scenarios.

How do I completely disable all logging at runtime?

How do I completely disable all logging at runtime? Setting the Threshold on the Hierarchy to Level OFF will disable all logging from that Hierarchy. This can be done in the log4net configuration file by setting the "threshold" attribute on the log4net configuration element to "OFF".

How do I use log4net net 6?

Just create a log4net. config file with a log file as an appender, then add two using statements and a single line of code to the new . NET 6 hosting model: //Program.

Is log4net thread safe?

But I thought log4net was thread-safe? Log4net is indeed thread-safe as it is clearly indicated on log4net's FAQ.


4 Answers

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" />
like image 143
Michael L Perry Avatar answered Sep 20 '22 20:09

Michael L Perry


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 LoggingEvents 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 IAppenders ...

/// <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.

like image 33
Linky Avatar answered Sep 20 '22 20:09

Linky


The logger should be initialized once per app-domain.

like image 33
Darin Dimitrov Avatar answered Sep 22 '22 20:09

Darin Dimitrov


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).

like image 25
Thomas Beck Avatar answered Sep 20 '22 20:09

Thomas Beck