Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 10 additions & 11 deletions dd-trace-ext/src/main/java/datadog/trace/tracer/ext/Examples.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package datadog.trace.tracer.ext;

import datadog.trace.tracer.Continuation;
import datadog.trace.tracer.Span;
import datadog.trace.tracer.Trace;
import datadog.trace.tracer.Tracer;

// Keeping in PR for potential discussions. Will eventually remove.
Expand All @@ -18,9 +18,8 @@ public static void test() {
final TracerContext ctx = TracerContext.getGlobalContext();
// without try-with-resources
{
Span rootSpan = ctx.getTracer().buildTrace(null);
final Span rootSpan = ctx.getTracer().buildTrace(null);
final Scope scope = ctx.pushScope(rootSpan);
rootSpan.setError(true);
rootSpan.attachThrowable(someThrowable);
scope.close();
rootSpan.finish();
Expand All @@ -44,11 +43,10 @@ public static void test() {

// with try-with-resources finishOnClose=false
{
Span rootSpan = ctx.getTracer().buildTrace(null);
try (Scope scope = ctx.pushScope(rootSpan)) {
final Span rootSpan = ctx.getTracer().buildTrace(null);
try (final Scope scope = ctx.pushScope(rootSpan)) {
// the body
} catch (Throwable t) {
rootSpan.setError(true);
} catch (final Throwable t) {
rootSpan.attachThrowable(t);
throw t;
} finally {
Expand All @@ -58,10 +56,10 @@ public static void test() {

// continuations
{
Span rootSpan = ctx.getTracer().buildTrace(null);
final Trace.Continuation cont = rootSpan.getTrace().createContinuation(rootSpan);
final Span rootSpan = ctx.getTracer().buildTrace(null);
final Continuation cont = rootSpan.getTrace().createContinuation(rootSpan);
{ // on another thread
final Span parent = cont.span();
final Span parent = cont.getSpan();
try {
// body
} finally {
Expand All @@ -71,6 +69,7 @@ public static void test() {
}

// create a span as a child of the currently active span
Span childSpan = ctx.peekScope().span().getTrace().createSpan(ctx.peekScope().span());
final Span childSpan =
ctx.peekScope().span().getTrace().createSpan(ctx.peekScope().span().getContext());
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package datadog.trace.tracer.ext;

import datadog.trace.tracer.Continuation;
import datadog.trace.tracer.Span;
import datadog.trace.tracer.Trace;

/**
* A scope holds a single span or trace continuation and may optionally finish its span or
* continuation.
*
* <p>To create a scope, see {@link TracerContext#pushScope(Span)} and {@link
* TracerContext#pushScope(Trace.Continuation)}.
* TracerContext#pushScope(Continuation)}.
Comment thread
tylerbenson marked this conversation as resolved.
Outdated
*
* <p>All created scopes must be closed with {@link Scope#close()}
*/
Expand All @@ -22,5 +22,6 @@ public interface Scope extends AutoCloseable {
* <p>Attempting to close a scope which is not on the top of its TracerContext's scope-stack is an
* error. See {@link TracerContext#peekScope()}.
*/
@Override
void close();
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package datadog.trace.tracer.ext;

import datadog.trace.tracer.Continuation;
import datadog.trace.tracer.Span;
import datadog.trace.tracer.Trace;
import datadog.trace.tracer.Tracer;

/**
Expand All @@ -27,7 +27,7 @@ public static TracerContext getGlobalContext() {
* @return The old global TracerContext, or null if no previous context ws registered
*/
public static TracerContext registerGlobalContext(
TracerContext context, boolean replaceExisting) {
final TracerContext context, final boolean replaceExisting) {
return null;
}

Expand All @@ -38,7 +38,7 @@ public static boolean isRegistered() {

private final Tracer tracer;

public TracerContext(Tracer tracer) {
public TracerContext(final Tracer tracer) {
this.tracer = tracer;
}

Expand All @@ -55,7 +55,7 @@ public Tracer getTracer() {
* @param span
* @return
*/
public Scope pushScope(Span span) {
public Scope pushScope(final Span span) {
return null;
}

Expand All @@ -66,7 +66,7 @@ public Scope pushScope(Span span) {
* @param continuation
* @return
*/
public Scope pushScope(Trace.Continuation continuation) {
public Scope pushScope(final Continuation continuation) {
return null;
}

Expand All @@ -77,7 +77,7 @@ public Scope pushScope(Trace.Continuation continuation) {
*
* @param scope the topmost scope in the scope stack.
*/
public void popScope(Scope scope) {}
public void popScope(final Scope scope) {}

/** @return The scope on the top of this scope-stack or null if there is no active scope. */
public Scope peekScope() {
Expand Down
6 changes: 6 additions & 0 deletions dd-trace/dd-trace.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,17 @@ dependencies {
annotationProcessor deps.autoservice
implementation deps.autoservice

compile project(':dd-java-agent:agent-bootstrap')

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

This is great. agent-bootstrap will be a great way to share internal tools to instrumentation and the core tracer. I added the project to list of potential renames (since it's more of a general util at this point and not agent-specific.

compile project(':dd-trace-api')

compile deps.jackson
compile deps.slf4j
// any higher versions seems to break ES tests with this exception:
// java.lang.NoSuchMethodError: com.fasterxml.jackson.dataformat.smile.SmileGenerator.getOutputContext()
compile group: 'org.msgpack', name: 'jackson-dataformat-msgpack', version: '0.8.14'

// Spock uses that for mocking
testCompile deps.bytebuddy
testCompile group: 'org.objenesis', name: 'objenesis', version: '2.6' // Last version to support Java7
testCompile group: 'nl.jqno.equalsverifier', name: 'equalsverifier', version: '2.5.2' // Last version to support Java7
}
81 changes: 62 additions & 19 deletions dd-trace/src/main/java/datadog/trace/tracer/Clock.java
Original file line number Diff line number Diff line change
@@ -1,34 +1,59 @@
package datadog.trace.tracer;

import java.util.concurrent.TimeUnit;
import lombok.EqualsAndHashCode;

/**
* A simple wrapper for system clock that aims to provide the current time
*
* <p>
*
* <p>
*
* <p>
* This is a wrapper to System clock that provides an easier way to get nanosecond precision.
*
* <p>The JDK provides two clocks:
* <li>one in nanoseconds, for precision, but it can only use to measure durations
* <li>one in milliseconds, for accuracy, useful to provide epoch time
*
* <p>
* <p>Once created this class captures current time with millisecond presition and current
* nanosecond counter.
*
* <p>At this time, we are using a millis precision (converted to micros) in order to guarantee
* consistency between the span start times and the durations
* <p>It provides an API to create {@link Timestamp} that can be used to measure durations with
* nanosecond precision.
*/
@EqualsAndHashCode
public class Clock {

/** Tracer that created this clock */
private final Tracer tracer;

/** Trace start time in nano seconds measured up to a millisecond accuracy */
private final long startTimeNano;
/** Nano ticks counter when clock is created */
private final long startNanoTicks;

public Clock(final Tracer tracer) {
this.tracer = tracer;
startTimeNano = epochTimeNano();
startNanoTicks = nanoTicks();
}

/** @return {@link Tracer} that created this clock. */
public Tracer getTracer() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does clock need to maintain a reference to the source tracer? Is this only so Timestamp can reportError?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, right now that is the only reason.

return tracer;
}

/**
* Create new timestamp instance for current time.
*
* @return new timestamp capturing current time.
*/
public Timestamp createCurrentTimestamp() {
return new Timestamp(this);
}

/**
* Get the current nanos ticks (i.e. System.nanonTime()), this method can't be use for date
* accuracy (only duration calculations)
* Get the current nanos ticks (i.e. System.nanoTime()), this method can't be use for date
* accuracy (only duration calculations).
*
* @return The current nanos ticks
* @return The current nanos ticks.
*/
public static long nanoTime() {
long nanoTicks() {
return System.nanoTime();
}

Expand All @@ -37,20 +62,38 @@ public static long nanoTime() {
*
* <p>Note: The actual precision is the millis.
*
* @return the current epoch time in micros
* @return the current epoch time in micros.
*/
public static long epochTimeMicro() {
long epochTimeMicro() {
return TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis());
}

/**
* Get the current epoch time in nanos.
*
* <p>Note: The actual precision is the millis. This will overflow ~290 years after epoch
* <p>Note: The actual precision is the millis. This will overflow ~290 years after epoch.
*
* @return the current epoch time in nanos
* @return the current epoch time in nanos.
*/
public static long epochTimeNano() {
long epochTimeNano() {
return TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis());
}

/**
* Get time this clock instance was created in nanos.
*
* @return the time this clock instance was created in nanos.
*/
long getStartTimeNano() {
return startTimeNano;
}

/**
* Get nano ticks counter value when this clock instance was created.
*
* @return nano ticks counter value when this clock instance was created.
*/
long getStartNanoTicks() {
return startNanoTicks;
}
}
26 changes: 26 additions & 0 deletions dd-trace/src/main/java/datadog/trace/tracer/Continuation.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package datadog.trace.tracer;

/**
* Continuations are used to prevent a trace from reporting without creating a span.
*
* <p>All spans are thread safe.
*
* <p>To create a Span, see {@link Trace#createContinuation(Span parentSpan)}
*/
public interface Continuation {

/** @return parent span used to create this continuation. */
Span getSpan();

/** @return trace used to create this continuation. */
Trace getTrace();

/** @return true iff continuation has been closed. */
boolean isClosed();

/**
* Close the continuation. Continuation's trace will not block reporting on account of this
* continuation.
*/
void close();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package datadog.trace.tracer;

import lombok.extern.slf4j.Slf4j;

/** Concrete implementation of a continuation */
@Slf4j
class ContinuationImpl implements Continuation {

private final TraceInternal trace;
private final Span span;
private volatile boolean closed = false;

ContinuationImpl(final TraceInternal trace, final Span span) {
this.trace = trace;
this.span = span;
}

@Override
public Trace getTrace() {
return trace;
}

@Override
public Span getSpan() {
return span;
}

@Override
public boolean isClosed() {
return closed;
}

@Override
public synchronized void close() {
if (closed) {
reportUsageError("Attempted to close continuation that is already closed: %s", this);
} else {
closeContinuation(false);
}
}

@Override
protected synchronized void finalize() {
try {
if (!closed) {
trace
.getTracer()
.reportWarning(
"Closing continuation due to GC, this will prevent trace from being reported: %s",
this);
closeContinuation(true);
}
} catch (final Throwable t) {
// Exceptions thrown in finalizer are eaten up and ignored, so log them instead
log.debug("Span finalizer had thrown an exception: ", t);
}
}

/**
* Helper method to perform operations needed to close the continuation.
*
* <p>Note: This has to be called under object lock.
*
* @param invalid true iff continuation is being closed due to GC, this will make trace invalid.
*/
private void closeContinuation(final boolean invalid) {
closed = true;
trace.closeContinuation(this, invalid);
}

private void reportUsageError(final String message, final Object... args) {
trace.getTracer().reportError(message, args);
}
}
Loading