| title | Tracing |
|---|---|
| date | 2018-07-16 14:29:21 -0700 |
| draft | false |
| class | shadowed-image lightbox |
- Requirements
- Installation
- Getting started
- Enable Tracing
- Exporting traces
- End to end code
- Viewing your traces
- References
In this quickstart, we’ll glean insights from code segments and learn how to:
- Trace the code using OpenCensus Tracing
- Register and enable an exporter for a backend of our choice
- View traces on the backend of our choice
- Java 8+
- Apache Maven
- Zipkin as our choice of tracing backend: we are picking it because it is free, open source and easy to setup
{{% notice tip %}} For assistance setting up Zipkin, Click here for a guided codelab.
You can swap out any other exporter from the list of Java exporters {{% /notice %}}
We will first create our project directory, generate the pom.xml, and bootstrap our entry file.
mkdir repl-app
cd repl-app
touch pom.xml
mkdir -p src/main/java/io/opencensus/tracing/quickstart
touch src/main/java/io/opencensus/tracing/quickstart/Repl.javaPlease add this content to your pom.xml file:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>io.opencensus.tracing.quickstart</groupId>
<artifactId>quickstart</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>quickstart</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<opencensus.version>0.17.0</opencensus.version> <!-- The OpenCensus version to use -->
</properties>
<build>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.5.0.Final</version>
</extension>
</extensions>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>appassembler-maven-plugin</artifactId>
<version>1.10</version>
<configuration>
<programs>
<program>
<id>Repl</id>
<mainClass>io.opencensus.tracing.quickstart.Repl</mainClass>
</program>
</programs>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>Put this in src/main/java/io/opencensus/tracing/quickstart/Repl.java:
{{}} package io.opencensus.tracing.quickstart;
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Map;
public class Repl { public static void main(String ...args) { BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
while (true) {
try {
readEvaluateProcessLine(stdin);
} catch (IOException e) {
System.err.println("Exception "+ e);
}
}
}
private static String processLine(String line) {
return line.toUpperCase();
}
private static String readLine(BufferedReader in) {
String line = "";
try {
line = in.readLine();
} catch (Exception e) {
System.err.println("Failed to read line "+ e);
} finally {
return line;
}
}
private static void readEvaluateProcessLine(BufferedReader in) throws IOException {
System.out.print("> ");
System.out.flush();
String line = readLine(in);
String processed = processLine(line);
System.out.println("< " + processed + "\n");
}
} {{}}
To install required dependencies, run this from your project's root directory:
# Make sure to be in your project's root directory
mvn installThe Repl application takes input from users, converts any lower-case letters into upper-case letters, and echoes the result back to the user, for example:
> foo
< FOOLet's first run the application and see what we have.
mvn exec:java -Dexec.mainClass=io.opencensus.tracing.quickstart.ReplYou will be given a text prompt. Try typing in a lowercase word and hit enter to receive the uppercase equivalent.
You should see something like this after a few runs:
To enable tracing, we’ll declare the dependencies in your pom.xml file. Insert the following code snippet after the <properties>...</properties> node:
{{}} {{}} io.opencensus opencensus-api ${opencensus.version}
<dependency>
<groupId>io.opencensus</groupId>
<artifactId>opencensus-impl</artifactId>
<version>${opencensus.version}</version>
<scope>runtime</scope>
</dependency>
{{}} 4.0.0 io.opencensus.tracing.quickstart quickstart jar 1.0-SNAPSHOT quickstart http://maven.apache.org
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<opencensus.version>0.17.0</opencensus.version> <!-- The OpenCensus version to use -->
</properties>
<dependencies>
<dependency>
<groupId>io.opencensus</groupId>
<artifactId>opencensus-api</artifactId>
<version>${opencensus.version}</version>
</dependency>
<dependency>
<groupId>io.opencensus</groupId>
<artifactId>opencensus-impl</artifactId>
<version>${opencensus.version}</version>
<scope>runtime</scope>
</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>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>appassembler-maven-plugin</artifactId>
<version>1.10</version>
<configuration>
<programs>
<program>
<id>Repl</id>
<mainClass>io.opencensus.tracing.quickstart.Repl</mainClass>
</program>
</programs>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
We will now be importing modules into Repl.java. Append the following snippet after the existing import statements:
{{}} import io.opencensus.common.Scope; import io.opencensus.trace.Span; import io.opencensus.trace.Status; import io.opencensus.trace.Tracer; import io.opencensus.trace.Tracing; {{}}
We will begin by creating a private static Tracer as a property of our Repl class.
private static final Tracer tracer = Tracing.getTracer();We will be tracing the execution as it flows through readEvaluateProcessLine, readLine, and finally processLine.
To do this, we will create a span.
You can create a span by inserting the following line in each of the three functions:
Scope ss = tracer.spanBuilder("repl").startScopedSpan();Here is our updated state of Repl.java:
package io.opencensus.tracing.quickstart;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import io.opencensus.common.Scope;
import io.opencensus.trace.Span;
import io.opencensus.trace.Status;
import io.opencensus.trace.Tracer;
import io.opencensus.trace.Tracing;
public class Repl {
private static final Tracer tracer = Tracing.getTracer();
public static void main(String ...args) {
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
while (true) {
try {
readEvaluateProcessLine(stdin);
} catch (IOException e) {
System.err.println("Exception "+ e);
}
}
}
private static String processLine(String line) {
try (Scope ss = tracer.spanBuilder("processLine").startScopedSpan()) {
return line.toUpperCase();
}
}
private static String readLine(BufferedReader in) {
Scope ss = tracer.spanBuilder("readLine").startScopedSpan();
String line = "";
try {
line = in.readLine();
} catch (Exception e) {
Span span = tracer.getCurrentSpan();
span.setStatus(Status.INTERNAL.withDescription(e.toString()));
} finally {
ss.close();
return line;
}
}
private static void readEvaluateProcessLine(BufferedReader in) throws IOException {
System.out.print("> ");
System.out.flush();
String line = readLine(in);
String processed = processLine(line);
System.out.println("< " + processed + "\n");
}
}To enable trace exporting to Zipkin, we’ll need to declare the Zipkin exporter dependency in your pom.xml. Add the following code snippet inside of your <dependencies> node:
{{}} {{}} io.opencensus opencensus-exporter-trace-zipkin ${opencensus.version} {{}}
{{}} 4.0.0 io.opencensus.tracing.quickstart quickstart jar 1.0-SNAPSHOT quickstart http://maven.apache.org
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<opencensus.version>0.17.0</opencensus.version> <!-- The OpenCensus version to use -->
</properties>
<dependencies>
<dependency>
<groupId>io.opencensus</groupId>
<artifactId>opencensus-api</artifactId>
<version>${opencensus.version}</version>
</dependency>
<dependency>
<groupId>io.opencensus</groupId>
<artifactId>opencensus-impl</artifactId>
<version>${opencensus.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.opencensus</groupId>
<artifactId>opencensus-exporter-trace-zipkin</artifactId>
<version>${opencensus.version}</version>
</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>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>appassembler-maven-plugin</artifactId>
<version>1.10</version>
<configuration>
<programs>
<program>
<id>Repl</id>
<mainClass>io.opencensus.tracing.quickstart.Repl</mainClass>
</program>
</programs>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
Now add the import statements to your Repl.java:
{{}} import java.util.HashMap; import java.util.Map;
import io.opencensus.trace.AttributeValue; import io.opencensus.trace.config.TraceConfig; import io.opencensus.trace.samplers.Samplers;
import io.opencensus.exporter.trace.zipkin.ZipkinTraceExporter; {{}}
We will create a function called setupOpenCensusAndZipkinExporter and call it from our main function:
{{}} {{}} public static void main(String ...args) { try { setupOpenCensusAndZipkinExporter(); } catch (IOException e) { System.err.println("Failed to create and register OpenCensus Zipkin Trace exporter "+ e); return; }
//..
} {{}}
{{}} package io.opencensus.tracing.quickstart;
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Map;
import io.opencensus.common.Scope; import io.opencensus.trace.AttributeValue; import io.opencensus.trace.config.TraceConfig; import io.opencensus.trace.samplers.Samplers; import io.opencensus.trace.Span; import io.opencensus.trace.Status; import io.opencensus.trace.Tracer; import io.opencensus.trace.Tracing;
import io.opencensus.exporter.trace.zipkin.ZipkinTraceExporter;
public class Repl { private static final Tracer tracer = Tracing.getTracer();
public static void main(String ...args) {
try {
setupOpenCensusAndZipkinExporter();
} catch (IOException e) {
System.err.println("Failed to create and register OpenCensus Zipkin Trace exporter "+ e);
return;
}
// Step 2. The normal REPL.
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
while (true) {
try {
readEvaluateProcessLine(stdin);
} catch (IOException e) {
System.err.println("Exception "+ e);
}
}
}
private static String processLine(String line) {
try (Scope ss = tracer.spanBuilder("processLine").startScopedSpan()) {
return line.toUpperCase();
}
}
private static String readLine(BufferedReader in) {
Scope ss = tracer.spanBuilder("readLine").startScopedSpan();
String line = "";
try {
line = in.readLine();
} catch (Exception e) {
Span span = tracer.getCurrentSpan();
span.setStatus(Status.INTERNAL.withDescription(e.toString()));
} finally {
ss.close();
return line;
}
}
private static void readEvaluateProcessLine(BufferedReader in) throws IOException {
System.out.print("> ");
System.out.flush();
String line = readLine(in);
String processed = processLine(line);
System.out.println("< " + processed + "\n");
}
} {{}} {{}}
We will do 2 things in our setupOpenCensusAndZipkinExporter function:
- Set our sampling rate
TraceConfig traceConfig = Tracing.getTraceConfig();
// For demo purposes, lets always sample.
traceConfig.updateActiveTraceParams(
traceConfig.getActiveTraceParams().toBuilder().setSampler(Samplers.alwaysSample()).build());- Export our Traces to Zipkin: For this we'll initialize the Zipkin exporter which will send traces to the endpoint that the Zipkin server is running
ZipkinTraceExporter.createAndRegister("http://localhost:9411/api/v2/spans", "ocjavaquickstart");The function ends up looking like this:
{{}} {{}} private static void setupOpenCensusAndZipkinExporter() throws IOException { TraceConfig traceConfig = Tracing.getTraceConfig(); // For demo purposes, lets always sample. traceConfig.updateActiveTraceParams( traceConfig.getActiveTraceParams().toBuilder().setSampler(Samplers.alwaysSample()).build());
ZipkinTraceExporter.createAndRegister("http://localhost:9411/api/v2/spans", "ocjavaquickstart");
} {{}}
{{}} package io.opencensus.tracing.quickstart;
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Map;
import io.opencensus.common.Scope; import io.opencensus.trace.AttributeValue; import io.opencensus.trace.config.TraceConfig; import io.opencensus.trace.samplers.Samplers; import io.opencensus.trace.Span; import io.opencensus.trace.Status; import io.opencensus.trace.Tracer; import io.opencensus.trace.Tracing;
import io.opencensus.exporter.trace.zipkin.ZipkinTraceExporter;
public class Repl { private static final Tracer tracer = Tracing.getTracer();
public static void main(String ...args) {
try {
setupOpenCensusAndZipkinExporter();
} catch (IOException e) {
System.err.println("Failed to create and register OpenCensus Zipkin Trace exporter "+ e);
return;
}
// Step 2. The normal REPL.
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
while (true) {
try {
readEvaluateProcessLine(stdin);
} catch (IOException e) {
System.err.println("Exception "+ e);
}
}
}
private static String processLine(String line) {
try (Scope ss = tracer.spanBuilder("processLine").startScopedSpan()) {
return line.toUpperCase();
}
}
private static String readLine(BufferedReader in) {
Scope ss = tracer.spanBuilder("readLine").startScopedSpan();
String line = "";
try {
line = in.readLine();
} catch (Exception e) {
Span span = tracer.getCurrentSpan();
span.setStatus(Status.INTERNAL.withDescription(e.toString()));
} finally {
ss.close();
return line;
}
}
private static void readEvaluateProcessLine(BufferedReader in) throws IOException {
System.out.print("> ");
System.out.flush();
String line = readLine(in);
String processed = processLine(line);
System.out.println("< " + processed + "\n");
}
private static void setupOpenCensusAndZipkinExporter() throws IOException {
TraceConfig traceConfig = Tracing.getTraceConfig();
// For demo purposes, lets always sample.
traceConfig.updateActiveTraceParams(
traceConfig.getActiveTraceParams().toBuilder().setSampler(Samplers.alwaysSample()).build());
ZipkinTraceExporter.createAndRegister("http://localhost:9411/api/v2/spans", "ocjavaquickstart");
}
} {{}} {{}}
When looking at our traces on a backend (such as Zipkin as we have used), we can add metadata to our traces to increase our post-mortem insight.
Let's record the length of each requested string so that it is available to view when we are looking at our traces.
To do this, we'll dive in to readEvaluateProcessLine.
Between String line = readLine(in) and String processed = processLine(line), add this:
// Annotate the span to indicate we are invoking processLine next.
Map<String, AttributeValue> attributes = new HashMap<String, AttributeValue>();
attributes.put("len", AttributeValue.longAttributeValue(line.length()));
attributes.put("use", AttributeValue.stringAttributeValue("repl"));
Span span = tracer.getCurrentSpan();
span.addAnnotation("Invoking processLine", attributes);Collectively the final versions of src/main/java/io/opencensus/tracing/quickstart/Repl.java and pom.xml should be as in the tabs below:
{{}} {{}} package io.opencensus.tracing.quickstart;
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Map;
import io.opencensus.common.Scope; import io.opencensus.trace.AttributeValue; import io.opencensus.trace.config.TraceConfig; import io.opencensus.trace.samplers.Samplers; import io.opencensus.trace.Span; import io.opencensus.trace.Status; import io.opencensus.trace.Tracer; import io.opencensus.trace.Tracing;
import io.opencensus.exporter.trace.zipkin.ZipkinTraceExporter;
public class Repl { private static final Tracer tracer = Tracing.getTracer();
public static void main(String ...args) {
try {
setupOpenCensusAndZipkinExporter();
} catch (IOException e) {
System.err.println("Failed to create and register OpenCensus Zipkin Trace exporter "+ e);
return;
}
// Step 2. The normal REPL.
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
while (true) {
try {
readEvaluateProcessLine(stdin);
} catch (IOException e) {
System.err.println("Exception "+ e);
}
}
}
private static String processLine(String line) {
try (Scope ss = tracer.spanBuilder("processLine").startScopedSpan()) {
return line.toUpperCase();
}
}
private static String readLine(BufferedReader in) {
Scope ss = tracer.spanBuilder("readLine").startScopedSpan();
String line = "";
try {
line = in.readLine();
} catch (Exception e) {
Span span = tracer.getCurrentSpan();
span.setStatus(Status.INTERNAL.withDescription(e.toString()));
} finally {
ss.close();
return line;
}
}
private static void readEvaluateProcessLine(BufferedReader in) throws IOException {
try (Scope ss = tracer.spanBuilder("repl").startScopedSpan()) {
System.out.print("> ");
System.out.flush();
String line = readLine(in);
// Annotate the span to indicate we are invoking processLine next.
Map<String, AttributeValue> attributes = new HashMap<String, AttributeValue>();
attributes.put("len", AttributeValue.longAttributeValue(line.length()));
attributes.put("use", AttributeValue.stringAttributeValue("repl"));
Span span = tracer.getCurrentSpan();
span.addAnnotation("Invoking processLine", attributes);
String processed = processLine(line);
System.out.println("< " + processed + "\n");
}
}
private static void setupOpenCensusAndZipkinExporter() throws IOException {
TraceConfig traceConfig = Tracing.getTraceConfig();
// For demo purposes, lets always sample.
traceConfig.updateActiveTraceParams(
traceConfig.getActiveTraceParams().toBuilder().setSampler(Samplers.alwaysSample()).build());
ZipkinTraceExporter.createAndRegister("http://localhost:9411/api/v2/spans", "ocjavaquickstart");
}
} {{}} {{}} 4.0.0 io.opencensus.tracing.quickstart quickstart jar 1.0-SNAPSHOT quickstart http://maven.apache.org
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<opencensus.version>0.17.0</opencensus.version> <!-- The OpenCensus version to use -->
</properties>
<dependencies>
<dependency>
<groupId>io.opencensus</groupId>
<artifactId>opencensus-api</artifactId>
<version>${opencensus.version}</version>
</dependency>
<dependency>
<groupId>io.opencensus</groupId>
<artifactId>opencensus-impl</artifactId>
<version>${opencensus.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.opencensus</groupId>
<artifactId>opencensus-exporter-trace-zipkin</artifactId>
<version>${opencensus.version}</version>
</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>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>appassembler-maven-plugin</artifactId>
<version>1.10</version>
<configuration>
<programs>
<program>
<id>Repl</id>
<mainClass>io.opencensus.tracing.quickstart.Repl</mainClass>
</program>
</programs>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
Having already successfully started Zipkin as in Zipkin Codelab, we can now run our code by
mvn install
mvn exec:java -Dexec.mainClass=io.opencensus.tracing.quickstart.ReplWith the above you should now be able to navigate to the Zipkin UI at http://localhost:9411
which will produce such a screenshot:

And on clicking on one of the traces, we should be able to see the annotation whose description isInvoking processLine

And on clicking on More info we should see

| Resource | URL |
|---|---|
| Zipkin project | https://zipkin.io/ |
| Setting up Zipkin | Zipkin Codelab |
| Zipkin Java exporter | https://www.javadoc.io/doc/io.opencensus/opencensus-exporter-trace-zipkin |
| Java exporters | Java exporters |
| OpenCensus Java Trace package | https://www.javadoc.io/doc/io.opencensus/opencensus-api/ |

