真正運行時修改log4net多個Appender的存儲路徑

問題說明

配置文件示例

在Net程序中,經常使用log4net存儲日誌文件,下面是一個log4net配置文件的示例,文件名爲log.config。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<log4net>
  <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender" >
    <lockingModel type="log4net.Appender.FileAppender+MinimalLock"/>
    <file value="Logs/App_" />
    <datePattern value="yyyyMMdd.'txt'"/>
    <appendToFile value="true" />
    <!--<rollingStyle value="Date" />-->
    <staticLogFileName value="false"/>
    <rollingStyle value="Date" />
    <maxSizeRollBackups value="10"/>
    <maximumFileSize value="1MB"/>
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%-5level - %date - [%-5.5thread] - %logger - [%class.%method] - %f - %l %message%newline" />
    </layout>
  </appender>

  <appender name="PlcAppender" type="log4net.Appender.RollingFileAppender" >
    <lockingModel type="log4net.Appender.FileAppender+MinimalLock"/>
    <file value="Logs/Plc_" />
    <datePattern value="yyyyMMdd HH.'txt'"/>
    <appendToFile value="true" />
    <rollingStyle value="Composite" />
    <staticLogFileName value="false"/>
    <maxSizeRollBackups value="10"/>
    <maximumFileSize value="1MB"/>
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%-5level - %date - [%-5.5thread] - %logger - [%class.%method] - %f - %l %message%newline" />
    </layout>
  </appender>

  <appender name="DebugAppender" type="log4net.Appender.RollingFileAppender" >
    <lockingModel type="log4net.Appender.FileAppender+MinimalLock"/>
    <file value="Logs/Debug_" />
    <datePattern value="yyyyMMdd.'txt'"/>
    <appendToFile value="true" />
    <!--<rollingStyle value="Date" />-->
    <staticLogFileName value="false"/>
    <rollingStyle value="Composite" />
    <maxSizeRollBackups value="10"/>
    <maximumFileSize value="1MB"/>
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%-5level - %date - [%-5.5thread] - %logger - [%class.%method] - %f - %l %message%newline" />
    </layout>
  </appender>
    
  <appender name="DbAppender" type="log4net.Appender.RollingFileAppender" >
    <lockingModel type="log4net.Appender.FileAppender+MinimalLock"/>
    <file value="Logs/Db_" />
    <datePattern value="yyyyMMdd.'txt'"/>
    <appendToFile value="true" />
    <staticLogFileName value="false"/>
    <rollingStyle value="Composite" />
    <maxSizeRollBackups value="10"/>
    <maximumFileSize value="1MB"/>
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%-5level - %date - [%-5.5thread] - %logger - [%class.%method] - %f - %l %message%newline" />
    </layout>
  </appender>  
  
  <!--<root>
    <appender-ref ref="RollingFileAppender" />
    <level value="DEBUG" />
  </root>-->
  <logger name="AppLogger" additivity="false">
    <level value="ALL" />
    <appender-ref ref="RollingFileAppender" />
  </logger>
  <!--PLC日誌-->
  <logger name="PlcLogger" additivity="false">
    <level value="ALL" />
    <!--<appender-ref ref="RollingFileAppender" />-->
    <appender-ref ref ="PlcAppender"/>
  </logger>
  <!-- 調試日誌-->
  <logger name="DebugLogger" additivity="false">
    <level value="ALL" />
    <appender-ref ref ="DebugAppender"/>
  </logger>
  
  <!-- 數據庫日誌-->
  <logger name="DbLogger" additivity="false">
    <level value="ALL" />
    <appender-ref ref ="DbAppender"/>
  </logger>  
    
</log4net>
</configuration>

從配置文件可以看出來,有4個Appender,軟件會建立4個日誌文件,路徑都在Logs/文件夾下,通常這個Logs文件夾在主程序所在路徑下。要注意的是每個日誌文件的文件名不同,例如DbAppender的日誌文件名爲Db_xxxx.txt,而DebugAppender的日誌文件名爲Debug_xxxx.txt。

修改存儲路徑

