关于日志

日志级别

error > warn > info > debug > trace > fatal
  1. trace:级别最低
  2. debug:需要调试时候的关键信息
  3. info:普通的打印信息
  4. warn:警告信息
  5. error:错误信息
  6. fatal:灾难级的,因为代码异常导致程序退出执行的事件;系统级别,程序无法打印

当某个目录设置了日志级别,我们只能得到此级别及更高级别的日志

springboot默认日志级别是 info,我们可以在springboot的默认配置文件中修改日志级别

日志格式

日志框架

日志框架包括日志门面、日志实现。日志门面就是接口,日志实现相当于是具体的实现类

一般常用的框架有:
JUL,JCL,JBOSS-LOGING,longback,log4j,log4j2,slf4j等等。

日志门面 (日志的抽象层) 日志实现
JCL(Jakarta Commons Logging) SLF4j(Simple Logging Facade for Java) jboss-logging Log4j JUL(java.util.logging) Log4j2 Logback

左边选一个门面(抽象层)、右边来选一个实现。SpringBoot选用的是SLF4J和logback

关于SLF4j

介绍

slf4j,simple logging facade for java的缩写,翻译为java的简单日志外观。slf4j(simple logging facade for java)不是一个真正的日志实现,而是一个抽象层( abstraction layer),也可以理解为一个接口,它是一种适配器的实现方式,它本身不具有输出日志的功能,输出日志还是由log4j、logback等这样的日志组件来进行输出。

简单来说,它仅仅是一个为Java程序提供日志输出的统一接口,并不是一个具体的日志实现方案,就比如JDBC一样,只是一种规则而已。所以单独的slf4j是不能工作的,必须搭配其他具体的日志实现方案。

使用场景

现在开发项目都是使用maven进行构建开发,假设架构师a开发了一个order.jar通用组件,他在程序中使用的是log4j组件进行日志输出;程序员b自己之前一直在开发自己的业务模块,并且他在程序中使用的是logback日志组件,突然有一天程序员b需要在自己的业务系统中使用架构师a的order.jar通用组件,这个时候问题就出现了,由于两套程序使用了不同的日志组件,程序员b除了要维护自己的logback日志组件配置,还需要维护order,jar中的日志组件配置,这个问题是很头疼的。解决方案就是:使用slf4j

SLF4j的使用

使用slf4j,只有一个强制性的依赖,就是slf4j-api-x.x.x.jar,我们在编写代码的时候,只会使用这个jar包里的API,应用程序在运行时去类路径下查找绑定的具体日志框架,并使用该绑定的日志框架进行实际的日志操作,如果在应用程序的类路径下面没有找到合适的绑定的话,slf4j默认使用一个没有任何操作的实现。

slf4j只是一个日志标准,并不是日志系统的具体实现。理解这句话非常重要,slf4j只做两件事情:

  • 提供日志接口
  • 提供获取具体日志对象的方法

比如slf4j-simple、logback都是slf4j的具体实现。

当一个应用面向了很多日志框架,如果我们直接去掉这些依赖包的话,系统肯定会报错的,因为Spring本来底层会调用这些框架的API等。可以采取偷梁换柱的做法:用另一个jar包代替本来的jar包。比如:log4j12;代替后和slf4j完美契合,就可以使用。

引入Maven依赖:

<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.21</version>
</dependency>
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.21</version>
</dependency>

总结:

  1. 先将以前的剔除
  2. 用中间包替换原有的日志框架
  3. 导入slf4j其他的实现

slf4j-api作为slf4j的接口类,使用在程序代码中,这个包提供了一个Logger类和LoggerFactory类,Logger类用来打日志,LoggerFactory类用来获取Logger,而slf4j-log4j就是连接slf4j和log4j的桥梁。那么他们是怎么连接的呢?我们来看看slf4j的LoggerFactory类的getLogger函数的源码:

/*** Return a logger named corresponding to the class passed as parameter, using* the statically bound {@link ILoggerFactory} instance.** @param clazz the returned logger will be named after clazz* @return logger*/
public static Logger getLogger(Class clazz) {return getLogger(clazz.getName());
}
/*** Return a logger named according to the name parameter using the statically* bound {@link ILoggerFactory} instance.** @param name The name of the logger.* @return logger*/
public static Logger getLogger(String name) {ILoggerFactory iLoggerFactory = getILoggerFactory();return iLoggerFactory.getLogger(name);
}public static ILoggerFactory getILoggerFactory() {if (INITIALIZATION_STATE == UNINITIALIZED) {INITIALIZATION_STATE = ONGOING_INITIALIZATION;performInitialization();}switch (INITIALIZATION_STATE) {case SUCCESSFUL_INITIALIZATION:return StaticLoggerBinder.getSingleton().getLoggerFactory();case NOP_FALLBACK_INITIALIZATION:return NOP_FALLBACK_FACTORY;case FAILED_INITIALIZATION:throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);case ONGOING_INITIALIZATION:// support re-entrant behavior.// See also http://bugzilla.slf4j.org/show_bug.cgi?id=106return TEMP_FACTORY;}throw new IllegalStateException("Unreachable code");
}

LoggerFactory.getLogger()首先获取一个ILoggerFactory接口,然后使用该接口获取具体的Logger。获取ILoggerFactory的时候用到了一个StaticLoggerBinder类,仔细研究我们会发现StaticLoggerBinder这个类并不是slf4j-api这个包中的类,而是slf4j-log4j包中的类,这个类就是一个中间类,它用来将抽象的slf4j变成具体的log4j,也就是说具体要使用什么样的日志实现方案,就得靠这个StaticLoggerBinder类。再看看slf4j-log4j包种的这个StaticLoggerBinder类创建ILoggerFactory长什么样子:

private final ILoggerFactory loggerFactory;private StaticLoggerBinder() {loggerFactory = new Log4jLoggerFactory();try {Level level = Level.TRACE;} catch (NoSuchFieldError nsfe) {Util.report("This version of SLF4J requires log4j version 1.2.12 or later. See also http://www.slf4j.org/codes.html#log4j_version");}
}public ILoggerFactory getLoggerFactory() {return loggerFactory;
}

可以看到slf4j-log4j中的StaticLoggerBinder类创建的ILoggerFactory其实是一个org.slf4j.impl.Log4jLoggerFactory,这个类的getLogger函数是这样的:

public Logger getLogger(String name) {Logger slf4jLogger = loggerMap.get(name);if (slf4jLogger != null) {return slf4jLogger;} else {org.apache.log4j.Logger log4jLogger;if(name.equalsIgnoreCase(Logger.ROOT_LOGGER_NAME))log4jLogger = LogManager.getRootLogger();elselog4jLogger = LogManager.getLogger(name);Logger newInstance = new Log4jLoggerAdapter(log4jLogger);Logger oldInstance = loggerMap.putIfAbsent(name, newInstance);return oldInstance == null ? newInstance : oldInstance;}
}

就在其中创建了真正的org.apache.log4j.Logger,也就是我们需要的具体的日志实现方案的Logger类。就这样,整个绑定过程就完成了。

在实际开发中,建议使用slf4j,而不是直接使用 log4j, commons logging, logback 或者 java.util.logging等,因为这样可以让程序具有更多的扩展性。

  1. **与客户端解耦:**使用slf4j会使得它独立于任何一个特定的日志实现,这意味着不需要管理多个日志配置或者多个日志类库,以后别人调用你的工具包时也可以不用关心日志组件问题。
  2. **省内存:**slf4j提供了基于占位符{}的日志方法,不会有字符串拼接操作,减少了无用String对象的数量,节省了内存。并且,使用slf4j的日志方法,可以延迟构建日志信息(srting)的开销,程序可以有更高的吞吐性能。

SpringBoot日志配置

默认日志

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId>
</dependency>

依赖关系图:

  1. 我们可以看到SpringBoot底层使用slf4j+logback的方式进行日志记录
  2. 其他日志会转换成slf4j
  3. 可以从依赖中看到明显的替换包

SpringBoot能自动适配所有的日志,而且底层使用slf4j+logback的方式记录日志,引入其他框架的时候,只需要把这个框架依赖的日志框架排除掉即可。

基本使用配置

