利用log4net创建日志文件时过滤日志,这是坑还是?
前言
网上貌似没有太多关于log4net过滤日志的资料,在研究过程中发现一点小问题,这里做下记录,希望对后续有用到的童鞋起到一丢丢帮助作用。
log4net日志过滤
由于是在.NET Core中使用,所以这里为了演示,我们创建一个.NET Core控制台程序,同时呢通过安装log4net最新稳定版本(2.0.8),好了,对于.NET Core而言,在开发时可直接配置web.config启用日志功能,此时会将不同级别日志直接放在同一文件中,在实际开发中无论我们使用log4net还是serilog或者自己写一个也好,大部分都会根据不同级别创建不同目录,这样更加易于后续跟踪和排查问题。但是也会存在特殊的需求,比如本文中,我们只需要创建两个日志文件,一个用于正常的信息文件记录,一个是审计信息记录,而且日志文件名可能不是日期格式,而是由我们自己根据配置给定,所以基于以上需求,我们来完成此项任务,首先,我们在控制台根目录下创建如下单独的log4net .config配置文件:
<?xml version="1.0" encoding="utf-8" ?>
<log4net> <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="log.txt" />
<appendToFile value="true" />
<countDirection value=""/>
<maximumFileSize value="10MB" />
<maxSizeRollBackups value="-1" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
</layout>
</appender>
<root>
<level value="DEBUG"/>
<appender-ref ref="RollingFileAppender" />
</root>
</log4net>
接下来则是读取上述配置文件,在.NET Framework中我们需要在Properties文件夹下的AssemblyInfo类中添加读取上述日志配置文件类,如下:
[assembly: log4net.Config.XmlConfigurator(ConfigFile ="log4net.config", Watch = true)]
但是到了.NET Core中压根就没有了上述Properties文件夹,此时我能想到的办法只能根据日志配置文件所在的目录去读取(不知是否还有其他更好的办法),并按照所提供的api,创建控制台程序集仓储和读取配置文件中XML的根节点并最终写到log4net配置中,如下:
var log4netFullPath = Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), @"..\..\..\"));
var log4netConfig = new XmlDocument();
log4netConfig.Load(File.OpenRead(Path.Combine(log4netFullPath, "log4net.config")));
var repo = LogManager.CreateRepository(Assembly.GetEntryAssembly(), typeof(Repository.Hierarchy.Hierarchy));
Config.XmlConfigurator.Configure(repo, log4netConfig["log4net"]);
接下来我们则是创建类的日志接口,测试并打印日志,如下:
class Program
{
static readonly ILog log = LogManager.GetLogger(typeof(Program));
static void Main(string[] args)
{
var log4netFullPath = Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), @"..\..\..\")); var log4netConfig = new XmlDocument();
log4netConfig.Load(File.OpenRead(Path.Combine(log4netFullPath, "log4net.config"))); var repo = LogManager.CreateRepository(Assembly.GetEntryAssembly(), typeof(Repository.Hierarchy.Hierarchy)); Config.XmlConfigurator.Configure(repo, log4netConfig["log4net"]); log.Info("Program start success......");
}
}

在log4net中,通过添加节点PropertyFilter来实现属性过滤,如下:
<filter type="log4net.Filter.PropertyFilter">
<key value="" />
<stringToMatch value="" />
<acceptOnMatch value="" />
</filter>
如上key代表需要我们定义的键,而stringToMatch代表我们通过对应键所添加的值,最后acceptOnMatch代表是否接受匹配,为布尔值,默认为true(接收匹配就记录)。若我们在配置文件appender节点小添加如下节点:
<filter type="log4net.Filter.PropertyFilter">
<key value="filter" />
<stringToMatch value="" />
<acceptOnMatch value="false" />
</filter>
如上设置代表,当我们对应设置属性的键为filter,而值为1时则记录日志,接下来我们在上述控制台基础通过log4net提供的api去设置线程级别的属性,添加如下:
ThreadContext.Properties["filter"] = "";
log.Info("1......"); ThreadContext.Properties["filter"] = "";
log.Info("0......");

我们通过设置键filter的值为1和0时都记录下来了,很显然没达到要求,我们只想记录对应值等于1的日志,此时需要在上述节点继续添加如下一行来只记录此属性键对应值的日志:


