1. 程式人生 > >spring-boot 利用 actuator 動態設定 logging 的日誌級別

spring-boot 利用 actuator 動態設定 logging 的日誌級別

引子

已經上線的服務通常情況下都會關閉日誌列印功能。但是一但進行排錯的時候,又必須開啟日誌輸出,而修改日誌級別的方式有多種。這裡只說明個人認為最優的方式

依賴

spring-boot、spring-boot-actuator

方式

定義一個根 endpoint

import java.util.concurrent.atomic.AtomicBoolean;

import org.springframework.boot.actuate.endpoint.AbstractEndpoint;

public class MyLogEndpoint extends AbstractEndpoint<Boolean> {

    AtomicBoolean atomicBoolean = new AtomicBoolean();

    // mgrLogging 為該 endpoint 的請求子路徑:  http://localhost:8080/mgrLogging
    public MyLogEndpoint() {
        super("mgrLogging", true, true);
    }

    @Override
    public Boolean invoke() {
        // 這裡我的本意是 log 開關,一個布林值。
        // 每次請求 http://localhost:8080/mgrLogging 都會呼叫該 invoke 方法
        // 通常情況下返回該 endpoint 的監控資訊
        return atomicBoolean.getAndSet(!atomicBoolean.get());
    }

}

定義一個掛靠在根 endpoint 的子節點

import org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter;
import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.logging.logback.LogbackLoggingSystem;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

public class MyLogMvcEndpoint extends EndpointMvcAdapter {

    String format = "change package name [%s] logging level to [%s]";

    public MyLogMvcEndpoint(MyLogEndpoint delegate) {
        super(delegate);
    }

    // 注意該 path 不是 http://localhost:8080/{level}/{pkn}
    // 而是構造方法中 MyLogEndpoint 的 id 對應 path 下的請求節點。
    // http://localhost:8080/mgrLogging/{level}/{pkn}

    @RequestMapping(value = "/{level}/{pkn}")
    @ResponseBody
    public Object changeLog(@PathVariable LogLevel level, @PathVariable("pkn") String packageName) {
        System.err.println(String.format(format, packageName, level));

        try {
            // 處理日誌 level 改變邏輯,根據個人需求改變
            LogbackLoggingSystem logbackLoggingSystem = new LogbackLoggingSystem(this.getClass().getClassLoader());
            logbackLoggingSystem.setLogLevel(packageName, level);

            // 處理成功(未丟擲異常)返回 success
            return "success";
        } catch (Exception e) {
            // 處理失敗返回異常資訊
            return e.getMessage();
        }
    }

}

endpoint 註冊

@Configuration
@ConditionalOnWebApplication
public class MyLogConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public MyLogEndpoint changeLogEndpoint() {
        return new MyLogEndpoint();
    }

    @Bean
    @ConditionalOnBean(MyLogEndpoint.class)
    public MyLogMvcEndpoint changeLogMvcEndpoint(MyLogEndpoint delegate) {
        return new MyLogMvcEndpoint(delegate);
    }

}

最後

org.springframework.boot.actuate.endpoint.Endpoint
該 url 不能接受請求引數,一般是返回該 endpoint 監控的資訊

org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint
該 url 可接受引數,一般情況下是用來修改或查詢該 endpoint 的配置。