Home » apache-log4j-1.2.15 » org.apache » log4j » [javadoc | source]
    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    * 
    9    *      http://www.apache.org/licenses/LICENSE-2.0
   10    * 
   11    * Unless required by applicable law or agreed to in writing, software
   12    * distributed under the License is distributed on an "AS IS" BASIS,
   13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    * See the License for the specific language governing permissions and
   15    * limitations under the License.
   16    */
   17   
   18   
   19   // Contibutors: "Luke Blanshard" <Luke@quiq.com>
   20   //              "Mark DONSZELMANN" <Mark.Donszelmann@cern.ch>
   21   //               Anders Kristensen <akristensen@dynamicsoft.com>
   22   
   23   package org.apache.log4j;
   24   
   25   import org.apache.log4j.config.PropertySetter;
   26   import org.apache.log4j.helpers.FileWatchdog;
   27   import org.apache.log4j.helpers.LogLog;
   28   import org.apache.log4j.helpers.OptionConverter;
   29   import org.apache.log4j.or.RendererMap;
   30   import org.apache.log4j.spi.Configurator;
   31   import org.apache.log4j.spi.LoggerFactory;
   32   import org.apache.log4j.spi.LoggerRepository;
   33   import org.apache.log4j.spi.OptionHandler;
   34   import org.apache.log4j.spi.RendererSupport;
   35   
   36   import java.io.FileInputStream;
   37   import java.io.InputStream;
   38   import java.util.Enumeration;
   39   import java.util.Hashtable;
   40   import java.util.Properties;
   41   import java.util.StringTokenizer;
   42   
   43   /**
   44      Allows the configuration of log4j from an external file.  See
   45      <b>{@link #doConfigure(String, LoggerRepository)}</b> for the
   46      expected format.
   47   
   48      <p>It is sometimes useful to see how log4j is reading configuration
   49      files. You can enable log4j internal logging by defining the
   50      <b>log4j.debug</b> variable.
   51   
   52      <P>As of log4j version 0.8.5, at class initialization time class,
   53      the file <b>log4j.properties</b> will be searched from the search
   54      path used to load classes. If the file can be found, then it will
   55      be fed to the {@link PropertyConfigurator#configure(java.net.URL)}
   56      method.
   57   
   58      <p>The <code>PropertyConfigurator</code> does not handle the
   59      advanced configuration features supported by the {@link
   60      org.apache.log4j.xml.DOMConfigurator DOMConfigurator} such as
   61      support for {@link org.apache.log4j.spi.Filter Filters}, custom
   62      {@link org.apache.log4j.spi.ErrorHandler ErrorHandlers}, nested
   63      appenders such as the {@link org.apache.log4j.AsyncAppender
   64      AsyncAppender}, etc.
   65   
   66      <p>All option <em>values</em> admit variable substitution. The
   67      syntax of variable substitution is similar to that of Unix
   68      shells. The string between an opening <b>&quot;${&quot;</b> and
   69      closing <b>&quot;}&quot;</b> is interpreted as a key. The value of
   70      the substituted variable can be defined as a system property or in
   71      the configuration file itself. The value of the key is first
   72      searched in the system properties, and if not found there, it is
   73      then searched in the configuration file being parsed.  The
   74      corresponding value replaces the ${variableName} sequence. For
   75      example, if <code>java.home</code> system property is set to
   76      <code>/home/xyz</code>, then every occurrence of the sequence
   77      <code>${java.home}</code> will be interpreted as
   78      <code>/home/xyz</code>.
   79   
   80   
   81      @author Ceki G&uuml;lc&uuml;
   82      @author Anders Kristensen
   83      @since 0.8.1 */
   84   public class PropertyConfigurator implements Configurator {
   85   
   86     /**
   87        Used internally to keep track of configured appenders.
   88      */
   89     protected Hashtable registry = new Hashtable(11);
   90     protected LoggerFactory loggerFactory = new DefaultCategoryFactory();
   91   
   92     static final String      CATEGORY_PREFIX = "log4j.category.";
   93     static final String      LOGGER_PREFIX   = "log4j.logger.";
   94     static final String       FACTORY_PREFIX = "log4j.factory";
   95     static final String    ADDITIVITY_PREFIX = "log4j.additivity.";
   96     static final String ROOT_CATEGORY_PREFIX = "log4j.rootCategory";
   97     static final String ROOT_LOGGER_PREFIX   = "log4j.rootLogger";
   98     static final String      APPENDER_PREFIX = "log4j.appender.";
   99     static final String      RENDERER_PREFIX = "log4j.renderer.";
  100     static final String      THRESHOLD_PREFIX = "log4j.threshold";
  101   
  102     /** Key for specifying the {@link org.apache.log4j.spi.LoggerFactory
  103         LoggerFactory}.  Currently set to "<code>log4j.loggerFactory</code>".  */
  104     public static final String LOGGER_FACTORY_KEY = "log4j.loggerFactory";
  105   
  106       /**
  107        * If property set to true, then hierarchy will be reset before configuration.
  108        */
  109     private static final String RESET_KEY = "log4j.reset";
  110   
  111     static final private String INTERNAL_ROOT_NAME = "root";
  112   
  113     /**
  114       Read configuration from a file. <b>The existing configuration is
  115       not cleared nor reset.</b> If you require a different behavior,
  116       then call {@link  LogManager#resetConfiguration
  117       resetConfiguration} method before calling
  118       <code>doConfigure</code>.
  119   
  120       <p>The configuration file consists of statements in the format
  121       <code>key=value</code>. The syntax of different configuration
  122       elements are discussed below.
  123   
  124       <h3>Repository-wide threshold</h3>
  125   
  126       <p>The repository-wide threshold filters logging requests by level
  127       regardless of logger. The syntax is:
  128   
  129       <pre>
  130       log4j.threshold=[level]
  131       </pre>
  132   
  133       <p>The level value can consist of the string values OFF, FATAL,
  134       ERROR, WARN, INFO, DEBUG, ALL or a <em>custom level</em> value. A
  135       custom level value can be specified in the form
  136       level#classname. By default the repository-wide threshold is set
  137       to the lowest possible value, namely the level <code>ALL</code>.
  138       </p>
  139   
  140   
  141       <h3>Appender configuration</h3>
  142   
  143       <p>Appender configuration syntax is:
  144       <pre>
  145       # For appender named <i>appenderName</i>, set its class.
  146       # Note: The appender name can contain dots.
  147       log4j.appender.appenderName=fully.qualified.name.of.appender.class
  148   
  149       # Set appender specific options.
  150       log4j.appender.appenderName.option1=value1
  151       ...
  152       log4j.appender.appenderName.optionN=valueN
  153       </pre>
  154   
  155       For each named appender you can configure its {@link Layout}. The
  156       syntax for configuring an appender's layout is:
  157       <pre>
  158       log4j.appender.appenderName.layout=fully.qualified.name.of.layout.class
  159       log4j.appender.appenderName.layout.option1=value1
  160       ....
  161       log4j.appender.appenderName.layout.optionN=valueN
  162       </pre>
  163   
  164       <h3>Configuring loggers</h3>
  165   
  166       <p>The syntax for configuring the root logger is:
  167       <pre>
  168         log4j.rootLogger=[level], appenderName, appenderName, ...
  169       </pre>
  170   
  171       <p>This syntax means that an optional <em>level</em> can be
  172       supplied followed by appender names separated by commas.
  173   
  174       <p>The level value can consist of the string values OFF, FATAL,
  175       ERROR, WARN, INFO, DEBUG, ALL or a <em>custom level</em> value. A
  176       custom level value can be specified in the form
  177       <code>level#classname</code>.
  178   
  179       <p>If a level value is specified, then the root level is set
  180       to the corresponding level.  If no level value is specified,
  181       then the root level remains untouched.
  182   
  183       <p>The root logger can be assigned multiple appenders.
  184   
  185       <p>Each <i>appenderName</i> (separated by commas) will be added to
  186       the root logger. The named appender is defined using the
  187       appender syntax defined above.
  188   
  189       <p>For non-root categories the syntax is almost the same:
  190       <pre>
  191       log4j.logger.logger_name=[level|INHERITED|NULL], appenderName, appenderName, ...
  192       </pre>
  193   
  194       <p>The meaning of the optional level value is discussed above
  195       in relation to the root logger. In addition however, the value
  196       INHERITED can be specified meaning that the named logger should
  197       inherit its level from the logger hierarchy.
  198   
  199       <p>If no level value is supplied, then the level of the
  200       named logger remains untouched.
  201   
  202       <p>By default categories inherit their level from the
  203       hierarchy. However, if you set the level of a logger and later
  204       decide that that logger should inherit its level, then you should
  205       specify INHERITED as the value for the level value. NULL is a
  206       synonym for INHERITED.
  207   
  208       <p>Similar to the root logger syntax, each <i>appenderName</i>
  209       (separated by commas) will be attached to the named logger.
  210   
  211       <p>See the <a href="../../../../manual.html#additivity">appender
  212       additivity rule</a> in the user manual for the meaning of the
  213       <code>additivity</code> flag.
  214   
  215       <h3>ObjectRenderers</h3>
  216   
  217       You can customize the way message objects of a given type are
  218       converted to String before being logged. This is done by
  219       specifying an {@link org.apache.log4j.or.ObjectRenderer ObjectRenderer}
  220       for the object type would like to customize.
  221   
  222       <p>The syntax is:
  223   
  224       <pre>
  225       log4j.renderer.fully.qualified.name.of.rendered.class=fully.qualified.name.of.rendering.class
  226       </pre>
  227   
  228       As in,
  229       <pre>
  230       log4j.renderer.my.Fruit=my.FruitRenderer
  231       </pre>
  232   
  233       <h3>Logger Factories</h3>
  234   
  235       The usage of custom logger factories is discouraged and no longer
  236       documented.
  237   
  238       <h3>Resetting Hierarchy</h3>
  239   
  240       The hierarchy will be reset before configuration when
  241       log4j.reset=true is present in the properties file.
  242   
  243       <h3>Example</h3>
  244   
  245       <p>An example configuration is given below. Other configuration
  246       file examples are given in the <code>examples</code> folder.
  247   
  248       <pre>
  249   
  250       # Set options for appender named "A1".
  251       # Appender "A1" will be a SyslogAppender
  252       log4j.appender.A1=org.apache.log4j.net.SyslogAppender
  253   
  254       # The syslog daemon resides on www.abc.net
  255       log4j.appender.A1.SyslogHost=www.abc.net
  256   
  257       # A1's layout is a PatternLayout, using the conversion pattern
  258       # <b>%r %-5p %c{2} %M.%L %x - %m\n</b>. Thus, the log output will
  259       # include # the relative time since the start of the application in
  260       # milliseconds, followed by the level of the log request,
  261       # followed by the two rightmost components of the logger name,
  262       # followed by the callers method name, followed by the line number,
  263       # the nested disgnostic context and finally the message itself.
  264       # Refer to the documentation of {@link PatternLayout} for further information
  265       # on the syntax of the ConversionPattern key.
  266       log4j.appender.A1.layout=org.apache.log4j.PatternLayout
  267       log4j.appender.A1.layout.ConversionPattern=%-4r %-5p %c{2} %M.%L %x - %m\n
  268   
  269       # Set options for appender named "A2"
  270       # A2 should be a RollingFileAppender, with maximum file size of 10 MB
  271       # using at most one backup file. A2's layout is TTCC, using the
  272       # ISO8061 date format with context printing enabled.
  273       log4j.appender.A2=org.apache.log4j.RollingFileAppender
  274       log4j.appender.A2.MaxFileSize=10MB
  275       log4j.appender.A2.MaxBackupIndex=1
  276       log4j.appender.A2.layout=org.apache.log4j.TTCCLayout
  277       log4j.appender.A2.layout.ContextPrinting=enabled
  278       log4j.appender.A2.layout.DateFormat=ISO8601
  279   
  280       # Root logger set to DEBUG using the A2 appender defined above.
  281       log4j.rootLogger=DEBUG, A2
  282   
  283       # Logger definitions:
  284       # The SECURITY logger inherits is level from root. However, it's output
  285       # will go to A1 appender defined above. It's additivity is non-cumulative.
  286       log4j.logger.SECURITY=INHERIT, A1
  287       log4j.additivity.SECURITY=false
  288   
  289       # Only warnings or above will be logged for the logger "SECURITY.access".
  290       # Output will go to A1.
  291       log4j.logger.SECURITY.access=WARN
  292   
  293   
  294       # The logger "class.of.the.day" inherits its level from the
  295       # logger hierarchy.  Output will go to the appender's of the root
  296       # logger, A2 in this case.
  297       log4j.logger.class.of.the.day=INHERIT
  298       </pre>
  299   
  300       <p>Refer to the <b>setOption</b> method in each Appender and
  301       Layout for class specific options.
  302   
  303       <p>Use the <code>#</code> or <code>!</code> characters at the
  304       beginning of a line for comments.
  305   
  306      <p>
  307      @param configFileName The name of the configuration file where the
  308      configuration information is stored.
  309   
  310     */
  311     public
  312     void doConfigure(String configFileName, LoggerRepository hierarchy) {
  313       Properties props = new Properties();
  314       FileInputStream istream = null;
  315       try {
  316         istream = new FileInputStream(configFileName);
  317         props.load(istream);
  318         istream.close();
  319       }
  320       catch (Exception e) {
  321         LogLog.error("Could not read configuration file ["+configFileName+"].", e);
  322         LogLog.error("Ignoring configuration file [" + configFileName+"].");
  323         return;
  324       } finally {
  325           if(istream != null) {
  326               try {
  327                   istream.close();
  328               } catch(Throwable ignore) {
  329               }
  330   
  331           }
  332       }
  333       // If we reach here, then the config file is alright.
  334       doConfigure(props, hierarchy);
  335     }
  336   
  337     /**
  338      */
  339     static
  340     public
  341     void configure(String configFilename) {
  342       new PropertyConfigurator().doConfigure(configFilename,
  343   					   LogManager.getLoggerRepository());
  344     }
  345   
  346     /**
  347        Read configuration options from url <code>configURL</code>.
  348   
  349        @since 0.8.2
  350      */
  351     public
  352     static
  353     void configure(java.net.URL configURL) {
  354       new PropertyConfigurator().doConfigure(configURL,
  355   					   LogManager.getLoggerRepository());
  356     }
  357   
  358   
  359     /**
  360        Read configuration options from <code>properties</code>.
  361   
  362        See {@link #doConfigure(String, LoggerRepository)} for the expected format.
  363     */
  364     static
  365     public
  366     void configure(Properties properties) {
  367       new PropertyConfigurator().doConfigure(properties,
  368   					   LogManager.getLoggerRepository());
  369     }
  370   
  371     /**
  372        Like {@link #configureAndWatch(String, long)} except that the
  373        default delay as defined by {@link FileWatchdog#DEFAULT_DELAY} is
  374        used.
  375   
  376        @param configFilename A file in key=value format.
  377   
  378     */
  379     static
  380     public
  381     void configureAndWatch(String configFilename) {
  382       configureAndWatch(configFilename, FileWatchdog.DEFAULT_DELAY);
  383     }
  384   
  385   
  386     /**
  387        Read the configuration file <code>configFilename</code> if it
  388        exists. Moreover, a thread will be created that will periodically
  389        check if <code>configFilename</code> has been created or
  390        modified. The period is determined by the <code>delay</code>
  391        argument. If a change or file creation is detected, then
  392        <code>configFilename</code> is read to configure log4j.
  393   
  394         @param configFilename A file in key=value format.
  395         @param delay The delay in milliseconds to wait between each check.
  396     */
  397     static
  398     public
  399     void configureAndWatch(String configFilename, long delay) {
  400       PropertyWatchdog pdog = new PropertyWatchdog(configFilename);
  401       pdog.setDelay(delay);
  402       pdog.start();
  403     }
  404   
  405   
  406     /**
  407        Read configuration options from <code>properties</code>.
  408   
  409        See {@link #doConfigure(String, LoggerRepository)} for the expected format.
  410     */
  411     public
  412     void doConfigure(Properties properties, LoggerRepository hierarchy) {
  413       String value = properties.getProperty(LogLog.DEBUG_KEY);
  414       if(value == null) {
  415         value = properties.getProperty("log4j.configDebug");
  416         if(value != null)
  417   	LogLog.warn("[log4j.configDebug] is deprecated. Use [log4j.debug] instead.");
  418       }
  419   
  420       if(value != null) {
  421         LogLog.setInternalDebugging(OptionConverter.toBoolean(value, true));
  422       }
  423   
  424         //
  425         //   if log4j.reset=true then
  426         //        reset hierarchy
  427       String reset = properties.getProperty(RESET_KEY);
  428       if (reset != null && OptionConverter.toBoolean(reset, false)) {
  429             hierarchy.resetConfiguration();
  430       }
  431   
  432       String thresholdStr = OptionConverter.findAndSubst(THRESHOLD_PREFIX,
  433   						       properties);
  434       if(thresholdStr != null) {
  435         hierarchy.setThreshold(OptionConverter.toLevel(thresholdStr,
  436   						     (Level) Level.ALL));
  437         LogLog.debug("Hierarchy threshold set to ["+hierarchy.getThreshold()+"].");
  438       }
  439   
  440       configureRootCategory(properties, hierarchy);
  441       configureLoggerFactory(properties);
  442       parseCatsAndRenderers(properties, hierarchy);
  443   
  444       LogLog.debug("Finished configuring.");
  445       // We don't want to hold references to appenders preventing their
  446       // garbage collection.
  447       registry.clear();
  448     }
  449   
  450     /**
  451        Read configuration options from url <code>configURL</code>.
  452      */
  453     public
  454     void doConfigure(java.net.URL configURL, LoggerRepository hierarchy) {
  455       Properties props = new Properties();
  456       LogLog.debug("Reading configuration from URL " + configURL);
  457       InputStream istream = null;
  458       try {
  459         istream = configURL.openStream();
  460         props.load(istream);
  461       }
  462       catch (Exception e) {
  463         LogLog.error("Could not read configuration file from URL [" + configURL
  464   		   + "].", e);
  465         LogLog.error("Ignoring configuration file [" + configURL +"].");
  466         return;
  467       }
  468       finally {
  469           if (istream != null) {
  470               try {
  471                   istream.close();
  472               } catch(Exception ignore) {
  473               }
  474           }
  475       }
  476       doConfigure(props, hierarchy);
  477     }
  478   
  479   
  480     // --------------------------------------------------------------------------
  481     // Internal stuff
  482     // --------------------------------------------------------------------------
  483   
  484     /**
  485        Check the provided <code>Properties</code> object for a
  486        {@link org.apache.log4j.spi.LoggerFactory LoggerFactory}
  487        entry specified by {@link #LOGGER_FACTORY_KEY}.  If such an entry
  488        exists, an attempt is made to create an instance using the default
  489        constructor.  This instance is used for subsequent Category creations
  490        within this configurator.
  491   
  492        @see #parseCatsAndRenderers
  493      */
  494     protected void configureLoggerFactory(Properties props) {
  495       String factoryClassName = OptionConverter.findAndSubst(LOGGER_FACTORY_KEY,
  496   							   props);
  497       if(factoryClassName != null) {
  498         LogLog.debug("Setting category factory to ["+factoryClassName+"].");
  499         loggerFactory = (LoggerFactory)
  500   	          OptionConverter.instantiateByClassName(factoryClassName,
  501   							 LoggerFactory.class,
  502   							 loggerFactory);
  503         PropertySetter.setProperties(loggerFactory, props, FACTORY_PREFIX + ".");
  504       }
  505     }
  506   
  507     /*
  508     void configureOptionHandler(OptionHandler oh, String prefix,
  509   			      Properties props) {
  510       String[] options = oh.getOptionStrings();
  511       if(options == null)
  512         return;
  513   
  514       String value;
  515       for(int i = 0; i < options.length; i++) {
  516         value =  OptionConverter.findAndSubst(prefix + options[i], props);
  517         LogLog.debug(
  518            "Option " + options[i] + "=[" + (value == null? "N/A" : value)+"].");
  519         // Some option handlers assume that null value are not passed to them.
  520         // So don't remove this check
  521         if(value != null) {
  522   	oh.setOption(options[i], value);
  523         }
  524       }
  525       oh.activateOptions();
  526     }
  527     */
  528   
  529   
  530     void configureRootCategory(Properties props, LoggerRepository hierarchy) {
  531       String effectiveFrefix = ROOT_LOGGER_PREFIX;
  532       String value = OptionConverter.findAndSubst(ROOT_LOGGER_PREFIX, props);
  533   
  534       if(value == null) {
  535         value = OptionConverter.findAndSubst(ROOT_CATEGORY_PREFIX, props);
  536         effectiveFrefix = ROOT_CATEGORY_PREFIX;
  537       }
  538   
  539       if(value == null)
  540         LogLog.debug("Could not find root logger information. Is this OK?");
  541       else {
  542         Logger root = hierarchy.getRootLogger();
  543         synchronized(root) {
  544   	parseCategory(props, root, effectiveFrefix, INTERNAL_ROOT_NAME, value);
  545         }
  546       }
  547     }
  548   
  549   
  550     /**
  551        Parse non-root elements, such non-root categories and renderers.
  552     */
  553     protected
  554     void parseCatsAndRenderers(Properties props, LoggerRepository hierarchy) {
  555       Enumeration enumeration = props.propertyNames();
  556       while(enumeration.hasMoreElements()) {
  557         String key = (String) enumeration.nextElement();
  558         if(key.startsWith(CATEGORY_PREFIX) || key.startsWith(LOGGER_PREFIX)) {
  559   	String loggerName = null;
  560   	if(key.startsWith(CATEGORY_PREFIX)) {
  561   	  loggerName = key.substring(CATEGORY_PREFIX.length());
  562   	} else if(key.startsWith(LOGGER_PREFIX)) {
  563   	  loggerName = key.substring(LOGGER_PREFIX.length());
  564   	}
  565   	String value =  OptionConverter.findAndSubst(key, props);
  566   	Logger logger = hierarchy.getLogger(loggerName, loggerFactory);
  567   	synchronized(logger) {
  568   	  parseCategory(props, logger, key, loggerName, value);
  569   	  parseAdditivityForLogger(props, logger, loggerName);
  570   	}
  571         } else if(key.startsWith(RENDERER_PREFIX)) {
  572   	String renderedClass = key.substring(RENDERER_PREFIX.length());
  573   	String renderingClass = OptionConverter.findAndSubst(key, props);
  574   	if(hierarchy instanceof RendererSupport) {
  575   	  RendererMap.addRenderer((RendererSupport) hierarchy, renderedClass,
  576   				  renderingClass);
  577   	}
  578         }
  579       }
  580     }
  581   
  582     /**
  583        Parse the additivity option for a non-root category.
  584      */
  585     void parseAdditivityForLogger(Properties props, Logger cat,
  586   				  String loggerName) {
  587       String value = OptionConverter.findAndSubst(ADDITIVITY_PREFIX + loggerName,
  588   					     props);
  589       LogLog.debug("Handling "+ADDITIVITY_PREFIX + loggerName+"=["+value+"]");
  590       // touch additivity only if necessary
  591       if((value != null) && (!value.equals(""))) {
  592         boolean additivity = OptionConverter.toBoolean(value, true);
  593         LogLog.debug("Setting additivity for \""+loggerName+"\" to "+
  594   		   additivity);
  595         cat.setAdditivity(additivity);
  596       }
  597     }
  598   
  599     /**
  600        This method must work for the root category as well.
  601      */
  602     void parseCategory(Properties props, Logger logger, String optionKey,
  603   		     String loggerName, String value) {
  604   
  605       LogLog.debug("Parsing for [" +loggerName +"] with value=[" + value+"].");
  606       // We must skip over ',' but not white space
  607       StringTokenizer st = new StringTokenizer(value, ",");
  608   
  609       // If value is not in the form ", appender.." or "", then we should set
  610       // the level of the loggeregory.
  611   
  612       if(!(value.startsWith(",") || value.equals(""))) {
  613   
  614         // just to be on the safe side...
  615         if(!st.hasMoreTokens())
  616   	return;
  617   
  618         String levelStr = st.nextToken();
  619         LogLog.debug("Level token is [" + levelStr + "].");
  620   
  621         // If the level value is inherited, set category level value to
  622         // null. We also check that the user has not specified inherited for the
  623         // root category.
  624         if(INHERITED.equalsIgnoreCase(levelStr) || 
  625    	                                  NULL.equalsIgnoreCase(levelStr)) {
  626   	if(loggerName.equals(INTERNAL_ROOT_NAME)) {
  627   	  LogLog.warn("The root logger cannot be set to null.");
  628   	} else {
  629   	  logger.setLevel(null);
  630   	}
  631         } else {
  632   	logger.setLevel(OptionConverter.toLevel(levelStr, (Level) Level.DEBUG));
  633         }
  634         LogLog.debug("Category " + loggerName + " set to " + logger.getLevel());
  635       }
  636   
  637       // Begin by removing all existing appenders.
  638       logger.removeAllAppenders();
  639   
  640       Appender appender;
  641       String appenderName;
  642       while(st.hasMoreTokens()) {
  643         appenderName = st.nextToken().trim();
  644         if(appenderName == null || appenderName.equals(","))
  645   	continue;
  646         LogLog.debug("Parsing appender named \"" + appenderName +"\".");
  647         appender = parseAppender(props, appenderName);
  648         if(appender != null) {
  649   	logger.addAppender(appender);
  650         }
  651       }
  652     }
  653   
  654     Appender parseAppender(Properties props, String appenderName) {
  655       Appender appender = registryGet(appenderName);
  656       if((appender != null)) {
  657         LogLog.debug("Appender \"" + appenderName + "\" was already parsed.");
  658         return appender;
  659       }
  660       // Appender was not previously initialized.
  661       String prefix = APPENDER_PREFIX + appenderName;
  662       String layoutPrefix = prefix + ".layout";
  663   
  664       appender = (Appender) OptionConverter.instantiateByKey(props, prefix,
  665   					      org.apache.log4j.Appender.class,
  666   					      null);
  667       if(appender == null) {
  668         LogLog.error(
  669                 "Could not instantiate appender named \"" + appenderName+"\".");
  670         return null;
  671       }
  672       appender.setName(appenderName);
  673   
  674       if(appender instanceof OptionHandler) {
  675         if(appender.requiresLayout()) {
  676   	Layout layout = (Layout) OptionConverter.instantiateByKey(props,
  677   								  layoutPrefix,
  678   								  Layout.class,
  679   								  null);
  680   	if(layout != null) {
  681   	  appender.setLayout(layout);
  682   	  LogLog.debug("Parsing layout options for \"" + appenderName +"\".");
  683   	  //configureOptionHandler(layout, layoutPrefix + ".", props);
  684             PropertySetter.setProperties(layout, props, layoutPrefix + ".");
  685   	  LogLog.debug("End of parsing for \"" + appenderName +"\".");
  686   	}
  687         }
  688         //configureOptionHandler((OptionHandler) appender, prefix + ".", props);
  689         PropertySetter.setProperties(appender, props, prefix + ".");
  690         LogLog.debug("Parsed \"" + appenderName +"\" options.");
  691       }
  692       registryPut(appender);
  693       return appender;
  694     }
  695   
  696   
  697     void  registryPut(Appender appender) {
  698       registry.put(appender.getName(), appender);
  699     }
  700   
  701     Appender registryGet(String name) {
  702       return (Appender) registry.get(name);
  703     }
  704   }
  705   
  706   class PropertyWatchdog extends FileWatchdog {
  707   
  708     PropertyWatchdog(String filename) {
  709       super(filename);
  710     }
  711   
  712     /**
  713        Call {@link PropertyConfigurator#configure(String)} with the
  714        <code>filename</code> to reconfigure log4j. */
  715     public
  716     void doOnChange() {
  717       new PropertyConfigurator().doConfigure(filename,
  718   					   LogManager.getLoggerRepository());
  719     }
  720   }

Save This Page
Home » apache-log4j-1.2.15 » org.apache » log4j » [javadoc | source]