SpringBoot如何动态改变日志级别

前言

关于日志级别,大部分项目可能都设置为info级别,当然也可能有一些追求性能或者说包含很多敏感信息的项目直接将级别设置为warn或者error;这时候如果项目中出现一些未知异常,需要用到很详细的日志信息,此时如果项目中没有动态改变日志级别的机制,排查问题将很棘手。

日志系统

我们常用的一些日志系统包括:Log4j2、Logback、Java Util Logging;我们想动态改变日志的级别,前提是这些日志系统都支持我们直接设置日志等级,当然这些系统提供了很简单的接口;

  • Log4j2
LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false);
LoggerConfig loggerConfig = loggerContext.getConfiguration().getLoggers().get("root");
loggerConfig.setLevel(level);
  • Logback
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
Logger logger = loggerContext.getLogger("root");
((ch.qos.logback.classic.Logger) logger).setLevel(level);
  • Java Util Logging
Logger logger = Logger.getLogger("root");
logger.setLevel(level);

当然除了上面直接设置日志级别的方式,也有可以动态加载配置文件的方式,同样也可以在配置文件中动态改变日志级别,以logback为例:

LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
File externalConfigFile = new File("logback.xml");
JoranConfigurator configurator = new JoranConfigurator();
configurator.setContext(lc);
lc.reset();
configurator.doConfigure(externalConfigFileLocation);

上面简单介绍了一下每种日志系统都是如何去设置日志级别的,最关键的是设置完之后,可以实时生效,立马可以看到我们想要的日志;有了这些下面其实就是通过何种方式去改变日志级别的问题了;

如何动态改变级别

如何去动态改变级别,最简单的方式就是对外提供一个接口,给定一个日志级别作为参数实时变更;或者通过配置中心的方式;另外其实像SpringBoot这些主流的框架本身也提供了动态修改的功能;下面可以具体看一下是如何实现的,以logback为例;

自定义接口

自定义一个给定日志级别的接口,外部直接通过调用接口来改变级别:

@RequestMapping(value = "logLevel/{logLevel}")
public String changeLogLevel(@PathVariable("logLevel") String logLevel) {
  try {
    LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
    Logger logger = loggerContext.getLogger("root");
    ((ch.qos.logback.classic.Logger) logger).setLevel(Level.valueOf(logLevel));
  } catch (Exception e) {
    logger.error("changeLogLevel error", e);
    return "fail";
  }
  return "success";
}

想要改变日志级别直接请求如下地址即可,设置一个debug的级别:

http://[ip]:[port]/logLevel/debug

这种方式虽然比较简单,但是如果节点很多的话,操作起来就很麻烦,当然也可以汇总所有节点路径,一次操作触发所有节点的请求;其实最好的办法应该是类似发布订阅的方式,发布者会给所有订阅者都发送一个更改日志级别的通知,有新的节点只要成为订阅者即可,这种方式其实就是现在主流的配置中心的方式。

配置中心

配置中心的目的其实就是把一些会经常变动的参数集中保存起来,某个系统启动时去配置中心获取相关的参数,同时会对这些参数进行监听,后面在配置中心里面改变参数的值会实时推送给相关系统;这样系统就可以在不重启的情况下就更新了配置;
利用现有的一些中间件我们就能很快实现一个配置中心,比如Zookeeper提供了对某个Node进行监听的功能,MQ和Redis都有发布订阅的功能,所以用来实时推送变更再好不过了;

  • Zookeeper方式

可以直接使用PathChildrenCache用来监听子节点的CHILD_ADDED,CHILD_UPDATED,CHILD_REMOVED事件;这样如果在Zookeeper服务端对节点的值就行更新,客户端会触发以上三个事件:

private void watcherPath(String path) {
  PathChildrenCache cache = new PathChildrenCache(client, path, true);
  cache.start(StartMode.POST_INITIALIZED_EVENT);
  cache.getListenable().addListener(new PathChildrenCacheListener() {
    @Override
    public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
      switch (event.getType()) {
      case CHILD_ADDED:
        break;
      case CHILD_UPDATED:
        String logLevel = new String(event.getData().getData());
         //日志级别更新处理
        break;
      case CHILD_REMOVED:
        break;
      default:
        break;
      }
    }
  });
}
  • MQ方式

