Design patterns Log4Net包装器类是什么样子的?

Design patterns Log4Net包装器类是什么样子的?,design-patterns,log4net,Design Patterns,Log4net,我一直在寻找.net(c#)的日志框架,在阅读了stackoverflow上的几个问答线程之后,我决定尝试一下log4net。我看到人们一次又一次地提到他们为log4net使用了一个包装器类,我想知道那会是什么样子 我将代码分为不同的项目(数据访问/业务/Web服务/)。 log4net包装器类是什么样子的?包装器类是否需要包含在所有项目中?我应该把它作为一个单独的项目一起构建吗 包装器应该是单例类吗 我的理解是log4net的包装类是一个静态类,负责从app.config/web.config

我一直在寻找.net(c#)的日志框架,在阅读了stackoverflow上的几个问答线程之后,我决定尝试一下log4net。我看到人们一次又一次地提到他们为log4net使用了一个包装器类,我想知道那会是什么样子

我将代码分为不同的项目(数据访问/业务/Web服务/)。 log4net包装器类是什么样子的?包装器类是否需要包含在所有项目中?我应该把它作为一个单独的项目一起构建吗


包装器应该是单例类吗

我的理解是log4net的包装类是一个静态类,负责从app.config/web.config或通过代码初始化日志对象(例如与NUnit集成).log4net包装器的一个可能用途是通过反射获取调用类和方法的类,以了解日志条目发生的位置。至少我经常使用它。

本质上,您创建了一个接口,然后是该接口的一个具体实现,它直接封装了Log4net的类和方法。可以通过创建更具体的类来包装其他日志记录系统,这些类可以包装这些系统的其他类和方法。最后,使用工厂根据配置设置或代码行更改创建包装器的实例。(注意:使用容器(例如)可以获得更灵活、更复杂的功能。)

以及在类中使用此代码的示例(声明为静态只读字段):

您可以使用以下方法获得同样的性能友好效果:

private static readonly ILogger _logger = 
    LogManager.GetLogger(typeof(YourTypeName));
前一个示例被认为更易于维护

您不希望创建一个单例来处理所有日志记录,因为Log4Net记录调用类型;让每种类型都使用自己的记录器,而不是在日志文件中只看到一种类型报告所有消息,这会更干净、更有用


因为您的实现应该是相当可重用的(组织中的其他项目),所以您可以将其作为自己的程序集,或者理想情况下将其包含在您自己的个人/组织的框架/实用程序集中。不要在每个业务/数据/UI程序集中分别重新声明这些类,因为它们是不可维护的。

为log4net编写包装器有什么好处。我建议先熟悉log4net类,然后再编写它们的包装器。cfeduke关于如何编写所述包装器的回答是正确的,但除非您需要在他的示例中添加实际功能,否则包装器只会成功地减慢日志记录过程,并为未来的维护人员增加复杂性。当.Net中可用的重构工具使这些更改变得非常简单时,尤其如此。

假设您使用类似的工具,您还可以向日志管理器添加重载,如下所示:

public static ILogger GetLogger()
{
    var stack = new StackTrace();
    var frame = stack.GetFrame(1);
    return new Log4NetWrapper(frame.GetMethod().DeclaringType);
}
这样,您现在就可以在代码中使用:

private static readonly ILogger _logger = LogManager.GetLogger();
而不是以下任何一项:

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

这实际上相当于第一个备选方案(即使用
MethodBase.GetCurrentMethod().DeclaringType
),只是简单一点。

Alconja,我喜欢您使用stacktrace跳回调用方法的想法。我正在考虑进一步封装调用,不仅要检索logger对象,还要实际执行日志记录。我想要的是一个静态类,通过从使用的特定实现中抽象来处理日志记录。即

LoggingService.LogError("my error message");
这样,如果我以后决定使用另一个日志系统,我只需要更改静态类的内部结构

因此,我利用您的想法使用堆栈跟踪获取调用对象:

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

有人认为这种方法有问题吗?

我知道这个答案已经晚了,但它可能会对将来的人有所帮助

听起来您需要XQuiSoft日志提供的编程API。您不必指定要使用XQuiSoft的记录器。就这么简单:

Log.Write(Level.Verbose,“source”,“category”,“此处的消息”)

然后通过配置,您可以按来源、类别、级别或任何其他自定义筛选器将消息定向到不同的位置(文件、电子邮件等)


请参阅以获取介绍。

我已成功地将log4net依赖项隔离到单个项目中。如果您也打算这样做,下面是我的包装器类的外观:

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);
                }
            }
        }
    }
}
别忘了在接口项目的
AssemblyInfo.cs
中添加这个(我花了好几个小时才找到这个)


并将log4net配置xml放入
log4net.config
文件中,将其设置为
Content
Copy Always

有一些类似的框架,它们促进了对您选择的日志框架使用a

这是一个使用以下内容的示例:

使用系统;
使用log4net;
使用log4net.Core;
使用棱镜测井;
公共类Log4NetLoggerFacade:ILoggerFacade
{
私有静态只读ILog Log4NetLog=LogManager.GetLogger(typeof(Log4NetLoggerFacade));
公共作废日志(字符串消息、类别、优先级)
{
开关(类别)
{
案例类别。调试:
Log4NetLog.Logger.Log(typeof(Log4NetLoggerFacade),Level.Debug,message,null);
打破
案件类别.例外情况:
Log4NetLog.Logger.Log(typeof(Log4NetLoggerFacade),Level.Error,message,null);
打破
案件类别。信息:
Log4NetLog.Logger.Log(typeof(Log4NetLoggerFacade),Level.Info,message,null);
打破
案例类别。警告:
Log4NetLog.Logger.Log(typeof(Log4NetLoggerFacade),Level.Warn,message,null);
打破
违约:
抛出新ArgumentOutOfRangeException(nameof(category),category,null);
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);
    }
    ...
}
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);
                }
            }
        }
    }
}
[assembly: log4net.Config.XmlConfigurator(Watch = true, ConfigFile = "log4net.config")]