2012-01-30 45 views
20

在基类中声明一个记录器并调用LogManager.GetLogger似乎更清晰,这样每个正在继承的人都可以使用它。然而,在log4net的网站和其他博客就像this blog post它指出,最好是每类中声明一个记录器,因为:我应该为每个类或基类声明log4net记录器吗?

您可以使用记录器这种方式在你的对象隔离日志关切,我完全推荐你这样做。这将使您能够使用log4net的分层配置机制来限制和指导单个记录器的日志输出。

这是否意味着如果我把它放在基类中,它会使记录器成为瓶颈?

如果是这样,还有其他解决方案,还是我只需要创建每个类的记录器?

回答

0

通常您应该有一个记录器类,您可以使用单例模式,并确保您的应用程序只有一个记录器实例。

编辑:使它现在线程安全,感谢您的意见。

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

希望这有助于

+0

OP正在使用log4net。虽然记录器类是单例模式很有用的罕见情况之一,但为每类使用不同的记录器可以极大地增强故障诊断能力:您可以非常详细地配置分别记录每个类的消息级别。您还可以将来自不同记录器的消息输出到不同的目标(文本文件,事件日志,电子邮件)。我强烈建议使用这样的库。如果记录器是静态实例化的(每种类型一次),性能差异可以忽略不计。 (不是我的downvote,但是) – Groo 2012-01-30 22:40:38

+0

你的单例不是线程安全的,所以你最终可能会有不同的Logger实例(在记录器的情况下可能不是一个大问题,但值得注意)。另外,对于日志记录,你可能不希望这种模式的分数慢一些(因为它必须执行额外的空检查......可能不是什么大事,但值得注意)。 – 2012-01-30 22:41:30

+0

不熟悉log4net? – 2012-01-30 22:42:14

1

提供的声明并未提及到了一个瓶颈。在基类中声明您的记录器会限制您对派生类中日志记录的控制。如果您的A类和B类来自同一个包含记录器的基类,则您在类A和类B中所做的所有日志记录都将保留相同的日志记录设置。

log4net允许您根据类配置记录器或它们的创建名称空间,使您能够对记录的内容进行非常严格的控制。例如,将A级日志记录在信息级别,将B级日志记录在调试级别。

将一行代码添加到您希望记录的每个类中,对于它提供的灵活性来说是一个非常小的负担。

20

的职位没有具体告诉你使用一个不同的记录器在每个派生类,而是一般每类类型不同的记录。您可以,但不必在每个派生类中使用新的记录器实例。

查看它的一种方法是,可能会让两个独立的记录器同时实例化(因为基本的记录器仍然存在)可能会令人困惑,特别是如果您使用相同的记录器名称隐藏基本记录器。您的基类方法(未覆盖)仍将引用基本静态记录器,并且覆盖的方法将使用不同的方法。

此外,文章实例这样的记录:

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

而稍微简单的办法可能是使用:

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

首先,它标志着readonly,这意味着你赢了”一旦初始化,就能够意外改变场地。使用该类型的方式与反射相同,但稍快(在编译时解析)。Visual Studio也将自动更新类名称,如果您选择重命名它(它不是你使用字符串重载)。

+0

你也可以使用反射而不是'typeof(YourClass)'。通过反射,您可以复制粘贴样板代码,而且您不必面对某人复制粘贴记录器并忘记更改'typeof(YourClass)'的情况。然后调用看起来像:'LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod()。DeclaringType);' – 2015-02-12 11:24:18

3

通常的做法是每个类都有一个记录器,而不是基类。这样您可以启用/禁用每个班级的日志记录。

我也可能建议看看使用Common Logging 2.0,http://netcommon.sourceforge.net/

当前正在使用的.NET有多种日志记录实现,log4net,企业库日志记录,NLog等,这些都是最流行的。具有不同实现的缺点是它们不共享通用接口,因此对库的用户强加特定的日志记录实现。

Common.Logging库引入了一个简单的抽象,允许您在运行时选择特定的日志记录实现。因此,您可以推迟决定使用什么特定的日志库直到部署。适配器用于将特定的日志记录系统插入Common.Logging。

0

我使用基类的一个静态辞典,键连接在类型名称:

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

随着方法(在基类)返回一个记录器:

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

我在基础类别上也有测井方法:

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

我assu我会这样允许我为每种类型配置日志记录(尽管我不这样做),并且GetLogger方法可能暴露给派生类,因此他们可以执行自己的日志记录。

+0

看起来你只是向你的基类转发记录器已存在的某些行为。 – 2014-12-04 23:28:26

相关问题