如果用戶想改變這個路徑到其它位置該怎麼辦呢?
方法1:修改這個配置文件log.config裏邊的每個Appender的配置;
方法2:在軟件運行時動態修改Appender的參數。
網上最典型的修改文件名的辦法,非常好,缺點是不夠徹底。
下面的例子引用自https://blog.csdn.net/yw1688/article/details/52590072

/// <summary>
        /// 改變默認的日誌位置
        /// </summary>
        /// <param name="folder"></param>
        public static void UpdateFolder(string folder)
        {
            var storedPath = LogManager.GetRepository();
            var appenders = storedPath.GetAppenders();
            //一般多種日誌目錄是寫在一起
            if (appenders == null) return;
            foreach (var app in appenders)
            {
                if (app.Name.Equals("ErrorAppender") || app.Name.Equals("InfoAppender"))
                {
                    var ra = app as RollingFileAppender;
                    ra.File = folder;
                    ra.ActivateOptions();
                }
            }
        }

這個例子的結果是,所有Appender的存儲文件名變成同一個,因此不是修改存儲路徑,而是修改存儲文件名。

修改多個Appender的存儲路徑

沒有datePattern設置的情況

下面是本篇在上述原理基礎上的改進。

        public static void ChangeDir(string configFile,string newDir)
        {
            XmlConfigurator.Configure(new FileInfo(configFile));
            var curPath = LogManager.GetRepository();
            var appenders = curPath.GetAppenders();
            if (appenders == null)
                return;
            foreach (var appender in appenders)
            {
                var rollingFileAppender = appender as RollingFileAppender;
                if(rollingFileAppender == null)
                    continue;
                var oldPath = rollingFileAppender.File;
                var oldFile = Path.GetFileName(oldPath);
                if(oldFile == null)
                    continue;
                var newFile = Path.Combine(newDir, oldFile);
                rollingFileAppender.File = newFile;
                rollingFileAppender.ActivateOptions();
            }
        }

調用方法如下。

LogHelper.ChangeDir("Log.config",newDir);

有datePattern設置的情況

本篇的log4net的配置文件中由於有datePattern配置,修改日誌路徑要用如下方法。

 public static void ChangeDir(string configFile,string newDir)
        {
            XmlConfigurator.Configure(new FileInfo(configFile));
            var curPath = LogManager.GetRepository();
            var appenders = curPath.GetAppenders();
            if (appenders == null)
                return;
            foreach (var appender in appenders)
            {
                var rollingFileAppender = appender as RollingFileAppender;
                if(rollingFileAppender == null)
                    continue;
                var oldPath = rollingFileAppender.File;
                var oldFile = Path.GetFileName(oldPath);
                if(oldFile == null)
                    continue;
                var newFile = Path.Combine(newDir, oldFile);

                rollingFileAppender.Writer = new StreamWriter(newFile, rollingFileAppender.AppendToFile,rollingFileAppender.Encoding);
            }
        }

即不能用修改appender的File屬性,而是,直接指定Writer屬性的內容。

修改配置文件方法

有些複雜datepattern,修改後,log4net會在file屬性的值變了後,又恢復的配置文件的file的設置模式,因此最徹底的方法還是修改xml文件。
代碼如下。

        public static void ChangeDirXml(string configFile, string newDir)
        {

            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(configFile);
            XmlNode nodes= xmlDoc.SelectSingleNode("configuration");
            var appenderNodes = nodes.ChildNodes[0];
            foreach (XmlNode xn in appenderNodes)
            {
                if (xn.Name == "appender")
                {
                    foreach (XmlNode ele in xn)
                    {
                        if (ele.Name == "#comment")
                            continue;
                        
                        XmlElement xe = (XmlElement)ele;
                        if (xe.Name != "file")
                        {
                            continue;
                            
                        }
                        var oldFileValue = xe.GetAttribute("value");
                        var oldFile = Path.GetFileName(oldFileValue);
                        if (oldFile == null)
                            continue;
                        var newFile = Path.Combine(newDir, oldFile);

                        xe.SetAttribute("value", newFile);                       
                    }
                }
                
            }
            xmlDoc.Save(configFile);

            XmlConfigurator.Configure(new FileInfo(configFile));

        }

本人親自測試沒毛病。歡迎各位批評指正。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章