Java日志框架概述
现有日志框架:
JUL、logback、log4j、log4j2、 JCL、slf4j
日志门面 :JCL、slf4j
日志实现 JUL、logback、log4j、log4j2
日志框架出现的历史顺序: log4j -->JUL-->JCL--> slf4j --> logback --> log4j2
JUL(Java Util logging)
JUL全称Java util Logging是java原生的日志框架,使用时不需要另外引用第三方类库,相对其他日志框 架使用方便,学习简单,能够在小型应用中灵活使用。
JUL组件
- Logger:被称为记录器,应用程序通过获取Logger对象,抵用其API来发布日志信息。Logger通常被认为是访问日志系统的入口程序。
- Handler:处理器,每个Logger都会关联一个或者是一组Handler,Logger会将日志交给关联的Handler去做处理,由Handler负责将日志做记录。Handler具体实现了日志的输出位置,比如可以输出到控制台或者是文件中等等。
- Filter:过滤器,根据需要定制哪些信息会被记录,哪些信息会被略过。
- Formatter:格式化组件,它负责对日志中的数据和信息进行转换和格式化,所以它决定了我们输出日志最终的形式。
- Level:日志的on'n级别,每条日志消息都有一个关联的级别。我们根据输出级别的设置,用来展现最终所呈现的日志信息。
总结:
用户使用Logger来进行日志记录,Logger持有若干个Handler,日志的输出操作是由Handler完成的。 在Handler在输出日志前,会经过Filter的过滤,判断哪些日志级别过滤放行哪些拦截,Handler会将日 志内容输出到指定位置(日志文件、控制台等)。Handler在输出日志时会使用Layout,将输出内容进 行排版。
JUL Demo
// 测试日志实现
public class JULTest {
@Test
public void testQuick() throws Exception {
// 1.创建日志记录器对象
Logger logger = Logger.getLogger("com.itheima.log.JULTest");
// 2.日志记录输出
logger.info("hello jul");
logger.log(Level.INFO, "info msg");
String name = "jack";
Integer age = 18;
logger.log(Level.INFO, "用户信息:{0},{1}", new Object[]{name, age});
}
}
// 日志级别
public void testLogLevel() throws Exception {
// 1.获取日志对象
Logger logger = Logger.getLogger("com.itheima.log.QuickTest");
// 2.日志记录输出
logger.severe("severe");
logger.warning("warning");
logger.info("info");
logger.config("cofnig");
logger.fine("fine");
logger.finer("finer");
logger.finest("finest");
}
Log4j
Log4j主要由oggers(日志记录器)、Appenders(输出控制器)和Layout(日志格式化器)组成。其中Loggers控制日志的输出以及输出级别;Appenders指定日志的输出方式(输出到控制台、文件等);Layout控制日志信息的输出格式。
Log4j组件介绍
Loggers
日志记录器,负责收集处理日志记录,实例的命名就是类的全限定名,如com.bjpowernode.log4j.XX,Logger的名字大小写敏感,其命名有继承机制:例如:name为com.bjpowernode.log4j的logger会继承 name为com.bjpowernode。Log4J中有一个特殊的logger叫做“root”,他是所有logger的根,也就意味着其他所有的logger都会直接或者间接地继承自root。root logger可以用Logger.getRootLogger)方法获取。自log4j1.2版以来,Logger类已经取代了Category类。对于熟悉早期版本的log4j的人来说,Logger类可以被视为Category类的别名。
Appenders (相当于JUL的Handler)
记录日志以及定义日志的级别仅仅是Log4j的基本功能,Log4j日志系统还提供许多强大的功能,比如允许把日志输出到不同的地方,如控制台(Console)、文件(Files)等,可以根据天数或者文件大小产生新的文件,可以以流的形式发送到其它地方等等。 常用Appenders:
- ConsoleAppender 将日志输出到控制台
- FileAppender 将日志输出到文件中
- DailyRollingFileAppender 将日志输出到一个日志文件,并且每天输出到一个新的文件
- RollingFileAppender将日志信息输出到一个日志文件,并且指定文件的尺寸,当文件大小达到指定尺寸时,会自动把文件改名,同时产生一个新的文件
- JDBCAppender 把日志信息保存到数据库中
#指定日志的输出级别与输出端
log4j.rootLogger=INFO,Console
# 控制台输出配置
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
# 文件输出配置
log4j.appender.A = org.apache.log4j.DailyRollingFileAppender
#指定日志的输出路径
log4j.appender.A.File = D:/log.txt
log4j.appender.A.Append = true
#使用自定义日志格式化器
log4j.appender.A.layout = org.apache.log4j.PatternLayout
#指定日志的输出格式
log4j.appender.A.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [%t:%r] -
[%p] %m%n
#指定日志的文件编码
log4j.appender.A.encoding=UTF-8
#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://localhost:3306/test
log4j.appender.logDB.User=root
log4j.appender.logDB.Password=root
log4j.appender.logDB.Sql=INSERT INTO
log(project_name,create_date,level,category,file_name,thread_name,line,all_categ
ory,message) values('itcast','%d{yyyy-MM-dd
HH:mm:ss}','%p','%c','%F','%t','%L','%l','%m')
Layout(相当于JUL的Formater)
有时用户希望根据自己的喜好格式化自己的日志输出,Log4j可以在Appenders的后面附加Layouts来完成这个功能。Layouts提供四种日志输出样式,如根据HTML样式、自由指定样式、包含日志级别与信息的样式和包含日志时间、线程、类别等信息的样式。 常用Layouts:
HTMLLayout 格式化日志输出为HTML表格形式
SimpleLayout 简单的日志输出格式化,打印的日志格式如默认INFO级别的消息
PatternLayout 最强大的格式化期,可以根据自定义格式输出日志,如果没有指定转换格式,就是用默认的转换格式
日志级别
关于日志级别信息,例如DEBUG、INFO、WARN、ERROR...级别是分大小的,
* 每个Logger都被了一个日志级别(log level),用来控制日志信息的输出。日志级别从高到低分为:
fatal 指出每个严重的错误事件将会导致应用程序的退出。
error 指出虽然发生错误事件,但仍然不影响系统的继续运行。
warn 表明会出现潜在的错误情形。
info 一般和在粗粒度级别上,强调应用程序的运行全程。
debug 一般用于细粒度级别上,对调试应用程序非常有帮助。
trace 是程序追踪,可以用于输出程序运行中的变量,显示执行的流程。
* 还有两个特殊的级别:
OFF 可用来关闭日志记录。
ALL 启用所有消息的日志记录。
日志格式输出说明
使用PatternLayout可以自定义格式输出,是我们最常用的方式这种格式化输出采用类似于C语言的printf函数的打印格式格式化日志信息,具体的占位符及其含义如下:
%m输出代码中指定的日志信息
%p输出优洗级,及DEBUG、INFO等
%n换行符(Windows平台的换行符为"\n",Unix平台为"\n")
%r输出自应用启动到输出该log信息耗费的毫秒数
%c输出打印语句所属的类的全名
%t输出产生该日志的线程全名
%d输出服务器当前时间,默认为ISO8601,也可以指定格式,如:%d{yyyy年MM月dd日HH:mm:ss}
Log4j Demo
-
引入依赖
<dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> -
使用log4j
public class Log4jTest { @Test public void testQuick() throws Exception { // 初始化系统配置,不需要配置文件 BasicConfigurator.configure(); // 创建日志记录器对象 Logger logger = Logger.getLogger(Log4jTest.class); // 日志记录输出 logger.info("hello log4j"); // 日志级别 logger.fatal("fatal"); // 严重错误,一般会造成系统崩溃和终止运行 logger.error("error"); // 错误信息,但不会影响系统运行 logger.warn("warn"); // 警告信息,可能会发生问题 logger.info("info"); // 程序运行信息,数据库的连接、网络、IO操作等 logger.debug("debug"); // 调试信息,一般在开发阶段使用,记录程序的变量、参数等 logger.trace("trace"); // 追踪信息,记录程序的所有流程信息 } }
JCL(日志门面)
全称为Jakarta Commons Logging,是Apache提供的一个通用日志API。 它是为 "所有的Java日志实现"提供一个统一的接口,它自身也提供一个日志的实现,但是功能非常常弱 (SimpleLog)。所以一般不会单独使用它。他允许开发人员使用不同的具体日志实现工具: Log4j, Jdk 自带的日志(JUL) JCL 有两个基本的抽象类:Log(基本记录器)和LogFactory(负责创建Log实例)。
JCL存在的必要性
SLF4J
SLF4J简介
简单日志门面(Simple Logging Facade For Java)SLF4主要是为了给Java日志访问提供一套标准、规范的API框架,其主要意义在于提供接口,具体的实现可以交由其他日志框架,例如log4j和logback等。当然slf4j自己也提供了功能较为简单的实现,但是一般很少用到。 对于一般的Java项目而言,日志框架会选择slf4j-api作为门面,配上具体的实现框架(log4j、logback等),中间使用桥接器完成桥接。所以我们可以得出SLF4J最重要的两个功能就是对于日志框架的绑定以及日志框架的桥接。
SLF4J桥接技术
通常,我们依赖的某些组件依赖于SLF4J以外的日志API。我们可能还假设这些组件在不久的将来不会切换到SLF4J。为了处理这种情况,SLF4J附带了几个桥接模块,这些模块会将对log4j,JCL和java.util.loggingAPI的调用重定向为行为,就好像是对SLF4JAPI进行的操作一样。
Logback
Logback是由log4j创始人设计的又一个开源日志组件。 Logback当前分成三个模块:logback-core,logback-classic和logback-access。
- logback-core是其它两个模块的基础模块。
- logback-classic是log4j的一个改良版本。此外logback-clasic完整实现SLF4JAPI。使你可以很方便地更换成其它日志系统如log4j或JDK14Logging。
- logback-access 访问模块与Servlet容器集成提供通过Http来访问日志的功能。
Logback的组件
Logger:日志的记录器,主要用于存放日志对象,也可以定义日志类型、级别。 Appender: 用于指定日志输出的目的地,目的地可以是控制台、文件、数据库等等。 Layout:负责把事件转换成字符串,格式化的日志信息的输出。在Logback中Layout对象被封装在encoder中。也就是说我们未来使用 的encoder 其实就是Layoute
Logback配置文件
Logback提供了3种配置文件 logback.groovy logback-test.xml logback.xml 如果都不存在则采用默认的配置
Logback输出格式
日志输出格式:
%-10level级别案例为设置10个字符,左对齐
%d{yyyy-MM-dd HH:mm:ss.SSS}日期
%c当前类全限定名
%M当前执行日志的方法
%L行号
%thread 线程名称
%m或者%msg信息息
%n换行
LogbackDemo
-
引入依赖
<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.25</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency> -
Logback配置
<?xml version="1.0" encoding="UTF-8" ?> <configuration> <!--日志输出格式--> <property name="pattern2" value="[%-5level] %d{yyyy-MM-dd HH:mm:ss} %c %M %L %thread %m%n"></property> <property name="colorPattern" value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) |%highlight(%-5level) |%blue(%thread) |%blue(%file:%line) |%green(%logger) |%cyan(%msg%n)"/> <property name="filePattern" value="%d{yyyy-MM-dd HH:mm:ss} |%-5level |%thread |%file:%line |%logger |%msg%n"/> <!--日志文件输出路径--> <property name="logDir" value="D:\\code\\Java\\deviceOnline\\log"></property> <!--输出到文件中--> <!-- <appender name="fileAppender" class="ch.qos.logback.core.FileAppender" > <file>${logDir}/deviceOnline.log</file> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <pattern>${pattern}</pattern> </encoder> </appender>--> <!--切割日志文件 --> <appender name="rollingFileAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <pattern>${filePattern}</pattern> </encoder> <file>${logDir}/deviceOnline.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <fileNamePattern>${logDir}/deviceOnline.%d{yyyy-MM-dd}.log%i.gz</fileNamePattern> <maxFileSize>2MB</maxFileSize> </rollingPolicy> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>INFO</level> <!--高于level中设置的级别,则打印日志--> <onMatch>ACCEPT</onMatch> <!--低于level中设置的级别,则不打印日志--> <onMismatch>DENY</onMismatch> </filter> </appender> <!--配置控制台的过滤器--> <appender name="consoleFilterAppender" class="ch.qos.logback.core.ConsoleAppender"> <target>System.err</target> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <pattern>${colorPattern}</pattern> </encoder> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>INFO</level> <!--高于level中设置的级别,则打印日志--> <onMatch>ACCEPT</onMatch> <!--低于level中设置的级别,则打印日志--> <onMismatch>DENY</onMismatch> </filter> </appender> <root level="ALL"> <appender-ref ref="rollingFileAppender"></appender-ref> <appender-ref ref="consoleFilterAppender"></appender-ref> </root> </configuration> -
使用Logback
//定义日志对象 public final static Logger LOGGER = LoggerFactory.getLogger(LogBackTest.class); @Test public void testSlf4j(){ //打印日志信息 LOGGER.error("error"); LOGGER.warn("warn"); LOGGER.info("info"); LOGGER.debug("debug"); LOGGER.trace("trace"); }Log4j
Apache Log4j 2是对Log4j的升级版,参考了logback的一些优秀的设计,并且修复了一些问题,因此带 来了一些重大的提升,主要有:
- 异常处理,在logback中,Appender中的异常不会被应用感知到,但是在log4j2中,提供了一些异 常处理机制。
- 性能提升, log4j2相较于log4j 和logback都具有很明显的性能提升,后面会有官方测试的数据。
- 自动重载配置,参考了logback的设计,当然会提供自动刷新参数配置,最实用的就是我们在生产 上可以动态的修改日志的级别而不需要重启应用。
- 无垃圾机制,log4j2在大部分情况下,都可以使用其设计的一套无垃圾机制,避免频繁的日志收集 导致的jvm gc。