一. 目标
- 1. 项目中使用log4net进行日志显示
- 2. 过期日志进行清理
- 3. 可以分目录和分文件显示日志
二. 技能介绍
① 使用log4Net的配置步骤
第一步: 创建App.config配置文件,并对log4Net配置如下:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
</configSections>
<log4net debug="true">
<!--
其中layout节点的配置说明:
%m(message):输出的日志消息;
%n(newline):换行;
%d(datetime):输出当前语句运行的时刻;
%r(runtime):输出程序从运行到执行到当前语句时消耗的毫秒数;
%t(threadid):当前语句所在的线程ID ;
%p(priority): 日志的当前日志级别;
%c(class):当前日志对象的名称;
%L:输出语句所在的行号;
%F:输出语句所在的文件名;
%-10:表示最小长度为10,如果不够,则用空格填充;
-->
<root>
<!--(高) OFF > FATAL > ERROR > WARN > INFO > DEBUG > ALL (低) -->
<level value="all" />
<!--<appender-ref ref="ColoredConsoleAppender"/>-->
<!--<appender-ref ref="RollingLogFileAppender"/>-->
</root>
<logger name="MainSlaveLogger">
<appender-ref ref="MainSlave"/>
</logger>
<appender name="MainSlave" type="log4net.Appender.RollingFileAppender">
<!--日志路径-->
<param name= "File" value= "Logs\主站\"/>
<!--多线程时采用最小锁定-->
<lockingModel type="log4net.Appender.FileAppender+MinimalLock"/>
<!--是否是向文件中追加日志-->
<param name= "AppendToFile" value= "true"/>
<!--log保留的备份数的最大值,如果为0表示不备份-->
<param name= "MaxSizeRollBackups" value= "0"/>
<!--日志文件名是否是固定不变的-->
<param name= "StaticLogFileName" value= "false"/>
<!--日志文件名格式为:2022-05-22.log-->
<param name= "DatePattern" value= "yyyy-MM-dd'_Main.Log'"/>
<!--日志根据日期滚动-->
<param name= "RollingStyle" value= "Date"/>
<layout type="log4net.Layout.PatternLayout">
<!-- 默认的 <param name="ConversionPattern" value="%n%d [%t] %-5p %c [%L] - %m %n" /> -->
<param name="ConversionPattern" value="%n%d [%t] %-5p - %m %n" />
</layout>
</appender>
</log4net>
<appSettings>
<!-- 过期日志设置限制 -->
<add key="OverdueDays" value="15"/>
</appSettings>
</configuration>
第二步: 编写LoggerHelper类,对日志进行一些操作
日志的配置文件需要应用程序去加载,这里有两种加载方式,第一种是手动的去加载,比如在构造函数中去加载配置,如下图所示的程序.
namespace WaferSelectV3.Common
{
public class LoggerHelper
{
// 静态构造函数在类型被第一次使用之前自动被调用,并且只会被调用一次.
// 这里的使用指的是引用任何静态成员,创建类的实例或者是派生自该类型的类被使用
static LoggerHelper()
{
// 加载log4Net的配置文件(手动加载)
log4net.Config.XmlConfigurator.Configure();
MainLogger = LogManager.GetLogger(@"MainSlaveLogger");
WriteLogMain("LoggerHelper() 构造方法被调用", LogType.Test);
}
// 主站日志记录
public static void WriteLogMain(string message, LogType logType, string errorCode = "")
{
switch (logType)
{
case LogType.Info:
MainLogger.Info(message);
break;
case LogType.Debug:
MainLogger.Debug(message);
break;
case LogType.Warn:
MainLogger.Warn(message);
break;
case LogType.Exception:
MainLogger.Error(message);
break;
case LogType.Fatal:
MainLogger.Fatal(message);
break;
case LogType.Test:
MainLogger.Info($"TestShow: {message}");
break;
}
}
private static readonly ILog MainLogger;
}
public enum LogType
{
Info,
Debug,
Warn,
Exception,
Fatal,
Test,
}
}
当然这里加载日志配置文件的方式还有另外一种,就是让.NET
应用自己去加载,只需要在应用配置文件AssemblyInfo.cs
文件中加入下面的代码
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
② 清理过期日志
private static void DoClearOverDueLogs()
{
// 从配置文件中获取保存日志的天数
int maxDays = Convert.ToInt32(ConfigurationManager.AppSettings["OverdueDays"]);
// 如果没有配置的时候maxDays返回的是多少呢.如果上面的OverdueDays没有配置,默认这里是返回0
int days = maxDays == 0 ? 15 : maxDays;
// 最小日期
DateTime latestDay = DateTime.Now.AddDays(-days);
// 通过LoggerManager获取所有的Appender
//IAppender[] appenders = LoggerManager.GetRepository(Assembly.GetEntryAssembly()).GetAppenders();
// 通过Logger对象获取所有的appenders,都是先获取Repository.都是先获取日志仓库,然后获取日志配置文件中已经配置的
// 的所有的Appender.
IAppender[] appenders = MainLogger.Logger.Repository.GetAppenders();
foreach (var append in appenders)
{
if (!(append is RollingFileAppender roller))
{
continue;
}
string? dir = Path.GetDirectoryName(roller.File);
string[] files = Directory.GetFiles(dir!, "*.log*");
foreach (string filePath in files)
{
FileInfo file = new FileInfo(filePath);
if (file.CreationTime < latestDay || file.LastWriteTime < latestDay)
{
try
{
file.Delete();
}
catch (Exception ex)
{
WriteLogMain("日志清理失败: " + ex.Message, LogType.Info);
}
}
}
}
}
然后在构造函数中调用这个清理过期日志的任务
static LoggerHelper()
{
// 加载log4Net的配置文件(手动加载)
//log4net.Config.XmlConfigurator.Configure();
MainLogger = LogManager.GetLogger(@"MainSlaveLogger");
SizeLogger = LogManager.GetLogger(@"SizeSlaveLogger");
WriteLogMain("LoggerHelper() 构造方法被调用", LogType.Test);
Task.Run(async () =>
{
try
{
while (!ClearCts.Token.IsCancellationRequested)
{
DoClearOverDueLogs();
WriteLogMain("清除过期日志完成.", LogType.Info);
// 每隔24小时清理一次,后面加上一个Token的目的就是可以在外部取消这个异步等待任务
await Task.Delay(86400000, ClearCts.Token);
}
}
catch (OperationCanceledException)
{
WriteLogMain("清理过期日志监控任务被取消", LogType.Info);
}
catch (Exception ex)
{
WriteLogMain("清理过期日志任务发生异常: " + ex.Message, LogType.Exception);
}
});
}
③ 多日志文件显示
假如有这样的需求,你想要在同一个应用程序中,分文件保存日志,该如何去做呢,其实很简单.就在配置文件中多添加几个
logger
节点和appender
节点即可,改成对应的目录名和文件名即可
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
</configSections>
<log4net debug="true">
<!--
其中layout节点的配置说明:
%m(message):输出的日志消息;
%n(newline):换行;
%d(datetime):输出当前语句运行的时刻;
%r(runtime):输出程序从运行到执行到当前语句时消耗的毫秒数;
%t(threadid):当前语句所在的线程ID ;
%p(priority): 日志的当前日志级别;
%c(class):当前日志对象的名称;
%L:输出语句所在的行号;
%F:输出语句所在的文件名;
%-10:表示最小长度为10,如果不够,则用空格填充;
-->
<root>
<!--(高) OFF > FATAL > ERROR > WARN > INFO > DEBUG > ALL (低) -->
<level value="all" />
<!--<appender-ref ref="ColoredConsoleAppender"/>-->
<!--<appender-ref ref="RollingLogFileAppender"/>-->
</root>
<logger name="MainSlaveLogger">
<appender-ref ref="MainSlave"/>
</logger>
<logger name="SizeSlaveLogger">
<appender-ref ref="SizeSlave"/>
</logger>
<appender name="MainSlave" type="log4net.Appender.RollingFileAppender">
<!--日志路径-->
<param name= "File" value= "Logs\主站\"/>
<!--多线程时采用最小锁定-->
<lockingModel type="log4net.Appender.FileAppender+MinimalLock"/>
<!--是否是向文件中追加日志-->
<param name= "AppendToFile" value= "true"/>
<!--log保留的备份数的最大值,如果为0表示不备份-->
<param name= "MaxSizeRollBackups" value= "0"/>
<!--日志文件名是否是固定不变的-->
<param name= "StaticLogFileName" value= "false"/>
<!--日志文件名格式为:2022-05-22.log-->
<param name= "DatePattern" value= "yyyy-MM-dd'_Main.Log'"/>
<!--日志根据日期滚动-->
<param name= "RollingStyle" value= "Date"/>
<layout type="log4net.Layout.PatternLayout">
<!-- 默认的 <param name="ConversionPattern" value="%n%d [%t] %-5p %c [%L] - %m %n" /> -->
<param name="ConversionPattern" value="%n%d [%t] %-5p - %m %n" />
</layout>
</appender>
<appender name="SizeSlave" type="log4net.Appender.RollingFileAppender">
<!--日志路径-->
<param name= "File" value= "Logs\尺寸\"/>
<!--多线程时采用最小锁定-->
<lockingModel type="log4net.Appender.FileAppender+MinimalLock"/>
<!--是否是向文件中追加日志-->
<param name= "AppendToFile" value= "true"/>
<!--log保留的备份数的最大值,如果为0表示不备份-->
<param name= "MaxSizeRollBackups" value= "0"/>
<!--日志文件名是否是固定不变的-->
<param name= "StaticLogFileName" value= "false"/>
<!--日志文件名格式为:2022-05-22.log-->
<param name= "DatePattern" value= "yyyy-MM-dd'_Size.Log'"/>
<!--日志根据日期滚动-->
<param name= "RollingStyle" value= "Date"/>
<layout type="log4net.Layout.PatternLayout">
<!-- 默认的 <param name="ConversionPattern" value="%n%d [%t] %-5p %c [%L] - %m %n" /> -->
<param name="ConversionPattern" value="%n%d [%t] %-5p - %m %n" />
</layout>
</appender>
</log4net>
<appSettings>
<!-- 过期日志设置限制 -->
<add key="OverdueDays" value="15"/>
</appSettings>
</configuration>