Java常用日志框架+Logback的应用实例

本文介绍了Java日志框架的发展历程,重点讲解了Slf4j与Logback的组合使用,包括Maven依赖配置、日志级别设置、日志格式化及文件滚动策略等内容,并列举了一些实际应用中可能遇到的问题及其解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、Java常用日志框架

1)1996年左右,以Ceki Gulcu(切基·古尔库)为首的团队创建了Log4j,后被Apache收归麾下;
2)2002年Sun公司推出了日志库JUL(java util logging),基本照搬Log4j,后来Sun也被Google收购,JUL自然也成为Apache的一员;
3)后来Apache又推出了Commons Logging,组成了日志接口Commons Logging,实现可选Log4j或JUL的架构;
4)2006年Ceki Gulcu离开Apache,先后创建了Slf4j和Logback,组成了日志接口Slf4j,实现以Logback为主的架构;
5)至此,java界两大日志框架阵营形成,主流应用都选这两个组合中的一个,由于Slf4j在各项性能及接入方式上都优于Commons Logging,而且Slf4j完全开源、而Commons Logging部分开源,所以Slf4j大有后来者居上的趋势。
现在,如果接手老项目,就沿用以前的的日志框架;如果是新建项目,建议用Slf4j的组合。

二、Logback应用(Slf4j接口,Logback实现)

1、约定

<!--
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.6.4</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-core</artifactId>
        <version>1.0.6</version>
    </dependency>
-->

<!-- 该依赖包括了上面两个依赖,所以只要引入该依赖即可 -->
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.0.6</version>
</dependency>

如果是springboot项目,spring-boot-starter这个依赖其中包含了 spring-boot-starter-logging,这种情况下就不用再另外加logback依赖了。

2、配置

1)默认配置

在用户没有对logback进行任何配置的情况下,logback会使用默认配置输出简单的日志到控制台。
但在实际工作中,我们通常对日志的输出有很多要求,比如设定日志的格式、要求日志文件按天分割、将日志文件按大小进行分割、定期删除旧日志等,所以一般都要建专门日志配置文件,用于管理logback的输出格式、级别等;这个文件一般放在resource文件夹下,一般命名为lockback.xml。
项目启动时,如果检测到在项目的classpath路径下存在logback.xml(或者logback-test.xml、logback.groovy),logback框架能够自动扫描到它、并读取配置。

2)根节点configuration

配置文件的根节点是configuration,它有三个属性,scan、scanPeriod、debug,一般都采用默认设置。

<configuration>
	...
</configuration>

configuration节点主要又包含appdender、logger、root三个标签,如下图:
在这里插入图片描述

3)一级子节点property

property标签,用来定义一些常用的变量,比如日志输出格式、很多地方会用到,而且一般格式都是一样的;用property配置以后,后面就可以用${name值}来引用自定义的配置。
当然,property设置了以后,其他各处还是可以不用。

<configuration>

	<!--配置日志文件格式-->
    <property name="pattern" value="%d{HH:mm:ss.SSS} [%-5level] [%thread] [%logger] %msg%n"/>
    <!--配置日志路径-->
    <property name="logPath" value="/backup/logs/jboss/bdp/log"/>
    <!--配置日志文件名-->
    <property name="appName" value="bdpadmin"/>
    
<configuration/>

4)一级子节点appender

appender标签,用来配置日志的输出位置、格式等等,标签主要有两个属性:name和class;
根据class不同,appender有不同功效,这里介绍几个常用的appender类型:

a、ch.qos.logback.core.ConsoleAppender

ConsoleAppender类型的appender标签,配置在控制台输出的日志。主要是设置它的二级子标签<encoder>的两个三级子标签:
<pattern>设置日志输出格式;
<charset>设置字符集,防止乱码

<configuration>

  	<!-- 输出到控制台 -->
    <appender name="print-on-console" class="ch.qos.logback.core.ConsoleAppender" >
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
        	<!-- 输出的格式,这里使用property配置的常量 -->
            <!-- <pattern>%d{HH:mm:ss.SSS} [%-5level] [%thread] [%logger] %msg%n</pattern> -->
            <pattern>${pattern}</pattern>
            <!-- 字符集 -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>

</configuration>
b、ch.qos.logback.core.rolling.RollingFileAppender

RollingFileAppender类型的appender标签,配置输出到文件的日志。
RollingFileAppender还提供了切割日志文件的功能,它首先将日志记录到一个自定义名称的文件中,一旦满足设置条件(一定大小、或者一定时间)之后,它会将新产生的日志记录到新文件中。

<configuration>

  	<!-- 输出到日志文件 -->
    <appender name="print-to-file" class="ch.qos.logback.core.rolling.RollingFileAppender">
    	<!-- 配置日志地址、名称 -->
    	<file>${logPath}/${appName}.log</file>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <Pattern>${pattern}</Pattern>
            <charset>UTF-8</charset>
        </encoder>
        <!-- 配置滚动的策略 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 配置滚动日志名称 -->
            <fileNamePattern>${logPath}/${appName}.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <!-- 每天生成新日志文件,如果文件超过30M,则再生成一个新的日志文件 -->
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>3MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
    </appender>
    
