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的发展趋势更好: -
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表格形式,如下
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