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: 3.9.1
Show newest version
package com.github.kristofa.brave;

import com.github.kristofa.brave.internal.Nullable;
import com.twitter.zipkin.gen.Span;
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}. */ 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.traceId = (parentId == traceId) ? parentId : traceId; this.parentId = (parentId == spanId) ? traceId : parentId; this.spanId = spanId; this.flags = flags; } /** Deserializes this from a big-endian byte array */ public static SpanId fromBytes(byte[] bytes) { checkNotNull(bytes, "bytes"); if (bytes.length != 32) { throw new IllegalArgumentException("bytes.length " + bytes.length + " != 32"); } ByteBuffer buffer = ByteBuffer.wrap(bytes); long spanId = buffer.getLong(0); long parentId = buffer.getLong(8); long traceId = buffer.getLong(16); long flags = buffer.getLong(24); return new SpanId(traceId, parentId, spanId, flags); } 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(); } /** * 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; /** Serializes this into a big-endian byte array */ public byte[] bytes() { byte[] result = new byte[32]; ByteBuffer buffer = ByteBuffer.wrap(result); buffer.putLong(0, spanId); buffer.putLong(8, parentId); 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() { char[] result = new char[(3 * 16) + 3]; // 3 ids and the constant delimiters writeHexLong(result, 0, traceId); result[16] = '.'; writeHexLong(result, 17, spanId); result[33] = '<'; result[34] = ':'; writeHexLong(result, 35, 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.traceId == that.traceId) && (this.parentId == that.parentId) && (this.spanId == that.spanId); } return false; } @Override public int hashCode() { int h = 1; h *= 1000003; h ^= (traceId >>> 32) ^ traceId; h *= 1000003; h ^= (parentId >>> 32) ^ parentId; h *= 1000003; h ^= (spanId >>> 32) ^ spanId; return h; } /** Preferred way to create spans, as it properly deals with the parent id */ public Span toSpan() { Span result = new Span(); result.setId(spanId); result.setTrace_id(traceId); result.setParent_id(nullableParentId()); result.setName(""); // avoid NPE on equals if (debug()) result.setDebug(debug()); return result; } public static final class Builder { Long traceId; Long parentId; Long spanId; long flags; Builder() { } Builder(SpanId source) { this.traceId = source.traceId; this.parentId = source.nullableParentId(); this.spanId = source.spanId; this.flags = source.flags; } /** @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.parentId = 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#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() { long traceId = this.traceId != null ? this.traceId : checkNotNull(spanId, "spanId"); long parentId = this.parentId != null ? this.parentId : traceId; return new SpanId(traceId, parentId, checkNotNull(spanId, "spanId"), flags); } } /** 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 - 2025 Weber Informatics LLC | Privacy Policy