What does the Wrapper Log4Net class look like?

I was looking for a .net framework (C #) and decided to let log4net go after reading a few questions / answers in the stackoverflow thread. I see people mentioning over and over again that they are using the shell class for log4net, and I'm wondering what that would look like.

I have my code divided into different projects (data access / business / webservice / ..). What does the log4net wrapper class look like? Will a wrapper class be included in all projects? Should I combine it as a separate project?

Should the shell be a singleton class?

+53
design-patterns log4net
Oct 03 '08 at 11:39
source share
9 answers

Essentially, you create an interface, and then a specific implementation of that interface, which directly transfers the Log4net classes and methods. Additional registration systems can be wrapped by creating more specific classes that combine other classes and methods of these systems. Finally, use factory to instantiate your wrappers based on configuration settings or a line of code change. (Note: you can become more flexible and complex - using an Inversion of Control container, such as StructureMap .)

public interface ILogger { void Debug(object message); bool IsDebugEnabled { get; } // continue for all methods like Error, Fatal ... } public class Log4NetWrapper : ILogger { private readonly log4net.ILog _logger; public Log4NetWrapper(Type type) { _logger = log4net.LogManager.GetLogger(type); } public void Debug(object message) { _logger.Debug(message); } public bool IsDebugEnabled { get { return _logger.IsDebugEnabled; } } // complete ILogger interface implementation } public static class LogManager { public static ILogger GetLogger(Type type) { // if configuration file says log4net... return new Log4NetWrapper(type); // if it says Joe Logger... // return new JoesLoggerWrapper(type); } } 

And an example of using this code in your classes (declared as readonly static field):

 private static readonly ILogger _logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 

You can get the same effect that is more powerful:

 private static readonly ILogger _logger = LogManager.GetLogger(typeof(YourTypeName)); 

The first example is considered more maintainable.

You do not want to create a Singleton to handle all protocols, because Log4Net logs are logged for the calling type; its much cleaner and more useful so that each type uses its own logger, rather than just seeing one type in the log file reporting all messages.

Since your implementation should be reusable enough (other projects in your organization), you can make it your own assembly or, ideally, include it in your own assembly / assembly / assembly. Do not redefine classes separately in each of your business / data / user interface assemblies that are not supported.

+48
Oct 03 '08 at 11:49
source share

Assuming you come across something like cfeduke's answer above , you can also add overloading to LogManager as follows:

 public static ILogger GetLogger() { var stack = new StackTrace(); var frame = stack.GetFrame(1); return new Log4NetWrapper(frame.GetMethod().DeclaringType); } 

So in your code you can simply use:

 private static readonly ILogger _logger = LogManager.GetLogger(); 

instead of any of them:

 private static readonly ILogger _logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILogger _logger = LogManager.GetLogger(typeof(YourTypeName)); 

This is actually equivalent to the first alternative (i.e. the one that uses MethodBase.GetCurrentMethod().DeclaringType ), only a little easier.

+24
Feb 26 '09 at 2:52
source share

What benefits do you plan to get from writing a wrapper for log4net. I would recommend mastering the log4net classes first before writing a wrapper around them. cfeduke is right in his answer on how to write the specified shell, but if you did not need to add the actual functionality to your example, the shell would only be able to slow down the registration process and add complexity for future maintainers. This is especially true when the refactoring tools available in .Net make such changes very easy.

+5
03 Oct '08 at 12:30
source share

I have successfully isolated the log4net dependency in one project. If you intend to do the same, here is what my wrapper class looks like:

 using System; namespace Framework.Logging { public class Logger { private readonly log4net.ILog _log; public Logger() { _log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); } public Logger(string name) { _log = log4net.LogManager.GetLogger(name); } public Logger(Type type) { _log = log4net.LogManager.GetLogger(type); } public void Debug(object message, Exception ex = null) { if (_log.IsDebugEnabled) { if (ex == null) { _log.Debug(message); } else { _log.Debug(message, ex); } } } public void Info(object message, Exception ex = null) { if (_log.IsInfoEnabled) { if (ex == null) { _log.Info(message); } else { _log.Info(message, ex); } } } public void Warn(object message, Exception ex = null) { if (_log.IsWarnEnabled) { if (ex == null) { _log.Warn(message); } else { _log.Warn(message, ex); } } } public void Error(object message, Exception ex = null) { if (_log.IsErrorEnabled) { if (ex == null) { _log.Error(message); } else { _log.Error(message, ex); } } } public void Fatal(object message, Exception ex = null) { if (_log.IsFatalEnabled) { if (ex == null) { _log.Fatal(message); } else { _log.Fatal(message, ex); } } } } } 

And don't forget to add this to the AssemblyInfo.cs pairing project (it took me a few hours to find this)

 [assembly: log4net.Config.XmlConfigurator(Watch = true, ConfigFile = "log4net.config")] 

And put your log4net configuration file in the log4net.config file, set it as Content , Copy Always

+1
Feb 02 '16 at 22:23
source share

I understand that the wrapper class for log4net will be a static class that will take care of initializing the logging object from app.config / web.config or by code (e.g. integration with NUnit).

0
Oct 03 '08 at 11:45
source share

a possible use for wrapping log4net could be a class that gets the calling class and method through reflection to get an idea of ​​where the log entry occurred. at least i use it often.

0
03 Oct '08 at 11:45
source share

Alconja, I like your idea of ​​using stacktrace to return to the calling method. I was thinking about further encapsulating the calls so that I would not only get the log object, but also do the actual execution of the log. I want a static class that handles logging by abstracting from the particular implementation used. I.e

 LoggingService.LogError("my error message"); 

Thus, I need to change the interiors of the static class if later I decide to use a different registration system.

So, I used your idea to get the caller using the stack trace:

 public static class LoggingService { private static ILog GetLogger() { var stack = new StackTrace(); var frame = stack.GetFrame(2); return log4net.LogManager.GetLogger(frame.GetMethod().DeclaringType); } public static void LogError(string message) { ILog logger = GetLogger(); if (logger.IsErrorEnabled) logger.Error(message); } ... } 

Does anyone see a problem with this approach?

0
Aug 17 '09 at 9:02
source share

There are frameworks such as the Prism Library for WPF that encourage the use of facade for the logging structure of your choice.

This is an example that uses log4net :

 using System; using log4net; using log4net.Core; using Prism.Logging; public class Log4NetLoggerFacade : ILoggerFacade { private static readonly ILog Log4NetLog = LogManager.GetLogger(typeof (Log4NetLoggerFacade)); public void Log(string message, Category category, Priority priority) { switch (category) { case Category.Debug: Log4NetLog.Logger.Log(typeof(Log4NetLoggerFacade), Level.Debug, message, null); break; case Category.Exception: Log4NetLog.Logger.Log(typeof(Log4NetLoggerFacade), Level.Error, message, null); break; case Category.Info: Log4NetLog.Logger.Log(typeof(Log4NetLoggerFacade), Level.Info, message, null); break; case Category.Warn: Log4NetLog.Logger.Log(typeof(Log4NetLoggerFacade), Level.Warn, message, null); break; default: throw new ArgumentOutOfRangeException(nameof(category), category, null); } } } 

Note that by specifying callerStackBoundaryDeclaringType , you can still get the class name of the caller issuing the registration request. All you have to do is include %C %M in the conversion pattern:

 <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%date [%thread] %-5level %C.%M - %message%newline" /> </layout> 

However, as the documentation warns, the generation of caller class information is slow, so it must be used wisely.

0
Jul 15 '16 at 11:17
source share

I know this answer is late, but it may help someone in the future.

It looks like you need a software API that gives you XQuiSoft Logging. You do not need to specify which registrar you want to use with XQuiSoft. it is so simple:

Log.Write (Level.Verbose, "source", "category", "your message here");

Then, through the configuration, you send messages by source, category, level or any other custom filter to different locations (files, emails, etc.).

See this article for an introduction.

-3
Dec 06 '10 at 19:39
source share



All Articles