动态调整日志级别 发表于 2020-05-08 | 更新于 2021-02-25 | 分类于 log 参考资料:日志级别动态调整——小工具解决大问题Java日志框架:slf4j作用及其实现原理 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165import java.util.ArrayList;import java.util.Enumeration;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.concurrent.ConcurrentHashMap;import java.util.concurrent.ConcurrentMap;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.slf4j.impl.StaticLoggerBinder;/** * 动态修改日志级别 * <p/> * <a href="https://tech.meituan.com/2017/02/17/change-log-level.html">日志级别动态调整——小工具解决大问题</a> * * @author <a href=mailto:ktyi@iflytek.com>伊开堂</a> * @date 2020/5/8 */public class LoggerLevelModifier { private static final Logger logger = LoggerFactory.getLogger(LoggerLevelModifier.class); private static LogFrameworkType logFrameworkType; private static ConcurrentMap<String, Object> loggerMap = new ConcurrentHashMap<>(); public static void init() { // slf4j找org/slf4j/impl/StaticLoggerBinder.class类, 有些是默认实现(logback), 有些是桥接包(log4j/2) String type = StaticLoggerBinder.getSingleton().getLoggerFactoryClassStr(); if (LogConstant.LOG4J_LOGGER_FACTORY.equals(type)) { logFrameworkType = LogFrameworkType.LOG4J; Enumeration enumeration = org.apache.log4j.LogManager.getCurrentLoggers(); while (enumeration.hasMoreElements()) { org.apache.log4j.Logger logger = (org.apache.log4j.Logger) enumeration.nextElement(); if (logger.getLevel() != null) { loggerMap.put(logger.getName(), logger); } } org.apache.log4j.Logger rootLogger = org.apache.log4j.LogManager.getRootLogger(); loggerMap.put(rootLogger.getName(), rootLogger); } else if (LogConstant.LOGBACK_LOGGER_FACTORY.equals(type)) { logFrameworkType = LogFrameworkType.LOGBACK; ch.qos.logback.classic.LoggerContext loggerContext = (ch.qos.logback.classic.LoggerContext) LoggerFactory.getILoggerFactory(); for (ch.qos.logback.classic.Logger logger : loggerContext.getLoggerList()) { if (logger.getLevel() != null) { loggerMap.put(logger.getName(), logger); } } ch.qos.logback.classic.Logger rootLogger = (ch.qos.logback.classic.Logger) LoggerFactory .getLogger(Logger.ROOT_LOGGER_NAME); loggerMap.put(rootLogger.getName(), rootLogger); } else if (LogConstant.LOG4J2_LOGGER_FACTORY.equals(type)) { logFrameworkType = LogFrameworkType.LOG4J2; org.apache.logging.log4j.core.LoggerContext loggerContext = (org.apache.logging.log4j.core.LoggerContext) org.apache.logging.log4j.LogManager .getContext(false); Map<String, org.apache.logging.log4j.core.config.LoggerConfig> map = loggerContext.getConfiguration().getLoggers(); for (org.apache.logging.log4j.core.config.LoggerConfig loggerConfig : map.values()) { String key = loggerConfig.getName(); if (isBlank(key)) { key = "root"; } loggerMap.put(key, loggerConfig); } } else { logFrameworkType = LogFrameworkType.UNKNOWN; logger.error("Log框架无法识别: type={}", type); } } private static boolean isBlank(CharSequence cs) { int strLen; if (cs != null && (strLen = cs.length()) != 0) { for (int i = 0; i < strLen; ++i) { if (!Character.isWhitespace(cs.charAt(i))) { return false; } } return true; } else { return true; } } public static Map<String, Object> getLoggerList() { Map<String, Object> result = new HashMap<>(); result.put("logFramework", logFrameworkType); List<Map<String, String>> loggerList = new ArrayList<>(); for (ConcurrentMap.Entry<String, Object> entry : loggerMap.entrySet()) { Map<String, String> loggerInfo = new HashMap<>(); loggerInfo.put("loggerName", entry.getKey()); if (logFrameworkType == LogFrameworkType.LOG4J) { org.apache.log4j.Logger targetLogger = (org.apache.log4j.Logger) entry.getValue(); loggerInfo.put("logLevel", targetLogger.getLevel().toString()); } else if (logFrameworkType == LogFrameworkType.LOGBACK) { ch.qos.logback.classic.Logger targetLogger = (ch.qos.logback.classic.Logger) entry.getValue(); loggerInfo.put("logLevel", targetLogger.getLevel().toString()); } else if (logFrameworkType == LogFrameworkType.LOG4J2) { org.apache.logging.log4j.core.config.LoggerConfig targetLogger = (org.apache.logging.log4j.core.config.LoggerConfig) entry.getValue(); loggerInfo.put("logLevel", targetLogger.getLevel().toString()); } else { loggerInfo.put("logLevel", "Logger的类型未知,无法处理!"); } loggerList.add(loggerInfo); } result.put("loggerList", loggerList); logger.info("getLoggerList: result={}", result); return result; } public static String setLogLevel(String loggerName, String level) { Object logger = loggerMap.get(loggerName); if (logger == null) { throw new RuntimeException("需要修改日志级别的Logger不存在"); } if (logFrameworkType == LogFrameworkType.LOG4J) { org.apache.log4j.Logger targetLogger = (org.apache.log4j.Logger) logger; org.apache.log4j.Level targetLevel = org.apache.log4j.Level.toLevel(level); targetLogger.setLevel(targetLevel); } else if (logFrameworkType == LogFrameworkType.LOGBACK) { ch.qos.logback.classic.Logger targetLogger = (ch.qos.logback.classic.Logger) logger; ch.qos.logback.classic.Level targetLevel = ch.qos.logback.classic.Level.toLevel(level); targetLogger.setLevel(targetLevel); } else if (logFrameworkType == LogFrameworkType.LOG4J2) { org.apache.logging.log4j.core.config.LoggerConfig loggerConfig = (org.apache.logging.log4j.core.config.LoggerConfig) logger; org.apache.logging.log4j.Level targetLevel = org.apache.logging.log4j.Level.toLevel(level); loggerConfig.setLevel(targetLevel); org.apache.logging.log4j.core.LoggerContext ctx = (org.apache.logging.log4j.core.LoggerContext) org.apache.logging.log4j.LogManager .getContext(false); ctx.updateLoggers(); // This causes all Loggers to refetch information from their LoggerConfig. } else { throw new RuntimeException("Logger的类型未知,无法处理!"); } return "success"; } private class LogConstant { public static final String LOGBACK_LOGGER_FACTORY = "ch.qos.logback.classic.util.ContextSelectorStaticBinder"; public static final String LOG4J2_LOGGER_FACTORY = "org.apache.logging.slf4j.Log4jLoggerFactory"; public static final String LOG4J_LOGGER_FACTORY = "org.slf4j.impl.Log4jLoggerFactory"; } private enum LogFrameworkType { LOG4J, LOGBACK, LOG4J2, UNKNOWN }} 本文作者: Tonny Yi 本文链接: http://codertang.com/2020/05/08/logger-level-modifier/ 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC 4.0 许可协议。转载请注明出处!