一 日志框架和日志门面
- 日志框架/日志实现:
JUL: Java util logging
log4j: Log for java
logback:
log4j2: - 日志门面
JCL: java commong logging
SLF4J: simple logging facade for java - 出现顺序
log4j → JUL → JCL(门面) → slf4j(门面) → logback → slf4j2
二 日志框架的使用
1. JUL日志框架
-
组件
Logger
Handder
Formatter -
logger之日记录器,入口Logger.getLogger
Logger logger = Logger.getLogger(Dailylog.class);
logger.info("info log");
logger.debug("debug log");
2. log4j日志框架
-
组件(对应于JUL的组件)
Loggers<==>Logger
Handder<==>Appender
Formatter<==>Layout -
logger之日记录器,入口Logger.getLogger
Logger logger = Logger.getLogger(Dailylog.class);
logger.info("info log");
logger.debug("debug log");
- log4j的配置文件
路径/文件名: Resouces > log4j.properties
逗号隔开:log4j.rootLogger = 日志级别,appenderName1, appenderName2
layout使用中最多的就是PatternLayout自定义输出格式,格式定义在ConversionPattern中实现:
log4j.rootLogger=INFO, stdout, logfile
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:ss} <%p> %c %m%n
日志格式的占位符意义:
%d 当前服务器时间
%c category
%m 相应的消息
%n 换行
%p 日志级别
%r 自开始执行到当前日志打印的时间
%10r 十个字符,空格补齐,右对齐 %-10r 十个字符,左对齐
-
FileAppender
-
RollingFileAppender
-
DailyRollingFileAppender
log4j.rootLogger=INFO, logfile
log4j.appender.logfile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.logfile.file=test-output/log4j_log/myLog4j.log
log4j.appender.logfile.encoding=UTF-8
log4j.appender.logfile.Append=true
log4j.appender.logfile.DatePattern='.'yyyy-MM-dd //按照日拆分,如果'.'yyyy-MM-dd HH-mm-ss就是按秒拆分
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} <%p> %c %m%n
三 日志门面的使用
- 日志门面统一了不同日志框架的不同API,写了一套统一的API,它本身不实现日志记录功能,自己只是提供了统一的接口,如果使用一款日志门面,具体的实现框架可以是多个框架。
-
logger入口统一:LogFactory.getLogger(xxx.class)
-
appenders
-
Layout
- 日志门面技术
- 统一入口接入API, LogFactory.getLogger(xxx.class),不再依赖具体的日志框架
package com.learn.log;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class NewLogTest {
//测试门面slf4j
//import里面没有指定具体用哪个log框架实现的
//具体log框架:
// 如果dependency里面有log4j就用log4j,
// 如果没有依赖,就用JUL(JDK自带的log框架)
@Test
public void logTest1(){
Logger logger = LoggerFactory.getLogger(NewLogTest.class);
logger.info("slf4j");
}
}
-
统一日志level
trace
debug
info
warn
error -
日志门面技术和具体的日志实现(框架)组合时候,由于出场时间的问题,在日志门面技术之前出现的日志实现(框架),需要适配器
技术出场顺序:log4j → JUL → JCL(门面) → slf4j(门面) → slf4j2- slf4j日志门面与日志实现绑定的图,来自slf4j用户手册https://slf4j.org/manual.html
- slf4j日志门面与日志实现绑定的图,来自slf4j用户手册https://slf4j.org/manual.html
- 日志门面,slf4j,有三种情况,对日志实现进行绑定
- 在没有任何日志实现绑定的情况下,是不能实现任何功能的,须得加上slf4j-simple的依赖
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.25</version>
</dependency>
-
logback,simple,nop都是出现在slf4j时间线后面的技术,只需要导入相应日志实现/框架的依赖包,就可以实现slf4j无缝衔接
-
log4j和JUL都是slf4j日志门面时间线之前的,API不符合slf4j的设计,所以,需要适配器来与日志门面衔接使用
-
dependency里面加了多个日志实现,先绑定哪个就用哪个,所以我们添加dependency的收就加一个就行
- slf4j与之前的日志框架适配的依赖,也就是适配器
- 与JUL适配,除了添加slf4j的依赖,还需要添加适配器:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>2.0.9</version>
</dependency>
*JUL是JDK内置的,本身不需要添加依赖*
- 与log4j适配,除了添加slf4j的依赖,还需要添加: log4j和适配器:
<!-- log4j自己的依赖-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.13</version>
</dependency>
<!-- log4j的适配器-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>
四 最新的日志框架/日志实现技术logckback
- logback是log4j的改良版,跟log4j是同一个创始人设计的,完全符合slf4j日志门面
- logback分三个模块, logback-core, logback-classic, logback-access, 其中logback-core是其他两个模块的基础模块
- 组件:
Logger
Appender
Layout封装在encoder中
%-10level 十个字符,左对齐
%d{yyyy-MM-dd HH:mm:ss.SSS} 日期
%c 当前类全限定名
%M 当前执行日志的方法名
%L 行号
%thread 线程名称
%m或者%msg 日志信息
%n 换行
- 配置文件
logback.groovy
logback-test.xml
logback.xml
我写了两个appender
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<property name="pattern" value="[%-5level] %d{yyyy-MM-dd} %c %M %L %thread %m%n"></property>
<appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
<!--
System.err是红色
System.out是黑色
-->
<target>
System.out
</target>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${pattern}</pattern>
</encoder>
</appender>
<appender name="fileAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${pattern}</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<append>true</append>
<maxHistroy>5</maxHistroy>
<minIndex>1</minIndex>
<maxIndex>5</maxIndex>
<totalSizeGap>50MB</totalSizeGap>
<!--必须包含%i和%d-->
<fileNamePattern>test-output/logback_log/myLogback.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>1MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
</appender>
<!--root logger的配置,level和appenders-->
<root level="ALL">
<appender-ref ref = "consoleAppender"></appender-ref>
<appender-ref ref = "fileAppender"></appender-ref>
</root>
</configuration>
- 依赖
<!-- logback不需要适配器,只需要添加自己的两个依赖包即可-->
<!--logback-core是classic的基础模块,根据maven的依赖传递属性,不需要额外添加-->
<dependency>
<groupId>com.hynnet</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.3</version>
</dependency>
- logger入口没有变化
package com.learn.log;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class NewLogTest {
//测试门面slf4j
//import里面没有指定具体用哪个log框架实现的
//具体log框架:
// 如果dependency里面有log4j就用log4j,
// 如果没有依赖,就用JUL(JDK自带的log框架)
//代码不需要改动,只需要修改依赖包就可以,这就是日志门面的好处
@Test
public void logTest1(){
Logger logger = LoggerFactory.getLogger(NewLogTest.class);
logger.info("slf4j");
String name = "harry";int age = 10;
logger.info("学生姓名:{};学生年龄:{}",name,age);
}
}