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