View Javadoc

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  import java.util.concurrent.atomic.AtomicInteger;
18  import java.util.concurrent.atomic.AtomicLong;
19  
20  import javax.servlet.ServletException;
21  import javax.servlet.http.HttpServletRequest;
22  import javax.servlet.http.HttpServletResponse;
23  
24  import org.eclipse.jetty.continuation.Continuation;
25  import org.eclipse.jetty.continuation.ContinuationListener;
26  import org.eclipse.jetty.server.AsyncContinuation;
27  import org.eclipse.jetty.server.Request;
28  import org.eclipse.jetty.server.Response;
29  import org.eclipse.jetty.util.statistic.SampleStatistic;
30  import org.eclipse.jetty.util.statistic.CounterStatistic;
31  
32  public class StatisticsHandler extends HandlerWrapper
33  {
34      private final AtomicLong _statsStartedAt = new AtomicLong();
35      
36      private final CounterStatistic _requestStats = new CounterStatistic();
37      private final SampleStatistic _requestTimeStats = new SampleStatistic();
38      private final CounterStatistic _dispatchedStats = new CounterStatistic();
39      private final SampleStatistic _dispatchedTimeStats = new SampleStatistic();
40      private final CounterStatistic _suspendStats = new CounterStatistic();
41  
42      private final AtomicInteger _resumes = new AtomicInteger();
43      private final AtomicInteger _expires = new AtomicInteger();
44      
45      private final AtomicInteger _responses1xx = new AtomicInteger();
46      private final AtomicInteger _responses2xx = new AtomicInteger();
47      private final AtomicInteger _responses3xx = new AtomicInteger();
48      private final AtomicInteger _responses4xx = new AtomicInteger();
49      private final AtomicInteger _responses5xx = new AtomicInteger();
50      private final AtomicLong _responsesTotalBytes = new AtomicLong();
51  
52      private final ContinuationListener _onCompletion = new ContinuationListener()
53      {
54          public void onComplete(Continuation continuation)
55          {
56              final Request request = ((AsyncContinuation)continuation).getBaseRequest();
57              final long elapsed = System.currentTimeMillis()-request.getTimeStamp();
58              
59              _requestStats.decrement();
60              _requestTimeStats.set(elapsed);
61              
62              updateResponse(request);
63              
64              if (!continuation.isResumed())
65                  _suspendStats.decrement();
66          }
67  
68          public void onTimeout(Continuation continuation)
69          {
70              _expires.incrementAndGet();
71          }
72      };
73      
74      /**
75       * Resets the current request statistics.
76       */
77      public void statsReset()
78      {
79          _statsStartedAt.set(System.currentTimeMillis());
80          
81          _requestStats.reset();
82          _requestTimeStats.reset();
83          _dispatchedStats.reset();
84          _dispatchedTimeStats.reset();
85          _suspendStats.reset();
86  
87          _resumes.set(0);
88          _expires.set(0);
89          _responses1xx.set(0);
90          _responses2xx.set(0);
91          _responses3xx.set(0);
92          _responses4xx.set(0);
93          _responses5xx.set(0);
94          _responsesTotalBytes.set(0L);
95      }
96  
97      @Override
98      public void handle(String path, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException
99      {
100         _dispatchedStats.increment();
101 
102         final long start;
103         AsyncContinuation continuation = request.getAsyncContinuation();
104         if (continuation.isInitial())
105         {
106             // new request
107             _requestStats.increment();
108             start = request.getTimeStamp();
109         }
110         else
111         {
112             // resumed request
113             start = System.currentTimeMillis();
114             _suspendStats.decrement();
115             if (continuation.isResumed())
116                 _resumes.incrementAndGet();
117         }
118 
119         try
120         {
121             super.handle(path, request, httpRequest, httpResponse);
122         }
123         finally
124         {
125             final long now = System.currentTimeMillis();
126             final long dispatched=now-start;
127             
128             _dispatchedStats.decrement();
129             _dispatchedTimeStats.set(dispatched);
130             
131             if (continuation.isSuspended())
132             {
133                 if (continuation.isInitial())
134                     continuation.addContinuationListener(_onCompletion);
135                 _suspendStats.increment();
136             }
137             else if (continuation.isInitial())
138             {
139                 _requestStats.decrement();
140                 _requestTimeStats.set(dispatched);
141                 updateResponse(request);
142             }
143             // else onCompletion will handle it.
144         }
145     }
146 
147     private void updateResponse(Request request)
148     {
149         Response response = request.getResponse();
150         switch (response.getStatus() / 100)
151         {
152             case 1:
153                 _responses1xx.incrementAndGet();
154                 break;
155             case 2:
156                 _responses2xx.incrementAndGet();
157                 break;
158             case 3:
159                 _responses3xx.incrementAndGet();
160                 break;
161             case 4:
162                 _responses4xx.incrementAndGet();
163                 break;
164             case 5:
165                 _responses5xx.incrementAndGet();
166                 break;
167             default:
168                 break;
169         }
170         _responsesTotalBytes.addAndGet(response.getContentCount());
171     }
172 
173     @Override
174     protected void doStart() throws Exception
175     {
176         super.doStart();
177         statsReset();
178     }
179 
180     /**
181      * @return the number of requests handled by this handler
182      * since {@link #statsReset()} was last called, excluding
183      * active requests
184      * @see #getResumes()
185      */
186     public int getRequests()
187     {
188         return (int)_requestStats.getTotal();
189     }
190 
191     /**
192      * @return the number of requests currently active.
193      * since {@link #statsReset()} was last called.
194      */
195     public int getRequestsActive()
196     {
197         return (int)_requestStats.getCurrent();
198     }
199 
200     /**
201      * @return the maximum number of active requests
202      * since {@link #statsReset()} was last called.
203      */
204     public int getRequestsActiveMax()
205     {
206         return (int)_requestStats.getMax();
207     }
208 
209     /**
210      * @return the maximum time (in milliseconds) of request handling
211      * since {@link #statsReset()} was last called.
212      */
213     public long getRequestTimeMax()
214     {
215         return _requestTimeStats.getMax();
216     }
217 
218     /**
219      * @return the total time (in milliseconds) of requests handling
220      * since {@link #statsReset()} was last called.
221      */
222     public long getRequestTimeTotal()
223     {
224         return _requestTimeStats.getTotal();
225     }
226 
227     /**
228      * @return the mean time (in milliseconds) of request handling
229      * since {@link #statsReset()} was last called.
230      * @see #getRequestTimeTotal()
231      * @see #getRequests()
232      */
233     public double getRequestTimeMean()
234     {
235         return _requestTimeStats.getMean();
236     }
237 
238     /**
239      * @return the standard deviation of time (in milliseconds) of request handling
240      * since {@link #statsReset()} was last called.
241      * @see #getRequestTimeTotal()
242      * @see #getRequests()
243      */
244     public double getRequestTimeStdDev()
245     {
246         return _requestTimeStats.getStdDev();
247     }
248 
249     /**
250      * @return the number of dispatches seen by this handler
251      * since {@link #statsReset()} was last called, excluding
252      * active dispatches
253      */
254     public int getDispatched()
255     {
256         return (int)_dispatchedStats.getTotal();
257     }
258 
259     /**
260      * @return the number of dispatches currently in this handler
261      * since {@link #statsReset()} was last called, including
262      * resumed requests
263      */
264     public int getDispatchedActive()
265     {
266         return (int)_dispatchedStats.getCurrent();
267     }
268 
269     /**
270      * @return the max number of dispatches currently in this handler
271      * since {@link #statsReset()} was last called, including
272      * resumed requests
273      */
274     public int getDispatchedActiveMax()
275     {
276         return (int)_dispatchedStats.getMax();
277     }
278 
279     /**
280      * @return the maximum time (in milliseconds) of request dispatch
281      * since {@link #statsReset()} was last called.
282      */
283     public long getDispatchedTimeMax()
284     {
285         return _dispatchedTimeStats.getMax();
286     }
287     
288     /**
289      * @return the total time (in milliseconds) of requests handling
290      * since {@link #statsReset()} was last called.
291      */
292     public long getDispatchedTimeTotal()
293     {
294         return _dispatchedTimeStats.getTotal();
295     }
296 
297     /**
298      * @return the mean time (in milliseconds) of request handling
299      * since {@link #statsReset()} was last called.
300      * @see #getRequestTimeTotal()
301      * @see #getRequests()
302      */
303     public double getDispatchedTimeMean()
304     {
305         return _dispatchedTimeStats.getMean();
306     }
307     
308     /**
309      * @return the standard deviation of time (in milliseconds) of request handling
310      * since {@link #statsReset()} was last called.
311      * @see #getRequestTimeTotal()
312      * @see #getRequests()
313      */
314     public double getDispatchedTimeStdDev()
315     {
316         return _dispatchedTimeStats.getStdDev();
317     }
318     
319     /**
320      * @return the number of requests handled by this handler
321      * since {@link #statsReset()} was last called, including
322      * resumed requests
323      * @see #getResumes()
324      */
325     public int getSuspends()
326     {
327         return (int)_suspendStats.getTotal();
328     }
329 
330     /**
331      * @return the number of requests currently suspended.
332      * since {@link #statsReset()} was last called.
333      */
334     public int getSuspendsActive()
335     {
336         return (int)_suspendStats.getCurrent();
337     }
338 
339     /**
340      * @return the maximum number of current suspended requests
341      * since {@link #statsReset()} was last called.
342      */
343     public int getSuspendsActiveMax()
344     {
345         return (int)_suspendStats.getMax();
346     }
347     
348     /**
349      * @return the number of requests that have been resumed
350      * @see #getExpires()
351      */
352     public int getResumes()
353     {
354         return _resumes.get();
355     }
356 
357     /**
358      * @return the number of requests that expired while suspended.
359      * @see #getResumes()
360      */
361     public int getExpires()
362     {
363         return _expires.get();
364     }
365 
366     /**
367      * @return the number of responses with a 1xx status returned by this context
368      * since {@link #statsReset()} was last called.
369      */
370     public int getResponses1xx()
371     {
372         return _responses1xx.get();
373     }
374 
375     /**
376      * @return the number of responses with a 2xx status returned by this context
377      * since {@link #statsReset()} was last called.
378      */
379     public int getResponses2xx()
380     {
381         return _responses2xx.get();
382     }
383 
384     /**
385      * @return the number of responses with a 3xx status returned by this context
386      * since {@link #statsReset()} was last called.
387      */
388     public int getResponses3xx()
389     {
390         return _responses3xx.get();
391     }
392 
393     /**
394      * @return the number of responses with a 4xx status returned by this context
395      * since {@link #statsReset()} was last called.
396      */
397     public int getResponses4xx()
398     {
399         return _responses4xx.get();
400     }
401 
402     /**
403      * @return the number of responses with a 5xx status returned by this context
404      * since {@link #statsReset()} was last called.
405      */
406     public int getResponses5xx()
407     {
408         return _responses5xx.get();
409     }
410 
411     /**
412      * @return the milliseconds since the statistics were started with {@link #statsReset()}.
413      */
414     public long getStatsOnMs()
415     {
416         return System.currentTimeMillis() - _statsStartedAt.get();
417     }
418     
419     /**
420      * @return the total bytes of content sent in responses
421      */
422     public long getResponsesBytesTotal()
423     {
424         return _responsesTotalBytes.get();
425     }
426     
427     public String toStatsHTML()
428     {   
429         StringBuilder sb = new StringBuilder();
430 
431         sb.append("<h1>Statistics:</h1>\n");
432         sb.append("Statistics gathering started ").append(getStatsOnMs()).append("ms ago").append("<br />\n");
433 
434         sb.append("<h2>Requests:</h2>\n");
435         sb.append("Total requests: ").append(getRequests()).append("<br />\n");
436         sb.append("Active requests: ").append(getRequestsActive()).append("<br />\n");
437         sb.append("Max active requests: ").append(getRequestsActiveMax()).append("<br />\n");
438         sb.append("Total requests time: ").append(getRequestTimeTotal()).append("<br />\n");
439         sb.append("Mean request time: ").append(getRequestTimeMean()).append("<br />\n");
440         sb.append("Max request time: ").append(getRequestTimeMax()).append("<br />\n");
441         sb.append("Request time standard deviation: ").append(getRequestTimeStdDev()).append("<br />\n");
442         
443 
444         sb.append("<h2>Dispatches:</h2>\n");
445         sb.append("Total dispatched: ").append(getDispatched()).append("<br />\n");
446         sb.append("Active dispatched: ").append(getDispatchedActive()).append("<br />\n");
447         sb.append("Max active dispatched: ").append(getDispatchedActiveMax()).append("<br />\n");
448         sb.append("Total dispatched time: ").append(getDispatchedTimeTotal()).append("<br />\n");
449         sb.append("Mean dispatched time: ").append(getDispatchedTimeMean()).append("<br />\n");
450         sb.append("Max dispatched time: ").append(getDispatchedTimeMax()).append("<br />\n");
451         sb.append("Dispatched time standard deviation: ").append(getDispatchedTimeStdDev()).append("<br />\n");
452 
453 
454         sb.append("Total requests suspended: ").append(getSuspends()).append("<br />\n");
455         sb.append("Total requests expired: ").append(getExpires()).append("<br />\n");
456         sb.append("Total requests resumed: ").append(getResumes()).append("<br />\n");
457         
458         sb.append("<h2>Responses:</h2>\n");
459         sb.append("1xx responses: ").append(getResponses1xx()).append("<br />\n");
460         sb.append("2xx responses: ").append(getResponses2xx()).append("<br />\n");
461         sb.append("3xx responses: ").append(getResponses3xx()).append("<br />\n");
462         sb.append("4xx responses: ").append(getResponses4xx()).append("<br />\n");
463         sb.append("5xx responses: ").append(getResponses5xx()).append("<br />\n");
464         sb.append("Bytes sent total: ").append(getResponsesBytesTotal()).append("<br />\n");
465 
466         return sb.toString();
467 
468     }
469 }