1 /* 2 * Copyright 2019, OpenCensus Authors 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 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 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 package io.opencensus.examples.http.jetty.server; 18 19 import io.opencensus.contrib.http.servlet.OcHttpServletFilter; 20 import io.opencensus.contrib.http.util.HttpViews; 21 import io.opencensus.exporter.stats.prometheus.PrometheusStatsCollector; 22 import io.opencensus.exporter.trace.jaeger.JaegerTraceExporter; 23 import io.opencensus.exporter.trace.logging.LoggingTraceExporter; 24 import io.opencensus.trace.Tracing; 25 import io.opencensus.trace.config.TraceConfig; 26 import io.opencensus.trace.samplers.Samplers; 27 import io.prometheus.client.exporter.HTTPServer; 28 import java.io.BufferedReader; 29 import java.io.IOException; 30 import java.io.PrintWriter; 31 import java.nio.ByteBuffer; 32 import java.nio.charset.StandardCharsets; 33 import java.util.EnumSet; 34 import javax.servlet.AsyncContext; 35 import javax.servlet.DispatcherType; 36 import javax.servlet.ServletException; 37 import javax.servlet.ServletOutputStream; 38 import javax.servlet.WriteListener; 39 import javax.servlet.http.HttpServlet; 40 import javax.servlet.http.HttpServletRequest; 41 import javax.servlet.http.HttpServletResponse; 42 import org.apache.log4j.Logger; 43 import org.eclipse.jetty.server.Request; 44 import org.eclipse.jetty.server.Server; 45 import org.eclipse.jetty.server.handler.AbstractHandler; 46 import org.eclipse.jetty.servlet.ServletContextHandler; 47 import org.eclipse.jetty.servlet.ServletHolder; 48 49 /** Sample application that shows how to instrument jetty server. */ 50 public class HelloWorldServer extends AbstractHandler { 51 52 private static final Logger logger = Logger.getLogger(HelloWorldServer.class.getName()); 53 54 public static class HelloServlet extends HttpServlet { 55 56 private static String body = "<h1>Hello World Servlet Get</h1>"; 57 58 private static final long serialVersionUID = 1L; 59 blockingGet(HttpServletRequest request, HttpServletResponse response)60 private void blockingGet(HttpServletRequest request, HttpServletResponse response) 61 throws ServletException, IOException { 62 63 String str = body.concat("<h3>blocking</h3>"); 64 ByteBuffer content = ByteBuffer.wrap(str.getBytes(StandardCharsets.UTF_8)); 65 66 PrintWriter pout = response.getWriter(); 67 68 pout.print("<html><body>"); 69 pout.print(str); 70 pout.print("</body></html>"); 71 return; 72 } 73 asyncGet(HttpServletRequest request, HttpServletResponse response)74 private void asyncGet(HttpServletRequest request, HttpServletResponse response) 75 throws ServletException, IOException { 76 String str = body.concat("<h3>async</h3>"); 77 ByteBuffer content = ByteBuffer.wrap(str.getBytes(StandardCharsets.UTF_8)); 78 79 AsyncContext async = request.startAsync(); 80 response.setContentType("text/html"); 81 try { 82 Thread.sleep(100); 83 } catch (Exception e) { 84 logger.info("Error sleeping"); 85 } 86 ServletOutputStream out = response.getOutputStream(); 87 out.setWriteListener( 88 new WriteListener() { 89 @Override 90 public void onWritePossible() throws IOException { 91 while (out.isReady()) { 92 if (!content.hasRemaining()) { 93 response.setStatus(200); 94 async.complete(); 95 return; 96 } 97 out.write(content.get()); 98 } 99 } 100 101 @Override 102 public void onError(Throwable t) { 103 logger.info("Server onError callled"); 104 getServletContext().log("Async Error", t); 105 async.complete(); 106 } 107 }); 108 } 109 110 @Override doGet(HttpServletRequest request, HttpServletResponse response)111 protected void doGet(HttpServletRequest request, HttpServletResponse response) 112 throws ServletException, IOException { 113 if (request.getPathInfo().contains("async")) { 114 asyncGet(request, response); 115 } else { 116 blockingGet(request, response); 117 } 118 } 119 120 @Override doPost(HttpServletRequest request, HttpServletResponse response)121 protected void doPost(HttpServletRequest request, HttpServletResponse response) 122 throws ServletException, IOException { 123 // Read from request 124 StringBuilder buffer = new StringBuilder(); 125 BufferedReader reader = request.getReader(); 126 String line; 127 while ((line = reader.readLine()) != null) { 128 buffer.append(line); 129 } 130 String data = buffer.toString(); 131 132 PrintWriter pout = response.getWriter(); 133 134 pout.print("<html><body>"); 135 pout.print("<h3>Hello World Servlet Post</h3>"); 136 pout.print("</body></html>"); 137 return; 138 } 139 } 140 141 @Override handle( String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)142 public void handle( 143 String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) 144 throws IOException, ServletException { 145 response.setContentType("text/html;charset=utf-8"); 146 response.setStatus(HttpServletResponse.SC_OK); 147 baseRequest.setHandled(true); 148 response.getWriter().println("<h1>Hello World. default handler.</h1>"); 149 } 150 initStatsExporter()151 private static void initStatsExporter() throws IOException { 152 HttpViews.registerAllServerViews(); 153 154 // Register Prometheus exporters and export metrics to a Prometheus HTTPServer. 155 // Refer to https://prometheus.io/ to run Prometheus Server. 156 PrometheusStatsCollector.createAndRegister(); 157 HTTPServer prometheusServer = new HTTPServer(9090, true); 158 } 159 initTracing()160 private static void initTracing() { 161 TraceConfig traceConfig = Tracing.getTraceConfig(); 162 163 // default sampler is set to Samplers.alwaysSample() for demonstration. In production 164 // or in high QPS environment please use default sampler. 165 traceConfig.updateActiveTraceParams( 166 traceConfig.getActiveTraceParams().toBuilder().setSampler(Samplers.alwaysSample()).build()); 167 168 // Register LoggingTraceExporter to see traces in logs. 169 LoggingTraceExporter.register(); 170 171 // Register Jaeger Tracing. Refer to https://www.jaegertracing.io/docs/1.8/getting-started/ to 172 // run Jaeger 173 JaegerTraceExporter.createAndRegister("http://localhost:14268/api/traces", "helloworldserver"); 174 } 175 176 /** 177 * HelloWorldServer starts a jetty server that responds to http request sent by {@link 178 * HelloWorldClient}. The server uses http servlet which is instrumented with opencensus to enable 179 * tracing and monitoring stats. 180 */ main(String[] args)181 public static void main(String[] args) throws Exception { 182 initTracing(); 183 initStatsExporter(); 184 185 Server server = new Server(8080); 186 ServletContextHandler contextHandler = 187 new ServletContextHandler(ServletContextHandler.SESSIONS); 188 contextHandler.setContextPath("/helloworld"); 189 ServletHolder sh = new ServletHolder(new HelloServlet()); 190 contextHandler.addServlet(sh, "/request/*"); 191 192 // Enable tracing by adding OcHttpServleFilter for all path 193 contextHandler.addFilter(OcHttpServletFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST)); 194 195 // Uncomment following line to use B3Format for trace context propagation. 196 // contextHandler.setAttribute( 197 // OC_TRACE_PROPAGATOR, Tracing.getPropagationComponent().getB3Format()); 198 199 // By default publicEndpoint parameter is set to false and incoming trace context is added as 200 // a parent. 201 // If the endpoint for http request is public then uncomment following line to set the 202 // publicEndpoint parameter to true. When set to true incoming trace context is added as a 203 // parent link instead of as a parent. 204 // 205 // contextHandler.setInitParameter(OC_PUBLIC_ENDPOINT, "true"); 206 207 server.setHandler(contextHandler); 208 try { 209 server.start(); 210 server.join(); 211 } catch (Exception e) { 212 logger.error("Failed to start application", e); 213 } 214 } 215 } 216