1   //========================================================================
2   //Copyright 2006 Mort Bay Consulting Pty. Ltd.
3   //------------------------------------------------------------------------
4   //Licensed under the Apache License, Version 2.0 (the "License");
5   //you may not use this file except in compliance with the License.
6   //You may obtain a copy of the License at 
7   //http://www.apache.org/licenses/LICENSE-2.0
8   //Unless required by applicable law or agreed to in writing, software
9   //distributed under the License is distributed on an "AS IS" BASIS,
10  //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11  //See the License for the specific language governing permissions and
12  //limitations under the License.
13  //========================================================================
14  
15  package org.mortbay.jetty.handler;
16  
17  import java.io.IOException;
18  
19  import javax.servlet.ServletException;
20  import javax.servlet.http.HttpServletRequest;
21  import javax.servlet.http.HttpServletResponse;
22  
23  import org.mortbay.jetty.HttpConnection;
24  import org.mortbay.jetty.Request;
25  import org.mortbay.jetty.Response;
26  
27  public class StatisticsHandler extends HandlerWrapper
28  {
29      transient long _statsStartedAt;
30      
31      transient int _requests;
32      
33      transient long _requestsDurationMin;         // min request duration
34      transient long _requestsDurationMax;         // max request duration
35      transient long _requestsDurationTotal;       // total request duration
36      transient long _requestsActiveDurationMin;   // min request active duration
37      transient long _requestsActiveDurationMax;   // max request active duration
38      transient long _requestsActiveDurationTotal; // total request active duration
39      
40      transient int _requestsActive;
41      transient int _requestsActiveMin;            // min number of connections handled simultaneously
42      transient int _requestsActiveMax;
43      transient int _requestsResumed;
44      transient int _requestsTimedout;             // requests that timed out while suspended
45      transient int _responses1xx; // Informal
46      transient int _responses2xx; // Success
47      transient int _responses3xx; // Redirection
48      transient int _responses4xx; // Client Error
49      transient int _responses5xx; // Server Error
50      
51      transient long _responsesBytesTotal;
52  
53      /* ------------------------------------------------------------ */
54      public void statsReset()
55      {
56          synchronized(this)
57          {
58              if (isStarted())
59                  _statsStartedAt=System.currentTimeMillis();
60              _requests=0;
61              _responses1xx=0;
62              _responses2xx=0;
63              _responses3xx=0;
64              _responses4xx=0;
65              _responses5xx=0;
66            
67              _requestsActiveMin=_requestsActive;
68              _requestsActiveMax=_requestsActive;
69  
70              _requestsDurationMin=0;
71              _requestsDurationMax=0;
72              _requestsDurationTotal=0;
73              
74              _requestsActiveDurationMin=0;
75              _requestsActiveDurationMax=0;
76              _requestsActiveDurationTotal=0;
77          }
78      }
79  
80  
81      /* ------------------------------------------------------------ */
82      public void handle(String target, HttpServletRequest request, HttpServletResponse response, int dispatch) throws IOException, ServletException
83      {
84          final Request base_request=(request instanceof Request)?((Request)request):HttpConnection.getCurrentConnection().getRequest();
85          final Response base_response=(response instanceof Response)?((Response)response):HttpConnection.getCurrentConnection().getResponse();
86  
87          long timestamp0=base_request.getTimeStamp();
88          long timestamp1=timestamp0;
89          try
90          {
91              synchronized(this)
92              {
93                  if(base_request.isInitial())
94                      _requests++;
95                  else
96                      timestamp1=System.currentTimeMillis();
97                  
98                  if(base_request.isTimeout())
99                      _requestsTimedout++;
100                 if(base_request.isResumed())
101                     _requestsResumed++;
102 
103                 _requestsActive++;
104                 if (_requestsActive>_requestsActiveMax)
105                     _requestsActiveMax=_requestsActive;
106             }
107             
108             super.handle(target, request, response, dispatch);
109         }
110         finally
111         {
112             synchronized(this)
113             {
114                 _requestsActive--;
115                 if (_requestsActive<0)
116                     _requestsActive=0;
117                 if (_requestsActive < _requestsActiveMin)
118                     _requestsActiveMin=_requestsActive;
119 
120                 long duration = System.currentTimeMillis()-timestamp1;
121                 _requestsActiveDurationTotal+=duration;
122                 if (_requestsActiveDurationMin==0 || duration<_requestsActiveDurationMin)
123                     _requestsActiveDurationMin=duration;
124                 if (duration>_requestsActiveDurationMax)
125                     _requestsActiveDurationMax=duration;
126 
127                 if(!base_request.isSuspended())
128                 {
129                     // TODO handle completed requests!
130                     
131                     duration = System.currentTimeMillis()-timestamp0;
132                     _requestsDurationTotal+=duration;
133                     if (_requestsDurationMin==0 || duration<_requestsDurationMin)
134                         _requestsDurationMin=duration;
135                     if (duration>_requestsDurationMax)
136                         _requestsDurationMax=duration;
137                     
138                     switch(base_response.getStatus()/100)
139                     {
140                         case 1: _responses1xx++;break;
141                         case 2: _responses2xx++;break;
142                         case 3: _responses3xx++;break;
143                         case 4: _responses4xx++;break;
144                         case 5: _responses5xx++;break;
145                     }
146                     
147                     _responsesBytesTotal += base_response.getContentCount();
148                 }                                            
149                 
150             }
151         }
152     }
153 
154     /* ------------------------------------------------------------ */
155     protected void doStart() throws Exception
156     {
157         super.doStart();
158         _statsStartedAt=System.currentTimeMillis();
159     }
160 
161     /* ------------------------------------------------------------ */
162     protected void doStop() throws Exception
163     {
164         super.doStop();
165     }
166 
167     /* ------------------------------------------------------------ */
168     /**
169      * @return Get the number of requests handled by this context
170      * since last call of statsReset(), not counting resumed requests.
171      * If setStatsOn(false) then this is undefined.
172      */
173     public int getRequests() {return _requests;}
174 
175     /* ------------------------------------------------------------ */
176     /**
177      * @return Number of requests currently active.
178      * Undefined if setStatsOn(false).
179      */
180     public int getRequestsActive() {return _requestsActive;}
181 
182     /* ------------------------------------------------------------ */
183     /**
184      * @return Number of requests that have been resumed.
185      * Undefined if setStatsOn(false).
186      */
187     public int getRequestsResumed() {return _requestsResumed;}
188 
189     /* ------------------------------------------------------------ */
190     /**
191      * @return Number of requests that timed out while suspended.
192      * Undefined if setStatsOn(false).
193      */
194     public int getRequestsTimedout() {return _requestsTimedout;}
195 
196     /* ------------------------------------------------------------ */
197     /**
198      * @return Maximum number of active requests
199      * since statsReset() called. Undefined if setStatsOn(false).
200      */
201     public int getRequestsActiveMax() {return _requestsActiveMax;}
202 
203     /* ------------------------------------------------------------ */
204     /**
205      * @return Get the number of responses with a 2xx status returned
206      * by this context since last call of statsReset(). Undefined if
207      * if setStatsOn(false).
208      */
209     public int getResponses1xx() {return _responses1xx;}
210 
211     /* ------------------------------------------------------------ */
212     /**
213      * @return Get the number of responses with a 100 status returned
214      * by this context since last call of statsReset(). Undefined if
215      * if setStatsOn(false).
216      */
217     public int getResponses2xx() {return _responses2xx;}
218 
219     /* ------------------------------------------------------------ */
220     /**
221      * @return Get the number of responses with a 3xx status returned
222      * by this context since last call of statsReset(). Undefined if
223      * if setStatsOn(false).
224      */
225     public int getResponses3xx() {return _responses3xx;}
226 
227     /* ------------------------------------------------------------ */
228     /**
229      * @return Get the number of responses with a 4xx status returned
230      * by this context since last call of statsReset(). Undefined if
231      * if setStatsOn(false).
232      */
233     public int getResponses4xx() {return _responses4xx;}
234 
235     /* ------------------------------------------------------------ */
236     /**
237      * @return Get the number of responses with a 5xx status returned
238      * by this context since last call of statsReset(). Undefined if
239      * if setStatsOn(false).
240      */
241     public int getResponses5xx() {return _responses5xx;}
242 
243     /* ------------------------------------------------------------ */
244     /** 
245      * @return Timestamp stats were started at.
246      */
247     public long getStatsOnMs()
248     {
249         return System.currentTimeMillis()-_statsStartedAt;
250     }
251 
252     /* ------------------------------------------------------------ */
253     /**
254      * @return Returns the requestsActiveMin.
255      */
256     public int getRequestsActiveMin()
257     {
258         return _requestsActiveMin;
259     }
260 
261     /* ------------------------------------------------------------ */
262     /**
263      * @return Returns the requestsDurationMin.
264      */
265     public long getRequestsDurationMin()
266     {
267         return _requestsDurationMin;
268     }
269 
270     /* ------------------------------------------------------------ */
271     /**
272      * @return Returns the requestsDurationTotal.
273      */
274     public long getRequestsDurationTotal()
275     {
276         return _requestsDurationTotal;
277     }
278 
279     /* ------------------------------------------------------------ */
280     /** 
281      * @return Average duration of request handling in milliseconds 
282      * since statsReset() called. Undefined if setStatsOn(false).
283      */
284     public long getRequestsDurationAve() {return _requests==0?0:(_requestsDurationTotal/_requests);}
285 
286     /* ------------------------------------------------------------ */
287     /** 
288      * @return Get maximum duration in milliseconds of request handling
289      * since statsReset() called. Undefined if setStatsOn(false).
290      */
291     public long getRequestsDurationMax() {return _requestsDurationMax;}
292     
293     /* ------------------------------------------------------------ */
294     /**
295      * @return Returns the requestsActiveDurationMin.
296      */
297     public long getRequestsActiveDurationMin()
298     {
299         return _requestsActiveDurationMin;
300     }
301 
302     /* ------------------------------------------------------------ */
303     /**
304      * @return Returns the requestsActiveDurationTotal.
305      */
306     public long getRequestsActiveDurationTotal()
307     {
308         return _requestsActiveDurationTotal;
309     }
310 
311     /* ------------------------------------------------------------ */
312     /** 
313      * @return Average duration of request handling in milliseconds 
314      * since statsReset() called. Undefined if setStatsOn(false).
315      */
316     public long getRequestsActiveDurationAve() {return _requests==0?0:(_requestsActiveDurationTotal/_requests);}
317 
318     /* ------------------------------------------------------------ */
319     /** 
320      * @return Get maximum duration in milliseconds of request handling
321      * since statsReset() called. Undefined if setStatsOn(false).
322      */
323     public long getRequestsActiveDurationMax() {return _requestsActiveDurationMax;}
324     
325     /* ------------------------------------------------------------ */
326     /** 
327      * @return Total bytes of content sent in responses
328      */
329     public long getResponsesBytesTotal() {return _responsesBytesTotal; }
330 
331 }