All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.kristofa.brave.SpanId Maven / Gradle / Ivy

There is a newer version: 4.13.6
Show newest version
package com.github.kristofa.brave;

import com.github.kristofa.brave.internal.Nullable;
import java.nio.ByteBuffer;

import static com.github.kristofa.brave.internal.Util.checkNotNull;

/**
 * Contains trace data that's propagated in-band across requests, sometimes known as Baggage.
 *
 * 

This implementation is biased towards a fixed-length binary serialization format that doesn't * have a way to represent an absent parent (root span). In this serialized form, a root span is * when all three ids are the same. Alternatively, you can use {@link #nullableParentId}. * *

Particularly, this includes sampled state, and a portable binary representation. The * implementation is a port of {@code com.twitter.finagle.tracing.TraceId}. * @deprecated Replaced by {@code brave.propagation.TraceContext} */ @Deprecated public final class SpanId { public static final int FLAG_DEBUG = 1 << 0; /** When set, we can interpret {@link #FLAG_SAMPLED} as a set value. */ public static final int FLAG_SAMPLING_SET = 1 << 1; public static final int FLAG_SAMPLED = 1 << 2; /** * When set, we can ignore the value of the {@link #parentId} * *

While many zipkin systems re-use a trace id as the root span id, we know that some don't. * With this flag, we can tell for sure if the span is root as opposed to the convention trace id * == span id == parent id. */ public static final int FLAG_IS_ROOT = 1 << 3; /** * Creates a new span id. * * @param traceId Trace Id. * @param spanId Span Id. * @param parentSpanId Nullable parent span id. * @deprecated Please use {@link SpanId.Builder} */ @Deprecated public static SpanId create(long traceId, long spanId, @Nullable Long parentSpanId) { return SpanId.builder().traceId(traceId).parentId(parentSpanId).spanId(spanId).build(); } /** * @deprecated Please use {@link SpanId.Builder} */ @Deprecated public SpanId(long traceId, long parentId, long spanId, long flags) { this(new Builder().traceId(parentId == traceId ? parentId : traceId) .parentId(parentId == spanId ? null : parentId) .spanId(spanId) .flags(flags)); } SpanId(Builder builder) { checkNotNull(builder.spanId, "spanId"); this.traceIdHigh = builder.traceIdHigh; this.traceId = builder.traceId != null ? builder.traceId : builder.spanId; this.parentId = builder.nullableParentId != null ? builder.nullableParentId : this.traceId; this.spanId = builder.spanId; this.flags = builder.flags; this.shared = builder.shared; } /** Deserializes this from a big-endian byte array */ public static SpanId fromBytes(byte[] bytes) { checkNotNull(bytes, "bytes"); if (bytes.length != 32 && bytes.length != 40) { throw new IllegalArgumentException("bytes.length " + bytes.length + " != 32 or 40"); } ByteBuffer buffer = ByteBuffer.wrap(bytes); Builder builder = new Builder(); builder.spanId(buffer.getLong(0)); builder.parentId(buffer.getLong(8)); if (bytes.length == 32) { builder.traceId(buffer.getLong(16)); builder.flags(buffer.getLong(24)); } else { builder.traceIdHigh(buffer.getLong(16)); builder.traceId(buffer.getLong(24)); builder.flags(buffer.getLong(32)); } return new SpanId(builder); } public static Builder builder() { return new Builder(); } /** * Get Trace id. * * @return Trace id. * @deprecated use {@link #traceId} */ @Deprecated public long getTraceId() { return traceId; } /** * Get span id. * * @return span id. * @deprecated use {@link #spanId} */ @Deprecated public long getSpanId() { return spanId; } /** * Get parent span id. * * @return Parent span id. Can be null. * @deprecated use {@link #nullableParentId()} */ @Deprecated @Nullable public Long getParentSpanId() { return nullableParentId(); } /** * When non-zero, the trace containing this span uses 128-bit trace identifiers. * * @since 3.15 */ public final long traceIdHigh; /** * Unique 8-byte identifier for a trace, set on all spans within it. */ public final long traceId; /** * The parent's {@link #spanId} or {@link #spanId} if this the root span in a trace. */ public final long parentId; /** Returns null when this is a root span. */ @Nullable public Long nullableParentId() { return root() ? null : parentId; } /** * Unique 8-byte identifier of this span within a trace. * *

A span is uniquely identified in storage by ({@linkplain #traceId}, {@code #id}). */ public final long spanId; /** Returns true if this is the root span. */ public final boolean root() { return (flags & FLAG_IS_ROOT) == FLAG_IS_ROOT || (parentId == traceId && parentId == spanId); } /** * True is a request to store this span even if it overrides sampling policy. Implies {@link * #sampled()}. */ public final boolean debug() { return (flags & FLAG_DEBUG) == FLAG_DEBUG; } /** * Should we sample this request or not? True means sample, false means don't, null means we defer * decision to someone further down in the stack. */ @Nullable public final Boolean sampled() { if (debug()) return true; return (flags & FLAG_SAMPLING_SET) == FLAG_SAMPLING_SET ? (flags & FLAG_SAMPLED) == FLAG_SAMPLED : null; } /** Raw flags encoded in {@link #bytes()} */ public final long flags; /** * True if we are contributing to a span started by another tracer (ex on a different host). * Defaults to false. * *

When an RPC trace is client-originated, it will be sampled and the same span ID is used for * the server side. However, the server shouldn't set span.timestamp or duration since it didn't * start the span. */ public final boolean shared; /** Serializes this into a big-endian byte array */ public byte[] bytes() { boolean traceHi = traceIdHigh != 0; byte[] result = new byte[traceHi ? 40 : 32]; ByteBuffer buffer = ByteBuffer.wrap(result); buffer.putLong(0, spanId); buffer.putLong(8, parentId); if (traceHi) { buffer.putLong(16, traceIdHigh); buffer.putLong(24, traceId); buffer.putLong(32, flags); } else { buffer.putLong(16, traceId); buffer.putLong(24, flags); } return result; } public Builder toBuilder() { return new Builder(this); } /** Returns {@code $traceId.$spanId<:$parentId} */ @Override public String toString() { boolean traceHi = traceIdHigh != 0; char[] result = new char[((traceHi ? 4 : 3) * 16) + 3]; // 3 ids and the constant delimiters int pos = 0; if (traceHi) { writeHexLong(result, pos, traceIdHigh); pos += 16; } writeHexLong(result, pos, traceId); pos += 16; result[pos++] = '.'; writeHexLong(result, pos, spanId); pos += 16; result[pos++] = '<'; result[pos++] = ':'; writeHexLong(result, pos, parentId); return new String(result); } @Override public boolean equals(Object o) { if (o == this) { return true; } if (o instanceof SpanId) { SpanId that = (SpanId) o; return (this.traceIdHigh == that.traceIdHigh) && (this.traceId == that.traceId) && (this.spanId == that.spanId); } return false; } @Override public int hashCode() { int h = 1; h *= 1000003; h ^= (traceIdHigh >>> 32) ^ traceIdHigh; h *= 1000003; h ^= (traceId >>> 32) ^ traceId; h *= 1000003; h ^= (spanId >>> 32) ^ spanId; return h; } /** * Returns the hex representation of the span's trace ID * * @since 3.15 */ public String traceIdString() { if (traceIdHigh != 0) { char[] result = new char[32]; writeHexLong(result, 0, traceIdHigh); writeHexLong(result, 16, traceId); return new String(result); } char[] result = new char[16]; writeHexLong(result, 0, traceId); return new String(result); } public static final class Builder { long traceIdHigh = 0; Long traceId; Long nullableParentId; Long spanId; long flags; boolean shared; Builder(SpanId source) { this.traceIdHigh = source.traceIdHigh; this.traceId = source.traceId; this.nullableParentId = source.nullableParentId(); this.spanId = source.spanId; this.flags = source.flags; this.shared = source.shared; } /** @see SpanId#traceIdHigh */ public Builder traceIdHigh(long traceIdHigh) { this.traceIdHigh = traceIdHigh; return this; } /** @see SpanId#traceId */ public Builder traceId(long traceId) { this.traceId = traceId; return this; } /** * If your trace ids are not span ids, you must call this method to indicate absent parent. * * @see SpanId#nullableParentId() */ public Builder parentId(@Nullable Long parentId) { if (parentId == null) { this.flags |= FLAG_IS_ROOT; } else { this.flags &= ~FLAG_IS_ROOT; } this.nullableParentId = parentId; return this; } /** @see SpanId#spanId */ public Builder spanId(long spanId) { this.spanId = spanId; return this; } /** @see SpanId#flags */ public Builder flags(long flags) { this.flags = flags; return this; } /** @see SpanId#debug() */ public Builder debug(boolean debug) { if (debug) { this.flags |= FLAG_DEBUG; } else { this.flags &= ~FLAG_DEBUG; } return this; } /** @see SpanId#shared */ public Builder shared(boolean shared) { this.shared = shared; return this; } /** @see SpanId#sampled */ public Builder sampled(@Nullable Boolean sampled) { if (sampled != null) { this.flags |= FLAG_SAMPLING_SET; if (sampled) { this.flags |= FLAG_SAMPLED; } else { this.flags &= ~FLAG_SAMPLED; } } else { this.flags &= ~FLAG_SAMPLING_SET; } return this; } public SpanId build() { return new SpanId(this); } Builder() { } } /** Inspired by {@code okio.Buffer.writeLong} */ static void writeHexLong(char[] data, int pos, long v) { writeHexByte(data, pos + 0, (byte) ((v >>> 56L) & 0xff)); writeHexByte(data, pos + 2, (byte) ((v >>> 48L) & 0xff)); writeHexByte(data, pos + 4, (byte) ((v >>> 40L) & 0xff)); writeHexByte(data, pos + 6, (byte) ((v >>> 32L) & 0xff)); writeHexByte(data, pos + 8, (byte) ((v >>> 24L) & 0xff)); writeHexByte(data, pos + 10, (byte) ((v >>> 16L) & 0xff)); writeHexByte(data, pos + 12, (byte) ((v >>> 8L) & 0xff)); writeHexByte(data, pos + 14, (byte) (v & 0xff)); } static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; static void writeHexByte(char[] data, int pos, byte b) { data[pos + 0] = HEX_DIGITS[(b >> 4) & 0xf]; data[pos + 1] = HEX_DIGITS[b & 0xf]; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy