You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@avalon.apache.org by mc...@apache.org on 2004/05/31 03:29:30 UTC

svn commit: rev 20671 - in avalon/trunk: central/site/src/xdocs/products/runtime/reference/kernel/repository central/site/src/xdocs/products/runtime/system/logging/logkit runtime/versioning

Author: mcconnell
Date: Sun May 30 18:29:30 2004
New Revision: 20671

Added:
   avalon/trunk/central/site/src/xdocs/products/runtime/system/logging/logkit/index.xml
Modified:
   avalon/trunk/central/site/src/xdocs/products/runtime/reference/kernel/repository/hosts.xml
   avalon/trunk/runtime/versioning/avalon-util.ent
Log:


Modified: avalon/trunk/central/site/src/xdocs/products/runtime/reference/kernel/repository/hosts.xml
==============================================================================
--- avalon/trunk/central/site/src/xdocs/products/runtime/reference/kernel/repository/hosts.xml	(original)
+++ avalon/trunk/central/site/src/xdocs/products/runtime/reference/kernel/repository/hosts.xml	Sun May 30 18:29:30 2004
@@ -33,7 +33,7 @@
         <table>
           <tr><th>Element</th><th>Occurance</th><th>Description</th></tr>
           <tr>
-            <td>host</td><td>0..1</td>
+            <td>host</td><td>0..n</td>
             <td>
              <p>Declaration of a remote host.  The value of the element 
              is an http address of a server the implements the Maven 

