(一)主要是 log4j 中 myappender 过滤
之前曾写过一篇帖子,是log4j按包路径输出到不同文件。
log4j按级别输出到不同文件,也类似。
先看配置:
[html] view plain copy
- ### set log levels ###
- log4j.rootLogger=info,error,info
- log4j.appender.stdout=org.apache.log4j.ConsoleAppender
- log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
- log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd-HH-mm} [%t] [%c] [%p] - %m%n
- log4j.logger.info=info
- log4j.appender.info=com.zznode.log.MyAppender
- log4j.appender.info.layout=org.apache.log4j.PatternLayout
- log4j.appender.info.layout.ConversionPattern=%d{yyyy-MM-dd-HH-mm} [%t] [%c] [%p] - %m%n
- log4j.appender.info.datePattern='.'yyyy-MM-dd
- log4j.appender.info.Threshold = INFO
- log4j.appender.info.append=false
- log4j.appender.info.File=D:/log4j/info.log
- log4j.logger.error=error
- log4j.appender.error=com.zznode.log.MyAppender
- log4j.appender.error.layout=org.apache.log4j.PatternLayout
- log4j.appender.error.layout.ConversionPattern=%d{yyyy-MM-dd-HH-mm} [%t] [%c] [%p] - %m%n
- log4j.appender.error.datePattern='.'yyyy-MM-dd
- log4j.appender.error.Threshold = ERROR
- log4j.appender.error.append=false
- log4j.appender.error.File=D:/log4j/error.log
测试类:
[java] view plain copy
- import org.apache.log4j.PropertyConfigurator;
- import org.apache.log4j.xml.DOMConfigurator;
- import com.zznode.test.Test;
- /**
- * @desc:
- * @since Nov 8, 2012
- * @author chaisson
- *
- * <p>
- */
- public class Log4jApp {
- public void printLog() {
- Logger log = Logger.getLogger(Log4jApp.class.getClass());
- log.info("测试info");
- log.debug("测试debug");
- log.error("测试error");
- }
- public static void main(String[] args) {
- //DOMConfigurator.configure("log4j.xml");
- PropertyConfigurator.configure("D:/workspace/Test/log4j-new.properties");
- Log4jApp app = new Log4jApp();
- app.printLog();
- // Test test = new Test();
- //test.printLog();
- }
- }
输出结果有点问题:info.log里面也包含了error的输出。
配置中关键的配置说明是这一句:
log4j.appender.debug.Threshold = INFO
而它的作用是输出INFO级别以上的内容到info.log中,所以info.log文件中包含了ERROR级别的文件。
解决办法是:定义自己的Appender类,继承DailyRollingFileAppender,改写针对Threshold 的设置说明(重写针对级别的比较方法)
源代码
[java] view plain copy
- public boolean isAsSevereAsThreshold(Priority priority) {
- return threshold == null || priority.isGreaterOrEqual(threshold);
- }
重写 isAsSevereAsThreshold(Priority priority)方法
[java] view plain copy
- /**
- * @desc:
- * @since Apr 17, 2013
- * @author chaisson
- *
- * <p>
- */
- public class MyAppender extends DailyRollingFileAppender {
- @Override
- public boolean isAsSevereAsThreshold(Priority priority) {
- //只判断是否相等,而不判断优先级
- return this.getThreshold().equals(priority);
- }
- }
这样,进行唯一判断,只有当Threshold与priority一致时,才进行输出,就实现了真正Log4j按照级别输出日志文件。
修改配置文件:
[plain] view plain copy
- ### set log levels ###
- log4j.rootLogger=info,error,info
- log4j.appender.stdout=org.apache.log4j.ConsoleAppender
- log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
- log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd-HH-mm} [%t] [%c] [%p] - %m%n
- log4j.logger.info=info
- log4j.appender.info=com.zznode.log.MyAppender
- log4j.appender.info.layout=org.apache.log4j.PatternLayout
- log4j.appender.info.layout.ConversionPattern=%d{yyyy-MM-dd-HH-mm} [%t] [%c] [%p] - %m%n
- log4j.appender.info.datePattern='.'yyyy-MM-dd
- log4j.appender.info.Threshold = INFO
- log4j.appender.info.append=false
- log4j.appender.info.File=D:/log4j/info.log
- log4j.logger.error=error
- log4j.appender.error=com.zznode.log.MyAppender
- log4j.appender.error.layout=org.apache.log4j.PatternLayout
- log4j.appender.error.layout.ConversionPattern=%d{yyyy-MM-dd-HH-mm} [%t] [%c] [%p] - %m%n
- log4j.appender.error.datePattern='.'yyyy-MM-dd
- log4j.appender.error.Threshold = ERROR
- log4j.appender.error.append=false
- log4j.appender.error.File=D:/log4j/error.log
这样才算完成了。
补充:有同事讨论,如果是XML配置,通过filter会简便:
[html] view plain copy
- <filter class="org.apache.log4j.varia.LevelRangeFilter">
- <param name="LevelMin" value="ERROR"/>
- <param name="LevelMax" value="ERROR"/>
- </filter>
有兴趣的朋友,可以自己动手尝试下。
(二)主要是log4j 中 properties 中建立子logger;properties 与 xml 的类比,尤其分包输出
1、Logger 完成日志信息的处理
定义输出的层次和决定信息是否输出
DEBUG < INFO < WARN < ERROR
2、Appender 设置日志信息的去向
常用的:
org.apache.log4j.ConsoleAppender(控制台)
org.apache.log4j.FileAppender(文件)
org.apache.log4j.DailyRollingFileAppener(每天产生一个日志文件)
org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件)
org.apache.log4j.WriterAppender(将日志讯息以串流格式发送到任意指定的地方)
org.apache.log4j.JdbcAppender(将日志讯息保存到数据库中)
3、Layout 设置日志信息的输出样式
layout有以下几种:
org.apache.log4j.HTMLLayout(以HTML表格形式布局)
org.apache.log4j.SimpleLayout(包含日志讯息的级别和讯息字符串)
org.apache.log4j.TTCCLayout(包含日志产生的时间、执行绪、类别等讯息)
org.apache.log4j.PatterLayout(可以灵活地指定布局格式)
4、配置文件 log4j.properties或log4j.xml
log4j.properties实例:
[plain] view plain copy
- log4j.logger.com.jjm.util=INFO, A1,A2
- log4j.logger.com.jjm.dao=DEBUG, A1 (com.jjm.util和com.jjm.dao是class全名匹配字符串)
- log4j.appender.A1=org.apache.log4j.ConsoleAppender
- log4j.appender.A1.layout=org.apache.log4j.PatternLayout
- log4j.appender.A1.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}][%C-%M]%m%n
- log4j.appender.A2=org.apache.log4j.RollingFileAppender
- log4j.appender.A2.File=sshdemo.log
- log4j.appender.A2.MaxFileSize=500KB
- log4j.appender.A2.MaxBackupIndex=1
- log4j.appender.A2.layout=org.apache.log4j.PatternLayout
- log4j.appender.A2.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}][%C-%M]%m%n
log4j.xml实例:
[html] view plain copy
- <?xml version="1.0" encoding="UTF-8" ?>
- <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
- <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
- <appender name="A1" class="org.apache.log4j.RollingFileAppender">
- <param name="File" value="sshdemo2.log" />
- <param name="MaxFileSize" value="1MB" />
- <param name="MaxBackupIndex" value="10" />
- <layout class="org.apache.log4j.PatternLayout">
- <param name="ConversionPattern" value="[%d{yyyy-MM-dd HH:mm:ss}][%C-%M]%m%n" />
- </layout>
- </appender>
- <appender name="A2" class="org.apache.log4j.ConsoleAppender">
- <layout class="org.apache.log4j.PatternLayout">
- <param name="ConversionPattern" value="[%d{yyyy-MM-dd HH:mm:ss}][%C-%M]%m%n" />
- </layout>
- </appender>
- <logger name="com.jjm.dao">
- <level value="DEBUG" />
- <appender-ref ref="A1" />
- </logger>
- <root>
- <priority value="DEBUG" />
- <appender-ref ref="A2" />
- </root>
- </log4j:configuration>
格式说明layout中的参数都以%开始,后面不同的参数代表不同的格式化信息(参数按字母表顺序列出):
%c 输出所属类的全名,可在修改为 %d{Num} ,Num类名输出的维(如:"org.apache.elathen.ClassName",%C{2}将输出elathen.ClassName)
%d 输出日志时间其格式为 %d{yyyy-MM-dd HH:mm:ss,SSS},可指定格式 如 %d{HH:mm:ss}
%l 输出日志事件发生位置,包括类目名、发生线程,在代码中的行数
%n 换行符
%m 输出代码指定信息,如info(“message”),输出message
%p 输出优先级,即 FATAL ,ERROR 等
%r 输出从启动到显示该log信息所耗费的毫秒数
%t 输出产生该日志事件的线程名
(三)主要是logback中的filter
最近才开始在项目中使用logback,有一种相见恨晚的感觉,因为它很轻易的满足了我的几个需求:
1. 配置简单,易于上手
2. 一个日志文件中只能某一个级别的日志
3. 一个类中可以指定多个不同的日志,并且生成的每个日志文件中只包含其本身的内容
4. 可以关闭或者打开某几个包的日志,并且可以设置不同的包使用不同的日志级别。
一、易用性
logback的易用性不用多讲,只需要通过下面两行就可以在console中输出日志:
[java] view plain copy
- <pre name="code" class="html">Logger debugLogger = LoggerFactory.getLogger(MyClass.class);
- </pre>logger.info("This is a log");
程序运行时,logback会查找默认的配置文件logback.xml或者logback-test.xml文件,如果没有找到它就会使用默认的配置,将日志打印到console中。下面是一个简单配置文件(http://logback.qos.ch/manual/configuration.html):
[html] view plain copy
- <configuration>
- <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
- <!-- encoders are assigned the type
- ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
- <encoder>
- <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
- </encoder>
- </appender>
- <root level="debug">
- <appender-ref ref="STDOUT" />
- </root>
- </configuration>
二、日志级别限制
在多数的Log工具中,级别是可以传递,例如如果指定了日志输出级别为DEBUG,那么INFO、ERROR级别的log也会出现在日志文件。这种默认给程序的调试带来了很多的麻烦。而在logback中可以通过appender中的filter来严格限制日志的输出级别:
[html] view plain copy
- <filter class="ch.qos.logback.classic.filter.LevelFilter">
- <level>INFO</level>
- <onMatch>ACCEPT</onMatch>
- <onMismatch>DENY</onMismatch>
- </filter>
上面的设置中只会在文件中出现级别为INFO的日志内容。
三、同一个类中包含不同的日志
有时候一个类中可能要求打印不同的日志信息,例如有的用来调试,有的用来记录程序运行中的某些参数的变化等等。这时候可以通过下面的语句声明不同的日志:
[java] view plain copy
- Logger debugLogger = LoggerFactory.getLogger(MyClass.class);
- Logger monitorLogger = LoggerFactory.getLogger("monitor");
然后在配置文件中分别指定不同的输出文件(debugLogger使用默认的配置):
[html] view plain copy
- <appender name="monitor" class="ch.qos.logback.core.rolling.RollingFileAppender">
- <File>${log.dir}/monitor.log</File>
- <encoder>
- <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} : %m%n</pattern>
- </encoder>
- <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
- <level>INFO</level>
- </filter>
- <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
- <fileNamePattern>${log.dir}/sensitive.log.%d{yyyy-MM-dd}</fileNamePattern>
- </rollingPolicy>
- </appender>
- <logger name="monitor" additivity="false" level="INFO">
- <span style="white-space:pre"> </span><appender-ref ref="monitor" />
- <span style="white-space:pre"> </span></logger>
这里通过设置additivity="false"禁止monitor里的内容向上传递,否则会同时显示在默认的日志中。
四、精确控制日志的应用范围
在程序调试中,经常出现的情况是:错误只在某一个或者几个类或者包里,所以只需要打开这几个类或者包里的DEBUG级别的log。在以前的项目,使用spring和hibernate时,一旦打开DEBUG级别的log,程序本身的debug信息就会被Spring和Hibernate的大量日志淹没,大大降低了调试的效率。而logback让这一切变的简单起来了:
[html] view plain copy
- <logger name="org" level="ERROR" />
这一行就将org包下面的所有日志级别设为了ERROR,不会再打扰我们的DEBUG。