Log4Net配置在外部文件中不起作用。

94

我们正在使用log4net,并希望在外部配置文件中指定其配置(就像我们已经对其他部分进行的那样)。为此,我们已更改了App.config中的log4net部分:

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

在Log.Config文件中(与App.config文件位于同一目录下),我们有以下内容:

<log4net>
  <appender name="General" type="log4net.Appender.FileAppender">
    <file value="myapp.log" />
    <layout type="log4net.Layout.SimpleLayout" />
  </appender>
  <root>
    <appender-ref ref="General" />
  </root>
</log4net>

然而,当我们运行应用程序时,并没有创建日志文件(也没有进行任何记录)。控制台没有输出错误消息。

如果我们将Log.config文件的内容移回到App.config中(替换上面的第一行代码),则可以按预期工作。有什么想法为什么在外部文件中它不起作用?


我遇到了同样的问题 - 我们可能都遵循了同样(误导性)的指南! - Zach Burlingame
15
这就是我不喜欢log4net的原因。在我看来,日志框架应该是您应用程序中最稳定的部分之一,但log4net经常似乎有些不太可靠。 - UpTheCreek
14个回答

120

你的 AssemblyInfo.cs 文件中是否有以下属性:

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

在需要记录日志的每个类的开头,加入以下代码:

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

我有一篇博客文章,其中包含此信息和其他信息,在这里可以阅读。


18
这个可行,确保如果你创建了log4net.config文件,将“复制到输出目录”属性设置为“始终复制”。 - E. van der Spoel
1
@mitchwheat 绝对是神一般的存在,我已经整天在与一个基于Ninject的解决方案进行斗争来实现与这个完全相同的功能...谢谢,老兄! - War
每个类都必须有“private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);”吗?如果我有一个通用类来处理日志,并将类名称作为字符串参数接收,这样行吗? - Gopi P

42

关于此问题已经有一个未解决的缺陷。Log4Net不支持配置元素的configSource属性。要使用完全的配置文件方案,您可以使用appSettings中的log4net.Config键。

步骤1:包括正常的配置部分定义:

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

步骤2:在appSettings中使用神奇的log4net.Config关键字。

<appSettings>
      <add key="log4net.Config" value="log4net.simple.config" />
</appSettings>

第三步:贡献一个补丁来修复configSource的处理。


5
调用log4net.Config.XmlConfigurator.Configure();应该可以解决它无法读取configSource的问题。 - Greg Domjan
这对我没有任何改变。我还没有找出问题所在,但我会尝试跟进。 - Don Rolling
5
将log4net配置文件标记为“拷贝如果较新”非常重要。如果该配置文件未复制到bin文件夹,则它将无法正常工作。 - Francisco Goldenstein
这对我来说是可行的,而且我更喜欢它而不是被接受的解决方案,因为我的一些库用于 Web 应用程序,在那里日志记录在单独的 log4net.config 中配置,并且有时用于独立应用程序,在那里日志记录在 app.exe.config 中配置。这样所有的配置都在配置文件中,而不是在程序集信息中 - 我不想将其“硬编码”到 log4net.config 中。 - Danny

30
漏掉的步骤是什么。
log4net.Config.XmlConfigurator.Configure(); 

这将导致使用configSource配置。确保在调用GetLogger()之前至少调用一次。


如果您使用 Mitch Wheat 的解决方案,则无需执行此操作。 - Robert Wagner
4
@Robert:当然可以,不过Mitch Wheat的解决方案需要在app.config之外硬编码配置文件,我读到原始问题是为什么configSource不起作用,如果遵循这个额外的步骤,则它会起作用。 - Greg Domjan
我更喜欢这种方法,特别是因为我创建了一个包装日志处理程序,它在内部使用log4net(稍后可以替换),然后在这个包装日志处理程序中,我总是调用log4net.Config.XmlConfigurator.Configure()。通过这种方式,任何具有自己app.config的项目都可以使用此包装日志处理程序,而无需更改assembler.cs。 - zheng yu
我应该在哪里调用它? - Yola
在调用GetLogger之前,请先调用@Yola一次。 - Greg Domjan

22

确保你的log4net.config文件已经设置了以下属性:

Build Action(生成操作):Content

Copy to output directory(复制到输出目录): Copy Always


11

要么使用,

<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
</configSections>
<appSettings>
<add key="log4net.Config" value="Log4Net.config" />
</appSettings>

或者只是这样,

log4net.Config.XmlConfigurator.ConfigureAndWatch(new System.IO.FileInfo("Log4Net.config"));

在这两种情况下,文件Log4Net.config应该存在于输出目录中。 您可以通过在解决方案资源管理器中设置Log4Net.config文件属性来实现此目的。 构建操作 - 内容和复制到输出目录 - 始终复制


你不需要在第一个案例中使用<configSections>标签。 - disklosr
第二个是我唯一可行的选项。 - Alon Kogan

3

您可以在App.config文件中开启log4net的调试模式。

 <appSettings>
      <add key="log4net.Internal.Debug" value="true"/>
 </appSettings>
 <system.diagnostics>
      <trace autoflush="true">
      <listeners>
           <add
             name="textWriterTraceListener"
             type="System.Diagnostics.TextWriterTraceListener"
             initializeData="link\to\your\file.log" />
      </listeners>
      </trace>
 </system.diagnostics>

您至少会收到错误信息,从中可以推断出到底出了什么问题。在我的情况下,我只是忘记将 复制到输出目录 设置为 始终复制


2

注意这个问题...

在我的情况下,一切都配置正确。问题是我使用 Visual Studio 2013 中的 Web Deploy 将网站上传到 WinHost.com,它重置了服务器上的ACLs。这反过来吊销了文件夹和文件的所有权限 - log4net 无法写入文件。

你可以在这里阅读更多信息:

如何防止 Web Deploy/MSBuild 搞乱服务器权限

我向那里的支持团队要求重置 ACLs,然后 log4net 开始输出日志。 :)


1
假设您有一个名为log4net.config的外部配置文件,已复制到您的部署目录中,您可以按以下方式进行配置:
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Reflection;

using log4net;

namespace MyAppNamespace {
    static class Program {
        //declare it as static and public so all classes in the project can access it
        //like so: Program.log.Error("got an error");
        public static readonly log4net.ILog log = log4net.LogManager.GetLogger(typeof(Program));

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main() {
             //configure it to use external file
            log4net.Config.XmlConfigurator.Configure(new Uri(Application.StartupPath + "\\log4net.config"));
            //use it
            log.Debug("#############   STARING APPLICATION    #################");


            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new FormMain());
        }
    }
}

1
  1. 将以下内容添加到 AssemblyInfo.cs

    [assembly: log4net.Config.XmlConfigurator(ConfigFile = "Log4Net.config")]

  2. 确保将 log4net.config 包含在项目中

  3. log4net.config 的属性中

CopyToOutputDirctory 标签更改为 CopyIfNewer 标签

  1. 仔细检查日志级别 级别 value="ALL"

1
我有同样的问题,除了拥有

之外。
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net")]

在进行中的项目中,我还在参考项目中有以下这行代码:
[assembly: log4net.Config.XmlConfigurator]

当我在相关的项目中移除了这行代码后,日志开始出现。

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