【问题标题】:unable to get log4net working with .net windows service无法让 log4net 与 .net Windows 服务一起使用
【发布时间】:2013-04-30 04:54:36
【问题描述】:

我有一个带有app.configlog4net.config 的Windows 服务。

app.config:

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

log4net.config:

<log4net>
  <appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender">
    <param name="File" value="D:\Projects\Integration\Interface Module\bin\Logs\MyFirstLogger.log"/>
    <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
    <appendToFile value="true" />
    <rollingStyle value="Size" />
    <maxSizeRollBackups value="2" />
    <maximumFileSize value="1MB" />
    <staticLogFileName value="true" />
    <layout type="log4net.Layout.PatternLayout">
      <param name="ConversionPattern" value="%d [%t] %-5p %c %m%n"/>
    </layout>
  </appender>

  <root>
    <level value="ALL" />
    <appender-ref ref="LogFileAppender" />
  </root>
</log4net>

我也在AssemblyInfo.cs 中添加了这个:

[assembly: log4net.Config.XmlConfigurator(Watch = true)]

在我的一堂课中,我有:

private readonly ILog _log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

_log.Info(content);

我已授予 所有 用户对我的日志文件夹的完全权限。

我的 bin 文件夹(运行该服务的文件夹)同时包含我的 app.configlog4net.config

但是没有生成日志文件。我错过了哪些设置?

2014 年 3 月 4 日更新

如果您像我一样使用单独的配置文件 (log4net.config),请记住在解决方案资源管理器中将 Copy to output directory 设置为 Copy always

【问题讨论】:

  • 这是在 IIS 应用程序中运行的吗?如果是这样,您需要授予 IIS_IUSRS 对日志目录的完全权限。
  • 它作为 Windows 服务托管
  • 您提到授予用户对您的日志文件夹的权限,但您的服务实际上是否以用户身份运行(而不是像 LocalService 之类的东西)?
  • 属性[assembly: log4net.Config.XmlConfigurator(Watch = true)]和对LogManager.GetLogger的调用是否在同一个程序集中?

标签: c# .net logging log4net log4net-configuration


【解决方案1】:

请注意,当进程作为 Windows 服务运行时,Environment.CurrentDirectory 将为“C:\Windows\system32”

所以如果你把log4net配置文件(log4net.config)放在你的*.exe旁边,就可以使用下面的代码来配置log4net了。

var assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
XmlConfigurator.Configure(new FileInfo(Path.Combine(assemblyFolder, "log4net.config")));

【讨论】:

  • 这是给我的。另请注意,出于同样的原因,您可能不想在日志文件名中使用相对路径,因为如果权限甚至允许写入,它们最终会在 windows\system32 下。
  • 好答案。也为我工作。
【解决方案2】:

Log4Net 的设计是

fail-stop,我们的意思是log4net不会抛出意外的异常 在运行时可能导致您的应用程序崩溃

因此很难找出导致问题的原因。

如何启用 log4net 内部调试?

来自常见问题解答 - http://logging.apache.org/log4net/release/faq.html

  • 也可以通过在 应用程序的配置文件(不是 log4net 配置文件, 除非 log4net 配置数据嵌入在应用程序的 配置文件)。 log4net.Internal.Debug 应用程序设置必须是 设置为真值。例如:
<?xml version="1.0" encoding="utf-8" ?> 
<configuration>
            <appSettings>
                <add key="log4net.Internal.Debug" value="true"/>
            </appSettings> 
</configuration>

此设置会在启动时立即读取,并会导致发出所有内部调试消息。

  • 。要以编程方式启用 log4net 的内部调试,您需要设置 log4net.Util.LogLog.InternalDebugging 属性为 true。 显然,设置得越早,产生的调试就越多。

所以这是我为 log4Net 创建的自定义类 - 因为配置文件 很困惑我创建了这个帮助类

  • 您可以在应用程序中启动任意数量的附加程序 因此,如果一个 dll 调用另一个 dll 两者都可以启动附加程序,并且两者都可以 追加将起作用。
  • 您也可以关闭附加程序和(在文件附加程序的情况下) 然后将其作为电子邮件发送
