diff --git a/tracing/src/main/java/com/palantir/tracing/CloseableSpan.java b/tracing/src/main/java/com/palantir/tracing/CloseableSpan.java index 76fe86123..85f89757e 100644 --- a/tracing/src/main/java/com/palantir/tracing/CloseableSpan.java +++ b/tracing/src/main/java/com/palantir/tracing/CloseableSpan.java @@ -17,7 +17,6 @@ package com.palantir.tracing; import java.io.Closeable; -import java.util.Optional; /** * Closeable marker around a tracing span operation. This object should be used in a try/with block. @@ -31,10 +30,4 @@ public interface CloseableSpan extends Closeable { */ @Override void close(); - - String getSpanId(); - - Optional getParentSpanId(); - - Optional getOriginatingSpanId(); } diff --git a/tracing/src/main/java/com/palantir/tracing/TraceMetadata.java b/tracing/src/main/java/com/palantir/tracing/TraceMetadata.java new file mode 100644 index 000000000..2f2e4961e --- /dev/null +++ b/tracing/src/main/java/com/palantir/tracing/TraceMetadata.java @@ -0,0 +1,44 @@ +/* + * (c) Copyright 2019 Palantir Technologies Inc. All rights reserved. + * + * 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.palantir.tracing; + +import java.util.Optional; +import org.immutables.value.Value; + +/** Ids necessary to write headers onto network requests. */ +@Value.Immutable +@Value.Style(visibility = Value.Style.ImplementationVisibility.PACKAGE) +interface TraceMetadata { + + /** Corresponds to {@link com.palantir.tracing.api.TraceHttpHeaders#TRACE_ID}. */ + String traceId(); + + /** Corresponds to {@link com.palantir.tracing.api.TraceHttpHeaders#SPAN_ID}. */ + String spanId(); + + /** Corresponds to {@link com.palantir.tracing.api.TraceHttpHeaders#PARENT_SPAN_ID}. */ + Optional parentSpanId(); + + /** Corresponds to {@link com.palantir.tracing.api.TraceHttpHeaders#ORIGINATING_SPAN_ID}. */ + Optional originatingSpanId(); + + static Builder builder() { + return new Builder(); + } + + class Builder extends ImmutableTraceMetadata.Builder {} +} diff --git a/tracing/src/main/java/com/palantir/tracing/Tracer.java b/tracing/src/main/java/com/palantir/tracing/Tracer.java index 3231db87e..d850cb2f5 100644 --- a/tracing/src/main/java/com/palantir/tracing/Tracer.java +++ b/tracing/src/main/java/com/palantir/tracing/Tracer.java @@ -28,6 +28,7 @@ import com.palantir.logsafe.SafeArg; import com.palantir.logsafe.UnsafeArg; import com.palantir.logsafe.exceptions.SafeIllegalArgumentException; +import com.palantir.logsafe.exceptions.SafeRuntimeException; import com.palantir.tracing.api.OpenSpan; import com.palantir.tracing.api.Span; import com.palantir.tracing.api.SpanObserver; @@ -89,6 +90,32 @@ private static boolean shouldObserve(Observability observability) { throw new SafeIllegalArgumentException("Unknown observability", SafeArg.of("observability", observability)); } + static TraceMetadata getTraceMetadata() { + Trace trace = checkNotNull(currentTrace.get(), "Unable to getTraceMetadata when there is trace in progress"); + + if (trace.isObservable()) { + OpenSpan openSpan = trace.top() + .orElseThrow(() -> new SafeRuntimeException("Trace with no spans in progress")); + return TraceMetadata.builder() + .spanId(openSpan.getSpanId()) + .parentSpanId(openSpan.getParentSpanId()) + .originatingSpanId(trace.getOriginatingSpanId()) + .traceId(trace.getTraceId()) + .build(); + } else { + // In the unsampled case, the Trace.Unsampled class doesn't actually store a spanId/parentSpanId + // stack, so we just make one up (just in time). This matches the behaviour of Tracer#startSpan. + + // n.b. this is a bit funky because calling getTraceMetadata multiple times will return different spanIds + return TraceMetadata.builder() + .spanId(Tracers.randomId()) + .parentSpanId(Optional.empty()) + .originatingSpanId(trace.getOriginatingSpanId()) + .traceId(trace.getTraceId()) + .build(); + } + } + /** * Deprecated. * @@ -207,8 +234,8 @@ public CloseableSpan childSpan(String operationName, SpanType type) { warnIfCompleted("startSpanOnCurrentThread"); Trace maybeCurrentTrace = currentTrace.get(); setTrace(Trace.of(true, traceId)); - OpenSpan newSpan = Tracer.startSpan(operationName, openSpan.getSpanId(), type); - return TraceRestoringCloseableSpan.of(maybeCurrentTrace, newSpan); + Tracer.fastStartSpan(operationName, openSpan.getSpanId(), type); + return TraceRestoringCloseableSpan.of(maybeCurrentTrace); } @Override @@ -251,8 +278,8 @@ private static final class UnsampledDetachedSpan implements DetachedSpan { public CloseableSpan childSpan(String operationName, SpanType type) { Trace maybeCurrentTrace = currentTrace.get(); setTrace(Trace.of(false, traceId)); - OpenSpan newSpan = Tracer.startSpan(operationName, type); - return TraceRestoringCloseableSpan.of(maybeCurrentTrace, newSpan); + Tracer.fastStartSpan(operationName, type); + return TraceRestoringCloseableSpan.of(maybeCurrentTrace); } @Override @@ -273,40 +300,23 @@ public String toString() { private static final class TraceRestoringCloseableSpan implements CloseableSpan { - @Nullable - private final Trace traceToRestore; - private final OpenSpan newSpan; - - TraceRestoringCloseableSpan(@Nullable Trace traceToRestore, OpenSpan newSpan) { - this.traceToRestore = traceToRestore; - this.newSpan = Preconditions.checkNotNull(newSpan, "OpenSpan"); - } - - public static CloseableSpan of(@Nullable Trace traceToRestore, OpenSpan newSpan) { - return new TraceRestoringCloseableSpan(traceToRestore, newSpan); - } + // Complete the current span. + private static final CloseableSpan DEFAULT_TOKEN = Tracer::fastCompleteSpan; - @Override - public void close() { - Tracer.fastCompleteSpan(); - if (traceToRestore != null) { - Tracer.setTrace(traceToRestore); - } - } + private final Trace original; - @Override - public String getSpanId() { - return newSpan.getSpanId(); + static CloseableSpan of(@Nullable Trace original) { + return original == null ? DEFAULT_TOKEN : new TraceRestoringCloseableSpan(original); } - @Override - public Optional getParentSpanId() { - return newSpan.getParentSpanId(); + TraceRestoringCloseableSpan(Trace original) { + this.original = Preconditions.checkNotNull(original, "Expected an original trace instance"); } @Override - public Optional getOriginatingSpanId() { - return newSpan.getOriginatingSpanId(); + public void close() { + DEFAULT_TOKEN.close(); + Tracer.setTrace(original); } }