日志(Slf4j+log4j)

Slf4j

Simple logging facade for Java (简单日记门面):

是为各种loging APIs提供一个简单统一的接口 在部署时,选择不同的实现包,即可自动转换到不同的日志系统上

Slf4j

Log4j

依赖包

使用slf4j + log4j,实现日志管理:

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.6.6</version>
</dependency>

会自动关联依赖slf4j-api-xxx.jar和log4j-xxx.jar

配置appender

配置日志信息输出目的的

    log4j.appender.appenderName = appenderClass
    log4j.appender.appenderName.option1 = value1
    ...
    log4j.appender.appenderName.option = valueN
  • appender class :implements Appender,eg:

    • org.apache.log4j.ConsoleAppender:控制台
    • org.apache.log4j.FileAppender:文件
    • org.apache.log4j.DailyRollingFileAppender:每天产生一个日志文件
    • org.apache.log4j.RollingFileAppender:文件大小到达指定尺寸的时候产生新文件
    • org.apache.log4j.WriterAppender:将日志信息以流格式发送到任意指定的地方
    • org.apache.log4j.JDBCAppender:将日志信息保存到数据库中
  • option (使用不同的Appender,option会有所不同,一般公有的option配置项如下)

    • Threshold:设置此appender的日志输出级别(过滤器,不设置则依据父类中相应的配置)
    • ImmediateFlush:默认值是true,意谓着所有的消息都会被立即输出
    • layout:配置日志信息的格式(布局)

       log4j.appender.appenderName.layout = layoutClass
       log4j.appender.appenderName.layout.option1 = value1
       ....
       log4j.appender.appenderName.layout.option = valueN
      
      • layout class: extends Layout,不同layout class,使用不同的可配置项
      • 例如:使用org.apache.log4j.PatternLayout

          log4j.appender.activiti.layout.ConversionPattern= %p %d | %C{1}.%M | %m%n
        
        标识 含义 举例
        %c 输出所属类的全名,%c{Num} ,Num类名输出的范围 "com.sun.aaa.classB", %C{2}将使日志输出输出范围为:aaa.classB
        %d 输出日志时间点的日期或时间,默认格式为ISO8601, 可指定格式 %d{yyy MMM dd HH:mm:ss,SSS} 2002年10月18日 22:10:28,921
        %l 输出日志事件发生位置,包括类目名、发生线程,在代码中的行数 Testlog4.main(TestLog4.java:10)
        %n 换行符 Windows平台为“rn”,Unix平台为“n”
        %m 输出代码中指定信息 info(“message”),输出message
        %p 输出日志的优先级 即DEBUG,INFO,WARN,ERROR,FATAL
        %r 输出从启动到显示该条日志信息所耗费的时间(毫秒数) /
        %t 输出产生该日志事件的线程名 /
        %F 输出日志消息产生时所在的文件名称 /
        %L 输出代码中的行号 /

        PS:可以在%与模式字符之间加上修饰符来控制其最小宽度、最大宽度、和文本的对齐方式,eg:%-20c 指定输出category的名称最小的宽度是20,左对齐;%.30c 最大的长度是30,大于30的左边多出的字符截掉

  • 示例:

      # 控制台
      log4j.appender.Stdout=org.apache.log4j.ConsoleAppender
      log4j.appender.Stdout.layout=org.apache.log4j.PatternLayout
      log4j.appender.Stdout.layout.ConversionPattern=[QC] %p %C{1}.%M | %m%n
      log4j.appender.Stdout.Target=System.err        #默认值是System.out
    
      # 回滚文件
      log4j.appender.RollingFile=org.apache.log4j.RollingFileAppender
      log4j.appender.RollingFile.layout=org.apache.log4j.PatternLayout
      log4j.appender.RollingFile.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n
      log4j.appender.RollingFile.ImmediateFlush=true
      log4j.appender.RollingFile.Append=true
      log4j.appender.RollingFile.File=D:/logs/log.log4j
      log4j.appender.RollingFile.MaxFileSize=200KB
      log4j.appender.RollingFile.MaxBackupIndex=50
    
      # 定期回滚日志文件
      log4j.appender.DailyFile=org.apache.log4j.DailyRollingFileAppender
      log4j.appender.DailyFile.layout=org.apache.log4j.PatternLayout
      log4j.appender.DailyFile.layout.ConversionPattern=[R] %p %d | %C{1}.%M | %m%n
      log4j.appender.DailyFile.File=D:/logs/shuttle/shuttle
      log4j.appender.DailyFile.DatePattern='.'yyyy-MM-dd'.log'
    
      # 发送日志到指定邮件
      log4j.appender.Mail=org.apache.log4j.net.SMTPAppender
      log4j.appender.Mail.Threshold = ERROR
      log4j.appender.Mail.layout=org.apache.log4j.PatternLayout
      log4j.appender.Mail.layout.ConversionPattern=%-4r %-5p [%t] %37c %3x - %m%n
      log4j.appender.Mail.BufferSize=5
      log4j.appender.Mail.Subject=ErrorLog
      log4j.appender.Mail.To=xxx@xxx.com
      log4j.appender.Mail.From=xxx@xxx.com
      log4j.appender.Mail.SMTPHost=smtp.xxx.net
    
      # 数据库
      log4j.appender.Database=org.apache.log4j.jdbc.JDBCAppender
      log4j.appender.Database.layout=org.apache.log4j.PatternLayout
      log4j.appender.Database.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n
      log4j.appender.Database.URL=jdbc:mysql://localhost:3306/test
      log4j.appender.Database.driver=com.mysql.jdbc.Driver
      log4j.appender.Database.user=root
      log4j.appender.Database.password=xxx
      log4j.appender.Database.sql=INSERT INTO LOG4J (Message) VALUES('=[%-5p] %d(%r) --> [%t] %l: %m %x %n')
    