</configuration>

如果还要配置日志文件的保存时间,可以在<rollingPolicy>标签下加

	<!-- 保存的最长时间:天数 -->
    <MaxHistory>30</MaxHistory>

5)一级子节点logger、root——配置日志有效级别

a、有效级别

日志是有级别的,从低到高为:TRACE < DEBUG < INFO < WARN < ERROR
logback是否打印某条日志,取决于这条日志的级别:
如果这条日志等于或高于logger、root配置的级别,那这条日志就属于有效级别,logback就会打印这条日志;反之,如果这边日志低于logger、root配置的级别,那这条日志就属于无效级别,logback就不会打印它。
比如root配置有效级别为error,那么
log.info(“…”)就不会被打印,
而log.error(“…”)才会被打印。

那么,都是配置有效级别,root和logger有什么区别呢?
简单来说就是root配置的是大多数日志的有效级别;
而logger配置的是个别部分的日志级别。
需要特殊设置的部分就用logger配置,剩下的都看root配置。

b、logger

logger用来为单独的包配置日志级别。
应用场景:生产环境root一般设置比较高,这样可以降低打印日志的资源消耗。
但是有些功能,又需要很详细的日志、以备将来定位问题;比如mybatis、sql相关的部分。
这时就可以通过logger为这些部分,设置专门的日志级别debug;如此一来,日志文件中就会出现mybatis的debug级别日志, 而其它包则会按root的级别输出日志

<configuration>

	<logger name="com.ibatis" level="DEBUG" />  
	<logger name="java.sql.Connection" level="DEBUG"/>
	<logger name="java.sql.Statement" level="DEBUG"/>
	<logger name="java.sql.PreparedStatement" level="DEBUG"/>
	<logger name="org.springframework" level="ERROR" />

<configuration/>
c、root

生产环境,应该配置合适的级别,以降低消耗

<configuration>

	<root level="debug">
        <!-- 控制台输出 -->
        <appender-ref ref="print-on-console" />
    </root>
    <root level="info">
        <!-- 文件输出 -->
        <appender-ref ref="print-to-file"/>
    </root>

<configuration/>

6)应用实例

将上述配置总结一下,就是logback.xml的应用实例

<configuration>

	<!--配置日志文件格式-->
    <property name="pattern" value="%d{HH:mm:ss.SSS} [%-5level] [%thread] [%logger] %msg%n"/>
    <!--配置日志路径-->
    <property name="logPath" value="/backup/logs/jboss/bdp/log"/>
    <!--配置日志文件名-->
    <property name="appName" value="bdpadmin"/>

	<!-- 输出到控制台 -->
    <appender name="print-on-console" class="ch.qos.logback.core.ConsoleAppender" >
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
        	<!-- 输出的格式,这里使用property配置的常量 -->
            <!-- <pattern>%d{HH:mm:ss.SSS} [%-5level] [%thread] [%logger] %msg%n</pattern> -->
            <pattern>${pattern}</pattern>
            <!-- 字符集 -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>

	<!-- 输出到日志文件 -->
    <appender name="print-to-file" class="ch.qos.logback.core.rolling.RollingFileAppender">
    	<!-- 配置日志地址、名称 -->
    	<file>${logPath}/${appName}.log</file>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <Pattern>${pattern}</Pattern>
            <charset>UTF-8</charset>
        </encoder>
        <!-- 配置滚动的策略 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 配置滚动日志名称 -->
            <fileNamePattern>${logPath}/${appName}.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <!-- 每天生成新日志文件,如果文件超过30M,则再生成一个新的日志文件 -->
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>3MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
    </appender>

	<logger name="com.ibatis" level="DEBUG" />  
	<logger name="java.sql.Connection" level="DEBUG"/>
	<logger name="java.sql.Statement" level="DEBUG"/>
	<logger name="java.sql.PreparedStatement" level="DEBUG"/>
	<logger name="org.springframework" level="ERROR" />

	<root level="debug">
        <!-- 控制台输出 -->
        <appender-ref ref="print-on-console" />
    </root>
    <root level="info">
        <!-- 文件输出 -->
        <appender-ref ref="print-to-file"/>
    </root>

<configuration/>

三、Logback实际应用中遇到的一些问题

1、RollingFileAppender标签,试图对日志文件名动态配置%d{yyyy-MM-dd}不起作用

	<appender name="RollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${logPath}/${appName}.%d{yyyy-MM-dd}.log</file>
        ...
    </appender>

在这里插入图片描述
原因:RollingFileAppender标签下的<file>标签并不支持日期pattern动态设置,不生效是正常的。应该将其改为

	<appender name="RollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${logPath}/${appName}.log</file>
        ...
    </appender>

