View Javadoc
1   package org.apache.fulcrum.yaafi.interceptor.performance;
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.configuration.Configuration;
25  import org.apache.avalon.framework.configuration.ConfigurationException;
26  import org.apache.avalon.framework.configuration.Reconfigurable;
27  import org.apache.avalon.framework.context.Contextualizable;
28  import org.apache.avalon.framework.thread.ThreadSafe;
29  import org.apache.fulcrum.yaafi.framework.interceptor.AvalonInterceptorContext;
30  import org.apache.fulcrum.yaafi.interceptor.baseservice.BaseInterceptorServiceImpl;
31  import org.apache.fulcrum.yaafi.interceptor.util.ArgumentToStringBuilderImpl;
32  import org.apache.fulcrum.yaafi.interceptor.util.MethodToStringBuilderImpl;
33  import org.apache.fulcrum.yaafi.interceptor.util.StopWatch;
34  
35  /**
36   * A service logging the execution time of service invocations.
37   *
38   * @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl</a>
39   */
40  
41  public class PerformanceInterceptorServiceImpl extends BaseInterceptorServiceImpl
42  		implements PerformanceInterceptorService, Reconfigurable, Contextualizable, ThreadSafe {
43  	/** the maximum length of a dumped argument */
44  	private static final int MAX_ARG_LENGTH = 100;
45  
46  	/** default length of the StringBuilder */
47  	private static final int BUFFER_LENGTH = 2000;
48  
49  	/** seperator for the arguments in the logfile */
50  	private static final String SEPERATOR = ";";
51  
52  	/** the tresholds in milliseconds to determine the loglevel */
53  	private int[] tresholdList;
54  
55  	/** maximum argument length for dumping arguments */
56  	private int maxArgLength;
57  
58  	/////////////////////////////////////////////////////////////////////////
59  	// Avalon Service Lifecycle Implementation
60  	/////////////////////////////////////////////////////////////////////////
61  
62  	/**
63  	 * Constructor
64  	 */
65  	public PerformanceInterceptorServiceImpl() {
66  		super();
67  		this.tresholdList = new int[5];
68  	}
69  
70  	/**
71  	 * @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
72  	 */
73  	public void configure(Configuration configuration) throws ConfigurationException {
74  		super.configure(configuration);
75  
76  		this.maxArgLength = configuration.getChild("maxArgLength").getValueAsInteger(MAX_ARG_LENGTH);
77  		Configuration tresholdConfiguration = configuration.getChild("tresholds");
78  		this.tresholdList[0] = tresholdConfiguration.getChild("fatal").getAttributeAsInteger("millis", 5000);
79  		this.tresholdList[1] = tresholdConfiguration.getChild("error").getAttributeAsInteger("millis", 1000);
80  		this.tresholdList[2] = tresholdConfiguration.getChild("warn").getAttributeAsInteger("millis", 500);
81  		this.tresholdList[3] = tresholdConfiguration.getChild("info").getAttributeAsInteger("millis", 100);
82  		this.tresholdList[4] = tresholdConfiguration.getChild("debug").getAttributeAsInteger("millis", 10);
83  	}
84  
85  	/**
86  	 * @see org.apache.avalon.framework.configuration.Reconfigurable#reconfigure(org.apache.avalon.framework.configuration.Configuration)
87  	 */
88  	public void reconfigure(Configuration configuration) throws ConfigurationException {
89  		super.reconfigure(configuration);
90  		this.configure(configuration);
91  	}
92  
93  	/////////////////////////////////////////////////////////////////////////
94  	// Service interface implementation
95  	/////////////////////////////////////////////////////////////////////////
96  
97  	/*
98  	 * (non-Javadoc)
99  	 * 
100 	 * @see
101 	 * org.apache.fulcrum.yaafi.interceptor.baseservice.BaseInterceptorServiceImpl#
102 	 * onEntry(org.apache.fulcrum.yaafi.framework.interceptor.
103 	 * AvalonInterceptorContext)
104 	 */
105 	public void onEntry(AvalonInterceptorContext interceptorContext) {
106 		if (this.isServiceMonitored(interceptorContext)) {
107 			this.createStopWatch(interceptorContext);
108 		}
109 	}
110 
111 	/*
112 	 * (non-Javadoc)
113 	 * 
114 	 * @see
115 	 * org.apache.fulcrum.yaafi.interceptor.baseservice.BaseInterceptorServiceImpl#
116 	 * onError(org.apache.fulcrum.yaafi.framework.interceptor.
117 	 * AvalonInterceptorContext, java.lang.Throwable)
118 	 */
119 	public void onError(AvalonInterceptorContext interceptorContext, Throwable t) {
120 		if (this.isServiceMonitored(interceptorContext)) {
121 			StopWatch stopWatch = this.getStopWatch(interceptorContext);
122 			stopWatch.stop();
123 			this.log(ON_ERROR, interceptorContext, stopWatch);
124 		}
125 	}
126 
127 	/*
128 	 * (non-Javadoc)
129 	 * 
130 	 * @see
131 	 * org.apache.fulcrum.yaafi.interceptor.baseservice.BaseInterceptorServiceImpl#
132 	 * onExit(org.apache.fulcrum.yaafi.framework.interceptor.
133 	 * AvalonInterceptorContext, java.lang.Object)
134 	 */
135 	public void onExit(AvalonInterceptorContext interceptorContext, Object result) {
136 		if (this.isServiceMonitored(interceptorContext)) {
137 			StopWatch stopWatch = this.getStopWatch(interceptorContext);
138 			stopWatch.stop();
139 			this.log(ON_EXIT, interceptorContext, stopWatch);
140 		}
141 	}
142 
143 	/////////////////////////////////////////////////////////////////////////
144 	// Service Implementation
145 	/////////////////////////////////////////////////////////////////////////
146 
147 	/**
148 	 * Creates a stop watch
149 	 *
150 	 * @param interceptorContext the current interceptor context
151 	 */
152 	protected void createStopWatch(AvalonInterceptorContext interceptorContext) {
153 		StopWatch stopWatch = new StopWatch();
154 		stopWatch.start();
155 		interceptorContext.getRequestContext().put(this.getServiceName(), stopWatch);
156 	}
157 
158 	/**
159 	 * Gets the stop watch
160 	 *
161 	 * @param interceptorContext the current interceptor context
162 	 * @return the stop watch
163 	 */
164 	protected StopWatch getStopWatch(AvalonInterceptorContext interceptorContext) {
165 		return (StopWatch) interceptorContext.getRequestContext().remove(this.getServiceName());
166 	}
167 
168 	/**
169 	 * Logs the execution time.
170 	 *
171 	 * @param mode               the invocation mode (onEntry, onExit, onError)
172 	 * @param interceptorContext the current interceptor context
173 	 * @param stopWatch          the stop watch
174 	 */
175 	protected void log(int mode, AvalonInterceptorContext interceptorContext, StopWatch stopWatch) {
176 		String msg = null;
177 		long time = stopWatch.getTime();
178 
179 		if (time >= tresholdList[0]) {
180 			if (this.getLogger().isFatalErrorEnabled()) {
181 				msg = this.toString(interceptorContext, stopWatch, mode);
182 				this.getLogger().fatalError(msg);
183 			}
184 		} else if (time >= tresholdList[1]) {
185 			if (this.getLogger().isErrorEnabled()) {
186 				msg = this.toString(interceptorContext, stopWatch, mode);
187 				this.getLogger().error(msg);
188 			}
189 		} else if (time >= tresholdList[2]) {
190 			if (this.getLogger().isWarnEnabled()) {
191 				msg = this.toString(interceptorContext, stopWatch, mode);
192 				this.getLogger().warn(msg);
193 			}
194 		} else if (time >= tresholdList[3]) {
195 			if (this.getLogger().isInfoEnabled()) {
196 				msg = this.toString(interceptorContext, stopWatch, mode);
197 				this.getLogger().info(msg);
198 			}
199 		} else if (time >= tresholdList[4] && this.getLogger().isDebugEnabled() == true) {
200 			msg = this.toString(interceptorContext, stopWatch, mode);
201 			this.getLogger().debug(msg);
202 		}
203 	}
204 
205 	/**
206 	 * Create the log message for the performance logfile.
207 	 *
208 	 * @param interceptorContext the context
209 	 * @param stopWatch          the stopwatch
210 	 * @param mode               the mode (onEntry, onExit, onError)
211 	 * @return the log message
212 	 */
213 	protected String toString(AvalonInterceptorContext interceptorContext, StopWatch stopWatch, int mode) {
214 		Method method = interceptorContext.getMethod();
215 		Object[] args = interceptorContext.getArgs();
216 		MethodToStringBuilderImpl methodToStringBuilder = new MethodToStringBuilderImpl(method);
217 		StringBuilder result = new StringBuilder(BUFFER_LENGTH);
218 
219 		result.append(interceptorContext.getTransactionId());
220 		result.append(SEPERATOR);
221 		result.append(interceptorContext.getInvocationId());
222 		result.append(SEPERATOR);
223 		result.append(interceptorContext.getInvocationDepth());
224 		result.append(SEPERATOR);
225 		result.append(mode);
226 		result.append(SEPERATOR);
227 		result.append(interceptorContext.getServiceShorthand());
228 		result.append(SEPERATOR);
229 		result.append(method.getName());
230 		result.append(SEPERATOR);
231 		result.append(stopWatch.getTime());
232 		result.append(SEPERATOR);
233 		result.append(methodToStringBuilder.toString());
234 		result.append(SEPERATOR);
235 		result.append(this.toString(args));
236 
237 		return result.toString();
238 	}
239 
240 	/**
241 	 * Prints the argument list.
242 	 *
243 	 * @param args array of arguments
244 	 * @return the debug output
245 	 */
246 	protected String toString(Object[] args) {
247 		StringBuilder result = new StringBuilder();
248 		ArgumentToStringBuilderImpl toStringBuilder = null;
249 
250 		if (args == null) {
251 			args = new Object[0];
252 		}
253 
254 		for (int i = 0; i < args.length; i++) {
255 			toStringBuilder = new ArgumentToStringBuilderImpl(args[i], this.maxArgLength, 1);
256 			result.append("arg[" + i + "]:={");
257 			result.append(toStringBuilder.toString());
258 			result.append("}");
259 
260 			if (i < args.length - 1) {
261 				result.append(SEPERATOR);
262 			}
263 		}
264 
265 		return result.toString();
266 	}
267 
268 }