log4j日志打印级别动态调整
1,为什么日志打印级别要动态调整?
随着项目越来越大,访问量也越来越高,遇到问题时想要排查,可是日志一打开却刷的太快太快,不好排查问题,有的时候甚至因为短时间打印日志太多,严重影响了性能,这个时候日志的打印级别的动态调整就相当有必要了,在不重启项目的情况,不改动代码的情况下,通过Apollo动态配置就可以通过配置动态的调整日志的级别,可以精确到配置具体的类的日志打印级别。
2,动态调整的方案
大致思路为在springboot项目启动之后,读取Apollo配置文件里的配置文件,总共有两个,一个是总的日志级别,一个是单独的类的配置,然后设置总的之后再设置具体到类的自定义的,同时注册一个监听器监听两个文件的变化,一旦有变化就重新设置一遍,是不是很简单呢?
具体代码如下,将该类在启动时注册入spring容器就行。值得注意的是该类中的initCustomClass()方法,该方法是因为有很多类没有在springboot启动时没有初始化,那么也就没有注册入
LoggerContext的属性中,所以是无法设置的,通过手动初始化该类的形式来初始化之后重新设置一遍。在详细的配置文件中是支持正则表达式来匹配的。
@Service
@Slf4j
public class LoggerConfiguration implements ConfigChangeListener, ApplicationListener<ContextRefreshedEvent> { private static final String LOGGER_LEVEL = "logger_level"; private static final String LOGGER_LEVEL_DETAIL = "logger_level_detail"; private static final String DEFAULT_LEVEL = "error"; private static final String INFO_LEVEL = "info"; private Config applicationConfig; public LoggerConfiguration(Config applicationConfig) {
this.applicationConfig = applicationConfig;
} @Override
public void onChange(ConfigChangeEvent changeEvent) {
if (changeEvent.changedKeys().contains(LOGGER_LEVEL)) {
String newValue = changeEvent.getChange(LOGGER_LEVEL).getNewValue();
try {
log.info("update rootLoggerLevel {}", newValue);
setRootLoggerLevel(newValue);
} catch (Exception e) {
log.error("loggerLevel onChange failed {}", ExceptionUtil.stacktraceToString(e));
}
}
if (changeEvent.changedKeys().contains(LOGGER_LEVEL_DETAIL)) {
String newValue = changeEvent.getChange(LOGGER_LEVEL_DETAIL).getNewValue();
try {
log.info("update loggerLevel detail {}", newValue);
parseLoggerConfig(newValue);
} catch (Exception e) {
log.error("loggerLevel detail onChange failed {}", ExceptionUtil.stacktraceToString(e));
}
}
} @Override
public void onApplicationEvent(ContextRefreshedEvent event) {
try {
// 初始化风控监听action配置
String level = applicationConfig.getProperty(LOGGER_LEVEL, DEFAULT_LEVEL);
log.info("init root loggerLevel {}", level);
setRootLoggerLevel(level);
// 注册配置监听
applicationConfig.addChangeListener(this);
} catch (Exception e) {
log.error("loggerLevel init failed {}", ExceptionUtil.stacktraceToString(e));
}
} /**
* 将未注册进日志容器的类处初始化
*
* @param className
*/
private boolean initCustomClass(String className) {
try {
Class.forName(className);
return true;
} catch (Exception e) {
log.error("init {} failed", className);
return false;
}
} private void setRootLoggerLevel(String level) {
try {
Level newLevel = Level.valueOf(level);
LoggerContext logContext = LoggerContext.getContext(false);
Configuration configuration = logContext.getConfiguration();
LoggerConfig loggerConfig = configuration.getRootLogger();
loggerConfig.setLevel(newLevel);
logContext.updateLoggers();
//update后会覆盖定制化的
setLoggerLevel(this.getClass().getName(), INFO_LEVEL);
reConfig();
log.info("update rootLoggerLevel {}", level);
} catch (Exception e) {
log.error("setRootLoggerLevel failed {}", ExceptionUtil.stacktraceToString(e));
} } private void setLoggerLevel(String name, String level) {
try {
Level newLevel = Level.valueOf(level);
LoggerContext logContext = LoggerContext.getContext(false); //是否没有匹配到
boolean flag = false; if (logContext.hasLogger(name)) {
//精确匹配
Logger logger = logContext.getLogger(name);
logger.setLevel(newLevel);
log.info("update {} logger level {}", name, level);
flag = true;
} else {
//正则匹配
Collection<Logger> loggers = logContext.getLoggers();
for (Logger logger : loggers) {
if (Pattern.matches(name, logger.getName())) {
logger.setLevel(newLevel);
log.info("update {} logger level {}", name, level);
flag = true;
}
}
} //该类未注册就注册,注册失败那么也就不再继续设置
if (!flag && initCustomClass(name)) {
//初始化未注册的类
setLoggerLevel(name, level);
} } catch (Exception e) {
log.error("setLoggerLevel failed {}", ExceptionUtil.stacktraceToString(e));
}
} private void reConfig() {
String detail = applicationConfig.getProperty(LOGGER_LEVEL_DETAIL, "");
if (StringUtils.isNotEmpty(detail)) {
parseLoggerConfig(detail);
}
} private void parseLoggerConfig(String value) {
Map<String, String> config = JSON.parseObject(value, Map.class);
if (config == null) {
return;
}
config.forEach((k, v) -> setLoggerLevel(k, v));
} public void setApplicationConfig(Config applicationConfig) {
this.applicationConfig = applicationConfig;
}
}
log4j日志打印级别动态调整的更多相关文章
- springboot2整合logback.xml动态修改日志打印级别
今天找bug烦到了,生产上的日志级别不能修改,非常不利于排查问题,于是想到了动态修改日志打印级别, 因为上一周把项目升级成springboot2,并且使用logback.xml管理日志打印,所以修改也 ...
- Nginx 改变错误日志打印级别
Nginx 改变错误日志打印级别 user root;worker_processes 2; worker_rlimit_nofile 10240;error_log logs/nginx_err ...
- Storm中log4j日志打印不出来的解决办法
使用storm命令启动JAVA进程的时候,发现log4j日志打印不出来,咋办呢? 解决办法如下(亲测): 删除strom/lib目录下的log4j-over-slf4j-1.6.6.jar strom ...
- log4j日志输出级别变更
1. 现阶段log4j日志输出配置 示例:基础服务日志配置 #DEBUG < INFO < WARN < ERROR < FATAL\u65E5\u5FD7\u7684\u ...
- log4j日志打印的配置文件简单使用
log4j.properties #将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码 log4j.rootLogger=DEBUG,c ...
- scarpy设置日志打印级别和存储位置
在settings.py中配置 日志级别设置 LOG_LEVEL = 'ERROR' # 当LOG_LEVEL设置为ERROR时,在进行日志打印时,只是打印ERROR级别的日志 日志存储设置 LOG_ ...
- log4j日志输出级别高低
Log4j是Apache的开源项目一个功能强大的日志组件,提供方便的日志记录.日志记录器(Logger)是日志处理的核心组件Log4j建议只使用四个级别,优先级从高到低分别是FATAL, ERROR. ...
- java项目log4j日志打印配置
#定义输出级别和输出平台 添加DEBUG表示打印sql 语句 log4j.rootLogger=DEBUG,INFO,ERROR,stdout,R log4j.category.org.spring ...
- Tomcat - 怎么控制某个类或者包下的日志打印级别
问题与分析 Tomcat是使用自己的日志实现tomcat-juli.jar来打印日志信息的,日志会被打印到catalina.out里,除去你在项目里自己使用的日志框架外,由System.out,Sys ...
随机推荐
- LQR算法如何跟随变化的期望状态
开门见山,通过LQR的能量函数可以看出,LQR算法是将状态量控制到零(关于能量函数请看我的随笔:LQR要点),但实际控制中我们希望状态量能够跟随期望值 下面将会解决如何用LQR算法跟随变化的期望值: ...
- Python实用笔记 (13)函数式编程——返回函数
函数作为返回值 我们来实现一个可变参数的求和.通常情况下,求和的函数是这样定义的: def calc_sum(*args): ax = 0 for n in args: ax = ax + n ret ...
- Github中添加SSH key
1-创建密钥,在终端输入下面的命令 ssh-keygen -t rsa -b -C "你的邮箱" //双引号不能去 要求输入密码,建议回车使用空密码方便以后的每次连接,此时会生成一 ...
- Dysregulation of Exosome Cargo by Mutant Tau Expressed in Human-induced Pluripotent Stem Cell (iPSC) Neurons Revealed by Proteomics Analyses(蛋白质组学揭示了人诱导的多能干细胞(iPSC)神经元中表达的突变Tau对外泌体的失调) 解读人:梁玉婷
期刊名:MCP 发表时间:(2020年4月) IF:4.828 单位:Skaggs School of Pharmacy and Pharmaceutical Sciences, University ...
- Django迁移命令无法生成mysql表
数据库迁移问题:在执行python manage.py makemigrations迁移命令之后,正常输出并生成迁移文件,但执行python manage.py migrate之后显示,No migr ...
- Linux distributions 发布网站
Red Hat: http://www.redhat.com SuSE: https://www.suse.com Fedora: https://getfedora.org/ CentOS: htt ...
- 【Java8新特性】冰河带你看尽Java8新特性,你想要的都在这儿了!!(文本有福利)
写在前面 很多小伙伴留言说,冰河你能不能写一些关于Java8的文章呢,看书看不下去,看视频进度太慢.好吧,看到不少读者对Java8还是比较陌生的,那我就写一些关于Java8的文章吧,希望对大家有所帮助 ...
- 大致掌握django的功能
目录 静态文件配置 request对象方法初识 pycharm链接数据库(mysql) django链接数据库(mysql) django orm 字段的增删查改 数据的增删查改 数据的查,改,删 d ...
- Howdoo中文社区AMA总结(10月21日)
10月21日Howdoo举办了中文社区的首次AMA活动,CEO -David Brierley和CMO -Jason Sibley加入到社群中与大家交流并回答社区成员的相关问题. 以下是精选的问题总结 ...
- 1-GPIO
GPIO的配置: GPIO库函数编程: void LED_init(void)//LED初始化 { GPIO_InitTypeDef GPIO_InitStructure;//定义一个结构体变量 RC ...