大家好,欢迎来到IT知识分享网。
SLF4j的介绍与使用+SpringBoot日志配置
【一】关于日志
【1】日志级别
fatal > error > warn > info > debug > trace
当某个目录设置了日志级别,我们只能得到此级别及更高级别的日志。
【2】日志格式
【3】日志框架
日志框架包括日志门面、日志实现。日志门面就是接口,日志实现相当于是具体的实现类
SpringBoot选用的是SLF4J和logback。
【二】关于SLF4j
【1】介绍
slf4j,simple logging facade for java的缩写,翻译为java的简单日志外观。slf4j(simple logging facade for java)不是一个真正的日志实现,而是一个抽象层( abstraction layer),也可以理解为一个接口,它是一种适配器的实现方式,它本身不具有输出日志的功能,输出日志还是由log4j、logback等这样的日志组件来进行输出。
简单来说,它仅仅是一个为Java程序提供日志输出的统一接口,并不是一个具体的日志实现方案,就比如JDBC一样,只是一种规则而已。所以单独的slf4j是不能工作的,必须搭配其他具体的日志实现方案。
【2】使用场景
现在开发项目都是使用maven进行构建开发,假设架构师a开发了一个order.jar通用组件,他在程序中使用的是log4j组件进行日志输出;程序员b自己之前一直在开发自己的业务模块,并且他在程序中使用的是logback日志组件,突然有一天程序员b需要在自己的业务系统中使用架构师a的order.jar通用组件,这个时候问题就出现了,由于两套程序使用了不同的日志组件,程序员b除了要维护自己的logback日志组件配置,还需要维护order,jar中的日志组件配置,这个问题是很头疼的。解决方案就是:使用slf4j。
【3】SLF4j的使用
使用slf4j,只有一个强制性的依赖,就是slf4j-api-x.x.x.jar,我们在编写代码的时候,只会使用这个jar包里的API,应用程序在运行时去类路径下查找绑定的具体日志框架,并使用该绑定的日志框架进行实际的日志操作,如果在应用程序的类路径下面没有找到合适的绑定的话,slf4j默认使用一个没有任何操作的实现。
(1)slf4j只是一个日志标准,并不是日志系统的具体实现
理解这句话非常重要,slf4j只做两件事情:
比如slf4j-simple、logback都是slf4j的具体实现。
当一个应用面向了很多日志框架,如果我们直接去掉这些依赖包的话,系统肯定会报错的,因为Spring本来底层会调用这些框架的API等。可以采取偷梁换柱的做法:用另一个jar包代替本来的jar包。比如:log4j12;代替后和slf4j完美契合,就可以使用。
(2)引入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>
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=106 return 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(); else log4jLogger = 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等,因为这样可以让程序具有更多的扩展性。
【三】Springboo日志配置
【1】默认日志
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </dependency>
SpringBoot能自动适配所有的日志,而且底层使用slf4j+logback的方式记录日志,引入其他框架的时候,只需要把这个框架依赖的日志框架排除掉即可。
【2】基本使用配置yaml
logging: #logging.level是map类型, 我们可以指定不同包下使用不同的日志级别 level: com.atguigu: trace #以文件形式打印日志logging.file file: 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%n file: %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
【3】指定日志配置文件
在类路径下放上每个日志框架自己的配置文件即可, springboot就不使用他默认的日志配置了
当日志配置命名为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>
【4】切换日志框架
(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>
<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </dependency>
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/110483.html


