Windows服務使用log4net記錄日誌

repeatedly發表於2019-05-13

該文章是系列文章 基於.NetCore和ABP框架如何讓Windows服務執行Quartz定時作業 的其中一篇。

比較流行的日誌元件有以下四種,Topshelf都有相應的元件提供

本篇文章主要介紹log4net的使用。
使用Topshelf建立Windows服務中提到了當我們除錯的時候Console會列印出如下的類似日誌

Configuration Result:
[Success] Name Demo.MyJob
[Success] Description Demo.MyJob Service
[Success] ServiceName Demo.MyJob
Topshelf v4.2.0.194, .NET Framework v4.0.30319.42000
The Demo.MyJob service is now running, press Control+C to exit.

該日誌是如何列印出來的呢?
訪問Topshelf Github的原始碼,在HostFactory.cs檢視Run執行邏輯,日誌列印是通過呼叫HostLogger.Get(Type type) 方法獲取了LogWriter,LogWriter是寫日誌介面。檢視HostLogger.cs,可以看到LogWriter的預設實現,該實現包含有三個類TraceHostLoggerConfigurator.cs 繼承介面HostLoggerConfiguratorTraceLogWriterFactory.cs 繼承介面LogWriterFactoryTraceLogWriter.cs 繼承介面LogWriter
如果我們需要實現log4net的日誌訪問,則需要實現三個類Log4NetLoggerConfigurator、Log4NetLoggerConfigurator、Log4NetLogWriter。我們可以自己實現,也可以使用Topshelf提供的實現,需要引用nuget包Topshelf.Log4Net。在Run執行邏輯新增UseLog4Net,如下所示。

        public override void PostInitialize()
        {
            HostFactory.Run(configure =>
            {
                //定義服務描述
                configure.SetDescription("Demo.MyJob Service");
                configure.SetDisplayName("Demo.MyJob");
                configure.SetServiceName("Demo.MyJob");

                configure.RunAsLocalSystem();

                //使用log4net記錄日誌
                configure.UseLog4Net("App.config");

                //定義操作
                configure.Service<MyJobService>(service =>
                {
                    service.ConstructUsing(_ => new MyJobService());
                    service.WhenStarted(async _ => await _.StartAsync());
                    service.WhenStopped(async _ => await _.StopAsync());
                    service.WhenContinued(async _ => await _.ContinueAsync());
                    service.WhenPaused(async _ => await _.PauseAsync());
                });
            });
        }

在上述程式碼中可知,我們需要新增自己的配置檔案,對log4net進行配置。注意:需將新增的配置檔案的屬性配置為如果較新則複製。因為UseLog4Net關於載入配置檔案的邏輯,是載入當前應用目錄下的指定名稱的檔案。
更多關於log4net的配置請訪問:https://logging.apache.org/log4net/release/manual/configuration.html

未使用log4net列印日誌時,列印出來的日誌是黑底白字,我們可以通過log4net配置改變列印字型的顏色,使用ManagedColoredConsoleAppender,也可以通過RollingFileAppender在本地機器生成log日誌檔案。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <log4net>
    <appender name="ManagedColoredConsoleAppender" type="log4net.Appender.ManagedColoredConsoleAppender">
      <mapping>
        <level value="ERROR" />
        <foreColor value="Red" />
      </mapping>
      <mapping>
        <level value="Info" />
        <foreColor value="Green" />
      </mapping>
      <mapping>
        <level value="DEBUG" />
        <foreColor value="Blue" />
      </mapping>
      <mapping>
        <level value="WARN" />
        <foreColor value="Yellow" />
      </mapping>
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%d{ABSOLUTE} [%thread] %-5p %c{1}:%L - %m%n" />
      </layout>
      <filter type="log4net.Filter.LevelRangeFilter">
        <param name="LevelMin" value="DEBUG" />
        <param name="LevelMax" value="Fatal" />
      </filter>
    </appender>
    <appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
      <file value=".\logs\" />
      <datePattern value="'my-windows-service-'dd.MM.yyyy'.log'" />
      <staticLogFileName value="false" />
      <appendToFile value="true" />
      <rollingStyle value="Composite" />
      <maxSizeRollBackups value="10" />
      <maximumFileSize value="5MB" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%d [%t] %-5p %c - %m%n" />
      </layout>
    </appender>
    <root>
      <level value="DEBUG" />
      <appender-ref ref="ManagedColoredConsoleAppender" />
      <appender-ref ref="RollingFile" />
    </root>
  </log4net>
</configuration>

在配置檔案中使用了<file value=".\logs\" />指定了檔案生成相對路徑,該相對路徑應指向的是應用程式當前目錄下,該目錄下確實生成了日誌檔案,但是很不爽的是在C:\Windows\System32路徑下也生成了檔案。怎麼解決該問題?通過log4net屬性指定目錄。
修改<file type="log4net.Util.PatternString" value="%property{LogsDirectory}\logs\" />,並需要新增一行配置程式碼log4net.GlobalContext.Properties["LogsDirectory"] = AppDomain.CurrentDomain.BaseDirectory;,如下所示。問題解決。

        public override void PostInitialize()
        {
            log4net.GlobalContext.Properties["LogsDirectory"] = AppDomain.CurrentDomain.BaseDirectory;

            HostFactory.Run(configure =>
            {
                //定義服務描述
                configure.SetDescription("Demo.MyJob Service");
                configure.SetDisplayName("Demo.MyJob");
                configure.SetServiceName("Demo.MyJob");

                configure.RunAsLocalSystem();

                //使用log4net記錄日誌
                configure.UseLog4Net("App.config");

                //定義操作
                configure.Service<MyJobService>(service =>
                {
                    service.ConstructUsing(_ => new MyJobService());
                    service.WhenStarted(async _ => await _.StartAsync());
                    service.WhenStopped(async _ => await _.StopAsync());
                    service.WhenContinued(async _ => await _.ContinueAsync());
                    service.WhenPaused(async _ => await _.PauseAsync());
                });
            });
        }

相關文章