Java常用日志框架介绍与使用

Java常用日志框架介绍

目前常用的日志框架包括Log4j,Commons Logging,Slf4j,Logback,Jul。

  • Log4j  Apache Log4j是一个基于Java的日志记录工具。它是由Ceki Gülcü首创的,现在则是Apache软件基金会的一个项目。 Log4j是几种Java日志框架之一。

  • Log4j 2  Apache Log4j 2是apache开发的一款Log4j的升级产品。

  • Commons Logging  Apache基金会所属的项目,是一套Java日志接口,之前叫Jakarta Commons Logging,后更名为Commons Logging。

  • Slf4j  类似于Commons Logging,是一套简易Java日志门面,本身并无日志的实现。(Simple Logging Facade for Java,缩写Slf4j)。

  • Logback  一套日志组件的实现(Slf4j阵营)。

  • Jul  (Java Util Logging),自Java1.4以来的官方日志实现。

历史:

  • 1996年早期,欧洲安全电子市场项目组决定编写它自己的程序跟踪API(Tracing API)。经过不断的完善,这个API终于成为一个十分受欢迎的Java日志软件包,即Log4j。后来Log4j成为Apache基金会项目中的一员。

  • 期间Log4j近乎成了Java社区的日志标准。据说Apache基金会还曾经建议Sun引入Log4j到java的标准库中,但Sun拒绝了。

  • 2002年Java1.4发布,Sun推出了自己的日志库JUL(Java Util Logging),其实现基本模仿了Log4j的实现。在JUL出来以前,Log4j就已经成为一项成熟的技术,使得Log4j在选择上占据了一定的优势。

  • 接着,Apache推出了Jakarta Commons Logging,JCL只是定义了一套日志接口(其内部也提供一个Simple Log的简单实现),支持运行时动态加载日志组件的实现,也就是说,在你应用代码里,只需调用Commons Logging的接口,底层实现可以是Log4j,也可以是Java Util Logging。

  • 后来(2006年),Ceki Gülcü不适应Apache的工作方式,离开了Apache。然后先后创建了Slf4j(日志门面接口,类似于Commons Logging)和Logback(Slf4j的实现)两个项目,并回瑞典创建了QOS公司,QOS官网上是这样描述Logback的:The Generic,Reliable Fast&Flexible Logging Framework(一个通用,可靠,快速且灵活的日志框架)。

  • 现今,Java日志领域被划分为两大阵营:Commons Logging阵营和Slf4j阵营。
    Commons Logging在Apache大树的笼罩下,有很大的用户基数。但有证据表明,形式正在发生变化。2013年底有人分析了GitHub上30000个项目,统计出了最流行的100个Libraries,可以看出Slf4j的发展趋势更好:

    Java常用日志框架介绍与使用

  • Apache眼看有被Logback反超的势头,于2012-07重写了Log4j 1.x,成立了新的项目Log4j 2, Log4j 2具有Logback的所有特性。

java常用日志框架关系

  • Log4j 2与Log4j 1发生了很大的变化,Log4j 2不兼容Log4j 1。

  • Commons Logging和Slf4j是日志门面(门面模式是软件工程中常用的一种软件设计模式,也被称为正面模式、外观模式。它为子系统中的一组接口提供一个统一的高层接口,使得子系统更容易使用)。Log4j和Logback则是具体的日志实现方案。可以简单的理解为接口与接口的实现,调用者只需要关注接口而无需关注具体的实现,做到解耦。

  • 比较常用的组合使用方式是Slf4j与Logback组合使用,Commons Logging与Log4j组合使用。

  • Logback必须配合Slf4j使用。由于Logback和Slf4j是同一个作者,其兼容性不言而喻。

Commons Logging与Slf4j实现机制对比

Commons Logging是通过动态查找机制,在程序运行时,使用自己的ClassLoader寻找和载入本地具体的实现。详细策略可以查看commons-logging-*.jar包中的org.apache.commons.logging.impl.LogFactoryImpl.java文件。由于Osgi不同的插件使用独立的ClassLoader,Osgi的这种机制保证了插件互相独立, 其机制限制了Commons Logging在Osgi中的正常使用。

