springboot+maven项目配置日志输出文件

目录

Commons Logging slf4j,logback,log4j的区别

日志级别

trace

debug

info

warn

error

commons-logging

原理:

commons-logging接口和自身的实现类

commons-logging接口和log4j实现类

 logback

slf4j

@Slf4j的简单使用教程

 Log4j入门教程


SpringBoot 在所有内部日志中使用Commons Logging,但是默认配置也提供了对常用日志的支持,如:Java Util Logging,Log4J, Log4J2和Logback。每种Logger都可以通过配置使用控制台或者文件输出日志内容。

SLF4J类似于Commons Logging,也是一个日志接口,而Logback类似于Log4j,是一个日志的实现。

根据不同的日志系统,你可以按如下规则组织配置文件名,就能被正确加载:

Spring Boot官方推荐使用带有-spring的文件名作为你的日志配置(如logback-spring.xml,而不是logback.xml),命名为logback-spring.xml的日志配置文件,spring boot可以为它添加一些spring boot特有的配置项(下面会提到)。

默认的命名规则,并且放在 src/main/resources 下面即可

Logback:logback-spring.xml, logback-spring.groovy, logback.xml, logback.groovy

Log4j:log4j-spring.properties, log4j-spring.xml, log4j.properties, log4j.xml

Log4j2:log4j2-spring.xml, log4j2.xml

JDK (Java Util Logging):logging.properties


commons-logging和slf4j都是日志门面。

Commons Logging slf4j,logback,log4j的区别

SpringBoot 在所有内部日志中使用Commons Logging,commons-logging和slf4j都是日志门面。
slf4j(Simple logging Facade for Java) 简单日志门面,日志系统的实现进行了具体的抽象化,只提供了统一的日志使用接口,没有任何日志实现,只有一个jar包(slf4j-api.jar)。

log4j和logback是具体的日志框架。这两个日志框是同一个作者开发,后者性能更高。

logbak直接实现slf4j接口,性能更高

springboot默认日子框架为logback
 

日志级别

SLF4J将日志分为trace、debug、info、warn、error五个级别,每个级别对应记录不同的日志,对应不同的使用场景。

日志级别从低到高分为

TRACE < DEBUG < INFO < WARN < ERROR < FATAL

如果设置为 WARN ,则低于 WARN 的信息都不会输出

一般设置为 DEBUG 就够用了,看具体的业务需求

trace

trace是最低优先级的日志,一般用来追踪详细的程序运行流,比如程序的运行过程中,运行到了哪一个方法进入了哪一条分支。通过trace程序的运行流程,可以判断程序是否按照期望的逻辑在运行。举个例子,有以下代码段。

public class Car{

//点火

public void fire(){

log.trace("fire")

...

}

debug


debug是比trace高一级别的日志,该级别的日志就是用来debug用的。这类日志往往用在判断是否有出现bug的场景,且往往记录了代码运行的详细信息,比如方法调用传入的参数信息。

假设运行的过程中出现了问题,为了定位问题的原因,可以使用debug级别的日志来记录档位,通过记录运行时传入的gear来判断是不是因为档位输入错误而导致Car起步失败。
 

//挂档

public void gear(int gear){

log.trace("gear")

//记录档位

log.debug(gear)

...

}
info


info比debug高一级别,用来记录程序运行的一些关键信息,它不像trace那样记录程序运行的整个流程,也不像debug那样为了解决问题而记录详细的信息。

info记录的是整个系统的运行信息,比如系统运行到了哪一个阶段,到达了哪一个状态。还是以车启动为例子,将启动的代码修改如下
 

public void static main(String[] args){

Car car = new Car();

car.fire();

car.clutch();

car.gear(1);

car.looseBrake();

log.info("car is ready to run faster !");

}

可以看到,运行完looseBrake方法之后,使用info记录了车的状态,车已经完成了起步了,可以踩油门加速了。

warn


warn比info的级别更高,用来记录一些警告信息。警告信息表示,程序进入了一个特殊的状态,在该状态下程序可以继续运行,但是不建议让程序进入该状态,因为该状态可能导致结果出现问题

车启动的过程中如果以大于1档起步,就使用warn记录警告,告诉调用者不推荐这样使用,实际上2档起步也是可以的,但可能会出问题
 

//挂档

public void gear(int gear){

log.trace("gear")

//记录档位

log.debug(gear)

if(gear > 1){

log.warn("gear "+ gear +" is too high !")

}

...

}

error

error级别的日志是最高优先级了,用来记录运行时的错误信息,表示程序运行过程中出现了需要被解决的问题,往往是一些异常。使用error日志的时候,一般会将详细的异常出现的原因记录。

public void static main(String[] args){

Car car = new Car();

try{

car.fire();

car.clutch();

car.gear(1);

car.looseBrake();

}catch(Exception e){

log.error("run failed !",e.getCause())

}

log.info("car is ready to run faster !");

}
commons-logging

Jakarta Commons Logging (JCL)提供的是一个日志(Log)接口(interface),同时兼顾轻量级和不依赖于具体的日志实现工具。
它提供给中间件/日志工具开发者一个简单的日志操作抽象,允许程序开发人员使用不同的具体日志实现工具。用户被假定已熟悉某种日志实现工具的更高级别的细节。JCL提供的接口,对其它一些日志工具,包括Log4J, Avalon LogKit, and JDK 1.4等,进行了简单的包装,此接口更接近于Log4J和LogKit的实现。

SpringBoot 在所有内部日志中使用Commons Logging,但是默认配置也提供了对常用日志的支持,如:Java Util Logging,Log4J, Log4J2和Logback。每种Logger都可以通过配置使用控制台或者文件输出日志内容。

SLF4J类似于Commons Logging,也是一个日志接口,而Logback类似于Log4j,是一个日志的实现。

在我们的项目中,如果只单纯的依赖了commons-logging,那么默认使用的日志对象就是Jdk14Logger,默认使用的日志工厂就是LogFactoryImpl,没有使用SpringBoot

commons-logging和slf4j都是日志门面。

原理:


