You are viewing a plain text version of this content. The canonical link for it is here.
Posted to log4j-cvs@jakarta.apache.org by pg...@apache.org on 2001/06/01 08:00:20 UTC

cvs commit: jakarta-log4j/src/java/org/apache/log4j/examples/appserver AppServerPropConfigurator.java AppServerCategory.java package.html

pglezen     01/05/31 23:00:20

  Modified:    src/java/org/apache/log4j/examples/appserver
                        AppServerCategory.java package.html
  Added:       src/java/org/apache/log4j/examples/appserver
                        AppServerPropConfigurator.java
  Log:
  1. Added static initializer to AppServerCategory.
     Fixed some broken links in comments.
  2. Added AppServerPropConfigurator to configure
     AppServerCategoryFactory instances.
  3. Changed package.html to explain how the modes
     of configuration operate.
  
  Revision  Changes    Path
  1.6       +70 -8     jakarta-log4j/src/java/org/apache/log4j/examples/appserver/AppServerCategory.java
  
  Index: AppServerCategory.java
  ===================================================================
  RCS file: /home/cvs/jakarta-log4j/src/java/org/apache/log4j/examples/appserver/AppServerCategory.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- AppServerCategory.java	2001/03/05 04:52:38	1.5
  +++ AppServerCategory.java	2001/06/01 06:00:17	1.6
  @@ -7,16 +7,21 @@
   
   package org.apache.log4j.examples.appserver;
   
  +import java.net.URL;
  +import java.net.MalformedURLException;
  +
   import org.apache.log4j.Priority;
   import org.apache.log4j.Category;
   import org.apache.log4j.spi.CategoryFactory;
   import org.apache.log4j.spi.LoggingEvent;
  +import org.apache.log4j.helpers.LogLog;
  +import org.apache.log4j.helpers.OptionConverter;
   
   /**
  - *  Extends <a href="../../Category.html"><code>Category</code></a> 
  - *  by adding four text attributes
  - *  relevant to applications run in application servers.
  - *  These attributes are
  + *  Extends {@link org.apache.log4j.Category Category} by
  + *  adding four text attributes relevant to applications
  + *  applications run in application servers.  These attributes
  + *  are
    *  <p>
    *  <ul>
    *  <li><b>host</b> - the host on which the code is running
  @@ -27,11 +32,11 @@
    *  <li><b>version</b> - the version of this code
    *  </ul>
    *  <p>This <code>Category</code> subclass generates
  - *  <a href="AppServerLoggingEvent.html"><code>AppServerLoggingEvent</code></a> 
  + *  {@link AppServerLoggingEvent AppServerLoggingEvent}
    *  subclasses of
  - *  <a href="../../spi/LoggingEvent.html"><code>LoggingEvent</code></a> 
  + *  {@link org.apache.log4j.spi.LoggingEvent LoggingEvent} 
    *  which include the additional attributes.  
  - *  <a href="AppServerPatternLayout.html"><code>AppServerPatternLayout</code></a> 
  + *  {@link AppServerPatternLayout AppServerPatternLayout} 
    *  provides the ability to format these attributes.
    *  <p>
    *  Rather than set all these attributes for each
  @@ -42,7 +47,16 @@
    *  <code>setFactory</code> method.  The
    *  <code>AppServerCategory.getInstance(String)</code> method can
    *  then be used to create <code>AppServerCategory</code>
  - *  instances conveniently.
  + *  instances.
  + *  <p>
  + *  A special {@link AppServerPropConfigurator AppServerPropConfigurator}
  + *  subclass of {@link org.apache.log4j.PropertyConfigurator
  + *  PropertyConfigurator} is provided to facilitate complete factory
  + *  configuration at class load time.  This is useful in application
  + *  server environments where a variety of entry points may exist for
  + *  an application.  Check the package level documentation for details
  + *  on how to set this up.
  + *  <p>
    *
    *  @author Paul Glezen
    */
  @@ -50,6 +64,9 @@
   
     private static String FQCN = AppServerCategory.class.getName();
   
  +  public static final String APPSERVER_INIT_OVERRIDE_KEY = 
  +                                         "log4j.appserverInitOverride";
  +
     /** The name of the component using this category.  */
     protected String component;
   
  @@ -67,6 +84,51 @@
     /** A reference to the factory to create <code>AppServerCategory</code>
         instances.  */
     private static CategoryFactory factory = new AppServerCategoryFactory(null, null, null);
  +    
  +  /** 
  +   *  This static initializer will configure over the one used by
  +   *  <code>Category</code> if the <code>log4j.appserver.factory</code>
  +   *  property is defined in the configuration file (and the default
  +   *  init override key is not set to true).
  +   */
  +  static {
  +    String override =OptionConverter.getSystemProperty(
  +                                               APPSERVER_INIT_OVERRIDE_KEY, 
  +                                               null);
  +
  +    // If there is no appserver init override, then get the resource
  +    // specified by the user or the default config file.
  +    if(override == null || "false".equalsIgnoreCase(override)) {
  +      String resource = OptionConverter.getSystemProperty(
  +                                                 DEFAULT_CONFIGURATION_KEY, 
  +                                                 DEFAULT_CONFIGURATION_FILE);
  +      LogLog.debug("Running AppserverDefaultInit");
  +      URL url = null;
  +      try {
  +        url = new URL(resource);
  +      } catch (MalformedURLException ex) {
  +        // So resource is not a URL;  attempt to get the resource
  +        // from the classpath
  +        url = ClassLoader.getSystemResource(resource);
  +        if(url == null) {
  +          // Is it under anywhere in the classpath?
  +          url = Category.class.getResource("/" + resource);
  +        }  
  +        if(url == null) {
  +          // Is it under org/apache/log4j somewhere in the classpath?
  +          url = Category.class.getResource(resource);
  +        }  
  +      }  
  +      // If we have a non-null url, then delegate the rest of the
  +      // configuration to the AppServerPropConfigurator class.
  +      if(url != null) {
  +		  LogLog.debug("Configuring with AppServerPropConfigurator");
  +        new AppServerPropConfigurator().doConfigure(url, defaultHierarchy);
  +      } else {
  +        LogLog.debug("Could not find resource: ["+resource+"].");
  +      }
  +    }  
  +  }
   
     /**
      *  Construct a new AppServerCategory with the provided
  
  
  
  1.3       +120 -21   jakarta-log4j/src/java/org/apache/log4j/examples/appserver/package.html
  
  Index: package.html
  ===================================================================
  RCS file: /home/cvs/jakarta-log4j/src/java/org/apache/log4j/examples/appserver/package.html,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- package.html	2001/03/05 04:52:40	1.2
  +++ package.html	2001/06/01 06:00:17	1.3
  @@ -12,18 +12,107 @@
      message was logged
   </ol>
   <p>
  -<h3>Usage</h3>
  +<h2>Configuration</h2>
   Using this package in your programs differs little from using the
  -corresponding classes in <code>org.apache.log4j</code>.  At log4j 
  -initialization you create an
  -instance of 
  -<a href="AppServerCategoryFactory.html"><code>AppServerCategoryFactory</code></a>
  -populated with the attributes you desire.  You can either supply these 
  -in the factory's constructor
  -or set them afterwards.  The host name is determined automatically
  -using the <code>java.net</code> API and can be reset manually.  It
  -is ok to set any of the attributes to null.
  +corresponding classes in <code>org.apache.log4j</code>.  Because of some
  +internal difference in the initialization sequence, this package
  +contains its own property configurator.  A static initializer is also
  +provided in the category subclass that works in much the same way as
  +the <code>Category</code> static initializer.  In this initial version,
  +only property file initialization is supported.
   <p>
  +The following properties serve to configure the 
  +<code>AppServerCategoryFactory</code>.
  +<p>
  +<table border=1>
  +<tr><th>Property<th>Description
  +<tr><td><code><b>log4j.appserver.factory</b></code>
  +	<td>The fully qualified class name of the factory implementation.
  +<tr><td><code><b>log4j.appserver.factory.server</b></code>
  +	<td>The value assigned to the server attribute.
  +<tr><td><code><b>log4j.appserver.factory.component</b></code>
  +	<td>The value assigned to the component attribute.
  +<tr><td><code><b>log4j.appserver.factory.version</b></code>
  +	<td>The value assigned to the version attribute.
  +<tr><td><code><b>log4j.appserver.factory.msgfile</b></code>
  +	<td>The name of bundle file to populate the message 
  +	<code>ResourceBundle</code>.  Because the
  +	<code>ResourceBundle.getBundle</code> method is used to load
  +	the message file, the <code>".properties"</code> extension
  +	should <b>not</b> be included as part of this property.
  +</table>
  +<p>
  +The property names are defined in {@link AppServerPropConfigurator}.
  +<p>
  +<h3>Automatic Configuration</h3>
  +In application servers, it is difficult to predict which code
  +will be the first to run.  There is no <code>main</code> method
  +the application programmer can grab hold of and populate with
  +initialization method calls.  This complicates the initialization
  +of a log4j hierarchy, an essentially static structure, by various
  +transient objects such as servlets, EJBs or CORBA objects.
  +<p>
  +The simplest way to achieve the log4j configuration is to allow
  +the configuration to occur at class load time of the
  +<code>AppServerCategory</code>.  The static initializer of
  +<code>AppServerCategory</code> is very similar to that of its
  +parent class, <code>Category</code>.  
  +<p>
  +For the static <code>AppServerCategory</code> to perform properly,
  +it is best to disable the configuration attempted by the
  +<code>Category</code> static initializer.  This is done by defining
  +the system property <code>log4j.defaultInitOverride</code> to be
  +<code>true</code> (or anything else but <code>false</code>).  If
  +you run your program from the command line, you do this with the
  +<code>-D</code> option; as in
  +<p>
  +<center>
  +<code>java -Dlog4j.defaultInitOverride=true my.class.with.main</code>
  +</center>
  +<p>
  +If you are logging from an application server, you will need to
  +consult the vendor's documentation on how to set system properties.
  +<p>
  +Like the <code>Category</code> static initializer, the 
  +<code>AppServerCategory</code> static initializer expects to find
  +the name of the property file in a system property called
  +<code>log4j.configuration</code>.  If this system property is not
  +defined, an attempt is made to load <b>log4j.properties</b>.
  +<p>
  +Since all the actions described above are triggered by the loading
  +of the <code>AppServerCategory</code> class, they will likely
  +happen at the first occurence of a statement like
  +<p>
  +<code>Category cat = AppServerCategory.getInstance("some.cat");</code>
  +<p>
  +There is no need to take special measures to ensure the appropriate
  +configurator was run beforehand.
  +
  +<h3>Manual Configuration</h3>
  +You can manually invoke the configuration much like the static
  +initializer would have.
  +<p>
  +<table border=1>
  +<tr><td><pre>
  +import org.apache.log4j.Category;
  +import org.apache.log4j.examples.appserver.AppServerCategory;
  +import org.apache.log4j.examples.appserver.AppServerPropConfigurator;
  +
  +...
  +
  +AppServerPropConfigurator.configure("test.properties");
  +Category cat = AppServerCategory.getInstance("some.cat");
  +
  +...
  +
  +cat.info("This is an INFO statement.");</pre>
  +</table>
  +<p>
  +<h3>Very Manual Configuration</h3>
  +If you want complete control over the configuration process, you
  +can leave <code>AppServerPropConfigurator</code> out of it all
  +together.
  +<p>
   After creating an appropriate <code>AppServerCategoryFactory</code>
   instance, set a static reference to it using the
   <a href="AppServerCategory.html#setFactory">
  @@ -52,7 +141,7 @@
   </pre>
   </table>
   <p>
  -<h3>A Note on Configurators</h3>
  +<h4>A Note on Configurators</h4>
   Using <code>AppServerCategory</code> with
   <a href="../../PropertyConfigurator.html">
   <code>PropertyConfigurator</code></a> or
  @@ -85,19 +174,29 @@
   this will only populate the hostname attribute.  The server name,
   component name and version name will be blank.  For many cases
   this may be satisfactory.
  +<p>
  +<h2>Remote Usage</h2>
  +Including attributes such as hostname and server are only relevant
  +if the logging entries somehow end up on other hosts or mixed with
  +those of other servers.  Remote logging in a distributed application
  +environment allows the logging of various remote components to be
  +collected together in a single location.  The basic building blocks
  +for remote usage are the <code>SimpleSocketServer</code> used in
  +conjunction with the <code>SocketAppender</code>.
  +<p>
  +The configuration of <code>SimpleSocketServer</code> receiving
  +serialized <code>AppServerLoggingEvent</code> classes is much the
  +same as with the standard <code>LoggingEvent</code> class.  The main
  +difference to keep in mind is that the layout implementation should be
  +<code>org.apache.log4j.examples.appserver.AppServerPatternLayout</code>.
  +This will allow for the interpretation of %h, %s, %b and %v symbols.
   <p>
  -<h3>Compatibility</h3>
  -The log4j package naming conventions used in
  -this package are compatible with log4j version 1.0.
  -<p>
  -<h3>Try It Yourself</h3>
  -While the attributes extended in this package are oriented toward
  -application servers, there is nothing application server specific
  -in the code structure.  This package may be used as a template for
  +<h2>Try It Yourself</h2>
  +This package may be used as a template for
   specifying your own collection of attributes or extended to include
   additional attributes.  A 
   <a href="../../../../../../deepExtension.html">log4j extension manual</a> 
  -accompanies this package that will take you step by step through the 
  -process.
  +accompanies this distribution that will take you step by step through the 
  +extension process.
   </body>
   </html>
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/log4j/examples/appserver/AppServerPropConfigurator.java
  
  Index: AppServerPropConfigurator.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software
   * License version 1.1, a copy of which has been included with this
   * distribution in the LICENSE.APL file.  */
  
  package org.apache.log4j.examples.appserver;
  
  import java.net.URL;
  import java.util.Properties;
  import java.util.ResourceBundle;
  import java.util.MissingResourceException;
  
  import org.apache.log4j.Category;
  import org.apache.log4j.PropertyConfigurator;
  import org.apache.log4j.helpers.FileWatchdog;
  import org.apache.log4j.helpers.LogLog;
  
  /**
   * Extends {@link org.apache.log4j.PropertyConfigurator PropertyConfigurator}
   * to configure {@link AppServerCategoryFactory AppServerCategoryFactory}
   * instances according to property file entries.  The important method is
   * <code>configureCategoryFactory</code>.  The static methods are
   * needed to override the static methods in <code>PropertyConfigurator</code>
   * that don't instanciate the desired instance (for
   * <code>AppServerPropConfigurator</code>).
   *
   * @author Paul Glezen
   * @since 1.1b6
   */
  public class AppServerPropConfigurator extends PropertyConfigurator
  {
    /** The key for specifying the server name in a propert file.  The 
        current value is "<code>log4j.appserver.factory.server</code>". */
    public static final String SERVER_NAME = "log4j.appserver.factory.server";
  
    /** The key for specifying the component name in a property file.  The
        current value is "<code>log4j.appserver.factory.component</code>".*/
    public static final String COMPONENT_NAME = "log4j.appserver.factory.component";
  
    /** The key for specifying the version in a property file.  The current
        value is "<code>log4j.appserver.factory.version</code>".  */
    public static final String VERSION_NAME = "log4j.appserver.factory.version";
  
    /** The key for specifying a message file containing externalized
        message strings.  The contents are assigned to a
  		<code>ResourceBundle</code> and assigned to each
  		<code>AppServerCategory</code> instance that is created.  The 
  		current value is "<code>log4j.appserver.factory.msgfile</code>".  
  		<p>
  		Since the message file is loaded as a resource bundle using the
  		<code>getBundle</code> method, the filename should end with
  		"<code>.properties</code>".  However, the <code>.properties</code>
  		extension should <b>not</b> be included as part of the value
  		specified for this property.  The <code>getBundle</code> method
  		assumes this already.                                          */
    public static final String MSGFILE_NAME = "log4j.appserver.factory.msgfile";
  
    /**
     *  Read configuration from a file using the provided filename.
     */
    public static void configure(String configFilename) {
      new AppServerPropConfigurator().doConfigure(configFilename,
                                                  Category.getDefaultHierarchy());
    }
  
    /** 
     *  Read configuration options from a URL.
     */
    public static void configure(URL configURL) {
      new AppServerPropConfigurator().doConfigure(configURL,
                                                  Category.getDefaultHierarchy());
    }
  
    /**
     *  Read configuration from a <code>Properties</code> object.
     */
    public static void configure(Properties props) {
      new AppServerPropConfigurator().doConfigure(props,
                                                  Category.getDefaultHierarchy());
    }
  
    /**
     * Like {@link #configureAndWatch(String, long)} except that the
     * default delay as defined by {@link FileWatchdog#DEFAULT_DELAY} is
     * used. 
     * 
     * @param configFilename A file in key=value format.
     *
     */
    public static void configureAndWatch(String configFilename) {
      configureAndWatch(configFilename, FileWatchdog.DEFAULT_DELAY);
    }
  
    /**
     * Read the configuration file <code>configFilename</code> if it
     * exists. A thread will be created that will periodically check
     * if <code>configFilename</code> has been created or modified.
     * The period is determined by the <code>delay</code> argument.
     * If a change or file creation is detected, then
     * <code>configFilename</code> is read to configure log4j.  
     *
     *  @param configFilename A file in key=value format.
     *  @param delay The delay in milliseconds to wait between each check.
     */
    public static void configureAndWatch(String configFilename, long delay) {
      FileWatchdog adog = new AppServerWatchdog(configFilename);
      adog.setDelay(delay);
      adog.start();
    }
  
  
    /** Configure an {@link AppServerCategoryFactory AppServerCategoryFactory}
     *  instance for use as the category factory in further log4j configuration.
     *  The property names used by this method are the following constants
     *  defined by this class.
     *  <p>
     *  <ul>
     *  <li>{@link SERVER_NAME}
     *  <li>{@link COMPONENT_NAME}
     *  <li>{@link VERSION_NAME}
     *  </ul>
     *  <p>
     *
     *  @param props <code>Properties object used for log4j configuration
     */
    protected void configureCategoryFactory(Properties props) {
      String server    = props.getProperty(SERVER_NAME);
      String component = props.getProperty(COMPONENT_NAME);
      String version   = props.getProperty(VERSION_NAME);
      String msgFile   = props.getProperty(MSGFILE_NAME);
  
      LogLog.debug("Creating AppServerCategoryFactory with server = " + server);
  	 LogLog.debug("                                    component = " + component);
  	 LogLog.debug("                                      version = " + version);
  	 LogLog.debug("                                 message file = " + msgFile);
      AppServerCategoryFactory factory = new AppServerCategoryFactory(server, component, version);
  
      if (msgFile != null) {
  	   try {
  		  LogLog.debug("Loading message bundle from " + msgFile);
  	     ResourceBundle bundle = ResourceBundle.getBundle(msgFile);
  		  factory.setMessageBundle(bundle);
  		}
  		catch(MissingResourceException mre) {
  		  LogLog.error("AppServerPropConfigurator could not locate message file: " + msgFile);
  		}
  	 }
  	 AppServerCategory.setFactory(factory);
  	 categoryFactory = factory;
    }
  }
  
  class AppServerWatchdog extends FileWatchdog {
    AppServerPropConfigurator configurator;
  
    AppServerWatchdog(String filename) {
      super(filename);
      configurator = new AppServerPropConfigurator();
    }
  
    /**
     *  Call <code>doConfigure</code> on an
     *  {@link AppServerPropConfigurator} instance.
     */
    public void doOnChange() {
      configurator.doConfigure(filename, Category.getDefaultHierarchy());  
    }
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: log4j-cvs-unsubscribe@jakarta.apache.org
For additional commands, e-mail: log4j-cvs-help@jakarta.apache.org