但是,日志文件触发切割条件后,切割日志文件名的动态配置是支持的
在这里插入图片描述
最终效果
在这里插入图片描述

2、tomcat、日志文件乱码

控制台看到打印日志乱码如下:
在这里插入图片描述
而日志文件用记事本打开不乱码:
在这里插入图片描述

用sublime打开乱码
在这里插入图片描述
关于这个问题,分析如下:

不同的文本编辑器默认的字符集不同,所以才会出现对同一文件,不同编辑器打开有的乱码、有的正常这种现象。

如果控制台logback输出的日志乱码,将ConsoleAppender中的字符集设为utf-8即可解决。
如果日志文件乱码,就将RollingFileAppender中的字符集设为utf-8。
在这里插入图片描述
logback.xml字符集都设置好了,再用某个编辑器、比如sublime打开,如果还是乱码,那就看一下sublime的字符集是啥?给改成utf-8,就不乱了。

3、java程序中获取logger日志对象

1)org.slf4j包下有个LoggerFactory类,LoggerFactory有个getLogger()方法,可以方便的获取一个Logger对象(org.slf4j包下的)。
getLogger()方法,入参填当前类的.calss,或者当前类的.class.getName()。

public class Abc {
    private static Logger logger = LoggerFactory.getLogger(Abc.class);
}

//或者

public class Abc {
    private static Logger logger = LoggerFactory.getLogger(Abc.class.getName());
}

2)接手旧项目、或者中途修改过项目日志框架(由log4j改为logback),注意修改获取日志对象的方法,对象创建工厂不要错用org.apache.log4j包的LogManager,下面这个是log4j的

private static Logger logger = LogManager.getLogger(PushController.class.getName());

4、springboot项目整合logback

1)实际开发中如果是springboot项目,不需要我们添加logback的依赖,这是因为spring-boot-starter这个依赖其中包含了 spring-boot-starter-logging,这个包下有所有日志框架需要的依赖(也包含log4j的依赖);

2)如果项目中使用了lombok插件,写日志时甚至都不用创建日志对象,只要在需要日志的类上加一个@Slf4j,就可以直接在方法中用 log.info();或者log.error();等写日志了,非常简单方便。
@Slf4j注解是lombok的一个注解,它会为类提供一个属性名为log的slf4j日志对象。

5、springboot从哪里读取logback.xml配置文件?

1)springboot默认从类路径下(classpath:),即 src/main/resources目录,读取logback.xml配置文件,具体来说:

Spring Boot 会在以下几个条件下尝试加载 logback.xml 文件:

A、如果 logback-spring.xml 文件存在于 src/main/resources,Spring Boot 将使用它而不是 logback.xml。

B、如果src/main/resources下 logback-spring.xml 不存在,Spring Boot 会查找 logback.xml 文件。

2)自定义日志配置文件的位置
如果想要自定义日志配置文件的位置,可以在 application.properties 或 application.yml 中设置 logging.config 属性。
例如,在application.yml中,指定去服务器的/home/config下读取logback.xml

logging:
  config: /home/config/logback.xml

补充:自定义日志配置文件的位置有什么意义?

正常把日志文件放在resources下,项目上线前打包、会把配置文件打入jar包中;
如果上线后需要修改日志配置文件,比如正常生产的日志级别设置为info,但是现在有个问题需要排查、得打印debug级别的日志,像诸如此类的修改,你需要修改logback.xml、重新打包、发版,也就是要做一次生产变更;
有工作经验的小伙伴都知道,这么小的改动发一次版很麻烦,尤其在大公司做变更步骤繁多。

那么有没有什么方式可以重新发版就修改配置呢?

答案就是在项目外部也放一份日志配置,然后指定让springboot去读取这个外部的日志配置;
这个外部的日志配置开始是和代码中的相同的,
但是后面如果有需要,可以修改,这时再伸缩一下容器配置修改就能生效了,不用重新发版。

6、为什么在logback.xml把项目的日志级别设为info,但是项目日志文件却打印了debug级别的日志?

除了在logback.xml中对日志进行配置,还可以在application.yml中对日志进行配置;
比如上面,对日志文件读取位置的配置就是一个例子。

所以,在logback.xml把项目的日志级别设为info,如果又在application.yml中设置某个包下的类的日志打印级别为debug,
那么这个包下的类就会打印debug级别的日志

# 日志输出配置
logging:
  level:
    com.xx.system.dao: DEBUG
  config: classpath:logback.xml

别人这样配置了,我们要能读懂、明白;但是我个人还是建议对于日志级别的配置,还是统一放在logback.xml中比较好。

ps:有一次我本地调试接口,发现控制台没有打印日志,但是检查application.yml中已经配置了logging.level为debug,可以为什么没生效呢?

排查了好久才发现,原来之前不知道出于什么原由,把dao包的路径写错了;写这个的原因是想说,这个配置是有效的,如果你手里的项目这样配置了还没生效,可以检查以下包路径是否正确。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值