配置logger

定义了appender后,需将appender加入Logger,才可用

  • 方式一:加入log4j.rootLogger (默认日志)
  • 方式二:加入log4j.logger (指定日志)

rootLogger

设置根日志的级别和输出,是所有的日志的父类(相当于默认日志)

  log4j.rootLogger=[level],appenderName, ……,
  • [level]:日志的级别

    • 指定这条日志信息的重要性,设置需要输出信息的级别:ALL<DEBUG<INFO<WARN<ERROR<FATAL<OFF,不区分大小写
    • 一般常用的为 DEBUGINFOWARNERROR四种,分别对应Logger类的四种方法:
      • debug(Object message ) ;
      • info(Object message ) ;
      • warn(Object message ) ;
      • error(Object message ) ;
    • 若设置级别为INFO,则优先级大于等于INFO级别的日志信息可以被输出
  • appenderName:日志信息输出目的地

    • 比如打印到控制台,输出到文件等
    • 同一条日志信息可以配置多个输出目的地
  • 例如: log4j.rootLogger = info,stdout,F

Logger

例如:

log4j.properties

# appender
log4j.appender.test1=org.apache.log4j.FileAppender
log4j.appender.test1.File=${myweb.root}/WEB-INF/log/test1.log
log4j.appender.test1.layout=org.apache.log4j.PatternLayout
log4j.appender.test1.layout.ConversionPattern=%d %p [%c] - %m%n

# logger
log4j.logger.myTest1= info, test1

Test:

@Test
public void testLogger(){
    Log logger = LogFactory.getLog("myTest1");
    logger.info("xxxx");
}

分离日志

在log4j中子日志输出,父日志也会相应的输出代码,可通过配置additivity分离日志

log4j.additivity.loggerName=false    # 所需的内容从原有日志中分离,默认为true

PS: additivity的作用在于 children-logger是否使用顶层或父层的的配置)

示例:

log4j.properties:

log4j.rootLogger=debug,test

# appender: test
log4j.appender.test=org.apache.log4j.FileAppender
log4j.appender.test.File=D://output/test.log
log4j.appender.test.layout=org.apache.log4j.PatternLayout
log4j.appender.test.layout.ConversionPattern=%d %p [%c] - %m%n

