1 // ========================================================================
2 // Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd.
3 // ------------------------------------------------------------------------
4 // All rights reserved. This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v1.0
6 // and Apache License v2.0 which accompanies this distribution.
7 // The Eclipse Public License is available at
8 // http://www.eclipse.org/legal/epl-v10.html
9 // The Apache License v2.0 is available at
10 // http://www.opensource.org/licenses/apache2.0.php
11 // You may elect to redistribute this code under either of these licenses.
12 // ========================================================================
13
14 package org.eclipse.jetty.server.handler;
15
16 import java.io.IOException;
17
18 import javax.servlet.ServletException;
19 import javax.servlet.http.HttpServletRequest;
20 import javax.servlet.http.HttpServletResponse;
21
22 import org.eclipse.jetty.server.AsyncContinuation;
23 import org.eclipse.jetty.server.HttpConnection;
24 import org.eclipse.jetty.server.Request;
25 import org.eclipse.jetty.server.Response;
26 import org.eclipse.jetty.util.LazyList;
27
28 public class StatisticsHandler extends HandlerWrapper implements CompleteHandler
29 {
30 transient long _statsStartedAt;
31
32 transient int _requests;
33
34 transient long _requestsDurationMin; // min request duration
35 transient long _requestsDurationMax; // max request duration
36 transient long _requestsDurationTotal; // total request duration
37 transient long _requestsActiveDurationMin; // min request active duration
38 transient long _requestsActiveDurationMax; // max request active duration
39 transient long _requestsActiveDurationTotal; // total request active duration
40
41 transient int _requestsActive;
42 transient int _requestsActiveMin; // min number of connections handled simultaneously
43 transient int _requestsActiveMax;
44 transient int _requestsResumed;
45 transient int _requestsTimedout; // requests that timed out while suspended
46 transient int _responses1xx; // Informal
47 transient int _responses2xx; // Success
48 transient int _responses3xx; // Redirection
49 transient int _responses4xx; // Client Error
50 transient int _responses5xx; // Server Error
51
52 transient long _responsesBytesTotal;
53
54 /* ------------------------------------------------------------ */
55 public void statsReset()
56 {
57 synchronized(this)
58 {
59 if (isStarted())
60 _statsStartedAt=System.currentTimeMillis();
61 _requests=0;
62 _responses1xx=0;
63 _responses2xx=0;
64 _responses3xx=0;
65 _responses4xx=0;
66 _responses5xx=0;
67
68 _requestsActiveMin=_requestsActive;
69 _requestsActiveMax=_requestsActive;
70
71 _requestsDurationMin=0;
72 _requestsDurationMax=0;
73 _requestsDurationTotal=0;
74
75 _requestsActiveDurationMin=0;
76 _requestsActiveDurationMax=0;
77 _requestsActiveDurationTotal=0;
78 }
79 }
80
81
82 /* ------------------------------------------------------------ */
83 public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
84 {
85 final Response base_response=baseRequest.getResponse();
86
87 long timestamp0=baseRequest.getTimeStamp();
88 long timestamp1=timestamp0;
89 try
90 {
91 AsyncContinuation asyncContextState=baseRequest.getAsyncContinuation();
92 synchronized(this)
93 {
94 if(asyncContextState==null)
95 {
96 _requests++;
97 }
98 else
99 {
100 if(asyncContextState.isInitial())
101 _requests++;
102 else
103 {
104 timestamp1=System.currentTimeMillis();
105 /*
106 if (asyncContextState.isTimeout())
107 _requestsTimedout++;
108 if(asyncContextState.isResumed())
109 _requestsResumed++;
110 */
111 }
112 }
113
114 _requestsActive++;
115 if (_requestsActive>_requestsActiveMax)
116 _requestsActiveMax=_requestsActive;
117 }
118
119 super.handle(target, baseRequest, request, response);
120 }
121 finally
122 {
123 synchronized(this)
124 {
125 _requestsActive--;
126 if (_requestsActive<0)
127 _requestsActive=0;
128 if (_requestsActive < _requestsActiveMin)
129 _requestsActiveMin=_requestsActive;
130
131 long duration = System.currentTimeMillis()-timestamp1;
132 _requestsActiveDurationTotal+=duration;
133 if (_requestsActiveDurationMin==0 || duration<_requestsActiveDurationMin)
134 _requestsActiveDurationMin=duration;
135 if (duration>_requestsActiveDurationMax)
136 _requestsActiveDurationMax=duration;
137
138
139 if(baseRequest.isAsyncStarted())
140 {
141 Object list = baseRequest.getAttribute(COMPLETE_HANDLER_ATTR);
142 baseRequest.setAttribute(COMPLETE_HANDLER_ATTR, LazyList.add(list, this));
143 }
144 else
145 {
146 duration = System.currentTimeMillis()-timestamp0;
147 addRequestsDurationTotal(duration);
148
149 switch(base_response.getStatus()/100)
150 {
151 case 1: _responses1xx++;break;
152 case 2: _responses2xx++;break;
153 case 3: _responses3xx++;break;
154 case 4: _responses4xx++;break;
155 case 5: _responses5xx++;break;
156 }
157
158 _responsesBytesTotal += base_response.getContentCount();
159 }
160 }
161 }
162 }
163
164 /* ------------------------------------------------------------ */
165 protected void doStart() throws Exception
166 {
167 super.doStart();
168 _statsStartedAt=System.currentTimeMillis();
169 }
170
171 /* ------------------------------------------------------------ */
172 protected void doStop() throws Exception
173 {
174 super.doStop();
175 }
176
177 /* ------------------------------------------------------------ */
178 /**
179 * @return Get the number of requests handled by this context
180 * since last call of statsReset(), not counting resumed requests.
181 * If setStatsOn(false) then this is undefined.
182 */
183 public int getRequests() {return _requests;}
184
185 /* ------------------------------------------------------------ */
186 /**
187 * @return Number of requests currently active.
188 * Undefined if setStatsOn(false).
189 */
190 public int getRequestsActive() {return _requestsActive;}
191
192 /* ------------------------------------------------------------ */
193 /**
194 * @return Number of requests that have been resumed.
195 * Undefined if setStatsOn(false).
196 */
197 public int getRequestsResumed() {return _requestsResumed;}
198
199 /* ------------------------------------------------------------ */
200 /**
201 * @return Number of requests that timed out while suspended.
202 * Undefined if setStatsOn(false).
203 */
204 public int getRequestsTimedout() {return _requestsTimedout;}
205
206 /* ------------------------------------------------------------ */
207 /**
208 * @return Maximum number of active requests
209 * since statsReset() called. Undefined if setStatsOn(false).
210 */
211 public int getRequestsActiveMax() {return _requestsActiveMax;}
212
213 /* ------------------------------------------------------------ */
214 /**
215 * @return Get the number of responses with a 2xx status returned
216 * by this context since last call of statsReset(). Undefined if
217 * if setStatsOn(false).
218 */
219 public int getResponses1xx() {return _responses1xx;}
220
221 /* ------------------------------------------------------------ */
222 /**
223 * @return Get the number of responses with a 100 status returned
224 * by this context since last call of statsReset(). Undefined if
225 * if setStatsOn(false).
226 */
227 public int getResponses2xx() {return _responses2xx;}
228
229 /* ------------------------------------------------------------ */
230 /**
231 * @return Get the number of responses with a 3xx status returned
232 * by this context since last call of statsReset(). Undefined if
233 * if setStatsOn(false).
234 */
235 public int getResponses3xx() {return _responses3xx;}
236
237 /* ------------------------------------------------------------ */
238 /**
239 * @return Get the number of responses with a 4xx status returned
240 * by this context since last call of statsReset(). Undefined if
241 * if setStatsOn(false).
242 */
243 public int getResponses4xx() {return _responses4xx;}
244
245 /* ------------------------------------------------------------ */
246 /**
247 * @return Get the number of responses with a 5xx status returned
248 * by this context since last call of statsReset(). Undefined if
249 * if setStatsOn(false).
250 */
251 public int getResponses5xx() {return _responses5xx;}
252
253 /* ------------------------------------------------------------ */
254 /**
255 * @return Timestamp stats were started at.
256 */
257 public long getStatsOnMs()
258 {
259 return System.currentTimeMillis()-_statsStartedAt;
260 }
261
262 /* ------------------------------------------------------------ */
263 /**
264 * @return Returns the requestsActiveMin.
265 */
266 public int getRequestsActiveMin()
267 {
268 return _requestsActiveMin;
269 }
270
271 /* ------------------------------------------------------------ */
272 /**
273 * @return Returns the requestsDurationMin.
274 */
275 public long getRequestsDurationMin()
276 {
277 return _requestsDurationMin;
278 }
279
280 /* ------------------------------------------------------------ */
281 /**
282 * @return Returns the requestsDurationTotal.
283 */
284 public long getRequestsDurationTotal()
285 {
286 return _requestsDurationTotal;
287 }
288
289 /* ------------------------------------------------------------ */
290 /**
291 * @return Average duration of request handling in milliseconds
292 * since statsReset() called. Undefined if setStatsOn(false).
293 */
294 public long getRequestsDurationAve() {return _requests==0?0:(_requestsDurationTotal/_requests);}
295
296 /* ------------------------------------------------------------ */
297 /**
298 * @return Get maximum duration in milliseconds of request handling
299 * since statsReset() called. Undefined if setStatsOn(false).
300 */
301 public long getRequestsDurationMax() {return _requestsDurationMax;}
302
303 /* ------------------------------------------------------------ */
304 /**
305 * @return Returns the requestsActiveDurationMin.
306 */
307 public long getRequestsActiveDurationMin()
308 {
309 return _requestsActiveDurationMin;
310 }
311
312 /* ------------------------------------------------------------ */
313 /**
314 * @return Returns the requestsActiveDurationTotal.
315 */
316 public long getRequestsActiveDurationTotal()
317 {
318 return _requestsActiveDurationTotal;
319 }
320
321 /* ------------------------------------------------------------ */
322 /**
323 * @return Average duration of request handling in milliseconds
324 * since statsReset() called. Undefined if setStatsOn(false).
325 */
326 public long getRequestsActiveDurationAve() {return _requests==0?0:(_requestsActiveDurationTotal/_requests);}
327
328 /* ------------------------------------------------------------ */
329 /**
330 * @return Get maximum duration in milliseconds of request handling
331 * since statsReset() called. Undefined if setStatsOn(false).
332 */
333 public long getRequestsActiveDurationMax() {return _requestsActiveDurationMax;}
334
335 /* ------------------------------------------------------------ */
336 /**
337 * @return Total bytes of content sent in responses
338 */
339 public long getResponsesBytesTotal() {return _responsesBytesTotal; }
340
341 private void addRequestsDurationTotal(long duration)
342 {
343 synchronized(this)
344 {
345 _requestsDurationTotal+=duration;
346 if (_requestsDurationMin==0 || duration<_requestsDurationMin)
347 _requestsDurationMin=duration;
348 if (duration>_requestsDurationMax)
349 _requestsDurationMax=duration;
350 }
351 }
352
353
354 /* ------------------------------------------------------------ */
355 /**
356 * Handle completed requests.
357 *
358 * @param request
359 * the request which has just completed
360 */
361 public void complete(Request request)
362 {
363 long duration = System.currentTimeMillis() - request.getTimeStamp();
364 addRequestsDurationTotal(duration);
365 }
366
367 }