log4net,单独的进程,单独的RollingFileAppenders

时间:2018-04-10 11:22:47

标签: c# log4net

我们有一个Windows服务启动另一个名为ClusterProcess的进程。 我想从Windows服务和ClusterProcess获取日志,我希望这些日志转到数据库和文件。例如,如果数据库不可访问,我希望能够在文件中看到日志。

我有一个Log4Net设置的外部配置文件。有两个RollingFileAppender和两个AdoNetAppender。 有一个默认的根记录器和一个名为ClusterProcessLogger的附加记录器。

这个想法是Windows服务使用根记录器并记录到其中一个AdoNetAppenders和一个RollingFileAppender,并且ClusterProcess使用ClusterProcessLogger并记录到另一个AdoNetAppender和另一个RollingFileAppender。

两个案例的AdoNetAppenders都运行良好。 RollingFileAppenders没有。

所以这是log4net配置的外部配置文件:

<?xml version="1.0" encoding="utf-8" ?>
<log4net debug="true">

<appender name="RollingFileAppender" 
type="log4net.Appender.RollingFileAppender">
<file value="C:\Program Files\Sym\Logging\CalcEngineLog.txt"/>
<appendToFile value="true"/>
<rollingStyle value="Size"/>
<maxSizeRollBackups value="5"/>
<maximumFileSize value="10MB"/>
<staticLogFileName value="true"/>
<layout type="log4net.Layout.PatternLayout">
  <conversionPattern value="%date [%thread] %level %logger %location - 
%message%newline%exception"/>
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
  <levelMin value="DEBUG"/>
  <levelMax value="FATAL"/>
</filter>
<filter type="log4net.Filter.DenyAllFilter" />
</appender>

<appender name="SpecialRollingFileAppender" 
type="log4net.Appender.RollingFileAppender">
<file value="C:\Program Files\Sym\Logging\SpecialCalcEngineLog.txt"/>
<appendToFile value="true"/>
<rollingStyle value="Size"/>
<maxSizeRollBackups value="5"/>
<maximumFileSize value="10MB"/>
<staticLogFileName value="true"/>
<layout type="log4net.Layout.PatternLayout">
  <conversionPattern value="%date [%thread] %level %logger %location - 
%message%newline%exception"/>
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
  <levelMin value="DEBUG"/>
  <levelMax value="FATAL"/>
</filter>
<filter type="log4net.Filter.DenyAllFilter" />
</appender>

<appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
<!--<threshold value="Error" />-->
<bufferSize value="1" />
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data, 
Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<connectionString value="" />
<commandText value="INSERT INTO [Calculation Engine Log] ([Date],[Thread], 
[Level],[Logger],[Location],[Message],[Exception]) VALUES (@log_date, 
@thread, @log_level, @logger, @location, @message, @exception)" />
<parameter>
  <parameterName value="@log_date" />
  <dbType value="DateTime" />
  <layout type="log4net.Layout.RawTimeStampLayout" />
</parameter>
<parameter>
  <parameterName value="@thread" />
  <dbType value="String" />
  <size value="255" />
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%thread" />
  </layout>
</parameter>
<parameter>
  <parameterName value="@log_level" />
  <dbType value="String" />
  <size value="50" />
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%level" />
  </layout>
</parameter>
<parameter>
  <parameterName value="@logger" />
  <dbType value="String" />
  <size value="255" />
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%logger" />
  </layout>
</parameter>
<parameter>
  <parameterName value="@location" />
  <dbType value="String" />
  <size value="255" />
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%location" />
  </layout>
</parameter>
<parameter>
  <parameterName value="@message" />
  <dbType value="String" />
  <size value="4000" />
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%message" />
  </layout>
</parameter>
<parameter>
  <parameterName value="@exception" />
  <dbType value="String" />
  <size value="2000" />
  <layout type="log4net.Layout.ExceptionLayout" />
</parameter>
</appender>

<appender name="ClusterProcessAdoNetAppender" 
type="log4net.Appender.AdoNetAppender">
<bufferSize value="1" />
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data, 
Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<connectionString value="" />
<commandText value="INSERT INTO [ClusterProcess Calculation Engine Log] 
([Date],[Thread],[Level],[Logger],[Message],[Exception]) VALUES (@log_date, 
@thread, @log_level, @logger, @message, @exception)" />
<parameter>
  <parameterName value="@log_date" />
  <dbType value="DateTime" />
  <layout type="log4net.Layout.RawTimeStampLayout" />
</parameter>
<parameter>
  <parameterName value="@thread" />
  <dbType value="String" />
  <size value="255" />
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%thread" />
  </layout>
</parameter>
<parameter>
  <parameterName value="@log_level" />
  <dbType value="String" />
  <size value="50" />
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%level" />
  </layout>
</parameter>
<parameter>
  <parameterName value="@logger" />
  <dbType value="String" />
  <size value="255" />
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%logger" />
  </layout>
</parameter>
<parameter>
  <parameterName value="@message" />
  <dbType value="String" />
  <size value="4000" />
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%message" />
  </layout>
</parameter>
<parameter>
  <parameterName value="@exception" />
  <dbType value="String" />
  <size value="2000" />
  <layout type="log4net.Layout.ExceptionLayout" />
