一.常规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(); } } }