在同一数据库上具有两个不同实例的Log4net

时间:2018-07-11 20:24:07

标签: c# log4net

我前一段时间使用log4net设置日志记录,只是没有想到特定的情况。

目前,我有一个全局配置文件。有一个RollingFileAppender和一个AdonetAppender。

当程序的一个实例仅在数据库上运行时,则一切正常。 有时,两个稍有不同的实例可能会在同一数据库上运行。附加程序记录来自两个实例的消息,但是通常(在公共代码中)无法分辨消息是从哪个实例发出的。当然,我可以将实例名称添加到消息中或其他内容,但这似乎是不得已的方法。

我的大脑就像雾。我认为解决方案应该很简单,但是我想不出什么是最好的。

我可以创建另一个追加程序,并在运行时根据实例名称使用哪个追加程序“切换”吗?

这是配置文件:

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

  <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
    <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
    <file value="D:\Medupi logs\CalcEngineLog.txt"/>
    <appendToFile value="true"/>
    <rollingStyle value="Size"/>
    <maxSizeRollBackups value="2"/>
    <maximumFileSize value="4MB"/>
    <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="Warn" /> -->
    <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>  

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

</log4net>

这是在启动项目中的配置方式:

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\\Symplexity\\bin\\Log4NetSettingsGlobal.xml"));
        }
        ...
    }

其他信息

在生产中,将启动Windows服务,这将检查必须在群集上运行其实例的配置文件。

每个实例都有一个单独的过程:

foreach (var cluster in clusters) 
        {
        ProcessStartInfo startInfo = new ProcessStartInfo
            {
                CreateNoWindow = true,
                FileName = processFileName,

                WindowStyle = ProcessWindowStyle.Hidden,
                Arguments = string.Format("\"{0}\" \"{1}\"", cluster.Name, _ConfigPath)
            };

            _ClusterProcesses.Add(Process.Start(startInfo));               
        }

我假设我可以将appIdentifier(根据评论)添加到Arguments的{​​{1}}中?

1 个答案:

答案 0 :(得分:2)

首先确定2个应用程序实例。
最简单的方法是使用唯一的命令行参数启动每个应用程序实例。
通过例如启动第一个实例。 .cmd文件为MyApplication.exe instance1,第二个文件为MyApplication.exe instance2
从方法args的{​​{1}}参数中读取此参数值。

Main

现在您有多种选择。

选项1:两个实例的共享Log4net配置

static void Main(String[] args) { String appIdentifier = args[0]; // ... } 分配给appIdentifier
使用范围取决于您的情况,请参见the Log4net documentation

Log4net context property

RollingFileAppender

通过log4net.GlobalContext.Properties["appIdentifier"] = appIdentifier; 将此上下文属性包括在layout的{​​{1}}中。 现在,每个记录的行将包含相应的RollingFileAppender值'instance1'或'instance2'。

%property{appIdentifier}

AdoNetAppender

首先请确保您要登录的表包含用于存储appIdentifier值的列, 例如。列<layout type="log4net.Layout.PatternLayout"> <conversionPattern value="... %property{appIdentifier} ..."/> </layout>

使用额外的参数扩展appIdentifier的配置以匹配appIdentifier VARCHAR(25)属性。

AdoNetAppender

用相应的列名和参数扩展appIdentifier语句。

<parameter>
    <parameterName value="@appIdentifier"/>
    <dbType value="String" />
    <size value="25" />
    <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%property{appIdentifier}" />
    </layout>
</parameter>

选项2:每个实例的单独Log4net配置文件

这不是选项1,而是选项。

通过将文件名与SQL INSERT命令行参数进行匹配,为每个实例创建一个单独的INSERT INTO [Calculation Engine Log] ([Date],[Thread],[Level],[Logger],[Location],[Message],[Exception],[appIdentifier]) VALUES (@log_date, @thread, @log_level, @logger, @location, @message, @exception, @appIdentifier) 配置文件。

xml

RollingFileAppender

为每个实例配置一个单独的输出文件路径。

例如1

appIdentifier

例如2

log4net.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo("C:\\Program Files\\Symplexity\\bin\\" + appIdentifier + '.xml'));

AdoNetAppender

有关如何设置列以存储<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender"> ... <file value="D:\Medupi logs\Instance1.txt"/> ... </appender> 的信息,请参阅选项1。
<file value="D:\Medupi logs\Instance2.txt"/> 语句中包含一个常量值作为标识符。

appIdentifier

在实例2的SQL INSERT配置文件中执行相同的操作,值为'Instance2'。


选项3:单个命名记录器

如果您在整个应用程序中仅使用一个INSERT INTO [Calculation Engine Log] ([Date],[Thread],[Level],[Logger],[Location],[Message],[Exception],[appIdentifier]) VALUES (@log_date, @thread, @log_level, @logger, @location, @message, @exception, 'Instance1') 实例,请使用xml的值按名称检索它。

ILog的{​​{1}}和appIdentifier标记的%logger标记将分别包含值'Instance1'或'Instance2'。

我不喜欢使用单个记录器,但是我经常看到这种做法。

RollingFileAppender

选项4:RollingFileAppender的参数化文件名

这是 @logger 的替代选项,仅将其与上述 AdoNetAppender的选项之一结合使用。

按照选项1中的说明设置private static log4net.ILog log; static void Main(String args) { String appIdentifier = args[0]; if (!log4net.LogManager.GetRepository().Configured) { log4net.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo("C:\\Program Files\\Symplexity\\bin\\Log4NetSettingsGlobal.xml")); log = log4net.LogManager.GetLogger(appIdentifier); } // ... }
可以在RollingFileAppender的输出文件的路径中包含这样的AdoNetAppender

这样做将分别生成文件“ Instance1.log”或“ Instance2.log”。
(除了更改文件名之外,您还可以将其应用于(子)文件夹名称。)

如果您遇到或担心锁定和/或性能问题,最好不要在同时运行的多个pepe应用程序实例之间共享相同的输出文件。 < / p>

Log4net context property