1 package org.apache.fulcrum.yaafi.interceptor.logging;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.lang.reflect.Method;
23
24 import org.apache.avalon.framework.activity.Initializable;
25 import org.apache.avalon.framework.configuration.Configuration;
26 import org.apache.avalon.framework.configuration.ConfigurationException;
27 import org.apache.avalon.framework.configuration.Reconfigurable;
28 import org.apache.fulcrum.yaafi.framework.interceptor.AvalonInterceptorContext;
29 import org.apache.fulcrum.yaafi.framework.reflection.Clazz;
30 import org.apache.fulcrum.yaafi.interceptor.baseservice.BaseInterceptorServiceImpl;
31 import org.apache.fulcrum.yaafi.interceptor.util.DefaultToStringBuilderImpl;
32 import org.apache.fulcrum.yaafi.interceptor.util.InterceptorToStringBuilder;
33 import org.apache.fulcrum.yaafi.interceptor.util.MethodToStringBuilderImpl;
34 import org.apache.fulcrum.yaafi.interceptor.util.ArgumentToStringBuilderImpl;
35 import org.apache.fulcrum.yaafi.interceptor.util.StopWatch;
36
37 /**
38 * A service logging of service invocations. The service allows to monitor
39 * a list of services defined in the configuration.
40 *
41 * @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl</a>
42 */
43
44 public class LoggingInterceptorServiceImpl
45 extends BaseInterceptorServiceImpl
46 implements LoggingInterceptorService, Reconfigurable, Initializable
47 {
48 /** the maximum length of a dumped argument */
49 private static final int MAX_ARG_LENGTH = 2000;
50
51 /** seperator for the arguments in the logfile */
52 private static final String SEPERATOR = ";";
53
54 /** maximum argument length for dumping arguments */
55 private int maxArgLength;
56
57 /** the class name of the string builder to use */
58 private String toStringBuilderClassName;
59
60 /** monitor all excpetions independent from the monitored services */
61 private boolean monitorAllExceptions;
62
63 /** the ReflectionToStringBuilder class */
64 private Class toStringBuilderClass;
65
66
67
68
69
70 /**
71 * Constructor
72 */
73 public LoggingInterceptorServiceImpl()
74 {
75 super();
76 this.maxArgLength = MAX_ARG_LENGTH;
77 }
78
79 /**
80 * @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
81 */
82 public void configure(Configuration configuration) throws ConfigurationException
83 {
84 super.configure(configuration);
85
86 this.maxArgLength = configuration.getChild("maxArgLength").getValueAsInteger(MAX_ARG_LENGTH);
87 this.toStringBuilderClassName = configuration.getChild("toStringBuilderClass").getValue(ArgumentToStringBuilderImpl.class.getName());
88 this.monitorAllExceptions = configuration.getChild("monitorAllExceptions").getValueAsBoolean(true);
89 }
90
91 /**
92 * @see org.apache.avalon.framework.activity.Initializable#initialize()
93 */
94 public void initialize() throws Exception
95 {
96
97
98 ClassLoader classLoader = this.getClass().getClassLoader();
99
100 if( Clazz.hasClazz(classLoader, this.getToStringBuilderClassName()) )
101 {
102 this.toStringBuilderClass = Clazz.getClazz(
103 classLoader,
104 this.getToStringBuilderClassName()
105 );
106 }
107
108
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
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
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 }