• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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