求求你,別再隨便打日志了,教你動態(tài)修改日志級別!


private?static?final?Logger?LOGGER?=?LoggerFactory.getLogger(LoggerService.class);
public?void?test(){
????LOGGER.info("hollis?log?test");
}
[arthas@2062]$?logger?-n?org.springframework.web
?name???????????????????????????????????org.springframework.web
?class??????????????????????????????????ch.qos.logback.classic.Logger
?classLoader????????????????????????????sun.misc.Launcher$AppClassLoader@2a139a55
?classLoaderHash????????????????????????2a139a55
?level??????????????????????????????????null
?effectiveLevel?????????????????????????INFO
?additivity?????????????????????????????true
?codeSource?????????????????????????????file:/Users/hengyunabc/.m2/repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar
[arthas@2062]$?logger?--name?ROOT?--level?debug
update?logger?level?success.
import?org.slf4j.Logger;
import?org.slf4j.LoggerFactory;
import?org.springframework.beans.factory.annotation.Autowired;
import?org.springframework.boot.logging.LogLevel;
import?org.springframework.boot.logging.LoggerConfiguration;
import?org.springframework.boot.logging.LoggingSystem;
import?java.util.Collections;
import?java.util.List;
import?java.util.Optional;
import?java.util.stream.Collectors;
import?static?org.springframework.boot.logging.LoggingSystem.ROOT_LOGGER_NAME;
/**
?*?日志級別設置服務類
?*
?*?@author?Hollis
?*/
public?class?LoggerLevelSettingService?{
????@Autowired
????private?LoggingSystem?loggingSystem;
????private?static?final?Logger?LOGGER?=?LoggerFactory.getLogger(LoggerLevelSettingService.class);
????public?void?setRootLoggerLevel(String?level)?{
????????LoggerConfiguration?loggerConfiguration?=?loggingSystem.getLoggerConfiguration(ROOT_LOGGER_NAME);
????????if?(loggerConfiguration?==?null)?{
????????????if?(LOGGER.isErrorEnabled())?{
????????????????LOGGER.error("no?loggerConfiguration?with?loggerName?"?+?level);
????????????}
????????????return;
????????}
????????if?(!supportLevels().contains(level))?{
????????????if?(LOGGER.isErrorEnabled())?{
????????????????LOGGER.error("current?Level?is?not?support?:?"?+?level);
????????????}
????????????return;
????????}
????????if?(!loggerConfiguration.getEffectiveLevel().equals(LogLevel.valueOf(level)))?{
????????????if?(LOGGER.isInfoEnabled())?{
????????????????LOGGER.info("setRootLoggerLevel?success,old?level?is??'"?+?loggerConfiguration.getEffectiveLevel()
????????????????????+?"'?,?new?level?is?'"?+?level?+?"'");
????????????}
????????????loggingSystem.setLogLevel(ROOT_LOGGER_NAME,?LogLevel.valueOf(level));
????????}
????}
????private?List?supportLevels()? {
????????return?loggingSystem.getSupportedLogLevels().stream().map(Enum::name).collect(Collectors.toList());
????}
}