       JCL有两个基本的抽象类: Log( 基本记录器 ) 和 LogFactory( 负责创建 Log 实例 ) 。当 commons-logging.jar 被加入到 CLASSPATH之后,它会合理地猜测你想用的日志工具,然后进行自我设置,用户根本不需要做任何设置。默认的 LogFactory 是按照下列的步骤去发现并决定那个日志工具将被使用的(按照顺序,寻找过程会在找到第一个工具时中止) :

①首先在classpath下寻找commons-logging.properties文件。如果找到,则使用其中定义的Log实现类;如果找不到,则在查找是否已定义系统环境变量org.apache.commons.logging.Log,找到则使用其定义的Log实现类;

②查看classpath中是否有Log4j的包,如果发现,则自动使用Log4j作为日志实现类;

③否则,使用JDK自身的日志实现类(JDK1.4以后才有日志实现类);

④否则,使用commons-logging自己提供的一个简单的日志实现类SimpleLog;
 

commons-logging接口和自身的实现类
<dependency>
    <groupId>commons-logging</groupId>  
    <artifactId>commons-logging</artifactId>  
    <version>1.1.3</version>  
</dependency>

接下来,在classpath下定义配置文件:commons-logging.properties:

#指定日志对象:
org.apache.commons.logging.Log = org.apache.commons.logging.impl.Jdk14Logger
#指定日志工厂:
org.apache.commons.logging.LogFactory = org.apache.commons.logging.impl.LogFactoryImpl

package com.wbf.log;
 
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
 
/**
 * commons-logging-1.0.4.jar,但是没有log4j-1.2.15.jar和log4j.properties
 * debug<info<warn<error
 * log4j.rootLogger=级别,如:warn,但是warn之下的级别debug, info的信息无法输出
 * @author wbf
 */
public class TestCommonsLoggingLog4j {
	private final Log log = LogFactory.getLog(TestCommonsLoggingLog4j.class);
	
	public static void main(String[] args) {
		TestCommonsLoggingLog4j testSlf4j = new TestCommonsLoggingLog4j();
		testSlf4j.testLog(10);
	}
	
	private void testLog(int a) {
		if (a == 10) {
			log.info("log info...");
			log.warn("log warn...");
			log.error("log error...");
		}
	}
}
commons-logging接口和log4j实现类
package com.wbf.log;
 
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
 
/**
 * commons-logging-1.0.4.jar、log4j-1.2.15.jar和log4j.properties
 * debug<info<warn<error
 * log4j.rootLogger=级别,如:warn,但是warn之下的级别debug, info的信息无法输出
 * @author wbf
 */
public class TestCommonsLoggingLog4j {
	private final Log log = LogFactory.getLog(TestCommonsLoggingLog4j.class);
	
	public static void main(String[] args) {
		TestCommonsLoggingLog4j testSlf4j = new TestCommonsLoggingLog4j();
		testSlf4j.testLog(10);
	}
	
