利用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/ ...
随机推荐
- OracleSpatial函数
Oracle_spatial的函数 一sdo_Geom包的函数: 用于表示两个几何对象的关系(结果为True/False)的函数:RELATE,WITHIN_DISTANCE 验证的函数:VALIDA ...
- @NOI模拟2017.06.30 - T3@ Right
目录 @description@ @solution@ @part - 1@ @part - 2@ @accepted code@ @details@ @description@ JOHNKRAM 和 ...
- docker + jenkins 自动化部署
公司书架上有本docker的书籍,正好最近事不多就写个demo来玩一玩. DevOps未死,ContainerOps已到 ContainerOps VS DevOps 避免了复杂的环境,应用之间的相互 ...
- [kuangbin带你飞]专题九 连通图B - Network UVA - 315
判断割点的性质: 如果点y满足 low[y]>=dfn[x] 且不是根节点 或者是根节点,满足上述式子的有两个及其以上. 就是割点 如果是起点,那么至少需要两个子节点满足上述条件,因为它是根节点 ...
- SCSS语法格式及编译调试
一.SASS编译 Sass 的编译有多种方法: 命令编译 GUI工具编译 自动化编译 1.1 命令编译 1)单文件编译 sass <要编译的Sass文件路径>/style.scss:< ...
- Python--day72--json内容回顾
前后端分离,Json格式字符串:序列化和反序列化 """ 复习python中的json模块 """ import json s = '{&q ...
- 【codeforces 761A】Dasha and Stairs
time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandard o ...
- DIRECTORY_SEPARATOR 与 getcwd
DIRECTORY_SEPARATOR:目录分隔符,linux上就是’/’ windows上是’\’ ,php的内置常量是一个显示系统分隔符的命令,php的内部常量,不需要任何定义与包含即可直接 ...
- Vue打包文件放在服务器,浏览器存在缓存问题的解决
在入口文件index.html添加 <meta http-equiv="pragram" content="no-cache"> <meta ...
- H3C IPv6地址表示方式