Slf4j在编译期间,静态绑定本地的Log库,因此可以在Osgi中正常使用。它是通过查找类路径下org.slf4j.impl.StaticLoggerBinder,然后在StaticLoggerBinder中进行绑定。

log4j使用

Log4j由三个重要的组件构成:日志记录器(Loggers),输出端(Appenders)和日志格式化器(Layout)。

1.Logger:控制要启用或禁用哪些日志记录语句,并对日志信息进行级别限制

2.Appenders : 指定了日志将打印到控制台还是文件中

3.Layout : 控制日志信息的显示格式

Logger对象的获得或创建

Logger被指定为实体,由一个String类的名字识别。Logger的名字是大小写敏感的,且名字之间具有继承关系,子名用父名作为前缀,用点“.”分隔,例如x.y是x.y.z的父亲。
root Logger(根Logger)是所有Logger的祖先。它有如下属性:1.它总是存在的。2.它不可以通过名字获得。

root Logger可以通过以下语句获得:

public static Logger Logger.getRootLogger();

或:

public static Logger Logger.getLogger(Class clazz)

其中调用Logger.getLogger(Class clazz)是目前Logger对象最理想的方法。
 

日志级别

在org.apache.log4j.Level类中,Log4j只建议使用4个级别,优先级从高到低分别是:error、warn、info、debug。通过使用日志级别控制应用程序中相应级别日志信息的输出。例如,如果使用了info级别,则应用程序中所有低于info级别的日志信息(如debug)将不会被打印出来。

package log4j;

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;

public class Log4jTest {

    public static void main(String[] args) {        

        //获得Logger对象
        Logger logger = Logger.getLogger(Log4jTest.class);        
        //使用默认的配置信息,不需要写log4j.properties
        BasicConfigurator.configure();
        //设置日志输出级别为info,这将覆盖配置文件中设置的级别
        logger.setLevel(Level.INFO);
        //下面的消息将被输出
        logger.info("this is an info");
        logger.warn("this is a warn");
        logger.error("this is an error");
        logger.fatal("this is a fatal");

    }

}

输出端Appender

Appender用来指定日志信息输出到哪个地方。每个Logger都可以拥有一个或多个Appender,每个Appender表示一个日志的输出目的地。

Logger.addAppender(Appender app)为Logger增加一个Appender

Logger.removeAppender(Appender app)为Logger删除一个Appender。

Log4j几种常用的输出目的地:

1,org.apache.log4j.ConsoleAppender:将日志信息输出到控制台。
2,org.apache.log4j.FileAppender:将日志信息输出到一个文件。
3,org.apache.log4j.DailyRollingFileAppender:将日志信息输出到一个日志文件,并且每天输出到一个新的日志文件。
4,org.apache.log4j.RollingFileAppender:将日志信息输出到一个日志文件,并且指定文件的尺寸,当文件大小达到指定尺寸时,会自动把文件改名,同时产生一个新的文件。
5,org.apache.log4j.WriteAppender:将日志信息以流格式发送到任意指定地方。
6,org.apache.log4j.jdbc.JDBCAppender:通过JDBC把日志信息输出到数据库中。

日志格式化器Layout

1.HTMLLayout : 格式化日志输出为HTML表格形式,如下

Java常用日志框架介绍与使用

2.SimpleLayout : 以一种非常简单的方式格式化日志输出,它打印三项内容:级别-信息

例:INFO - info

3.PatternLayout : 根据指定的转换模式格式化日志输出,或者如果没有指定任何转换模式,就使用默认的转化模式格式。

4.TTCCLayout : 包含日志产生的时间、线程、类别等等信息

