1   package org.mortbay.jetty.servlet;
2   
3   //========================================================================
4   //Copyright 2008 Mort Bay Consulting Pty. Ltd.
5   //------------------------------------------------------------------------
6   //Licensed under the Apache License, Version 2.0 (the "License");
7   //you may not use this file except in compliance with the License.
8   //You may obtain a copy of the License at
9   //http://www.apache.org/licenses/LICENSE-2.0
10  //Unless required by applicable law or agreed to in writing, software
11  //distributed under the License is distributed on an "AS IS" BASIS,
12  //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  //See the License for the specific language governing permissions and
14  //limitations under the License.
15  //========================================================================
16  
17  import java.io.IOException;
18  import java.io.PrintWriter;
19  import java.lang.management.ManagementFactory;
20  import java.lang.management.MemoryMXBean;
21  
22  import javax.servlet.ServletContext;
23  import javax.servlet.ServletException;
24  import javax.servlet.http.HttpServlet;
25  import javax.servlet.http.HttpServletRequest;
26  import javax.servlet.http.HttpServletResponse;
27  
28  import org.mortbay.jetty.Connector;
29  import org.mortbay.jetty.Handler;
30  import org.mortbay.jetty.Server;
31  import org.mortbay.jetty.handler.ContextHandler;
32  import org.mortbay.jetty.handler.StatisticsHandler;
33  import org.mortbay.log.Log;
34  
35  public class StatisticsServlet extends HttpServlet
36  {
37      boolean _restrictToLocalhost = true; // defaults to true
38      private Server _server = null;
39      private StatisticsHandler _statsHandler;
40      private MemoryMXBean _memoryBean;
41      private Connector[] _connectors;
42  
43      public void init() throws ServletException
44      {
45          _memoryBean = ManagementFactory.getMemoryMXBean();
46  
47          ServletContext context = getServletContext();
48          ContextHandler.SContext scontext = (ContextHandler.SContext) context;
49          _server = scontext.getContextHandler().getServer();
50  
51          Handler handler = _server.getChildHandlerByClass(StatisticsHandler.class);
52  
53          if (handler != null)
54          {
55              _statsHandler = (StatisticsHandler) handler;
56          } 
57          else
58          {
59              Log.info("Installing Statistics Handler");
60              _statsHandler = new StatisticsHandler();
61              _server.addHandler(_statsHandler);
62          }
63  
64  
65          _connectors = _server.getConnectors();
66  
67          if (getInitParameter("restrictToLocalhost") != null)
68          {
69              _restrictToLocalhost = "true".equals(getInitParameter("restrictToLocalhost"));
70          }
71  
72      }
73  
74      public void doPost(HttpServletRequest sreq, HttpServletResponse sres) throws ServletException, IOException
75      {
76          doGet(sreq, sres);
77      }
78  
79      protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
80      {
81  
82          if (_restrictToLocalhost)
83          {
84              if (!"127.0.0.1".equals(req.getRemoteAddr()))
85              {
86                  resp.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
87                  return;
88              }
89          }
90  
91          if (req.getParameter("xml") != null && "true".equals(req.getParameter("xml")))
92          {
93              sendXmlResponse(resp);
94          } else
95          {
96              sendTextResponse(resp);
97          }
98  
99      }
100 
101     private void sendXmlResponse(HttpServletResponse response) throws IOException
102     {
103         StringBuilder sb = new StringBuilder();
104 
105         sb.append("<statistics>\n");
106 
107         sb.append("  <requests>\n");
108         sb.append("    <statsOnMs>").append(_statsHandler.getStatsOnMs()).append("</statsOnMs>\n");
109         sb.append("    <requests>").append(_statsHandler.getRequests()).append("</requests>\n");
110         sb.append("    <requestsTimedout>").append(_statsHandler.getRequestsTimedout()).append("</requestsTimedout>\n");
111         sb.append("    <requestsResumed>").append(_statsHandler.getRequestsResumed()).append("</requestsResumed>\n");
112         sb.append("    <requestsActive>").append(_statsHandler.getRequestsActive()).append("</requestsActive>\n");
113         sb.append("    <requestsActiveMin>").append(_statsHandler.getRequestsActiveMin()).append("</requestsActiveMin>\n");
114         sb.append("    <requestsActiveMax>").append(_statsHandler.getRequestsActiveMax()).append("</requestsActiveMax>\n");
115         sb.append("    <requestsDurationTotal>").append(_statsHandler.getRequestsDurationTotal()).append("</requestsDurationTotal>\n");
116         sb.append("    <requestsDurationAve>").append(_statsHandler.getRequestsDurationAve()).append("</requestsDurationAve>\n");
117         sb.append("    <requestsDurationMin>").append(_statsHandler.getRequestsDurationMin()).append("</requestsDurationMin>\n");
118         sb.append("    <requestsDurationMax>").append(_statsHandler.getRequestsDurationMax()).append("</requestsDurationMax>\n");
119         sb.append("    <requestsActiveDurationAve>").append(_statsHandler.getRequestsActiveDurationAve()).append("</requestsActiveDurationAve>\n");
120         sb.append("    <requestsActiveDurationMin>").append(_statsHandler.getRequestsActiveDurationMin()).append("</requestsActiveDurationMin>\n");
121         sb.append("    <requestsActiveDurationMax>").append(_statsHandler.getRequestsActiveDurationMax()).append("</requestsActiveDurationMax>\n");
122         sb.append("  </requests>\n");
123         
124         sb.append("  <responses>\n");
125         sb.append("    <responses1xx>").append(_statsHandler.getResponses1xx()).append("</responses1xx>\n");
126         sb.append("    <responses2xx>").append(_statsHandler.getResponses2xx()).append("</responses2xx>\n");
127         sb.append("    <responses3xx>").append(_statsHandler.getResponses3xx()).append("</responses3xx>\n");
128         sb.append("    <responses4xx>").append(_statsHandler.getResponses4xx()).append("</responses4xx>\n");
129         sb.append("    <responses5xx>").append(_statsHandler.getResponses5xx()).append("</responses5xx>\n");
130         sb.append("    <responsesBytesTotal>").append(_statsHandler.getResponsesBytesTotal()).append("</responsesBytesTotal>\n");
131         sb.append("  </responses>\n");
132         
133         sb.append("  <connections>\n");
134         for (Connector connector : _connectors)
135         {
136         	sb.append("    <connector>\n");        
137         	sb.append("      <name>").append(connector.getName()).append("</name>\n");
138         	sb.append("      <statsOn>").append(connector.getStatsOn()).append("</statsOn>\n");
139             if (connector.getStatsOn())
140             {
141             	sb.append("    <statsOnMs>").append(connector.getStatsOnMs()).append("</statsOnMs>\n");
142             	sb.append("    <connections>").append(connector.getConnections()).append("</connections>\n");
143             	sb.append("    <connectionsOpen>").append(connector.getConnectionsOpen()).append("</connectionsOpen>\n");
144             	sb.append("    <connectionsOpenMin>").append(connector.getConnectionsOpenMin()).append("</connectionsOpenMin>\n");
145             	sb.append("    <connectionsOpenMax>").append(connector.getConnectionsOpenMax()).append("</connectionsOpenMax>\n");
146             	sb.append("    <connectionsDurationTotal>").append(connector.getConnectionsDurationTotal()).append("</connectionsDurationTotal>\n");
147             	sb.append("    <connectionsDurationAve>").append(connector.getConnectionsDurationAve()).append("</connectionsDurationAve>\n");
148             	sb.append("    <connectionsDurationMin>").append(connector.getConnectionsDurationMin()).append("</connectionsDurationMin>\n");
149             	sb.append("    <connectionsDurationMax>").append(connector.getConnectionsDurationMax()).append("</connectionsDurationMax>\n");
150                 sb.append("    <requests>").append(connector.getRequests()).append("</requests>\n");
151                 sb.append("    <connectionsRequestsAve>").append(connector.getConnectionsRequestsAve()).append("</connectionsRequestsAve>\n");
152                 sb.append("    <connectionsRequestsMin>").append(connector.getConnectionsRequestsMin()).append("</connectionsRequestsMin>\n");
153                 sb.append("    <connectionsRequestsMax>").append(connector.getConnectionsRequestsMax()).append("</connectionsRequestsMax>\n");
154             }
155             sb.append("    </connector>\n");
156         }
157         sb.append("  </connections>\n");
158         
159         sb.append("  <memory>\n");
160         sb.append("    <heapMemoryUsage>").append(_memoryBean.getHeapMemoryUsage().getUsed()).append("</heapMemoryUsage>\n");
161         sb.append("    <nonHeapMemoryUsage>").append(_memoryBean.getNonHeapMemoryUsage().getUsed()).append("</nonHeapMemoryUsage>\n");
162         sb.append("  </memory>\n");
163         
164         sb.append("</statistics>\n");
165         
166         response.setContentType("text/xml");
167         PrintWriter pout = null;
168         pout = response.getWriter();
169         pout.write(sb.toString());
170     }
171 
172     private void sendTextResponse(HttpServletResponse response) throws IOException
173     {
174 
175         StringBuilder sb = new StringBuilder();
176 
177         sb.append("<h1>Statistics:</h1>\n");
178 
179         sb.append("<h2>Requests:</h2>\n");
180         sb.append("Statistics gathering started " + _statsHandler.getStatsOnMs() + "ms ago").append("<br />\n");
181         sb.append("Total requests: " + _statsHandler.getRequests()).append("<br />\n");
182         sb.append("Total requests timed out: " + _statsHandler.getRequestsTimedout()).append("<br />\n");
183         sb.append("Total requests resumed: " + _statsHandler.getRequestsResumed()).append("<br />\n");
184         sb.append("Current requests active: " + _statsHandler.getRequestsActive()).append("<br />\n");
185         sb.append("Min concurrent requests active: " + _statsHandler.getRequestsActiveMin()).append("<br />\n");
186         sb.append("Max concurrent requests active: " + _statsHandler.getRequestsActiveMax()).append("<br />\n");
187         sb.append("Total requests duration: " + _statsHandler.getRequestsDurationTotal()).append("<br />\n");
188         sb.append("Average request duration: " + _statsHandler.getRequestsDurationAve()).append("<br />\n");
189         sb.append("Min request duration: " + _statsHandler.getRequestsDurationMin()).append("<br />\n");
190         sb.append("Max request duration: " + _statsHandler.getRequestsDurationMax()).append("<br />\n");
191         sb.append("Average request active duration: " + _statsHandler.getRequestsActiveDurationAve()).append("<br />\n");
192         sb.append("Min request active duration: " + _statsHandler.getRequestsActiveDurationMin()).append("<br />\n");
193         sb.append("Max request active duration: " + _statsHandler.getRequestsActiveDurationMax()).append("<br />\n");
194 
195         sb.append("<h2>Responses:</h2>\n");
196         sb.append("1xx responses: " + _statsHandler.getResponses1xx()).append("<br />\n");
197         sb.append("2xx responses: " + _statsHandler.getResponses2xx()).append("<br />\n");
198         sb.append("3xx responses: " + _statsHandler.getResponses3xx()).append("<br />\n");
199         sb.append("4xx responses: " + _statsHandler.getResponses4xx()).append("<br />\n");
200         sb.append("5xx responses: " + _statsHandler.getResponses5xx()).append("<br />\n");
201         sb.append("Bytes sent total: " + _statsHandler.getResponsesBytesTotal()).append("<br />\n");
202 
203         sb.append("<h2>Connections:</h2>\n");
204         for (Connector connector : _connectors)
205         {
206             sb.append("<h3>" + connector.getName() + "</h3>");
207             
208             if (connector.getStatsOn())
209             {
210                 sb.append("Statistics gathering started " +  connector.getStatsOnMs() + "ms ago").append("<br />\n");
211                 sb.append("Total connections: " +  connector.getConnections()).append("<br />\n");
212                 sb.append("Current connections open: " + connector.getConnectionsOpen());
213                 sb.append("Min concurrent connections open: " +  connector.getConnectionsOpenMin()).append("<br />\n");
214                 sb.append("Max concurrent connections open: " +  connector.getConnectionsOpenMax()).append("<br />\n");
215                 sb.append("Total connections duration: " +  connector.getConnectionsDurationTotal()).append("<br />\n");
216                 sb.append("Average connection duration: " +  connector.getConnectionsDurationAve()).append("<br />\n");
217                 sb.append("Min connection duration: " +  connector.getConnectionsDurationMin()).append("<br />\n");
218                 sb.append("Max connection duration: " +  connector.getConnectionsDurationMax()).append("<br />\n");
219                 sb.append("Total requests: " +  connector.getRequests()).append("<br />\n");
220                 sb.append("Average requests per connection: " +  connector.getConnectionsRequestsAve()).append("<br />\n");
221                 sb.append("Min requests per connection: " +  connector.getConnectionsRequestsMin()).append("<br />\n");
222                 sb.append("Max requests per connection: " +  connector.getConnectionsRequestsMax()).append("<br />\n");
223             }
224             else
225             {
226                 sb.append("Statistics gathering off.\n");
227             }
228                 
229         }
230 
231         sb.append("<h2>Memory:</h2>\n");
232         sb.append("Heap memory usage: " + _memoryBean.getHeapMemoryUsage().getUsed() + " bytes").append("<br />\n");
233         sb.append("Non-heap memory usage: " + _memoryBean.getNonHeapMemoryUsage().getUsed() + " bytes").append("<br />\n");
234 
235         response.setContentType("text/html");
236         PrintWriter pout = null;
237         pout = response.getWriter();
238         pout.write(sb.toString());
239 
240     }
241 }