Added: avalon/trunk/central/site/src/xdocs/products/runtime/system/logging/logkit/index.xml
==============================================================================
--- (empty file)
+++ avalon/trunk/central/site/src/xdocs/products/runtime/system/logging/logkit/index.xml	Sun May 30 18:29:30 2004
@@ -0,0 +1,410 @@
+<!--
+     Copyright 2004 The Apache Software Foundation
+     Licensed  under the  Apache License,  Version 2.0  (the "License");
+     you may not use  this file  except in  compliance with the License.
+     You may obtain a copy of the License at
+     
+     http://www.apache.org/licenses/LICENSE-2.0
+     
+     Unless required by applicable law or agreed to in writing, software
+     distributed  under the  License is distributed on an "AS IS" BASIS,
+     WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+     implied.
+     
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<document>
+  <properties>
+    <author email="dev@avalon.apache.org">Avalon Development Team</author>
+    <title>Logkit - Whitepaper</title>
+  </properties>
+  <body>
+    <section name="Abstract">
+      <p>
+        Logging is an integral component to any software development project.
+        During the development stages it offers a valuable source of debugging
+        information for the developer. During deployment it can provide 
+        valuable operational data that allows administrators to diagnose 
+        problems as they arise. This whitepaper describes the design and 
+        implementation of LogKit.
+      </p>
+    </section>
+    <section name="Introduction">
+      <p>
+        LogKit, began life as a facade for a more complex logging toolkit. 
+        During development it was found that existing toolkits were complex and
+        difficult to use. A malformed logger configuration file could cause the
+        whole system to fail or the logging information to go into the void.
+      </p>
+      <p>
+        Over time it was discovered that the facade, while simple to use, 
+        inherited many of the faults of the underlying logging toolkit. The 
+        logging was slow and was impossible to dynamically reconfigure.
+      </p>
+      <p>
+        At this time the whole system was overhauled. Existing logging toolkits
+        were surveyed and user feedback was gathered from both developers and
+        administrators. The new toolkit focused on speed, reliability and 
+        dynamic reconfiguration. It then added, at that time unique features, 
+        for filtering log events, multiple listeners (aka LogTargets) per 
+        category and delayed serialization of events.
+      </p>
+    </section>
+    <section name="Structure and Elements">
+      <p>
+        The most basic components of LogKit are the Logger, the LogEvent and the
+        LogTarget. The Logger represents the client interface to the logging 
+        system. The developer interacts with Logger to generate LogEvents. The 
+        LogEvents are routed to a LogTarget. The LogTarget decides what to do 
+        with the LogEvent, usually it is recorded to a file, a database or 
+        transmitted over the network.
+      </p>
+    </section>
+    <section name="Priorities">
+      <p>
+        One of the advantages of a logging toolkit is fine grain control over 
+        which statements get printed. At some times during development you may 
+        wish to enable all logging statements and at other times they may wish 
+        to disable debug messages. It was from this need that the notion of of 
+        Priorities were born. A Priority describes the urgency of a LogEvent. 
+        Below is a list of priorities that are usable within the LogKit system 
+        (extracted from the constants of class org.apache.log.Priority).
+      </p>
+      <ul>
+        <li>
+          <strong>DEBUG:</strong>
+          <br/>
+          Developer oriented messages, usually used during development of the 
+          product.
+        </li>
+        <li>
+          <strong>INFO:</strong>
+          <br/>
+          Useful information messages such as state changes, client connection, 
+          user login etc.
+        </li>
+        <li>
+          <strong>WARN:</strong>
+          <br/>
+          A problem or conflict has occurred but it may be recoverable, then
+          again it could be the start of the system failing.
+        </li>
+        <li>
+          <strong>ERROR:</strong>
+          <br/>
+          A problem has occurred but it is not fatal. The system will still 
+          function.
+        </li>
+        <li>
+          <strong>FATAL_ERROR:</strong>
+          <br/>
+          Something caused whole system to fail. This indicates that an 
+          administrator should restart the system and try to fix the problem 
+          that caused the failure.
+        </li>
+      </ul>
+      <p>
+        The range of priorities is limited by design as past experience has
+        indicated more levels do not offer any significant advantage to the
+        user.
+      </p>
+      <p>
+        Each logger instance is associated with a Priority. This allows you to
+        limit each logger so that it only displays messages greater than a 
+        certain priority. So if a DEBUG message occurred and the logger's 
+        priority was WARN, the LogEvent would be suppressed.
+      </p>
+      <p>
+        A user can log at a certain priority by calling a method with matching 
+        name and the message as a string. For instance to log at debug level 
+        you would call logger.debug("My Message"). Similar methods exist for 
+        info(), warn() and error(). There is also a set of similarly named 
+        methods that take both a message string and an exception.
+      </p>
+      <p>
+        Where performance is critical it is often useful to check if a priority
+        is enabled before constructing the message. In many cases the 
+        construction of the message is an expensive string operation and 
+        conversion operation. In this case it is useful to know before you 
+        create the message whether it will be logged. The pattern of the method
+        to check if a priority is enabled is "is&lt;Priority&gt;Enabled()". An 
+        example use case is displayed below.
+      </p>
+      <source>
+if( logger.isDebugEnabled() )
+{
+    //Construct a message (expensive operation)
+    final String message = "Var1 value: " + var1 + "\tVar2 value: " + var2 +
+        "\tVar3 value: " + var3 + ".";
+    logger.debug( message );
+}
+      </source>
+    </section>
+    <section name="Categories">
+      <p>
+        In a complex system it is often not enough to suppress logging based on
+        priority. For instance you may wish to log the network subsystem with 
+        DEBUG priority while the simulator subsystem with WARN priority. To 
+        accomplish this LogKit uses a concept termed Categories. Categories, 
+        often called Channels, Subjects or Facilities, are a subdivision of the
+        logging namespace.
+      </p>
+      <p>
+        Each category is a name, made up of name components separated by a ".". 
+        So a category named "network.interceptor.connected" is made up of three 
+        name components "network", "interceptor" and "connected", ordered from 
+        left to right. Every logger is associated with a category at creation.
+      </p>
+      <p>
+        LogKit takes it one step further and assumes that the namespace is 
+        hierarchical. The left-most name component is the most generic category 
+        while the right-most name component is the most specific. So 
+        "network.interceptor.connected" is a child category of 
+        "network.interceptor", which is in turn a child category of "network".
+        There is also a root category "" that is hidden inside the 
+        org.apache.log.Hierarchy class.
+      </p>
+      <p>
+        The main reason for structuring logging namespace in a hierarchical 
+        manner is to allow inheritance. A logger will inherit it's parent 
+        priority if it has not been explicitly set. This allows you to set the
+        "network" logger to have INFO priority and unless the 
+        "network.interceptor" has had it's priority set it will inherit the 
+        INFO priority.
+      </p>
+      <p>
+        Unlike other logging toolkits, there is no performance penalty for 
+        having deep hierarchies. Each logger caches a Priority to check against.
+        When a logger has it's logger set or unset, it updates the cached 
+        version of it's child loggers.
+      </p>
+    </section>
+    <section name="Log Targets">
+      <p>
+        In LogKit, LogTargets are the destination of LogEvents. Decoupling 
+        LogEvent generation from handling allows developers to change 
+        destinations of LogEvents dynamically or via configuration files. 
+        Possible destinations include writing to a database, a file, an IRC 
+        channel, a syslog server, an instant messaging client etc.
+      </p>
+      <p>
+        Like Priorities, it is often useful to allow LogTargets to be inherited
+        between loggers. Like Priority inheritance, LogTarget inheritance does 
+        not suffer any runtime performance penalty.
+      </p>
+      <section name="Filters">
+        <p>
+          Filters are a special kind of LogTarget. Instead of writing to an 
+          output destination they are used to filter out LogEvents or modify 
+          the LogEvents details and pass it on to another LogTarget.
+        </p>
+        <p>
+          This can be a useful feature when you assign multiple LogTargets to a
+          logger. For instance you may add two LogTargets to a logger, one which
+          writes LogEvents to a database and one which writes a message to the
+          administrators pager. However you may want to record all messages to
+          the database but only transmit FATAL_ERROR messages to pager. In this
+          case you would use a PriorityFilter to filter out non-FATAL_ERROR 
+          messages for pager log target.
+        </p>
+      </section>
+      <section name="AsyncLogTarget">
+        <p>
+          AsyncLogTarget is another kind of special LogTarget. It takes a log 
+          event and copies it into a queue so that another thread can actually 
+          write the LogEvent to another LogTarget. This is useful if logging to 
+          a particular LogTarget is a slow operation (such as a MailLogTarget).
+        </p>
+        <p>
+          Below is a snippet of code that creates an AsyncLogTarget to write 
+          messages in another thread.
+        </p>
+        <source>
+LogTarget mySlowTarget = ...;
+AsyncLogTarget asyncTarget = new AsyncLogTarget( mySlowTarget );
+Thread thread = new Thread( asyncTarget );
+thread.setPriority( Thread.MIN_PRIORITY );
+thread.start();
+logger.setLogTargets( new LogTarget[] { asyncTarget } );
+        </source>
+      </section>
+    </section>
+    <section name="Formatters">
+      <p>
+        LogTargets that write to a serial or unstructured store (ie filesystem 
+        or network based LogTargets) need some method to serialize the LogEvent
+        before writing to the store. The most common way to serialize the 
+        LogEvent is to use a Formatter.
+      </p>
+      <p>
+        The Formatter interface takes a LogEvent and returns a String object. 
+        The most commonly use LogEvent is the PatternFormatter. The pattern 
+        formatter takes a format specifier that has a similar format to c's 
+        printf function.
+      </p>
+      <p>
+        The format specifier consists of a string containing raw text combined 
+        with pattern elements. Each pattern element has the generalized form
+        "%[+|-]#.#{field:subformat}". The +|- indicates whether the pattern 
+        element should be left or right justified (defaults to left justified if
+        unspecified). The #.# indicates the minimum and maximum size of output,
+        if unspecified the output is neither padded nor truncated. 'field' 
+        indicates the field to be written and must be one of "category", 
+        "context", "message", "time", "rtime" (time relative to start of 
+        application), "throwable" or "priority". This parameter must be supplied
+        and correlates to fields of LogEvent. 'subformat' is currently unused 
+        except in the case of "context" field. This is further discussed below.
+      </p>
+      <p>
+        Following is a number of examples for PatternFormatter's format 
+        specifier and actual output.
+      </p>
+      <source>
+format: "%7.7{priority} %5.5{rtime} [%8.8{category}]: %{message}\n%{throwable}"
+output: DEBUG   123   [network.]: This is a debug message
+format: "%7.7{priority} %5.5{rtime} [%{category}]: %{message}\n"
+output: DEBUG   123   [network.interceptor.connected]: This is a debug message
+output: DEBUG   123   [network]: This is another debug message
+format: "%7.7{priority} %5.5{rtime} [%10.{category}]: %{message}\n"
+output: DEBUG   123   [network.interceptor.connected]: This is a debug message
+output: DEBUG   123   [network   ]: This is another debug message
+      </source>
+      <p>
+        There is also ExtendedPatternFormatter that allows two extra fields, 
+        namely "method" and "thread". The "method" field attempts to determine 
+        the method that called the Logger method to generate the LogEvent. The 
+        "thread" field displays the name of the current thread.
+      </p>
+    </section>
+    <section name="Context">
+      <p>
+        In many systems you need to include extra information depending in logs
+        that depends on information not included in the LogEvent. For instance 
+        the Formatters section described an ExtendedPatternFormatter that 
+        included information such as calling method and calling thread. Other 
+        contextual information that you may need to include in log files include
+        user executing log statement, the network interface that the client 
+        component is listening to (ie 127.0.0.1 vs 192.168.1.1), hostname 
+        (especially important on multihomed boxs) or source of LogEvent (useful 
+        when writing a centralized log server).
+      </p>
+      <p>
+        There are a number of strategies to deal with application specific 
+        contextual information. Some logging toolkits encourage extending the 
+        Logger, LogEvent and LogTargets while others encourage using application
+        specific LogTargets. The way that LogKit solves this problem is by using
+        a generic ContexMap object.
+      </p>
+      <p>
+        The ContextMap allows the user to store arbitrary objects using a string
+        key. These objects can then be extracted by the LogTargets and used as 
+        appropriate. If you were using the PatternFormatter you could extract a 
+        value from ContextMap by specify the "context" field with it's subformat
+        set to the appropriate key. Some examples are illustrated below.
+      </p>
+      <source>
+format: "%7.7{priority} [%{context:hostname}]: %{message}\n"
+output: DEBUG   [helm.realityforge.org]: This is a debug message
+format: "%7.7{priority} [%{context:interface}]: %{message}\n"
+output: DEBUG   [127.0.0.1]: This is logging about loopback interface
+output: DEBUG   [192.168.1.1]: This is logging about internal network interface
+output: DEBUG   [203.121.1.2]: This is logging about external network interface
+format: "%7.7{priority} [%{context:user}]: %{message}\n"
+output: DEBUG   [Barney Rubble]: This is a debug message
+      </source>
+      <p>
+        <em>Warning:</em>
+        Older versions of LogKit also incorporated a ContextStack that offered 
+        hierarchical management of context. It was discovered that this design 
+        encouraged bad practices and thus use of this feature has been 
+        deprecated in favour of using ContextMap. The ContextStack is still 
+        accessible if users do not specify a subformat or specify the subformat 
+        "stack". However it is strongly advised that users do not use this 
+        feature as it will be removed in a future iteration.
+      </p>
+      <p>
+        When using a ContextMap you create the object and populate it using the
+        set(key,value) method. After populating the ContextMap you call the 
+        method makeReadOnly(). This makes it impossible for hostile code to 
+        modify context in which logging occurs.
+      </p>
+      <p>
+        Then you need to associate the ContextMap with a thread by using
+        ContextMap.bind( myContextMap ). The ContextMap is bound to a thread
+        using java.lang.InheritableThreadLocal and thus maps are inherited 
+        between threads as specified by InheritableThreadLocal.
+      </p>
+      <p>Below is an example of how a user can create and bind a ContextMap.</p>
+      <source>
+final ContextMap context = new ContextMap();
+context.set( "user", "Fred Flinstone" );
+context.set( "interface", myInterface );
+context.set( "hostname", "helm.realityforge.org" );
+context.set( "jvmid", myJvmId );
+context.makeReadOnly();
+//bind new ContextMap to current thread and subthreads
+ContextMap.bind( context );
+      </source>
+    </section>
+    <section name="Examples" >
+      <p>
+        One of the best ways to learn how to use a toolkit is to see an
+        example in action. With that heres some example uses of LogKit. The 
+        first example is in a simple application while the next example is in a
+        servlet. The servlet example demonstrates the usage of filters.
+      </p>
+      <source>
+Logger logger = Hierarchy.getDefaultHierarchy().getLoggerFor("myCategory");
+logger.setPriority( Priority.DEBUG );
+logger.debug( "This is a debug message" );
+      </source>
+      <source>
+//Create a Log filter that writes to servlet Containers log
+//If priority greater than ERROR
+PriorityFilter filter = new PriorityFilter(Priority.ERROR);
+filter.addTarget( new ServletOutputLogTarget(context) );
+
+String logName = getInitParameter("log-name");
+if( null == logName ) 
+    logName = "myservlet.log";
+
+final String path = context.getRealPath("/") + "/WEB-INF/logs/" + logName ;
+
+//Create a logger to write to a file as specified
+//with servlet init parameters
+final String pattern = "%7.7{priority} %5.5{time}   [%8.8{category}] " +
+    "(%{context}): %{message}\\n%{throwable}";
+    
+final PatternFormatter formatter = new PatternFormatter( pattern );
+final File file = new File( path );
+
+//open file target in append mode
+FileTarget target = new FileTarget( file, true, formatter );
+
+//Create logger
+myLogger = Hierarchy.getDefaultHierarchy().getLoggerFor("myServlet");
+
+//Set log targets of logger
+myLogger.setLogTargets( new LogTarget[] { target, filter } );
+String logLevel = getInitParameter("log-priority");
+
+if( null == logLevel ) 
+    logLevel = "DEBUG";
+    
+//Set log targets parameter based on init parameters
+Priority priority = Priority.getPriorityForName( logLevel );
+myLogger.setPriority( priority );
+      </source>
+    </section>
+    <section name="Conclusion">
+      <p>
+        LogKit is a friendly, easy to use logging toolkit. It is high 
+        performing and easily integrated into existing products. By design it 
+        does not specify any configuration format but instead encourages users 
+        to integrate it into their existing products. It also is designed to run
+        in a secure environment by limiting client access to hierarchies.
+      </p>
+    </section>
+  </body>
+</document>

Modified: avalon/trunk/runtime/versioning/avalon-util.ent
==============================================================================
--- avalon/trunk/runtime/versioning/avalon-util.ent	(original)
+++ avalon/trunk/runtime/versioning/avalon-util.ent	Sun May 30 18:29:30 2004
@@ -9,7 +9,7 @@
 <!ENTITY avalon-util-defaults-version "1.2.1">
 
 <!ENTITY avalon-util-env-id "avalon-util-env">
-<!ENTITY avalon-util-env-version "1.1.1">
+<!ENTITY avalon-util-env-version "1.1.2-dev">
 
 <!ENTITY avalon-util-exception-id "avalon-util-exception">
 <!ENTITY avalon-util-exception-version "1.0.0">

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