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