Skip to content
6 changes: 6 additions & 0 deletions .palantir/revapi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,9 @@ acceptedBreaks:
old: "method com.palantir.tracing.api.OpenSpan.Builder com.palantir.tracing.api.ImmutableOpenSpan.Builder::originatingSpanId(java.util.Optional<java.lang.String>)\
\ @ com.palantir.tracing.api.OpenSpan.Builder"
justification: "Type is not meant for external creation"
"6.4.0":
com.palantir.tracing:tracing:
- code: "java.field.serialVersionUIDChanged"
old: "field com.palantir.tracing.DeferredTracer.serialVersionUID"
new: "field com.palantir.tracing.DeferredTracer.serialVersionUID"
justification: "Library versions are in usually in sync"
17 changes: 6 additions & 11 deletions tracing/src/main/java/com/palantir/tracing/DeferredTracer.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,12 @@
*/
public final class DeferredTracer implements Serializable {

private static final long serialVersionUID = 1L;
private static final long serialVersionUID = 2L;

private static final String DEFAULT_OPERATION = "DeferredTracer(unnamed operation)";

@Nullable
private final String traceId;
private final TraceState traceState;

private final boolean isObservable;

Expand All @@ -71,9 +71,6 @@ public final class DeferredTracer implements Serializable {
@Nullable
private final String parentSpanId;

@Nullable
private final transient String requestId;

/**
* Deprecated.
*
Expand All @@ -98,15 +95,13 @@ public DeferredTracer(@Safe String operation, @Safe Map<String, String> metadata
Optional<Trace> maybeTrace = Tracer.copyTrace();
if (maybeTrace.isPresent()) {
Trace trace = maybeTrace.get();
this.traceId = trace.getTraceId();
this.requestId = trace.getRequestId().orElse(null);
this.traceState = trace.getTraceState();
this.isObservable = trace.isObservable();
this.parentSpanId = trace.top().map(OpenSpan::getSpanId).orElse(null);
this.operation = operation;
this.metadata = metadata;
} else {
this.traceId = null;
this.requestId = null;
this.traceState = null;
this.isObservable = false;
this.parentSpanId = null;
this.operation = null;
Expand All @@ -128,13 +123,13 @@ public <T, E extends Throwable> T withTrace(Tracers.ThrowingCallable<T, E> inner
@MustBeClosed
@SuppressWarnings("NullAway") // either both operation & parentSpanId are nullable or neither are
CloseableTrace withTrace() {
if (traceId == null) {
if (traceState == null) {
return NopCloseableTrace.INSTANCE;
}

Optional<Trace> originalTrace = Tracer.getAndClearTraceIfPresent();

Tracer.setTrace(Trace.of(isObservable, traceId, Optional.ofNullable(requestId)));
Tracer.setTrace(Trace.of(isObservable, traceState));
if (parentSpanId != null) {
Tracer.fastStartSpan(operation, parentSpanId, SpanType.LOCAL);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public static boolean isSampled(DetachedSpan detachedSpan) {

/** Returns true if the provided detachedSpan is sampled. */
public static Optional<String> getRequestId(DetachedSpan detachedSpan) {
return Tracer.getRequestId(detachedSpan);
return Optional.ofNullable(Tracer.getRequestId(detachedSpan));
}

private InternalTracers() {}
Expand Down
52 changes: 29 additions & 23 deletions tracing/src/main/java/com/palantir/tracing/Trace.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,11 @@
*/
public abstract class Trace {

private final String traceId;
private final TraceState traceState;

private final Optional<String> requestId;

private Trace(String traceId, Optional<String> requestId) {
checkArgument(!Strings.isNullOrEmpty(traceId), "traceId must be non-empty");
this.traceId = traceId;
this.requestId = checkNotNull(requestId, "requestId");
private Trace(TraceState traceState) {
checkNotNull(traceState, "Common trace state should not be null");
this.traceState = traceState;
}

/**
Expand Down Expand Up @@ -111,9 +108,14 @@ final OpenSpan startSpan(String operation, SpanType type) {
*/
abstract boolean isObservable();

/** The state of the trace which is stored for each created trace. */
final TraceState getTraceState() {
return this.traceState;
}

/** The globally unique non-empty identifier for this call trace. */
final String getTraceId() {
return traceId;
return traceState.traceId();
}

/**
Expand All @@ -124,27 +126,32 @@ final String getTraceId() {
* distinguish between requests with the same traceId.
*/
final Optional<String> getRequestId() {
return requestId;
return Optional.ofNullable(traceState.requestId());
}

/** Returns a copy of this Trace which can be independently mutated. */
abstract Trace deepCopy();

@Deprecated
static Trace of(boolean isObservable, String traceId, Optional<String> requestId) {
return isObservable ? new Sampled(traceId, requestId) : new Unsampled(traceId, requestId);
return of(isObservable, TraceState.of(traceId, requestId));
}

static Trace of(boolean isObservable, TraceState traceState) {
return isObservable ? new Sampled(traceState) : new Unsampled(traceState);
}

private static final class Sampled extends Trace {

private final Deque<OpenSpan> stack;

private Sampled(ArrayDeque<OpenSpan> stack, String traceId, Optional<String> requestId) {
super(traceId, requestId);
private Sampled(ArrayDeque<OpenSpan> stack, TraceState traceState) {
super(traceState);
this.stack = stack;
}

private Sampled(String traceId, Optional<String> requestId) {
this(new ArrayDeque<>(), traceId, requestId);
private Sampled(TraceState traceState) {
this(new ArrayDeque<>(), traceState);
}

@Override
Expand Down Expand Up @@ -186,12 +193,12 @@ boolean isObservable() {

@Override
Trace deepCopy() {
return new Sampled(new ArrayDeque<>(stack), getTraceId(), getRequestId());
return new Sampled(new ArrayDeque<>(stack), getTraceState());
}

@Override
public String toString() {
return "Trace{stack=" + stack + ", isObservable=true, traceId='" + getTraceId() + "'}";
return "Trace{stack=" + stack + ", isObservable=true, state=" + getTraceState() + "}";
}
}

Expand All @@ -202,14 +209,14 @@ private static final class Unsampled extends Trace {
*/
private int numberOfSpans;

private Unsampled(int numberOfSpans, String traceId, Optional<String> requestId) {
super(traceId, requestId);
private Unsampled(int numberOfSpans, TraceState traceState) {
super(traceState);
this.numberOfSpans = numberOfSpans;
validateNumberOfSpans();
}

private Unsampled(String traceId, Optional<String> requestId) {
this(0, traceId, requestId);
private Unsampled(TraceState traceState) {
this(0, traceState);
}

@Override
Expand Down Expand Up @@ -254,7 +261,7 @@ boolean isObservable() {

@Override
Trace deepCopy() {
return new Unsampled(numberOfSpans, getTraceId(), getRequestId());
return new Unsampled(numberOfSpans, getTraceState());
}

/** Internal validation, this should never fail because {@link #pop()} only decrements positive values. */
Expand All @@ -267,8 +274,7 @@ private void validateNumberOfSpans() {

@Override
public String toString() {
return "Trace{numberOfSpans=" + numberOfSpans + ", isObservable=false, traceId='" + getTraceId()
+ "', requestId='" + getRequestId().orElse(null) + "'}";
return "Trace{numberOfSpans=" + numberOfSpans + ", isObservable=false, traceState=" + getTraceState() + "}";
}
}
}
73 changes: 73 additions & 0 deletions tracing/src/main/java/com/palantir/tracing/TraceState.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* (c) Copyright 2021 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 static com.palantir.logsafe.Preconditions.checkArgument;
import static com.palantir.logsafe.Preconditions.checkNotNull;

import com.google.common.base.Strings;
import java.io.Serializable;
import java.util.Optional;
import javax.annotation.Nullable;

/**
* Class representing the state which is created for each {@link Trace}. Contains the globally non-unique identifier of
* a trace and a request identifier used to identify different requests sent from the same trace.
*/
final class TraceState implements Serializable {
private static final long serialVersionUID = 1L;

private final String traceId;

@Nullable
private final String requestId;

static TraceState of(String traceId, Optional<String> requestId) {
checkArgument(!Strings.isNullOrEmpty(traceId), "traceId must be non-empty");
checkNotNull(requestId, "requestId should be not-null");
return new TraceState(traceId, requestId.orElse(null));
}

private TraceState(String traceId, @Nullable String requestId) {
this.traceId = traceId;
this.requestId = requestId;
}

/**
* The globally unique non-empty identifier for this call trace.
* */
String traceId() {
return traceId;
}

/**
* The request identifier of this trace.
*
* The request identifier is an implementation detail of this tracing library. A new identifier is generated
* each time a new trace is created with a SERVER_INCOMING root span. This is a convenience in order to
* distinguish between requests with the same traceId.
*/
@Nullable
String requestId() {
return requestId;
}

@Override
public String toString() {
return "TraceState{traceId='" + traceId + "', requestId='" + requestId + "'}";
}
}
Loading