# appender: test1
log4j.appender.test1=org.apache.log4j.FileAppender
log4j.appender.test1.File=D://output/test1.log
log4j.appender.test1.layout=org.apache.log4j.PatternLayout
log4j.appender.test1.layout.ConversionPattern=%d %p [%c] - %m%n

# appender: test2
log4j.appender.test2=org.apache.log4j.FileAppender
log4j.appender.test2.File=D://output/test2.log
log4j.appender.test2.layout=org.apache.log4j.PatternLayout
log4j.appender.test2.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.test2.Threshold = warn

# appender: test3
log4j.appender.test3=org.apache.log4j.FileAppender
log4j.appender.test3.File=D://output/test3.log
log4j.appender.test3.layout=org.apache.log4j.PatternLayout
log4j.appender.test3.layout.ConversionPattern=%d %p [%c] - %m%n


# logger
log4j.logger.myTest1= info, test1

log4j.logger.myTest2= info, test2
log4j.additivity.myTest2 = false

Test:

Logger logger=Logger.getLogger(this.getClass());
logger.debug("Debug Message");
logger.info("Info Message");


Logger logger1=Logger.getLogger("myTest1");
logger1.debug("Debug Message-1");
logger1.info("Info Message-1");


Logger logger2=Logger.getLogger("myTest2");
logger2.debug("Debug Message-2");
logger2.info("Info Message-2");
logger2.warn("Warn Message-2");

Result:

test.log:
使用class的logger输出信息(debug级别及以上)
使用myTest1的logger输出信息(info级别及以上)
不包含使用myTest2的logger输出信息 (因为additivity设置为false)

test1.log:
使用myTest1的logger输出信息(info级别及以上)

test2.log:
使用myTest2的logger输出信息(warn级别及以上,因为Threshold设置为warn,且logger中设置的为info,info<warn)

test3.log 不生成 (因为没有被加入到logger中,且rootLogger中也没有加入)

后台使用

读取配置文件

#自动快速地使用缺省Log4j环境:log4j.properties
BasicConfigurator.configure();

#读取使用Java的特性文件编写的配置文件
PropertyConfigurator.configure(String configFilename) ;

# 读取XML形式的配置文件
DOMConfigurator.configure(String filename);

获取日志记录器

//使用Log4j获得logger对象
Logger logger = Logger.getLogger(xxx);

//使用Slf4J获得logger对象
 Logger logger = LoggerFactory.getLogger(xxx);

插入记录信息

Logger.debug ( Object message ) ;
Logger.info ( Object message ) ;
Logger.warn ( Object message ) ;
Logger.error ( Object message ) ;

在Spring中使用log4j

  1. 配置web.xml (在Spring配置基础上),也可什么都不配,使用默认的即可

     <context-param>
         <param-name>log4jConfigLocation</param-name>
         <param-value>classpath*:log4j.properties</param-value>
     </context-param>
    
     <!-- 3000表示 开一条watchdog线程每60秒扫描一下配置文件的变化;这样便于日志存放位置的改变 -->
     <context-param>
             <param-name>log4jRefreshInterval</param-name>
             <param-value>3000</param-value>
        </context-param>
     <listener>
         <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>  
     </listener>
    
  2. Bean中使用

     public class SystemAnnualTask
     {
         //log4j获取Logger
         //static Logger logger = Logger.getLogger(SystemAnnualTask.class);
         //通过slf4j获取Logger
         static Logger logger = LoggerFactory.getLogger(SystemAnnualTask.class);
    
         public void startAnnualProcess(){
             ...
             logger.info(xxx);
             //这里增加判断,提高效率(可不判断,直接调用)
             if (logger.isDebugEnabled()){
                 logger.debug(xxx);
             }
             //若使用Slf4j,则可如下使用:
             logger.info("{} is {}", new String[]{“x",“y"});
             ...
         }
     }