zoukankan      html  css  js  c++  java
  • log4j容器初始化探究

    Log4j容器初始化探究

    Log4j第一步就是初始化Logger容器Repository,这一章我们来探究Logger容器,从别从独立应用以及servlet容器下启动初始化两方面探究。

    1 独立应用

    静态初始化,java语言保证静态初始化只被执行一次,静态初始化源码在LogManager中。

    时序图:

    初始化流程:

    第一步: LogManager获取配置文件的URL

    第二步: OptionConverter获取Configurator实现类(配置类)

    第三步: Configurator读取配置文件内容,配置Logger容器(默认配置Hierarchy)

    1.1 LoggManager探究

    LogManager获取配置文件的URL

    源码:

    //只在内部使用,将来版本将变为protected级别。
    
    static public final String DEFAULT_CONFIGURATION_FILE = "log4j.properties";
    
    static final String DEFAULT_XML_CONFIGURATION_FILE = "log4j.xml";  
    
    //将来版本变为private级别
    
    public String DEFAULT_CONFIGURATION_KEY="log4j.configuration";
    
    //将来版本将变为private级别。用来指定在定义配置类
    
    static final public String CONFIGURATOR_CLASS_KEY="log4j.configuratorClass";
    
    //将来版本将变为private级别。如果不为空并且不为`false`则直接跳过初始化阶段
    
    public static final String DEFAULT_INIT_OVERRIDE_KEY =  "log4j.defaultInitOverride";
    
    static private Object guard = null;
    
    //Logger容器选择器
    
    static private RepositorySelector repositorySelector;
    
    static {
    
        //初始化Logger容器为Hierarchy。根节点是RootLogger,默认级别是DEBUG
    
        Hierarchy h = new Hierarchy(new RootLogger((Level) Level.DEBUG));
    
        //初始化Logger容器选择器,以Hierarchy为Logger容器
    
        repositorySelector = new DefaultRepositorySelector(h);
    
        //获取系统属性log4j.defaultInitOverride
    
        String override =OptionConverter.getSystemProperty(DEFAULT_INIT_OVERRIDE_KEY,null);
    
        //如果没有设置log4j.defaultInitOverride,或者log4j.defaultInitOverride为false,进入初始化流程,否则跳过初始化
    
        if(override == null || "false".equalsIgnoreCase(override)) {
    
              //读取系统属性log4j.configuration
    
              String configurationOptionStr = OptionConverter.getSystemProperty(DEFAULT_CONFIGURATION_KEY, null);
    
              //读取系统属性log4j.configuratorClass
    
              String configuratorClassName = OptionConverter.getSystemProperty(CONFIGURATOR_CLASS_KEY, null);
    
              URL url = null;
    
              //如果不存在log4j.configuration
    
              if(configurationOptionStr == null) {  
    
                //第一步先检查是否有log4j.xml
    
                url = Loader.getResource(DEFAULT_XML_CONFIGURATION_FILE);
    
                //如果没有检查是否有log4j.properties
    
                if(url == null) {
    
                  url = Loader.getResource(DEFAULT_CONFIGURATION_FILE);
    
                }
    
              } else {
    
                try {
    
                  url = new URL(configurationOptionStr);
    
                } catch (MalformedURLException ex) {
    
                  url = Loader.getResource(configurationOptionStr); 
    
                }    
    
              }
    
              if(url != null) {
    
                LogLog.debug("Using URL ["+url+"] for automatic log4j configuration.");
    
                try {
    
                    //如果存在url,则利用URL配置Logger容器
    
                    OptionConverter.selectAndConfigure(url, configuratorClassName,LogManager.getLoggerRepository());
    
                } catch (NoClassDefFoundError e) {
    
                    LogLog.warn("Error during default initialization", e);
    
                }
    
              } else {
    
                  LogLog.debug("Could not find resource: ["+configurationOptionStr+"].");
    
              }
    
        } else {
    
                LogLog.debug("Default initialization of overridden by " +  DEFAULT_INIT_OVERRIDE_KEY + "property."); 
    
        }  
    
    } 
    

    源码流程解析:

    1.初始化Logger容器Hierarchy,设置根节点为RootLogger

    2.初始LoggerRepositorySelector(容器选择器)为默认的DefaultRepositorySelector,容器为Hierarchy

    3.读取系统属性log4j.defaultInitOverride,如果没有设置或者为false进行初始化,否则跳过初始化

    4.读取系统属性log4j.configuration(log4j文件路径配置),如果存在对应的文件,则得到URL.如果没有对应的文件,首先检查是否存在log4j.xml文件,如果存在,得到Log4j配置文件URL,如果不存在log4j.xml,继续检查是否存在log4j.properties文件,如果存在该文件,得到log4j配置文件的URL,否则提示没有发现配置文件。

    5.读取系统属性log4j.configuratorClass(自定义Configurator配置类全路径,一般不自定义)

    6.调用OptionConverter.selectAndConfigure(url, configuratorClassName,LogManager.getLoggerRepository()),初始化logger容器

    1.2 OptionConverter探究

    OptionConverter获取Configurator实现类(配置类)

    源码:

    
    //利用给定URL配置Logger容器
    
    static  public void selectAndConfigure(URL url, String clazz, LoggerRepository hierarchy) { 
    
        Configurator configurator = null; 
    
        String filename = url.getFile(); 
    
        //优先检查使用xml文件,并查看是否有自定义的configurator
    
        if(clazz == null && filename != null && filename.endsWith(".xml")) { 
    
            clazz = "org.apache.log4j.xml.DOMConfigurator"; 
    
        } 
    
       if(clazz != null) { 
    
            LogLog.debug("Preferred configurator class: " + clazz); 
    
            configurator = (Configurator) instantiateByClassName(clazz, Configurator.class, null); 
    
            if(configurator == null) { 
    
                LogLog.error("Could not instantiate configurator ["+clazz+"]."); 
    
                return; 
    
            } 
    
        } else { 
    
            configurator = new PropertyConfigurator(); 
    
        } 
    
        configurator.doConfigure(url, hierarchy);
    
    }
    
    

    源码流程解析:

    1.如果没有自定义配置类Configurator并且文件的后缀名是xml.配置类设置为org.apache.log4j.xml.DOMConfigurator

    2.如果自定义了配置类,根据配置类的全限定名,发射得到配置类实例

    3.上面两种情况都没有匹配成功,默认是PropertyConfigurator配置类

    4.调用configurator.doConfigure(url,hierarchy),根据配置文件URL,配置logger容器Hierarchy(已经静态化构造了简单的容器,RootLogger是根节点)

    1.3 Configurator探究(以ProptertyConfigurator为例)

    Configurator读取配置文件内容,配置Logger容器

    1.3.1 doConfigure(URL,LoggerRepository)

    源码:

    
    //从URL中读取配置文件,配置Logger容器Hierarchy
    
    publicvoid doConfigure(java.net.URL configURL, LoggerRepository hierarchy) { 
    
        Properties props = new Properties(); 
    
        LogLog.debug("Reading configuration from URL " + configURL); 
    
        InputStream istream = null; 
    
        URLConnection uConn = null; 
    
        try { 
    
            uConn = configURL.openConnection(); 
    
            uConn.setUseCaches(false); 
    
            istream = uConn.getInputStream(); 
    
            props.load(istream); 
    
        } catch (Exception e) { 
    
            if (e instanceof InterruptedIOException || e instanceof InterruptedException) { 
    
                 Thread.currentThread().interrupt(); 
    
            } 
    
            LogLog.error("Could not read configuration file from URL [" + configURL + "].", e); 
    
            LogLog.error("Ignoring configuration file [" + configURL +"]."); 
    
            return; 
    
        } finally { 
    
            if (istream != null) { 
    
                try { 
    
                    istream.close(); 
    
                } catch(InterruptedIOException ignore) { 
    
                    Thread.currentThread().interrupt(); 
    
                } catch(IOException ignore) { 
    
                } catch(RuntimeException ignore) { 
    
                } 
    
            } 
    
        } 
    
        doConfigure(props, hierarchy);
    
    }
    
    

    源码流程解析:

    1.文件URL读取文件内容,赋值给Properties

    2.调用doConfigure(properties,hierarchy)配置logger容器

    1.3.2 doConfigure(Properties , LoggerRepository)

    源码:

    
    public void doConfigure(Properties properties, LoggerRepository hierarchy) {
    
        repository = hierarchy; 
    
        String value = properties.getProperty(LogLog.DEBUG_KEY); 
    
        if(value == null) { 
    
            value = properties.getProperty("log4j.configDebug"); 
    
            if(value != null)
    
                LogLog.warn("[log4j.configDebug] is deprecated. Use [log4j.debug] instead."); 
    
         } 
    
        if(value != null) { 
    
            LogLog.setInternalDebugging(OptionConverter.toBoolean(value, true)); 
    
        } 
    
        // if log4j.reset=true then 
    
        // reset hierarchy 
    
        String reset = properties.getProperty(RESET_KEY); 
    
        if (reset != null && OptionConverter.toBoolean(reset, false)) { 
    
            hierarchy.resetConfiguration(); 
    
        } 
    
        String thresholdStr = OptionConverter.findAndSubst(THRESHOLD_PREFIX, properties); 
    
        if(thresholdStr != null) { 
    
            hierarchy.setThreshold(OptionConverter.toLevel(thresholdStr, (Level) Level.ALL)); 
    
            LogLog.debug("Hierarchy threshold set to ["+hierarchy.getThreshold()+"]."); 
    
        }  
    
        configureRootCategory(properties, hierarchy); 
    
        configureLoggerFactory(properties); 
    
        parseCatsAndRenderers(properties, hierarchy); 
    
        LogLog.debug("Finished configuring."); 
    
        // We don't want to hold references to appenders preventing their 
    
        // garbage collection. 
    
        registry.clear(); 
    
    }
    
    void configureRootCategory(Properties props, LoggerRepository hierarchy) {
    
        String effectiveFrefix = ROOT_LOGGER_PREFIX;
    
        String value = OptionConverter.findAndSubst(ROOT_LOGGER_PREFIX, props);
    
        if(value == null) {
    
          value = OptionConverter.findAndSubst(ROOT_CATEGORY_PREFIX, props);
    
          effectiveFrefix = ROOT_CATEGORY_PREFIX;
    
        }
    
        if(value == null)
    
          LogLog.debug("Could not find root logger information. Is this OK?");
    
        else {
    
          Logger root = hierarchy.getRootLogger();
    
          synchronized(root) {
    
            parseCategory(props, root, effectiveFrefix, INTERNAL_ROOT_NAME, value);
    
          }
    
        }
    
      }
    
    protected void configureLoggerFactory(Properties props) {
    
        String factoryClassName = OptionConverter.findAndSubst(LOGGER_FACTORY_KEY,props);
    
        if(factoryClassName != null) {
    
          LogLog.debug("Setting category factory to ["+factoryClassName+"].");
    
          loggerFactory = (LoggerFactory)OptionConverter.instantiateByClassName(factoryClassName,LoggerFactory.class,loggerFactory);
    
          PropertySetter.setProperties(loggerFactory, props, FACTORY_PREFIX + ".");
    
        }
    
      }
    
    protected void parseCatsAndRenderers(Properties props, LoggerRepository hierarchy) { 
    
        Enumeration enumeration = props.propertyNames(); 
    
        while(enumeration.hasMoreElements()) { 
    
            String key = (String) enumeration.nextElement(); 
    
            if(key.startsWith(CATEGORY_PREFIX) || key.startsWith(LOGGER_PREFIX)) {
    
                String loggerName = null;
    
                if(key.startsWith(CATEGORY_PREFIX)) { 
    
                    loggerName = key.substring(CATEGORY_PREFIX.length());
    
                } else if(key.startsWith(LOGGER_PREFIX)) { 
    
                    loggerName = key.substring(LOGGER_PREFIX.length());
    
                }
    
                String value = OptionConverter.findAndSubst(key, props);
    
                Logger logger = hierarchy.getLogger(loggerName, loggerFactory);
    
                synchronized(logger) { 
    
                    parseCategory(props, logger, key, loggerName, value); 
    
                    parseAdditivityForLogger(props, logger, loggerName);
    
                } 
    
            } else if(key.startsWith(RENDERER_PREFIX)) {
    
                String renderedClass = key.substring(RENDERER_PREFIX.length());
    
                String renderingClass = OptionConverter.findAndSubst(key, props);
    
                if(hierarchy instanceof RendererSupport) { 
    
                    RendererMap.addRenderer((RendererSupport) hierarchy, renderedClass, renderingClass);
    
                } 
    
            } else if (key.equals(THROWABLE_RENDERER_PREFIX)) { 
    
                if (hierarchy instanceof ThrowableRendererSupport) { 
    
                    ThrowableRenderer tr = (ThrowableRenderer) OptionConverter.instantiateByKey(props, THROWABLE_RENDERER_PREFIX, org.apache.log4j.spi.ThrowableRenderer.class, null); 
    
                    if(tr == null) { 
    
                        LogLog.error( "Could not instantiate throwableRenderer."); 
    
                    } else { 
    
                        PropertySetter setter = new PropertySetter(tr); 
    
                        setter.setProperties(props, THROWABLE_RENDERER_PREFIX + "."); 
    
                        ((ThrowableRendererSupport) hierarchy).setThrowableRenderer(tr); 
    
                    } 
    
                } 
    
            } 
    
        } 
    
    }
    
    

    源码流程解析:

    1.获取log4j.debug(log4j内部是否debug打印日志),如果为ture打印,false不打印。如果没有设置,尝试读取log4j.configdebug(已经废弃,用logdebug取代)

    2.读取log4j.reset,如果设置为true,重置logger容器

    3.读取log4j.threshold,设置logger容器总阀值,低于阀值将不打印日志。如果没有配置,默认设置为最低级别Level.ALL

    4.调用configureRootCategory\(Properties, LoggerRepository\),配置RootLogger.RootLogger级别不能设置为空或者inherit.解析设置RootLogger的Appenders和Filters.

    5.调用configureLoggerFactory(Properties props),配置Logger工厂类LoggerFactory.

    6.调用parseCatsAndRenderers(Properties, LoggerRepository),配置Logger以及Renderer

    2 Web应用

    最常用的就是与Spring集成,这里主要将和Spring集成以及启动流程.其实web应用初始化log4j流程就是,容器启动的时候,首先找到Log4j配置文件,然后调用log4j API进行log4j初始化配置(同上)

    2.1 搭建web环境

    第一步:加入依赖

    
      <properties>
    
        <spring.version>4.2.4.RELEASE</spring.version>
    
        <log4j.version>1.2.17</log4j.version>
    
      </properties>
    
      <dependencies>
    
        <dependency>
    
          <groupId>junit</groupId>
    
          <artifactId>junit</artifactId>
    
          <version>4.4</version>
    
          <scope>test</scope>
    
        </dependency>
    
        <dependency>
    
          <groupId>javax.servlet</groupId>
    
          <artifactId>servlet-api</artifactId>
    
          <version>2.5</version>
    
          <scope>provided</scope>
    
        </dependency>
    
        <dependency>
    
          <groupId>javax.servlet</groupId>
    
          <artifactId>jsp-api</artifactId>
    
          <version>2.0</version>
    
          <scope>provided</scope>
    
        </dependency>
    
        <dependency>
    
          <groupId>org.springframework</groupId>
    
          <artifactId>spring-webmvc</artifactId>
    
          <version>${spring.version}</version>
    
        </dependency>
    
        <!--  Log4j1 日志框架包  -->
    
        <dependency>
    
          <groupId>log4j</groupId>
    
          <artifactId>log4j</artifactId>
    
          <version>${log4j.version}</version>
    
        </dependency>
    
      </dependencies>
    
    

    第二步:在web.xml中加入Log4jConfigListener

    
       <listener>
    
            <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
    
        </listener>
    
    

    第三步:在resources文件夹下加入log4j.xml或者log4j.properties

    
    ### 设置###
    
    log4j.rootLogger = debug,stdout,D,E
    
    log4j.threshold= debug
    
    ## log4j内部是否debug
    
    log4j.debug= false
    
    ### 配置自己的log工厂类
    
    log4j.loggerFactory=com.log.log4j.configure.MyLoggerFactory
    
    ### 输出信息到控制抬 ###
    
    log4j.appender.stdout = org.apache.log4j.ConsoleAppender
    
    log4j.appender.stdout.Target = System.out
    
    log4j.appender.stdout.Threshold = warn
    
    log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
    
    log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
    
    ### 输出DEBUG 级别以上的日志到=/data/applogs/log/logtopic/app.log ###
    
    log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
    
    log4j.appender.D.File = /data/applogs/log/logtopic/app.log
    
    log4j.appender.D.Append = true
    
    log4j.appender.D.Threshold = DEBUG
    
    log4j.appender.D.layout = org.apache.log4j.PatternLayout
    
    log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
    
    ### 输出ERROR 级别以上的日志到=/data/applogs/log/log4jLearning/error.log ###
    
    log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
    
    log4j.appender.E.File =/data/applogs/log/logtopic/error.log
    
    log4j.appender.E.Append = true
    
    log4j.appender.E.Threshold = ERROR
    
    log4j.appender.E.layout = org.apache.log4j.PatternLayout
    
    log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
    
    

    第四步:编写ServletDemo并配置

    ServletDemo代码:

    
    public class Log4jServletDemo extends HttpServlet {
    
        public static final Logger LOGGER = Logger.getLogger(Log4jServletDemo.class);
    
        @Override
    
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
            service(req, resp);
    
        }
    
        @Override
    
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
    
            service(req, resp);
    
        }
    
        @Override
    
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
    
            LOGGER.debug("Log4jServletDemo Info Level");
    
            LOGGER.info("Log4jServletDemo Info Level");
    
            LOGGER.warn("Log4jServletDemo Info Level");
    
            LOGGER.error("Log4jServletDemo Info Level");
    
            req.getRequestDispatcher("/index.jsp").forward(req, resp);
    
        }
    
    }
    
    

    web.xml中配置:

    
        <servlet>
    
            <servlet-name>servletDemo</servlet-name>
    
            <servlet-class>com.log.log4j.web.Log4jServletDemo</servlet-class>
    
        </servlet>
    
        <servlet-mapping>
    
            <servlet-name>servletDemo</servlet-name>
    
            <url-pattern>/demo</url-pattern>
    
        </servlet-mapping>
    
    
    2.2 log4jweb初始化

    初始化时序图:

    初始化流程:

    1.tomcat容器加载Log4jConfigListener

    2.Log4jConfigListener把初始化Log4j的工作为委托给Log4jWebConfigurer

    3.Log4jWebConfigurer获取配置文件路径。然后再委托给Log4jConfigurer

    4.Log4jConfigurer调用Log4j框架的DomConfigurator.configure(url)或者PropertyConfigurator.configure(url)初始化配置Log4j,这样就走到了上面独立应用初始化Log4j的过程

    2.3 源码探究
    2.3.1 Log4jConfigListener

    源码:

    
    public class Log4jConfigListener implements ServletContextListener { 
    
        @Override 
    
        public void contextInitialized(ServletContextEvent event) {
    
            Log4jWebConfigurer.initLogging(event.getServletContext()); 
    
        } 
    
        @Override 
    
        public void contextDestroyed(ServletContextEvent event) {    
    
           Log4jWebConfigurer.shutdownLogging(event.getServletContext()); 
    
        }
    
    }
    
    

    源码流程解析:

    1.调用contextInitialized(ServletContextEvent)初始化Log4j

    2.委托给Log4jWebConfigurer初始化Log4j

    2.3.2 Log4jWebConfigurer

    源码:

    
    public static void initLogging(ServletContext servletContext) { 
    
        // 首先检查是否暴露系统属性,默认是暴露
    
        if (exposeWebAppRoot(servletContext)) { 
    
            WebUtils.setWebAppRootSystemProperty(servletContext); 
    
        } 
    
        //得到自定义的log4j配置文件位置
    
        String location = servletContext.getInitParameter(CONFIG_LOCATION_PARAM); 
    
        if (location != null) { 
    
            // 主要是获取log4j配置文件的真实路径
    
            try { 
    
                // Resolve property placeholders before potentially resolving a real path. 
    
                location = ServletContextPropertyUtils.resolvePlaceholders(location, servletContext);
    
                // 判断是否是资源路径,以classpath:" or "file:"开头 
    
                if (!ResourceUtils.isUrl(location)) { 
    
                    // 获取配置文件的真实路径
    
                    location = WebUtils.getRealPath(servletContext, location); } 
    
                    // Write log message to server log. 
    
                    servletContext.log("Initializing log4j from [" + location + "]"); 
    
                    // 读取 log4jRefreshInterval 属性
    
                    String intervalString = servletContext.getInitParameter(REFRESH_INTERVAL_PARAM); 
    
                    if (StringUtils.hasText(intervalString)) { 
    
                        try { 
    
                            long refreshInterval = Long.parseLong(intervalString); 
    
                            //配置log4j并启动一个监控线程
    
                            org.springframework.util.Log4jConfigurer.initLogging(location, refreshInterval); 
    
                        } catch (NumberFormatException ex) { 
    
                            throw new IllegalArgumentException("Invalid 'log4jRefreshInterval' parameter: " + ex.getMessage());   } 
    
                    } else { 
    
                        //配置log4j
    
                        org.springframework.util.Log4jConfigurer.initLogging(location); 
    
                    } 
    
            } catch (FileNotFoundException ex) { 
    
                throw new IllegalArgumentException("Invalid 'log4jConfigLocation' parameter: " + ex.getMessage()); 
    
            } 
    
        }
    
    }
    
    //设置WebAppRoot属性
    
    public static void setWebAppRootSystemProperty(ServletContext servletContext) throws IllegalStateException {
    
           Assert.notNull(servletContext, "ServletContext must not be null"); 
    
           String root = servletContext.getRealPath("/"); 
    
           if (root == null) { 
    
                throw new IllegalStateException( "Cannot set web app root system property when WAR file is not expanded"); 
    
            } 
    
           String param = servletContext.getInitParameter(WEB_APP_ROOT_KEY_PARAM); 
    
           String key = (param != null ? param : DEFAULT_WEB_APP_ROOT_KEY); 
    
           String oldValue = System.getProperty(key); 
    
           if (oldValue != null && !StringUtils.pathEquals(oldValue, root)) { 
    
                throw new IllegalStateException( "Web app root system property already set to different value: '" + key + "' = [" + oldValue + "] instead of [" + root + "] - " + "Choose unique values for the 'webAppRootKey' context-param in your web.xml files!"); 
    
            } 
    
           System.setProperty(key, root); 
    
           servletContext.log("Set web app root system property: '" + key + "' = [" + root + "]");
    
    }
    
    

    源码流程解析

    1.exposeWebAppRoot判断是否暴露WebAppRoot,默认是暴露.可以自定义,如下配置

    
        <context-param> 
    
            <param-name>log4jExposeWebAppRoot</param-name> 
    
            <param-value>true</param-value>
    
        </context-param>
    
    

    2.如果暴露,将设置系统属性为 webapp.root = servletContext.getRealPath("/")(项目部署根路径),也可以自定义webAppRootKey,如下

    
        <context-param>
    
            <param-name>webAppRootKey</param-name>
    
            <param-value>logtopic.root</param-value>
    
        </context-param>
    
    

    这样就会设置系统属性 logtopic.root = servletContext.getRealPath("/"),再配置文件中就可以用${logtopic.root}代替部署根路径

    3.String location = servletContext.getInitParameter(CONFIG_LOCATION_PARAM)获取Log4j自定义配置路径,如果不为空解析得到真实路径location = WebUtils.getRealPath(servletContext, location)如下配置

    
    <context-param> 
    
        <param-name>log4jConfigLocation</param-name> 
    
        <param-value>classpath:log4j.properties</param-value>
    
    </context-param>
    
    

    配置有两种情况

    - `classpath`开头,找到项目类路径,最后用ClassLoader加载,所以不要用"/"开头
    
    
    <context-param>
    
     <param-name>log4jConfigLocation</param-name>
    
     <param-value>classpath:log4j.properties</param-value>
    
    </context-param>
    
    
    • file开头,配置文件具体位置
    
    <context-param> 
    
        <param-name>log4jConfigLocation</param-name> 
    
        <param-value>file:///Users/lh/Desktop/log4j.properties</param-value>
    
    </context-param>
    
    

    4.读取log4jRefreshInterval属性,表示每隔一段时间,会重新读取配置文件,重新配置Log4j,自动检测更新。会单独启动一个线程来监控定时监控,单位是(ms).配置如下:

    
    <context-param> 
    
        <param-name>log4jRefreshInterval</param-name> 
    
        <param-value>2000</param-value>
    
    </context-param>
    
    

    5.最后调用log4j自身的API进行配置

    
    if (resolvedLocation.toLowerCase().endsWith(XML_FILE_EXTENSION)) { 
    
        DOMConfigurator.configure(url);
    
    }else { 
    
        PropertyConfigurator.configure(url);
    
    }
    
    
  • 相关阅读:
    字符设备驱动——申请设备号、注册字符设备
    Linux设备驱动——简单的字符驱动
    Linux驱动入门——构建和运行模块
    Ubuntu12.04下samba服务器共享配置
    python get() 和getattr()
    flask 发送QQ邮箱
    Flask之flask_script
    Flask 知识点
    Flask 项目结构(仅供参考)
    python虚拟环境迁移
  • 原文地址:https://www.cnblogs.com/beginmind/p/5989036.html
Copyright © 2011-2022 走看看