001 package org.apache.fulcrum.yaafi.interceptor.logging; 002 003 /* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022 import java.lang.reflect.Method; 023 024 import org.apache.avalon.framework.activity.Initializable; 025 import org.apache.avalon.framework.configuration.Configuration; 026 import org.apache.avalon.framework.configuration.ConfigurationException; 027 import org.apache.avalon.framework.configuration.Reconfigurable; 028 import org.apache.fulcrum.yaafi.framework.interceptor.AvalonInterceptorContext; 029 import org.apache.fulcrum.yaafi.framework.reflection.Clazz; 030 import org.apache.fulcrum.yaafi.interceptor.baseservice.BaseInterceptorServiceImpl; 031 import org.apache.fulcrum.yaafi.interceptor.util.DefaultToStringBuilderImpl; 032 import org.apache.fulcrum.yaafi.interceptor.util.InterceptorToStringBuilder; 033 import org.apache.fulcrum.yaafi.interceptor.util.MethodToStringBuilderImpl; 034 import org.apache.fulcrum.yaafi.interceptor.util.ArgumentToStringBuilderImpl; 035 import org.apache.fulcrum.yaafi.interceptor.util.StopWatch; 036 037 /** 038 * A service logging of service invocations. The service allows to monitor 039 * a list of services defined in the configuration. 040 * 041 * @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl</a> 042 */ 043 044 public class LoggingInterceptorServiceImpl 045 extends BaseInterceptorServiceImpl 046 implements LoggingInterceptorService, Reconfigurable, Initializable 047 { 048 /** the maximum length of a dumped argument */ 049 private static final int MAX_ARG_LENGTH = 2000; 050 051 /** seperator for the arguments in the logfile */ 052 private static final String SEPERATOR = ";"; 053 054 /** maximum argument length for dumping arguments */ 055 private int maxArgLength; 056 057 /** the class name of the string builder to use */ 058 private String toStringBuilderClassName; 059 060 /** monitor all excpetions independent from the monitored services */ 061 private boolean monitorAllExceptions; 062 063 /** the ReflectionToStringBuilder class */ 064 private Class toStringBuilderClass; 065 066 ///////////////////////////////////////////////////////////////////////// 067 // Avalon Service Lifecycle Implementation 068 ///////////////////////////////////////////////////////////////////////// 069 070 /** 071 * Constructor 072 */ 073 public LoggingInterceptorServiceImpl() 074 { 075 super(); 076 this.maxArgLength = MAX_ARG_LENGTH; 077 } 078 079 /** 080 * @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration) 081 */ 082 public void configure(Configuration configuration) throws ConfigurationException 083 { 084 super.configure(configuration); 085 086 this.maxArgLength = configuration.getChild("maxArgLength").getValueAsInteger(MAX_ARG_LENGTH); 087 this.toStringBuilderClassName = configuration.getChild("toStringBuilderClass").getValue(ArgumentToStringBuilderImpl.class.getName()); 088 this.monitorAllExceptions = configuration.getChild("monitorAllExceptions").getValueAsBoolean(true); 089 } 090 091 /** 092 * @see org.apache.avalon.framework.activity.Initializable#initialize() 093 */ 094 public void initialize() throws Exception 095 { 096 // load the string builder class 097 098 ClassLoader classLoader = this.getClass().getClassLoader(); 099 100 if( Clazz.hasClazz(classLoader, this.getToStringBuilderClassName()) ) 101 { 102 this.toStringBuilderClass = Clazz.getClazz( 103 classLoader, 104 this.getToStringBuilderClassName() 105 ); 106 } 107 108 // create an instance of the StringBuilder to see if everything works 109 110 InterceptorToStringBuilder interceptorToStringBuilder = this.createArgumentToStringBuilder( 111 this 112 ); 113 114 interceptorToStringBuilder.toString(); 115 } 116 117 /** 118 * @see org.apache.avalon.framework.configuration.Reconfigurable#reconfigure(org.apache.avalon.framework.configuration.Configuration) 119 */ 120 public void reconfigure(Configuration configuration) throws ConfigurationException 121 { 122 super.reconfigure(configuration); 123 this.configure(configuration); 124 } 125 126 ///////////////////////////////////////////////////////////////////////// 127 // Service interface implementation 128 ///////////////////////////////////////////////////////////////////////// 129 130 /** 131 * @see org.apache.fulcrum.yaafi.framework.interceptor.AvalonInterceptorService#onEntry(org.apache.fulcrum.yaafi.framework.interceptor.AvalonInterceptorContext) 132 */ 133 public void onEntry(AvalonInterceptorContext interceptorContext) 134 { 135 if( this.isServiceMonitored(interceptorContext ) ) 136 { 137 if( this.getLogger().isInfoEnabled() ) 138 { 139 String msg = this.toString(interceptorContext,null,ON_ENTRY); 140 this.getLogger().info(msg); 141 this.createStopWatch(interceptorContext); 142 } 143 } 144 } 145 146 /** 147 * @see org.apache.fulcrum.yaafi.framework.interceptor.AvalonInterceptorService#onError(org.apache.fulcrum.yaafi.framework.interceptor.AvalonInterceptorContext, java.lang.Throwable) 148 */ 149 public void onError(AvalonInterceptorContext interceptorContext,Throwable t) 150 { 151 if( this.getLogger().isErrorEnabled() ) 152 { 153 if( this.isMonitorAllExceptions() || this.isServiceMonitored(interceptorContext) ) 154 { 155 StopWatch stopWatch = this.getStopWatch(interceptorContext); 156 stopWatch.stop(); 157 String msg = this.toString(interceptorContext, stopWatch, t); 158 this.getLogger().error(msg); 159 } 160 } 161 } 162 163 /** 164 * @see org.apache.fulcrum.yaafi.framework.interceptor.AvalonInterceptorService#onExit(org.apache.fulcrum.yaafi.framework.interceptor.AvalonInterceptorContext, java.lang.Object) 165 */ 166 public void onExit(AvalonInterceptorContext interceptorContext, Object result) 167 { 168 if( this.isServiceMonitored(interceptorContext) ) 169 { 170 if( this.getLogger().isDebugEnabled() ) 171 { 172 StopWatch stopWatch = this.getStopWatch(interceptorContext); 173 stopWatch.stop(); 174 String msg = this.toString(interceptorContext, stopWatch, result); 175 this.getLogger().debug(msg); 176 } 177 } 178 } 179 180 ///////////////////////////////////////////////////////////////////////// 181 // Service Implementation 182 ///////////////////////////////////////////////////////////////////////// 183 184 /** 185 * Creates a stop watch 186 * 187 * @param interceptorContext the current interceptor context 188 */ 189 protected void createStopWatch( 190 AvalonInterceptorContext interceptorContext ) 191 { 192 StopWatch stopWatch = new StopWatch(); 193 stopWatch.start(); 194 interceptorContext.getRequestContext().put(this.getServiceName(),stopWatch); 195 } 196 197 /** 198 * Gets the stop watch. Even if none is defined we return one 199 * in a proper state. 200 * 201 * @param interceptorContext the current interceptor context 202 * @return the stop watch 203 */ 204 protected StopWatch getStopWatch( 205 AvalonInterceptorContext interceptorContext ) 206 { 207 StopWatch result = (StopWatch) interceptorContext.getRequestContext().remove( 208 this.getServiceName() 209 ); 210 211 if( result == null ) 212 { 213 result = new StopWatch(); 214 result.start(); 215 } 216 217 return result; 218 } 219 220 /** 221 * @return Returns the maxLineLength. 222 */ 223 protected int getMaxArgLength() 224 { 225 return maxArgLength; 226 } 227 228 /** 229 * @return Returns the monitorAllExceptions. 230 */ 231 protected boolean isMonitorAllExceptions() 232 { 233 return monitorAllExceptions; 234 } 235 236 /** 237 * @return Returns the toStringBuilderClass. 238 */ 239 protected Class getToStringBuilderClass() 240 { 241 return toStringBuilderClass; 242 } 243 244 /** 245 * @return Returns the toStringBuilderClassName. 246 */ 247 protected String getToStringBuilderClassName() 248 { 249 return toStringBuilderClassName; 250 } 251 252 /** 253 * Create an instance of an InterceptorToStringBuilder 254 * 255 * @param target the object to stringify 256 * @return the string builder 257 */ 258 protected InterceptorToStringBuilder createArgumentToStringBuilder(Object target) 259 { 260 InterceptorToStringBuilder result = null; 261 262 try 263 { 264 result = (InterceptorToStringBuilder) 265 this.getToStringBuilderClass().newInstance(); 266 } 267 catch (Exception e) 268 { 269 String msg = "Unable to create an instance for " + this.getToStringBuilderClassName(); 270 this.getLogger().error(msg,e); 271 result = new DefaultToStringBuilderImpl(); 272 } 273 274 result.setTarget(target); 275 result.setMaxArgLength(this.getMaxArgLength()); 276 result.setMode(1); 277 278 return result; 279 } 280 281 /** 282 * Create a string representation of a service invocation returning a result. 283 * 284 * @param avalonInterceptorContext the interceptor context 285 * @param stopWatch the stopwatch for the execution time 286 * @param result the result of the service invocation 287 * @return the string representation of the result 288 */ 289 protected String toString( 290 AvalonInterceptorContext avalonInterceptorContext, 291 StopWatch stopWatch, 292 Object result ) 293 { 294 StringBuffer methodSignature = new StringBuffer(); 295 InterceptorToStringBuilder toStringBuilder = this.createArgumentToStringBuilder(result); 296 297 methodSignature.append( this.toString(avalonInterceptorContext, stopWatch, ON_EXIT) ); 298 methodSignature.append(SEPERATOR); 299 methodSignature.append( "result={" ); 300 methodSignature.append( toStringBuilder.toString() ); 301 methodSignature.append( "}" ); 302 303 return methodSignature.toString(); 304 } 305 306 /** 307 * Create a string representation of a service invocation throwing a Throwable 308 * 309 * @param avalonInterceptorContext the interceptor context 310 * @param stopWatch the stopwatch for the execution time 311 * @param throwable the result of the service invocation 312 * @return the string representation of the result 313 */ 314 protected String toString( 315 AvalonInterceptorContext avalonInterceptorContext, 316 StopWatch stopWatch, 317 Throwable throwable ) 318 { 319 StringBuffer methodSignature = new StringBuffer(); 320 InterceptorToStringBuilder toStringBuilder = this.createArgumentToStringBuilder(throwable); 321 322 methodSignature.append( this.toString(avalonInterceptorContext, stopWatch, ON_ERROR) ); 323 methodSignature.append(SEPERATOR); 324 methodSignature.append( throwable.getClass().getName() ); 325 methodSignature.append(SEPERATOR); 326 methodSignature.append( toStringBuilder.toString() ); 327 328 return methodSignature.toString(); 329 } 330 331 /** 332 * Create a method signature. 333 * 334 * @param interceptorContext the avalonInterceptorContext 335 * @param stopWatch the stopwatch for the execution time 336 * @param mode the mode (onEntry, onExit, onError) 337 * @return the debug output 338 */ 339 protected String toString( 340 AvalonInterceptorContext interceptorContext, StopWatch stopWatch, int mode ) 341 { 342 StringBuffer result = new StringBuffer(); 343 Method method = interceptorContext.getMethod(); 344 Object[] args = interceptorContext.getArgs(); 345 InterceptorToStringBuilder toStringBuilder = null; 346 MethodToStringBuilderImpl methodToStringBuilder = new MethodToStringBuilderImpl(method); 347 348 if( args == null ) 349 { 350 args = new Object[0]; 351 } 352 353 result.append(interceptorContext.getTransactionId()); 354 result.append(SEPERATOR); 355 result.append(interceptorContext.getInvocationId()); 356 result.append(SEPERATOR); 357 result.append(interceptorContext.getInvocationDepth()); 358 result.append(SEPERATOR); 359 result.append(mode); 360 result.append(SEPERATOR); 361 result.append(interceptorContext.getServiceShorthand()); 362 result.append(SEPERATOR); 363 result.append(method.getName()); 364 result.append(SEPERATOR); 365 366 if( stopWatch != null ) 367 { 368 result.append(stopWatch.getTime()); 369 } 370 else 371 { 372 result.append('0'); 373 } 374 375 result.append(SEPERATOR); 376 result.append(methodToStringBuilder.toString()); 377 378 if( (ON_ENTRY == mode) || (ON_ERROR == mode) ) 379 { 380 for( int i=0; i<args.length; i++ ) 381 { 382 toStringBuilder = this.createArgumentToStringBuilder(args[i]); 383 result.append(SEPERATOR); 384 result.append("arg[" + i + "]:={"); 385 result.append( toStringBuilder.toString()); 386 result.append("}"); 387 } 388 } 389 390 return result.toString(); 391 } 392 }