日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

背景

作為程序猿,定位問題是我們的日常工作,而日志是我們定位問題非常重要的依據。傳統方式定位問題時,往往是如下步驟:

  • 將日志級別設低,例如 DEBUG ;
  • 重啟應用;
  • 復現問題,觀察日志;

那么問題就來了,可不可以動態修改日志級別呢?(無需重啟應用,就能立刻刷新)

答案是肯定的!

下面提供幾個思路給大家參考。

使用 LoggingSystem 自行開發修改日志級別的接口

不廢話,直接上代碼

@Resource
        private LoggingSystem loggingSystem;

@PostMApping("/changeLogLevel")
public void changeLogLevel(@RequestParam("name") String name, @RequestParam("level") String level) {
  LogLevel logLevel = LogLevel.valueOf(level.toUpperCase());
  loggingSystem.setLogLevel(name, logLevel);
}

what?這么簡單?是的,就是這么簡單。

LoggingSystem 這個抽象類就是關鍵,其實后面所要介紹的幾個修改思路(actuator,Apollo,mq)的底層也是基于它進行修改的。

如果大家對LoggingSystem這個類在底層究竟是如何實現動態修改日志級別感興趣的話,請評論區留言,我抽時間再寫一篇文章來詳細說一下。

然后再說一下這種方式的優缺點吧。

優點:簡單!

缺點:也很明顯,只適合單機/生產機器不多的服務。如果你的服務有上百個節點,用這種方式來修改。。。

那有朋友會問,有沒有適合多機集群的服務的修改方式?

那必須有啊,下面介紹一下思路二。

使用 Apollo + LoggingSystem

這種方式的前提是系統接入了Apollo。

也不廢話,直接上代碼吧。代碼里也有注釋。

@Configuration
public class LogLevelRefresher {
    private final static Logger log = LoggerFactory.getLogger(com.dylan.config.LoggingLevelRefresher.class);

    private static final String PREFIX = "logging.level.";
    private static final String ROOT = LoggingSystem.ROOT_LOGGER_NAME;

    @Resource
    private LoggingSystem loggingSystem;


    /**
     * 支持類配置
     */
    @PostConstruct
    private void init() {
      //要修改日志級別的key(包路徑/類路徑)
        String keyStr = ConfigCenterService.getAppProperty("log.changeKey", "logging.level.root,logging.level.com.dylan.config");
        Set<String> changedKeys = Arrays.stream(keyStr.split(",")).collect(Collectors.toSet());
        refreshLoggingLevels(changedKeys);
    }

    /**
    * 修改Apollo配置后的回調方法
    */
    @ApolloConfigChangeListener
    private void onChange(ConfigChangeEvent changeEvent) {
        refreshLoggingLevels(changeEvent.changedKeys());
    }

    private void refreshLoggingLevels(Set<String> changedKeys) {
        for (String key : changedKeys) {
            // key may be : logging.level.com.example.web
            if (StringUtils.startsWithIgnoreCase(key, PREFIX)) {
                String loggerName = PREFIX.equalsIgnoreCase(key) ? ROOT : key.substring(PREFIX.length());
                String strLevel = ConfigCenterService.getProperty(key, parentStrLevel(loggerName));
                LogLevel level = LogLevel.valueOf(strLevel.toUpperCase());
                loggingSystem.setLogLevel(loggerName, level);
              //打印一下信息,可以不用
                log(loggerName, strLevel);
            }
        }
    }