logging:#logging.level是map类型, 我们可以指定不同包下使用不同的日志级别level:com.atguigu: trace#以文件形式打印日志logging.filefile:name: boot.log   #不指定日志文件的具体位置, 只指定文件名字时, 日志文件默认会生成在项目目录下name: D:/boot.log   #指定日志文件的具体位置时, 日志文件会生成在指定的位置path: /spring/log   #在项目所在磁盘根目录下的spring目录下的log目录下生成名为spring.log的日志文件#日志输出格式:控制台 or 文件pattern: console: %d{yyyy-MM-dd} [%thread] %-5level %logger{50} - %msg%nfile: %d{yyyy-MM-dd} === [%thread] === %-5level === %logger{50} ==== %msg%n#    日志输出格式:#    %d 表示日期时间,#    %thread 表示线程名,#    %-5level 级别从左显示5个字符宽度#    %logger{50} 表示logger名字最长50个字符,否则按照句点分割。 #    %msg 日志消息,#    %n 换行符#--># %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n

指定日志配置文件

在类路径下放上每个日志框架自己的配置文件即可, springboot就不使用他默认的日志配置了

Logging System Customization
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

当日志配置命名为logback.xml时, 这个配置直接就被日志框架识别了

当日志配置命名为logback-spring.xml时, 这个配置由springboot解析识别, 可以使用更高级的功能, 例如 springProfile, 他与springboot中的Profiles对应, 在springboot默认配置文件中激活指定Profiles, 日志配置也将改变

<springProfile name="staging"><!-- configuration to be enabled when the "staging" profile is active -->
</springProfile>

如果使用logback.xml作为日志配置文件,还要使用profile功能,会有以下错误:

no applicable action for [springProfile]

比如在logback-spring.xml中做出以下配置,就可以指定某段配置只在某个环境下生效

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true"><include resource="org/springframework/boot/logging/logback/defaults.xml" /><property name="log.path" value="./logs" /><appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>${CONSOLE_LOG_PATTERN}</pattern><charset>utf8</charset></encoder><layout class="ch.qos.logback.classic.PatternLayout"><pattern>[%X{trackId}][%thread] [%d{yyyy-MM-dd HH:mm:ss.SSS}] %-5level %logger{30} - %msg%n</pattern></layout></appender><!-- level为 info 日志,时间滚动输出  --><appender name="Log_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><!-- 正在记录的日志文档的路径及文档名 --><file>${log.path}/info.log</file><!--日志文档输出格式--><encoder><pattern>[%X{trackId}][%thread] [%d{yyyy-MM-dd HH:mm:ss.SSS}] %-5level %logger{30} - %msg%n</pattern><charset>UTF-8</charset> <!-- 设置字符集 --></encoder><!-- 日志记录器的滚动策略,按日期,按大小记录 --><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><!-- 日志归档 --><fileNamePattern>${log.path}/info-%d{yyyy-MM-dd}.%i.log</fileNamePattern><!--日志文档保留天数--><maxHistory>5</maxHistory><maxFileSize>100MB</maxFileSize><totalSizeCap>5GB</totalSizeCap><cleanHistoryOnStart>true</cleanHistoryOnStart></rollingPolicy><filter class="ch.qos.logback.classic.filter.LevelFilter"><level>INFO</level><onMatch>ACCEPT</onMatch><onMismatch>ACCEPT</onMismatch></filter></appender><springProfile name="dev"><root level="info"><appender-ref ref="CONSOLE" /></root><!--    mybatis sql单独控制输出级别    --><logger name="com.demo.example.dao" level="debug"/></springProfile><springProfile name="prod"><root level="info"><appender-ref ref="Log_FILE" /></root><!--    mybatis sql单独控制输出级别    --><logger name="com.demo.example.dao" level="debug"/></springProfile><springProfile name="online"><root level="info"><appender-ref ref="Log_FILE" /></root><!--    mybatis sql单独控制输出级别    --><logger name="com.demo.example.dao" level="debug"/></springProfile>
</configuration>

切换日志框架

  1. springboot默认使用spring-boot-starter-logging启动器, 使用这个启动器默认使用Logback 进行日志记录, 如果要使用Log4j2 进行日志记录, 那么可以切换spring-boot-starter-log4j2启动器

  2. 具体切换方法为, 将默认spring-boot-starter-logging启动器排除, 使用spring-boot-starter-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><!--使用spring-boot-starter-log4j2启动器-->
    <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-log4j2</artifactId>
    </dependency>
    
  3. 切换log4j日志框架

    首先排除日志框架的实现jar, 比如偷梁换柱jar, log4j-to-slf4j.jar, 和logback-classic.jar(logback实现jar), 然后引入log4j的实现jar

    <dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId>
    </dependency>
    

