亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.430618.com 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

背景

作為程序猿,定位問(wèn)題是我們的日常工作,而日志是我們定位問(wèn)題非常重要的依據(jù)。傳統(tǒng)方式定位問(wèn)題時(shí),往往是如下步驟:

  • 將日志級(jí)別設(shè)低,例如 DEBUG ;
  • 重啟應(yīng)用;
  • 復(fù)現(xiàn)問(wèn)題,觀察日志;

那么問(wèn)題就來(lái)了,可不可以動(dòng)態(tài)修改日志級(jí)別呢?(無(wú)需重啟應(yīng)用,就能立刻刷新)

答案是肯定的!

下面提供幾個(gè)思路給大家參考。

使用 LoggingSystem 自行開(kāi)發(fā)修改日志級(jí)別的接口

不廢話,直接上代碼

@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?這么簡(jiǎn)單?是的,就是這么簡(jiǎn)單。

LoggingSystem 這個(gè)抽象類(lèi)就是關(guān)鍵,其實(shí)后面所要介紹的幾個(gè)修改思路(actuator,Apollo,mq)的底層也是基于它進(jìn)行修改的。

如果大家對(duì)LoggingSystem這個(gè)類(lèi)在底層究竟是如何實(shí)現(xiàn)動(dòng)態(tài)修改日志級(jí)別感興趣的話,請(qǐng)?jiān)u論區(qū)留言,我抽時(shí)間再寫(xiě)一篇文章來(lái)詳細(xì)說(shuō)一下。

然后再說(shuō)一下這種方式的優(yōu)缺點(diǎn)吧。

優(yōu)點(diǎn):簡(jiǎn)單!

缺點(diǎn):也很明顯,只適合單機(jī)/生產(chǎn)機(jī)器不多的服務(wù)。如果你的服務(wù)有上百個(gè)節(jié)點(diǎn),用這種方式來(lái)修改。。。

那有朋友會(huì)問(wèn),有沒(méi)有適合多機(jī)集群的服務(wù)的修改方式?

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

使用 Apollo + LoggingSystem

這種方式的前提是系統(tǒng)接入了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;


    /**
     * 支持類(lèi)配置
     */
    @PostConstruct
    private void init() {
      //要修改日志級(jí)別的key(包路徑/類(lèi)路徑)
        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配置后的回調(diào)方法
    */
    @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();
    }

    /**
     * 獲取當(dāng)前類(lèi)的Logger對(duì)象有效日志級(jí)別對(duì)應(yīng)的方法,進(jìn)行日志輸出。舉例:
     * 如果當(dāng)前類(lèi)的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 這個(gè)類(lèi)進(jìn)行修改日志級(jí)別的操作。

那可能大家會(huì)問(wèn),Apollo在這里的作用是什么?

如果大家用過(guò)Apollo的話就會(huì)發(fā)現(xiàn),在Apollo可視化管理系統(tǒng)中,每個(gè)系統(tǒng)都有一個(gè)實(shí)例列表,里面就是我們具體的應(yīng)用地址。所以在這里你可以認(rèn)為Apollo有類(lèi)似注冊(cè)中心的作用,在我們應(yīng)用啟動(dòng)的時(shí)候,Apollo后臺(tái)就會(huì)記錄下來(lái)。

所以Apollo能實(shí)現(xiàn)集群的日志級(jí)別動(dòng)態(tài)修改的原理就在這。是不是也很簡(jiǎn)單呢?

使用 MQ + LoggingSystem

 

如果你們的系統(tǒng)沒(méi)有接入Apollo的話,那應(yīng)該如何實(shí)現(xiàn)集群的日志級(jí)別動(dòng)態(tài)修改呢?

MQ就是其中一個(gè)選擇。我簡(jiǎn)單說(shuō)一下實(shí)現(xiàn)思路吧,具體實(shí)現(xiàn)也很簡(jiǎn)單,就留給大家去動(dòng)手實(shí)踐啦。

  1. 暴露一個(gè)修改日志級(jí)別的接口
  2. 這個(gè)接口要做的是使用producer來(lái)發(fā)送一個(gè)廣播類(lèi)型的MQ,注意了,是廣播類(lèi)型的
  3. 在consumer里面通過(guò)LoggingSystem進(jìn)行日志級(jí)別的修改即可。

是不是很簡(jiǎn)單呢?

使用Springboot的 actuator 組件

其實(shí)這種方法和方式一是差不多的,只是actuator把接口通過(guò)端點(diǎn)Endpoints 的方式暴露出來(lái)。

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

  • 什么是端點(diǎn)

Endpoints 是 Actuator 的核心部分,它用來(lái)監(jiān)視應(yīng)用程序及交互,spring-boot-actuator中已經(jīng)內(nèi)置了非常多的Endpoints(health、info、beans、httptrace、shutdown等等),同時(shí)也允許我們擴(kuò)展自己的端點(diǎn)。

  • 端點(diǎn)的分類(lèi)

Endpoints 分成兩類(lèi):原生端點(diǎn)和用戶自定義端點(diǎn);自定義端點(diǎn)主要是指擴(kuò)展性,用戶可以根據(jù)自己的實(shí)際應(yīng)用,定義一些比較關(guān)心的指標(biāo),在運(yùn)行期進(jìn)行監(jiān)控。

原生端點(diǎn)是在應(yīng)用程序里提供的眾多 restful api 接口,通過(guò)它們可以監(jiān)控應(yīng)用程序運(yùn)行時(shí)的內(nèi)部狀況。

原生端點(diǎn)又可以分成三類(lèi):

  1. 應(yīng)用配置類(lèi):可以查看應(yīng)用在運(yùn)行期間的靜態(tài)信息:例如自動(dòng)配置信息、加載的spring bean信息、yml文件配置信息、環(huán)境信息、請(qǐng)求映射信息;
  2. 度量指標(biāo)類(lèi):主要是運(yùn)行期間的動(dòng)態(tài)信息,例如堆棧、請(qǐng)求鏈、一些健康指標(biāo)、metrics信息等
  3. 操作控制類(lèi):主要是指shutdown,用戶可以發(fā)送一個(gè)請(qǐng)求將應(yīng)用的監(jiān)控功能關(guān)閉。

我們這里修改配置文件用到的就是應(yīng)用配置類(lèi)的端點(diǎn)。

查看當(dāng)前應(yīng)用各包/類(lèi)的日志級(jí)別

http://localhost:8080/actuator/loggers

可看到類(lèi)似如下的結(jié)果:

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

查看指定包/類(lèi)日志詳情

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

可看到類(lèi)似如下的結(jié)果:

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

修改日志級(jí)別

POST方式,json格式的參數(shù)

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

Springboot 動(dòng)態(tài)改變Log級(jí)別

actuator修改日志級(jí)別

但這種方式和方式一有同樣的局限性,就是只適合單機(jī)或者開(kāi)發(fā)環(huán)境。如果想用這種方式的話可以接入Spring Boot Admin。通過(guò)后臺(tái)的方式進(jìn)行管理。

分享到:
標(biāo)簽:Springboot
用戶無(wú)頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過(guò)答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫(kù),初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定