美文网首页
2019-06-24————异常日志

2019-06-24————异常日志

作者: 假鞋子 | 来源:发表于2019-07-02 15:15 被阅读0次

    https://blog.csdn.net/f4761/article/details/86589600

    Spring Boot -日志配置加载流程
    https://www.jianshu.com/p/04ce5d85eeb8

    日志在application下可以打印,在tomat下无法打印
    猜测:根据日志文件,tomcat的日志下存在jdk的日志-Djava.util.logging.config.file=/home/bianla_jxs/eggServer/conf/logging.properties。猜测是tomcat选择了java的log。

    debug发现:在初始化的时候2次都是从(environment)载入jdk的log。而application是没有env的,所以通过url载入资源。
    【首选是env】,所以应该是先把env中的配置修改,项目用的配置文件是yml,所以应该考虑如何把yml加入到env中。

    查询。springboot如何加载springboot
    1:学框架至少先把入口学明白。【SpringApplication.run】
    https://blog.csdn.net/chengkui1990/article/details/79866499

    然后再debug的时候,发现系统启动的时候会先调用LoggingApplicationListener,然后初始化spring,配置env,在调用一遍LoggingApplicationListener

    1:springboot也会报错:2:在启动代里也有log方法,所以在启动前肯定也有配置日志的地方。

    容器启动时的初始化环境的环节。
    ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
    发现是在生成监听器的时候就有log,再发现有2个logfactory。

    查找另一个的来源
    错误:log虽然是抽象类类产生,但是是抽象类的静态方法,所以没问题。
    但是实例一定是要类的,所以进去查看抽象类中的静态方法是如何产生实例的。发现是一个抽象方法。然后查看这个抽象方法是如何产


    springboot,启动接口进入以后,在方法最后打断点,发现执行到段点的时候是容器启动完。
    Deployment of web application directory G:\apache-tomcat-7.0.88\webapps\manager has finished in 214 ms,
    同事通过断点发现传参没有用,关于传参,这是一个规范,可以参考

    然后springboot在LoggingApplicationListener初始化方法中的断点再次停下。


    https://blog.csdn.net/lz710117239/article/details/80444200
    spring的SpringApplication.run()执行两遍的问题


    https://www.jianshu.com/p/04ce5d85eeb8
    一个项目可以用多个日志,springboot可能考虑到没有后期日志框架,所以默认使用common.apache中的日志文件,没毛病。

    在入口处断点,在监听器开始的时候,会执行log的监听器LoggingApplicationListener中的onApplicationEvent方法。

    在onApplicationStartingEvent日志初始化前置操作的时候loggingSystem的类为log4j2的实现类。

    环境资源加载完成事件,初始化LoggingSystem时,在LoggingApplicationListener的initialize方法中查找配置。

    【重点】这里忽略了自定义的配置

    private void initializeSystem(ConfigurableEnvironment environment, LoggingSystem system, LogFile logFile) {
            LoggingInitializationContext initializationContext = new LoggingInitializationContext(environment);
            String logConfig = environment.getProperty("logging.config");
            //是否忽略日志配置,采用自定义配置  
            if (this.ignoreLogConfig(logConfig)) {
                system.initialize(initializationContext, (String)null, logFile);
            } else {
                try {
                    ResourceUtils.getURL(logConfig).openStream().close();
                    system.initialize(initializationContext, logConfig, logFile);
                } catch (Exception var7) {
                    System.err.println("Logging system failed to initialize using configuration from '" + logConfig + "'");
                    var7.printStackTrace(System.err);
                    throw new IllegalStateException(var7);
                }
            }
    
        }
    

    内部方法索命如果logConfig为空或者-D开头,忽略。同时打断点发现,logCinfig是
    -Djava.util.logging.config.file="C:\Users...\logging.properties"
    从环境enviroment中获取

        private boolean ignoreLogConfig(String logConfig) {
            return !StringUtils.hasLength(logConfig) || logConfig.startsWith("-D");
        }
    

    这里走了很多弯路,其实早就找到了,但是没仔细看,导致理解错了这个判断的意思。至此,需要查看环境中的配置是哪来的,并做修改。

    猜测是来自tomcat容器,但是理论上应该可以通过yml初始化。但是这里还是要先从根本enviroment的实例开始
    https://fangjian0423.github.io/2017/06/10/springboot-environment-analysis/

    ConfigFileApplicationListener的doLoadIntoGroup(464行)断点的时候(第二次,第一次是application。yml中 的数据),发现propertySource中有logging.config=applicationConfig: [classpath:/config/application-dev.yml],是需要的数据。

    【也可能】是yml直接加在到propertySource,然后从注解@propertySource中获取。

    LoggingApplicationListener中的logging.config来自environment.getProperty("logging.config");所以要查environment来源,一步一步往上查找(不要直接从入口找,可能不是同一个环境),发现是从ApplicationEnvironmentPreparedEvent中getEnvironment。然后在onApplicationEvent中调用。这个方法继承自父类ApplicationListener。

    在启动接口处的下面两段代码中加入2个断点,发现执行第一个断点厚跳入内部上述代码,结束玩以后执行第二个断点。

                ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
                Banner printedBanner = this.printBanner(environment);
    

    猜测最终的Environment实现类可能是StandardServletEnvironment

    prepareEnvironment是预备环境,在这个方法里已经有了配置的文件属性。同时具体的实现方面里面的getOrCreateEnvironment,生成一个没什么用的初始实例。

    在SpringApplication的入口方法中的
    ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
    中的prepareEnvironment中的
    listeners.environmentPrepared((ConfigurableEnvironment)environment);
    打断点的时候发现,listens中的application中的listens中有log监听器,同时传入外部的StandardServletEnvironment
    作为参数给这些监听器。
    同时根据排序发现,
    第一个是ConfigFileApplicationListener监听器,
    第三个是LoggingApplicationListener监听器,
    所以是先用config监听机加载配置文件后,再调用log监听器


    StandardServletEnvironment的getProperty来自父类AbstractEnvironment中的PropertySourcesPropertyResolver实例的getProperty。

    断点先走到LoggingApplicationListener的获取logging.config部分,再在PropertySourcesPropertyResolver的getProperty打断点。


    图片.png

    发现logging.config属性为空。同时propertySource的属性为servletConfigInitParams,只能说明在这个内容里面没有值,【因为外面有一层循环,会在var4里面一个个获取】,继续断点到systemEnvironment,发现里面有了值,为-Djava.util.logging.config.file="C:...\logging.properties"。
    【重点】看代码发现,在找到上述值以后,不会继续循环,而是会赋值以后直接结束该循环。

    解决:要么修改这个参数,要么在之前的属性里面添加logging.config的参数。但是上面的不可以加

    【重点】突然发现之前的思路又是错的。日志的使用并不是通过系统中的日志,如果是的话,应该走上面的思路,但实际上是通过LoggerFactory.getLogger()实现,所以思路应该是查看这个getlogger是怎么获取logger的。

        public static Logger getLogger(String name) {
            ILoggerFactory iLoggerFactory = getILoggerFactory();
            return iLoggerFactory.getLogger(name);
        }
    

    所以getILoggerFactory得到是一个Log4jLoggerFactory实例,而Log4jLoggerFactory没有getLogger的方法,所以跳到父类AbstractLoggerAdapter<Logger>,父类新建一个个logger【Log4jLogger】并放到loggers中。然后由Log4jLogger打印日志。然后....断思路
    PS:这里要强调下目的,【研究LoggerFactory.getLogger是如何获取实例的】

    重启思路:在错误点打断点,发现logger是log4j的实例,说明只是没输出。实例是存在的。
    再次往里面跳,在最后的AbstractLogger的this.logMessage无法跳到实现。因为该类是抽象类,实现的父接口的接口,所以具体实现由具体继承的子类来实现。

    回想application的时候能输出日志到.log文件,说明文件就是在初始化的时候生成的。所以问题还是出在初始化的时候。


    通过application的断点,确定是system.initialize(initializationContext, logConfig, logFile);这串代码生成了日志文件。

    application
    tomcat

    发现:输出日志也会有个多个,本质是还是不懂日志模块。
    【网上给出的答案】https://www.jianshu.com/p/7543a2cde78d【学习思路】


    弄懂了外置和内置tomcat的区别以后,在入口的configure方法中加入

            System.setProperty("logging.config","classpath:config/log4j2-spring.xml");
            System.setProperty("logging.manager","org.apache.logging.log4j.LogManager");
    

    在logger初始化的时候正确,但是依旧没有生成日志文件

    以外发现:
    想找最后生成生成文件的类,但是找不到。无意间在配置文件里面写错路径,报错。根据异常栈找到了最后的类。断点发现已经产生父类。但是路径未知。再次通过项目新建一个file,然后获取绝对路径,发现日志打印在了tomcat下的bin文件内。

    https://www.jianshu.com/p/04ce5d85eeb8
    可参考
    PS:网上说springboot2.0没事,但是当前spring1.5.X会有问题。当前版本【1.5.7】

    相关文章

      网友评论

          本文标题:2019-06-24————异常日志

          本文链接:https://www.haomeiwen.com/subject/sjpoqctx.html