aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorYang Song <songy23@users.noreply.github.com>2018-03-17 16:53:41 -0700
committerGitHub <noreply@github.com>2018-03-17 16:53:41 -0700
commit8bce79cde63190d3703af222782871533f7ea1a8 (patch)
treeb2a61bd985c557b9ef5b0240576b6724019c4899 /examples
parentafd18e36232e74823c867f0a13b3d39ac313221d (diff)
downloadopencensus-java-8bce79cde63190d3703af222782871533f7ea1a8.tar.gz
Add a gRPC Hello World example. (#1044)
Diffstat (limited to 'examples')
-rw-r--r--examples/BUILD.bazel3
-rw-r--r--examples/README.md30
-rw-r--r--examples/build.gradle72
-rw-r--r--examples/pom.xml74
-rw-r--r--examples/src/main/java/io/opencensus/examples/grpc/helloworld/HelloWorldClient.java151
-rw-r--r--examples/src/main/java/io/opencensus/examples/grpc/helloworld/HelloWorldServer.java176
-rw-r--r--examples/src/main/java/io/opencensus/examples/grpc/helloworld/HelloWorldUtils.java50
-rw-r--r--examples/src/main/proto/helloworld.proto39
8 files changed, 590 insertions, 5 deletions
diff --git a/examples/BUILD.bazel b/examples/BUILD.bazel
index 82f322e7..6245c0a3 100644
--- a/examples/BUILD.bazel
+++ b/examples/BUILD.bazel
@@ -4,7 +4,8 @@ opencensus_java_libraries()
java_library(
name = "opencensus_examples",
srcs = glob(
- ["src/main/java/**/*.java"]
+ ["src/main/java/**/*.java"],
+ exclude = ["src/main/java/io/opencensus/examples/grpc/**/*.java"],
),
deps = [
"@io_opencensus_opencensus_api//jar",
diff --git a/examples/README.md b/examples/README.md
index e7a270c4..62324f20 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -78,3 +78,33 @@ $ ./target/appassembler/bin/QuickStart
```
$ ./bazel-bin/QuickStart
```
+
+## To run "gRPC Hello World" example use
+
+Please note all the arguments are optional. If you do not specify these arguments, default values
+will be used:
+
+* host and serverPort will be "localhost:50051"
+* user will be "world"
+* cloudProjectId will be null (which means no stats/spans will be exported to Stackdriver)
+* server zPagePort will be 3000
+* client zPagePort will be 3001
+* Prometheus port will be 9090
+
+
+However, if you want to specify any of these arguements, please make sure they are in order.
+
+### Gradle
+```
+$ ./build/install/opencensus-examples/bin/HelloWorldServer serverPort cloudProjectId zPagePort prometheusPort
+$ ./build/install/opencensus-examples/bin/HelloWorldClient user host serverPort cloudProjectId zPagePort
+```
+
+### Maven
+```
+$ ./target/appassembler/bin/HelloWorldServer serverPort cloudProjectId zPagePort prometheusPort
+$ ./target/appassembler/bin/HelloWorldClient user host serverPort cloudProjectId zPagePort
+```
+
+### Bazel
+TODO \ No newline at end of file
diff --git a/examples/build.gradle b/examples/build.gradle
index ab5de34a..163b0b80 100644
--- a/examples/build.gradle
+++ b/examples/build.gradle
@@ -10,12 +10,14 @@ buildscript {
}
dependencies {
classpath "gradle.plugin.com.github.sherter.google-java-format:google-java-format-gradle-plugin:0.6"
+ classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.3'
}
}
apply plugin: 'checkstyle'
apply plugin: 'idea'
apply plugin: 'java'
+apply plugin: 'com.google.protobuf'
// Plugins that require java8
if (JavaVersion.current().isJava8Compatible()) {
apply plugin: 'com.github.sherter.google-java-format'
@@ -30,6 +32,8 @@ group = "io.opencensus"
version = "0.13.0-SNAPSHOT" // CURRENT_OPENCENSUS_VERSION
def opencensusVersion = "0.12.2" // LATEST_OPENCENSUS_RELEASE_VERSION
+def grpcVersion = "1.9.0" // CURRENT_GRPC_VERSION
+def prometheusVersion = "0.3.0"
checkstyle {
configFile = file("$rootDir/../buildscripts/checkstyle.xml")
@@ -41,6 +45,11 @@ checkstyle {
configProperties["rootDir"] = file("$rootDir/../")
}
+checkstyleMain {
+ // This skips proto generated files beucasue they are in gen_gradle/src/main/**
+ source = fileTree(dir: "src/main", include: "**/*.java")
+}
+
// Google formatter works only on java8.
if (JavaVersion.current().isJava8Compatible()) {
googleJavaFormat {
@@ -49,12 +58,14 @@ if (JavaVersion.current().isJava8Compatible()) {
afterEvaluate { // Allow subproject to add more source sets.
tasks.googleJavaFormat {
- source = sourceSets*.allJava
+ // This skips proto generated files beucasue they are in gen_gradle/src/main/**
+ source = "src/main"
include '**/*.java'
}
tasks.verifyGoogleJavaFormat {
- source = sourceSets*.allJava
+ // This skips proto generated files beucasue they are in gen_gradle/src/main/**
+ source = "src/main"
include '**/*.java'
}
}
@@ -66,13 +77,50 @@ tasks.withType(JavaCompile) {
}
dependencies {
- compile "io.opencensus:opencensus-api:${opencensusVersion}",
+ compile "com.google.api.grpc:proto-google-common-protos:1.0.5",
+ "io.opencensus:opencensus-api:${opencensusVersion}",
"io.opencensus:opencensus-contrib-zpages:${opencensusVersion}",
- "io.opencensus:opencensus-exporter-trace-logging:${opencensusVersion}"
+ "io.opencensus:opencensus-contrib-grpc-metrics:${opencensusVersion}",
+ "io.opencensus:opencensus-exporter-stats-prometheus:${opencensusVersion}",
+ "io.opencensus:opencensus-exporter-stats-stackdriver:${opencensusVersion}",
+ "io.opencensus:opencensus-exporter-trace-stackdriver:${opencensusVersion}",
+ "io.opencensus:opencensus-exporter-trace-logging:${opencensusVersion}",
+ "io.grpc:grpc-protobuf:${grpcVersion}",
+ "io.grpc:grpc-stub:${grpcVersion}",
+ "io.grpc:grpc-netty:${grpcVersion}",
+ "io.prometheus:simpleclient_httpserver:${prometheusVersion}"
runtime "io.opencensus:opencensus-impl:${opencensusVersion}"
}
+protobuf {
+ protoc {
+ artifact = 'com.google.protobuf:protoc:3.5.1-1'
+ }
+ plugins {
+ grpc {
+ artifact = "io.grpc:protoc-gen-grpc-java:${grpcVersion}"
+ }
+ }
+ generateProtoTasks {
+ all()*.plugins {
+ grpc {}
+ }
+ ofSourceSet('main')
+ }
+}
+
+// Inform IDEs like IntelliJ IDEA, Eclipse or NetBeans about the generated code.
+sourceSets {
+ main {
+ java {
+ srcDir 'src'
+ srcDirs 'build/generated/source/proto/main/grpc'
+ srcDirs 'build/generated/source/proto/main/java'
+ }
+ }
+}
+
// Provide convenience executables for trying out the examples.
apply plugin: 'application'
@@ -120,6 +168,20 @@ task quickStart(type: CreateStartScripts) {
classpath = jar.outputs.files + project.configurations.runtime
}
+task helloWorldServer(type: CreateStartScripts) {
+ mainClassName = 'io.opencensus.examples.grpc.helloworld.HelloWorldServer'
+ applicationName = 'HelloWorldServer'
+ outputDir = new File(project.buildDir, 'tmp')
+ classpath = jar.outputs.files + project.configurations.runtime
+}
+
+task helloWorldClient(type: CreateStartScripts) {
+ mainClassName = 'io.opencensus.examples.grpc.helloworld.HelloWorldClient'
+ applicationName = 'HelloWorldClient'
+ outputDir = new File(project.buildDir, 'tmp')
+ classpath = jar.outputs.files + project.configurations.runtime
+}
+
applicationDistribution.into('bin') {
from(multiSpansTracing)
from(multiSpansScopedTracing)
@@ -127,5 +189,7 @@ applicationDistribution.into('bin') {
from(statsRunner)
from(zPagesTester)
from(quickStart)
+ from(helloWorldServer)
+ from(helloWorldClient)
fileMode = 0755
}
diff --git a/examples/pom.xml b/examples/pom.xml
index 468f9774..38c6d6d0 100644
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -11,6 +11,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- change to the version you want to use. -->
<opencensus.version>0.12.2</opencensus.version><!-- LATEST_OPENCENSUS_RELEASE_VERSION -->
+ <grpc.version>1.9.0</grpc.version><!-- CURRENT_GRPC_VERSION -->
</properties>
<dependencies>
<dependency>
@@ -20,15 +21,55 @@
</dependency>
<dependency>
<groupId>io.opencensus</groupId>
+ <artifactId>opencensus-contrib-grpc-metrics</artifactId>
+ <version>${opencensus.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.opencensus</groupId>
<artifactId>opencensus-contrib-zpages</artifactId>
<version>${opencensus.version}</version>
</dependency>
<dependency>
<groupId>io.opencensus</groupId>
+ <artifactId>opencensus-exporter-stats-stackdriver</artifactId>
+ <version>${opencensus.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.opencensus</groupId>
+ <artifactId>opencensus-exporter-stats-prometheus</artifactId>
+ <version>${opencensus.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.opencensus</groupId>
+ <artifactId>opencensus-exporter-trace-stackdriver</artifactId>
+ <version>${opencensus.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.opencensus</groupId>
<artifactId>opencensus-exporter-trace-logging</artifactId>
<version>${opencensus.version}</version>
</dependency>
<dependency>
+ <groupId>io.grpc</groupId>
+ <artifactId>grpc-netty</artifactId>
+ <version>${grpc.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.grpc</groupId>
+ <artifactId>grpc-protobuf</artifactId>
+ <version>${grpc.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.grpc</groupId>
+ <artifactId>grpc-stub</artifactId>
+ <version>${grpc.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.prometheus</groupId>
+ <artifactId>simpleclient_httpserver</artifactId>
+ <version>0.3.0</version>
+ </dependency>
+ <dependency>
<groupId>io.opencensus</groupId>
<artifactId>opencensus-impl</artifactId>
<version>${opencensus.version}</version>
@@ -36,6 +77,13 @@
</dependency>
</dependencies>
<build>
+ <extensions>
+ <extension>
+ <groupId>kr.motd.maven</groupId>
+ <artifactId>os-maven-plugin</artifactId>
+ <version>1.5.0.Final</version>
+ </extension>
+ </extensions>
<pluginManagement>
<plugins>
<plugin>
@@ -80,9 +128,35 @@
<id>QuickStart</id>
<mainClass>io.opencensus.examples.helloworld.QuickStart</mainClass>
</program>
+ <program>
+ <id>HelloWorldClient</id>
+ <mainClass>io.opencensus.examples.grpc.helloworld.HelloWorldClient</mainClass>
+ </program>
+ <program>
+ <id>HelloWorldServer</id>
+ <mainClass>io.opencensus.examples.grpc.helloworld.HelloWorldServer</mainClass>
+ </program>
</programs>
</configuration>
</plugin>
+ <plugin>
+ <groupId>org.xolstice.maven.plugins</groupId>
+ <artifactId>protobuf-maven-plugin</artifactId>
+ <version>0.5.0</version>
+ <configuration>
+ <protocArtifact>com.google.protobuf:protoc:3.5.1-1:exe:${os.detected.classifier}</protocArtifact>
+ <pluginId>grpc-java</pluginId>
+ <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
+ </configuration>
+ <executions>
+ <execution>
+ <goals>
+ <goal>compile</goal>
+ <goal>compile-custom</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
</plugins>
</build>
</project>
diff --git a/examples/src/main/java/io/opencensus/examples/grpc/helloworld/HelloWorldClient.java b/examples/src/main/java/io/opencensus/examples/grpc/helloworld/HelloWorldClient.java
new file mode 100644
index 00000000..30e41633
--- /dev/null
+++ b/examples/src/main/java/io/opencensus/examples/grpc/helloworld/HelloWorldClient.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2018, OpenCensus Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.opencensus.examples.grpc.helloworld;
+
+import static io.opencensus.examples.grpc.helloworld.HelloWorldUtils.getPortOrDefaultFromArgs;
+import static io.opencensus.examples.grpc.helloworld.HelloWorldUtils.getStringOrDefaultFromArgs;
+
+import io.grpc.ManagedChannel;
+import io.grpc.ManagedChannelBuilder;
+import io.grpc.StatusRuntimeException;
+import io.opencensus.common.Duration;
+import io.opencensus.common.Scope;
+import io.opencensus.contrib.grpc.metrics.RpcViews;
+import io.opencensus.contrib.zpages.ZPageHandlers;
+import io.opencensus.exporter.stats.prometheus.PrometheusStatsCollector;
+import io.opencensus.exporter.stats.stackdriver.StackdriverStatsConfiguration;
+import io.opencensus.exporter.stats.stackdriver.StackdriverStatsExporter;
+import io.opencensus.exporter.trace.logging.LoggingTraceExporter;
+import io.opencensus.exporter.trace.stackdriver.StackdriverTraceConfiguration;
+import io.opencensus.exporter.trace.stackdriver.StackdriverTraceExporter;
+import io.opencensus.trace.SpanBuilder;
+import io.opencensus.trace.Status.CanonicalCode;
+import io.opencensus.trace.Tracer;
+import io.opencensus.trace.Tracing;
+import io.opencensus.trace.samplers.Samplers;
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/** A simple client that requests a greeting from the {@link HelloWorldServer}. */
+public class HelloWorldClient {
+ private static final Logger logger = Logger.getLogger(HelloWorldClient.class.getName());
+
+ private static final Tracer tracer = Tracing.getTracer();
+
+ private final ManagedChannel channel;
+ private final GreeterGrpc.GreeterBlockingStub blockingStub;
+
+ /** Construct client connecting to HelloWorld server at {@code host:port}. */
+ public HelloWorldClient(String host, int port) {
+ this(
+ ManagedChannelBuilder.forAddress(host, port)
+ // Channels are secure by default (via SSL/TLS). For the example we disable TLS to avoid
+ // needing certificates.
+ .usePlaintext(true)
+ .build());
+ }
+
+ /** Construct client for accessing RouteGuide server using the existing channel. */
+ HelloWorldClient(ManagedChannel channel) {
+ this.channel = channel;
+ blockingStub = GreeterGrpc.newBlockingStub(channel);
+ }
+
+ public void shutdown() throws InterruptedException {
+ channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
+ }
+
+ /** Say hello to server. */
+ public void greet(String name) {
+ logger.info("Will try to greet " + name + " ...");
+ HelloRequest request = HelloRequest.newBuilder().setName(name).build();
+ HelloReply response;
+
+ SpanBuilder spanBuilder =
+ tracer.spanBuilder("client").setRecordEvents(true).setSampler(Samplers.alwaysSample());
+ try (Scope scope = spanBuilder.startScopedSpan()) {
+ tracer.getCurrentSpan().addAnnotation("Saying Hello to Server.");
+ response = blockingStub.sayHello(request);
+ tracer.getCurrentSpan().addAnnotation("Received response from Server.");
+ } catch (StatusRuntimeException e) {
+ tracer
+ .getCurrentSpan()
+ .setStatus(
+ CanonicalCode.valueOf(e.getStatus().getCode().name())
+ .toStatus()
+ .withDescription(e.getMessage()));
+ logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus());
+ return;
+ }
+ logger.info("Greeting: " + response.getMessage());
+ }
+
+ /**
+ * Greet server. If provided, the first element of {@code args} is the name to use in the
+ * greeting.
+ */
+ public static void main(String[] args) throws IOException, InterruptedException {
+ // Add final keyword to pass checkStyle.
+ final String user = getStringOrDefaultFromArgs(args, 0, "world");
+ final String host = getStringOrDefaultFromArgs(args, 1, "localhost");
+ final int serverPort = getPortOrDefaultFromArgs(args, 2, 50051);
+ final String cloudProjectId = getStringOrDefaultFromArgs(args, 3, null);
+ final int zPagePort = getPortOrDefaultFromArgs(args, 4, 3001);
+
+ // Registers all RPC views.
+ RpcViews.registerAllViews();
+
+ // Starts a HTTP server and registers all Zpages to it.
+ ZPageHandlers.startHttpServerAndRegisterAll(zPagePort);
+ logger.info("ZPages server starts at localhost:" + zPagePort);
+
+ // Registers logging trace exporter.
+ LoggingTraceExporter.register();
+
+ // Registers Stackdriver exporters.
+ if (cloudProjectId != null) {
+ StackdriverTraceExporter.createAndRegister(
+ StackdriverTraceConfiguration.builder().setProjectId(cloudProjectId).build());
+ StackdriverStatsExporter.createAndRegister(
+ StackdriverStatsConfiguration.builder()
+ .setProjectId(cloudProjectId)
+ .setExportInterval(Duration.create(15, 0))
+ .build());
+ }
+
+ // Register Prometheus exporters and export metrics to a Prometheus HTTPServer.
+ PrometheusStatsCollector.createAndRegister();
+
+ HelloWorldClient client = new HelloWorldClient(host, serverPort);
+ try {
+ client.greet(user);
+ } finally {
+ client.shutdown();
+ }
+
+ logger.info("Client sleeping, ^C to exit. Meanwhile you can view stats and spans on zpages.");
+ while (true) {
+ try {
+ Thread.sleep(10000);
+ } catch (InterruptedException e) {
+ logger.info("Exiting HelloWorldClient...");
+ }
+ }
+ }
+}
diff --git a/examples/src/main/java/io/opencensus/examples/grpc/helloworld/HelloWorldServer.java b/examples/src/main/java/io/opencensus/examples/grpc/helloworld/HelloWorldServer.java
new file mode 100644
index 00000000..15a0a896
--- /dev/null
+++ b/examples/src/main/java/io/opencensus/examples/grpc/helloworld/HelloWorldServer.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2018, OpenCensus Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.opencensus.examples.grpc.helloworld;
+
+import static io.opencensus.examples.grpc.helloworld.HelloWorldUtils.getPortOrDefaultFromArgs;
+import static io.opencensus.examples.grpc.helloworld.HelloWorldUtils.getStringOrDefaultFromArgs;
+
+import com.google.common.collect.ImmutableMap;
+import io.grpc.Server;
+import io.grpc.ServerBuilder;
+import io.grpc.stub.StreamObserver;
+import io.opencensus.common.Duration;
+import io.opencensus.common.Scope;
+import io.opencensus.contrib.grpc.metrics.RpcViews;
+import io.opencensus.contrib.zpages.ZPageHandlers;
+import io.opencensus.exporter.stats.prometheus.PrometheusStatsCollector;
+import io.opencensus.exporter.stats.stackdriver.StackdriverStatsConfiguration;
+import io.opencensus.exporter.stats.stackdriver.StackdriverStatsExporter;
+import io.opencensus.exporter.trace.logging.LoggingTraceExporter;
+import io.opencensus.exporter.trace.stackdriver.StackdriverTraceConfiguration;
+import io.opencensus.exporter.trace.stackdriver.StackdriverTraceExporter;
+import io.opencensus.trace.AttributeValue;
+import io.opencensus.trace.Span;
+import io.opencensus.trace.SpanBuilder;
+import io.opencensus.trace.Status;
+import io.opencensus.trace.Tracer;
+import io.opencensus.trace.Tracing;
+import io.opencensus.trace.samplers.Samplers;
+import io.prometheus.client.exporter.HTTPServer;
+import java.io.IOException;
+import java.util.logging.Logger;
+
+/** Server that manages startup/shutdown of a {@code Greeter} server. */
+public class HelloWorldServer {
+ private static final Logger logger = Logger.getLogger(HelloWorldServer.class.getName());
+
+ private static final Tracer tracer = Tracing.getTracer();
+
+ private final int serverPort;
+ private Server server;
+
+ private HelloWorldServer(int serverPort) {
+ this.serverPort = serverPort;
+ }
+
+ // A helper function that performs some work in its own Span.
+ private static void performWork(Span parent) {
+ SpanBuilder spanBuilder =
+ tracer
+ .spanBuilderWithExplicitParent("internal_work", parent)
+ .setRecordEvents(true)
+ .setSampler(Samplers.alwaysSample());
+ try (Scope scope = spanBuilder.startScopedSpan()) {
+ Span span = tracer.getCurrentSpan();
+ span.putAttribute("my_attribute", AttributeValue.stringAttributeValue("blue"));
+ span.addAnnotation("Performing work.");
+ sleepFor(20); // Working hard here.
+ span.addAnnotation("Done work.");
+ }
+ }
+
+ private static void sleepFor(int milliseconds) {
+ try {
+ Thread.sleep(milliseconds);
+ } catch (InterruptedException e) {
+ Span span = tracer.getCurrentSpan();
+ span.addAnnotation("Exception thrown when performing work " + e.getMessage());
+ span.setStatus(Status.UNKNOWN);
+ }
+ }
+
+ private void start() throws IOException {
+ server = ServerBuilder.forPort(serverPort).addService(new GreeterImpl()).build().start();
+ logger.info("Server started, listening on " + serverPort);
+ Runtime.getRuntime()
+ .addShutdownHook(
+ new Thread() {
+ @Override
+ public void run() {
+ // Use stderr here since the logger may have been reset by its JVM shutdown hook.
+ System.err.println("*** shutting down gRPC server since JVM is shutting down");
+ HelloWorldServer.this.stop();
+ System.err.println("*** server shut down");
+ }
+ });
+ }
+
+ private void stop() {
+ if (server != null) {
+ server.shutdown();
+ }
+ }
+
+ /** Await termination on the main thread since the grpc library uses daemon threads. */
+ private void blockUntilShutdown() throws InterruptedException {
+ if (server != null) {
+ server.awaitTermination();
+ }
+ }
+
+ /** Main launches the server from the command line. */
+ public static void main(String[] args) throws IOException, InterruptedException {
+ // Add final keyword to pass checkStyle.
+ final int serverPort = getPortOrDefaultFromArgs(args, 0, 50051);
+ final String cloudProjectId = getStringOrDefaultFromArgs(args, 1, null);
+ final int zPagePort = getPortOrDefaultFromArgs(args, 2, 3000);
+ final int prometheusPort = getPortOrDefaultFromArgs(args, 3, 9090);
+
+ // Registers all RPC views.
+ RpcViews.registerAllViews();
+
+ // Registers logging trace exporter.
+ LoggingTraceExporter.register();
+
+ // Starts a HTTP server and registers all Zpages to it.
+ ZPageHandlers.startHttpServerAndRegisterAll(zPagePort);
+ logger.info("ZPages server starts at localhost:" + zPagePort);
+
+ // Registers Stackdriver exporters.
+ if (cloudProjectId != null) {
+ StackdriverTraceExporter.createAndRegister(
+ StackdriverTraceConfiguration.builder().setProjectId(cloudProjectId).build());
+ StackdriverStatsExporter.createAndRegister(
+ StackdriverStatsConfiguration.builder()
+ .setProjectId(cloudProjectId)
+ .setExportInterval(Duration.create(15, 0))
+ .build());
+ }
+
+ // Register Prometheus exporters and export metrics to a Prometheus HTTPServer.
+ PrometheusStatsCollector.createAndRegister();
+ HTTPServer prometheusServer = new HTTPServer(prometheusPort, true);
+
+ // Start the RPC server. You shouldn't see any output from gRPC before this.
+ logger.info("gRPC starting.");
+ final HelloWorldServer server = new HelloWorldServer(serverPort);
+ server.start();
+ server.blockUntilShutdown();
+ }
+
+ static class GreeterImpl extends GreeterGrpc.GreeterImplBase {
+
+ @Override
+ public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) {
+ Span span = tracer.getCurrentSpan();
+ span.putAttribute("my_attribute", AttributeValue.stringAttributeValue("red"));
+ span.addAnnotation(
+ "Constructing greeting.",
+ ImmutableMap.of(
+ "name", AttributeValue.stringAttributeValue(req.getName()),
+ "name length", AttributeValue.longAttributeValue(req.getName().length())));
+ sleepFor(10);
+ performWork(span);
+ span.addAnnotation("Sleeping.");
+ sleepFor(30);
+ HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + req.getName()).build();
+ responseObserver.onNext(reply);
+ responseObserver.onCompleted();
+ logger.info("SayHello RPC handled.");
+ }
+ }
+}
diff --git a/examples/src/main/java/io/opencensus/examples/grpc/helloworld/HelloWorldUtils.java b/examples/src/main/java/io/opencensus/examples/grpc/helloworld/HelloWorldUtils.java
new file mode 100644
index 00000000..f6dcdaab
--- /dev/null
+++ b/examples/src/main/java/io/opencensus/examples/grpc/helloworld/HelloWorldUtils.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2018, OpenCensus Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.opencensus.examples.grpc.helloworld;
+
+import java.util.logging.Logger;
+import javax.annotation.Nullable;
+
+/** Util methods. */
+final class HelloWorldUtils {
+
+ private static Logger logger = Logger.getLogger(HelloWorldUtils.class.getName());
+
+ static int getPortOrDefaultFromArgs(String[] args, int index, int defaultPort) {
+ int portNumber = defaultPort;
+ if (index < args.length) {
+ try {
+ portNumber = Integer.parseInt(args[index]);
+ } catch (NumberFormatException e) {
+ logger.warning(
+ String.format("Port %s is invalid, use default port %d.", args[index], defaultPort));
+ }
+ }
+ return portNumber;
+ }
+
+ static String getStringOrDefaultFromArgs(
+ String[] args, int index, @Nullable String defaultString) {
+ String s = defaultString;
+ if (index < args.length) {
+ s = args[index];
+ }
+ return s;
+ }
+
+ private HelloWorldUtils() {}
+}
diff --git a/examples/src/main/proto/helloworld.proto b/examples/src/main/proto/helloworld.proto
new file mode 100644
index 00000000..1bd79300
--- /dev/null
+++ b/examples/src/main/proto/helloworld.proto
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2018, OpenCensus Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+
+option java_multiple_files = true;
+option java_package = "io.opencensus.examples.grpc.helloworld";
+option java_outer_classname = "HelloWorldProto";
+
+package helloworld;
+
+// The greeting service definition.
+service Greeter {
+ // Sends a greeting
+ rpc SayHello (HelloRequest) returns (HelloReply) {}
+}
+
+// The request message containing the user's name.
+message HelloRequest {
+ string name = 1;
+}
+
+// The response message containing the greetings
+message HelloReply {
+ string message = 1;
+}