sylvain 01/07/24 02:34:08
Modified: src/org/apache/cocoon/servlet CocoonServlet.java
Added: src/org/apache/cocoon/util/log CocoonLogFormatter.java
ExtensiblePatternFormatter.java package.html
Log:
New log formatter : outputs request URI and caller class name in the log file
Revision Changes Path
1.23 +14 -4 xml-cocoon2/src/org/apache/cocoon/servlet/CocoonServlet.java
Index: CocoonServlet.java
===================================================================
RCS file: /home/cvs/xml-cocoon2/src/org/apache/cocoon/servlet/CocoonServlet.java,v
retrieving revision 1.22
retrieving revision 1.23
diff -u -r1.22 -r1.23
--- CocoonServlet.java 2001/07/20 09:03:29 1.22
+++ CocoonServlet.java 2001/07/24 09:34:08 1.23
@@ -42,12 +42,13 @@
import org.apache.cocoon.util.ClassUtils;
import org.apache.cocoon.util.IOUtils;
import org.apache.cocoon.util.NetUtils;
+import org.apache.cocoon.util.log.CocoonLogFormatter;
+import org.apache.log.ContextStack;
import org.apache.log.Hierarchy;
import org.apache.log.LogTarget;
import org.apache.log.Logger;
import org.apache.log.Priority;
import org.apache.log.filter.PriorityFilter;
-import org.apache.log.format.AvalonFormatter;
import org.apache.log.output.FileOutputLogTarget;
import org.apache.log.output.ServletOutputLogTarget;
import org.xml.sax.SAXException;
@@ -61,7 +62,7 @@
* @author <a href="mailto:[EMAIL PROTECTED]">Nicola Ken Barozzi</a> Aisa
* @author <a href="mailto:[EMAIL PROTECTED]">Berin Loritsch</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Carsten Ziegeler</a>
- * @version CVS $Revision: 1.22 $ $Date: 2001/07/20 09:03:29 $
+ * @version CVS $Revision: 1.23 $ $Date: 2001/07/24 09:34:08 $
*/
public class CocoonServlet extends HttpServlet {
@@ -334,9 +335,9 @@
this.appContext.put(Constants.CONTEXT_LOG_FILE, logName);
final String path = logDir + logName;
- final AvalonFormatter formatter = new AvalonFormatter();
+ final CocoonLogFormatter formatter = new CocoonLogFormatter();
formatter.setFormat( "%7.7{priority} %5.5{time} [%8.8{category}] " +
- "(%{context}): %{message}\\n%{throwable}" );
+ "(%{uri}) %{thread}/%{class:short}:
%{message}\\n%{throwable}" );
this.log = Hierarchy.getDefaultHierarchy().getLoggerFor("cocoon");
this.log.setPriority(logPriority);
@@ -485,6 +486,15 @@
}
Environment env = this.getEnvironment(uri, request, res);
+
+ // Initialize a fresh log context containing the object model : it
+ // will be used by the CocoonLogFormatter
+ ContextStack ctxStack = org.apache.log.ContextStack.getCurrentContext();
+ ctxStack.clear();
+ // Add thread name (default content for empty context)
+ ctxStack.push(Thread.currentThread().getName());
+ // Add the object model
+ ctxStack.push(env.getObjectModel());
if (!this.cocoon.process(env)) {
1.1
xml-cocoon2/src/org/apache/cocoon/util/log/CocoonLogFormatter.java
Index: CocoonLogFormatter.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 file. *
*****************************************************************************/
package org.apache.cocoon.util.log;
import java.util.Map;
import org.apache.avalon.framework.CascadingThrowable;
import org.apache.cocoon.Constants;
import org.apache.cocoon.environment.Request;
import org.apache.log.ContextStack;
import org.apache.log.LogEvent;
/**
* An extended pattern formatter. New patterns are defined by this class are :
* <ul>
* <li><code>class</code> : outputs the name of the class that has logged the
* message. The optional <code>short</code> subformat removes the
* package name. Warning : this pattern works only if formatting occurs in
* the same thread as the call to Logger, i.e. it won't work with
* <code>AsyncLogTarget</code>.</li>
* <li><code>thread</code> : outputs the name of the current thread (first element
* on the context stack).</li>
* <li><code>uri</code> : outputs the request URI.<li>
* </ul>
*
* @author <a href="[EMAIL PROTECTED]">Sylvain Wallez</a>
*/
public class CocoonLogFormatter extends ExtensiblePatternFormatter
{
protected final static int TYPE_CLASS = MAX_TYPE + 1;
protected final static int TYPE_URI = MAX_TYPE + 2;
protected final static int TYPE_THREAD = MAX_TYPE + 3;
protected final static String TYPE_CLASS_STR = "class";
protected final static String TYPE_CLASS_SHORT_STR = "short";
protected final static String TYPE_URI_STR = "uri";
protected final static String TYPE_THREAD_STR = "thread";
/**
* Hack to get the call stack as an array of classes. The
* SecurityManager class provides it as a protected method, so
* change it to public through a new method !
*/
static public class CallStack extends SecurityManager
{
/**
* Returns the current execution stack as an array of classes.
* The length of the array is the number of methods on the execution
* stack. The element at index 0 is the class of the currently executing
* method, the element at index 1 is the class of that method's caller,
* and so on.
*/
public Class[] get()
{
return getClassContext();
}
}
/** The class that we will search for in the call stack */
private Class loggerClass = org.apache.log.Logger.class;
private CallStack callStack = new CallStack();
protected int getTypeIdFor(String type) {
// Search for new patterns defined here, or else delegate
// to the parent class
if (type.equalsIgnoreCase(TYPE_CLASS_STR))
return TYPE_CLASS;
else if (type.equalsIgnoreCase(TYPE_URI_STR))
return TYPE_URI;
else if (type.equalsIgnoreCase(TYPE_THREAD_STR))
return TYPE_THREAD;
else
return super.getTypeIdFor( type );
}
protected String formatPatternRun(LogEvent event, PatternRun run) {
// Format new patterns defined here, or else delegate to
// the parent class
switch (run.m_type) {
case TYPE_CLASS :
return getClass(run.m_format);
case TYPE_URI :
return getURI(event.getContextStack());
case TYPE_THREAD :
return getThread(event.getContextStack());
}
return super.formatPatternRun(event, run);
}
/**
* Finds the class that has called Logger.
*/
private String getClass(String format) {
Class[] stack = this.callStack.get();
// Traverse the call stack in reverse order until we find a Logger
for (int i = stack.length-1; i >= 0; i--) {
if (this.loggerClass.isAssignableFrom(stack[i])) {
// Found : the caller is the previous stack element
String className = stack[i+1].getName();
// Handle optional format
if (TYPE_CLASS_SHORT_STR.equalsIgnoreCase(format))
{
int pos = className.lastIndexOf('.');
if (pos >= 0)
className = className.substring(pos + 1);
}
return className;
}
}
// No Logger found in call stack : can occur with AsyncLogTarget
// where formatting takes place in a different thread.
return "Unknown-class";
}
/**
* Find the URI that is being processed.
*/
private String getURI(ContextStack ctxStack) {
String result = "Unknown-URI";
// Get URI from the first context stack element, if it's a Map (the object
model).
if (ctxStack.getSize() > 1) {
Object context = ctxStack.get(1);
if (context instanceof Map) {
// Get the request
Request request =
(Request)((Map)context).get(Constants.REQUEST_OBJECT);
if (request != null) {
result = request.getRequestURI();
}
}
}
return result;
}
/**
* Find the thread that is logged this event.
*/
private String getThread(ContextStack ctxStack) {
if (ctxStack.getSize() > 0)
return String.valueOf(ctxStack.get(0));
else
return "Unknown-thread";
}
/**
* Utility method to format stack trace so that CascadingExceptions are
* formatted with all nested exceptions.
*
* FIXME : copied from AvalonFormatter, to be removed if
ExtensiblePatternFormatter
* replaces PatternFormatter.
*
* @param throwable the throwable instance
* @param format ancilliary format parameter - allowed to be null
* @return the formatted string
*/
protected String getStackTrace( final Throwable throwable, final String format )
{
final StringBuffer sb = new StringBuffer();
sb.append( super.getStackTrace( throwable, format ) );
if( throwable instanceof CascadingThrowable )
{
final Throwable t = ((CascadingThrowable)throwable).getCause();
sb.append( getStackTrace( t, format ) );
}
return sb.toString();
}
}
1.1
xml-cocoon2/src/org/apache/cocoon/util/log/ExtensiblePatternFormatter.java
Index: ExtensiblePatternFormatter.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 file. *
*****************************************************************************/
package org.apache.cocoon.util.log;
import java.io.StringWriter;
import java.util.Stack;
import org.apache.log.*;
/**
* A refactoring of <code>org.apache.log.format.PatternFormatter</code> that
* can be extended.
* This formater formats the LogEntries according to a input pattern
* string.
*
* The format of each pattern element can be %[+|-]#.#{field:subformat}
*
* The +|- indicates left or right justify.
* The #.# indicates the minimum and maximum size of output.
* 'field' indicates which field is to be output and must be one of
* proeprties of LogEvent
* 'subformat' indicates a particular subformat and is currently unused.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Peter Donald</a>
* @author <a href="[EMAIL PROTECTED]">Sylvain Wallez</a>
*/
public class ExtensiblePatternFormatter
implements Formatter
{
protected final static int TYPE_TEXT = 1;
protected final static int TYPE_CATEGORY = 2;
protected final static int TYPE_CONTEXT = 3;
protected final static int TYPE_MESSAGE = 4;
protected final static int TYPE_TIME = 5;
protected final static int TYPE_RELATIVE_TIME = 6;
protected final static int TYPE_THROWABLE = 7;
protected final static int TYPE_PRIORITY = 8;
/**
* The maximum value used for TYPEs. Subclasses can define their own TYPEs
* starting at <code>MAX_TYPE + 1</code>.
*/
protected final static int MAX_TYPE = 8;
protected final static String TYPE_CATEGORY_STR = "category";
protected final static String TYPE_CONTEXT_STR = "context";
protected final static String TYPE_MESSAGE_STR = "message";
protected final static String TYPE_TIME_STR = "time";
protected final static String TYPE_RELATIVE_TIME_STR = "rtime";
protected final static String TYPE_THROWABLE_STR = "throwable";
protected final static String TYPE_PRIORITY_STR = "priority";
protected final static String SPACE_16 = " ";
protected final static String SPACE_8 = " ";
protected final static String SPACE_4 = " ";
protected final static String SPACE_2 = " ";
protected final static String SPACE_1 = " ";
protected final static String EOL =
System.getProperty("line.separator", "\n");
protected static class PatternRun
{
public String m_data;
public boolean m_rightJustify;
public int m_minSize;
public int m_maxSize;
public int m_type;
public String m_format;
}
protected PatternRun m_formatSpecification[];
/**
* Extract and build a pattern from input string.
*
* @param stack the stack on which to place patterns
* @param pattern the input string
* @param index the start of pattern run
* @return the number of characters in pattern run
*/
protected int addPatternRun( final Stack stack,
final char pattern[],
int index )
{
final PatternRun run = new PatternRun();
final int start = index++;
//first check for a +|- sign
if( '+' == pattern[ index ] ) index++;
else if( '-' == pattern[ index ] )
{
run.m_rightJustify = true;
index++;
}
if( Character.isDigit( pattern[ index ] ))
{
int total = 0;
while( Character.isDigit( pattern[ index ] ) )
{
total = total * 10 + (pattern[ index ] - '0');
index++;
}
run.m_minSize = total;
}
//check for . sign indicating a maximum is to follow
if( index < pattern.length && '.' == pattern[ index ] )
{
index++;
if( Character.isDigit( pattern[ index ] ))
{
int total = 0;
while( Character.isDigit( pattern[ index ] ) )
{
total = total * 10 + (pattern[ index ] - '0');
index++;
}
run.m_maxSize = total;
}
}
if( index >= pattern.length || '{' != pattern[ index ] )
{
throw
new IllegalArgumentException( "Badly formed pattern at character " +
index );
}
int typeStart = index;
while( index < pattern.length &&
pattern[ index ]!= ':' && pattern[ index ] != '}' )
{
index++;
}
int typeEnd = index - 1;
final String type =
new String( pattern, typeStart + 1, typeEnd - typeStart );
run.m_type = getTypeIdFor( type );
if( index < pattern.length && pattern[ index ] == ':' )
{
index++;
while( index < pattern.length && pattern[ index ] != '}' ) index++;
final int length = index - typeEnd - 2;
if( 0 != length )
{
run.m_format = new String( pattern, typeEnd + 2, length );
}
}
if( index >= pattern.length || '}' != pattern[ index ] )
{
throw new
IllegalArgumentException("Unterminated type in pattern at character "
+ index );
}
index++;
stack.push( run );
return index - start;
}
/**
* Extract and build a text run from input string.
* It does special handling of '\n' and '\t' replaceing
* them with newline and tab.
*
* @param stack the stack on which to place runs
* @param pattern the input string
* @param index the start of the text run
* @return the number of characters in run
*/
protected int addTextRun( final Stack stack,
final char pattern[],
int index )
{
final PatternRun run = new PatternRun();
final int start = index;
boolean escapeMode = false;
if( '%' == pattern[ index ] ) index++;
final StringBuffer sb = new StringBuffer();
while( index < pattern.length && pattern[ index ] != '%' )
{
if( escapeMode )
{
if( 'n' == pattern[ index ] ) sb.append( EOL );
else if( 't' == pattern[ index ] ) sb.append( '\t' );
else sb.append( pattern[ index ] );
escapeMode = false;
}
else if( '\\' == pattern[ index ] ) escapeMode = true;
else sb.append( pattern[ index ] );
index++;
}
run.m_data = sb.toString();
run.m_type = TYPE_TEXT;
stack.push( run );
return index - start;
}
/**
* Utility to append a string to buffer given certain constraints.
*
* @param sb the StringBuffer
* @param minSize the minimum size of output (0 to ignore)
* @param maxSize the maximum size of output (0 to ignore)
* @param rightJustify true if the string is to be right justified in it's box.
* @param output the input string
*/
protected void append( final StringBuffer sb,
final int minSize,
final int maxSize,
final boolean rightJustify,
final String output )
{
final int size = output.length();
if( size < minSize )
{
//assert( minSize > 0 );
if( rightJustify )
{
appendWhiteSpace( sb, minSize - size );
sb.append( output );
}
else
{
sb.append( output );
appendWhiteSpace( sb, minSize - size );
}
}
else if( maxSize > 0 && maxSize < size )
{
sb.append( output.substring( 0, maxSize ) );
}
else
{
sb.append( output );
}
}
/**
* Append a certain number of whitespace characters to a StringBuffer.
*
* @param sb the StringBuffer
* @param length the number of spaces to append
*/
protected void appendWhiteSpace( final StringBuffer sb, int length )
{
while( length >= 16 )
{
sb.append( SPACE_16 );
length -= 16;
}
if( length >= 8 )
{
sb.append( SPACE_8 );
length -= 8;
}
if( length >= 4 )
{
sb.append( SPACE_4 );
length -= 4;
}
if( length >= 2 )
{
sb.append( SPACE_2 );
length -= 2;
}
if( length >= 1 )
{
sb.append( SPACE_1 );
length -= 1;
}
}
/**
* Format the event according to the pattern.
*
* @param event the event
* @return the formatted output
*/
public String format( final LogEvent event )
{
final StringBuffer sb = new StringBuffer();
String str = null;
for( int i = 0; i < m_formatSpecification.length; i++ )
{
final PatternRun run = m_formatSpecification[ i ];
//treat text differently as it doesn't need min/max padding
if ( run.m_type == TYPE_TEXT )
{
sb.append( run.m_data );
}
else
{
str = formatPatternRun( event, run );
if (str != null)
{
append( sb, run.m_minSize, run.m_maxSize, run.m_rightJustify,
str );
}
}
}
return sb.toString();
}
/**
* Formats a single pattern run (can be extended in subclasses).
*
* @param run the pattern run to format.
* @return the formatted result.
*/
protected String formatPatternRun( final LogEvent event, final PatternRun run )
{
String str = null;
switch( run.m_type )
{
case TYPE_RELATIVE_TIME:
str = getTime( event.getRelativeTime(), run.m_format );
break;
case TYPE_TIME:
str = getTime( event.getTime(), run.m_format );
break;
case TYPE_THROWABLE:
str = getStackTrace( event.getThrowable(), run.m_format );
break;
case TYPE_MESSAGE:
str = getMessage( event.getMessage(), run.m_format );
break;
case TYPE_CONTEXT:
str = getContext( event.getContextStack(), run.m_format );
break;
case TYPE_CATEGORY:
str = getCategory( event.getCategory(), run.m_format );
break;
case TYPE_PRIORITY:
str = getPriority( event.getPriority(), run.m_format );
break;
default:
//TODO: Convert next line to use error handler
Hierarchy.getDefaultHierarchy().log( "Unknown Pattern
specification." + run.m_type );
}
return str;
}
/**
* Utility method to format category.
*
* @param category the category string
* @param format ancilliary format parameter - allowed to be null
* @return the formatted string
*/
protected String getCategory( final String category, final String format )
{
return category;
}
/**
* Get formatted priority string.
*/
protected String getPriority( final Priority priority, final String format )
{
return priority.getName();
}
/**
* Utility method to format context.
*
* @param context the context string
* @param format ancilliary format parameter - allowed to be null
* @return the formatted string
*/
protected String getContext( final ContextStack stack, final String format )
{
//TODO: Retrieve StringBuffers from a cache
final StringBuffer sb = new StringBuffer();
final int size = stack.getSize();
int sizeSpecification = Integer.MAX_VALUE;
if( null != format )
{
try { sizeSpecification = Integer.parseInt( format ); }
catch( final NumberFormatException nfe ) { nfe.printStackTrace(); }
}
final int end = size - 1;
final int start = Math.max( end - sizeSpecification + 1, 0 );
for( int i = start; i < end; i++ )
{
sb.append( fix( stack.get( i ).toString() ) );
sb.append( '.' );
}
sb.append( stack.get( end ) );
return sb.toString();
}
/**
* Correct a context string by replacing '.''s with a '_'.
*
* @param context the un-fixed context
* @return the fixed context
*/
protected final String fix( final String context )
{
return context.replace( '.', '_' );
}
/**
* Utility method to format message.
*
* @param message the message string
* @param format ancilliary format parameter - allowed to be null
* @return the formatted string
*/
protected String getMessage( final String message, final String format )
{
return message;
}
/**
* Utility method to format stack trace.
*
* @param throwable the throwable instance
* @param format ancilliary format parameter - allowed to be null
* @return the formatted string
*/
protected String getStackTrace( final Throwable throwable, final String format )
{
if( null == throwable ) return "";
final StringWriter sw = new StringWriter();
throwable.printStackTrace( new java.io.PrintWriter( sw ) );
return sw.toString();
}
/**
* Utility method to format time.
*
* @param time the time
* @param format ancilliary format parameter - allowed to be null
* @return the formatted string
*/
protected String getTime( final long time, final String format )
{
return Long.toString( time );
}
/**
* Retrieve the type-id for a particular string.
*
* @param type the string
* @return the type-id
*/
protected int getTypeIdFor( final String type )
{
if( type.equalsIgnoreCase( TYPE_CATEGORY_STR ) ) return TYPE_CATEGORY;
else if( type.equalsIgnoreCase( TYPE_CONTEXT_STR ) ) return TYPE_CONTEXT;
else if( type.equalsIgnoreCase( TYPE_MESSAGE_STR ) ) return TYPE_MESSAGE;
else if( type.equalsIgnoreCase( TYPE_PRIORITY_STR ) ) return TYPE_PRIORITY;
else if( type.equalsIgnoreCase( TYPE_TIME_STR ) ) return TYPE_TIME;
else if( type.equalsIgnoreCase( TYPE_RELATIVE_TIME_STR ) ) return
TYPE_RELATIVE_TIME;
else if( type.equalsIgnoreCase( TYPE_THROWABLE_STR ) )
{
return TYPE_THROWABLE;
}
else
{
throw new IllegalArgumentException( "Unknown Type in pattern - " +
type );
}
}
/**
* Parse the input pattern and build internal data structures.
*
* @param patternString the pattern
*/
protected void parse( final String patternString )
{
final Stack stack = new Stack();
final int size = patternString.length();
final char pattern[] = new char[ size ];
int index = 0;
patternString.getChars( 0, size, pattern, 0 );
while( index < size )
{
if( pattern[ index ] == '%' &&
!( index != size - 1 && pattern[ index + 1 ] == '%' ) )
{
index += addPatternRun( stack, pattern, index );
}
else
{
index += addTextRun( stack, pattern, index );
}
}
final int elementCount = stack.size();
m_formatSpecification = new PatternRun[ elementCount ];
for( int i = 0; i < elementCount; i++ )
{
m_formatSpecification[ i ] = (PatternRun) stack.elementAt( i );
}
}
/**
* Set the string description that the format is extracted from.
*
* @param format the string format
*/
public void setFormat( final String format )
{
parse( format );
}
}
1.1 xml-cocoon2/src/org/apache/cocoon/util/log/package.html
Index: package.html
===================================================================
<html>
<head>
</head>
<body>
LogKit related utilities.
</body>
----------------------------------------------------------------------
In case of troubles, e-mail: [EMAIL PROTECTED]
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]