• 让你的spring-boot应用日志随心所欲--spring boot日志深入分析


    1.spring boot日志概述

    spring boot使用Commons Logging作为内部的日志系统,并且给Java Util Logging,Log4J2以及Logback都提供了默认的配置。
    如果使用了spring boot的Starters,那么默认会使用Logback用于记录日志。

    2.spring boot日志默认配置

    我们启动一个空的spring-boot项目看一下控制台的日志

    控制台的默认配置

    logging.pattern.console=%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}

    其中%clr为配置不同的颜色输出,支持的颜色有以下几种:

    • blue
    • cyan
    • faint
    • green
    • magenta
    • red
    • yellow

    输出顺序分析:

    1、日期和时间--精确到毫秒,并按照时间进行简单的排序,格式为:

    %clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint}


    2、日志级别--ERROR,WARN,INFO,DEBUG,TRACE

    %clr(${LOG_LEVEL_PATTERN:-%5p})


    3、进程ID号

    %clr(${PID:- })


    4、日志内容,用"---"分隔符分开

    %clr(---){faint}


    5、线程名字--括在方括号中

      

    %clr([%15.15t]){faint}


    6、日志的名字--通常对应的是类名

      

    %clr(%-40.40logger{39}){cyan}

    注意:Logback没有FATAL级别(映射到ERROR)

    不同日志级别对应的颜色如下

    3.spring boot日志配置

    可以通过application.properties或者application.yml查看所有配置

    每个配置后面都有说明,就不一一赘述了。

    4.spring boot日志实现原理

     点击配置属性,可以进入LoggingApplicationListener这个类,

    /**
     * An {@link ApplicationListener} that configures the {@link LoggingSystem}. If the
     * environment contains a {@code logging.config} property it will be used to bootstrap the
     * logging system, otherwise a default configuration is used. Regardless, logging levels
     * will be customized if the environment contains {@code logging.level.*} entries and
     * logging groups can be defined with {@code logging.group}.
     * <p>
     * Debug and trace logging for Spring, Tomcat, Jetty and Hibernate will be enabled when
     * the environment contains {@code debug} or {@code trace} properties that aren't set to
     * {@code "false"} (i.e. if you start your application using
     * {@literal java -jar myapp.jar [--debug | --trace]}). If you prefer to ignore these
     * properties you can set {@link #setParseArgs(boolean) parseArgs} to {@code false}.
     * <p>
     * By default, log output is only written to the console. If a log file is required the
     * {@code logging.path} and {@code logging.file} properties can be used.
     * <p>
     * Some system properties may be set as side effects, and these can be useful if the
     * logging configuration supports placeholders (i.e. log4j or logback):
     * <ul>
     * <li>{@code LOG_FILE} is set to the value of path of the log file that should be written
     * (if any).</li>
     * <li>{@code PID} is set to the value of the current process ID if it can be determined.
     * </li>
     * </ul>
     *
     * @author Dave Syer
     * @author Phillip Webb
     * @author Andy Wilkinson
     * @author Madhura Bhave
     * @since 2.0.0
     * @see LoggingSystem#get(ClassLoader)
     */

    它实现了GenericApplicationListener接口,它默认定义了日志组DEFAULT_GROUP_LOGGERS和日志级别LOG_LEVEL_LOGGERS

    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");
            DEFAULT_GROUP_LOGGERS = Collections.unmodifiableMap(loggers);
        }
    
        private static final Map<LogLevel, List<String>> LOG_LEVEL_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");
            LOG_LEVEL_LOGGERS = Collections.unmodifiableMap(loggers);
        }

    你也可以自定义logging.level和logging.group,它们都是map结构。LoggingApplicationListener重写了onApplicationEvent方法,实现日志的打印

        @Override
        public void onApplicationEvent(ApplicationEvent event) {
            if (event instanceof ApplicationStartingEvent) {
                onApplicationStartingEvent((ApplicationStartingEvent) event); //1
            }
            else if (event instanceof ApplicationEnvironmentPreparedEvent) {
                onApplicationEnvironmentPreparedEvent(
                        (ApplicationEnvironmentPreparedEvent) event); //2 
            }
            else if (event instanceof ApplicationPreparedEvent) {
                onApplicationPreparedEvent((ApplicationPreparedEvent) event); //3
            }
            else if (event instanceof ContextClosedEvent && ((ContextClosedEvent) event)
                    .getApplicationContext().getParent() == null) {
                onContextClosedEvent();  //4
            }
            else if (event instanceof ApplicationFailedEvent) {
                onApplicationFailedEvent();  //5
            }
        }

    第一步:根据classloader里加载的依赖决定使用哪个日志系统?

    主要实现有JavaLoggingSystem,Log4J2LoggingSystem,LogbackLoggingSystem

        private void onApplicationStartingEvent(ApplicationStartingEvent event) {
            this.loggingSystem = LoggingSystem
                    .get(event.getSpringApplication().getClassLoader());
            this.loggingSystem.beforeInitialize();
        }

    第二步:通过classpath,enviroment等获取参数初始化日志系统

        /**
         * Initialize the logging system according to preferences expressed through the
         * {@link Environment} and the classpath.
         * @param environment the environment
         * @param classLoader the classloader
         */
        protected void initialize(ConfigurableEnvironment environment,
                ClassLoader classLoader) {
            new LoggingSystemProperties(environment).apply();
            LogFile logFile = LogFile.get(environment);
            if (logFile != null) {
                logFile.applyToSystemProperties();
            }
            initializeEarlyLoggingLevel(environment);
            initializeSystem(environment, this.loggingSystem, logFile);
            initializeFinalLoggingLevels(environment, this.loggingSystem);
            registerShutdownHookIfNecessary(environment, this.loggingSystem);
        }

    第三步:注册springBootLoggingSystem

        private void onApplicationPreparedEvent(ApplicationPreparedEvent event) {
            ConfigurableListableBeanFactory beanFactory = event.getApplicationContext()
                    .getBeanFactory();
            if (!beanFactory.containsBean(LOGGING_SYSTEM_BEAN_NAME)) {
                beanFactory.registerSingleton(LOGGING_SYSTEM_BEAN_NAME, this.loggingSystem);
            }
        }

    第四步和第五步:日志系统清洗

        private void onContextClosedEvent() {
            if (this.loggingSystem != null) {
                this.loggingSystem.cleanUp();
            }
        }
    
        private void onApplicationFailedEvent() {
            if (this.loggingSystem != null) {
                this.loggingSystem.cleanUp();
            }
        }

    5.自定义配置文件

    日志系统自定义配置文件

    Logback

    logback-spring.xmllogback-spring.groovylogback.xml, or logback.groovy

    Log4j2

    log4j2-spring.xml or log4j2.xml

    JDK (Java Util Logging)

    logging.properties

    6.总结

      spring boot日志系统封装了logback,log4j2和java log,默认情况下使用java log,一旦使用各种starts,则默认使用Log4J2,也可以通过classpath来改变,pom.xml指定

    <dependency> 
     <groupId>org.springframework.boot</groupId> 
     <artifactId>spring-boot-starter</artifactId> 
     <exclusions> 
      <exclusion> 
       <groupId>org.springframework.boot</groupId> 
       <artifactId>spring-boot-starter-logging</artifactId> 
      </exclusion> 
     </exclusions> 
    </dependency> 
    <dependency> 
     <groupId>org.springframework.boot</groupId> 
     <artifactId>spring-boot-starter-log4j</artifactId> 
    </dependency> 

    参考资料

    【1】https://docs.spring.io/spring-boot/docs/2.1.2.RELEASE/reference/htmlsingle/#boot-features-logging-format

    【2】https://www.jb51.net/article/133795.htm

  • 相关阅读:
    环形缓冲区: ringbuf.c
    Linux内核中_IO,_IOR,_IOW,_IOWR宏的用法与解析
    list.h在用户态下的应用
    如何优雅的拔盘?
    谨慎调整内核参数:vm.min_free_kbytes
    Linux内核tracepoints
    网卡多队列
    How to use pthread_create && mutex?
    美国电子工程师最值得打工的50个东家
    关于零点和极点的讨论
  • 原文地址:https://www.cnblogs.com/davidwang456/p/10997038.html
Copyright © 2020-2023  润新知