//下面的代码实现了SimpleLayout和FileAppender的程序
public static void main(String[] args) {        
        Logger logger = Logger.getLogger(Log4jTest.class);        
        SimpleLayout layout = new SimpleLayout();
        //HTMLLayout  layout = new HTMLLayout();
        FileAppender appender = null;
        try
        {
            //把输出端配置到out.txt
            appender = new FileAppender(layout,"out.txt",false);
        }catch(Exception e){}
        logger.addAppender(appender);//添加输出端
        logger.setLevel((Level)Level.DEBUG);//覆盖配置文件中的级别
        logger.debug("debug");
        logger.info("info");
        logger.warn("warn");
        logger.error("error");
        logger.fatal("fatal");
    }
 

Log4j的配置

配置Log4j环境就是指配置root Logger,把Logger为哪个级别,为它增加Appender,以及为Appender设置Layout

BasicConfigurator.configure()方法,用默认的方式,不需要写log4j.properties:

//用默认的方式创建PatternLayout对象p:
  PatternLayout p = new PatternLayout("%-4r[%t]%-5p%c%x-%m%n");
//用p创建ConsoleAppender对象a,目标是System.out,标准输出设备:
 ConsoleAppender a = new ConsoleAppender(p,ConsoleAppender.SYSTEM_OUT);
//为root Logger增加一个ConsoleAppender a;
 rootLogger.addAppender(a);
//把rootLogger的log level设置为DUBUG级别;
 rootLogger.setLevel(Level.DEBUG);

PropertyConfigurator.configure()方法:

当使用以下语句生成Logger对象时:static Logger logger = Logger.getLogger(mycalss.class);

如果没有调用BasicConfigurator.configure(),PropertyConfigurator.configure()或DOMConfigurator.configure()方法,Log4j会自动加载CLASSPATH下名为log4j.properties的配置文件。如果把此配置文件改为其他名字,例如my.properties,程序虽然仍能运行,但会报出不能正确初始化Log4j系统的提示。这时可以在程序中加上:

PropertyConfigurator.configure("classes/my.properties");问题即可解决。

log4j.properties配置详解

  • 配置根Logger,其语法为:

log4j.rootLogger =[level],appenderName,appenderName2,...

//level是日志记录的优先级,分为OFF,TRACE,DEBUG,INFO,WARN,ERROR,FATAL,ALL 
//Log4j建议只使用四个级别,优先级从低到高分别是DEBUG,INFO,WARN,ERROR 
//通过在这里定义的级别,您可以控制到应用程序中相应级别的日志信息的开关 ,比如在这里定义了INFO级别,则应用程序中所有DEBUG级别的日志信息将不被打印出来 
//appenderName就是指定日志信息输出到哪个地方。可同时指定多个输出目的 

  • 配置日志信息输出目的地Appender,其语法为:

log4j.appender.appenderName = fully.qualified.name.of.appender.class

log4j.appender.appenderName.optionN = valueN

Log4j提供的appender有以下几种: 
1)org.apache.log4j.ConsoleAppender(输出到控制台) 
2)org.apache.log4j.FileAppender(输出到文件) 
3)org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件) 
4)org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件) 
5)org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方) 

1)ConsoleAppender选项属性 
 -Threshold = DEBUG:指定日志消息的输出最低层次 
 -ImmediateFlush = TRUE:默认值是true,所有的消息都会被立即输出 
 -Target = System.err:默认值System.out,输出到控制台(err为红色,out为黑色) 

2)FileAppender选项属性 
 -Threshold = INFO:指定日志消息的输出最低层次 
 -ImmediateFlush = TRUE:默认值是true,所有的消息都会被立即输出 
 -File = C:\log4j.log:指定消息输出到C:\log4j.log文件 
 -Append = FALSE:默认值true,将消息追加到指定文件中,false指将消息覆盖指定的文件内容 
 -Encoding = UTF-8:可以指定文件编码格式 

