springboot的logging.group日志分组方法源码流程解析
目录
- 序
- LoggersEndpoint
- LoggerGroups
- LoggerGroup
- LogbackLoggingSystem
- setLevel
- LoggingApplicationListener
- 示例
- 小结
序
本文主要研究一下springboot的logging.group
LoggersEndpoint
org/springframework/boot/actuate/logging/LoggersEndpoint.Java
@Endpoint(id = "loggers") public class LoggersEndpoint { private final LoggingSystem loggingSystem; private final LoggerGroups loggerGroups; /** * Create a new {@link LoggersEndpoint} instance. * @param loggingSystem the logging system to expose * @param loggerGroups the logger group to expose */ public LoggersEndpoint(LoggingSystem loggingSystem, LoggerGroups loggerGroups) { Assert.notNull(loggingSystem, "LoggingSystem must not be null"); Assert.notNull(loggerGroups, "LoggerGroups must not be null"); this.loggingSystem = loggingSystem; this.loggerGroups = loggerGroups; } @ReadOperation public Map<String, Object> loggers() { Collection<LoggerConfiguration> configurations = this.loggingSystem.getLoggerConfigurations(); if (configurations == null) { return Collections.emptypythonMap(); } Map<String, Object> result = new LinkedHashMap<>(); result.put("levels", getLevels()); result.put("loggers", getLoggers(configurations)); result.put("groups", getGroups()); return result; } private Map<String, LoggerLevels> getGroups() { Map<String, LoggerLevels> groups = new LinkedHashMap<>(); this.loggerGroups.forEach((group) -> groups.put(group.getName(), new GroupLoggerLevels(group.getConfiguredLevel(), group.getMembers()))); return groups; } @ReadOperation public LoggerLevels loggerLevels(@Selector String name) { Assert.notNull(name, "Name must not be null"); LoggerGroup group = this.loggerGroups.get(name); if (group != null) { return new GroupLoggerLevels(group.getConfiguredLevel(), group.getMembers()); } LoggerConfiguration configuration = this.loggingSystem.getLoggerConfiguration(name); return (configuration != null) ? new SingleLoggerLevels(configuration) : null; } @WriteOperation public void configureLogLevel(@Selector String name, @Nullable LogLevel configuredLevel) { Assert.notNull(name, "Name must not be empty"); LoggerGroup group = this.loggerGroups.get(name); if (group != null && group.hasMembers()) { group.configureLogLevel(configuredLevel, this.loggingSystem::setLogLevel); return; } this.loggingSystem.setLogLevel(name, configuredLevel); } //...... }
LoggersEndpoint提供了loggers、loggerLevels、configureLogLevel方法
LoggerGroups
org/springframework/boot/logging/LoggerGroups.java
public final class LoggerGroups implements Iterable<LoggerGroup> { private final Map<String, LoggerGroup> groups = new ConcurrentHashMap<>(); public LoggerGroups() { } public LoggerGroups(Map<String, List<String>> namesAndMembers) { putAll(namesAndMembers); } public void putAll(Map<String, List<String>> namesAndMembers) { namesAndMembers.forEach(this::put); } private void put(String name, List<String> members) { put(new LoggerGroup(name, members)); } private void put(LoggerGroup loggerGroup) { this.groups.put(loggerGroup.getName(), loggerGroup); } public LoggerGroup get(String name) { return this.groups.get(name); } @Override android public Iterator<LoggerGroup> iterator() { return this.groups.values().iterator(); } }
LoggerGroups实现了Iterable接口,其泛型为LoggerGroup
LoggerGroup
org/springframework/boot/logging/LoggerGroup.java
public final class LoggerGroup { private final String name; private final List<String> members; private LogLevel configuredLevel; LoggerGro编程up(String name, List<String> members) { this.name = name; this.members = Collections.unmodifiableList(new ArrayList<>(members)); } public String getName() { return this.name; } public List<String> getMembers() { return this.members; } public boolean hasMembers() { return !this.members.isEmpty(); } public LogLevel getConfiguredLevel() { return this.configuredLevel; } public void configureLogLevel(LogLevel level, BiConsumer<String, LogLevel> configurer) { this.configuredLevel = level; this.members.forEach((name) -> configurer.accept(name, level)); } }
LoggerGroup定义了name、members、configuredLevel属性,其configureLogLevel会遍历members,通过configurer(LoggingSystem接口定义了setLogLevel方法)去变更level
LogbackLoggingSystem
org/springframework/boot/logging/logback/LogbackLoggingSystem.java
@Override public void setLogLevel(String loggerName, LogLevel level) { ch.qos.logback.classic.Logger logger = getLogger(loggerName); if (logger != null) { logger.setLevel(LEVELS.convertSystemToNative(level)); } }
LogbackLoggingSystem的setLogLevel委托给了logger.setLevel
setLevel
ch/qos/logback/classic/Logger.java
public synchronized void setLevel(Level newLevel) { if (level == newLevel) { // nothing to do; return; } if (newLevel == null && isRootLogger()) { throw nejsw IllegalArgumentException("The level of the root logger cannot be set to null"); } level = newLevel; if (newLevel == null) { effectiveLevelInt = parent.effectiveLevelInt; newLevel = parent.getEffectiveLevel(); } else { effectiveLevelInt = newLevel.levelInt; } if (childrenList != null) { int len = childrenList.size(); for (int i = 0; i < len; i++) { Logger child = (Logger) childrenList.get(i); // tell child to handle parent levelInt change child.handleParentLevelChange(effectiveLevelInt); } } // inform listeners loggerContext.fireOnLevelChange(this, newLevel); }
setLevel先判断当前level是否需要变更,不需要直接返回,之后变更effectiveLevelInt为newLevel.levelInt,若该logger有childrenList,则触发child.handleParentLevelChange(effectiveLevelInt),最后执行loggerContext.fireOnLevelChange(this, newLevel)。
LoggingApplicationListener
org/springframework/boot/context/logging/LoggingApplicationListener.java
public class LoggingApplicationListener implements GenericApplicationListener { private static final ConfigurationPropertyName LOGGING_LEVEL = ConfigurationPropertyName.of("logging.level"); private static final ConfigurationPropertyName LOGGING_GROUP = ConfigurationPropertyName.of("logging.group"); private static final Bindable<Map<String, LogLevel>> STRING_LOGLEVEL_MAP = Bindable.mapOf(String.class, LogLevel.class); private static final Bindable<Map<String, List<String>>> STRING_STRINGS_MAP = Bindable .of(ResolvableType.forClassWithGenerics(MultiValueMap.class, String.class, String.class).asMap()); /** * The default order for the LoggingApplicationListener. */ public static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 20; /** * The name of the Spring property that contains a reference to the logging * configuration to load. */ public static final String CONFIG_PROPERTY = "logging.config"; /** * The name of the Spring property that controls the registration of a shutdown hook * to shut down the logging system when the JVM exits. * @see LoggingSystem#getShutdownHandler */ public static final String REGISTER_SHUTDOWN_HOOK_PROPERTY = "logging.register-shutdown-hook"; /** * The name of the {@link LoggingSystem} bean. */ public static final String LOGGING_SYSTEM_BEAN_NAME = "springBootLoggingSystem"; /** * The name of the {@link LogFile} bean. * @since 2.2.0 */ public static final String LOG_FILE_BEAN_NAME = "springBootLogFile"; /** * The name of the{@link LoggerGroups} bean. * @since 2.2.0 */ public static final String LOGGER_GROUPS_BEAN_NAME = "springBootLoggerGroups"; private static final Map<String, List<String>> DEFAULT_GROUP_LOGGERS; static { MultiValueMap<String, String> loggers = new LinkedMultiValueMap<>(); loggers.add("web", "org.springframework.core.codec"); loggers.add("web", "org.springframework.http"); loggers.add("web", "org.springframework.web"); loggers.add("web", "org.springframework.boot.actuate.endpoint.web"); loggers.add("web", "org.springframework.boot.web.servlet.ServletContextInitializerBeans"); loggers.add("sql", "org.springframework.jdbc.core"); loggers.add("sql", "org.hibernate.SQL"); loggers.add("sql", "org.jooq.tools.LoggerListener"); DEFAULT_GROUP_LOGGERS = Collections.unmodifiableMap(loggers); } private static final Map<LogLevel, List<String>> SPRING_BOOT_LOGGING_LOGGERS; static { MultiValueMap<LogLevel, String> loggers = new LinkedMultiValueMap<>(); loggers.add(LogLevel.DEBUG, "sql"); loggers.add(LogLevel.DEBUG, "web"); loggers.add(LogLevel.DEBUG, "org.springframework.boot"); loggers.add(LogLevel.TRACE, "org.springframework"); loggers.add(LogLevel.TRACE, "org.apache.tomcat"); loggers.add(LogLevel.TRACE, "org.apache.catalina"); loggers.add(LogLevel.TRACE, "org.eclipse.jetty"); loggers.add(LogLevel.TRACE, "org.hibernate.tool.hbm2ddl"); SPRING_BOOT_LOGGING_LOGGERS = Collections.unmodifiableMap(loggers); } //...... }
LoggingApplicationListener继承了GenericApplicationListener,它定义了DEFAULT_GROUP_LOGGERS,默认定义了web、sql两个LoggerGroup
示例
{ "levels": [ "OFF", "ERROR", "WARN", "INFO", "DEBUG", "TRACE" ], "loggers": { "ROOT": { "configuredLevel": "INFO", "effectiveLevel": "INFO" }, "Validator": { "configuredLevel": null, "effectiveLevel": "INFO" } }, "groups": { "web": { "configuredLevel": null, "members": [ "org.springframework.core.codec", "org.springframework.http", "org.springframework.web", "org.springframework.boot.actuate.endpoint.web", "org.springframework.boot.web.servlet.ServletContextInitializerBeans" ] }, "sql": { "configuredLevel": null, "members": [ "org.springframework.jdbc.core", "org.hibernate.SQL", "org.jooq.tools.LoggerListener" ] } } }
小结
springboot的LoggersEndpoint提供了loggers、loggerLevels、configureLogLevel方法;LoggingApplicatphpionListener继承了GenericApplicationListener,它定义了DEFAULT_GROUP_LOGGERS,默认定义了web、sql两个LoggerGroup;configureLogLevel方法可以传group名,也可以传具体的logger名,如果是group,则会一次变更其所有members的level。
以上就是springboot的logging.group日志分组方法源码流程解析的详细内容,更多关于springboot logging.group的资料请关注编程客栈(www.devze.com)其它相关文章!
精彩评论