beforeInitialize方法:日志系統(tǒng)初始化之前需要處理的事情。抽象方法,不同的日志架構進行不同的處理
initialize方法:初始化日志系統(tǒng)。默認不進行任何處理,需子類進行初始化工作
cleanUp方法:日志系統(tǒng)的清除工作。默認不進行任何處理,需子類進行清除工作
getShutdownHandler方法:返回一個Runnable用于當jvm退出的時候處理日志系統(tǒng)關閉后需要進行的操作,默認返回null,也就是什么都不做
setLogLevel方法:抽象方法,用于設置對應logger的級別
/**
?*?執(zhí)行LoggingSystem初始化的前置操作
?*/
private?void?onApplicationStartingEvent(ApplicationStartingEvent?event)?{
????//獲取LoggingSystem的真實實現(xiàn),
????//?此處會根據(jù)不同的日志框架獲取不同的實現(xiàn),
????// logback :LogbackLoggingSystem
????// log4j2:Log4J2LoggingSystem
????// javalog:JavaLoggingSystem
????this.loggingSystem?=?LoggingSystem
????????.get(event.getSpringApplication().getClassLoader());
????//執(zhí)行beforeInitialize方法完成初始化前置操作
????this.loggingSystem.beforeInitialize();
}
/**
?*?the?config?of?logger
?*
?*?@author?Hollis
?*/
public?class?LoggerConfig?{
????/**
?????*?the?name?of?the?logger
?????*/
????private?String?loggerName;
????/**
?????*?the?log?level
?????*
?????*?@see?LogLevel
?????*/
????private?String?level;
????public?String?getLoggerName()?{
????????return?loggerName;
????}
????public?void?setLoggerName(String?loggerName)?{
????????this.loggerName?=?loggerName;
????}
????public?String?getLevel()?{
????????return?level;
????}
????public?void?setLevel(String?level)?{
????????this.level?=?level;
????}
}
接著提供方法動態(tài)修改日志級別:
public?void?setLoggerLevel(List ?configList)?{
????Optional.ofNullable(configList).orElse(Collections.emptyList()).forEach(
????????config?->?{
????????????LoggerConfiguration?loggerConfiguration?=?loggingSystem.getLoggerConfiguration(config.getLoggerName());
????????????if?(loggerConfiguration?==?null)?{
????????????????if?(LOGGER.isErrorEnabled())?{
????????????????????LOGGER.error("no?loggerConfiguration?with?loggerName?"?+?config.getLoggerName());
????????????????}
????????????????return;
????????????}
????????????if?(!supportLevels().contains(config.getLevel()))?{
????????????????if?(LOGGER.isErrorEnabled())?{
????????????????????LOGGER.error("current?Level?is?not?support?:?"?+?config.getLevel());
????????????????}
????????????????return;
????????????}
????????????if?(LOGGER.isInfoEnabled())?{
????????????????LOGGER.info("setLoggerLevel?success?for?logger?'"?+?config.getLoggerName()?+?"'?,old?level?is??'"
????????????????????+?loggerConfiguration.getEffectiveLevel()
????????????????????+?"'?,?new?level?is?'"?+?config.getLevel()?+?"'");
????????????}
????????????loggingSystem.setLogLevel(config.getLoggerName(),?LogLevel.valueOf(config.getLevel()));
????????}
????);
}
[{'loggerName':'com.hollis.degradation.core.logger.LoggerLevelSettingService','level':'WARN'}]
[{'loggerName':'com.hollis.degradation.core.logger','level':'WARN'}]
[
??{'loggerName':'com.hollis.degradation.core.logger','level':'WARN'}
??,{'loggerName':'com.hollis.degradation.core.logger.LoggerLevelSettingService','level':'INFO'}
]
private?static?final?Logger?LOGGER1?=?LoggerFactory.getLogger(LoggerLevelSettingService.class);
private?static?final?Logger?LOGGER2?=?LoggerFactory.getLogger(TestService.class);
private?static?final?Logger?LOGGER3?=?LoggerFactory.getLogger(DebugService.class);
public?void?setDegradationLoggerLevel(String?level)?{
????LoggerConfiguration?loggerConfiguration?=?loggingSystem.getLoggerConfiguration(
????????this.getClass().getName());
????if?(loggerConfiguration?==?null)?{
????????if?(LOGGER.isWarnEnabled())?{
????????????LOGGER.warn("no?loggerConfiguration?with?loggerName?"?+?level);
????????}
????????return;
????}
????if?(!supportLevels().contains(level))?{
????????if?(LOGGER.isErrorEnabled())?{
????????????LOGGER.error("current?Level?is?not?support?:?"?+?level);
????????}
????????return;
????}
????if?(!loggerConfiguration.getEffectiveLevel().equals(LogLevel.valueOf(level)))?{
????????loggingSystem.setLogLevel(this.getClass().getName(),?LogLevel.valueOf(level));
????}
}
/**
?*?降級開關注冊器
?*
?*?@author?Hollis
?*/
public?class?DegradationSwitchInitializer?implements?Listener,?InitializingBean?{
????//從配置項中讀取應用名,方便注冊到配置中心
????@Value("${project.name}")
????private?String?appName;
????@Autowired
????private?LoggerLevelSettingService?loggerLevelSettingService;
????//配置中心值發(fā)生變化會自動回調該方法
????@Override
????public?void?valueChange(String?appName,?String?nameSpace,?String?name,
????????????????????????????String?value)?{
????????if?(name.equals(rootLogLevel.name()))?{
????????????loggerLevelSettingService.setRootLoggerLevel(value);
????????}
????????if?(name.equals(logLevelConfig.name()))?{
????????????List?loggerConfigs?=?JSON.parseArray(value,?LoggerConfig.class);
????????????loggerLevelSettingService.setLoggerLevel(loggerConfigs);
????????}
????????//將降級工具的日志輸出級別設置成INFO,保證其日志可以正常輸出
????????loggerLevelSettingService.setDegradationLoggerLevel("INFO");
????}
????@Override
????public?void?afterPropertiesSet()?{
????????//將服務配置到配置中心
????????ConfigCenterManager.addListener(this);
????????ConfigCenterManager.init(appName,?DegradationConfig.class);
????}
}
/**
?*?@author?Hollis
?*/
@Configuration
@ConditionalOnProperty(prefix?=?"hollis.degradation",?name?=?"enable",?havingValue?=?"true")
public?class?HollisDegradationAutoConfiguration?{
????@Bean
????@ConditionalOnMissingBean
????@ConditionalOnProperty(name?=?"project.name")
????public?LoggerLevelSettingService?loggerLevelSettingService()?{
????????return?new?LoggerLevelSettingService();
????}
????@Bean
????@ConditionalOnMissingBean
????@ConditionalOnBean(value?=?LoggerLevelSettingService.class)
????public?DegradationSwitchInitializer?degradationSwitchInitializer()?{
????????return?new?DegradationSwitchInitializer();
????}
}
hollis.degradation.enable?=?true
project.name?=?test
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.hollis.degradation.starter.autoconfiguration.HollisDegradationAutoConfiguration
1、通用性。要同時可以支持不同的日志框架,客戶端使用的日志框架不影響我們的功能,并且客戶端不需要關心自己的日志框架的區(qū)別。
2、可配置性??梢詫⑴渲眯畔⑼ㄟ^外部配置中心推送,可以快速進行調整。
3、易用性。通過封裝到SpringBoot Starter中,方便客戶端快速接入。
4、無侵入性。框架的使用不應該影響到應用的正常運行。
往期推薦

HTTP/2做錯了什么?剛剛輝煌2年就要被棄用了!?

央視曝光:全國第九大電商平臺倒了!創(chuàng)始人卷走260億,1200萬人被騙

那個 CEO 寫下 70 萬行代碼的公司,馬上要上市了
直面Java第343期:為什么TOMCAT要破壞雙親委派
深入并發(fā)第013期:拓展synchronized——鎖優(yōu)化