    private String parentStrLevel(String loggerName) {
        String parentLoggerName = loggerName.contains(".") ? loggerName.substring(0, loggerName.lastIndexOf(".") : ROOT;
        return loggingSystem.getLoggerConfiguration(parentLoggerName).getEffectiveLevel().name();
    }

    /**
     * 獲取當前類的Logger對象有效日志級別對應的方法,進行日志輸出。舉例:
     * 如果當前類的EffectiveLevel為WARN,則獲取的Method為 `org.slf4j.Logger#warn(JAVA.lang.String, java.lang.Object, java.lang.Object)`
     * 目的是為了輸出`changed {} log level to:{}`這一行日志
     */
    private void log(String loggerName, String strLevel) {
        try {
            LoggerConfiguration loggerConfiguration = loggingSystem.getLoggerConfiguration(log.getName());
            Method method = log.getClass().getMethod(loggerConfiguration.getEffectiveLevel().name().toLowerCase(), String.class, Object.class, Object.class);
            method.invoke(log, "changed {} log level to:{}", loggerName, strLevel);
        } catch (Exception e) {
            log.error("changed {} log level to:{} error", loggerName, strLevel, e);
        }
    }
}

大家可以看到,Apollo的方式最終也是LoggingSystem 這個類進行修改日志級別的操作。

那可能大家會問,Apollo在這里的作用是什么?

如果大家用過Apollo的話就會發現,在Apollo可視化管理系統中,每個系統都有一個實例列表,里面就是我們具體的應用地址。所以在這里你可以認為Apollo有類似注冊中心的作用,在我們應用啟動的時候,Apollo后臺就會記錄下來。

所以Apollo能實現集群的日志級別動態修改的原理就在這。是不是也很簡單呢?

使用 MQ + LoggingSystem

 

如果你們的系統沒有接入Apollo的話,那應該如何實現集群的日志級別動態修改呢?

MQ就是其中一個選擇。我簡單說一下實現思路吧,具體實現也很簡單,就留給大家去動手實踐啦。

  1. 暴露一個修改日志級別的接口
  2. 這個接口要做的是使用producer來發送一個廣播類型的MQ,注意了,是廣播類型的
  3. 在consumer里面通過LoggingSystem進行日志級別的修改即可。

是不是很簡單呢?

使用Springboot的 actuator 組件

其實這種方法和方式一是差不多的,只是actuator把接口通過端點Endpoints 的方式暴露出來。

至于什么是端點(Endpoints),我簡單介紹一下吧。

  • 什么是端點

Endpoints 是 Actuator 的核心部分,它用來監視應用程序及交互,spring-boot-actuator中已經內置了非常多的Endpoints(health、info、beans、httptrace、shutdown等等),同時也允許我們擴展自己的端點。

  • 端點的分類

Endpoints 分成兩類:原生端點和用戶自定義端點;自定義端點主要是指擴展性,用戶可以根據自己的實際應用,定義一些比較關心的指標,在運行期進行監控。

原生端點是在應用程序里提供的眾多 restful api 接口,通過它們可以監控應用程序運行時的內部狀況。

原生端點又可以分成三類:

  1. 應用配置類:可以查看應用在運行期間的靜態信息:例如自動配置信息、加載的spring bean信息、yml文件配置信息、環境信息、請求映射信息;
  2. 度量指標類:主要是運行期間的動態信息,例如堆棧、請求鏈、一些健康指標、metrics信息等
  3. 操作控制類:主要是指shutdown,用戶可以發送一個請求將應用的監控功能關閉。

我們這里修改配置文件用到的就是應用配置類的端點。

查看當前應用各包/類的日志級別

http://localhost:8080/actuator/loggers

可看到類似如下的結果:

{
	"levels": ["OFF", "ERROR", "WARN", "INFO", "DEBUG", "TRACE"],
	"loggers": {
		"ROOT": {
			"configuredLevel": "INFO",
			"effectiveLevel": "INFO"
		},		
		"com.itmuch.logging.TestController": {
			"configuredLevel": null,
			"effectiveLevel": "INFO"
		}
	}
	// ...省略
}

查看指定包/類日志詳情

http://localhost:8080/actuator/loggers/com.dylan.logging.TestController

可看到類似如下的結果:

{"configuredLevel":null,"effectiveLevel":"INFO"}

修改日志級別

POST方式,json格式的參數

example:http://localhost:8080/actuator/loggers/com.dylan.controller.IncreaseAgentController

Springboot 動態改變Log級別

actuator修改日志級別

但這種方式和方式一有同樣的局限性,就是只適合單機或者開發環境。如果想用這種方式的話可以接入Spring Boot Admin。通過后臺的方式進行管理。

分享到:
標簽:Springboot
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定