spring boot slf4j与log4j

本文主要内容:1.spring boot的日志配置 2.log4j的配置
一.准备:
默前的主流日志框架:

接口实现
JCL(Jakarta Commons Logging)2014年后不再维护
SLF4j(Simple LoggingFacade for Java)
jboss-logging
Log4j
JUL(java.util.logging)
Log4j2
Logback

先说一下,目前三大框架默认的日志框架
Spring:jcl(jakarta Commons Logging)–优先实现类:Log4j,如果在运行时没有发现任何其他日志框架,则commons-loggin会直接使用JDK的日志系统(java.util.logging)。
在spring-core这个模块中引入了该依赖jcl;
Hibernate:jboss-logging-- 实现类:自已的
Mybits:有自己的日志接口,然后在需要进行日志输出的时候使用统一的API进行日志输出。这个统一的接口是org.apache.ibatis.logging.Log。Mybatis分别基于常用的日志输出工具给出了对应的实现,默认情况下Mybatis的org.apache.ibatis.logging.LogFactory会按照以下顺序依次判断当前程序下可以使用哪种日志实现,直到找到为止,如果一个实现都没有那就是最后的noLogging了,将采用NoLoggingImpl实现;

使用的顺序为:
slf4j框架的实现类
JCL(jakarta Commons logging)框架的实现类
log4j2
JUL(java,util.logging)
useNoLogging

static {
        tryImplementation(new Runnable(){
@Override
public void run(){
        useSlf4jLogging();
        }
        });
        tryImplementation(new Runnable(){
@Override
public void run(){
        useCommonsLogging();
        }
        });
        tryImplementation(new Runnable(){
@Override
public void run(){
        useLog4J2Logging();
        }
        });
        tryImplementation(new Runnable(){
@Override
public void run(){
        useLog4JLogging();
        }
        });
        tryImplementation(new Runnable(){
@Override
public void run(){
        useJdkLogging();
        }
        });
        tryImplementation(new Runnable(){
@Override
public void run(){
        useNoLogging();
        }
        });
        }

二.Spring boot:默认slf4j–实现类:logback
1.5.9的依赖:
在这里插入图片描述
2.1.8的依赖,可以发现,2.1.8的去掉了jcl-to-slf4j的替换包,为什么会去掉呢?
参考https://blog.csdn.net/weixin_36507118/article/details/85341379
boot2.0对于的应该是spring5,在spring5在jcl的基础上自己做了优化,整理成了spring-jcl;虽然还是用jcl框架,但是已经不支持log4j, 而是按照log4j2实现类,slf4j接口,jul来初始化日志实现类的; 即默认的spring5会使用jul来管理日志;
个人觉得应该是spring5把jcl独立出core了,不需要从core排除了;
在这里插入图片描述

如果我要切换其他实现类呢?
1.默认情况
只要引入了spring-boot-starter-web包,那么就会自动引入spring-boot-starter-logging依赖,并且排除了jcl框架
在这里插入图片描述

对于boot1.5.9的,可以看到在引入spring-core的时候自动排除了commons-logging(jcl框架),而2.0不需要排除,因为独立出来了。
在这里插入图片描述
在这里插入图片描述
默认就可以直接测试了

package com.ysy.springboot01;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * Created by ysy on 2019/09/20 17:59
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class TestLog {

    Logger log = LoggerFactory.getLogger(this.getClass());
    //LoggerFactory.getLogger(this.getClass());
    /*1. 以下日志级别,由低到高:trace < debug < info < warn < error
        2. Spring Boot默认设定的是 info 级别日志,(日志默认级别也称为root级别)。
         可修改默认级别日志:logging.level.root=级别名
         如logging.level.root=debug,那么启动的时候,所以debug以上(包括自已的)的日志就会打印出来,
         这个跟设置debug=true类似;
        3. 可以进行调整日志级别,设定某个级别后,就只打印设定的这个级别及后面高级别的日志信息
         没有指定级别的就用SpringBoot默认规定的级别:root级别
        4. 可修改指定包的日志级别:
         指定某个包下面的所有日志级别:logging.level.包名=级别名
         如logging.level.com.ysy=info
*/
    @Test
    public void t1() {
        //System.out.println(this.getClass());
        //因为默认是info级别,所以trace和debug不会被打印出来
        log.trace("trace");
        log.debug("debug");
        log.info("info");
        log.warn("warn");
        log.error("error");
    }
}

