【springboot】如何动态修改日志级别???

这篇具有很好参考价值的文章主要介绍了【springboot】如何动态修改日志级别???。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在日常的开发过程中,为了方便定位问题,也为了甩锅,我们时常会打印一些日志,在开发,测试,生产各个环境中的日志级别可能不一样,在自己编码过程中为了方便调试打印了很多日志,但是生产中为了性能,为了节约存储资源,我们可能需要屏蔽掉一些不必要的日志,只保留一些关键的必要的日志。

我们在开发中一般使用如下代码打印日志:

package com.morris.spring.boot.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class LogController {
    private static final Logger log = LoggerFactory.getLogger(LogController.class);

    public LogController() {
    }

    @GetMapping({"log"})
    public String log() {
        log.trace("log trace level test");
        log.debug("log debug level test");
        log.info("log info level test");
        log.warn("log warn level test");
        log.error("log error level test");
        return "success";
    }
}

使用slf4j的api来打印日志,底层具体日志的打印可以使用logback、log4j等框架。

slf4j中日志的级别优先级从高到低依次为:ERROR,WARN,INFO,DEBUG,TRACE。例如当日志级别为INFO时,只会打印比INFO级别高的日志。

如果在项目的运行过程中,想动态的修改日志的级别,不需要重启项目直接给日志降级或者升级该怎么实现呢?

从Spring Boot 1.5开始,Spring Boot Actuator组件就已提供动态修改日志级别的能力,废话不多说了,直接上代码吧!

引入依赖

引入spring-boot-starter-actuator依赖,这里使用的是gradle,可自行转为maven:

implementation 'org.springframework.boot:spring-boot-starter-actuator:2.6.7'

开启日志端点配置

然后需要在配置文件中开启日志的端点:

# 由于Spring Boot 2.x默认只暴露 /health 以及 /info 端点,
# 而日志控制需要用到 /loggers 端点,故而需要设置将其暴露。当然把loggers替换成*也是可以的;开启所有!
management:
  endpoints:
    web:
      exposure:
        include: 'loggers'
        # include: *

启动服务,访问http://127.0.0.1:8888/log,可查看日志如下:

2023-07-07 10:15:51.298  INFO 18076 --- [nio-8888-exec-1] c.m.s.boot.controller.LogController      : log info level test
2023-07-07 10:15:51.299  WARN 18076 --- [nio-8888-exec-1] c.m.s.boot.controller.LogController      : log warn level test
2023-07-07 10:15:51.299 ERROR 18076 --- [nio-8888-exec-1] c.m.s.boot.controller.LogController      : log error level test

可以看到默认的日志级别是INFO,比INFO优先级高的WARN和ERROR日志都会被打印出来。

查看指定包/类的日志级别

可以通过访问URL/actuator/loggers/后加包名或者类名来查询指定包或者类的当前日志级别。

$ curl "http://127.0.0.1:8888/actuator/loggers/com.morris.spring.boot.controller.LogController"
{"configuredLevel":null,"effectiveLevel":"INFO"}

$ curl "http://127.0.0.1:8888/actuator/loggers/com.morris.spring.boot.controller"
{"configuredLevel":null,"effectiveLevel":"INFO"}

修改包/类的日志级别

可以通过访问URL/actuator/loggers/后加包名或者类名来修改指定包或者类的当前日志级别。

$ curl -X POST "http://127.0.0.1:8888/actuator/loggers/com.morris.spring.boot.controller.LogController" -H "Content-Type: application/json;charset=UTF-8" --data '{"configuredLevel":"debug"}'

再次查看日志级别:

$ curl "http://127.0.0.1:8888/actuator/loggers/com.morris.spring.boot.controller.LogController"
{"configuredLevel":"DEBUG","effectiveLevel":"DEBUG"}

再次访问http://127.0.0.1:8888/log,可查看日志如下:

2023-07-07 10:22:03.252 DEBUG 18076 --- [nio-8888-exec-2] c.m.s.boot.controller.LogController      : log debug level test
2023-07-07 10:22:03.253  INFO 18076 --- [nio-8888-exec-2] c.m.s.boot.controller.LogController      : log info level test
2023-07-07 10:22:03.253  WARN 18076 --- [nio-8888-exec-2] c.m.s.boot.controller.LogController      : log warn level test
2023-07-07 10:22:03.253 ERROR 18076 --- [nio-8888-exec-2] c.m.s.boot.controller.LogController      : log error level test

可以看到日志级别已经被动态的修改为debug级别。

分析实现原理

Actuator有个约定,/actuator/xxx端点的定义代码在xxxEndpoint中。

所以/actuator/loggers对应的类为org.springframework.boot.actuate.logging.LoggersEndpoint

@Endpoint(id = “loggers”) 用来描述Spring Boot Actuator的端点,这样就会产生一个/actuator/loggers的路径,它类似于Spring MVC的@RequestMapping(“loggers”) 。

@Endpoint(id = "loggers")
public class LoggersEndpoint {

	private final LoggingSystem loggingSystem;

	private final LoggerGroups loggerGroups;

