1 /* 2 * Copyright 2018, 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.grpc.helloworld; 18 19 import static io.opencensus.examples.grpc.helloworld.HelloWorldUtils.getPortOrDefaultFromArgs; 20 import static io.opencensus.examples.grpc.helloworld.HelloWorldUtils.getStringOrDefaultFromArgs; 21 22 import com.google.common.collect.ImmutableMap; 23 import io.grpc.Server; 24 import io.grpc.ServerBuilder; 25 import io.grpc.stub.StreamObserver; 26 import io.opencensus.common.Duration; 27 import io.opencensus.common.Scope; 28 import io.opencensus.contrib.grpc.metrics.RpcViews; 29 import io.opencensus.contrib.zpages.ZPageHandlers; 30 import io.opencensus.exporter.stats.prometheus.PrometheusStatsCollector; 31 import io.opencensus.exporter.stats.stackdriver.StackdriverStatsConfiguration; 32 import io.opencensus.exporter.stats.stackdriver.StackdriverStatsExporter; 33 import io.opencensus.exporter.trace.logging.LoggingTraceExporter; 34 import io.opencensus.exporter.trace.stackdriver.StackdriverTraceConfiguration; 35 import io.opencensus.exporter.trace.stackdriver.StackdriverTraceExporter; 36 import io.opencensus.trace.AttributeValue; 37 import io.opencensus.trace.Span; 38 import io.opencensus.trace.SpanBuilder; 39 import io.opencensus.trace.Status; 40 import io.opencensus.trace.Tracer; 41 import io.opencensus.trace.Tracing; 42 import io.opencensus.trace.config.TraceConfig; 43 import io.opencensus.trace.samplers.Samplers; 44 import io.prometheus.client.exporter.HTTPServer; 45 import java.io.IOException; 46 import java.util.logging.Logger; 47 48 /** Server that manages startup/shutdown of a {@code Greeter} server. */ 49 public class HelloWorldServer { 50 private static final Logger logger = Logger.getLogger(HelloWorldServer.class.getName()); 51 52 private static final Tracer tracer = Tracing.getTracer(); 53 54 private final int serverPort; 55 private Server server; 56 HelloWorldServer(int serverPort)57 private HelloWorldServer(int serverPort) { 58 this.serverPort = serverPort; 59 } 60 61 // A helper function that performs some work in its own Span. performWork(Span parent)62 private static void performWork(Span parent) { 63 SpanBuilder spanBuilder = 64 tracer.spanBuilderWithExplicitParent("internal_work", parent).setRecordEvents(true); 65 try (Scope scope = spanBuilder.startScopedSpan()) { 66 Span span = tracer.getCurrentSpan(); 67 span.putAttribute("my_attribute", AttributeValue.stringAttributeValue("blue")); 68 span.addAnnotation("Performing work."); 69 sleepFor(20); // Working hard here. 70 span.addAnnotation("Done work."); 71 } 72 } 73 sleepFor(int milliseconds)74 private static void sleepFor(int milliseconds) { 75 try { 76 Thread.sleep(milliseconds); 77 } catch (InterruptedException e) { 78 Span span = tracer.getCurrentSpan(); 79 span.addAnnotation("Exception thrown when performing work " + e.getMessage()); 80 span.setStatus(Status.UNKNOWN); 81 } 82 } 83 start()84 private void start() throws IOException { 85 server = ServerBuilder.forPort(serverPort).addService(new GreeterImpl()).build().start(); 86 logger.info("Server started, listening on " + serverPort); 87 Runtime.getRuntime() 88 .addShutdownHook( 89 new Thread() { 90 @Override 91 public void run() { 92 // Use stderr here since the logger may have been reset by its JVM shutdown hook. 93 System.err.println("*** shutting down gRPC server since JVM is shutting down"); 94 HelloWorldServer.this.stop(); 95 System.err.println("*** server shut down"); 96 } 97 }); 98 } 99 stop()100 private void stop() { 101 if (server != null) { 102 server.shutdown(); 103 } 104 } 105 106 /** Await termination on the main thread since the grpc library uses daemon threads. */ blockUntilShutdown()107 private void blockUntilShutdown() throws InterruptedException { 108 if (server != null) { 109 server.awaitTermination(); 110 } 111 } 112 113 /** Main launches the server from the command line. */ main(String[] args)114 public static void main(String[] args) throws IOException, InterruptedException { 115 // Add final keyword to pass checkStyle. 116 final int serverPort = getPortOrDefaultFromArgs(args, 0, 50051); 117 final String cloudProjectId = getStringOrDefaultFromArgs(args, 1, null); 118 final int zPagePort = getPortOrDefaultFromArgs(args, 2, 3000); 119 final int prometheusPort = getPortOrDefaultFromArgs(args, 3, 9090); 120 121 // For demo purposes, always sample 122 TraceConfig traceConfig = Tracing.getTraceConfig(); 123 traceConfig.updateActiveTraceParams( 124 traceConfig.getActiveTraceParams().toBuilder().setSampler(Samplers.alwaysSample()).build()); 125 126 // Registers all RPC views. For demonstration all views are registered. You may want to 127 // start with registering basic views and register other views as needed for your application. 128 RpcViews.registerAllViews(); 129 130 // Registers logging trace exporter. 131 LoggingTraceExporter.register(); 132 133 // Starts a HTTP server and registers all Zpages to it. 134 ZPageHandlers.startHttpServerAndRegisterAll(zPagePort); 135 logger.info("ZPages server starts at localhost:" + zPagePort); 136 137 // Registers Stackdriver exporters. 138 if (cloudProjectId != null) { 139 StackdriverTraceExporter.createAndRegister( 140 StackdriverTraceConfiguration.builder().setProjectId(cloudProjectId).build()); 141 StackdriverStatsExporter.createAndRegister( 142 StackdriverStatsConfiguration.builder() 143 .setProjectId(cloudProjectId) 144 .setExportInterval(Duration.create(5, 0)) 145 .build()); 146 } 147 148 // Register Prometheus exporters and export metrics to a Prometheus HTTPServer. 149 PrometheusStatsCollector.createAndRegister(); 150 HTTPServer prometheusServer = new HTTPServer(prometheusPort, true); 151 152 // Start the RPC server. You shouldn't see any output from gRPC before this. 153 logger.info("gRPC starting."); 154 final HelloWorldServer server = new HelloWorldServer(serverPort); 155 server.start(); 156 server.blockUntilShutdown(); 157 } 158 159 static class GreeterImpl extends GreeterGrpc.GreeterImplBase { 160 161 @Override sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver)162 public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) { 163 Span span = tracer.getCurrentSpan(); 164 span.putAttribute("my_attribute", AttributeValue.stringAttributeValue("red")); 165 span.addAnnotation( 166 "Constructing greeting.", 167 ImmutableMap.of( 168 "name", AttributeValue.stringAttributeValue(req.getName()), 169 "name length", AttributeValue.longAttributeValue(req.getName().length()))); 170 sleepFor(10); 171 performWork(span); 172 span.addAnnotation("Sleeping."); 173 sleepFor(30); 174 HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + req.getName()).build(); 175 responseObserver.onNext(reply); 176 responseObserver.onCompleted(); 177 logger.info("SayHello RPC handled."); 178 } 179 } 180 } 181