001    package org.apache.fulcrum.yaafi.interceptor.performance;
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.configuration.Configuration;
025    import org.apache.avalon.framework.configuration.ConfigurationException;
026    import org.apache.avalon.framework.configuration.Reconfigurable;
027    import org.apache.avalon.framework.context.Contextualizable;
028    import org.apache.avalon.framework.thread.ThreadSafe;
029    import org.apache.fulcrum.yaafi.framework.interceptor.AvalonInterceptorContext;
030    import org.apache.fulcrum.yaafi.interceptor.baseservice.BaseInterceptorServiceImpl;
031    import org.apache.fulcrum.yaafi.interceptor.util.ArgumentToStringBuilderImpl;
032    import org.apache.fulcrum.yaafi.interceptor.util.MethodToStringBuilderImpl;
033    import org.apache.fulcrum.yaafi.interceptor.util.StopWatch;
034    
035    /**
036     * A service logging the execution time of service invocations.
037     *
038     * @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl</a>
039     */
040    
041    public class PerformanceInterceptorServiceImpl
042        extends BaseInterceptorServiceImpl
043        implements PerformanceInterceptorService, Reconfigurable, Contextualizable, ThreadSafe
044    {
045              /** the maximum length of a dumped argument */
046              private static final int MAX_ARG_LENGTH = 100;
047    
048        /** default length of the StringBuffer */
049        private static final int BUFFER_LENGTH = 2000;
050    
051        /** seperator for the arguments in the logfile */
052        private static final String SEPERATOR = ";";
053    
054        /** the tresholds in milliseconds to determine the loglevel */
055        private int[] tresholdList;
056    
057        /** maximum argument length for dumping arguments */
058        private int maxArgLength;
059    
060        /////////////////////////////////////////////////////////////////////////
061        // Avalon Service Lifecycle Implementation
062        /////////////////////////////////////////////////////////////////////////
063    
064        /**
065         * Constructor
066         */
067        public PerformanceInterceptorServiceImpl()
068        {
069            super();
070            this.tresholdList = new int[5];
071        }
072    
073        /**
074         * @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
075         */
076        public void configure(Configuration configuration) throws ConfigurationException
077        {
078            super.configure(configuration);
079    
080            this.maxArgLength = configuration.getChild("maxArgLength").getValueAsInteger(MAX_ARG_LENGTH);
081            Configuration tresholdConfiguration = configuration.getChild("tresholds");
082            this.tresholdList[0] = tresholdConfiguration.getChild("fatal").getAttributeAsInteger("millis", 5000);
083            this.tresholdList[1] = tresholdConfiguration.getChild("error").getAttributeAsInteger("millis", 1000);
084            this.tresholdList[2] = tresholdConfiguration.getChild("warn").getAttributeAsInteger("millis", 500);
085            this.tresholdList[3] = tresholdConfiguration.getChild("info").getAttributeAsInteger("millis", 100);
086            this.tresholdList[4] = tresholdConfiguration.getChild("debug").getAttributeAsInteger("millis", 10);
087        }
088    
089        /**
090         * @see org.apache.avalon.framework.configuration.Reconfigurable#reconfigure(org.apache.avalon.framework.configuration.Configuration)
091         */
092        public void reconfigure(Configuration configuration) throws ConfigurationException
093        {
094            super.reconfigure(configuration);
095            this.configure(configuration);
096        }
097    
098        /////////////////////////////////////////////////////////////////////////
099        // Service interface implementation
100        /////////////////////////////////////////////////////////////////////////
101    
102        /**
103         * @see org.apache.fulcrum.yaafi.framework.interceptor.AvalonInterceptorService#onEntry(org.apache.fulcrum.yaafi.framework.interceptor.AvalonInterceptorContext)
104         */
105        public void onEntry(AvalonInterceptorContext interceptorContext)
106        {
107            if( this.isServiceMonitored(interceptorContext ) )
108            {
109                this.createStopWatch(interceptorContext);
110            }
111        }
112    
113        /**
114         * @see org.apache.fulcrum.yaafi.framework.interceptor.AvalonInterceptorService#onError(org.apache.fulcrum.yaafi.framework.interceptor.AvalonInterceptorContext, java.lang.Throwable)
115         */
116        public void onError(AvalonInterceptorContext interceptorContext,Throwable t)
117        {
118            if( this.isServiceMonitored(interceptorContext) )
119            {
120                StopWatch stopWatch = this.getStopWatch(interceptorContext);
121                stopWatch.stop();
122                this.log( ON_ERROR, interceptorContext, stopWatch );
123            }
124        }
125    
126        /**
127         * @see org.apache.fulcrum.yaafi.framework.interceptor.AvalonInterceptorService#onExit(org.apache.fulcrum.yaafi.framework.interceptor.AvalonInterceptorContext, java.lang.Object)
128         */
129        public void onExit(AvalonInterceptorContext interceptorContext, Object result)
130        {
131            if( this.isServiceMonitored(interceptorContext) )
132            {
133                if( this.isServiceMonitored(interceptorContext) )
134                {
135                    StopWatch stopWatch = this.getStopWatch(interceptorContext);
136                    stopWatch.stop();
137                    this.log( ON_EXIT, interceptorContext, stopWatch );
138                }
139            }
140        }
141    
142        /////////////////////////////////////////////////////////////////////////
143        // Service Implementation
144        /////////////////////////////////////////////////////////////////////////
145    
146        /**
147         * Creates a stop watch
148         *
149         * @param interceptorContext the current interceptor context
150         */
151        protected void createStopWatch(
152            AvalonInterceptorContext interceptorContext )
153        {
154            StopWatch stopWatch = new StopWatch();
155            stopWatch.start();
156            interceptorContext.getRequestContext().put(this.getServiceName(),stopWatch);
157        }
158    
159        /**
160         * Gets the stop watch
161         *
162         * @param interceptorContext the current interceptor context
163         * @return the stop watch
164         */
165        protected StopWatch getStopWatch(
166            AvalonInterceptorContext interceptorContext )
167        {
168            return (StopWatch) interceptorContext.getRequestContext().remove(
169                this.getServiceName()
170                );
171        }
172    
173        /**
174         * Logs the execution time.
175         *
176         * @param mode the invocation mode (onEntry, onExit, onError)
177         * @param interceptorContext the current interceptor context
178         * @param stopWatch the stop watch
179         */
180        protected void log(
181            int mode,
182            AvalonInterceptorContext interceptorContext,
183            StopWatch stopWatch
184            )
185        {
186            String msg = null;
187            long time = stopWatch.getTime();
188    
189            if( time >= tresholdList[0] )
190            {
191                if( this.getLogger().isFatalErrorEnabled() )
192                {
193                        msg = this.toString(interceptorContext,stopWatch,mode);
194                        this.getLogger().fatalError(msg);
195                }
196            }
197            else if( time >= tresholdList[1] )
198            {
199                if( this.getLogger().isErrorEnabled() )
200                {
201                        msg = this.toString(interceptorContext,stopWatch,mode);
202                        this.getLogger().error(msg);
203                }
204            }
205            else if( time >= tresholdList[2] )
206            {
207                if( this.getLogger().isWarnEnabled() )
208                {
209                        msg = this.toString(interceptorContext,stopWatch,mode);
210                        this.getLogger().warn(msg);
211                }
212            }
213            else if( time >= tresholdList[3] )
214            {
215                if( this.getLogger().isInfoEnabled() )
216                {
217                        msg = this.toString(interceptorContext,stopWatch,mode);
218                        this.getLogger().info(msg);
219                }
220            }
221            else if( time >= tresholdList[4] )
222            {
223                if( this.getLogger().isDebugEnabled() )
224                {
225                        msg = this.toString(interceptorContext,stopWatch,mode);
226                        this.getLogger().debug(msg);
227                }
228            }
229        }
230    
231        /**
232         * Create the log message for the performance logfile.
233         *
234         * @param interceptorContext the context
235         * @param stopWatch the stopwatch
236         * @param mode the mode (onEntry, onExit, onError)
237         * @return the log message
238         */
239        protected String toString(
240            AvalonInterceptorContext interceptorContext,
241            StopWatch stopWatch,
242            int mode
243            )
244        {
245            Method method = interceptorContext.getMethod();
246            Object[] args = interceptorContext.getArgs();
247            MethodToStringBuilderImpl methodToStringBuilder = new MethodToStringBuilderImpl(method);
248            StringBuffer result = new StringBuffer(BUFFER_LENGTH);
249    
250            result.append(interceptorContext.getTransactionId());
251            result.append(SEPERATOR);
252            result.append(interceptorContext.getInvocationId());
253            result.append(SEPERATOR);
254            result.append(interceptorContext.getInvocationDepth());
255            result.append(SEPERATOR);
256            result.append(mode);
257            result.append(SEPERATOR);
258            result.append(interceptorContext.getServiceShorthand());
259            result.append(SEPERATOR);
260            result.append(method.getName());
261            result.append(SEPERATOR);
262            result.append(stopWatch.getTime());
263            result.append(SEPERATOR);
264            result.append(methodToStringBuilder.toString());
265            result.append(SEPERATOR);
266            result.append(this.toString(args));
267    
268            return result.toString();
269        }
270    
271        /**
272         * Prints the argument list.
273         *
274         * @return the debug output
275         */
276        protected String toString( Object[] args )
277        {
278            StringBuffer result = new StringBuffer();
279            ArgumentToStringBuilderImpl toStringBuilder = null;
280    
281            if( args == null )
282            {
283                args = new Object[0];
284            }
285    
286            for( int i=0; i<args.length; i++ )
287            {
288                toStringBuilder = new ArgumentToStringBuilderImpl(args[i],this.maxArgLength,1);
289                result.append("arg[" + i + "]:={");
290                result.append( toStringBuilder.toString());
291                result.append("}");
292    
293                if( i<args.length-1)
294                {
295                            result.append(SEPERATOR);
296                }
297            }
298    
299            return result.toString();
300        }
301    
302    }