Log4NetFileHelper log = new Log4NetFileHelper();
        log.Init(); //Initialize
        log.AddConsoleLogging(); //Add Console Logging
        log.AddFileLogging(Path.Combine(AssemblyDirectory, "BatchConsole.log")); 
        log.AddFileLogging(Path.Combine(AssemblyDirectory,"BatchConsole_error.log"),log4net.Core.Level.Error); 

请将此属性设置为 True log4net.Util.LogLog.InternalDebugging=true;

public class Log4NetFileHelper
{
    private string  DEFAULT_LOG_FILENAME=string.Format("application_log_{0}.log",DateTime.Now.ToString("yyyyMMMdd_hhmm"));
    Logger root;
    public Log4NetFileHelper()
    {

    }

    public virtual void Init()
    {
        root = ((Hierarchy)LogManager.GetRepository()).Root;
        //root.AddAppender(GetConsoleAppender());
        //root.AddAppender(GetFileAppender(sFileName));
        root.Repository.Configured = true;
    }

    #region Public Helper Methods
    #region Console Logging
    public virtual void AddConsoleLogging()
    {
        ConsoleAppender C = GetConsoleAppender();
        AddConsoleLogging(C);
    }

    public virtual void AddConsoleLogging(ConsoleAppender C)
    {
        root.AddAppender(C);
    }
    #endregion

    #region File Logging
    public virtual FileAppender AddFileLogging()
    {
        return AddFileLogging(DEFAULT_LOG_FILENAME);
    }

    public virtual FileAppender AddFileLogging(string sFileFullPath)
    {
        return AddFileLogging(sFileFullPath, log4net.Core.Level.All);
    }

    public virtual FileAppender AddFileLogging(string sFileFullPath, log4net.Core.Level threshold)
    {
        return AddFileLogging(sFileFullPath, threshold,true);  
    }

    public virtual FileAppender AddFileLogging(string sFileFullPath, log4net.Core.Level threshold, bool bAppendfile)
    {
        FileAppender appender = GetFileAppender(sFileFullPath, threshold , bAppendfile);
        root.AddAppender(appender);
        return appender;
    }

    public virtual SmtpAppender AddSMTPLogging(string smtpHost, string From, string To, string CC, string subject, log4net.Core.Level threshhold)
    {
        SmtpAppender appender = GetSMTPAppender(smtpHost, From, To, CC, subject, threshhold);
         root.AddAppender(appender);
         return appender;
    }

    #endregion


    public log4net.Appender.IAppender GetLogAppender(string AppenderName)
    {
        AppenderCollection ac = ((log4net.Repository.Hierarchy.Hierarchy)LogManager.GetRepository()).Root.Appenders;

        foreach(log4net.Appender.IAppender appender in ac){
            if (appender.Name == AppenderName)
            {
                return appender;
            }
        }

        return null;
    }

    public void CloseAppender(string AppenderName)
    {
        log4net.Appender.IAppender appender = GetLogAppender(AppenderName);
        CloseAppender(appender);
    }

    private void CloseAppender(log4net.Appender.IAppender appender)
    {
        appender.Close();
    }

    #endregion

    #region Private Methods

    private SmtpAppender GetSMTPAppender(string smtpHost, string From, string To, string CC, string subject, log4net.Core.Level threshhold)
    {
        SmtpAppender lAppender = new SmtpAppender();
        lAppender.Cc = CC;
        lAppender.To = To;
        lAppender.From = From;
        lAppender.SmtpHost = smtpHost;
        lAppender.Subject = subject;
        lAppender.BufferSize = 512;
        lAppender.Lossy = false;
        lAppender.Layout = new
        log4net.Layout.PatternLayout("%date{dd-MM-yyyy HH:mm:ss,fff} %5level [%2thread] %message (%logger{1}:%line)%n");
        lAppender.Threshold = threshhold;
        lAppender.ActivateOptions();
        return lAppender;
    }

