C# 无法让 log4net 与 .net windows 服务一起工作

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16398680/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 00:56:21  来源:igfitidea点击:

unable to get log4net working with .net windows service

c#.netlogginglog4netlog4net-configuration

提问by Null Reference

I have a windows service with an app.configand a log4net.config.

我有一个带有app.config和 的Windows 服务log4net.config

app.config:

app.config

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

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>

I have added this in AssemblyInfo.cstoo:

我也添加了这个AssemblyInfo.cs

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

And in one of my classes, I have:

在我的一堂课中,我有:

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

and

_log.Info(content);

I have given allusers full permissions to my Logs folder.

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

My bin folder (which the service is running from) has both my app.configand log4net.config.

我的 bin 文件夹(服务正在运行)同时包含 myapp.configlog4net.config.

But no logging file got generated. What settings did I miss?

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

Updated on 4-March-2014

2014 年 3 月 4 日更新

If you are using a separate config file like I did (log4net.config), do remember to set the Copy to output directorysetting to Copy alwaysin the Solution Explorer

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

采纳答案by dekdev

By Design Log4Net is

按设计 Log4Net 是

fail-stop,we mean that log4net will not throw unexpected exceptions at run-time potentially causing your application to crash

故障停止,我们的意思是 log4net 不会在运行时抛出意外异常,这可能会导致您的应用程序崩溃

So it is very difficult to figure out what is causing the issue .

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

How do I enable log4net internal debugging?

如何启用 log4net 内部调试?

FROM FAQ - http://logging.apache.org/log4net/release/faq.html

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

  • Internal debugging can also be enabled by setting a value in the application's configuration file (not the log4net configuration file, unless the log4net config data is embedded in the application's config file). The log4net.Internal.Debug application setting must be set to the value true. For example:
  • 也可以通过在应用程序的配置文件(不是 log4net 配置文件,除非 log4net 配置数据嵌入在应用程序的配置文件中)中设置一个值来启用内部调试。log4net.Internal.Debug 应用程序设置必须设置为值 true。例如:
<?xml version="1.0" encoding="utf-8" ?> 
<configuration>
            <appSettings>
                <add key="log4net.Internal.Debug" value="true"/>
            </appSettings> 
</configuration>
<?xml version="1.0" encoding="utf-8" ?> 
<configuration>
            <appSettings>
                <add key="log4net.Internal.Debug" value="true"/>
            </appSettings> 
</configuration>

This setting is read immediately on startup an will cause all internal debugging messages to be emitted.

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

  • . To enable log4net's internal debug programmatically you need to set the log4net.Util.LogLog.InternalDebuggingproperty to true. Obviously the sooner this is set the more debug will be produced.
  • . 要以编程方式启用 log4net 的内部调试,您需要将log4net.Util.LogLog.InternalDebugging属性设置为 true。显然,设置得越早,产生的调试就越多。

So here is a custom class i created for log4Net - because config file was very confusing I created this helper class

所以这是我为 log4Net 创建的自定义类 - 因为配置文件非常混乱我创建了这个帮助类

  • you can initiate as many appender you need across the applications so if one dll call other dll both can initiate appenders and both appends will work.
  • also you can close the appender and ( as in case of file appender) then send it as a email
  • 您可以在应用程序中启动任意数量的 appender,因此如果一个 dll 调用另一个 dll,两个 dll 都可以启动 appender,并且两个 appends 都可以工作。
  • 您也可以关闭附加程序,然后(如文件附加程序)然后将其作为电子邮件发送
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); 

Do set this Property to True log4net.Util.LogLog.InternalDebugging=true;

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)
    {


    }
}

回答by Ofir

After checking and recheck... :-)

检查并重新检查后... :-)

All you need is to call XmlConfigurator.Configure();before you create the logger (only once).

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

Glad to help you,

很高兴帮助你,

Ofir

奥菲尔

回答by Alpay

