blob: cb86376a1501edc5c5c330613c520e39513657e9 [file] [log] [blame]
package org.apache.fulcrum.yaafi.interceptor.logging;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import java.lang.reflect.Method;
import org.apache.avalon.framework.activity.Initializable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.configuration.Reconfigurable;
import org.apache.fulcrum.yaafi.framework.interceptor.AvalonInterceptorContext;
import org.apache.fulcrum.yaafi.framework.reflection.Clazz;
import org.apache.fulcrum.yaafi.interceptor.baseservice.BaseInterceptorServiceImpl;
import org.apache.fulcrum.yaafi.interceptor.util.DefaultToStringBuilderImpl;
import org.apache.fulcrum.yaafi.interceptor.util.InterceptorToStringBuilder;
import org.apache.fulcrum.yaafi.interceptor.util.MethodToStringBuilderImpl;
import org.apache.fulcrum.yaafi.interceptor.util.ArgumentToStringBuilderImpl;
import org.apache.fulcrum.yaafi.interceptor.util.StopWatch;
/**
* A service logging of service invocations. The service allows to monitor
* a list of services defined in the configuration.
*
* @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl</a>
*/
public class LoggingInterceptorServiceImpl
extends BaseInterceptorServiceImpl
implements LoggingInterceptorService, Reconfigurable, Initializable
{
/** the maximum length of a dumped argument */
private static final int MAX_ARG_LENGTH = 2000;
/** seperator for the arguments in the logfile */
private static final String SEPERATOR = ";";
/** maximum argument length for dumping arguments */
private int maxArgLength;
/** the class name of the string builder to use */
private String toStringBuilderClassName;
/** monitor all excpetions independent from the monitored services */
private boolean monitorAllExceptions;
/** the ReflectionToStringBuilder class */
private Class toStringBuilderClass;
/////////////////////////////////////////////////////////////////////////
// Avalon Service Lifecycle Implementation
/////////////////////////////////////////////////////////////////////////
/**
* Constructor
*/
public LoggingInterceptorServiceImpl()
{
super();
this.maxArgLength = MAX_ARG_LENGTH;
}
/**
* @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
*/
public void configure(Configuration configuration) throws ConfigurationException
{
super.configure(configuration);
this.maxArgLength = configuration.getChild("maxArgLength").getValueAsInteger(MAX_ARG_LENGTH);
this.toStringBuilderClassName = configuration.getChild("toStringBuilderClass").getValue(ArgumentToStringBuilderImpl.class.getName());
this.monitorAllExceptions = configuration.getChild("monitorAllExceptions").getValueAsBoolean(true);
}
/**
* @see org.apache.avalon.framework.activity.Initializable#initialize()
*/
public void initialize() throws Exception
{
// load the string builder class
ClassLoader classLoader = this.getClass().getClassLoader();
if( Clazz.hasClazz(classLoader, this.getToStringBuilderClassName()) )
{
this.toStringBuilderClass = Clazz.getClazz(
classLoader,
this.getToStringBuilderClassName()
);
}
// create an instance of the StringBuilder to see if everything works
InterceptorToStringBuilder interceptorToStringBuilder = this.createArgumentToStringBuilder(
this
);
interceptorToStringBuilder.toString();
}
/**
* @see org.apache.avalon.framework.configuration.Reconfigurable#reconfigure(org.apache.avalon.framework.configuration.Configuration)
*/
public void reconfigure(Configuration configuration) throws ConfigurationException
{
super.reconfigure(configuration);
this.configure(configuration);
}
/////////////////////////////////////////////////////////////////////////
// Service interface implementation
/////////////////////////////////////////////////////////////////////////
/**
* @see org.apache.fulcrum.yaafi.framework.interceptor.AvalonInterceptorService#onEntry(org.apache.fulcrum.yaafi.framework.interceptor.AvalonInterceptorContext)
*/
public void onEntry(AvalonInterceptorContext interceptorContext)
{
if( this.isServiceMonitored(interceptorContext ) )
{
if( this.getLogger().isInfoEnabled() )
{
String msg = this.toString(interceptorContext,null,ON_ENTRY);
this.getLogger().info(msg);
this.createStopWatch(interceptorContext);
}
}
}
/**
* @see org.apache.fulcrum.yaafi.framework.interceptor.AvalonInterceptorService#onError(org.apache.fulcrum.yaafi.framework.interceptor.AvalonInterceptorContext, java.lang.Throwable)
*/
public void onError(AvalonInterceptorContext interceptorContext,Throwable t)
{
if( this.getLogger().isErrorEnabled() )
{
if( this.isMonitorAllExceptions() || this.isServiceMonitored(interceptorContext) )
{
StopWatch stopWatch = this.getStopWatch(interceptorContext);
stopWatch.stop();
String msg = this.toString(interceptorContext, stopWatch, t);
this.getLogger().error(msg);
}
}
}
/**
* @see org.apache.fulcrum.yaafi.framework.interceptor.AvalonInterceptorService#onExit(org.apache.fulcrum.yaafi.framework.interceptor.AvalonInterceptorContext, java.lang.Object)
*/
public void onExit(AvalonInterceptorContext interceptorContext, Object result)
{
if( this.isServiceMonitored(interceptorContext) )
{
if( this.getLogger().isDebugEnabled() )
{
StopWatch stopWatch = this.getStopWatch(interceptorContext);
stopWatch.stop();
String msg = this.toString(interceptorContext, stopWatch, result);
this.getLogger().debug(msg);
}
}
}
/////////////////////////////////////////////////////////////////////////
// Service Implementation
/////////////////////////////////////////////////////////////////////////
/**
* Creates a stop watch
*
* @param interceptorContext the current interceptor context
*/
protected void createStopWatch(
AvalonInterceptorContext interceptorContext )
{
StopWatch stopWatch = new StopWatch();
stopWatch.start();
interceptorContext.getRequestContext().put(this.getServiceName(),stopWatch);
}
/**
* Gets the stop watch. Even if none is defined we return one
* in a proper state.
*
* @param interceptorContext the current interceptor context
* @return the stop watch
*/
protected StopWatch getStopWatch(
AvalonInterceptorContext interceptorContext )
{
StopWatch result = (StopWatch) interceptorContext.getRequestContext().remove(
this.getServiceName()
);
if( result == null )
{
result = new StopWatch();
result.start();
}
return result;
}
/**
* @return Returns the maxLineLength.
*/
protected int getMaxArgLength()
{
return maxArgLength;
}
/**
* @return Returns the monitorAllExceptions.
*/
protected boolean isMonitorAllExceptions()
{
return monitorAllExceptions;
}
/**
* @return Returns the toStringBuilderClass.
*/
protected Class getToStringBuilderClass()
{
return toStringBuilderClass;
}
/**
* @return Returns the toStringBuilderClassName.
*/
protected String getToStringBuilderClassName()
{
return toStringBuilderClassName;
}
/**
* Create an instance of an InterceptorToStringBuilder
*
* @param target the object to stringify
* @return the string builder
*/
protected InterceptorToStringBuilder createArgumentToStringBuilder(Object target)
{
InterceptorToStringBuilder result = null;
try
{
result = (InterceptorToStringBuilder)
this.getToStringBuilderClass().newInstance();
}
catch (Exception e)
{
String msg = "Unable to create an instance for " + this.getToStringBuilderClassName();
this.getLogger().error(msg,e);
result = new DefaultToStringBuilderImpl();
}
result.setTarget(target);
result.setMaxArgLength(this.getMaxArgLength());
result.setMode(1);
return result;
}
/**
* Create a string representation of a service invocation returning a result.
*
* @param avalonInterceptorContext the interceptor context
* @param stopWatch the stopwatch for the execution time
* @param result the result of the service invocation
* @return the string representation of the result
*/
protected String toString(
AvalonInterceptorContext avalonInterceptorContext,
StopWatch stopWatch,
Object result )
{
StringBuilder methodSignature = new StringBuilder();
InterceptorToStringBuilder toStringBuilder = this.createArgumentToStringBuilder(result);
methodSignature.append( this.toString(avalonInterceptorContext, stopWatch, ON_EXIT) );
methodSignature.append(SEPERATOR);
methodSignature.append( "result={" );
methodSignature.append( toStringBuilder.toString() );
methodSignature.append( "}" );
return methodSignature.toString();
}
/**
* Create a string representation of a service invocation throwing a Throwable
*
* @param avalonInterceptorContext the interceptor context
* @param stopWatch the stopwatch for the execution time
* @param throwable the result of the service invocation
* @return the string representation of the result
*/
protected String toString(
AvalonInterceptorContext avalonInterceptorContext,
StopWatch stopWatch,
Throwable throwable )
{
StringBuilder methodSignature = new StringBuilder();
InterceptorToStringBuilder toStringBuilder = this.createArgumentToStringBuilder(throwable);
methodSignature.append( this.toString(avalonInterceptorContext, stopWatch, ON_ERROR) );
methodSignature.append(SEPERATOR);
methodSignature.append( throwable.getClass().getName() );
methodSignature.append(SEPERATOR);
methodSignature.append( toStringBuilder.toString() );
return methodSignature.toString();
}
/**
* Create a method signature.
*
* @param interceptorContext the avalonInterceptorContext
* @param stopWatch the stopwatch for the execution time
* @param mode the mode (onEntry, onExit, onError)
* @return the debug output
*/
protected String toString(
AvalonInterceptorContext interceptorContext, StopWatch stopWatch, int mode )
{
StringBuilder result = new StringBuilder();
Method method = interceptorContext.getMethod();
Object[] args = interceptorContext.getArgs();
InterceptorToStringBuilder toStringBuilder = null;
MethodToStringBuilderImpl methodToStringBuilder = new MethodToStringBuilderImpl(method);
if( args == null )
{
args = new Object[0];
}
result.append(interceptorContext.getTransactionId());
result.append(SEPERATOR);
result.append(interceptorContext.getInvocationId());
result.append(SEPERATOR);
result.append(interceptorContext.getInvocationDepth());
result.append(SEPERATOR);
result.append(mode);
result.append(SEPERATOR);
result.append(interceptorContext.getServiceShorthand());
result.append(SEPERATOR);
result.append(method.getName());
result.append(SEPERATOR);
if( stopWatch != null )
{
result.append(stopWatch.getTime());
}
else
{
result.append('0');
}
result.append(SEPERATOR);
result.append(methodToStringBuilder.toString());
if( (ON_ENTRY == mode) || (ON_ERROR == mode) )
{
for( int i=0; i<args.length; i++ )
{
toStringBuilder = this.createArgumentToStringBuilder(args[i]);
result.append(SEPERATOR);
result.append("arg[" + i + "]:={");
result.append( toStringBuilder.toString());
result.append("}");
}
}
return result.toString();
}
}