3)DailyRollingFileAppender选项属性 
 -Threshold = WARN:指定日志消息的输出最低层次 
 -ImmediateFlush = TRUE:默认值是true,所有的消息都会被立即输出 
 -File = C:\log4j.log:指定消息输出到C:\log4j.log文件 
 -Append = FALSE:默认值true,将消息追加到指定文件中,false指将消息覆盖指定的文件内容 
 -DatePattern='.'yyyy-ww:每周滚动一次文件,即每周产生一个新的文件。还可以按用以下参数: 
              '.'yyyy-MM:每月 
              '.'yyyy-ww:每周 
              '.'yyyy-MM-dd:每天 
              '.'yyyy-MM-dd-a:每天两次 
              '.'yyyy-MM-dd-HH:每小时 
              '.'yyyy-MM-dd-HH-mm:每分钟 
 -Encoding = UTF-8:可以指定文件编码格式 
 
4)RollingFileAppender选项属性 
 -Threshold = ERROR:指定日志消息的输出最低层次 
 -ImmediateFlush = TRUE:默认值是true,所有的消息都会被立即输出 
 -File = C:/log4j.log:指定消息输出到C:/log4j.log文件 
 -Append = FALSE:默认值true,将消息追加到指定文件中,false指将消息覆盖指定的文件内容 
 -MaxFileSize = 100KB:后缀可以是KB,MB,GB.在日志文件到达该大小时,将会自动滚动.如:log4j.log.1 
 -MaxBackupIndex = 2:指定可以产生的滚动文件的最大数 
 -Encoding = UTF-8:可以指定文件编码格式 

  •  配置日志信息的格式(布局),其语法为: 

log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class 
log4j.appender.appenderName.layout.optionN = valueN 

Log4j提供的layout有以下几种: 
1)org.apache.log4j.HTMLLayout(以HTML表格形式布局) 
2)org.apache.log4j.PatternLayout(可以灵活地指定布局模式) 
3)org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串) 
4)org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息) 
5)org.apache.log4j.xml.XMLLayout(以XML形式布局) 

1)HTMLLayout选项属性 
 -LocationInfo = TRUE:默认值false,输出java文件名称和行号 
 -Title=Struts Log Message:默认值 Log4J Log Messages 
 
2)PatternLayout选项属性 
 -ConversionPattern = %m%n:格式化指定的消息(参数意思下面有) 
 
3)XMLLayout选项属性 
 -LocationInfo = TRUE:默认值false,输出java文件名称和行号 

//Log4J采用类似C语言中的printf函数的打印格式格式化日志信息,打印参数如下: 
 %m 输出代码中指定的消息 
 %p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL 
 %r 输出自应用启动到输出该log信息耗费的毫秒数 
 %c 输出所属的类目,通常就是所在类的全名 
 %t 输出产生该日志事件的线程名 
 %n 输出一个回车换行符,Windows平台为“\r\n”,Unix平台为“\n” 
 %d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式 
    如:%d{yyyy年MM月dd日 HH:mm:ss,SSS},输出类似:2012年01月05日 22:10:28,921 
 %l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数 
    如:Testlog.main(TestLog.java:10) 
 %F 输出日志消息产生时所在的文件名称 
 %L 输出代码中的行号 
 %x 输出和当前线程相关联的NDC(嵌套诊断环境),像java servlets多客户多线程的应用中 
 %% 输出一个"%"字符 
 
// 可以在%与模式字符之间加上修饰符来控制其最小宽度、最大宽度、和文本的对齐方式。如: 
  %5c: 输出category名称,最小宽度是5,category<5,默认的情况下右对齐 
  %-5c:输出category名称,最小宽度是5,category<5,"-"号指定左对齐,会有空格 
  %.5c:输出category名称,最大宽度是5,category>5,就会将左边多出的字符截掉,<5不会有空格 
  %20.30c:category名称<20补空格,并且右对齐,>30字符,就从左边交远销出的字符截掉 

  • 指定特定包的输出特定的级别 log4j.logger.org.springframework=DEBUG

例:

log4j.rootLogger =ALL,systemOut,logFile,logDailyFile,logRollingFile,logMail,logDB 

