Log4net库是.Net下一个开源日志记录组件。网络上大部分讲述这个库都是介绍怎么配置log4Net.config配置文件。这么做最大的缺点就是配置太繁琐。有很多功能是用户不了解的,因为毕竟做工程嘛,是给别人用的。用户觉得需要什么配置信息,我们给暴露什么就好了。把整个配置文件都暴露给用户,显然用户也会一脸懵逼。这都什么玩意。所以结合自身的需求以及用户体验感来考虑,设计了一个封装Log4net的一个库。
Log4net在配置中有一点不懂的是,如果我想每天生成一个新的文件(前提是我的程序一直在输出log,不退出,不重启),直接在配置文件中配置就可以了吗?每天生成新文件是Log4net已经内部做好了,还是在程序开始加载配置文件的时候才会检查呢?我尝试更改系统的日期,发现没有生成新的文件。我理解是Log4net提供了每个文件最大size,因此这种做法也是新建文件了。不知是我测试的不对,还是理解的不对,如果有人知道,欢迎评论区留言交流。因此采用了21世纪最笨的方法,自己搞。
官网地址:https://logging.apache.org/log4net/
源代码:https://github.com/apache/logging-log4net/
我的需求是:
1、将尽量少的配置放在配置文件中,供用户选择。(存放路径,记录天数,日志等级)
2、我需要每天生成一个log。
明确了需求后,我们得到了一个配置文件如下:>
XML
<?xml version="1.0" encoding="utf-8" ?>
<appSettings>
<!--日志等级-->
<LogLevel>0</LogLevel>
<!--日志目录-->
<LogFilePath>D:\Log\</LogFilePath>
<!--日志存在天数-->
<LogFileExistDay>10</LogFileExistDay>
</appSettings>
有了配置文件,我们需要一个类存放配置参数
cs
public class Parameter
{
/// <summary>
/// 日志等级
/// </summary>
public enum LogLevelEnum
{
Debug = 0,
Info = 1,
Warn = 2,
Error = 3,
Fatal = 4
}
/// <summary>
/// 当前保存日志等级
/// </summary>
public LogLevelEnum LogLevel;
/// <summary>
/// 日志存放路径
/// </summary>
public string LogFilePath;
/// <summary>
/// 日志存放天数
/// </summary>
public int LogFileExistDay;
}
提供一个类解析这个配置文件:
cs
class LogHelper
{
public static Parameter ReadXml()
{
Parameter parameter = new Parameter();
try
{
XmlDocument doc = new XmlDocument();
string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.xml");
doc.Load(path);
var node = doc.SelectSingleNode("appSettings");
parameter.LogLevel = (Parameter.LogLevelEnum)Enum.Parse(typeof(Parameter.LogLevelEnum), node.SelectSingleNode("LogLevel").InnerText);
parameter.LogFilePath = node.SelectSingleNode("LogFilePath").InnerText;
parameter.LogFileExistDay = int.Parse(node.SelectSingleNode("LogFileExistDay").InnerText);
}
catch (Exception ex)
{
CommonLogger.Info(ex.ToString());
}
return parameter;
}
}
然后我们就能写封装Log4Net的类了,类叫做CommonLog。使用此类需要先调用初始化函数;读取用户的配置信息;然后初始化log;检查log存放的天数(删除超过天数的log);启动线程(每天生成一个新的log)。
初始化函数:
cs
public static void Init()
{
//读取XML配置信息
parameter = LogHelper.ReadXml();
//初始化日志
InitLog();
//日志清除
DeleteLog();
Thread thread = new Thread(MonitorDay);
thread.Start();
}
初始化log,这里将配置文件的信息放在程序中。其中LockingModel 需要配置,否则会出现问题。具体参考:https://blog.csdn.net/dragon_ton/article/details/77840138
cs
public static void InitLog()
{
// 命令行日志格式
var patternLayout = new PatternLayout
{
ConversionPattern = "%date %-5level %message%newline"
};
patternLayout.ActivateOptions();
// 文档日志
var roller = new RollingFileAppender
{
StaticLogFileName = false,
File = parameter.LogFilePath,
AppendToFile = true,
RollingStyle = RollingFileAppender.RollingMode.Date,
MaxSizeRollBackups = parameter.LogFileExistDay,
DatePattern = "yyyy-MM-dd'.log'",
MaximumFileSize = "10KB",
//下面这句话必须要有,如果没有,会出现生成多个log的情况
LockingModel = new FileAppender.MinimalLock(),
Layout = patternLayout
};
roller.ActivateOptions();
// 命令行日志
//var consoleAppender = new ConsoleAppender
//{
// Name = "console",
// Layout = patternLayout
//};
//consoleAppender.ActivateOptions();
Hierarchy hierarchy = (Hierarchy)LogManager.GetRepository();
hierarchy.Root.Level = Level.All;
hierarchy.Root.AddAppender(roller);
//hierarchy.Root.AddAppender(consoleAppender);
hierarchy.Configured = true;
}
Delete log,检查日志日期,删除超过天数的日志:
cs
public static void DeleteLog()
{
Task.Factory.StartNew(() =>
{
DirectoryInfo di = new DirectoryInfo(parameter.LogFilePath);
if (!di.Exists)
di.Create();
FileInfo[] fi = di.GetFiles("*.log");
DateTime dateTime = DateTime.Now;
foreach (FileInfo info in fi)
{
TimeSpan ts = dateTime.Subtract(info.LastWriteTime);
if (ts.TotalDays > parameter.LogFileExistDay)
{
info.Delete();
}
}
});
}
每天生成一个新的日志,MonitorDay
cs
public static void MonitorDay()
{
DateTime date = DateTime.Now;
int oldDay = date.Day;
while (true)
{
Thread.Sleep(500);
date = DateTime.Now;
int day = date.Day;
if (day == oldDay)
continue;
else
{
oldDay = day;
InitLog();
}
}
}
除了上述的东西之外,其余的就是根据日志等级来打印日志了。
cs
public static void Debug(object messsage)
{
if ((int)parameter.LogLevel <= (int)Parameter.LogLevelEnum.Debug)
{
log.Debug(messsage);
}
}
public static void Debug(string format, params object[] args)
{
if ((int)parameter.LogLevel <= (int)Parameter.LogLevelEnum.Debug)
{
log.DebugFormat(format, args);
}
}
public static void Info(object message)
{
if ((int)parameter.LogLevel <= (int)Parameter.LogLevelEnum.Info)
{
log.Info(message);
}
}
public static void Info(string format, params object[] args)
{
if ((int)parameter.LogLevel <= (int)Parameter.LogLevelEnum.Info)
{
log.InfoFormat(format, args);
}
}
public static void Warn(object message)
{
if ((int)parameter.LogLevel <= (int)Parameter.LogLevelEnum.Warn)
{
log.Warn(message);
}
}
public static void Warn(string format, params object[] args)
{
if ((int)parameter.LogLevel <= (int)Parameter.LogLevelEnum.Warn)
{
log.WarnFormat(format, args);
}
}
public static void Error(object message)
{
if ((int)parameter.LogLevel <= (int)Parameter.LogLevelEnum.Error)
{
log.Error(message);
}
}
public static void Error(object message, Exception exception)
{
if ((int)parameter.LogLevel <= (int)Parameter.LogLevelEnum.Error)
{
log.Error(message, exception);
}
}
public static void Error(string format, params object[] args)
{
if ((int)parameter.LogLevel <= (int)Parameter.LogLevelEnum.Error)
{
log.ErrorFormat(format, args);
}
}
public static void Fatal(object message)
{
if ((int)parameter.LogLevel <= (int)Parameter.LogLevelEnum.Fatal)
{
log.Fatal(message);
}
}
public static void Fatal(object message, Exception exception)
{
if ((int)parameter.LogLevel <= (int)Parameter.LogLevelEnum.Fatal)
{
log.Fatal(message, exception);
}
}
public static void Fatal(string format, params object[] args)
{
if ((int)parameter.LogLevel <= (int)Parameter.LogLevelEnum.Fatal)
{
log.FatalFormat(format, args);
}
}
至此,我们的库开发完成。欢迎留言交流。