aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorBogdan Drutu <bdrutu@google.com>2017-03-07 17:49:43 -0800
committerGitHub <noreply@github.com>2017-03-07 17:49:43 -0800
commitb1d43a650e5bc36c6dfdf1dc5cb4c71bd5db00c7 (patch)
treeca8c734b78de7d3e0d7f803f5b8c8bdf48babb7e /core
parentd5fdf57eefe0d64752a5d680744c9c47b6350524 (diff)
downloadplatform_external_opencensus-java-b1d43a650e5bc36c6dfdf1dc5cb4c71bd5db00c7.tar.gz
platform_external_opencensus-java-b1d43a650e5bc36c6dfdf1dc5cb4c71bd5db00c7.tar.bz2
platform_external_opencensus-java-b1d43a650e5bc36c6dfdf1dc5cb4c71bd5db00c7.zip
Add a SpanBuilder class. (#123)
* Add a SpanBuilder to avoid exponential increase in the number of startSpan[XXX] methods in the Tracer class. * Modify examples and comments based on Adrian's feedback.
Diffstat (limited to 'core')
-rw-r--r--core/src/main/java/com/google/instrumentation/trace/Span.java2
-rw-r--r--core/src/main/java/com/google/instrumentation/trace/SpanBuilder.java295
-rw-r--r--core/src/main/java/com/google/instrumentation/trace/SpanFactory.java20
-rw-r--r--core/src/main/java/com/google/instrumentation/trace/StartSpanOptions.java173
-rw-r--r--core/src/main/java/com/google/instrumentation/trace/Tracer.java237
-rw-r--r--core/src/test/java/com/google/instrumentation/trace/SpanBuilderTest.java176
-rw-r--r--core/src/test/java/com/google/instrumentation/trace/StartSpanOptionsTest.java103
-rw-r--r--core/src/test/java/com/google/instrumentation/trace/TracerTest.java181
8 files changed, 664 insertions, 523 deletions
diff --git a/core/src/main/java/com/google/instrumentation/trace/Span.java b/core/src/main/java/com/google/instrumentation/trace/Span.java
index 26de28f7..28ed14a7 100644
--- a/core/src/main/java/com/google/instrumentation/trace/Span.java
+++ b/core/src/main/java/com/google/instrumentation/trace/Span.java
@@ -25,7 +25,7 @@ import javax.annotation.Nullable;
* An abstract class that represents a span. It has an associated {@link SpanContext} and a set of
* {@link Options}.
*
- * <p>Spans are created by the {@link Tracer#startSpan} method.
+ * <p>Spans are created by the {@link SpanBuilder#startSpan} method.
*
* <p>{@code Span} implements NonThrowingCloseable, to support try-with-resource idiom. See {@link
* Span#close}.
diff --git a/core/src/main/java/com/google/instrumentation/trace/SpanBuilder.java b/core/src/main/java/com/google/instrumentation/trace/SpanBuilder.java
new file mode 100644
index 00000000..25e2db56
--- /dev/null
+++ b/core/src/main/java/com/google/instrumentation/trace/SpanBuilder.java
@@ -0,0 +1,295 @@
+/*
+ * Copyright 2017, Google Inc.
+ * 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 com.google.instrumentation.trace;
+
+import com.google.instrumentation.common.NonThrowingCloseable;
+import com.google.instrumentation.common.Timestamp;
+
+import java.util.List;
+import javax.annotation.Nullable;
+
+/**
+ * {@link SpanBuilder} is used to construct {@link Span} instances which define arbitrary scopes of
+ * code that are sampled for distributed tracing as a single atomic unit.
+ *
+ * <p>This is a simple example where all the work is being done within a single scope and the
+ * Context is manually propagated:
+ *
+ * <pre>{@code
+ * class MyClass {
+ * private static final Tracer tracer = Tracer.getTracer();
+ * void doWork(Span parent) {
+ * // Create a Span as a child of the given parent.
+ * try (Span span = tracer.spanBuilder(parent, "MyChildSpan").startSpan()) {
+ * span.addAnnotation("my annotation");
+ * doSomeWork(span); // Manually propagate the new span down the stack.
+ * }
+ * // "span" will be ended here.
+ * }
+ * }
+ * }</pre>
+ *
+ * <p>This is a simple example where all the work is being done within a single scope and a single
+ * thread and the Context is automatically propagated:
+ *
+ * <pre>{@code
+ * class MyClass {
+ * private static final Tracer tracer = Tracer.getTracer();
+ * void doWork {
+ * // Create a Span as a child of the current Span.
+ * try (NonThrowingCloseable ss = tracer.spanBuilder("MyChildSpan").startScopedSpan()) {
+ * tracer.getCurrentSpan().addAnnotation("my annotation");
+ * doSomeWork(); // Here the new span is in the current Context, so it can be used
+ * // implicitly anywhere down the stack.
+ * }
+ * }
+ * }
+ * }</pre>
+ *
+ * <p>There might be cases where you do not perform all the work inside one static scope and the
+ * Context is automatically propagated:
+ *
+ * <pre>{@code
+ * class MyRpcServerInterceptorListener implements RpcServerInterceptor.Listener {
+ * private static final Tracer tracer = Tracer.getTracer();
+ * private Span mySpan;
+ *
+ * public MyRpcInterceptor() {}
+ *
+ * public void onRequest(String rpcName, Metadata metadata) {
+ * // Create a Span as a child of the remote Span.
+ * mySpan = tracer.spanBuilderWithRemoteParent(
+ * getTraceContextFromMetadata(metadata), rpcName).startSpan();
+ * }
+ *
+ * public void onExecuteHandler(ServerCallHandler serverCallHandler) {
+ * try (NonThrowingCloseable ws = tracer.withSpan(mySpan)) {
+ * tracer.getCurrentSpan().addAnnotation("Start rpc execution.");
+ * serverCallHandler.run(); // Here the new span is in the current Context, so it can be
+ * // used implicitly anywhere down the stack.
+ * }
+ * }
+ *
+ * // Called when the RPC is canceled and guaranteed onComplete will not be called.
+ * public void onCancel() {
+ * // IMPORTANT: DO NOT forget to ended the Span here as the work is done.
+ * mySpan.end(EndSpanOptions.builder().setStatus(Status.CANCELLED));
+ * }
+ *
+ * // Called when the RPC is done and guaranteed onCancel will not be called.
+ * public void onComplete(RpcStatus rpcStatus) {
+ * // IMPORTANT: DO NOT forget to ended the Span here as the work is done.
+ * mySpan.end(EndSpanOptions.builder().setStatus(rpcStatusToCanonicalTraceStatus(status));
+ * }
+ * }
+ * }</pre>
+ *
+ * <p>If your Java version is less than Java SE 7, see {@link SpanBuilder#startSpan} and {@link
+ * SpanBuilder#startScopedSpan} for usage examples.
+ */
+public final class SpanBuilder {
+ private final SpanFactory spanFactory;
+ private final ContextSpanHandler contextSpanHandler;
+ private SpanContext parentSpanContext;
+ private boolean hasRemoteParent;
+ private final String name;
+ private final StartSpanOptions startSpanOption = new StartSpanOptions();
+
+ SpanBuilder(
+ SpanFactory spanFactory,
+ ContextSpanHandler contextSpanHandler,
+ SpanContext parentSpanContext,
+ boolean hasRemoteParent,
+ String name) {
+ this.parentSpanContext = parentSpanContext;
+ this.hasRemoteParent = hasRemoteParent;
+ this.name = name;
+ this.spanFactory = spanFactory;
+ this.contextSpanHandler = contextSpanHandler;
+ }
+
+ /**
+ * Sets the start time for the {@link Span}.
+ *
+ * @param startTime The start time for the {@code Span}. If {@code null} is used, then the current
+ * system time at the point at which {@link #startSpan} is called will be used.
+ * @return this.
+ */
+ public SpanBuilder setStartTime(@Nullable Timestamp startTime) {
+ startSpanOption.setStartTime(startTime);
+ return this;
+ }
+
+ /**
+ * Sets the {@link Sampler} to use. If a {@code null} value is passed, the implementation will
+ * provide a default.
+ *
+ * @param sampler The {@code Sampler} to use when determining sampling for a {@code Span}.
+ * @return this.
+ */
+ public SpanBuilder setSampler(@Nullable Sampler sampler) {
+ startSpanOption.setSampler(sampler);
+ return this;
+ }
+
+ /**
+ * Sets the {@code List} of parent links. Links are used to link {@link Span}s in different
+ * traces. Used (for example) in batching operations, where a single batch handler processes
+ * multiple requests from different traces.
+ *
+ * @param parentLinks New links to be added.
+ * @return this.
+ */
+ public SpanBuilder setParentLinks(@Nullable List<Span> parentLinks) {
+ startSpanOption.setParentLinks(parentLinks);
+ return this;
+ }
+
+ /**
+ * Sets recordEvents.
+ *
+ * @param recordEvents New value determining if this {@code Span} should have events recorded. If
+ * a {@code null} value is passed, the implementation will provide a default.
+ * @return this.
+ */
+ public SpanBuilder setRecordEvents(@Nullable Boolean recordEvents) {
+ startSpanOption.setRecordEvents(recordEvents);
+ return this;
+ }
+
+ /**
+ * If called this will force the newly created {@code Span} to be a root span. As a consequence,
+ * any parent specified (or inherited from the Context) will be ignored (N.B. does not apply to
+ * linked parents set through {@link #setParentLinks}).
+ *
+ * <p>This is useful when {@link Tracer#spanBuilder(String)} is used and the newly created {@code
+ * Span} needs to be decoupled from the parent {@code Span}.
+ *
+ * @return this.
+ */
+ public SpanBuilder becomeRoot() {
+ parentSpanContext = null;
+ hasRemoteParent = false;
+ return this;
+ }
+
+ /**
+ * Starts a new {@link Span}.
+ *
+ * <p>If used without try-with-resources <b>must</b> manually call {@link Span#end}.
+ *
+ * <p>Does not install the newly created {@code Span} to the current Context.
+ *
+ * <p>Example of usage:
+ *
+ * <pre>{@code
+ * class MyClass {
+ * private static final Tracer tracer = Tracer.getTracer();
+ * void DoWork() {
+ * try (Span span = tracer.spanBuilder(null, "MyRootSpan").startSpan()) {
+ * span.addAnnotation("We did X");
+ * }
+ * }
+ * }
+ * }</pre>
+ *
+ * <p>Prior to Java SE 7, you can use a finally block to ensure that a resource is closed (the
+ * {@code Span} is ended) regardless of whether the try statement completes normally or abruptly.
+ *
+ * <p>Example of usage prior to Java SE7:
+ *
+ * <pre>{@code
+ * class MyClass {
+ * private static final Tracer tracer = Tracer.getTracer();
+ * void DoWork() {
+ * Span span = tracer.spanBuilder(null, "MyRootSpan").startSpan();
+ * try {
+ * span.addAnnotation("We did X");
+ * } finally {
+ * span.close();
+ * }
+ * }
+ * }
+ * }</pre>
+ *
+ * @return the newly created {@code Span}.
+ */
+ public Span startSpan() {
+ return start();
+ }
+
+ // TODO(bdrutu): Add error_prone annotation @MustBeClosed when the 2.0.16 jar is fixed.
+ /**
+ * Starts a new new span and sets it as the {@link Tracer#getCurrentSpan current span}.
+ *
+ * <p>Enters the scope of code where the newly created {@code Span} is in the current Context, and
+ * returns an object that represents that scope. The scope is exited when the returned object is
+ * closed then the previous Context is restored and the newly created {@code Span} is ended using
+ * {@link Span#end}.
+ *
+ * <p>Supports try-with-resource idiom.
+ *
+ * <p>Example of usage:
+ *
+ * <pre>{@code
+ * class MyClass {
+ * private static final Tracer tracer = Tracer.getTracer();
+ * void doWork {
+ * // Create a Span as a child of the current Span.
+ * try (NonThrowingCloseable ss = tracer.spanBuilder("MyChildSpan").startScopedSpan()) {
+ * tracer.getCurrentSpan().addAnnotation("my annotation");
+ * doSomeWork(); // Here the new span is in the current Context, so it can be used
+ * // implicitly anywhere down the stack. Anytime in this closure the span
+ * // can be accessed via tracer.getCurrentSpan().
+ * }
+ * }
+ * }
+ * }</pre>
+ *
+ * <p>Prior to Java SE 7, you can use a finally block to ensure that a resource is closed (the
+ * {@code Span} is ended and removed from the Context) regardless of whether the try statement
+ * completes normally or abruptly.
+ *
+ * <p>Example of usage prior to Java SE7:
+ *
+ * <pre>{@code
+ * class MyClass {
+ * private static Tracer tracer = Tracer.getTracer();
+ * void doWork {
+ * // Create a Span as a child of the current Span.
+ * NonThrowingCloseable ss = tracer.spanBuilder("MyChildSpan").startScopedSpan();
+ * try {
+ * tracer.getCurrentSpan().addAnnotation("my annotation");
+ * doSomeWork(); // Here the new span is in the current Context, so it can be used
+ * // implicitly anywhere down the stack. Anytime in this closure the span
+ * // can be accessed via tracer.getCurrentSpan().
+ * } finally {
+ * ss.close();
+ * }
+ * }
+ * }
+ * }</pre>
+ *
+ * @return an object that defines a scope where the newly created {@code Span} will be set to the
+ * current Context.
+ */
+ public NonThrowingCloseable startScopedSpan() {
+ return new ScopedSpanHandle(start(), contextSpanHandler);
+ }
+
+ // Utility method to start a Span.
+ private Span start() {
+ return spanFactory.startSpan(parentSpanContext, hasRemoteParent, name, startSpanOption);
+ }
+}
diff --git a/core/src/main/java/com/google/instrumentation/trace/SpanFactory.java b/core/src/main/java/com/google/instrumentation/trace/SpanFactory.java
index 80f2b61d..e331d9f4 100644
--- a/core/src/main/java/com/google/instrumentation/trace/SpanFactory.java
+++ b/core/src/main/java/com/google/instrumentation/trace/SpanFactory.java
@@ -21,26 +21,14 @@ import javax.annotation.Nullable;
abstract class SpanFactory {
/**
* Creates and starts a new child {@link Span} (or root if parent is {@code null}), with parent
- * being the designated {@code Span} and the given options.
- *
- * @param parent The parent of the returned {@code Span}.
- * @param name The name of the returned {@code Span}.
- * @param options The options for the start of the {@code Span}.
- * @return A child {@code Span} that will have the name provided.
- */
- abstract Span startSpan(@Nullable Span parent, String name, StartSpanOptions options);
-
- /**
- * Creates and starts a new child {@link Span} (or root if parent is {@code null}), with parent
* being the {@code Span} designated by the {@link SpanContext} and the given options.
*
- * <p>This must be used to create a {@code Span} when the parent is on a different process.
- *
- * @param remoteParent The remote parent of the returned {@code Span}.
+ * @param parent The parent of the returned {@code Span}.
+ * @param hasRemoteParent {@code true} if this is a child of a remote {@code Span}.
* @param name The name of the returned {@code Span}.
* @param options The options for the start of the {@code Span}.
* @return A child {@code Span} that will have the name provided.
*/
- abstract Span startSpanWithRemoteParent(
- @Nullable SpanContext remoteParent, String name, StartSpanOptions options);
+ abstract Span startSpan(
+ @Nullable SpanContext parent, boolean hasRemoteParent, String name, StartSpanOptions options);
}
diff --git a/core/src/main/java/com/google/instrumentation/trace/StartSpanOptions.java b/core/src/main/java/com/google/instrumentation/trace/StartSpanOptions.java
index d0c6a6b8..11853582 100644
--- a/core/src/main/java/com/google/instrumentation/trace/StartSpanOptions.java
+++ b/core/src/main/java/com/google/instrumentation/trace/StartSpanOptions.java
@@ -13,15 +13,10 @@
package com.google.instrumentation.trace;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import com.google.instrumentation.common.Timestamp;
-import java.util.ArrayList;
import java.util.Collections;
-import java.util.LinkedList;
import java.util.List;
import javax.annotation.Nullable;
@@ -30,45 +25,17 @@ import javax.annotation.Nullable;
* overriding the {@link Timestamp start time}, the {@link Sampler sampler}, the parent links, and
* option to record all the events even if the {@code Span} is not sampled.
*/
-public final class StartSpanOptions {
- private static final StartSpanOptions DEFAULT_OPTIONS = builder().build();
- private final Timestamp startTime;
- private final Sampler sampler;
- // This object is an unmodifiable List.
- private final List<Span> parentLinks;
- private final Boolean recordEvents;
-
- /**
- * Returns default {@code StartSpanOptions}.
- *
- * @return default {@code StartSpanOptions}.
- */
- public static StartSpanOptions getDefault() {
- return DEFAULT_OPTIONS;
- }
-
- /**
- * Returns a new {@link Builder} with default options.
- *
- * @return a new {@code Builder} with default options.
- */
- public static Builder builder() {
- return new Builder();
- }
-
- private StartSpanOptions(
- @Nullable Timestamp startTime,
- @Nullable Sampler sampler,
- @Nullable List<Span> parentLinks,
- @Nullable Boolean recordEvents) {
- this.startTime = startTime;
- this.sampler = sampler;
- // Make parentLinks an unmodifiable list.
- this.parentLinks =
- parentLinks == null
- ? Collections.<Span>emptyList()
- : Collections.unmodifiableList(new ArrayList<Span>(parentLinks));
- this.recordEvents = recordEvents;
+final class StartSpanOptions {
+ private Timestamp startTime;
+ private Sampler sampler;
+ private List<Span> parentLinks;
+ private Boolean recordEvents;
+
+ StartSpanOptions() {
+ this.startTime = null;
+ this.sampler = null;
+ this.parentLinks = null;
+ this.recordEvents = null;
}
/**
@@ -77,7 +44,7 @@ public final class StartSpanOptions {
* @return start time to be used, or {@code null} if default.
*/
@Nullable
- public Timestamp getStartTime() {
+ Timestamp getStartTime() {
return startTime;
}
@@ -87,7 +54,7 @@ public final class StartSpanOptions {
* @return the {@code Sampler} to be used, or {@code null} if default.
*/
@Nullable
- public Sampler getSampler() {
+ Sampler getSampler() {
return sampler;
}
@@ -96,9 +63,11 @@ public final class StartSpanOptions {
*
* @return the parent links to be set for the {@code Span}.
*/
- public List<Span> getParentLinks() {
- // It is safe to directly return parentLinks because it is an unmodifiable list.
- return parentLinks;
+ List<Span> getParentLinks() {
+ // Return an unmodifiable list.
+ return parentLinks == null
+ ? Collections.<Span>emptyList()
+ : Collections.unmodifiableList(parentLinks);
}
/**
@@ -107,7 +76,7 @@ public final class StartSpanOptions {
* @return the record events option setting.
*/
@Nullable
- public Boolean getRecordEvents() {
+ Boolean getRecordEvents() {
return recordEvents;
}
@@ -133,103 +102,19 @@ public final class StartSpanOptions {
return Objects.hashCode(startTime, sampler, parentLinks, recordEvents);
}
- @Override
- public String toString() {
- return MoreObjects.toStringHelper(this)
- .add("startTime", startTime)
- .add("sampler", sampler)
- .add("parentLinks", parentLinks)
- .add("recordEvents", recordEvents)
- .toString();
+ void setStartTime(@Nullable Timestamp startTime) {
+ this.startTime = startTime;
}
- /**
- * Builder class for {@link StartSpanOptions}.
- */
- public static final class Builder {
- private Timestamp startTime;
- private Sampler sampler;
- private List<Span> parentLinks;
- private Boolean recordEvents;
-
- private Builder() {}
-
- /**
- * Sets the start time for the {@link Span}.
- *
- * @param startTime The start time for the {@code Span}. If {@code null} is used, then the
- * current system time at the point at which {@link Tracer#startSpan} is called will be
- * used.
- * @return this.
- */
- public Builder setStartTime(@Nullable Timestamp startTime) {
- this.startTime = startTime;
- return this;
- }
-
- /**
- * Sets the {@link Sampler} to use. If a {@code null} value is passed, the implementation will
- * provide a default.
- *
- * @param sampler The {@code Sampler} to use when determining sampling for a {@code Span}.
- * @return this.
- */
- public Builder setSampler(@Nullable Sampler sampler) {
- this.sampler = sampler;
- return this;
- }
-
- /**
- * Adds one parent link. Links are used to link {@link Span}s in different traces. Used (for
- * example) in batching operations, where a single batch handler processes multiple requests
- * from different traces.
- *
- * @param parentLink The new {@code Span} parent link.
- * @return this.
- * @throws NullPointerException if {@code parentLink} is {@code null}.
- */
- public Builder addParentLink(Span parentLink) {
- if (parentLinks == null) {
- parentLinks = new LinkedList<Span>();
- }
- parentLinks.add(checkNotNull(parentLink, "parentLink"));
- return this;
- }
-
- /**
- * Adds a {@code List} of parent links. See {@link #addParentLink}.
- *
- * @param parentLinks New links to be added.
- * @return this.
- * @throws NullPointerException if {@code parentLinks} is {@code null}.
- */
- public Builder addParentLinks(List<Span> parentLinks) {
- if (this.parentLinks == null) {
- this.parentLinks = new LinkedList<Span>();
- }
- this.parentLinks.addAll(checkNotNull(parentLinks, "parentLinks"));
- return this;
- }
+ void setSampler(@Nullable Sampler sampler) {
+ this.sampler = sampler;
+ }
- /**
- * Sets recordEvents.
- *
- * @param recordEvents New value determining if this {@code Span} should have events recorded.
- * If a {@code null} value is passed, the implementation will provide a default.
- * @return this.
- */
- public Builder setRecordEvents(@Nullable Boolean recordEvents) {
- this.recordEvents = recordEvents;
- return this;
- }
+ void setParentLinks(@Nullable List<Span> parentLinks) {
+ this.parentLinks = parentLinks;
+ }
- /**
- * Builds and returns a {@link StartSpanOptions} with the desired settings.
- *
- * @return a {@link StartSpanOptions} with the desired settings.
- */
- public StartSpanOptions build() {
- return new StartSpanOptions(startTime, sampler, parentLinks, recordEvents);
- }
+ void setRecordEvents(@Nullable Boolean recordEvents) {
+ this.recordEvents = recordEvents;
}
}
diff --git a/core/src/main/java/com/google/instrumentation/trace/Tracer.java b/core/src/main/java/com/google/instrumentation/trace/Tracer.java
index 61f106c5..57b9a7ff 100644
--- a/core/src/main/java/com/google/instrumentation/trace/Tracer.java
+++ b/core/src/main/java/com/google/instrumentation/trace/Tracer.java
@@ -29,25 +29,34 @@ import javax.annotation.Nullable;
*
* <p>This can be used similarly to {@link java.util.logging.Logger}.
*
- * <p>Example usage:
+ * <p>Users may choose to use manual or automatic Context propagation. Because of that this class
+ * offers APIs to facilitate both usages.
+ *
+ * <p>Example usage with automatic context propagation:
*
* <pre>{@code
* class MyClass {
* private static final Tracer tracer = Tracer.getTracer();
* void DoWork() {
- * try(NonThrowingCloseable ss = tracer.startScopedSpan("MyClass.DoWork")) {
+ * try(NonThrowingCloseable ss = tracer.spanBuilder("MyClass.DoWork").startScopedSpan) {
* tracer.getCurrentSpan().addAnnotation("We did the work.");
* }
* }
* }
* }</pre>
*
- * <p>{@code Tracer} manages the following modules:
+ * <p>Example usage with manual context propagation:
*
- * <ul>
- * <li>In process interaction between the {@code Span} and the Context.
- * <li>{@code Span} creation.
- * </ul>
+ * <pre>{@code
+ * class MyClass {
+ * private static final Tracer tracer = Tracer.getTracer();
+ * void DoWork(Span parent) {
+ * try(NonThrowingCloseable ss = tracer.spanBuilder(parent, "MyClass.DoWork").startScopedSpan) {
+ * tracer.getCurrentSpan().addAnnotation("We did the work.");
+ * }
+ * }
+ * }
+ * }</pre>
*/
public final class Tracer {
private static final Logger logger = Logger.getLogger(Tracer.class.getName());
@@ -75,7 +84,7 @@ public final class Tracer {
* Gets the current Span from the current Context.
*
* <p>To install a {@link Span} to the current Context use {@link #withSpan(Span)} OR use {@link
- * #startScopedSpan} methods to start a new {@code Span}.
+ * SpanBuilder#startScopedSpan} methods to start a new {@code Span}.
*
* <p>startSpan methods do NOT modify the current Context {@code Span}.
*
@@ -88,7 +97,6 @@ public final class Tracer {
return currentSpan != null ? currentSpan : BlankSpan.INSTANCE;
}
- // TODO(bdrutu): Add error_prone annotation @MustBeClosed when the 2.0.16 jar is fixed.
/**
* Enters the scope of code where the given {@link Span} is in the current Context, and returns an
* object that represents that scope. The scope is exited when the returned object is closed.
@@ -134,7 +142,7 @@ public final class Tracer {
* }</pre>
*
* @param span The {@link Span} to be set to the current Context.
- * @return An object that defines a scope where the given {@link Span} will be set to the current
+ * @return an object that defines a scope where the given {@link Span} will be set to the current
* Context.
* @throws NullPointerException if span is null.
*/
@@ -143,190 +151,66 @@ public final class Tracer {
}
/**
- * Creates and starts a new child {@link Span} as a child of to the current {@code Span} if any,
- * otherwise creates a root Span with the default options.
- *
- * <p>Enters the scope of code where the newly created {@code Span} is in the current Context, and
- * returns an object that represents that scope. The scope is exited when the returned object is
- * closed then the previous Context is restored and the newly created {@code Span} is ended using
- * {@link Span#end}.
- *
- * <p>Supports try-with-resource idiom.
+ * Returns a {@link SpanBuilder} to create and start a new child {@link Span} as a child of to the
+ * current {@code Span} if any, otherwise create a root Span with the default options.
*
- * <p>Example of usage:
+ * <p>See {@link SpanBuilder} for usage examples.
*
- * <pre>{@code
- * private static Tracer tracer = Tracer.getTracer();
- * void doWork {
- * // Create a Span as a child of the current Span.
- * try (NonThrowingCloseable ss = tracer.startScopedSpan("my span")) {
- * tracer.getCurrentSpan().addAnnotation("my annotation");
- * doSomeOtherWork(); // Here "span" is the current Span.
- * }
- * }
- * }</pre>
- *
- * <p>Prior to Java SE 7, you can use a finally block to ensure that a resource is closed
- * regardless of whether the try statement completes normally or abruptly.
- *
- * <p>Example of usage prior to Java SE7:
- *
- * <pre>{@code
- * private static Tracer tracer = Tracer.getTracer();
- * void doWork {
- * // Create a Span as a child of the current Span.
- * NonThrowingCloseable ss = tracer.startScopedSpan("my span");
- * try {
- * tracer.getCurrentSpan().addAnnotation("my annotation");
- * doSomeOtherWork(); // Here "span" is the current Span.
- * } finally {
- * ss.close();
- * }
- * }
- * }</pre>
+ * <p>This <b>must</b> be used to create a {@code Span} when automatic Context propagation is
+ * used.
*
* @param name The name of the returned Span.
- * @return An object that defines a scope where the newly created child will be set to the current
- * Context.
+ * @return a {@code SpanBuilder} to create and start a new {@code Span}.
* @throws NullPointerException if name is null.
*/
- public NonThrowingCloseable startScopedSpan(String name) {
- return new ScopedSpanHandle(
- spanFactory.startSpan(
- getCurrentSpan(), checkNotNull(name, "name"), StartSpanOptions.getDefault()),
- contextSpanHandler);
- }
-
- /**
- * Creates and starts a new child {@link Span} as a child of to the current {@code Span} if any,
- * otherwise creates a root Span with the given options.
- *
- * <p>Enters the scope of code where the newly created {@code Span} is in the current Context, and
- * returns an object that represents that scope. The scope is exited when the returned object is
- * closed then the previous Context is restored and the newly created {@code Span} is ended using
- * {@link Span#end}.
- *
- * <p>Supports try-with-resource idiom.
- *
- * <p>See {@link #startScopedSpan(String)} for example to use.
- *
- * @param name The name of the returned Span.
- * @param options The options for the start of the Span.
- * @return An object that defines a scope where the newly created child will be set to the current
- * Context.
- * @throws NullPointerException if name or options is null.
- */
- public NonThrowingCloseable startScopedSpan(String name, StartSpanOptions options) {
- return new ScopedSpanHandle(
- spanFactory.startSpan(
- getCurrentSpan(), checkNotNull(name, "name"), checkNotNull(options, "options")),
- contextSpanHandler);
+ public SpanBuilder spanBuilder(String name) {
+ return spanBuilder(contextSpanHandler.getCurrentSpan(), name);
}
/**
- * Creates and starts a new child {@link Span} (or root if parent is null), with parent being the
- * designated {@code Span} and the default options.
+ * Returns a {@link SpanBuilder} to create and start a new child {@link Span} (or root if parent
+ * is null), with parent being the designated {@code Span}.
*
- * <p>Enters the scope of code where the newly created {@code Span} is in the current Context, and
- * returns an object that represents that scope. The scope is exited when the returned object is
- * closed then the previous Context is restored and the newly created {@code Span} is ended using
- * {@link Span#end}.
+ * <p>See {@link SpanBuilder} for usage examples.
*
- * <p>Supports try-with-resource idiom.
+ * <p>This <b>must</b> be used to create a {@code Span} when manual Context propagation is used.
*
- * <p>See {@link #startScopedSpan(String)} for example to use.
- *
- * @param parent The parent of the returned Span.
+ * @param parent The parent of the returned Span. If null the {@code SpanBuilder} will build a
+ * root {@code Span}.
* @param name The name of the returned Span.
- * @return An object that defines a scope where the newly created child will be set to the current
- * Context.
+ * @return a {@code SpanBuilder} to create and start a new {@code Span}.
* @throws NullPointerException if name is null.
*/
- public NonThrowingCloseable startScopedSpan(@Nullable Span parent, String name) {
- return new ScopedSpanHandle(
- spanFactory.startSpan(parent, checkNotNull(name, "name"), StartSpanOptions.getDefault()),
- contextSpanHandler);
- }
-
- /**
- * Creates and starts a new child {@link Span} (or root if parent is null), with parent being the
- * designated {@code Span} and the given options.
- *
- * <p>Enters the scope of code where the newly created {@code Span} is in the current Context, and
- * returns an object that represents that scope. The scope is exited when the returned object is
- * closed then the previous Context is restored and the newly created {@code Span} is ended using
- * {@link Span#end}.
- *
- * <p>Supports try-with-resource idiom.
- *
- * <p>See {@link #startScopedSpan(String)} for example to use.
- *
- * @param parent The parent of the returned Span.
- * @param name The name of the returned Span.
- * @param options The options for the start of the Span.
- * @return An object that defines a scope where the newly created child will be set to the current
- * Context.
- * @throws NullPointerException if name or options is null.
- */
- public NonThrowingCloseable startScopedSpan(
- @Nullable Span parent, String name, StartSpanOptions options) {
- return new ScopedSpanHandle(
- spanFactory.startSpan(parent, checkNotNull(name, "name"), checkNotNull(options, "options")),
- contextSpanHandler);
+ public SpanBuilder spanBuilder(@Nullable Span parent, String name) {
+ return new SpanBuilder(
+ spanFactory,
+ contextSpanHandler,
+ parent == null ? null : parent.getContext(),
+ /* hasRemoteParent = */ false,
+ checkNotNull(name, "name"));
}
/**
- * Creates and starts a new child {@link Span} (or root if parent is null), with parent being the
- * designated {@code Span} and the given options.
+ * Returns a {@link SpanBuilder} to create and start a new child {@link Span} (or root if parent
+ * is null), with parent being the {@link Span} designated by the {@link SpanContext}.
*
- * <p>Users must manually end the newly created {@code Span}.
+ * <p>See {@link SpanBuilder} for usage examples.
*
- * <p>Does not install the newly created {@code Span} to the current Context.
- *
- * <p>Example of usage:
- *
- * <pre>{@code
- * class MyClass {
- * private static final Tracer tracer = Tracer.getTracer();
- * void DoWork() {
- * try (Span span = tracer.startSpan(null, "MyRootSpan", StartSpanOptions.getDefault())) {
- * span.addAnnotation("We did X");
- * }
- * }
- * }
- * }</pre>
- *
- * @param parent The parent of the returned Span.
- * @param name The name of the returned Span.
- * @param options The options for the start of the Span.
- * @return A child span that will have the name provided.
- * @throws NullPointerException if name or options is null.
- */
- public Span startSpan(@Nullable Span parent, String name, StartSpanOptions options) {
- return spanFactory.startSpan(
- parent, checkNotNull(name, "name"), checkNotNull(options, "options"));
- }
-
- /**
- * Creates and starts a new child {@link Span} (or root if parent is null), with parent being the
- * {@link Span} designated by the {@link SpanContext} and the given options.
- *
- * <p>This must be used to create a {@code Span} when the parent is on a different process.
- *
- * <p>Users must manually end the newly created {@code Span}.
- *
- * <p>Does not install the newly created {@code Span} to the current Context.
+ * <p>This <b>must</b> be used to create a {@code Span} when the parent is in a different process.
+ * This is only intended for use by RPC systems or similar.
*
* @param remoteParent The remote parent of the returned Span.
* @param name The name of the returned Span.
- * @param options The options for the start of the Span.
- * @return A child span that will have the name provided.
- * @throws NullPointerException if name or options is null.
+ * @return a {@code SpanBuilder} to create and start a new {@code Span}.
+ * @throws NullPointerException if name is null.
*/
- public Span startSpanWithRemoteParent(
- @Nullable SpanContext remoteParent, String name, StartSpanOptions options) {
- return spanFactory.startSpanWithRemoteParent(
- remoteParent, checkNotNull(name, "name"), checkNotNull(options, "options"));
+ public SpanBuilder spanBuilderWithRemoteParent(@Nullable SpanContext remoteParent, String name) {
+ return new SpanBuilder(
+ spanFactory,
+ contextSpanHandler,
+ remoteParent,
+ /* hasRemoteParent = */ true,
+ checkNotNull(name, "name"));
}
@VisibleForTesting
@@ -346,6 +230,7 @@ public final class Tracer {
};
@Override
+ @Nullable
public Span getCurrentSpan() {
return null;
}
@@ -359,13 +244,11 @@ public final class Tracer {
// No-op implementation of the SpanFactory
private static final class NoopSpanFactory extends SpanFactory {
@Override
- public Span startSpan(@Nullable Span parent, String name, StartSpanOptions options) {
- return BlankSpan.INSTANCE;
- }
-
- @Override
- public Span startSpanWithRemoteParent(
- @Nullable SpanContext remoteParent, String name, StartSpanOptions options) {
+ public Span startSpan(
+ @Nullable SpanContext parent,
+ boolean hasRemoteParent,
+ String name,
+ StartSpanOptions options) {
return BlankSpan.INSTANCE;
}
}
diff --git a/core/src/test/java/com/google/instrumentation/trace/SpanBuilderTest.java b/core/src/test/java/com/google/instrumentation/trace/SpanBuilderTest.java
new file mode 100644
index 00000000..6e91ca4d
--- /dev/null
+++ b/core/src/test/java/com/google/instrumentation/trace/SpanBuilderTest.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2017, Google Inc.
+ * 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 com.google.instrumentation.trace;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isNull;
+import static org.mockito.Matchers.same;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import com.google.instrumentation.common.NonThrowingCloseable;
+import com.google.instrumentation.common.Timestamp;
+import java.util.Arrays;
+import java.util.List;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/** Unit tests for {@link Tracer}. */
+@RunWith(JUnit4.class)
+public class SpanBuilderTest {
+ @Mock private ContextSpanHandler contextSpanHandler;
+ @Mock private Span span;
+ @Mock private SpanFactory spanFactory;
+ @Mock private NonThrowingCloseable withSpan;
+
+ private static final SpanContext SPAN_CONTEXT =
+ new SpanContext(new TraceId(10, 20), new SpanId(30), TraceOptions.getDefault());
+ private static final String SPAN_NAME = "MySpanName";
+ private SpanBuilder spanBuilder;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ spanBuilder =
+ new SpanBuilder(
+ spanFactory, contextSpanHandler, SPAN_CONTEXT, false /* hasRemoteParent */, SPAN_NAME);
+ }
+
+ @Test
+ public void startScopedSpanRoot() {
+ when(spanFactory.startSpan(
+ isNull(SpanContext.class), eq(false), same(SPAN_NAME), eq(new StartSpanOptions())))
+ .thenReturn(span);
+ when(contextSpanHandler.withSpan(same(span))).thenReturn(withSpan);
+ try (NonThrowingCloseable ss = spanBuilder.becomeRoot().startScopedSpan()) {}
+ verify(withSpan).close();
+ verify(span).end(same(EndSpanOptions.DEFAULT));
+ }
+
+ @Test
+ public void startScopedSpanRootWithOptions() {
+ StartSpanOptions startSpanOptions = new StartSpanOptions();
+ startSpanOptions.setSampler(Samplers.neverSample());
+ startSpanOptions.setStartTime(Timestamp.fromMillis(1234567L));
+ when(spanFactory.startSpan(
+ isNull(SpanContext.class), eq(false), same(SPAN_NAME), eq(startSpanOptions)))
+ .thenReturn(span);
+ when(contextSpanHandler.withSpan(same(span))).thenReturn(withSpan);
+ try (NonThrowingCloseable ss =
+ spanBuilder
+ .becomeRoot()
+ .setSampler(Samplers.neverSample())
+ .setStartTime(Timestamp.fromMillis(1234567L))
+ .startScopedSpan()) {}
+ verify(withSpan).close();
+ verify(span).end(same(EndSpanOptions.DEFAULT));
+ }
+
+ @Test
+ public void startRootSpan() {
+ when(spanFactory.startSpan(
+ isNull(SpanContext.class), eq(false), same(SPAN_NAME), eq(new StartSpanOptions())))
+ .thenReturn(span);
+ try (Span rootSpan = spanBuilder.becomeRoot().startSpan()) {
+ assertThat(rootSpan).isEqualTo(span);
+ }
+ }
+
+ @Test
+ public void startSpan_WithNullParent() {
+ spanBuilder =
+ new SpanBuilder(
+ spanFactory, contextSpanHandler, null, false /* hasRemoteParent */, SPAN_NAME);
+ when(spanFactory.startSpan(
+ isNull(SpanContext.class), eq(false), same(SPAN_NAME), eq(new StartSpanOptions())))
+ .thenReturn(span);
+ try (Span rootSpan = spanBuilder.startSpan()) {
+ assertThat(rootSpan).isEqualTo(span);
+ }
+ }
+
+ @Test
+ public void startRootSpanWithOptions() {
+ List<Span> parentList = Arrays.asList(BlankSpan.INSTANCE);
+ StartSpanOptions startSpanOptions = new StartSpanOptions();
+ startSpanOptions.setParentLinks(parentList);
+ startSpanOptions.setSampler(Samplers.neverSample());
+ when(spanFactory.startSpan(
+ isNull(SpanContext.class), eq(false), same(SPAN_NAME), eq(startSpanOptions)))
+ .thenReturn(span);
+ try (Span rootSpan =
+ spanBuilder
+ .becomeRoot()
+ .setSampler(Samplers.neverSample())
+ .setParentLinks(parentList)
+ .startSpan()) {
+ assertThat(rootSpan).isEqualTo(span);
+ }
+ }
+
+ @Test
+ public void startChildSpan() {
+ when(spanFactory.startSpan(
+ same(SPAN_CONTEXT), eq(false), same(SPAN_NAME), eq(new StartSpanOptions())))
+ .thenReturn(span);
+ try (Span childSpan = spanBuilder.startSpan()) {
+ assertThat(childSpan).isEqualTo(span);
+ }
+ }
+
+ @Test
+ public void startChildSpanWithOptions() {
+ StartSpanOptions startSpanOptions = new StartSpanOptions();
+ startSpanOptions.setSampler(Samplers.neverSample());
+ startSpanOptions.setRecordEvents(true);
+ when(spanFactory.startSpan(
+ same(SPAN_CONTEXT), eq(false), same(SPAN_NAME), eq(startSpanOptions)))
+ .thenReturn(span);
+ try (Span childSpan =
+ spanBuilder.setSampler(Samplers.neverSample()).setRecordEvents(true).startSpan()) {
+ assertThat(childSpan).isEqualTo(span);
+ }
+ }
+
+ @Test
+ public void startSpanWitRemoteParent() {
+ spanBuilder =
+ new SpanBuilder(
+ spanFactory, contextSpanHandler, SPAN_CONTEXT, true /* hasRemoteParent */, SPAN_NAME);
+ when(spanFactory.startSpan(
+ same(SPAN_CONTEXT), eq(true), same(SPAN_NAME), eq(new StartSpanOptions())))
+ .thenReturn(span);
+ try (Span remoteChildSpan = spanBuilder.startSpan()) {
+ assertThat(remoteChildSpan).isEqualTo(span);
+ }
+ }
+
+ @Test
+ public void startSpanWitRemoteParent_WithNullParent() {
+ spanBuilder =
+ new SpanBuilder(
+ spanFactory, contextSpanHandler, null, true /* hasRemoteParent */, SPAN_NAME);
+ when(spanFactory.startSpan(
+ isNull(SpanContext.class), eq(true), same(SPAN_NAME), eq(new StartSpanOptions())))
+ .thenReturn(span);
+ try (Span remoteChildSpan = spanBuilder.startSpan()) {
+ assertThat(remoteChildSpan).isEqualTo(span);
+ }
+ }
+}
diff --git a/core/src/test/java/com/google/instrumentation/trace/StartSpanOptionsTest.java b/core/src/test/java/com/google/instrumentation/trace/StartSpanOptionsTest.java
index 4aa6a243..314789a8 100644
--- a/core/src/test/java/com/google/instrumentation/trace/StartSpanOptionsTest.java
+++ b/core/src/test/java/com/google/instrumentation/trace/StartSpanOptionsTest.java
@@ -18,6 +18,7 @@ import static com.google.common.truth.Truth.assertThat;
import com.google.common.testing.EqualsTester;
import com.google.instrumentation.common.Timestamp;
import java.util.Arrays;
+import java.util.LinkedList;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -26,21 +27,21 @@ import org.junit.runners.JUnit4;
/** Unit tests for {@link StartSpanOptions}. */
@RunWith(JUnit4.class)
public class StartSpanOptionsTest {
- private final Span singleParent = BlankSpan.INSTANCE;
- private final List<Span> parentList = Arrays.asList(BlankSpan.INSTANCE, BlankSpan.INSTANCE);
+ private final List<Span> singleParentList = Arrays.asList(BlankSpan.INSTANCE);
@Test
public void defaultOptions() {
- assertThat(StartSpanOptions.getDefault().getStartTime()).isNull();
- assertThat(StartSpanOptions.getDefault().getSampler()).isNull();
- assertThat(StartSpanOptions.getDefault().getParentLinks().isEmpty()).isTrue();
- assertThat(StartSpanOptions.getDefault().getRecordEvents()).isNull();
+ StartSpanOptions defaultOptions = new StartSpanOptions();
+ assertThat(defaultOptions.getStartTime()).isNull();
+ assertThat(defaultOptions.getSampler()).isNull();
+ assertThat(defaultOptions.getParentLinks().isEmpty()).isTrue();
+ assertThat(defaultOptions.getRecordEvents()).isNull();
}
@Test
public void setStartTime() {
- StartSpanOptions options =
- StartSpanOptions.builder().setStartTime(Timestamp.fromMillis(1234567L)).build();
+ StartSpanOptions options = new StartSpanOptions();
+ options.setStartTime(Timestamp.fromMillis(1234567L));
assertThat(options.getStartTime()).isEqualTo(Timestamp.fromMillis(1234567L));
assertThat(options.getSampler()).isNull();
assertThat(options.getParentLinks().isEmpty()).isTrue();
@@ -49,8 +50,8 @@ public class StartSpanOptionsTest {
@Test
public void setSampler() {
- StartSpanOptions options =
- StartSpanOptions.builder().setSampler(Samplers.neverSample()).build();
+ StartSpanOptions options = new StartSpanOptions();
+ options.setSampler(Samplers.neverSample());
assertThat(options.getStartTime()).isNull();
assertThat(options.getSampler()).isEqualTo(Samplers.neverSample());
assertThat(options.getParentLinks().isEmpty()).isTrue();
@@ -58,36 +59,39 @@ public class StartSpanOptionsTest {
}
@Test
- public void addParentLink() {
- StartSpanOptions options = StartSpanOptions.builder().addParentLink(singleParent).build();
+ public void setParentLinks() {
+ StartSpanOptions options = new StartSpanOptions();
+ options.setParentLinks(singleParentList);
assertThat(options.getStartTime()).isNull();
assertThat(options.getSampler()).isNull();
- assertThat(options.getParentLinks().size()).isEqualTo(1);
+ assertThat(options.getParentLinks()).isEqualTo(singleParentList);
assertThat(options.getRecordEvents()).isNull();
}
- @Test(expected = NullPointerException.class)
- public void addParentLink_Null() {
- StartSpanOptions.builder().addParentLink(null).build();
+ @Test
+ public void setParentLinks_EmptyList() {
+ StartSpanOptions options = new StartSpanOptions();
+ options.setParentLinks(new LinkedList<Span>());
+ assertThat(options.getStartTime()).isNull();
+ assertThat(options.getSampler()).isNull();
+ assertThat(options.getParentLinks().size()).isEqualTo(0);
+ assertThat(options.getRecordEvents()).isNull();
}
@Test
- public void addParentLinks() {
- StartSpanOptions options = StartSpanOptions.builder().addParentLinks(parentList).build();
+ public void setParentLinks_MultipleParents() {
+ StartSpanOptions options = new StartSpanOptions();
+ options.setParentLinks(Arrays.asList(BlankSpan.INSTANCE, BlankSpan.INSTANCE));
assertThat(options.getStartTime()).isNull();
assertThat(options.getSampler()).isNull();
assertThat(options.getParentLinks().size()).isEqualTo(2);
assertThat(options.getRecordEvents()).isNull();
}
- @Test(expected = NullPointerException.class)
- public void addParentLinks_Null() {
- StartSpanOptions.builder().addParentLinks(null).build();
- }
-
@Test
public void setRecordEvents() {
- StartSpanOptions options = StartSpanOptions.builder().setRecordEvents(true).build();
+ StartSpanOptions options = new StartSpanOptions();
+ options.setRecordEvents(true);
assertThat(options.getStartTime()).isNull();
assertThat(options.getSampler()).isNull();
assertThat(options.getParentLinks().isEmpty()).isTrue();
@@ -96,46 +100,33 @@ public class StartSpanOptionsTest {
@Test
public void setAllProperties() {
- StartSpanOptions options =
- StartSpanOptions.builder()
- .setStartTime(Timestamp.fromMillis(1234567L))
- .setSampler(Samplers.neverSample())
- .setSampler(Samplers.alwaysSample()) // second SetSampler should apply
- .addParentLink(singleParent)
- .setRecordEvents(true)
- .addParentLinks(parentList)
- .build();
+ StartSpanOptions options = new StartSpanOptions();
+ options.setStartTime(Timestamp.fromMillis(1234567L));
+ options.setSampler(Samplers.neverSample());
+ options.setSampler(Samplers.alwaysSample()); // second SetSampler should apply
+ options.setRecordEvents(true);
+ options.setParentLinks(singleParentList);
assertThat(options.getStartTime()).isEqualTo(Timestamp.fromMillis(1234567L));
assertThat(options.getSampler()).isEqualTo(Samplers.alwaysSample());
- assertThat(options.getParentLinks().size()).isEqualTo(3);
+ assertThat(options.getParentLinks()).isEqualTo(singleParentList);
assertThat(options.getRecordEvents()).isTrue();
}
@Test
- public void startSpanOptions_ToString() {
- StartSpanOptions options =
- StartSpanOptions.builder()
- .setStartTime(Timestamp.fromMillis(1234567L))
- .setSampler(Samplers.neverSample())
- .addParentLink(singleParent)
- .setRecordEvents(true)
- .build();
- assertThat(options.toString()).contains(Timestamp.fromMillis(1234567L).toString());
- assertThat(options.toString()).contains(Samplers.neverSample().toString());
- assertThat(options.toString()).contains(singleParent.toString());
- assertThat(options.toString()).contains("recordEvents=true");
- }
-
- @Test
public void startSpanOptions_EqualsAndHashCode() {
EqualsTester tester = new EqualsTester();
- tester.addEqualityGroup(
- StartSpanOptions.builder().setStartTime(Timestamp.fromMillis(1234567L)).build(),
- StartSpanOptions.builder().setStartTime(Timestamp.fromMillis(1234567L)).build());
- tester.addEqualityGroup(
- StartSpanOptions.builder().setRecordEvents(true).build(),
- StartSpanOptions.builder().setRecordEvents(true).build());
- tester.addEqualityGroup(StartSpanOptions.getDefault(), StartSpanOptions.builder().build());
+ StartSpanOptions optionsWithStartTime1 = new StartSpanOptions();
+ optionsWithStartTime1.setStartTime(Timestamp.fromMillis(1234567L));
+ StartSpanOptions optionsWithStartTime2 = new StartSpanOptions();
+ optionsWithStartTime2.setStartTime(Timestamp.fromMillis(1234567L));
+ tester.addEqualityGroup(optionsWithStartTime1, optionsWithStartTime2);
+ StartSpanOptions optionsWithAlwaysSampler = new StartSpanOptions();
+ optionsWithAlwaysSampler.setSampler(Samplers.alwaysSample());
+ tester.addEqualityGroup(optionsWithAlwaysSampler);
+ StartSpanOptions optionsWithNeverSampler = new StartSpanOptions();
+ optionsWithNeverSampler.setSampler(Samplers.neverSample());
+ tester.addEqualityGroup(optionsWithNeverSampler);
+ tester.addEqualityGroup(new StartSpanOptions());
tester.testEquals();
}
}
diff --git a/core/src/test/java/com/google/instrumentation/trace/TracerTest.java b/core/src/test/java/com/google/instrumentation/trace/TracerTest.java
index de67c6ec..4afbb93d 100644
--- a/core/src/test/java/com/google/instrumentation/trace/TracerTest.java
+++ b/core/src/test/java/com/google/instrumentation/trace/TracerTest.java
@@ -41,6 +41,11 @@ public class TracerTest {
@Mock private Span span;
@Mock private NonThrowingCloseable withSpan;
+ @Test
+ public void defaultGetCurrentSpan() {
+ assertThat(tracer.getCurrentSpan()).isEqualTo(BlankSpan.INSTANCE);
+ }
+
@Test(expected = NullPointerException.class)
public void withSpan_NullSpan() {
try (NonThrowingCloseable ws = tracer.withSpan(null)) {}
@@ -54,96 +59,35 @@ public class TracerTest {
}
@Test(expected = NullPointerException.class)
- public void startScopedSpanWithName_NullName() {
- try (NonThrowingCloseable ss = tracer.startScopedSpan(null)) {}
- }
-
- @Test
- public void defaultStartScopedSpanWithName() {
- try (NonThrowingCloseable ss = tracer.startScopedSpan("MySpanName")) {
- assertThat(tracer.getCurrentSpan()).isEqualTo(BlankSpan.INSTANCE);
- }
- }
-
- @Test(expected = NullPointerException.class)
- public void startScopedSpanWithNameAndOptions_NullName() {
- try (NonThrowingCloseable ss = tracer.startScopedSpan(null, StartSpanOptions.getDefault())) {}
- }
-
- @Test(expected = NullPointerException.class)
- public void startScopedSpanWithNameAndOptions_NullOptions() {
- try (NonThrowingCloseable ss = tracer.startScopedSpan("MySpanName", null)) {}
- }
-
- @Test
- public void defaultStartScopedSpanWithNameAndOptions() {
- try (NonThrowingCloseable ss =
- tracer.startScopedSpan("MySpanName", StartSpanOptions.getDefault())) {
- assertThat(tracer.getCurrentSpan()).isEqualTo(BlankSpan.INSTANCE);
- }
- }
-
- @Test(expected = NullPointerException.class)
- public void startScopedSpanWithParentAndName_NullName() {
- try (NonThrowingCloseable ss = tracer.startScopedSpan((Span) null, null)) {}
+ public void spanBuilderWithName_NullName() {
+ assertThat(tracer.spanBuilder(null).startSpan()).isSameAs(BlankSpan.INSTANCE);
}
@Test
- public void defaultStartScopedSpanWithParentAndName() {
- try (NonThrowingCloseable ss = tracer.startScopedSpan(null, "MySpanName")) {
- assertThat(tracer.getCurrentSpan()).isEqualTo(BlankSpan.INSTANCE);
- }
- }
-
- @Test(expected = NullPointerException.class)
- public void startScopedSpanWithParentAndNameAndOptions_NullName() {
- try (NonThrowingCloseable ss =
- tracer.startScopedSpan(null, null, StartSpanOptions.getDefault())) {}
- }
-
- @Test(expected = NullPointerException.class)
- public void startScopedSpanWithParentAndNameAndOptions_NullOptions() {
- try (NonThrowingCloseable ss = tracer.startScopedSpan(null, "MySpanName", null)) {}
- }
-
- @Test
- public void defaultStartScopedSpanWithParentAndNameAndOptions() {
- try (NonThrowingCloseable ss =
- tracer.startScopedSpan(null, "MySpanName", StartSpanOptions.getDefault())) {
- assertThat(tracer.getCurrentSpan()).isEqualTo(BlankSpan.INSTANCE);
- }
+ public void defaultSpanBuilderWithName() {
+ assertThat(tracer.spanBuilder("MySpanName").startSpan()).isSameAs(BlankSpan.INSTANCE);
}
@Test(expected = NullPointerException.class)
- public void startSpan_NullName() {
- tracer.startSpan(null, null, StartSpanOptions.getDefault());
- }
-
- @Test(expected = NullPointerException.class)
- public void startSpan_NullOptions() {
- tracer.startSpan(null, "MySpanName", null);
+ public void spanBuilderWithParentAndName_NullName() {
+ assertThat(tracer.spanBuilder(null, null).startSpan()).isSameAs(BlankSpan.INSTANCE);
}
@Test
- public void defaultStartSpan() {
- assertThat(tracer.startSpan(null, "MySpanName", StartSpanOptions.getDefault()))
- .isEqualTo(BlankSpan.INSTANCE);
- }
-
- @Test(expected = NullPointerException.class)
- public void startSpanWithRemoteParent_NullName() {
- tracer.startSpanWithRemoteParent(null, null, StartSpanOptions.getDefault());
+ public void defaultSpanBuilderWithParentAndName() {
+ assertThat(tracer.spanBuilder(null, "MySpanName").startSpan()).isSameAs(BlankSpan.INSTANCE);
}
@Test(expected = NullPointerException.class)
- public void startSpanWithRemoteParent_NullOptions() {
- tracer.startSpanWithRemoteParent(null, "MySpanName", null);
+ public void spanBuilderWithRemoteParent_NullName() {
+ assertThat(tracer.spanBuilderWithRemoteParent(null, null).startSpan())
+ .isSameAs(BlankSpan.INSTANCE);
}
@Test
- public void defaultStartSpanWitRemoteParent() {
- assertThat(tracer.startSpanWithRemoteParent(null, "MySpanName", StartSpanOptions.getDefault()))
- .isEqualTo(BlankSpan.INSTANCE);
+ public void defaultSpanBuilderWitRemoteParent() {
+ assertThat(tracer.spanBuilderWithRemoteParent(null, "MySpanName").startSpan())
+ .isSameAs(BlankSpan.INSTANCE);
}
@Test
@@ -220,72 +164,61 @@ public class TracerTest {
}
@Test
- public void startScopedSpanWithName() {
+ public void startScopedSpanRoot() {
Tracer mockTracer = newTracerWithMocks();
when(contextSpanHandler.getCurrentSpan()).thenReturn(null);
when(spanFactory.startSpan(
- same(BlankSpan.INSTANCE), eq("MySpanName"), same(StartSpanOptions.getDefault())))
+ isNull(SpanContext.class), eq(false), eq("MySpanName"), eq(new StartSpanOptions())))
.thenReturn(span);
when(contextSpanHandler.withSpan(same(span))).thenReturn(withSpan);
- try (NonThrowingCloseable ss = mockTracer.startScopedSpan("MySpanName")) {}
+ try (NonThrowingCloseable ss =
+ mockTracer.spanBuilder("MySpanName").becomeRoot().startScopedSpan()) {}
verify(withSpan).close();
verify(span).end(same(EndSpanOptions.DEFAULT));
}
@Test
- public void startScopedSpanWithNameAndOptions() {
+ public void startScopedSpanChild() {
Tracer mockTracer = newTracerWithMocks();
- when(contextSpanHandler.getCurrentSpan()).thenReturn(null);
- StartSpanOptions startSpanOptions = StartSpanOptions.builder().build();
+ when(contextSpanHandler.getCurrentSpan()).thenReturn(BlankSpan.INSTANCE);
when(spanFactory.startSpan(
- same(BlankSpan.INSTANCE), eq("MySpanName"), same(startSpanOptions)))
+ same(BlankSpan.INSTANCE.getContext()),
+ eq(false),
+ eq("MySpanName"),
+ eq(new StartSpanOptions())))
.thenReturn(span);
when(contextSpanHandler.withSpan(same(span))).thenReturn(withSpan);
- try (NonThrowingCloseable ss = mockTracer.startScopedSpan("MySpanName", startSpanOptions)) {}
+ try (NonThrowingCloseable ss = mockTracer.spanBuilder("MySpanName").startScopedSpan()) {}
verify(withSpan).close();
verify(span).end(same(EndSpanOptions.DEFAULT));
}
@Test
- public void startScopedSpanWithParentAndName() {
- Tracer mockTracer = newTracerWithMocks();
- when(spanFactory.startSpan(same(span), eq("MySpanName"), same(StartSpanOptions.getDefault())))
- .thenReturn(span);
- when(contextSpanHandler.withSpan(same(span))).thenReturn(withSpan);
- try (NonThrowingCloseable ss = mockTracer.startScopedSpan(span, "MySpanName")) {}
- verify(withSpan).close();
- verify(span).end(same(EndSpanOptions.DEFAULT));
- }
-
- @Test
- public void startScopedSpanWithParentAndNameAndOptions() {
+ public void startRootSpan() {
Tracer mockTracer = newTracerWithMocks();
- StartSpanOptions startSpanOptions = StartSpanOptions.builder().build();
- when(spanFactory.startSpan(same(span), eq("MySpanName"), same(startSpanOptions)))
+ when(spanFactory.startSpan(
+ isNull(SpanContext.class), eq(false), eq("MySpanName"), eq(new StartSpanOptions())))
.thenReturn(span);
- when(contextSpanHandler.withSpan(same(span))).thenReturn(withSpan);
- try (NonThrowingCloseable ss =
- mockTracer.startScopedSpan(span, "MySpanName", startSpanOptions)) {}
- verify(withSpan).close();
+ try (Span rootSpan =
+ mockTracer.spanBuilder(BlankSpan.INSTANCE, "MySpanName").becomeRoot().startSpan()) {
+ assertThat(rootSpan).isEqualTo(span);
+ }
verify(span).end(same(EndSpanOptions.DEFAULT));
}
@Test
public void startChildSpan() {
Tracer mockTracer = newTracerWithMocks();
- StartSpanOptions startSpanOptions = StartSpanOptions.builder().build();
- when(spanFactory.startSpan(same(span), eq("MySpanName"), same(startSpanOptions)))
- .thenReturn(span);
- assertThat(mockTracer.startSpan(span, "MySpanName", startSpanOptions)).isEqualTo(span);
- }
-
- @Test
- public void startRootSpan() {
- Tracer mockTracer = newTracerWithMocks();
- StartSpanOptions startSpanOptions = StartSpanOptions.builder().build();
- when(spanFactory.startSpan(isNull(Span.class), eq("MySpanName"), same(startSpanOptions)))
+ when(spanFactory.startSpan(
+ same(BlankSpan.INSTANCE.getContext()),
+ eq(false),
+ eq("MySpanName"),
+ eq(new StartSpanOptions())))
.thenReturn(span);
- assertThat(mockTracer.startSpan(null, "MySpanName", startSpanOptions)).isEqualTo(span);
+ try (Span childSpan = mockTracer.spanBuilder(BlankSpan.INSTANCE, "MySpanName").startSpan()) {
+ assertThat(childSpan).isEqualTo(span);
+ }
+ verify(span).end(same(EndSpanOptions.DEFAULT));
}
@Test
@@ -293,23 +226,13 @@ public class TracerTest {
Tracer mockTracer = newTracerWithMocks();
SpanContext spanContext = new SpanContext(new TraceId(10, 20), new SpanId(30),
TraceOptions.getDefault());
- StartSpanOptions startSpanOptions = StartSpanOptions.builder().build();
- when(spanFactory.startSpanWithRemoteParent(
- same(spanContext), eq("MySpanName"), same(startSpanOptions)))
- .thenReturn(span);
- assertThat(mockTracer.startSpanWithRemoteParent(spanContext, "MySpanName", startSpanOptions))
- .isEqualTo(span);
- }
-
- @Test
- public void startSpanWitRemoteParent_WithNullParent() {
- Tracer mockTracer = newTracerWithMocks();
- StartSpanOptions startSpanOptions = StartSpanOptions.builder().build();
- when(spanFactory.startSpanWithRemoteParent(
- isNull(SpanContext.class), eq("MySpanName"), same(startSpanOptions)))
+ when(spanFactory.startSpan(
+ same(spanContext), eq(true), eq("MySpanName"), eq(new StartSpanOptions())))
.thenReturn(span);
- assertThat(mockTracer.startSpanWithRemoteParent(null, "MySpanName", startSpanOptions))
- .isEqualTo(span);
+ try (Span remoteChildSpan =
+ mockTracer.spanBuilderWithRemoteParent(spanContext, "MySpanName").startSpan()) {
+ assertThat(remoteChildSpan).isEqualTo(span);
+ }
}
private Tracer newTracerWithMocks() {