If you will make a different configuration file and put log4net related things in it, then you will need to use [assembly: log4net.Config.XmlConfigurator(ConfigFile = @"...\log4net.config", Watch = true)]inside AssemblyInfo.csinstead of just

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

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

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

Otherwise, you have to put <log4net> ... </log4net>part of the configuration inside your App.config

否则,您必须将 <log4net> ... </log4net>部分配置放入App.config

回答by SteveM

Sorry if some of these seem obvious, but these are what I would check:

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

  • Make sure you have your log4net.config file properties Copy to Output set to Copy Always, verify by checking for the file in your bin directory

  • Also note from the log4net docs related to AssemblyInfo.cs properties:

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

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

Using attributes can be a clearer method for defining where the application's configuration will be loaded from. However it is worth noting that attributes are purely passive. They are information only. Therefore if you use configuration attributes you must invoke log4net to allow it to read the attributes. A simple call to LogManager.GetLogger will cause the attributes on the calling assembly to be read and processed. Therefore it is imperative to make a logging call as early as possible during the application start-up, and certainly before any external assemblies have been loaded and invoked.

使用属性可以是一种更清晰的方法,用于定义将从何处加载应用程序的配置。然而值得注意的是,属性是纯粹被动的。它们仅供参考。因此,如果您使用配置属性,则必须调用 log4net 以允许它读取属性。对 LogManager.GetLogger 的简单调用将导致读取和处理调用程序集上的属性。因此,必须在应用程序启动期间尽早进行日志记录调用,并且肯定在加载和调用任何外部程序集之前

  • To troubleshoot you might try switching from the assembly level property to an explicit configuration call

    XmlConfigurator.Configure();

    should be sufficient.

  • I always make log4net.config a full config file, starting with

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <configSections>
        <section name="log4net" 
           type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
      </configSections>
      <log4net>
    ...
      </log4net>
    </configuration>
    
  • 要进行故障排除,您可以尝试从程序集级别属性切换到显式配置调用

    XmlConfigurator.Configure();

    应该足够了。

  • 我总是让 log4net.config 成为一个完整的配置文件,从

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <configSections>
        <section name="log4net" 
           type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
      </configSections>
      <log4net>
    ...
      </log4net>
    </configuration>
    

You should not need anything in app.config related to log4net as long as your config file is log4net.config

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

回答by user2373845

log4net runs under the privileges of the active user. Make sure that the active user has rights to create/modify/delete the specified text file.

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

回答by l33tmike

When you say 'All Users' have full permissions to the log directory, does this include the service accounts?

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

Check that LocalService, NetworkService, LocalSystem etc have permissions (depending on what context the service is running).

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

Also, assuming you have a harness to run the service as an application, does logging work when running as your user?

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

If it doesn't run okay as an application, you've got a problem with the log4net config (which other answers have tried to address).

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

回答by Uri Abramson

Could you please upload you application so that i could debug it myself?

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

a few i recommend to check:

我建议检查一些:

  1. replace all the "\" in your file path to "\"

  2. put all the log4net config embedded in the application's config file.

  3. enable log4net debugging (see here)

  4. try a different configuration. just get a sample config for somewhere on the internet.

  5. just to be sure, i'd give maximum permissions for all users to your logging directory

  6. try to uninstall the service and reinstall it.

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

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

  3. 启用 log4net 调试(请参阅此处

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

  5. 可以肯定的是,我会为所有用户提供对您的日志目录的最大权限

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

回答by Deeptechtons

Here is the config that works for me.

这是对我有用的配置。

AssemblyInfo.cs

装配信息.cs

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

Log4net.Config

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# Code

C# 代码

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

I have this setup in C# Class library project and all other project uses this project reference to log the exceptions.

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

回答by shawtza

if you have a separate file for log4net.config. Have you set following property:

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

Copy to the output directory = Copy always

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

回答by YantingChen

Please note that when the process is run as Windows Service, Environment.CurrentDirectory will be "C:\Windows\system32"

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

So if you put the log4net configuration file (log4net.config) next to your *.exe, you can use the following code to configure log4net.

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

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