MQ一般都有Queue和Topic方式,Topic方式其实就是订阅发布模式,所有的集群节点可以订阅某个Topic,这样发布端发送更新日志级别的消息,其他订阅节点都能收到:

//日志等级Topic
private final String TOPIC = "LOGLEVEL";

private void watcherPaths() throws JMSException {
  Topic topic = session.createTopic(TOPIC);
  MessageConsumer consumer = session.createConsumer(topic);
  consumer.setMessageListener(new MessageListener() {
    @Override
    public void onMessage(Message message) {
      TextMessage tm = (TextMessage) message;
      String logLevel = tm.getText();
      //日志级别更新处理
    }
  });
}
  • Redis方式

Redis其实除了缓存的功能,也提供了类似MQ的发布订阅的模式;集群节点通过订阅一个channel,发布端通过此channel来发布消息:

private void watcherPaths() throws JMSException {
  jedis.subscribe(new JedisPubSub() {
    @Override
    public void onMessage(String channel, String message) {
       String logLevel = message;
       //日志级别更新处理
    }
  },"LOGLEVEL");
}

SpringBoot内置

SpringBoot2.0之后可以通过actuator动态调整日志级别,主要是通过暴露loggers这个endpoint来实现,具体步骤如下:

  • 需要引入actuator
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
  • 暴露loggers

在application.properties中添加如下配置:

management.endpoints.web.exposure.include=loggers
  • 查看日志级别

启动服务可以通过:

http://[ip]:[port]/actuator/loggers

查看当前项目每个包的日志级别:

{
levels: [
  "OFF","ERROR","WARN","INFO","DEBUG","TRACE"
],
loggers: {
  ROOT: {
   configuredLevel: "INFO",
   effectiveLevel: "INFO"
  },
...
}
  • 动态修改日志级别

发送POST请求到:

http://[ip]:[port]/actuator/loggers/[包路径]

需要在body中指定configuredLevel参数;
比如修改整个项目日志级别为error:

http://[ip]:[port]/actuator/loggers/root

关于SpringBoot内部是如何实现动态改变日志级别的,可以查看其实现核心类LoggersEndpoint:

@Endpoint(id = "loggers")
public class LoggersEndpoint {
  private final LoggingSystem loggingSystem;
  @WriteOperation
  public void configureLogLevel(@Selector String name, @Nullable LogLevel configuredLevel) {
    Assert.notNull(name, "Name must not be empty");
    this.loggingSystem.setLogLevel(name, configuredLevel);
  }
  ...
}

具体通过LoggingSystem来对日志系统动态改变级别,上面也介绍了主流使用的日志系统,SpringBoot也都支持这些系统,这是一个抽象类,具体实现类:

  • JavaLoggingSystem
  • Log4J2LoggingSystem
  • LogbackLoggingSystem
  • NoOpLoggingSystem

分别对应了几种日志系统,这几个类内部其实也是调用上面介绍的方法去改变日志级别,当然SpringBoot自动会识别出当前使用的是哪个日志系统,然后使用哪个LoggingSystem;

总结

大部分公司其实更多的还是使用配置中心的方式来动态改变日志级别,这种方式更加灵活,而且配置中心已经成为很多公司的标配组件,不光用来改变日志级别,所有有可能改变的参数都可以使用。

以上就是SpringBoot如何动态改变日志级别的详细内容,更多关于SpringBoot 动态改变日志级别的资料请关注我们其它相关文章!

(0)

相关推荐

  • springboot整合dubbo设置全局唯一ID进行日志追踪的示例代码

    1.新建项目 利用idea创建一个父项目,三个子项目,其中一个项目为生产者,一个项目为消费者,一个为接口等公共服务项目,生产者和消费者需要有web依赖,可以作为tomcat容器启动. 2.项目依赖 <dependencies> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <v

  • springboot logback调整mybatis日志级别无效的解决

    现象 在日志配置文件 logback-spring.xml 中,无论怎么修改级别,mybatis 的 sql 日志都会打印出来. 原因 在 application.yml 中配置了 mybatis 的自定义日志类,如下: mybatis: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl 点进去查看源码,发现 debug 日志级别始终为 true,所以怎么配置都不生效 public boolean isDeb

  • SpringBoot项目的logback日志配置(包括打印mybatis的sql语句)

    关于logback日志的详解见这位仁兄的博客:Spring Boot-日志配置(超详细) 我在这就开门见山直接介绍我们项目日志的配置使用吧!~ 1.基本介绍 默认情况下,Spring Boot项目就会用Logback来记录日志,并用INFO级别输出到控制台.如下图: 实际开发中我们不需要直接添加logback日志依赖. 你会发现 spring-boot-starter 其中包含了 spring-boot-starter-logging,该依赖内容就是 Spring Boot 默认的日志框架 lo

  • springboot使用Logback把日志输出到控制台或输出到文件

    一:日志: 1.配置日志级别 日志记录器(Logger)的行为是分等级的.如下表所示: 分为:OFF.FATAL.ERROR.WARN.INFO.DEBUG.ALL 默认情况下,spring boot从控制台打印出来的日志级别只有INFO及以上级别,可以配置日志级别 设置日志级别 logging.level.root=WARN 这种方式只能将日志打印在控制台上 二.Logback日志 spring boot内部使用Logback作为日志实现的框架. Logback和log4j非常相似,如果你对l

  • SpringBoot应用整合ELK实现日志收集的示例代码

    ELK即Elasticsearch.Logstash.Kibana,组合起来可以搭建线上日志系统,本文主要讲解使用ELK来收集SpringBoot应用产生的日志. ELK中各个服务的作用 Elasticsearch:用于存储收集到的日志信息: Logstash:用于收集日志,SpringBoot应用整合了Logstash以后会把日志发送给Logstash,Logstash再把日志转发给Elasticsearch: Kibana:通过Web端的可视化界面来查看日志. 使用Docker Compos

  • springboot配置aop切面日志打印过程解析

    这篇文章主要介绍了springboot配置aop切面日志打印过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.SpringBoot Aop说明 1. Aop AOP(Aspect-Oriented Programming,面向切面编程),它利用一种"横切"的技术,将那些多个类的共同行为封装到一个可重用的模块.便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性. 2. AOP相关概念: Aspect

  • Springboot项目使用Slf4j将日志保存到本地目录的实现代码

    1.引入jar包 <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.25</version> </dependency> 2.编写application.properties/yml #.properties logging.config= classpath:logback-spr

  • springboot+mybatis配置控制台打印sql日志的方法

    此处项目环境为简单的springboot+mybatis环境.可查看到上一篇文章搭建的简单springboot+mybatis的项目 想要控制台打印sql日志. 只需要在resources目录下添加logback.xml文件即可 logback内容如下.直接复制即可 <?xml version="1.0" encoding="UTF-8"?> <configuration debug="false"> <!--定义日

  • springboot 配置日志 打印不出来sql的解决方法

    今天整合springboot2 + mybatis + logback 遇到了在日志中sql打印不出来的坑,在网上找了好久,都不是我遇到的问题,这里吐槽一下下现在的博客质量,好多都是抄袭的,也没有标注转载. 先说下要将sql打印到日志的配置 1.在mybatis.xml配置中增加以下配置 <!--指定 MyBatis 增加到日志名称的前缀.--> <setting name="logPrefix" value="m-shop-mybatis-sql.&quo

  • SpringBoot实用小技巧之如何动态设置日志级别

    前言 有时线上问题我们用打日志的方式来观察错误或埋点参数,但由于这些日志如果都打出来会占用大量存储空间而且覆盖了一些有效信息,所以线上级别一般设置INFO,调试级别用作特殊情况下.此时如果线上想查看调试级别下的日志,又不能更改日志级别后重新发布该怎么办? Spring Boot提供了日志级别动态配置功能,为我们的线上应用调试提供了很好的机制.在实际使用中需要结合Spring-Security提供的安全机制来保护Actuator 提供的各种系统级端点的安全访问. SpringBoot从版本 1.5

  • springboot使JUL实现日志管理功能

    第一步:设置logging.properties的内容(放在resource文件夹下面) #输出两种方式 handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler .level= FINE #对日志的输出进行设置(主要是file类) #java.util.logging.FileHandler.pattern = %h/java%u.log #下面的是输出到制定的目录下 java.util.logging.

随机推荐