那么默认的打印格式是怎么来的呢?比如在spring.boot:2.1.8.RELEASE中的logging文件夹下面:
在这里插入图片描述

base.xml这里规定了默认输出级别info,已经LOG_FILE的默认值,这里最后取的是-/tem这个是不存在的,所以默认没有文件输出;
<included>
	<include resource="org/springframework/boot/logging/logback/defaults.xml" />
	<property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}}/spring.log}"/>
	<include resource="org/springframework/boot/logging/logback/console-appender.xml" />
	<include resource="org/springframework/boot/logging/logback/file-appender.xml" />
	<root level="INFO">
		<appender-ref ref="CONSOLE" />
		<appender-ref ref="FILE" />
	</root>
</included>

defaults.xml
这里定义了CONSOLE_LOG_PATTERN/FILE_LOG_PATTERN等的默认值
<included>
	<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
	<conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
	<conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
	<property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
	<property name="FILE_LOG_PATTERN" value="${FILE_LOG_PATTERN:-%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>

	<logger name="org.apache.catalina.startup.DigesterFactory" level="ERROR"/>
	<logger name="org.apache.catalina.util.LifecycleBase" level="ERROR"/>
	<logger name="org.apache.coyote.http11.Http11NioProtocol" level="WARN"/>
	<logger name="org.apache.sshd.common.util.SecurityUtils" level="WARN"/>
	<logger name="org.apache.tomcat.util.net.NioSelectorPool" level="WARN"/>
	<logger name="org.eclipse.jetty.util.component.AbstractLifeCycle" level="ERROR"/>
	<logger name="org.hibernate.validator.internal.util.Version" level="WARN"/>
</included>

控制台追加器
<included>
	<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
		<encoder>
			<pattern>${CONSOLE_LOG_PATTERN}</pattern>
			<charset>utf8</charset>
		</encoder>
	</appender>
</included>

文件追加器
<included>
	<appender name="FILE"
		class="ch.qos.logback.core.rolling.RollingFileAppender">
		<encoder>
			<pattern>${FILE_LOG_PATTERN}</pattern>
		</encoder>
		<file>${LOG_FILE}</file>
		<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
			<fileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz</fileNamePattern>
			<maxFileSize>${LOG_FILE_MAX_SIZE:-10MB}</maxFileSize>
			<maxHistory>${LOG_FILE_MAX_HISTORY:-0}</maxHistory>
		</rollingPolicy>
	</appender>
</included>

具体映射实现参考LoggingApplicationListener

可以在application.properties 修改日志文件的生成路径,
在这里插入图片描述

server.port=8081
#设置root级别
logging.level.root=info
# 日志输出格式说明:
# %d 输出日期时间,
# %thread 输出当前线程名,
# %-5level 输出日志级别,左对齐5个字符宽度
# %logger{50} 输出全类名最长50个字符,超过按照句点分割
# %msg 日志信息
# %n 换行符
# 修改控制台输出的日志格式

#设置文件路经,默认的文件名是spring.log
logging.path=D:/log
#不指定的话,默认spring.log

# 跟logging.path是互斥的,设置文件名,默认是在项目根目录下
# 同时设置的话,以logging.file优先
#logging.file=springboot.log

logging.pattern.console=%d{yyyy-MM-dd} [%thread] %-5level %logger{50} - %msg%n
# 修改文件中输出的日志格式
logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss.SSS} >>> [%thread] >>> %-5level >>>%logger{50} >>> %msg%n

可以自定义配置文件:

Logging System自定义日志配置文件名
Logback logback-spring.xml , logback-spring.groovy , logback.xml , or logback.groovy
Log4j2 log4j2-spring.xml or log4j2.xml
JDK (Java Util Logging) logging.properties
log4log4j.properties

其中,默认的logback,如果使用logback.xml则直接被加载,如果使用logback-spring.xml,则由spring-boot加载,可以使用一些高级功能:比如指定日志的运行环境,具体参考官方文档