SLF4j的介绍与使用+SpringBoot日志配置相关推荐

  1. springboot日志配置logback-spring.xml

    springboot日志配置logback-spring.xml 日志配置文件logback-spring.xml 放在项目src/main/resources目录下 <?xml version ...

  2. springboot日志配置

    SpringBoot日志使用 1. 在springboot中测试打印日志 package com.leon.springboot_log;import org.apache.logging.log4j ...

  3. Springboot日志配置探索(主要看logback)(二)

    这篇博客主要是讲在Springboot中扩展的日志框架的配置,也是主要讲logback 8 继续看文档,这里讲到: springboot里面还有几个日志系统框架可以选择使用,你可以通过在classpa ...

  4. SpringBoot 日志配置

    SpringBoot 日志的配置 如果不配置日志,默认配置是 base.xml 配置日志 在 resource 目录下新建 logback.xml <?xml version="1.0 ...

  5. 【SpringBoot】springboot日志配置

    文章目录 4. 日志配置 1. 引入日志 2. 日志输出级别 3. 保存日志文件 4. 日志配置 我们知道日志对于系统监控.故障定位非常重要,比如当生产系统发生问题时,完整清晰的日志记录有助于快速定位 ...

  6. SpringBoot (14)---日志配置(logback)

    SpringBoot 日志配置(logback) SpringBoot支持Java Util Logging,Log4J,Log4J2和Logback日志框架,默认采用logback日志.在实际Spr ...

  7. springboot 默认日志配置以及更换其他日志配置

    springboot 默认日志配置 最简单的打印Sql日志 方法一 此方法无需改动直接复制即可使用 #打印SQL mybatis.configuration.log-impl=org.apache.i ...

  8. springboot日志打印

    springboot日志打印 很多项目在生产上严禁使用System.out输出,性能太低,原因是System.out输出会导致线程等待(同步),而使用Logger输出线程不等待日志的输出(异步),而继 ...

  9. SpringBoot日志实现

    SpringBoot日志实现 SpringBoot日志默认实现 SpringBoot默认的日志实现是使用slf4j+logback,这种实现类似于JDBC + 数据库驱动(统一接口+实现类). slf ...

最新文章

  1. Nginx搭建flv视频点播服务器
  2. 求最大元最小元极大元极小元_极大元、最大元.ppt
  3. Interview:算法岗位面试—10.15下午—上海某公司算法岗位(偏机器学习,合资制造行业)技术面试考点之电话面试—研究项目的技术考察
  4. iframe的子界面获取父界面的标签元素
  5. [二]RabbitMQ-客户端源码之AMQConnection
  6. 使用UI Automation实现自动化测试 --工具使用
  7. 关于web性能一些特性汇总
  8. 如何将html转为report,如何使用XtraReport将报表导出为HTML
  9. 波音正在对737 Max进行软件升级 改善飞行员培训计划
  10. Linux 内核的测试和调试(1)
  11. 混亂的思維 ~ 很高興能邂逅到常年不見的竹子
  12. shiro会话监听_shiro session 监听
  13. 特征向量的归一化方法
  14. 大数据即席查询与分析
  15. 【实现方案】拼夕夕订单超时未支付自动关闭!
  16. 自动打call机 qq伪自动发消息
  17. 泛函分析——内积空间定义的概念
  18. 学Python有前途吗?学Python能做什么?
  19. 19-05-数据库mysql增删改查
  20. Hbase学习之——协处理Coprocessor的使用

热门文章

  1. C语言学生籍贯信息记录簿
  2. 宽字符wchar_t和窄字符char区别和相互转换
  3. php+xampp添加虚拟主机
  4. 服务器(linux)磁盘挂载nfs
  5. sqlserver 2008 r2 误删数据库还原方法
  6. java菜单项_java中菜单条和菜单项,详细解析
  7. 计算机毕业设计时间修改代码程序软件安装运行问题题目汇总送开题送文档先代码
  8. Vim_设置Esc快捷键及补全功能:
  9. ☀️在爬完一周的朋友圈后,我发现了.......惊人⚠️秘密
  10. Lua:深拷贝与浅拷贝,强引用与弱引用