好了,到此有了对log4net日志过滤的基础铺垫,接下来实现我们的需求:创建两个日志文件,一个记录正常信息(排除审计),一个只记录审计信息 。接下来我们对配置文件修改如下:
<?xml version="1.0" encoding="utf-8" ?>
<log4net> <!--只接收auditing日志-->
<appender name="AuditingRollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="auditing.txt" />
<appendToFile value="true" />
<countDirection value=""/>
<maximumFileSize value="10MB" />
<maxSizeRollBackups value="-1" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
</layout> <filter type="log4net.Filter.PropertyFilter">
<key value="filter" />
<stringToMatch value="auditing" />
</filter>
<filter type="log4net.Filter.DenyAllFilter" /> </appender> <!--只接收除auditing以外的日志-->
<appender name="ExceptAuditingRollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="non-auditing.txt" />
<appendToFile value="true" />
<countDirection value=""/>
<maximumFileSize value="10MB" />
<maxSizeRollBackups value="-1" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
</layout> <filter type="log4net.Filter.PropertyFilter">
<key value="filter" />
<stringToMatch value="auditing" />
<acceptOnMatch value="false" />
</filter> </appender>
<root>
<level value="DEBUG"/>
<appender-ref ref="AuditingRollingFileAppender" />
<appender-ref ref="ExceptAuditingRollingFileAppender" />
</root>
</log4net>
上述配置文件就不用我多讲,接下来我们将控制台中上述测试打印的日志给移除,我们添加如下代码进行测试:
//只接收auditing日志
ThreadContext.Properties["filter"] = "auditing";
log.Info("auditing......."); //只接收除了auditing以外日志
ThreadContext.Properties["filter"] = "non-auditing";
log.Info("non-auditing.......");
log.Warn("测试非审计......"); //只接收auditing日志
ThreadContext.Properties["filter"] = "auditing";
log.Info("测试审计.......");

虽然创建一个审计日志文件和一个非审计日志文件,我们的配置也没任何毛病,但是通过上述日志输出发现,非审计文件压根没有日志却全部到了审计文件里,这是为何呢? 经过排查,我开始猜测log4net难道是对值进行模糊匹配吗?为了验证猜想,我将上述对非审计的值(多加一个字母Z)修改成如下:


只要我们将上述非审计日志的值设置时并不包含审计日志里的值(auditing)就没问题,真香,哈哈。上述排除auditing节点以外日志的节点是从反向考虑,当然我们也可以从正向考虑,设置为其他值,还是注意不要包含auditing,并且只记录该值的记录,如下
<!--只接收除auditing以外的日志-->
<appender name="ExceptAuditingRollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="non-auditing.txt" />
<appendToFile value="true" />
<countDirection value=""/>
<maximumFileSize value="10MB" />
<maxSizeRollBackups value="-1" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
</layout> <filter type="log4net.Filter.PropertyFilter">
<key value="filter" />
<stringToMatch value="other" />
<acceptOnMatch value="true" />
</filter>
<filter type="log4net.Filter.DenyAllFilter" />
</appender>

如上我们在输出非审计日志时,我们设置了INFO和Warn级别日志,要是我们想过滤掉上述Warn以及其他级别,只想保留Info级别日志,那么我们应该肿么办呢?我们添加输出内置INFO级别日志,除此级别外拒绝其他级别的日志,如下:
<filter type="log4net.Filter.LevelMatchFilter">
<levelToMatch value="INFO"/>
</filter>
<filter type="log4net.Filter.DenyAllFilter"/>