<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<!‐‐
日志输出格式:
%d表示日期时间,
%thread表示线程名,
%‐5level:级别从左显示5个字符宽度
%logger{50} 表示logger名字最长50个字符,否则按照句点分割。
%msg:日志消息,
%n是换行符
‐‐>
<layout class="ch.qos.logback.classic.PatternLayout">
<springProfile name="dev">
<pattern>%d{yyyy‐MM‐dd HH:mm:ss.SSS} ‐‐‐‐> [%thread] ‐‐‐> %‐5level
%logger{50} ‐ %msg%n</pattern>
</springProfile>
<springProfile name="!dev">
<pattern>%d{yyyy‐MM‐dd HH:mm:ss.SSS} ==== [%thread] ==== %‐5level
%logger{50} ‐ %msg%n</pattern>
</springProfile>
</layout>
</appender>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐web</artifactId>
<exclusions>
<exclusion>
<artifactId>logback‐classic</artifactId>
<groupId>ch.qos.logback</groupId>
</exclusion>
<exclusion>
<artifactId>log4j‐over‐slf4j</artifactId>

如果要使用log4j2呢?
只需要如下配置:

  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
<!--            先排除 spring-boot-starter-logging 日志启动器-->
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
<!--        再使用 log4j2 日志启动器-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
        </dependency>

配置完,就可以使用slf4j+log4j2组合了;
看看底层依赖:
1.5.9
在这里插入图片描述
2.1.8的,少了jcl-over-slf4j
在这里插入图片描述

下面开始介绍slf4j与log4j的组合
1. slf4j-api
slf4j:Simple Logging Facade for Java,为java提供的简单日志Facade。Facade门面,更底层一点说就是接口。它允许用户以自己的喜好,在工程中通过slf4j接入不同的日志系统。

因此slf4j入口就是众多接口的集合,它不负责具体的日志实现,只在编译时负责寻找合适的日志系统进行绑定。具体有哪些接口,全部都定义在slf4j-api中。查看slf4j-api源码就可以发现,里面除了public final class LoggerFactory类之外,都是接口定义。因此slf4j-api本质就是一个接口定义。
具体的配置文件,还是用实现类的,比如log4j.properties,log4j2.xml,logback.xml

它只提供一个核心slf4j api(就是slf4j-api.jar包),这个包只有日志的接口,并没有实现,所以如果要使用就得再给它提供一个实现了些接口的日志包,比 如:log4j,common logging,jdk log日志实现包等,但是这些日志实现又不能通过接口直接调用,实现上他们根本就和slf4j-api不一致,因此slf4j又增加了一层来转换各日志实 现包的使用,比如slf4j-log4j12等。

slf4j+log4j组合使用模式:

  1. slf4j-api-1.5.11.jar
  2. slf4j-log4j12-1.5.11.jar 适配器
  3. log4j-1.2.15.jar
  4. log4j.properties(也可以是 log4j.xml)

具体使用日志类的API:

  1. log4j:
    import org.apache.log4j.Logger;
    Logger logger= Logger.getLogger(xx.class);

  2. slf4j+log4j:
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    Logger logger = LoggerFactory.getLogger(xx.class);

2. slf4j-api、slf4j-log4j12、log4j
下图比较清晰的描述了它们之间的关系,例子为当系统采用log4j作为日志框架实现的调用关系:
在这里插入图片描述
3. 首先系统包含slf4j-api作为日志接入的接口:编译时slf4j-api中public final class LoggerFactor类中private final static void bind()方法会寻找具体的日志实现类绑定,主要通过StaticLoggerBinder.getSingleton()的语句调用。
4. slf4j-log4j12是链接slf4j-api和log4j中间的适配器:它实现了slf4j-api中StaticLoggerBinder接口,从而使得在编译时绑定的是slf4j-log4j12的getSingleton()方法。
5. log4j是具体的日志系统:通过slf4j-log4j12初始化Log4j,达到最终日志的输出。

那么slf4j如何统一各个接口框架为自已的呢?当系统存在其他日志框架时,运用jar替换来调用slf4框架,进而调用其实现类;
在这里插入图片描述

3. log4j 的单独使用
3.1 log4j的使用
(1)使用eclipse创建maven工程,在maven中增加依赖:

log4j
// 一般创建工程,建议通过slf4j设计日志系统,方便扩展
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-log4j12</artifactId>
  <version>1.7.22</version>
</dependency>
 
// 可以用于学习log4j,正式项目中不推荐使用,这样是依赖具体的log4j日志系统。
<dependency>
  <groupId>log4j</groupId>
  <artifactId>log4j</artifactId>
  <version>1.2.17</version>
</dependency>  

如果是log4j2
<!--log4j2核心包-->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.9.1</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.9.1</version>
</dependency>
<!-- Web项目需添加 -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-web</artifactId>
    <version>2.9.1</version>
</dependency>
<!--用于与slf4j保持桥接-->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>2.9.1</version>
</dependency>
<!-- slf4j核心包-->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.25</version>
</dependency>

如果是logback,不需要是适配器
           <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>
 
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-core</artifactId>
			<version>1.2.3</version>
		</dependency>

在这里插入图片描述
log4j.properties的内容如下:

# 级别,名称
log4j.rootLogger = debug, console
 
log4j.appender.console = org.apache.log4j.ConsoleAppender #日志输出到控制台
log4j.appender.console.Target = System.out
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%m%n # 日志格式
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HelloWorld {
  public static void main(String[] args) {
    Logger logger = LoggerFactory.getLogger(HelloWorld.class);
    logger.info("Hello World");
  }
}

3.2配置说明
Log4j由三个重要的组件构成:日志信息的优先级,日志信息的输出目的地,日志信息的输出格式。

日志信息的优先级从高到低有ERROR、WARN、 INFO、DEBUG,分别用来指定这条日志信息的重要程度;

日志信息的输出目的地指定了日志将打印到控制台还是文件中;

而输出格式则控制了日志信息的显示内容。

3.2.1 定义配置文件
可以完全不使用配置文件,而是在代码中配置Log4j环境。但是使用配置文件将使您的应用程序更加灵活。Log4j支持两种配置文件格式,一种是XML格式的文件,一种是Java特性文件(键=值)。

(1)配置根Logger

log4j.rootLogger = level, appenderName, appenderName, …

其中,level 是日志记录的优先级,分为OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者您定义的级别。Log4j建议只使用四个级别,优 先级从高到低分别是ERROR、WARN、INFO、DEBUG。

每个Logger都被了一个日志级别(log level),用来控制日志信息的输出。日志级别从高到低分为:

off 最高等级,用于关闭所有日志记录。
fatal 指出每个严重的错误事件将会导致应用程序的退出。
error 指出虽然发生错误事件,但仍然不影响系统的继续运行。
warm 表明会出现潜在的错误情形。
info 一般和在粗粒度级别上,强调应用程序的运行全程。
debug 一般用于细粒度级别上,对调试应用程序非常有帮助。
all 最低等级,用于打开所有日志记录。
通过在这里定义的级别,您可以控制到应用程序中相应级别的日志信息的开关。比如在这里定 义了INFO级别,则应用程序中所有DEBUG级别的日志信息将不被打印出来。

appenderName就是指level级别的日志信息输出到哪个地方,可以同时指定多个输出目的地。

(2)配置日志信息输出目的地Appender

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

log4j.appender.appenderName.option = valueN

其中,Log4j提供的appender有以下几种:

org.apache.log4j.ConsoleAppender(控制台)
org.apache.log4j.FileAppender(文件)
org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件)
org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件)
org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)
(3)配置日志信息的格式(布局)

log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class
log4j.appender.appenderName.layout.option1 = value1

log4j.appender.appenderName.layout.option = valueN

其中,Log4j提供的layout有以下几种:

org.apache.log4j.HTMLLayout(以HTML表格形式布局)
org.apache.log4j.PatternLayout(可以灵活地指定布局模式)
org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串)
org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息)
log4J采用类似C语言中的printf函数的打印格式格式化日志信息,打印参数如下: %m 输出代码中指定的消息

%p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL
%r 输出自应用启动到输出该log信息耗费的毫秒数
%c 输出所属的类目,通常就是所在类的全名
%t 输出产生该日志事件的线程名
%n 输出一个回车换行符,Windows平台为“rn”,Unix平台为“n”
%d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},输出类似:2002年10月18日 22:10:28,921
%l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main(TestLog4.java:10)

实例:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值