开发者

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)其它相关文章!

        0

        上一篇:

        下一篇:

        精彩评论

        暂无评论...
        验证码 换一张
        取 消

        最新开发

        开发排行榜