简体   繁体   中英

Should I declare log4net logger once per class or in base class?

It seems cleaner to declare a logger and call LogManager.GetLogger in a base class so that everyone who is inheriting can use it. However, on log4net site and other blogs like in this blog post it states that it is better to declare one logger per class because:

You can use loggers this way to isolate logging concerns across your objects, and I wholly recommend you do so. This will enable you to throttle and direct log output from individual loggers using log4net's hierarchical configuration mechanism.

Does this mean if I put it in base class, it will make that logger a bottleneck?

If so, are there other solutions or do I just have to create a logger per class?

The post is not specifically telling you to use a different logger in each derived class, but instead a different logger per class type in general. You can, but don't have to use a new logger instance in each derived class.

One way to look at it is that it might be confusing to have two separate loggers instantiated at the same time (because the base one will still exist), especially if you hide the base one using the same logger name. Your base class methods (not overridden) will still reference the base static logger, and overridden ones will use a different one.

Also, the article instantiates the logger like this:

static ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType );

while a slightly simpler way might be to use:

static readonly ILog Log = LogManager.GetLogger(typeof(YourClass));

First of all, it's marked readonly , meaning you won't be able to change the field accidentally, once initialized. And using the type will work the same way as with reflection, but slightly faster (resolved at compile time). Visual Studio will also update the class name automatically if you choose to rename it (which it wouldn't it you used the string overload).

Common practice is to have one logger per class, NOT base class. This way you can enable/disable logging on a per class basis.

I might also suggest looking at using Common Logging 2.0, http://netcommon.sourceforge.net/ .

There are a variety of logging implementations for .NET currently in use, log4net, Enterprise Library Logging, NLog, to name the most popular. The downside of having differerent implementation is that they do not share a common interface and therefore impose a particular logging implementation on the users of your library.

Common.Logging library introduces a simple abstraction to allow you to select a specific logging implementation at runtime. Thus you can defer the decision what particular logging library to use until deployment. Adapters are used for plugging a particular logging system into Common.Logging.

The provided statement does not refer to a bottleneck. Declaring your logger in a base class limits the control you have over the logging in derived classes. If you have classes A and B deriving from the same logger-containing base class, you are stuck with the same logging settings for all logging done in classes A and B.

log4net allows you to configure your loggers based on the class or namespace they are created for, giving you very tight control of what is logged. For example, having class A log at the info level and class B log at the debug level.

Adding a single line of a code to each class you wish to log things in is a very small burden for the flexibility it provides.

I use a static dictionary in the base class, keyed on type name:

private static readonly Dictionary<string, ILog> _loggers = new Dictionary<string, ILog>();

With a method (on the base class) to return a logger:

    private ILog GetLogger(){
        var tn = this.GetType().FullName;
        if (!_loggers.ContainsKey(tn)) {
            _loggers.Add(tn,LogManager.GetLogger(this.GetType()));
        }
        return _loggers[tn];
    }

I also have the logging methods on the base class:

    public void Log(string msg, params object[] args) {
        GetLogger().InfoFormat(msg, args);
    }

I assume that this would allow me to configure logging per type (although I don't do that) and the GetLogger method could be exposed to derived classes so they can do their own logging.

Usually you should have a single logger class, you could use singleton pattern and make sure that you have only one instance of logger for your application.

Edit: Made it thread safe now, thanks for comments.

    public class Logger
    { 
      private static object syncRoot = new Object();
      private static Logger instance=null;
      // private constructor
      private Logger()
      {
      }
      /// <summary>
    /// Gets an instance with default parameters based upon the caller
    /// </summary>
    /// <returns></returns>
    public static Logger GetInstance()
    {
       // make sure you return single instance
       if (instance == null)
        {
           lock (syncRoot) 
           { 
            instance=new Logger();
           } 
        }
        return instance;
    }
   }

Hope this helps

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM