使用log4net的正确方法(记录器命名)

88

有两种配置和使用log4net的方式。第一种是我可以配置自己的appender和相关logger:

<!-- language: xml -->

<appender name="myLogAppender" type="log4net.Appender.RollingFileAppender" >
    <file value="Logs\myLog.log" />
    <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date %level - %message%n" />
    </layout>
</appender>

<logger name="myLog">
    <level value="All"></level>
    <appender-ref ref="myLogAppender" />
</logger>

然后当我想要在日志中写入内容时,我可以执行以下操作:

ILog log = LogManager.GetLogger("myLog");
log.Info("message");

另一种使用方法是将根配置为尽可能详细:

<!-- language: xml -->

<root>
    <level value="Error" />
    <appender-ref ref="myLogAppender" />
</root>

在这种情况下,我可以像这样记录消息:

ILog log = LogManager.GetLogger(typeof(Bar));
log.Info("message");

第二种方法的好处是可以随时启用或禁用一些消息。但问题是我正在EPiServer CMS中进行开发,它有自己的日志记录系统,使用log4net,如果我在根级别启用了信息记录,则会写入大量系统日志。

你如何使用log4net?系统的每个部分都在自己的日志记录器中写入,还是所有内容都写入默认记录器,并由配置决定下一步做什么?

4个回答

101

关于在代码中记录消息的方式,我会选择第二种方法:

ILog log = LogManager.GetLogger(typeof(Bar));
log.Info("message");

日志中记录的信息将使用完全合格的类型Bar进行“命名”,例如:

MyNamespace.Foo.Bar [INFO] message

这种方法的优点是它是组织日志记录的事实标准,它还允许您按命名空间过滤日志消息。例如,您可以指定要记录INFO级别消息,但特别将Bar的日志级别提高到DEBUG:

<log4net>
    <!-- appenders go here -->
    <root>
        <level value="INFO" />
        <appender-ref ref="myLogAppender" />
    </root>

    <logger name="MyNamespace.Foo.Bar">
        <level value="DEBUG" />
    </logger>
</log4net>

通过名称筛选日志记录是log4net的一个强大特性。如果你只将所有消息记录到"myLog",则会失去很多这种功能!

关于EPiServer CMS,您可以使用上述方法来指定CMS和自己代码的不同日志记录级别。

想要进一步了解,请参考我在CodeProject上撰写的有关日志记录的文章:


5
您可以使用PatternLayout来排除类命名空间的日志部分,以减少日志中的噪音。例如,对于记录器名称"a.b.c",模式%logger{2}将输出"b.c"。详情请参考:http://logging.apache.org/log4net/release/sdk/log4net.Layout.PatternLayout.html。 - AlfeG
7
私有的静态只读变量log,其值为LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType)。 - Casper Leon Nielsen
第二种方法为什么比第一种更好?!类名是静态的,如果您更改它,还必须在记录器中更新名称,那么引起反射调用只是为了获取类名有何意义呢? - MeTitus
1
@CasperLeonNielsen,你能解释一下这与“this.GetType()”有什么不同吗? - ErikE
2
@ErikE 在定义静态属性、静态类或构造函数外部时,将无法使用 this.GetType()。 - dhochee
@dhochee 是的,你说得很对。我没有注意到事物的静态性质。在静态方法中没有this。但是你所说的“在构造函数外部”是什么意思呢? - ErikE

14

我的答案可能来得有点晚,但我认为它可以帮助新手。除非进行以下更改,否则您将看不到执行的日志记录。

实施Log4net时必须更改2个文件。


  1. 在项目中添加log4net.dll的引用。
  2. app.config
  3. 你将要实现日志的Class文件。

在 [app.config] 中:

首先,在 'configSections' 下,您需要添加以下代码段;

<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />

然后,在 'configuration' 代码块下,您需要编写以下代码。(这段代码根据我的需求进行了定制,但它非常有效。)

<log4net debug="true">
    <logger name="log">
      <level value="All"></level>
      <appender-ref ref="RollingLogFileAppender" />
    </logger>

    <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
      <file value="log.txt" />
      <appendToFile value="true" />
      <rollingStyle value="Composite" />
      <maxSizeRollBackups value="1" />
      <maximumFileSize value="1MB" />
      <staticLogFileName value="true" />

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

调用类内部:

在你要使用log4net的类中,你需要声明以下代码片段。

 ILog log = LogManager.GetLogger("log");

现在,您已经准备好在同一类中的任何位置调用日志记录。以下是您在执行操作时可以调用的方法之一。

现在,您可以在该类中任何地方调用日志记录。以下是您在执行操作时可以调用的方法之一。

log.Error("message");

你不需要将 ILog 设置为实例成员,对吧?我在这个帖子里提出了相同的问题,但也许我能获取您的意见? - Minh Tran

6

我开始使用以下方式代替给调用者命名:

private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

这样,我可以在使用log4net的每个类中使用相同的代码行,而无需在复制和粘贴时记得更改代码。 或者,我可以创建一个日志记录类,并使每个其他类从我的日志记录类继承。


0

第二种方法的缺点是创建了一个大型存储库,其中包含了许多日志记录器。如果定义了根记录器并且未定义类记录器,则这些记录器会执行相同的操作。在生产系统中的标准方案是使用几个专用于一组类的记录器。对于我的英语表示抱歉。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接