	private void testLog(int a) {
		if (a == 10) {
			log.info("log info...");
			log.warn("log warn...");
			log.error("log error...");
		}
	}
}
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
 
log4j.rootLogger=warn, stdout

修改commons-logging.properties文件:显示地指定log4j

org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger

源码分析

(84条消息) 日志之commons-logging_commons-logging依赖_木村牧村的博客-CSDN博客

获取当前线程的classLoader,根据classLoader从缓存中获取LogFactroy,使用的缓存是WeakHashTable对象;如果缓存中存在,则返回,没有则进入下面流程;

读取classpath下的commons-logging.properties文件,判断其中是否设置了use_tccl属性,如果不为空则判断,该属性的值是否为false,若为false,则将baseClassLoader替换为当前类的classLoader;

接着,继续获取LogFactory对象,此步骤分为4中方式:
    (1)在系统属性中查找“org.apache.commons.logging.LogFactory”属性的值,根据值生成LogFactory对象;
    (2)通过资源“META-INF/services/org.apache.commons.logging.LogFactory”文件,获取的值生成LogFactory对象;
    (3)通过配置文件commons-logging.properties,获取以“org.apache.commons.logging.LogFactory”为key的值,根据值生成logFactory;
    (4)如果以上均不成功,则创建系统默认的日志工厂:org.apache.commons.logging.impl.LogFactoryImpl

成功获取日志工厂后,根据类名获取日志对象;

主要逻辑在discoverLogImplementation方法中:
    (1)检查commons-logging.properties文件中是否存在“org.apache.commons.logging.Log”属性,若存在则创建具体的日志对象;若不存在,进行下面逻辑;
    (2)遍历classesToDiscover数组,该数组存有日志具体实现类的全限定类名:org.apache.commons.logging.impl.Log4JLogger、org.apache.commons.logging.impl.Jdk14Logger、org.apache.commons.logging.impl.Jdk13LumberjackLogger、org.apache.commons.logging.impl.SimpleLog;
    (3)根据数组中存着的全限定类名,按照顺序依次加载Class文件,进行实例化操作,最后返回Log实例,默认为Jdk14Logger;

其中,获取日志工厂的过程,诟病最多。究其原因,主要是commons-logging在获取日志工厂的过程中使用了classLoader来寻找日志工厂实现,进而导致了其他组件,如若使用自己的classload,则不能获取具体的日志工厂对象,则导致启动失败,这样就是我们常说的–动态查找机制

 logback

spring-boot-starter 这个包就自带了 logging 的依赖包,SpringBoot会默认使用logback作为日志框架,在生成springboot项目的时候可以直接勾选logback,那么就可以直接使用logback了。

如下配置将:

在根目录applog中每天生成一个文件夹,并生成一个天级别的日志文件。

Logger标签:作为日志的记录器,把它关联到应用的对应的context上后,主要用于存放日志对象,也可以定义日志类型、级别。

Appender主要用于指定日志输出的目的地,目的地可以是控制台、文件、远程套接字服务器、 MySQL、PostreSQL、 Oracle和其他数据库、 JMS和远程UNIX Syslog守护-进程等。

Layout 负责把事件转换成字符串,格式化的日志信息的输出

logback-spring.xml,放在 src/main/resources 下面
 

logback-spring.xml,放在 src/main/resources 下面 

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
    <contextName>logback</contextName>

    <!--输出到控制台-->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <!--按天生成日志,即一天只生成一个文件夹和一个日志文件-->
    <appender name="logFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <Prudent>true</Prudent>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>
                applog/%d{yyyy-MM-dd}/%d{yyyy-MM-dd}.log
            </FileNamePattern>
        </rollingPolicy>
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>
                %d{yyyy-MM-dd HH:mm:ss} -%msg%n
            </Pattern>
        </layout>
    </appender>

    <!-- logger节点,可选节点,作用是指明具体的包或类的日志输出级别,
    以及要使用的<appender>(可以把<appender>理解为一个日志模板)。
    addtivity:非必写属性,是否向上级loger传递打印信息。默认是true-->
    <logger name="com.framework.job" additivity="false">
        <appender-ref ref="console"/>
        <appender-ref ref="logFile"/>
    </logger>