    private ConsoleAppender GetConsoleAppender()
    {
        ConsoleAppender lAppender = new ConsoleAppender();
        lAppender.Name = "Console";
        lAppender.Layout = new 
        log4net.Layout.PatternLayout(" %message %n");
        lAppender.Threshold = log4net.Core.Level.All;
        lAppender.ActivateOptions();
        return lAppender;
    } 
    /// <summary>
    /// DETAILED Logging 
    /// log4net.Layout.PatternLayout("%date{dd-MM-yyyy HH:mm:ss,fff} %5level [%2thread] %message (%logger{1}:%line)%n");
    ///  
    /// </summary>
    /// <param name="sFileName"></param>
    /// <param name="threshhold"></param>
    /// <returns></returns>
    private FileAppender GetFileAppender(string sFileName , log4net.Core.Level threshhold ,bool bFileAppend)
    {
        FileAppender lAppender = new FileAppender();
        lAppender.Name = sFileName;
        lAppender.AppendToFile = bFileAppend;
        lAppender.File = sFileName;
        lAppender.Layout = new 
        log4net.Layout.PatternLayout("%date{dd-MM-yyyy HH:mm:ss,fff} %5level [%2thread] %message (%logger{1}:%line)%n");
        lAppender.Threshold = threshhold;
        lAppender.ActivateOptions();
        return lAppender;
    }

    //private FileAppender GetFileAppender(string sFileName)
    //{
    //    return GetFileAppender(sFileName, log4net.Core.Level.All,true);
    //}

    #endregion

    private void  ConfigureLog(string sFileName)
    {


    }
}

