一.常規Log4Net開發
在.net開發上關於日志方面輸出大多數都是使用Log4Net類庫進行開發,大家在配置Log4Net的配置文件時一般都可以查到如下配置,一般復制下來就可以使用。
<appender name="ErrorAppender" type="log4net.Appender.RollingFileAppender"> <!-- name屬性指定其名稱,type則是log4net.Appender命名空間的一個類的名稱,意思是,指定使用哪種介質--> <param name="File" value="Log\\LogError\\" /> <!-- 輸出到什么目錄--> <param name="AppendToFile" value="true" /><!-- 是否覆寫到文件中--> <param name="MaxSizeRollBackups" value="100" /><!-- 備份文件的個數--> <param name="MaxFileSize" value="10240" /><!-- 單個日志文件最大的大小--> <param name="StaticLogFileName" value="false" /><!-- 是否使用靜態文件名--> <param name="DatePattern" value="yyyyMMdd".htm"" /><!-- 日志文件名--> <param name="RollingStyle" value="Date" /> <!--布局--> <layout type="log4net.Layout.PatternLayout"> <param name="ConversionPattern" value="<HR COLOR=red>%n異常時間:%d [%t] <BR>%n異常級別:%-5p <BR>%n異 常 類:%c [%x] <BR>%n%m <BR>%n <HR Size=1>" /> </layout> </appender>
在之前的使用過程中對上述配置的實用性並沒有質疑,也沒有太多測試,只知道在運行之后的確是有日志輸出,OK,上線使用...
二.測試
但最近又一次有新項目使用到Log4Net,突然對上述配置的單文件大小(MaxFileSize)和備份文件個數(MaxSizeRollBackups)是否生效了產生懷疑,所以做了一系列測試。
<appender name="ErrorAppender" type="log4net.Appender.RollingFileAppender"> <!-- name屬性指定其名稱,type則是log4net.Appender命名空間的一個類的名稱,意思是,指定使用哪種介質--> <param name="File" value="Log\\LogError\\" /> <!-- 輸出到什么目錄--> <param name="AppendToFile" value="true" /><!-- 是否覆寫到文件中--> <param name="MaxSizeRollBackups" value="10" /><!-- 備份文件的個數,最多備份數量設置為5個--> <param name="MaxFileSize" value="10" /><!-- 單個日志文件最大的大小,單個日志最大為10kb--> <param name="StaticLogFileName" value="false" /><!-- 是否使用靜態文件名--> <param name="DatePattern" value="yyyyMMdd".htm"" /><!-- 日志文件名--> <param name="RollingStyle" value="Date" /> <!--布局--> <layout type="log4net.Layout.PatternLayout"> <param name="ConversionPattern" value="<HR COLOR=red>%n異常時間:%d [%t] <BR>%n異常級別:%-5p <BR>%n異 常 類:%c [%x] <BR>%n%m <BR>%n <HR Size=1>" /> </layout> </appender>
測試代碼:
for (int i = 0; i < 10000000; i++) { Logger.Info($"ID={i}"); }
測試結果:140MB也沒有創建新日志文件,失敗...
三.解決辦法
沒想出什么問題和解決方案來,把Log4Net源碼拉出來看了一圈,調試了幾遍發現有如下部分很重要,也是常被人忽略的部分,
在RollingFileAppender類里RollingStyle有兩個私有字段
- m_rollDate代表時間滾動記錄標識,在其為true的時候進行判斷是否超過一定時間后創建新文件繼續記錄日志
- m_rollSize代表文件滾動記錄標識 ,在其為true的時候進行判斷是否日志文件超過一定大小后創建新文件繼續記錄日志
這兩個字段的賦值主要看RollingStyle的值,RollingStyle參數類型為RollingMode枚舉類型,其包含四個枚舉值:
- Once 代表只負責記錄,不考慮文件大小和日期
- Size 代表只判斷文件大小進行日志新文件創建輸出
- Date 代表只判斷日期間隔進行日志新文件創建輸出
- Composite 代表對文件大小和日期間隔都需要進行判斷並創建新文件輸出
原因:不要只抄別人寫好的就去用,要看看原理,RollingStyle賦值很重要,別人寫好的一般都是寫Date,而在配置文件中沒有對Date進行設置,所以P用沒有,將RollingStyle設置為Size或Composite后上述文件大小管理才會生效。
最后:貼出這部分源碼看看,如下:
public RollingMode RollingStyle { get { return m_rollingStyle; } set { m_rollingStyle = value; switch (m_rollingStyle) { case RollingMode.Once: m_rollDate = false; m_rollSize = false; this.AppendToFile = false; break; case RollingMode.Size: m_rollDate = false; m_rollSize = true; break; case RollingMode.Date: m_rollDate = true; m_rollSize = false; break; case RollingMode.Composite: m_rollDate = true; m_rollSize = true; break; } } }
判斷是否創建新日志文件進行記錄的方法AdjustFileBeforeAppend:
virtual protected void AdjustFileBeforeAppend() { if (m_rollDate) { DateTime n = m_dateTime.Now; if (n >= m_nextCheck) { m_now = n; m_nextCheck = NextCheckDate(m_now, m_rollPoint); RollOverTime(true); } } if (m_rollSize) { if ((File != null) && ((CountingQuietTextWriter)QuietWriter).Count >= m_maxFileSize) { RollOverSize(); } } }