View Javadoc

1   package org.apache.fulcrum.yaafi.interceptor.logging;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
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      // Avalon Service Lifecycle Implementation
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          // load the string builder class
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         // 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 }