1 //
2 //  ========================================================================
3 //  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
4 //  ------------------------------------------------------------------------
5 //  All rights reserved. This program and the accompanying materials
6 //  are made available under the terms of the Eclipse Public License v1.0
7 //  and Apache License v2.0 which accompanies this distribution.
8 //
9 //      The Eclipse Public License is available at
10 //      http://www.eclipse.org/legal/epl-v10.html
11 //
12 //      The Apache License v2.0 is available at
13 //      http://www.opensource.org/licenses/apache2.0.php
14 //
15 //  You may elect to redistribute this code under either of these licenses.
16 //  ========================================================================
17 //
18 
19 package org.eclipse.jetty.servlet;
20 
21 import java.io.IOException;
22 import java.io.PrintWriter;
23 import java.lang.management.ManagementFactory;
24 import java.lang.management.MemoryMXBean;
25 import java.net.InetAddress;
26 import java.net.UnknownHostException;
27 
28 import javax.servlet.ServletContext;
29 import javax.servlet.ServletException;
30 import javax.servlet.http.HttpServlet;
31 import javax.servlet.http.HttpServletRequest;
32 import javax.servlet.http.HttpServletResponse;
33 
34 import org.eclipse.jetty.server.Connector;
35 import org.eclipse.jetty.server.Handler;
36 import org.eclipse.jetty.server.Server;
37 import org.eclipse.jetty.server.handler.ContextHandler;
38 import org.eclipse.jetty.server.handler.StatisticsHandler;
39 import org.eclipse.jetty.util.log.Log;
40 import org.eclipse.jetty.util.log.Logger;
41 
42 public class StatisticsServlet extends HttpServlet
43 {
44     private static final Logger LOG = Log.getLogger(StatisticsServlet.class);
45 
46     boolean _restrictToLocalhost = true; // defaults to true
47     private StatisticsHandler _statsHandler;
48     private MemoryMXBean _memoryBean;
49     private Connector[] _connectors;
50 
init()51     public void init() throws ServletException
52     {
53         ServletContext context = getServletContext();
54         ContextHandler.Context scontext = (ContextHandler.Context) context;
55         Server _server = scontext.getContextHandler().getServer();
56 
57         Handler handler = _server.getChildHandlerByClass(StatisticsHandler.class);
58 
59         if (handler != null)
60         {
61             _statsHandler = (StatisticsHandler) handler;
62         }
63         else
64         {
65             LOG.warn("Statistics Handler not installed!");
66             return;
67         }
68 
69         _memoryBean = ManagementFactory.getMemoryMXBean();
70         _connectors = _server.getConnectors();
71 
72         if (getInitParameter("restrictToLocalhost") != null)
73         {
74             _restrictToLocalhost = "true".equals(getInitParameter("restrictToLocalhost"));
75         }
76 
77     }
78 
doPost(HttpServletRequest sreq, HttpServletResponse sres)79     public void doPost(HttpServletRequest sreq, HttpServletResponse sres) throws ServletException, IOException
80     {
81         doGet(sreq, sres);
82     }
83 
doGet(HttpServletRequest req, HttpServletResponse resp)84     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
85     {
86         if (_statsHandler == null)
87         {
88             LOG.warn("Statistics Handler not installed!");
89             resp.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
90             return;
91         }
92         if (_restrictToLocalhost)
93         {
94             if (!isLoopbackAddress(req.getRemoteAddr()))
95             {
96                 resp.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
97                 return;
98             }
99         }
100 
101         String wantXml = req.getParameter("xml");
102         if (wantXml == null)
103           wantXml = req.getParameter("XML");
104 
105         if (wantXml != null && "true".equalsIgnoreCase(wantXml))
106         {
107             sendXmlResponse(resp);
108         }
109         else
110         {
111             sendTextResponse(resp);
112         }
113 
114     }
115 
isLoopbackAddress(String address)116     private boolean isLoopbackAddress(String address)
117     {
118         try
119         {
120             InetAddress addr = InetAddress.getByName(address);
121             return addr.isLoopbackAddress();
122         }
123         catch (UnknownHostException e )
124         {
125             LOG.warn("Warning: attempt to access statistics servlet from " + address, e);
126             return false;
127         }
128     }
129 
sendXmlResponse(HttpServletResponse response)130     private void sendXmlResponse(HttpServletResponse response) throws IOException
131     {
132         StringBuilder sb = new StringBuilder();
133 
134         sb.append("<statistics>\n");
135 
136         sb.append("  <requests>\n");
137         sb.append("    <statsOnMs>").append(_statsHandler.getStatsOnMs()).append("</statsOnMs>\n");
138 
139         sb.append("    <requests>").append(_statsHandler.getRequests()).append("</requests>\n");
140         sb.append("    <requestsActive>").append(_statsHandler.getRequestsActive()).append("</requestsActive>\n");
141         sb.append("    <requestsActiveMax>").append(_statsHandler.getRequestsActiveMax()).append("</requestsActiveMax>\n");
142         sb.append("    <requestsTimeTotal>").append(_statsHandler.getRequestTimeTotal()).append("</requestsTimeTotal>\n");
143         sb.append("    <requestsTimeMean>").append(_statsHandler.getRequestTimeMean()).append("</requestsTimeMean>\n");
144         sb.append("    <requestsTimeMax>").append(_statsHandler.getRequestTimeMax()).append("</requestsTimeMax>\n");
145         sb.append("    <requestsTimeStdDev>").append(_statsHandler.getRequestTimeStdDev()).append("</requestsTimeStdDev>\n");
146 
147         sb.append("    <dispatched>").append(_statsHandler.getDispatched()).append("</dispatched>\n");
148         sb.append("    <dispatchedActive>").append(_statsHandler.getDispatchedActive()).append("</dispatchedActive>\n");
149         sb.append("    <dispatchedActiveMax>").append(_statsHandler.getDispatchedActiveMax()).append("</dispatchedActiveMax>\n");
150         sb.append("    <dispatchedTimeTotal>").append(_statsHandler.getDispatchedTimeTotal()).append("</dispatchedTimeTotal>\n");
151         sb.append("    <dispatchedTimeMean>").append(_statsHandler.getDispatchedTimeMean()).append("</dispatchedTimeMean>\n");
152         sb.append("    <dispatchedTimeMax>").append(_statsHandler.getDispatchedTimeMax()).append("</dispatchedTimeMax>\n");
153         sb.append("    <dispatchedTimeStdDev").append(_statsHandler.getDispatchedTimeStdDev()).append("</dispatchedTimeStdDev>\n");
154 
155         sb.append("    <requestsSuspended>").append(_statsHandler.getSuspends()).append("</requestsSuspended>\n");
156         sb.append("    <requestsExpired>").append(_statsHandler.getExpires()).append("</requestsExpired>\n");
157         sb.append("    <requestsResumed>").append(_statsHandler.getResumes()).append("</requestsResumed>\n");
158         sb.append("  </requests>\n");
159 
160         sb.append("  <responses>\n");
161         sb.append("    <responses1xx>").append(_statsHandler.getResponses1xx()).append("</responses1xx>\n");
162         sb.append("    <responses2xx>").append(_statsHandler.getResponses2xx()).append("</responses2xx>\n");
163         sb.append("    <responses3xx>").append(_statsHandler.getResponses3xx()).append("</responses3xx>\n");
164         sb.append("    <responses4xx>").append(_statsHandler.getResponses4xx()).append("</responses4xx>\n");
165         sb.append("    <responses5xx>").append(_statsHandler.getResponses5xx()).append("</responses5xx>\n");
166         sb.append("    <responsesBytesTotal>").append(_statsHandler.getResponsesBytesTotal()).append("</responsesBytesTotal>\n");
167         sb.append("  </responses>\n");
168 
169         sb.append("  <connections>\n");
170         for (Connector connector : _connectors)
171         {
172         	sb.append("    <connector>\n");
173         	sb.append("      <name>").append(connector.getName()).append("</name>\n");
174         	sb.append("      <statsOn>").append(connector.getStatsOn()).append("</statsOn>\n");
175             if (connector.getStatsOn())
176             {
177             	sb.append("    <statsOnMs>").append(connector.getStatsOnMs()).append("</statsOnMs>\n");
178             	sb.append("    <connections>").append(connector.getConnections()).append("</connections>\n");
179             	sb.append("    <connectionsOpen>").append(connector.getConnectionsOpen()).append("</connectionsOpen>\n");
180             	sb.append("    <connectionsOpenMax>").append(connector.getConnectionsOpenMax()).append("</connectionsOpenMax>\n");
181             	sb.append("    <connectionsDurationTotal>").append(connector.getConnectionsDurationTotal()).append("</connectionsDurationTotal>\n");
182             	sb.append("    <connectionsDurationMean>").append(connector.getConnectionsDurationMean()).append("</connectionsDurationMean>\n");
183             	sb.append("    <connectionsDurationMax>").append(connector.getConnectionsDurationMax()).append("</connectionsDurationMax>\n");
184                 sb.append("    <connectionsDurationStdDev>").append(connector.getConnectionsDurationStdDev()).append("</connectionsDurationStdDev>\n");
185                 sb.append("    <requests>").append(connector.getRequests()).append("</requests>\n");
186                 sb.append("    <connectionsRequestsMean>").append(connector.getConnectionsRequestsMean()).append("</connectionsRequestsMean>\n");
187                 sb.append("    <connectionsRequestsMax>").append(connector.getConnectionsRequestsMax()).append("</connectionsRequestsMax>\n");
188                 sb.append("    <connectionsRequestsStdDev>").append(connector.getConnectionsRequestsStdDev()).append("</connectionsRequestsStdDev>\n");
189             }
190             sb.append("    </connector>\n");
191         }
192         sb.append("  </connections>\n");
193 
194         sb.append("  <memory>\n");
195         sb.append("    <heapMemoryUsage>").append(_memoryBean.getHeapMemoryUsage().getUsed()).append("</heapMemoryUsage>\n");
196         sb.append("    <nonHeapMemoryUsage>").append(_memoryBean.getNonHeapMemoryUsage().getUsed()).append("</nonHeapMemoryUsage>\n");
197         sb.append("  </memory>\n");
198 
199         sb.append("</statistics>\n");
200 
201         response.setContentType("text/xml");
202         PrintWriter pout = response.getWriter();
203         pout.write(sb.toString());
204     }
205 
sendTextResponse(HttpServletResponse response)206     private void sendTextResponse(HttpServletResponse response) throws IOException
207     {
208         StringBuilder sb = new StringBuilder();
209         sb.append(_statsHandler.toStatsHTML());
210 
211         sb.append("<h2>Connections:</h2>\n");
212         for (Connector connector : _connectors)
213         {
214             sb.append("<h3>").append(connector.getName()).append("</h3>");
215 
216             if (connector.getStatsOn())
217             {
218                 sb.append("Statistics gathering started ").append(connector.getStatsOnMs()).append("ms ago").append("<br />\n");
219                 sb.append("Total connections: ").append(connector.getConnections()).append("<br />\n");
220                 sb.append("Current connections open: ").append(connector.getConnectionsOpen()).append("<br />\n");
221                 sb.append("Max concurrent connections open: ").append(connector.getConnectionsOpenMax()).append("<br />\n");
222                 sb.append("Total connections duration: ").append(connector.getConnectionsDurationTotal()).append("<br />\n");
223                 sb.append("Mean connection duration: ").append(connector.getConnectionsDurationMean()).append("<br />\n");
224                 sb.append("Max connection duration: ").append(connector.getConnectionsDurationMax()).append("<br />\n");
225                 sb.append("Connection duration standard deviation: ").append(connector.getConnectionsDurationStdDev()).append("<br />\n");
226                 sb.append("Total requests: ").append(connector.getRequests()).append("<br />\n");
227                 sb.append("Mean requests per connection: ").append(connector.getConnectionsRequestsMean()).append("<br />\n");
228                 sb.append("Max requests per connection: ").append(connector.getConnectionsRequestsMax()).append("<br />\n");
229                 sb.append("Requests per connection standard deviation: ").append(connector.getConnectionsRequestsStdDev()).append("<br />\n");
230             }
231             else
232             {
233                 sb.append("Statistics gathering off.\n");
234             }
235 
236         }
237 
238         sb.append("<h2>Memory:</h2>\n");
239         sb.append("Heap memory usage: ").append(_memoryBean.getHeapMemoryUsage().getUsed()).append(" bytes").append("<br />\n");
240         sb.append("Non-heap memory usage: ").append(_memoryBean.getNonHeapMemoryUsage().getUsed()).append(" bytes").append("<br />\n");
241 
242         response.setContentType("text/html");
243         PrintWriter pout = response.getWriter();
244         pout.write(sb.toString());
245 
246     }
247 }
248