Пользовательский PatternLayout для определенного регистратора вызывается на GetLogger <T>(); - PullRequest
0 голосов
/ 11 января 2019

Я пытаюсь создать новый appender для журнала в формате W3C.

Моему макету appender нужен собственный заголовок. Итак, я наследую класс PatternLayout так:


    using System;
    using System.Diagnostics;
    using System.Text;
    using log4net.Layout;

    namespace MyApp.Framework.Logging
    {
        public class W3CLayout : PatternLayout
        {
            public override string Header
            {
                get { return buildW3CLogHeader(); }
                set {  }
            }

            private string buildW3CLogHeader()
            {
                var header = new StringBuilder();

                header.AppendLine("#Software: " + ConfigurationSettings.ProductName + " " + ConfigurationSettings.Product + " " + ConfigurationSettings.Version);
                header.AppendLine("#Version: 1.0 // Reference: http://www.w3.org/TR/WD-logfile");
                header.AppendLine("#Date: " + DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss"));
                header.AppendLine("#Fields: date time cs-host cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent) cs(Referer) sc-status time-taken");

                return header.ToString();
            }
        }
    }

и мой в web.config:

...  the rest of the web.config ...

    <log4net>
        <appender name="ServicesLogAppender" type="MyApp.Framework.Logging.ConsumerLoggingAppender, MyApp.Framework">
          <param name="File" value="web-services.log" />
          <param name="MaximumFileSize" value="20MB" />
          <param name="MaxSizeRollBackups" value="3" />
          <param name="StaticLogFileName" value="false" />
          <param name="Threshold" value="ALL" />
          <param name="RollingStyle" value="Size" />
          <param name="appendToFile" value="true" />
          <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
          <layout type="log4net.Layout.PatternLayout">
            <conversionPattern value="%date [%thread,%a] %-5level %logger - %message%newline" />
          </layout>
        </appender>
        <appender name="OutgoingServicesLogAppender" type="MyApp.Framework.Logging.ConsumerLoggingAppender, MyApp.Framework">
          <param name="File" value="outgoing-web-services.log" />
          <param name="MaximumFileSize" value="21MB" />
          <param name="MaxSizeRollBackups" value="3" />
          <param name="StaticLogFileName" value="false" />
          <param name="Threshold" value="ALL" />
          <param name="RollingStyle" value="Size" />
          <param name="appendToFile" value="true" />
          <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
          <layout type="MyApp.Framework.Logging.W3CLayout, MyApp.Framework">
            <conversionPattern value="%message%newline" />
          </layout>
        </appender>
        <root>
          <level value="WARN" />
          <appender-ref ref="ServicesLogAppender" />
        </root>
        <logger name="ServicesLogger">
          <level value="INFO" />
        </logger>
        <logger name="MyCompany">
          <level value="INFO" />
        </logger>
        <logger name="MyApp">
          <level value="INFO" />
        </logger>
        <logger name="OutgoingServices" additivity="false">
          <level value="INFO" />
          <appender-ref ref="OutgoingServicesLogAppender" />
        </logger>
      </log4net>
    ...  the rest of the web.config ...

Проблема, с которой я сталкиваюсь, - это когда программа вызывает GetLogger<T>(), как показано ниже в программе,


    namespace MyApp.WebUI
    {
        public class Global : System.Web.HttpApplication
        {
            private static readonly ILog _log = LogManager.GetLogger<Global>();

            private void Application_Start(object sender, EventArgs e)
            {
                // This will write a log to web-services.log
                _log.Info("Starting Application_Start");

            }
       }
    }

Вместо простого вызова ServicesLogAppender appender, он также инициализирует MyApp.Framework.Logging.W3CLayout Свойства заголовка. Это вызывает проблему, потому что, когда я собираюсь использовать OutgoingServices appender, он записывает журнал дважды. Смотрите ниже:


    namespace MyApp.Domain.WorkOrder
    {
        public abstract class AbstractStatusChangeNotifier
        {
            private static readonly ILog Logger = LogManager.GetLogger("OutgoingServices");

            public void DoWork(){
               Logger.Info("This log will show up twice");
            }
        }
    }

Файл журнала, созданный для web-services.log:


    2019-01-10 17:00:51,674 [81,/LM/W3SVC/1/ROOT/MyApp-5-131916312513450449] INFO  Myapp.WebUI.Global - Starting Application_Start

Файл журнала, сгенерированный для outgoing-web-services.log:


    #Software: MyApp 257.14.0.0 
    #Version: 1.0 // Reference: http://www.w3.org/TR/WD-logfile
    #Date: 2019-01-10 21:46:48
    #Fields: date time cs-host cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent) cs(Referer) sc-status time-taken
    This log will show up twice
    #Software: MyApp 257.14.0.0
    #Version: 1.0 // Reference: http://www.w3.org/TR/WD-logfile
    #Date: 2019-01-10 21:58:54
    #Fields: date time cs-host cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent) cs(Referer) sc-status time-taken
    This log will show up twice

Похоже, что у приложения есть дублирующий регистратор (потому что W3CLayout вызывается дважды), и он записывает в один и тот же файл дважды. Как предотвратить GetLogger () для запуска W3CLayout PatternLayout? Или что-то, что я пропустил по web.config?

1 Ответ

0 голосов
/ 14 января 2019
namespace MyApp.Framework.Logging
    {
        public class W3CLayout : PatternLayout
        {
            public override string Header
            {
                get { return buildW3CLogHeader(); }
                set {  }
            }

            private string buildW3CLogHeader()
            {
                var header = new StringBuilder();

                header.AppendLine("#Software: " + ConfigurationSettings.ProductName + " " + ConfigurationSettings.Product + " " + ConfigurationSettings.Version);
                header.AppendLine("#Version: 1.0 // Reference: http://www.w3.org/TR/WD-logfile");
                header.AppendLine("#Date: " + DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss"));
                header.AppendLine("#Fields: date time cs-host cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent) cs(Referer) sc-status time-taken");

                return header.ToString();
            }
        }
    }

В приведенном выше классе я вызвал ConfigurationSettings.ProductName, который инициализирует другой экземпляр log4net. Я должен быть осторожен, чтобы не вызывать private static ILog _log = LogManager.GetLogger<ClassName>(); в любом месте при использовании унаследованного класса.

...