• 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.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