</parameter>
</appender>

<logger name="ClusterProcessLogger" additivity="false">
<level value="Debug" />
<appender-ref ref="ClusterProcessAdoNetAppender" />
<appender-ref ref="SpecialRollingFileAppender" />
</logger>

<root>
<level value="Debug"/>
<appender-ref ref="AdoNetAppender"/>
<appender-ref ref="RollingFileAppender"/>
</root>

</log4net>

以下是Windows服务的主要方法:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.ServiceProcess;
    using System.Text;
    using System.IO;
    using System.Globalization;
    using Sym.Core.Culture;
    using System.Threading;


    namespace Sym.WindowsService
    {
        static class Program
        {

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

            static void Main()
            {
                if (!log4net.LogManager.GetRepository().Configured)
                {
                    log4net.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo("C:\\Program Files\\Sym\\bin\\Log4NetSettingsGlobal.xml"));
                }

                log.Debug("Culture info before change: " + Thread.CurrentThread.CurrentCulture.Name);

                ...

            }
        }
    }

以下是Windows服务的App.config:

    <?xml version="1.0"?>
    <configuration>
      <appSettings>
        <add key="ConfigPath" value="C:\Program Files\Sym\Configs\Example.config"/>
        <add key="log4net.Internal.Debug" value="true"/>
      </appSettings>
      <system.diagnostics>
        <trace autoflush="true">
          <listeners>
            <add
                name="textWriterTraceListener"
                type="System.Diagnostics.TextWriterTraceListener"
                initializeData="C:\Program Files\Sym\Logging\Log4Net_Trace_WindowsServer.txt" />
          </listeners>
        </trace>
      </system.diagnostics>
    <startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>

对于ClusterProcess项目,这是Main方法:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Sym.Core.Config;
    using Sym.Clustering.Framework;
    using System.Diagnostics;
    using Sym.Core.Services;
    using System.Reflection;
    using System.IO;
    using log4net.Repository.Hierarchy;
    using log4net;
    using log4net.Appender;
    using System.Configuration;
    using System.Collections.Specialized;
    using Sym.Core.Log4Net;
    using log4net.Config;


    namespace Sym.Clustering.ClusterProcess
    {
        class Program
        {
            private static  ClusterProcessor _ClusterProcessor ;       
            private static SelectedConfiguration _Config;

            private static readonly log4net.ILog log = log4net.LogManager.GetLogger("ClusterProcessLogger");

            static void Main(string[] args)
            {
                try 
                {
                    ...                         

                    try
                    {
                        log4net.Config.XmlConfigurator.Configure(); 
                        if (!log4net.LogManager.GetRepository().Configured)
                        {
                            log4net.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo("C:\\Program Files\\Sym\\bin\\Log4NetSettingsGlobal.xml"));
                        }
                        Log4NetConfiguration.ConfigureLog4Net(_Config); // Load connection strings
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e);
                    }

                    log.Debug("ClusterProcess using DatabaseName: " + config.Database.DatabaseName);

                    ...
                }
                catch(Exception exp)
                {
                    log.Error(exp.Message, exp);
                }

            }       
        }
    }

这是ClusterProcess项目的App.config:

        <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <appSettings>
        <add key="log4net.Internal.Debug" value="true"/>
      </appSettings>
      <system.diagnostics>
        <trace autoflush="true">
          <listeners>
            <add
                name="textWriterTraceListener"
                type="System.Diagnostics.TextWriterTraceListener"
                initializeData="C:\Program Files\Sym\Logging\Log4Net_Trace_ClusterProcess.txt" />
          </listeners>
        </trace>
      </system.diagnostics>


    </configuration>

在ClusterProcess的log4net跟踪中,给出了以下错误:

  

log4net:ERROR无法在应用程序的.config文件中找到配置节'log4net'。检查.config文件中的<log4net><configSections>元素。配置部分应如下所示:

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

log4net:ERROR [RollingFileAppender] ErrorCode:GenericFailure。无法获取文件C:\ Program Files \ Sym \ Logging \ SpecialCalcEngineLog.txt上的锁定。该进程无法访问文件'C:\ Program Files \ Sym \ Logging \ SpecialCalcEngineLog.txt',因为它正由另一个进程使用。

     

log4net:ERROR [RollingFileAppender] ErrorCode:GenericFailure。无法获取文件C:\ Program Files \ Sym \ Logging \ CalcEngineLog.txt上的锁定。该进程无法访问文件'C:\ Program Files \ Sym \ Logging \ CalcEngineLog.txt',因为它正由另一个进程使用。

我不知道如何处理第一个错误。 第二个和第三个错误不应该存在。 ClusterProcess应该能够访问SpecialCalcEngineLog.txt,它不应该被CalcEngineLog.txt打扰,因为那是Windows服务正在使用的RollingFileAppender。

如何解决这些错误?我在俯瞰什么?

1 个答案:

答案 0 :(得分:0)

添加

可以缓解第一个错误
No Tests were found

的某个地方。

多个RollingFileAppenders无法写入同一文件。但是,您可以区分,例如,将进程ID添加到文件名(然后从所有进程收集日志):

<configSections>
    <section name="log4net" type="System.Configuration.IgnoreSectionHandler" />
</configSections>