在log4net中除了设置属性过滤外,还可以比如通过日志中的字符串进行匹配,比如我们添加如下字符串匹配节点,说明包含cache_log的值将不会被记录:
<filter type="log4net.Filter.StringMatchFilter">
<stringToMatch value="cache_log" />
<acceptOnMatch value="false" />
</filter>
log4net运行时创建日志
我们可能会遇到根据什么规则或者需要在运行时创建日志文件,这个时候就不能如上写死日志文件名了,我们通过log4net提供给我们的api【%property】来实现,我们将上述节点file进行如下修改:
<file type="log4net.Util.PatternString" value="D:\logs\%property{LogName}" />
接着添加创建日志文件名代码,注意要将如下第一行放在第二行前面,否则创建的文件名将为null,如下:
ThreadContext.Properties["LogName"] = "runtime.log"; Config.XmlConfigurator.Configure(repo, log4netConfig["log4net"]);
总结
log4net在以前.NET Framework中用到的比较多,但是并未使用过过滤日志这一特性,我们通过业务模块不同来过滤日志,最近要使用时研究发现的问题,看到网上对此资料甚少,所以在此作为备忘录,能够帮到有需要的童鞋当然再好不过啦。
利用log4net创建日志文件时过滤日志,这是坑还是?的更多相关文章
- logstash 监控日志文件时应对日志文件名改变的原理
开门见山先说结论:基于inode实现. 分析很简单,logstash是用一个filewatch去监视文件的.在logstash目录里搜索filewatch即可找到该目录 logstash/vendor ...
- 查阅日志文件:有时候报错信息只是给出了问题的表面现象,要想更深入的了解问题,必须查看相应的日志文件,而日志文件又分为系统日志文件(/var/log)和应用的日志文件,结合这两个日志文件,一般就能定位问题所在。
作为一名合格的 Linux 运维工程师,一定要有一套清晰.明确的解决故障思路,当问题出现时,才能迅速定位.解决问题,这里给出一个处理问题的一般思路: 重视报错提示信息:每个错误的出现,都是给出错误提示 ...
- tail -f 实时查看日志文件 linux查看日志后100行
tail -f 实时查看日志文件 tail -f 日志文件logtail - 100f 实时查看日志文件 后一百行tail -f -n 100 catalina.out linux查看日志后100行搜 ...
- Pycharm在创建py文件时,如何自动添加默认文件头注释?
PyCharm是一款很好用的编写Python工程的IDE,用PyCharm创建一个Python文件或者向工程添加一个.py文件时,为了更好的使所编写的代码在各操作环境更好的运行,我们往往需要在.py文 ...
- webstorm创建js文件时自动生成js注释
设置webstorm创建js文件时自动生成js注释 settings--Editor--File and Code Temlates 黑色框框里的内容自己填写上去,以下是参考的代码块: /** * @ ...
- 利用struts2上传文件时,如果文件名中含有-符号,那么会出错
利用struts2上传文件时,如果文件名中含有-符号,那么会出错 报错如下: HTTP Status 500 - C:\Program Files\Apache Software Foundation ...
- 【Azure 应用服务】App Service For Linux 部署Java Spring Boot应用后,查看日志文件时的疑惑
编写Java Spring Boot应用,通过配置logging.path路径把日志输出在指定的文件夹中. 第一步:通过VS Code创建一个空的Spring Boot项目 第二步:在applicat ...
- C语言关闭日志文件时忘了将日志文件全局变量指针置为NULL
C语言写了一个write_log函数以写日志,写了一个close_log_file函数以关闭日志,声明了一个日志文件全局变量文件指针plogFile. write_log中首先判断plogFile是否 ...
- Spark RDD/Core 编程 API入门系列之动手实战和调试Spark文件操作、动手实战操作搜狗日志文件、搜狗日志文件深入实战(二)
1.动手实战和调试Spark文件操作 这里,我以指定executor-memory参数的方式,启动spark-shell. 启动hadoop集群 spark@SparkSingleNode:/usr/ ...
随机推荐
- hdu 3234 Exclusive-OR (并查集)
Problem - 3234 题意不难理解,就是给出一些断言,以及一些查询,回答查询或者在找到断言矛盾以后沉默不做任何事. 这题其实就是一个并查集的距离存储问题,只要记录并查集元素的相对值以及绝对值就 ...
- 原生js用div实现简单的轮播图
文章地址 https://www.cnblogs.com/sandraryan/ 原生js实现轮播图. 打开页面图片自动轮播,点击prev next按钮切换到上/下一张图片,点击1-5切换到对应图片. ...
- 原生_H5交互插件(适用于与V2.1)
这是js代码 /* * 适合版本为 2.1.0 * 前提是url上加 from=app */ var Native = {}; var ua = navigator.userAgent; var oU ...
- poj 1787 Charlie's Change (多重背包可作完全背包)
Charlie's Change Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 3792 Accepted: 1144 ...
- 达观数据CTO纪达麒:小标注数据量下自然语言处理实战经验
自然语言处理在文本信息抽取.自动审校.智能问答.情感分析等场景下都有非常多的实际应用需求,在人工智能领域里有极为广泛的应用场景.然而在实际工程应用中,最经常面临的挑战是我们往往很难有大量高质量的标注语 ...
- 2019-9-2-git-需要知道的1000个问题
title author date CreateTime categories git 需要知道的1000个问题 lindexi 2019-09-02 10:12:31 +0800 2018-2-13 ...
- ThinkPHP URL 路由简介
简单的说,URL 路由就是允许你在一定规则下定制你需要的 URL 样子,以达到美化 URL ,提高用户体验,也有益于搜索引擎收录的目的. 例子 原本的 URL 为: http://www.5idev. ...
- Java中方法的格式
[修饰符] 返回值类型 方法名([参数类型 形式参数1,参数类型 形式参数2,……]) { 执行语句; [return 返回值;]//需要的话 } 参数列表(参数的类型 ...
- CodeForces 1216C(假的计算几何+扫描线)
传送门 •题意 给你三个矩形,依次编号为 1,2,3: 判断 矩形1 是否被 矩形2 和 矩形3 完全覆盖: 如果没有完全覆盖,输出 "YES",反之,输出 "NO&qu ...
- linux flags 参数
记住 kmalloc 原型是: #include <linux/slab.h> void *kmalloc(size_t size, int flags); 给 kmalloc 的第一个参 ...