【讨论】:

    【解决方案3】:

    这是适合我的配置。

    AssemblyInfo.cs

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

    Log4net.Config

    <?xml version="1.0" encoding="utf-8" ?>
    <log4net>
        <appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender,log4net">
                <param name="File" value="C:\TEMP\Logs.txt"/>
                <lockingModel type="log4net.Appender.FileAppender+MinimalLock,log4net" />
                <appendToFile value="true" />
                <rollingStyle value="Size" />
                <maxSizeRollBackups value="2" />
                <maximumFileSize value="1MB" />
                <staticLogFileName value="true" />
            <layout type="log4net.Layout.PatternLayout,log4net">
                <param name="ConversionPattern" value="%d [%t] %-5p %c %m%n"/>
            </layout>
        </appender>
        <root>
             <level value="ALL" />
             <appender-ref ref="LogFileAppender" />
        </root>
    </log4net>
    

    C# 代码

    private static readonly log4net.ILog Logger = log4net.LogManager.GetLogger(typeof(class_name));
    

    我在 C# 类库项目中有此设置,所有其他项目都使用此项目引用来记录异常。

    【讨论】:

    • 就我而言,问题似乎与 FileAppender 有关。我已经替换了它 RollingFileAppender 并且效果很好。之前没有任何帮助。
    • 只有你改变 GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);工作完美,谢谢伙计!
    【解决方案4】:

    检查再检查后... :-)

    您只需在创建记录器之前调用XmlConfigurator.Configure();(只需一次)。

    很高兴为您提供帮助,

    办公室

    【讨论】:

    • 我在我的 AssemblyInfo.cs 中做到了 [assembly: log4net.Config.XmlConfigurator(Watch = true)]
    • 我认为您要么需要调用 XmlConfigurator.Configure() 要么更改您的 assemblyInfo.cs 以使用 [assembly: log4net.Config.XmlConfigurator(Watch = true, ConfigFile="log4net.config") ]
    • 它在 AssemblyInfo.cs 文件中对我不起作用。请调用“XmlConfigurator.Configure();”在“GetLogger”之前。如果它仍然不起作用,请告诉我。
    【解决方案5】:

    如果你将制作一个不同的配置文件并将 log4net 相关的东西放入其中,那么你将需要使用 [assembly: log4net.Config.XmlConfigurator(ConfigFile = @"...\log4net.config", Watch = true)]AssemblyInfo.cs 中,而不仅仅是

    [assembly: log4net.Config.XmlConfigurator(Watch = true)]

    否则,你必须把 <log4net> ... </log4net> App.config

    中的部分配置

    【讨论】:

    • ConfigFile = @"...\log4net.config"
    • 必须是log4net.config的全路径。例如,如果它位于您的C:\temp,您应该输入C:\temp\log4net.config 我不确定它是否接受相对路径,值得一试
    • This 文章清楚地解释了用法。希望对你有帮助
    【解决方案6】:

    对不起,如果其中一些看起来很明显,但这些是我要检查的:

    • 确保将 log4net.config 文件属性复制到输出设置为始终复制,通过检查 bin 目录中的文件进行验证

    • 另请注意 log4net 文档中与 AssemblyInfo.cs 属性相关的内容:

    使用属性可以更清楚地定义应用程序的配置将从何处加载。不过值得 注意到属性纯粹是被动的。它们只是信息。 因此,如果您使用配置属性,则必须调用 log4net 允许它读取属性。一个简单的调用 LogManager.GetLogger 将导致调用程序集上的属性 被读取和处理。 因此,必须制定一个 在应用程序启动期间尽早记录调用,以及 当然在任何外部程序集被加载之前 调用

    • 要排除故障,您可以尝试从程序集级别属性切换到显式配置调用

      XmlConfigurator.Configure();

      应该足够了。

    • 我总是将 log4net.config 设为完整的配置文件,以

      开头 ... 配置>

    app.config 中不需要任何与 log4net 相关的内容,只要您的配置文件是 log4net.config 即可

    【讨论】:

      【解决方案7】:

      当您说“所有用户”对日志目录具有完全权限时,这是否包括服务帐户?

      检查 LocalService、NetworkService、LocalSystem 等是否具有权限(取决于服务运行的上下文)。

      另外,假设您有一个工具可以将服务作为应用程序运行,那么当您以用户身份运行时,日志记录是否有效?

      如果它作为应用程序运行不正常,则说明 log4net 配置存在问题(其他答案已尝试解决)。

      【讨论】:

        【解决方案8】:

        log4net 在活动用户的权限下运行。确保活动用户有权创建/修改/删除指定的文本文件。

        【讨论】:

          【解决方案9】:

          能否请您上传您的应用程序,以便我自己调试它?

          我建议检查一些:

          1. 将文件路径中的所有“\”替换为“\”

          2. 将所有嵌入的log4net配置放入应用程序的配置文件中。

          3. 启用 log4net 调试 (see here)

          4. 尝试不同的配置。只需获取 Internet 上某个地方的示例配置即可。

          5. 为了确定,我会为所有用户授予对您的日志目录的最大权限

          6. 尝试卸载服务并重新安装。

          【讨论】:

            【解决方案10】:

            在上述线程中继续 Yanting Chen 的评论 - 使用下面的代码,您可以找到在 Windows 调度程序下运行应用程序时 log4net 记录的所有配置消息。它可能有助于某人了解 log4net,尤其是在您看不到命令​​屏幕的服务或调度程序下运行时。

              private static void InstanceLogger()
                {
                    if (logger == null)
                        logger = LogManager.GetLogger(typeof(Utility));
            
                    // Code to troubleshoot Log4Net issues through Event log viewer
                    StringBuilder sb = new StringBuilder();
            
                    foreach (log4net.Util.LogLog m in logger.Logger.Repository.ConfigurationMessages)
                    {
                        sb.AppendLine(m.Message);
                    }
            
                    throw new Exception("String messages: " + sb.ToString());
            
                }
            

            【讨论】:

              【解决方案11】:

              如果您有单独的 log4net.config 文件。您是否设置了以下属性:

              复制到输出目录 = 始终复制

              【讨论】:

                【解决方案12】:

                我看到您的代码在 AssemblyInfo.cs 中有一个小问题。

                将您的代码替换为: [程序集:log4net.Config.XmlConfigurator(ConfigFile = "{{folder_path}}\log4net.config")]

                其中 {{folder_path}} 是 log4net.config 的路径

                【讨论】:

                  【解决方案13】:

                  使用系统登录的 Windows 服务无法访问所有存在的目录。 所以尝试登录“C:\Users\Public\AppData”。 这对我有用

                  【讨论】:

                    【解决方案14】:

                    以管理员身份从 Microsoft SysinternalsSuite 运行 Dbgview.exe --> Capture Global Win32 --> 启动您的服务,这表明我的 log4net.config 与 Windows 服务可执行文件不在同一个目录中。左键单击 VS 中的 log4net.config 和属性 --> 高级 --> 设置复制到输出目录:如果更新则复制。这样,Build 将在 bin 中包含运行服务所需的文件。

                    • How do I enable log4net internal debugging? 来自log4net's FAQ
                    • 我按照tutorial 将日志记录添加到我的服务中。

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 2011-06-19
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2011-02-28
                      • 1970-01-01
                      • 2014-06-06
                      • 1970-01-01
                      相关资源
                      最近更新 更多