diff options
Diffstat (limited to 'examples/src/main')
11 files changed, 995 insertions, 0 deletions
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..55d6c225 --- /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 final 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/java/io/opencensus/examples/helloworld/QuickStart.java b/examples/src/main/java/io/opencensus/examples/helloworld/QuickStart.java new file mode 100644 index 00000000..c71e0f3e --- /dev/null +++ b/examples/src/main/java/io/opencensus/examples/helloworld/QuickStart.java @@ -0,0 +1,111 @@ +/* + * 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.helloworld; + +import io.opencensus.common.Scope; +import io.opencensus.exporter.trace.logging.LoggingTraceExporter; +import io.opencensus.stats.Aggregation; +import io.opencensus.stats.BucketBoundaries; +import io.opencensus.stats.Measure.MeasureLong; +import io.opencensus.stats.Stats; +import io.opencensus.stats.StatsRecorder; +import io.opencensus.stats.View; +import io.opencensus.stats.ViewData; +import io.opencensus.stats.ViewManager; +import io.opencensus.tags.TagContextBuilder; +import io.opencensus.tags.TagKey; +import io.opencensus.tags.TagValue; +import io.opencensus.tags.Tagger; +import io.opencensus.tags.Tags; +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 java.util.Arrays; +import java.util.Collections; +import java.util.Random; +import java.util.logging.Logger; + +/** Simple program that collects data for video size. */ +public final class QuickStart { + + private static final Logger logger = Logger.getLogger(QuickStart.class.getName()); + + private static final Tagger tagger = Tags.getTagger(); + private static final ViewManager viewManager = Stats.getViewManager(); + private static final StatsRecorder statsRecorder = Stats.getStatsRecorder(); + private static final Tracer tracer = Tracing.getTracer(); + + // frontendKey allows us to break down the recorded data. + private static final TagKey FRONTEND_KEY = TagKey.create("my.org/keys/frontend"); + + // videoSize will measure the size of processed videos. + private static final MeasureLong VIDEO_SIZE = + MeasureLong.create("my.org/measure/video_size", "size of processed videos", "By"); + + private static final long MiB = 1 << 20; + + // Create view to see the processed video size distribution broken down by frontend. + // The view has bucket boundaries (0, 16 * MiB, 65536 * MiB) that will group measure + // values into histogram buckets. + private static final View.Name VIDEO_SIZE_VIEW_NAME = View.Name.create("my.org/views/video_size"); + private static final View VIDEO_SIZE_VIEW = + View.create( + VIDEO_SIZE_VIEW_NAME, + "processed video size over time", + VIDEO_SIZE, + Aggregation.Distribution.create( + BucketBoundaries.create(Arrays.asList(0.0, 16.0 * MiB, 256.0 * MiB))), + Collections.singletonList(FRONTEND_KEY)); + + /** Main launcher for the QuickStart example. */ + public static void main(String[] args) throws InterruptedException { + TagContextBuilder tagContextBuilder = + tagger.currentBuilder().put(FRONTEND_KEY, TagValue.create("mobile-ios9.3.5")); + SpanBuilder spanBuilder = + tracer + .spanBuilder("my.org/ProcessVideo") + .setRecordEvents(true) + .setSampler(Samplers.alwaysSample()); + viewManager.registerView(VIDEO_SIZE_VIEW); + LoggingTraceExporter.register(); + + // Process video. + // Record the processed video size. + try (Scope scopedTags = tagContextBuilder.buildScoped(); + Scope scopedSpan = spanBuilder.startScopedSpan()) { + tracer.getCurrentSpan().addAnnotation("Start processing video."); + // Sleep for [0,10] milliseconds to fake work. + Thread.sleep(new Random().nextInt(10) + 1); + statsRecorder.newMeasureMap().put(VIDEO_SIZE, 25 * MiB).record(); + tracer.getCurrentSpan().addAnnotation("Finished processing video."); + } catch (Exception e) { + tracer.getCurrentSpan().addAnnotation("Exception thrown when processing video."); + tracer.getCurrentSpan().setStatus(Status.UNKNOWN); + logger.severe(e.getMessage()); + } + + logger.info("Wait longer than the reporting duration..."); + // Wait for a duration longer than reporting duration (5s) to ensure spans are exported. + // TODO(songya): remove the gap once we add a shutdown hook for exporting unflushed spans. + Thread.sleep(5100); + ViewData viewData = viewManager.getView(VIDEO_SIZE_VIEW_NAME); + logger.info( + String.format("Recorded stats for %s:\n %s", VIDEO_SIZE_VIEW_NAME.asString(), viewData)); + } +} diff --git a/examples/src/main/java/io/opencensus/examples/tags/TagContextExample.java b/examples/src/main/java/io/opencensus/examples/tags/TagContextExample.java new file mode 100644 index 00000000..727c5fbb --- /dev/null +++ b/examples/src/main/java/io/opencensus/examples/tags/TagContextExample.java @@ -0,0 +1,77 @@ +/* + * Copyright 2016-17, 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.tags; + +import io.opencensus.common.Scope; +import io.opencensus.stats.Measure.MeasureDouble; +import io.opencensus.stats.Stats; +import io.opencensus.stats.StatsRecorder; +import io.opencensus.tags.TagContext; +import io.opencensus.tags.TagKey; +import io.opencensus.tags.TagValue; +import io.opencensus.tags.Tagger; +import io.opencensus.tags.Tags; + +/** Simple program that uses {@link TagContext}. */ +public class TagContextExample { + + private static final TagKey K1 = TagKey.create("k1"); + private static final TagKey K2 = TagKey.create("k2"); + private static final TagKey K3 = TagKey.create("k3"); + private static final TagKey K4 = TagKey.create("k4"); + + private static final TagValue V1 = TagValue.create("v1"); + private static final TagValue V2 = TagValue.create("v2"); + private static final TagValue V3 = TagValue.create("v3"); + private static final TagValue V4 = TagValue.create("v4"); + + private static final String UNIT = "1"; + private static final MeasureDouble M1 = MeasureDouble.create("m1", "1st test metric", UNIT); + private static final MeasureDouble M2 = MeasureDouble.create("m2", "2nd test metric", UNIT); + + private static final Tagger tagger = Tags.getTagger(); + private static final StatsRecorder statsRecorder = Stats.getStatsRecorder(); + + private TagContextExample() {} + + /** + * Main method. + * + * @param args the main arguments. + */ + public static void main(String[] args) { + System.out.println("Hello Stats World"); + System.out.println("Default Tags: " + tagger.empty()); + System.out.println("Current Tags: " + tagger.getCurrentTagContext()); + TagContext tags1 = tagger.emptyBuilder().put(K1, V1).put(K2, V2).build(); + try (Scope scopedTagCtx1 = tagger.withTagContext(tags1)) { + System.out.println(" Current Tags: " + tagger.getCurrentTagContext()); + System.out.println( + " Current == Default + tags1: " + tagger.getCurrentTagContext().equals(tags1)); + TagContext tags2 = tagger.toBuilder(tags1).put(K3, V3).put(K4, V4).build(); + try (Scope scopedTagCtx2 = tagger.withTagContext(tags2)) { + System.out.println(" Current Tags: " + tagger.getCurrentTagContext()); + System.out.println( + " Current == Default + tags1 + tags2: " + + tagger.getCurrentTagContext().equals(tags2)); + statsRecorder.newMeasureMap().put(M1, 0.2).put(M2, 0.4).record(); + } + } + System.out.println( + "Current == Default: " + tagger.getCurrentTagContext().equals(tagger.empty())); + } +} diff --git a/examples/src/main/java/io/opencensus/examples/trace/MultiSpansContextTracing.java b/examples/src/main/java/io/opencensus/examples/trace/MultiSpansContextTracing.java new file mode 100644 index 00000000..c8df144f --- /dev/null +++ b/examples/src/main/java/io/opencensus/examples/trace/MultiSpansContextTracing.java @@ -0,0 +1,89 @@ +/* + * Copyright 2017, 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.trace; + +import static io.opencensus.examples.trace.Utils.sleep; + +import io.opencensus.common.Scope; +import io.opencensus.exporter.trace.logging.LoggingTraceExporter; +import io.opencensus.trace.Span; +import io.opencensus.trace.Tracer; +import io.opencensus.trace.Tracing; +import io.opencensus.trace.config.TraceConfig; +import io.opencensus.trace.samplers.Samplers; + +/** + * Example showing how to create a child {@link Span}, install it to the current context and add + * annotations. + */ +public final class MultiSpansContextTracing { + // Per class Tracer. + private static final Tracer tracer = Tracing.getTracer(); + + private MultiSpansContextTracing() {} + + private static void doSomeOtherWork() { + tracer.getCurrentSpan().addAnnotation("Annotation to the child Span"); + } + + private static void doSomeMoreWork() { + // Create a child Span of the current Span. + Span span = tracer.spanBuilder("MyChildSpan").startSpan(); + try (Scope ws = tracer.withSpan(span)) { + doSomeOtherWork(); + } + span.end(); + } + + private static void doWork() { + tracer.getCurrentSpan().addAnnotation("Annotation to the root Span before child is created."); + doSomeMoreWork(); + tracer.getCurrentSpan().addAnnotation("Annotation to the root Span after child is ended."); + } + + /** + * Main method. + * + * @param args the main arguments. + */ + public static void main(String[] args) { + + // WARNING: Be careful before you set sampler value to always sample, especially in + // production environment. Trace data is often very large in size and is expensive to + // collect. This is why rather than collecting traces for every request(i.e. alwaysSample), + // downsampling is prefered. + // + // By default, OpenCensus provides a probabilistic sampler that will trace once in every + // 10,000 requests, that's why if default probabilistic sampler is used + // you might not see trace data printed or exported and this is expected behavior. + + TraceConfig traceConfig = Tracing.getTraceConfig(); + traceConfig.updateActiveTraceParams( + traceConfig.getActiveTraceParams().toBuilder().setSampler(Samplers.alwaysSample()).build()); + + LoggingTraceExporter.register(); + Span span = tracer.spanBuilderWithExplicitParent("MyRootSpan", null).startSpan(); + try (Scope ws = tracer.withSpan(span)) { + doWork(); + } + span.end(); + + // Wait for a duration longer than reporting duration (5s) to ensure spans are exported. + // Spans are exported every 5 seconds + sleep(5100); + } +} diff --git a/examples/src/main/java/io/opencensus/examples/trace/MultiSpansScopedTracing.java b/examples/src/main/java/io/opencensus/examples/trace/MultiSpansScopedTracing.java new file mode 100644 index 00000000..5cfc9dfc --- /dev/null +++ b/examples/src/main/java/io/opencensus/examples/trace/MultiSpansScopedTracing.java @@ -0,0 +1,85 @@ +/* + * Copyright 2017, 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.trace; + +import static io.opencensus.examples.trace.Utils.sleep; + +import io.opencensus.common.Scope; +import io.opencensus.exporter.trace.logging.LoggingTraceExporter; +import io.opencensus.trace.Span; +import io.opencensus.trace.Tracer; +import io.opencensus.trace.Tracing; +import io.opencensus.trace.config.TraceConfig; +import io.opencensus.trace.samplers.Samplers; + +/** + * Example showing how to create a child {@link Span} using scoped Spans, install it in the current + * context, and add annotations. + */ +public final class MultiSpansScopedTracing { + // Per class Tracer. + private static final Tracer tracer = Tracing.getTracer(); + + private MultiSpansScopedTracing() {} + + private static void doSomeOtherWork() { + tracer.getCurrentSpan().addAnnotation("Annotation to the child Span"); + } + + private static void doSomeMoreWork() { + // Create a child Span of the current Span. + try (Scope ss = tracer.spanBuilder("MyChildSpan").startScopedSpan()) { + doSomeOtherWork(); + } + } + + private static void doWork() { + tracer.getCurrentSpan().addAnnotation("Annotation to the root Span before child is created."); + doSomeMoreWork(); + tracer.getCurrentSpan().addAnnotation("Annotation to the root Span after child is ended."); + } + + /** + * Main method. + * + * @param args the main arguments. + */ + public static void main(String[] args) { + + // WARNING: Be careful before you set sampler value to always sample, especially in + // production environment. Trace data is often very large in size and is expensive to + // collect. This is why rather than collecting traces for every request(i.e. alwaysSample), + // downsampling is prefered. + // + // By default, OpenCensus provides a probabilistic sampler that will trace once in every + // 10,000 requests, that's why if default probabilistic sampler is used + // you might not see trace data printed or exported and this is expected behavior. + + TraceConfig traceConfig = Tracing.getTraceConfig(); + traceConfig.updateActiveTraceParams( + traceConfig.getActiveTraceParams().toBuilder().setSampler(Samplers.alwaysSample()).build()); + + LoggingTraceExporter.register(); + try (Scope ss = tracer.spanBuilderWithExplicitParent("MyRootSpan", null).startScopedSpan()) { + doWork(); + } + + // Wait for a duration longer than reporting duration (5s) to ensure spans are exported. + // Spans are exported every 5 seconds + sleep(5100); + } +} diff --git a/examples/src/main/java/io/opencensus/examples/trace/MultiSpansTracing.java b/examples/src/main/java/io/opencensus/examples/trace/MultiSpansTracing.java new file mode 100644 index 00000000..fae4e3ff --- /dev/null +++ b/examples/src/main/java/io/opencensus/examples/trace/MultiSpansTracing.java @@ -0,0 +1,72 @@ +/* + * Copyright 2017, 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.trace; + +import static io.opencensus.examples.trace.Utils.sleep; + +import io.opencensus.exporter.trace.logging.LoggingTraceExporter; +import io.opencensus.trace.Span; +import io.opencensus.trace.Tracer; +import io.opencensus.trace.Tracing; +import io.opencensus.trace.config.TraceConfig; +import io.opencensus.trace.samplers.Samplers; + +/** Example showing how to directly create a child {@link Span} and add annotations. */ +public final class MultiSpansTracing { + // Per class Tracer. + private static final Tracer tracer = Tracing.getTracer(); + + private MultiSpansTracing() {} + + private static void doWork() { + Span rootSpan = tracer.spanBuilderWithExplicitParent("MyRootSpan", null).startSpan(); + rootSpan.addAnnotation("Annotation to the root Span before child is created."); + Span childSpan = tracer.spanBuilderWithExplicitParent("MyChildSpan", rootSpan).startSpan(); + childSpan.addAnnotation("Annotation to the child Span"); + childSpan.end(); + rootSpan.addAnnotation("Annotation to the root Span after child is ended."); + rootSpan.end(); + } + + /** + * Main method. + * + * @param args the main arguments. + */ + public static void main(String[] args) { + + // WARNING: Be careful before you set sampler value to always sample, especially in + // production environment. Trace data is often very large in size and is expensive to + // collect. This is why rather than collecting traces for every request(i.e. alwaysSample), + // downsampling is prefered. + // + // By default, OpenCensus provides a probabilistic sampler that will trace once in every + // 10,000 requests, that's why if default probabilistic sampler is used + // you might not see trace data printed or exported and this is expected behavior. + + TraceConfig traceConfig = Tracing.getTraceConfig(); + traceConfig.updateActiveTraceParams( + traceConfig.getActiveTraceParams().toBuilder().setSampler(Samplers.alwaysSample()).build()); + + LoggingTraceExporter.register(); + doWork(); + + // Wait for a duration longer than reporting duration (5s) to ensure spans are exported. + // Spans are exported every 5 seconds + sleep(5100); + } +} diff --git a/examples/src/main/java/io/opencensus/examples/trace/Utils.java b/examples/src/main/java/io/opencensus/examples/trace/Utils.java new file mode 100644 index 00000000..9f0338af --- /dev/null +++ b/examples/src/main/java/io/opencensus/examples/trace/Utils.java @@ -0,0 +1,37 @@ +/* + * 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.trace; + +import java.util.logging.Logger; + +/** Util methods. */ +final class Utils { + + private static final Logger logger = Logger.getLogger(Utils.class.getName()); + + static void sleep(int ms) { + // A helper to avoid try-catch when invoking Thread.sleep so that + // sleeps can be succinct and not permeated by exception handling. + try { + Thread.sleep(ms); + } catch (Exception e) { + logger.warning((String.format("Failed to sleep for %dms. Exception: %s", ms, e))); + } + } + + private Utils() {} +} diff --git a/examples/src/main/java/io/opencensus/examples/zpages/ZPagesTester.java b/examples/src/main/java/io/opencensus/examples/zpages/ZPagesTester.java new file mode 100644 index 00000000..282b40ec --- /dev/null +++ b/examples/src/main/java/io/opencensus/examples/zpages/ZPagesTester.java @@ -0,0 +1,108 @@ +/* + * Copyright 2017, 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.zpages; + +import io.opencensus.common.Scope; +import io.opencensus.contrib.grpc.metrics.RpcMeasureConstants; +import io.opencensus.contrib.grpc.metrics.RpcViews; +import io.opencensus.contrib.zpages.ZPageHandlers; +import io.opencensus.stats.MeasureMap; +import io.opencensus.stats.Stats; +import io.opencensus.stats.StatsRecorder; +import io.opencensus.tags.TagValue; +import io.opencensus.tags.Tagger; +import io.opencensus.tags.Tags; +import io.opencensus.trace.SpanBuilder; +import io.opencensus.trace.Tracer; +import io.opencensus.trace.Tracing; +import io.opencensus.trace.samplers.Samplers; +import java.util.Collections; + +/** Testing only class for the UI. */ +public class ZPagesTester { + + private ZPagesTester() {} + + private static final Tagger tagger = Tags.getTagger(); + private static final Tracer tracer = Tracing.getTracer(); + private static final StatsRecorder statsRecorder = Stats.getStatsRecorder(); + + private static final String SPAN_NAME = "ExampleSpan"; + private static final TagValue METHOD = TagValue.create("ExampleMethod"); + + private static void recordExampleData() throws InterruptedException { + Tracing.getExportComponent() + .getSampledSpanStore() + .registerSpanNamesForCollection(Collections.singletonList(SPAN_NAME)); + RpcViews.registerAllViews(); // Use old RPC constants to get interval stats. + SpanBuilder spanBuilder = + tracer.spanBuilder(SPAN_NAME).setRecordEvents(true).setSampler(Samplers.alwaysSample()); + + try (Scope scope = spanBuilder.startScopedSpan()) { + tracer.getCurrentSpan().addAnnotation("Starts recording."); + MeasureMap measureMap = + statsRecorder + .newMeasureMap() + // Client measurements. + .put(RpcMeasureConstants.RPC_CLIENT_STARTED_COUNT, 1) + .put(RpcMeasureConstants.RPC_CLIENT_FINISHED_COUNT, 1) + .put(RpcMeasureConstants.RPC_CLIENT_ROUNDTRIP_LATENCY, 1.0) + .put(RpcMeasureConstants.RPC_CLIENT_REQUEST_COUNT, 1) + .put(RpcMeasureConstants.RPC_CLIENT_RESPONSE_COUNT, 1) + .put(RpcMeasureConstants.RPC_CLIENT_REQUEST_BYTES, 1e5) + .put(RpcMeasureConstants.RPC_CLIENT_RESPONSE_BYTES, 1e5) + .put(RpcMeasureConstants.RPC_CLIENT_UNCOMPRESSED_REQUEST_BYTES, 1e5) + .put(RpcMeasureConstants.RPC_CLIENT_UNCOMPRESSED_RESPONSE_BYTES, 1e5) + // Server measurements. + .put(RpcMeasureConstants.RPC_SERVER_STARTED_COUNT, 1) + .put(RpcMeasureConstants.RPC_SERVER_FINISHED_COUNT, 1) + .put(RpcMeasureConstants.RPC_SERVER_SERVER_LATENCY, 1.0) + .put(RpcMeasureConstants.RPC_SERVER_REQUEST_COUNT, 1) + .put(RpcMeasureConstants.RPC_SERVER_RESPONSE_COUNT, 1) + .put(RpcMeasureConstants.RPC_SERVER_REQUEST_BYTES, 1e5) + .put(RpcMeasureConstants.RPC_SERVER_RESPONSE_BYTES, 1e5) + .put(RpcMeasureConstants.RPC_SERVER_UNCOMPRESSED_REQUEST_BYTES, 1e5) + .put(RpcMeasureConstants.RPC_SERVER_UNCOMPRESSED_RESPONSE_BYTES, 1e5); + measureMap.record( + tagger + .currentBuilder() + .put(RpcMeasureConstants.RPC_STATUS, TagValue.create("OK")) + .put(RpcMeasureConstants.RPC_METHOD, METHOD) + .build()); + MeasureMap measureMapErrors = + statsRecorder + .newMeasureMap() + .put(RpcMeasureConstants.RPC_CLIENT_ERROR_COUNT, 1) + .put(RpcMeasureConstants.RPC_SERVER_ERROR_COUNT, 1); + measureMapErrors.record( + tagger + .currentBuilder() + .put(RpcMeasureConstants.RPC_STATUS, TagValue.create("UNKNOWN")) + .put(RpcMeasureConstants.RPC_METHOD, METHOD) + .build()); + + Thread.sleep(200); // sleep for fake work. + tracer.getCurrentSpan().addAnnotation("Finish recording."); + } + } + + /** Main method. */ + public static void main(String[] args) throws Exception { + ZPageHandlers.startHttpServerAndRegisterAll(8080); + recordExampleData(); + } +} 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; +} |