#输出到控制台 
log4j.appender.systemOut = org.apache.log4j.ConsoleAppender 
log4j.appender.systemOut.layout = org.apache.log4j.PatternLayout 
log4j.appender.systemOut.layout.ConversionPattern = [%-5p][%-22d{yyyy/MM/dd HH:mm:ssS}][%l]%n%m%n 
log4j.appender.systemOut.Threshold = DEBUG 
log4j.appender.systemOut.ImmediateFlush = TRUE 
log4j.appender.systemOut.Target = System.out 

#输出到文件 
log4j.appender.logFile = org.apache.log4j.FileAppender 
log4j.appender.logFile.layout = org.apache.log4j.PatternLayout 
log4j.appender.logFile.layout.ConversionPattern = [%-5p][%-22d{yyyy/MM/dd HH:mm:ssS}][%l]%n%m%n 
log4j.appender.logFile.Threshold = DEBUG 
log4j.appender.logFile.ImmediateFlush = TRUE 
log4j.appender.logFile.Append = TRUE 
log4j.appender.logFile.File = ../Struts2/WebRoot/log/File/log4j_Struts.log 
log4j.appender.logFile.Encoding = UTF-8 

#按DatePattern输出到文件 
log4j.appender.logDailyFile = org.apache.log4j.DailyRollingFileAppender 
log4j.appender.logDailyFile.layout = org.apache.log4j.PatternLayout 
log4j.appender.logDailyFile.layout.ConversionPattern = [%-5p][%-22d{yyyy/MM/dd HH:mm:ssS}][%l]%n%m%n 
log4j.appender.logDailyFile.Threshold = DEBUG 
log4j.appender.logDailyFile.ImmediateFlush = TRUE 
log4j.appender.logDailyFile.Append = TRUE 
log4j.appender.logDailyFile.File = ../Struts2/WebRoot/log/DailyFile/log4j_Struts 
log4j.appender.logDailyFile.DatePattern = '.'yyyy-MM-dd-HH-mm'.log' 
log4j.appender.logDailyFile.Encoding = UTF-8 

#设定文件大小输出到文件 
log4j.appender.logRollingFile = org.apache.log4j.RollingFileAppender 
log4j.appender.logRollingFile.layout = org.apache.log4j.PatternLayout 
log4j.appender.logRollingFile.layout.ConversionPattern = [%-5p][%-22d{yyyy/MM/dd HH:mm:ssS}][%l]%n%m%n 
log4j.appender.logRollingFile.Threshold = DEBUG 
log4j.appender.logRollingFile.ImmediateFlush = TRUE 
log4j.appender.logRollingFile.Append = TRUE 
log4j.appender.logRollingFile.File = ../Struts2/WebRoot/log/RollingFile/log4j_Struts.log 
log4j.appender.logRollingFile.MaxFileSize = 1MB 
log4j.appender.logRollingFile.MaxBackupIndex = 10 
log4j.appender.logRollingFile.Encoding = UTF-8 

#用Email发送日志 
log4j.appender.logMail = org.apache.log4j.net.SMTPAppender 
log4j.appender.logMail.layout = org.apache.log4j.HTMLLayout 
log4j.appender.logMail.layout.LocationInfo = TRUE 
log4j.appender.logMail.layout.Title = Struts2 Mail LogFile 
log4j.appender.logMail.Threshold = DEBUG 
log4j.appender.logMail.SMTPDebug = FALSE 
log4j.appender.logMail.SMTPHost = SMTP.163.com 
log4j.appender.logMail.From = [email protected] 
log4j.appender.logMail.To = [email protected] 
#log4j.appender.logMail.Cc = [email protected] 
#log4j.appender.logMail.Bcc = [email protected] 
log4j.appender.logMail.SMTPUsername = xly3000 
log4j.appender.logMail.SMTPPassword = 1234567 
log4j.appender.logMail.Subject = Log4j Log Messages 
#log4j.appender.logMail.BufferSize = 1024 
#log4j.appender.logMail.SMTPAuth = TRUE 

