Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you configure and enable log4net for a stand-alone class library assembly?

Tags:

c#

.net

log4net

Background

I am writing a class library assembly in C# .NET 3.5 which is used for integration with other applications including third-party Commercial-Off-The-Shelf (COTS) tools. Therefore, sometimes this class library will be called by applications (EXEs) that I control while other times it will be called by other DLLs or applications that I do not control.

Assumptions

  • I am using C# 3.0, .NET 3.5 SP1, and Visual Studio 2008 SP1
  • I am using log4net 1.2.10.0 or greater

Constraints

Any solution must:

  • Allow for the class library to enable and configure logging via it's own configuration file, if the calling application does not configure log4net.
  • Allow for the class library to enable and configuring logging via the calling applications configuration, if it specifies log4net information

OR

  • Allow for the class library to enable and configuring logging using it's own configuration file at all times.

Problem

When my stand-alone class library is called by a DLL or application that I do not control (such as a third-party COTS tool) and which doesn't specify log4net configuration information, my class library is unable to do any of it's logging.


Question

How do you configure and enable log4net for a stand-alone class library assembly so that it will log regardless if the calling application provides log4net configuration?

like image 617
Zach Burlingame Avatar asked Jun 22 '09 17:06

Zach Burlingame


People also ask

Where do I put log4net in web config?

Add log4net in config file config and enter the following details. Add a class Log. cs in the Utilities folder. Now, in the constructor of this class, instantiate logs for monitoring and debugger loggers.

What is the use of log4net DLL?

dll to log information that might be beneficial for error tracking and other tracing issues. My new article states how to use the Log4net's external Log4net. dll to log information that might be beneficial for error tracking and other tracing issues.


2 Answers

Solution 1

A solution for the first set of constraints is to basically wrap the log4net.LogManager into your own custom LogManager class like Jacob, Jeroen, and McWafflestix have suggested (see code below).

Unfortunately, the log4net.LogManager class is static and C# doesn't support static inheritance, so you couldn't simply inherit from it and override the GetLogger method. There aren't too many methods in the log4net.LogManager class however, so this is certainly a possibility.

The other drawback to this solution is that if you have an existing codebase (which I do in my case) you would have to replace all existing calls to log4net.LogManager with your wrapper class. Not a big deal with today's refactoring tools however.

For my project, these drawbacks outweighed the benefits of using a logging configuration supplied by the calling application so, I went with Solution 2.

Code

First, you need a LogManager wrapper class:

using System; using System.IO; using log4net; using log4net.Config;  namespace MyApplication.Logging {     //// TODO: Implement the additional GetLogger method signatures and log4net.LogManager methods that are not seen below.     public static class LogManagerWrapper     {         private static readonly string LOG_CONFIG_FILE= @"path\to\log4net.config";          public static ILog GetLogger(Type type)         {             // If no loggers have been created, load our own.             if(LogManager.GetCurrentLoggers().Length == 0)             {                 LoadConfig();             }             return LogManager.GetLogger(type);         }          private void LoadConfig()         {            //// TODO: Do exception handling for File access issues and supply sane defaults if it's unavailable.               XmlConfigurator.ConfigureAndWatch(new FileInfo(LOG_CONFIG_FILE));         }               } 

Then in your classes, instead of:

private static readonly ILog log = LogManager.GetLogger(typeof(MyApp)); 

Use:

private static readonly ILog log = LogManagerWrapper.GetLogger(typeof(MyApp)); 

Solution 2

For my purposes, I have decided to settle on a solution that meets the second set of constraints. See the code below for my solution.

From the Apache log4net document:

"An assembly may choose to utilize a named logging repository rather than the default repository. This completely separates the logging for the assembly from the rest of the application. This can be very useful to component developers that wish to use log4net for their components but do not want to require that all the applications that use their component are aware of log4net. It also means that their debugging configuration is separated from the applications configuration. The assembly should specify the RepositoryAttribute to set its logging repository."

Code

I placed the following lines in the AssemblyInfo.cs file of my class library:

// Log4Net configuration file location [assembly: log4net.Config.Repository("CompanyName.IntegrationLibName")] [assembly: log4net.Config.XmlConfigurator(ConfigFile = "CompanyName.IntegrationLibName.config", Watch = true)] 

    

References

  • LogManagerMembers
  • Jacob's Answer
  • Jeroen's Answer
  • McWafflestix's Answer
  • log4net Manual - Repositories
  • log4NET from a class library (dll)
like image 134
Zach Burlingame Avatar answered Oct 01 '22 04:10

Zach Burlingame


You can probably code something around the XmlConfigurator class:

public static class MyLogManager {     // for illustration, you should configure this somewhere else...     private static string configFile = @"path\to\log4net.config";      public static ILog GetLogger(Type type)     {         if(log4net.LogManager.GetCurrentLoggers().Length == 0)         {             // load logger config with XmlConfigurator             log4net.Config.XmlConfigurator.Configure(configFile);         }         return LogManager.GetLogger(type);     } } 

Then in your classes, instead of:

private static readonly ILog log = LogManager.GetLogger(typeof(MyApp)); 

Use:

private static readonly ILog log = MyLogManager.GetLogger(typeof(MyApp)); 

Of course, it would be preferable to make this class a service and dynamically configure it with the IoC container of your choice, but you get the idea?

EDIT: Fixed Count() problem pointed out in comments.

like image 20
Jacob Avatar answered Oct 01 '22 05:10

Jacob