Spring Recipes之如何动态调整日志的级别

        前一篇博文也介绍了如何打印sql语句,这个打印sql语句的开关一般用日志级别的方式可以配置的,所以动态调整日志的级别就变得有意义了,不仅仅sql日志可以开启,我们可以对所有日志的级别更改,便于线上找出问题所在。

     本博文参考了spring boot的做法https://docs.spring.io/spring-boot/docs/2.0.3.RELEASE/reference/htmlsingle/#production-ready-logger-configuration,利用JMX对log级别动态调整,为了方便接口的调用,引入了Jolokia,而且spring boot 也支持这个框架的https://docs.spring.io/spring-boot/docs/2.0.3.RELEASE/reference/htmlsingle/#production-ready-jolokia,如果你使用的是spring boot,可以不用继续阅读博文,博文对与spring boot 和非spring boot做了区别。

    根据前一篇文章,为了调整打印sql的日志级别,我们需要一个MXBean:

package com.sdcuike.spring.jmx;

import ch.qos.logback.classic.Level;
import org.jolokia.jmx.JsonMBean;
import org.springframework.stereotype.Component;

/**
 * @author sdcuike
 * @date 2018/8/4
 * @since 2018/8/4
 */
@Component
@JsonMBean
public class LogSqlMXBean implements ILogSqlMXBean {

    private volatile boolean logSql = false;


    private static final String LOGSQL_LOGGERNAME = "com.sdcuike.spring.log.db";


    @Override
    public boolean isLogSql() {
        return logSql;
    }

    @Override
    public void setLogSql(boolean logSql) {
        this.logSql = logSql;

        if (logSql) {
            LoggerLevelUtils.setLogLevel(LOGSQL_LOGGERNAME, Level.DEBUG);
        } else {
            LoggerLevelUtils.setLogLevel(LOGSQL_LOGGERNAME, Level.INFO);

        }
    }

}

 其接口:

package com.sdcuike.spring.jmx;

/**
 * @author sdcuike
 * @date 2018/8/4
 * @since 2018/8/4
 */
public interface ILogSqlMXBean {

    void setLogSql(boolean b);

    boolean isLogSql();
}

 这个MXBean主要对打印sql的log级别做调整,日志级别调整工具类:

package com.sdcuike.spring.jmx;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
import org.slf4j.ILoggerFactory;
import org.slf4j.Logger;
import org.slf4j.impl.StaticLoggerBinder;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.security.CodeSource;
import java.security.ProtectionDomain;

/**
 * @author sdcuike
 * @date 2018/8/4
 * @since 2018/8/4
 */
class LoggerLevelUtils {
    private static final String ROOT_LOGGER_NAME = "ROOT";

    private LoggerLevelUtils() {

    }

    /**
     * 动态设置log级别
     * 

* 代码来源于:https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/logging/LoggersEndpoint.java * * @param loggerName * @param level */ static void setLogLevel(String loggerName, Level level) { ch.qos.logback.classic.Logger logger = getLogger(loggerName); if (logger != null) { logger.setLevel(level); } } private static ch.qos.logback.classic.Logger getLogger(String name) { LoggerContext factory = getLoggerContext(); if (StringUtils.isEmpty(name) || ROOT_LOGGER_NAME.equals(name)) { name = Logger.ROOT_LOGGER_NAME; } return factory.getLogger(name); } private static LoggerContext getLoggerContext() { ILoggerFactory factory = StaticLoggerBinder.getSingleton().getLoggerFactory(); Assert.isInstanceOf(LoggerContext.class, factory, String.format( "LoggerFactory is not a Logback LoggerContext but Logback is on " + "the classpath. Either remove Logback or the competing " + "implementation (%s loaded from %s). If you are using " + "WebLogic you will need to add 'org.slf4j' to " + "prefer-application-packages in WEB-INF/weblogic.xml", factory.getClass(), getLocation(factory))); return (LoggerContext) factory; } private static Object getLocation(ILoggerFactory factory) { try { ProtectionDomain protectionDomain = factory.getClass().getProtectionDomain(); CodeSource codeSource = protectionDomain.getCodeSource(); if (codeSource != null) { return codeSource.getLocation(); } } catch (SecurityException ex) { // Unable to determine location } return "unknown location"; } }

  代码来源于spring boot,日志框架支持对其设置级别的喔(和版本有关系吗,目前没调研)。

 现在配置一下jolokia,暴露JMX:






  
    
      
        
          
            
            
            
            
          
        
      
    
  

整个代码见:https://github.com/sdcuike/all_learning_201806/tree/blog_2018-08-05/spring-recipes/src/main/java/com/sdcuike/spring。

  暴露了JMX,我们启动一下spring boot,测试一下:

 

curl -X POST \
  http://localhost:8788/jolokia/ \
  -H 'Cache-Control: no-cache' \
  -H 'Postman-Token: c6d2266b-24aa-4d8e-933f-2226d16a38eb' \
  -d '{
    "type" : "search",
    "mbean" : "*:*"
  }'

返回的内容看看是不是有我们的MXBean:

 

Spring Recipes之如何动态调整日志的级别_第1张图片

 

现在我们查询一下打印sql的log级别:

curl -X POST \
  http://localhost:8788/jolokia/ \
  -H 'Cache-Control: no-cache' \
  -H 'Postman-Token: 56b13fc4-907f-49e1-90b4-e8b6db8aed96' \
  -d '{
    "type" : "read",
    "mbean" : "com.sdcuike.spring.jmx:name=logSqlMXBean,type=LogSqlMXBean",
    "attribute" : "LogSql"
    
  }'

Spring Recipes之如何动态调整日志的级别_第2张图片

 

  把日志级别调整到debug:

 

curl -X POST \
  http://localhost:8788/jolokia/ \
  -H 'Cache-Control: no-cache' \
  -H 'Postman-Token: d5a96f61-d531-4910-8574-a0137c58280c' \
  -d '{
    "type" : "write",
    "mbean" : "com.sdcuike.spring.jmx:name=logSqlMXBean,type=LogSqlMXBean",
    "attribute" : "LogSql",
    "value":"true"
    
  }'

 查询一下是不是我们的日志级别变了,而且测试sql打印成功。

 

如果是非spring boot应该,而是一般的应用而且使用了spring框架,可以看一下测试用例,描述了如何配置:

https://github.com/sdcuike/all_learning_201806/blob/blog_2018-08-05/spring-recipes/src/test/java/com/sdcuike/spring/JMXTest.java

。这里就不再复述了。

 

Spring Recipes之如何动态调整日志的级别_第3张图片

你可能感兴趣的:(Spring,Spring,Boot,Spring,Boot,实战)