#将日志登录到MySQL数据库 
log4j.appender.logDB = org.apache.log4j.jdbc.JDBCAppender 
log4j.appender.logDB.layout = org.apache.log4j.PatternLayout 
log4j.appender.logDB.Driver = com.mysql.jdbc.Driver 
log4j.appender.logDB.URL = jdbc:mysql://127.0.0.1:3306/xly 
log4j.appender.logDB.User = root 
log4j.appender.logDB.Password = 123456 
log4j.appender.logDB.Sql = INSERT INTOT_log4j(project_name,create_date,level,category,file_name,thread_name,line,all_category,message)values('Struts2','%d{yyyy-MM-ddHH:mm:ss}','%p','%c','%F','%t','%L','%l','%m')

Commons Logging+log4j使用

我们在使用commons-logging+日志实现工具时,我们的代码只需要和commons-logging打交道,由commons-logging去选择适当的日志实现工具。这里我们看一下commons-logging是如何去选择实现工具的:

,首先在classpath下寻找自己的配置文件commons-logging.properties,如果找到,则使用其中定义的Log实现类:

1.org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog

这个配置,commons-logging会使用commons-logging的SimpleLog

2.org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger

这个配置,commons-logging就会选择使用log4j

3.org.apache.commons.logging.Log=org.apache.commons.logging.impl.Jdk14Logger

这个配置,commons-logging会选择jdk的logger

二,如果找不到commons-logging.properties文件,则在查找是否已定义系统环境变量org.apache.commons.logging.Log,找到则使用其定义的Log实现类

三,否则,查看classpath中是否有Log4j的包,如果发现,则自动使用Log4j作为日志实现类。

四,否则,使用JDK自身的日志实现类(JDK1.4以后才有日志实现类)。

五,否则,使用commons-logging自己提供的一个简单的日志实现类SimpleLog。

可见,commons-logging总是能找到一个日志实现类,并且尽可能找到一个最合适的日志实现类。
为了简化配置,我们可以不使用commons-logging的配置文件,也不设置commons-logging相关的环境变量,只需将log4j的包放入classpath就可以了,这样就可以完成commons-logging与log4j的结合。如果以后不想使用log4j,只需将log4j的包 从classpath中移除就可以了。

在代码中输出日志:

1.导入所需commons-logging的类

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

如果愿意简化的话,还可以两行合为一行: 
import org.apache.commons.logging.*;

2、在自己的类中定义一个org.apache.commons.logging.Log类的私有静态类成员:

private static Log log = LogFactory.getLog(YouClassName.class);

注意这里定义的是static成员,以避免产生多个实例。

3.使用静态类变量输出日志信息

  为了方便的控制日志输出,把日志分成了不同的级别,从低到高分别是调试(DEBUG),信息(INFO),警告(WARN),错误(ERROR),致命错误(FATAL)。这样我们可以通过log4j的配置决定只输出某个级别以上的日志。例如,在开发时我们将debug(调试)及以上的日志全部输出,而在项目正常运行时,设置为只输出warn(警告)及以上的日志。

1.log.debug("debug");
//输出信息级别的日志信息
2.log.info("information");
//输出警告级别的日志信息
3.log.warn("warning");
//输出错误级别的日志信息
4.log.error("error");
//输出致命错误级别的日志信息
5.log.fatal("fatal");
正因为我们可以通过配置文件来设置日志输出的级别,所以写代码时我们并不知道某条日志是不是会真正输出,比如
log.debug("debug");

下面给出一个完整的Java类的代码: 
package liigo.testlog; 
import org.apache.commons.logging.Log; 
import org.apache.commons.logging.LogFactory;

public class TestLog { 
private static Log log = LogFactory.getLog(TestLog.class); 
public void test() { 
log.debug("111"); 
log.info("222"); 
log.warn("333"); 
log.error("444"); 
log.fatal("555"); 
}

public static void main(String[] args) { 
TestLog testLog = new TestLog(); 
testLog.test(); 

}
by:https://www.cnblogs.com/mibloom/p/9871603.html

https://blog.****.net/u011781521/article/details/55002553

https://blog.****.net/qq877507054/article/details/51395856