    <!--项目的整体的日志打印级别为info-->
    <root level="info">
        <appender-ref ref="console"/>
        <appender-ref ref="logFile"/>
    </root>

</configuration>

如果没有按照命名规则,则需要手动添加logback.xml

application.yml中配置logging

#logging
logging:
  config: classpath:log/logback.xml

使用以下方式,可以单独设置每个包下的日志记录级别, 

application.yml,application.properties

logging:
  file: applog/sys.log
  level:
    com:
      leshangju:
        prism:
          auth:
            dao: debug
          usershop:
            dao: debug
          loginuser:
            dao: debug

logging.level.com.framework.job : info

 测试结果

@Slf4j
public class MyJob extends QuartzJobBean {

    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        System.out.println("启动定时任务 My Job:" + LocalDateTime.now());
        log.trace("进入了myjob任务");

        try {
            Thread.sleep(3000);
            log.trace("睡了3秒");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("结束任务!");
        System.out.println("end  My Job:" + LocalDateTime.now());

    }
}

slf4j

简单日志门面(Simple Logging Facade For Java) SLF4J主要是为了给Java日志访问提供一套标准、规范的API框架,其主要意义在于提供接口,具体的实现交由其他日志框架,例如log4j2和logback等。当然slf4j自己也提供了功能较为简单的实现,但是一般很少用到。对于一般的Java项目而言,日志框架会选择slf4j-api作为门面,配上具体的实现框架(log4j2、logback等),中间使用桥接器完成桥接。所以我们可以得出SLF4J最重要的两个功能就是对于日志框架的绑定以及日志框架的桥接。
 

<dependency>
     <!--日志门面核心包 -->
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>1.7.32</version>
</dependency>
<dependency>
      <groupId>日志实现框架</groupId>
      <artifactId>日志实现框架</artifactId>
            
</dependency>

SLF4J依赖slf4j-api包和日志实现框架包,如果不导入任何日志实现框架的话,会报错

@Slf4j的简单使用教程

很简单的就是为了能够少写两行代码,不用每次都在类的最前边写上:
private static final Logger logger = LoggerFactory.getLogger(this.XXX.class);
我们只需要在类前面添加注解@Slf4j,即可使用log日志的功能了
确保idea中有Lombok插件

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.25</version>
    </dependency>
  
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.22</version>
    </dependency>

可以直接使用log.info(""); 

日志实现框架:JUL,log4j,logback,log4j2

常见的日志门面:JCL,slf4j

出现顺序:log4j->JUL->JCL->slf4j->logback->log4j2

 Log4j入门教程

Log4J 是 Apache 的一个开源项目(官网 http://jakarta.apache.org/log4j),通过在项目中使用 Log4J,我们可以控制日志信息输出到控制台、文件、GUI 组件、甚至是数据库中。我们可以控制每一条日志的输出格式,通过定义日志的输出级别,可以更灵活的控制日志的输出过程。方便项目的调试。
Log4J 主要由 Loggers (日志记录器)、Appenders(输出端)和 Layout(日志格式化器)组成。其中 Loggers 控制日志的输出级别与日志是否输出;Appenders 指定日志的输出方式(输出到控制台、文件等);Layout 控制日志信息的输出格式。

Appender(输出端)
Appender 用来指定日志输出到哪个地方,可以同时指定日志的输出目的地。Log4j 常用的输出目的地有以下几种:

输出端 类型    作用
ConsoleAppender    将日志输出到控制台
FileAppender    将日志输出到文件中
DailyRollingFileAppender    将日志输出到一个日志文件,并且每天输出到一个新的文件
RollingFileAppender    将日志信息输出到一个日志文件,并且指定文件的尺寸,当文件大 小达到指定尺寸时,会自动把文件改名,同时产生一个新的文件
JDBCAppender    把日志信息保存到数据库中


Layout(日志格式化器)
格式化器类型    作用
HTMLLayout    格式化日志输出为HTML表格形式
SimpleLayout    简单的日志输出格式化,打印的日志格式为(info - message)
PatternLayout    最强大的格式化期,可以根据自定义格式输出日志,如果没有指定转换格式,就是用默认的转换格式
 

# 控制台输出配置
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.Threshold = DEBUG
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 #指定日志的文件编码
 
#指定日志的输出级别与输出端
log4j.rootLogger=DEBUG,Console,A

public class Log4JTest {
 
    public static void main(String[] args) {   
        //获取Logger对象的实例         
        Logger logger = Logger.getLogger(Log4JTest.class);
        logger.debug("这是debug");
        logger.info("这是info");
        logger.warn("这是warn");
        logger.error("这是error");
        logger.fatal("这是fatal");
    }
 
}

并会在 D 盘生成一份 log.txt 文件。文本内容如下:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值