	/**
	 * Create a new {@link LoggersEndpoint} instance.
	 * @param loggingSystem the logging system to expose
	 * @param loggerGroups the logger group to expose
	 */
	public LoggersEndpoint(LoggingSystem loggingSystem, LoggerGroups loggerGroups) {
		Assert.notNull(loggingSystem, "LoggingSystem must not be null");
		Assert.notNull(loggerGroups, "LoggerGroups must not be null");
		this.loggingSystem = loggingSystem;
		this.loggerGroups = loggerGroups;
	}

Spring Boot Actuator还提供了其他操作,如下表:

Operation HTTP method
@ReadOperation GET
@WriteOperation POST
@DeleteOperation DELETE

查看指定包/类的日志级别

org.springframework.boot.actuate.logging.LoggersEndpoint#loggerLevels

@ReadOperation
public LoggerLevels loggerLevels(@Selector String name) {
    Assert.notNull(name, "Name must not be null");
    LoggerGroup group = this.loggerGroups.get(name);
    if (group != null) {
        return new GroupLoggerLevels(group.getConfiguredLevel(), group.getMembers());
    }
    LoggerConfiguration configuration = this.loggingSystem.getLoggerConfiguration(name);
    return (configuration != null) ? new SingleLoggerLevels(configuration) : null;
}

LoggingSystem有四个实现类:

// 适用于java.util.logging的LoggingSystem
org.springframework.boot.logging.java.JavaLoggingSystem
//适用于Log4j2的LoggingSystem
org.springframework.boot.logging.log4j2.Log4J2LoggingSystem
//适用于logback的LoggingSystem
org.springframework.boot.logging.logback.LogbackLoggingSystem
// 啥都不干的LoggingSystem
org.springframework.boot.logging.LoggingSystem.NoOpLoggingSystem

Spring Boot 2.x中,默认使用Logback,因此进入到LogbackLoggingSystem中。

org.springframework.boot.logging.logback.LogbackLoggingSystem#getLoggerConfiguration(java.lang.String)

public LoggerConfiguration getLoggerConfiguration(String loggerName) {
    String name = getLoggerName(loggerName);
    LoggerContext loggerContext = getLoggerContext();
    return getLoggerConfiguration(loggerContext.exists(name));
}

private LoggerConfiguration getLoggerConfiguration(ch.qos.logback.classic.Logger logger) {
    if (logger == null) {
        return null;
    }
    LogLevel level = LEVELS.convertNativeToSystem(logger.getLevel());
    LogLevel effectiveLevel = LEVELS.convertNativeToSystem(logger.getEffectiveLevel());
    String name = getLoggerName(logger.getName());
    return new LoggerConfiguration(name, level, effectiveLevel);
}

修改包/类的日志级别

org.springframework.boot.actuate.logging.LoggersEndpoint#configureLogLevel

public void configureLogLevel(@Selector String name, @Nullable LogLevel configuredLevel) {
    Assert.notNull(name, "Name must not be empty");
    LoggerGroup group = this.loggerGroups.get(name);
    if (group != null && group.hasMembers()) {
        group.configureLogLevel(configuredLevel, this.loggingSystem::setLogLevel);
        return;
    }
    this.loggingSystem.setLogLevel(name, configuredLevel);
}

org.springframework.boot.logging.logback.LogbackLoggingSystem#setLogLevel

public void setLogLevel(String loggerName, LogLevel level) {
    ch.qos.logback.classic.Logger logger = getLogger(loggerName);
    if (logger != null) {
        logger.setLevel(LEVELS.convertSystemToNative(level));
    }
}

其实就是Spring Boot使用了Logback的API,ch.qos.logback.classic.Logger.setLevel实现日志级别的修改。

自己实现动态修改日志级别

在实际的开发过程中,应用是不会暴露出/actuator/loggers端点,因为这样会直接暴露在公网上,有安全风险,所以我们可以自己写一个Controller来修改日志级别。

package com.morris.spring.boot.controller;

import org.springframework.boot.actuate.logging.LoggersEndpoint;
import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.logging.LoggerConfiguration;
import org.springframework.boot.logging.LoggingSystem;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 动态修改日志级别
 */
@RequestMapping("loggers")
@RestController
public class LoggersController {

    private final LoggingSystem loggingSystem = LoggingSystem.get(LoggingSystem.class.getClassLoader());

    @GetMapping("/level")
    public Object getLevel(String name) {
        LoggerConfiguration configuration = loggingSystem.getLoggerConfiguration(name);
        return (configuration != null) ? new LoggersEndpoint.SingleLoggerLevels(configuration) : null;
    }

    @PostMapping("/level")
    public void setLevel(String name, LogLevel level) {
        loggingSystem.setLogLevel(name, level);
    }
}

测试,注意设置level的时候使用大写:文章来源地址https://www.toymoban.com/news/detail-763487.html

$ curl http://127.0.0.1:8888/loggers/level
{"configuredLevel":"INFO","effectiveLevel":"INFO"}

$ curl http://127.0.0.1:8888/loggers/level?name=com.morris.spring.boot.controller.LogController
{"configuredLevel":null,"effectiveLevel":"INFO"}

$ curl -X POST "http://127.0.0.1:8888/loggers/level?name=com.morris.spring.boot.controller.LogController&level=DEBUG"

$ curl http://127.0.0.1:8888/loggers/level?name=com.morris.spring.boot.controller.LogController
{"configuredLevel":"DEBUG","effectiveLevel":"DEBUG"}

到了这里,关于【springboot】如何动态修改日志级别???的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • SpringBoot设置日志输出级别及Logback日志工具输出到文件

