基于log4net的支持动态文件名、按日期和大小自动分割文件的日志组件
2016-05-20 17:35
555 查看
最近处理一个日志功能,用log4net的配置不能完全满足要求,所以在其基础上简单封装了一下,支持以下功能:
1 零配置
内置默认配置,引用dll后不需要添加或修改任何配置文件也可以使用
2 动态指定文件路径和文件名
我们的需求是按请求来源和功能生成多个独立的日志文件,例如 /app编号/功能编号.txt 的结构,需要根据请求动态指定文件名称
3 按日期和大小自动分割文件,满足其中一个条件即可
来看实现
将在运行目录下生成 Log\10001\pay.txt
按日期分割日志文件,如果文件超过256M,也进行分割
配置项均为可选项,具体含义如下:
file
文件路径
appendToFile
如果同名文件已存在,是否在文件中追加日志
maxSizeRollBackups
在发生文件分割时,最多保留的历史文件个数
maximumFileSize
设置按文件大小分割的阈值
datePattern
按日期分割时文件重命名规则
level
logger输出等级
layout
日志输出格式
1 零配置
内置默认配置,引用dll后不需要添加或修改任何配置文件也可以使用
2 动态指定文件路径和文件名
我们的需求是按请求来源和功能生成多个独立的日志文件,例如 /app编号/功能编号.txt 的结构,需要根据请求动态指定文件名称
3 按日期和大小自动分割文件,满足其中一个条件即可
来看实现
一、自定义读取配置文件的Appender
为了同时支持零配置和使用配置文件的方式,采用自定义一个用于读取配置项的Appender,初始化Logger时首先读取配置项中的同名Appender,如果存在使用配置参数,如果不存在则使用默认配置。using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Rainstorm.Log4net { /// <summary> /// http://blog.csdn.net/autfish /// </summary> public class ReadParamAppender : log4net.Appender.AppenderSkeleton { private string _file; public string File { get { return this._file; } set { _file = value; } } private int _maxSizeRollBackups; public int MaxSizeRollBackups { get { return this._maxSizeRollBackups; } set { _maxSizeRollBackups = value; } } private bool _appendToFile = true; public bool AppendToFile { get { return this._appendToFile; } set { _appendToFile = value; } } private string _maximumFileSize; public string MaximumFileSize { get { return this._maximumFileSize; } set { _maximumFileSize = value; } } private string _layoutPattern; public string LayoutPattern { get { return this._layoutPattern; } set { _layoutPattern = value; } } private string _datePattern; public string DatePattern { get { return this._datePattern; } set { _datePattern = value; } } private string _level; public string Level { get { return this._level; } set { _level = value; } } protected override void Append(log4net.Core.LoggingEvent loggingEvent) { } } }
二、动态创建Logger工厂类
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections.Concurrent; using System.Configuration; using log4net; using log4net.Appender; using log4net.Core; using log4net.Layout; using log4net.Repository; using log4net.Repository.Hierarchy; [assembly: log4net.Config.XmlConfigurator(Watch = true)] namespace Rainstorm.Log4net { /// <summary> /// http://blog.csdn.net/autfish /// </summary> public static class CustomRollingFileLogger { private static readonly ConcurrentDictionary<string, ILog> loggerContainer = new ConcurrentDictionary<string, ILog>(); private static readonly Dictionary<string, ReadParamAppender> appenderContainer = new Dictionary<string, ReadParamAppender>(); private static object lockObj = new object(); //默认配置 private const int MAX_SIZE_ROLL_BACKUPS = 20; private const string LAYOUT_PATTERN = "%d [%t] %-5p %c - %m%n"; private const string DATE_PATTERN = "yyyyMMdd\".txt\""; private const string MAXIMUM_FILE_SIZE = "256MB"; private const string LEVEL = "debug"; //读取配置文件并缓存 static CustomRollingFileLogger() { IAppender[] appenders = LogManager.GetRepository().GetAppenders(); for (int i = 0; i < appenders.Length; i++) { if (appenders[i] is ReadParamAppender) { ReadParamAppender appender = (ReadParamAppender)appenders[i]; if (appender.MaxSizeRollBackups == 0) { appender.MaxSizeRollBackups = MAX_SIZE_ROLL_BACKUPS; } if (appender.Layout != null && appender.Layout is log4net.Layout.PatternLayout) { appender.LayoutPattern = ((log4net.Layout.PatternLayout)appender.Layout).ConversionPattern; } if (string.IsNullOrEmpty(appender.LayoutPattern)) { appender.LayoutPattern = LAYOUT_PATTERN; } if (string.IsNullOrEmpty(appender.DatePattern)) { appender.DatePattern = DATE_PATTERN; } if (string.IsNullOrEmpty(appender.MaximumFileSize)) { appender.MaximumFileSize = MAXIMUM_FILE_SIZE; } if (string.IsNullOrEmpty(appender.Level)) { appender.Level = LEVEL; } lock(lockObj) { appenderContainer[appenders[i].Name] = appender; } } } } public static ILog GetCustomLogger(string loggerName, string category = null, bool additivity = false) { return loggerContainer.GetOrAdd(loggerName, delegate(string name) { RollingFileAppender newAppender = null; ReadParamAppender appender = null; if (appenderContainer.ContainsKey(loggerName)) { appender = appenderContainer[loggerName]; newAppender = GetNewFileApender(loggerName, string.IsNullOrEmpty(appender.File) ? GetFile(category, loggerName) : appender.File, appender.MaxSizeRollBackups, appender.AppendToFile, true, appender.MaximumFileSize, RollingFileAppender.RollingMode.Composite, appender.DatePattern, appender.LayoutPattern); } else { newAppender = GetNewFileApender(loggerName, GetFile(category, loggerName), MAX_SIZE_ROLL_BACKUPS, true, true, MAXIMUM_FILE_SIZE, RollingFileAppender.RollingMode.Composite, DATE_PATTERN, LAYOUT_PATTERN); } log4net.Repository.Hierarchy.Hierarchy repository = (log4net.Repository.Hierarchy.Hierarchy)LogManager.GetRepository(); Logger logger = repository.LoggerFactory.CreateLogger(repository, loggerName); logger.Hierarchy = repository; logger.Parent = repository.Root; logger.Level = GetLoggerLevel(appender == null ? LEVEL : appender.Level); logger.Additivity = additivity; logger.AddAppender(newAppender); logger.Repository.Configured = true; return new LogImpl(logger); }); } //如果没有指定文件路径则在运行路径下建立 Log\{loggerName}.txt private static string GetFile(string category, string loggerName) { if (string.IsNullOrEmpty(category)) { return string.Format(@"Log\{0}.txt", loggerName); } else { return string.Format(@"Log\{0}\{1}.txt", category, loggerName); } } private static Level GetLoggerLevel(string level) { if (!string.IsNullOrEmpty(level)) { switch (level.ToLower().Trim()) { case "debug": return Level.Debug; case "info": return Level.Info; case "warn": return Level.Warn; case "error": return Level.Error; case "fatal": return Level.Fatal; } } return Level.Debug; } private static RollingFileAppender GetNewFileApender(string appenderName, string file, int maxSizeRollBackups, bool appendToFile = true, bool staticLogFileName = false, string maximumFileSize = "5MB", RollingFileAppender.RollingMode rollingMode = RollingFileAppender.RollingMode.Composite, string datePattern = "yyyyMMdd\".txt\"", string layoutPattern = "%d [%t] %-5p %c - %m%n") { RollingFileAppender appender = new RollingFileAppender { LockingModel = new FileAppender.MinimalLock(), Name = appenderName, File = file, AppendToFile = appendToFile, MaxSizeRollBackups = maxSizeRollBackups, MaximumFileSize = maximumFileSize, StaticLogFileName = staticLogFileName, RollingStyle = rollingMode, DatePattern = datePattern }; PatternLayout layout = new PatternLayout(layoutPattern); appender.Layout = layout; layout.ActivateOptions(); appender.ActivateOptions(); return appender; } } }
三、使用方法
3.1 零配置
ILog logger = CustomRollingFileLogger.GetCustomLogger("pay", "10001"); logger.Debug("debug message");
将在运行目录下生成 Log\10001\pay.txt
按日期分割日志文件,如果文件超过256M,也进行分割
3.2 使用配置文件
修改App.config/Web.config,添加或修改项<configSections> <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/> </configSections> <log4net> <appender name="pay" type="Rainstorm.Log4net.ReadParamAppender"> <param name="file" value="D:\\log\\pay.txt"/> <param name="appendToFile" value="true"/> <param name="maxSizeRollBackups" value="100"/> <param name="maximumFileSize" value="2MB"/> <param name="datePattern" value="yyyyMMdd'.txt'"/> <param name="level" value="debug"/> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%d - %m%n"/> </layout> </appender> <root> <level value="INFO"/> <appender-ref ref="pay"/> </root> </log4net>
ILog logger = CustomRollingFileLogger.GetCustomLogger("pay"); logger.Debug("debug message");
配置项均为可选项,具体含义如下:
file
文件路径
appendToFile
如果同名文件已存在,是否在文件中追加日志
maxSizeRollBackups
在发生文件分割时,最多保留的历史文件个数
maximumFileSize
设置按文件大小分割的阈值
datePattern
按日期分割时文件重命名规则
level
logger输出等级
layout
日志输出格式
相关文章推荐
- Vue.js-----轻量高效的MVVM框架(六、Class与Style绑定)
- 构建之法阅读笔记05
- loadrunner常用函数
- Maven创建servlet项目演示(三)
- Spring7:基于注解的Spring MVC(下篇)
- linux下开发的头文件
- Java7中的ForkJoin并发框架初探(上)——需求背景和设计原理
- 自定义字典表的使用
- asp.net多文件打包下载
- 关于弹窗:自定义PopuWindow和Toast
- C# Compiler Errors
- 第三方库 zlib库 引入到现有项目中
- 升级centos内核到最新版本
- 行式数据库与列式数据库的对比
- Spring6:基于注解的Spring MVC(上篇)
- APC UPS 网络管理卡(型号apc ap9631)的配置
- APC UPS 网络管理卡(型号apc ap9631)的配置
- logcat 命令行只打印某个 app 的 log
- javascript不起作用了
- c++实现读写共享锁