    1.SpringBoot设置日志输出级别 越高包含的就越多,输出的信息也就越多 2.Logback日志工具使用 1.首先需要把你yaml文件里面关于日志的配置去掉,避免冲突报错 2.在resource目录下创建logback-spring.xml文件 2.运行后指定路径就会生成.log文件 3.此时一般默认只有info信息写入,其他两个

    2024年02月16日
    浏览(62)
  • Spring Cloud Gateway日志级别链路追踪设计

    ​ 为了配合日志分析系统ELK(ElasticSearch,Logstash,Kibana)方便解析日志文件,需要对日志文件的输出格式进行JSON格式化,我这里使用的日志工具是logback(幸运的躲过了log4j的漏洞)+logstash-encoder包进行的封装的一个日志插件,该插件实现了日志JSON格式化,适配了多种中间件的链

    2024年02月11日
    浏览(42)
  • Spring Boot学习随笔- 本地化测试(@SpringBootTest)、热部署(spring-boot-devtools)、日志Logback常用级别使用、指定包级别输出

    学习视频:【编程不良人】2021年SpringBoot最新最全教程 频繁启动服务器进行功能的访问非常繁琐、SpringBoot给我们提供了用于测试的依赖,自动集成Junit,使用了这个以来后,test包在打包时不会被打包进去 @SpringBootTest注解 修饰在类上,用来启动本地Spring环境 作用 热部署是指

    2024年02月05日
    浏览(79)
  • Hive终端命令行打印很多日志时,如何设置日志级别

    示例:use test; 切换到test数据库时,输出很多日志信息不方便看结果,如下图。   解决方法: 退出hive命令行界面(ctrl+C) 执行“vi /usr/local/apache-hive-3.1.2-bin/conf/log4j.properties”命令,创建并编辑log4j.properties文件,添加以下内容。(完成后保存退出)   再次通过“hive”指令进

    2024年02月13日
    浏览(41)
  • 如何控制Flink代码运行时控制日志级别

    在Flink程序中,可以通过设置日志级别来控制控制台输出的信息。要让控制台只打印结果信息,可以将日志级别设置为 ERROR 。这样,只有错误信息和 print() 方法输出的结果会显示在控制台上。 要设置日志级别,请在Flink项目的 resources 目录下创建一个名为 log4j.properties 的文件

    2024年02月06日
    浏览(34)
  • 【Spring Boot】事务的隔离级别与事务的传播特性详解:如何在 Spring 中使用事务?不同隔离级别的区别?

    事务这个词在学习 MySQL 和多线程并发编程的时候,想必大家或多或少接触过。 那么什么是事务呢? 事务是指一组操作作为一个不可分割的执行单元,要么全部成功执行,要么全部失败回滚。在数据库中,事务可以保证数据的一致性、完整性和稳定性,同时避免了数据的异常

    2024年02月13日
    浏览(42)
  • spring boot 使用AOP+自定义注解+反射实现操作日志记录修改前数据和修改后对比数据,并保存至日志表

    使用FieldMeta自定义注解,看个人业务自行觉得是否需要重新定义实体 实现类 :通过该实现类获取更新前后的数据。 该实现类的实现原理为:获取入参出入的id值,获取sqlSessionFactory,通过sqlSessionFactory获取selectByPrimaryKey()该方法,执行该方法可获取id对应数据更新操作前后的数

    2024年01月23日
    浏览(53)
  • 【Spring】SpringBoot日志

    在计算机领域,日志是一个记录了发生在运行中的操作系统或其他软件中的事件,或者记录了在网络聊天软件的用户之间发送的消息。 通常情况下,系统日志是用户可以直接阅读的文本文件,其中包含了一个时间戳和一个信息或者子系统所特有的其他信息。任何系统中,日志

    2024年02月04日
    浏览(33)
  • 【JavaEE & Spring】SpringBoot 日志

    为什么要学习日志 对于平常来说, 我们就在使⽤ System.out.print 来打印⽇志了 随着项⽬的复杂度提升, 我们对⽇志的打印也有了更⾼的需求, ⽽不仅仅是定位排查问题. 有时候我们需要将日志持久化, 进行对应的数据分析, 但是 System.out.print 不能很好的满⾜我们的需求, 我们就需要

    2024年01月25日
    浏览(38)
  • springboot 项目启动不打印spring 启动日志

    今天项目遇到一个很奇怪的问题,服务在启动时,不打印spring 的启动日志。经过排查发现是因为其他的依赖引入了 log4j 的依赖,因为我们的项目用的是logback,所以项目中没有log4j 的相关配置,所以干扰到了日志的打印 下面是log4j缺失配置文件的告警日志: log4j:WARN No append

    2024年02月11日
    浏览(58)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包