Skip to content
This repository has been archived by the owner on Jul 1, 2022. It is now read-only.

Commit

Permalink
Fixes #495 : support for 128 bits trace ids. (#507)
Browse files Browse the repository at this point in the history
Added environment variable JAEGER_TRACEID_128BIT
Added withTraceId128Bit method to Configuration
Added withTraceId128Bit method to Tracer.Builder
Added useTraceId128Bit property to Tracer

Signed-off-by: JACQUES Francois <[email protected]>
  • Loading branch information
hypnoce authored and jpkrohling committed Oct 15, 2018
1 parent 6ee913a commit 88a8497
Show file tree
Hide file tree
Showing 24 changed files with 482 additions and 94 deletions.
15 changes: 15 additions & 0 deletions jaeger-core/src/main/java/io/jaegertracing/Configuration.java
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,11 @@ public class Configuration {
*/
public static final String JAEGER_SENDER_FACTORY = JAEGER_PREFIX + "SENDER_FACTORY";

/**
* Opt-in to use 128 bit traceIds. By default, uses 64 bits.
*/
public static final String JAEGER_TRACEID_128BIT = JAEGER_PREFIX + "TRACEID_128BIT";

/**
* The supported trace context propagation formats.
*/
Expand All @@ -172,6 +177,7 @@ public enum Propagation {
private CodecConfiguration codecConfig;
private MetricsFactory metricsFactory;
private Map<String, String> tracerTags;
private boolean useTraceId128Bit;

/**
* lazy singleton JaegerTracer initialized in getTracer() method.
Expand All @@ -193,6 +199,7 @@ public static Configuration fromEnv() {
public static Configuration fromEnv(String serviceName) {
return new Configuration(serviceName)
.withTracerTags(tracerTagsFromEnv())
.withTraceId128Bit(getPropertyAsBool(JAEGER_TRACEID_128BIT))
.withReporter(ReporterConfiguration.fromEnv())
.withSampler(SamplerConfiguration.fromEnv())
.withCodec(CodecConfiguration.fromEnv());
Expand All @@ -219,6 +226,9 @@ public JaegerTracer.Builder getTracerBuilder() {
.withReporter(reporter)
.withMetrics(metrics)
.withTags(tracerTags);
if (useTraceId128Bit) {
builder = builder.withTraceId128Bit();
}
codecConfig.apply(builder);
return builder;
}
Expand Down Expand Up @@ -285,6 +295,11 @@ public Configuration withCodec(CodecConfiguration codecConfig) {
return this;
}

public Configuration withTraceId128Bit(boolean useTraceId128Bit) {
this.useTraceId128Bit = useTraceId128Bit;
return this;
}

public Configuration withTracerTags(Map<String, String> tracerTags) {
if (tracerTags != null) {
this.tracerTags = new HashMap<String, String>(tracerTags);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,14 @@ public JaegerSpan createSpan(
}

public JaegerSpanContext createSpanContext(
long traceId,
long traceIdHigh,
long traceIdLow,
long spanId,
long parentId,
byte flags,
Map<String, String> baggage,
String debugId) {
return new JaegerSpanContext(traceId, spanId, parentId, flags, baggage, debugId, this);
return new JaegerSpanContext(traceIdHigh, traceIdLow, spanId, parentId, flags, baggage, debugId, this);
}

public JaegerTracer.SpanBuilder createSpanBuilder(JaegerTracer tracer, String operationName) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import io.jaegertracing.internal.propagation.TextMapCodec;
import io.opentracing.SpanContext;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
Expand All @@ -25,17 +26,19 @@ public class JaegerSpanContext implements SpanContext {
protected static final byte flagSampled = 1;
protected static final byte flagDebug = 2;

private final long traceId;
private final long traceIdLow;
private final long traceIdHigh;
private final long spanId;
private final long parentId;
private final byte flags;
private final Map<String, String> baggage;
private final String debugId;
private final JaegerObjectFactory objectFactory;

public JaegerSpanContext(long traceId, long spanId, long parentId, byte flags) {
public JaegerSpanContext(long traceIdHigh, long traceIdLow, long spanId, long parentId, byte flags) {
this(
traceId,
traceIdHigh,
traceIdLow,
spanId,
parentId,
flags,
Expand All @@ -45,7 +48,8 @@ public JaegerSpanContext(long traceId, long spanId, long parentId, byte flags) {
}

protected JaegerSpanContext(
long traceId,
long traceIdHigh,
long traceIdLow,
long spanId,
long parentId,
byte flags,
Expand All @@ -55,7 +59,8 @@ protected JaegerSpanContext(
if (baggage == null) {
baggage = Collections.<String, String>emptyMap();
}
this.traceId = traceId;
this.traceIdLow = traceIdLow;
this.traceIdHigh = traceIdHigh;
this.spanId = spanId;
this.parentId = parentId;
this.flags = flags;
Expand All @@ -77,8 +82,27 @@ Map<String, String> baggage() {
return this.baggage;
}

public long getTraceId() {
return traceId;
public String getTraceId() {
if (traceIdHigh == 0L) {
return Long.toHexString(traceIdLow);
}
final String hexStringHigh = Long.toHexString(traceIdHigh);
final String hexStringLow = Long.toHexString(traceIdLow);
if (hexStringLow.length() < 16) {
// left pad low trace id with '0'.
// In theory, only 12.5% of all possible long values will be padded.
// In practice, using Random.nextLong(), only 6% will need padding
return hexStringHigh + "0000000000000000".substring(hexStringLow.length()) + hexStringLow;
}
return hexStringHigh + hexStringLow;
}

public long getTraceIdLow() {
return traceIdLow;
}

public long getTraceIdHigh() {
return traceIdHigh;
}

public long getSpanId() {
Expand Down Expand Up @@ -113,15 +137,15 @@ public JaegerSpanContext withBaggageItem(String key, String val) {
} else {
newBaggage.put(key, val);
}
return objectFactory.createSpanContext(traceId, spanId, parentId, flags, newBaggage, debugId);
return objectFactory.createSpanContext(traceIdHigh, traceIdLow, spanId, parentId, flags, newBaggage, debugId);
}

public JaegerSpanContext withBaggage(Map<String, String> newBaggage) {
return objectFactory.createSpanContext(traceId, spanId, parentId, flags, newBaggage, debugId);
return objectFactory.createSpanContext(traceIdHigh, traceIdLow, spanId, parentId, flags, newBaggage, debugId);
}

public JaegerSpanContext withFlags(byte flags) {
return objectFactory.createSpanContext(traceId, spanId, parentId, flags, baggage, debugId);
return objectFactory.createSpanContext(traceIdHigh, traceIdLow, spanId, parentId, flags, baggage, debugId);
}

/**
Expand All @@ -133,7 +157,7 @@ public JaegerSpanContext withFlags(byte flags) {
* @see Constants#BAGGAGE_HEADER_KEY
*/
boolean hasTrace() {
return traceId != 0 && spanId != 0;
return (traceIdLow != 0 || traceIdHigh != 0) && spanId != 0;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ public class JaegerTracer implements Tracer, Closeable {
private final Map<String, ?> tags;
private final boolean zipkinSharedRpcSpan;
private final boolean expandExceptionLogs;
private final boolean useTraceId128Bit;

@ToString.Exclude private final PropagationRegistry registry;
@ToString.Exclude private final Clock clock;
Expand All @@ -89,6 +90,7 @@ protected JaegerTracer(JaegerTracer.Builder builder) {
this.baggageSetter = new BaggageSetter(builder.baggageRestrictionManager, metrics);
this.expandExceptionLogs = builder.expandExceptionLogs;
this.objectFactory = builder.objectFactory;
this.useTraceId128Bit = builder.useTraceId128Bit;

this.version = loadVersion();

Expand Down Expand Up @@ -299,7 +301,9 @@ public JaegerTracer.SpanBuilder withStartTimestamp(long microseconds) {

private JaegerSpanContext createNewContext() {
String debugId = getDebugId();
long id = Utils.uniqueId();
long spanId = Utils.uniqueId();
long traceIdLow = spanId;
long traceIdHigh = isUseTraceId128Bit() ? Utils.uniqueId() : 0;

byte flags = 0;
if (debugId != null) {
Expand All @@ -308,7 +312,7 @@ private JaegerSpanContext createNewContext() {
metrics.traceStartedSampled.inc(1);
} else {
// TODO: (prithvi) Don't assume operationName is set on creation
SamplingStatus samplingStatus = sampler.sample(operationName, id);
SamplingStatus samplingStatus = sampler.sample(operationName, spanId);
if (samplingStatus.isSampled()) {
flags |= JaegerSpanContext.flagSampled;
tags.putAll(samplingStatus.getTags());
Expand All @@ -319,8 +323,9 @@ private JaegerSpanContext createNewContext() {
}

return getObjectFactory().createSpanContext(
id,
id,
traceIdHigh,
traceIdLow,
spanId,
0,
flags,
getBaggage(),
Expand Down Expand Up @@ -364,7 +369,8 @@ private JaegerSpanContext createChildContext() {
}

return getObjectFactory().createSpanContext(
preferredReference.getTraceId(),
preferredReference.getTraceIdHigh(),
preferredReference.getTraceIdLow(),
Utils.uniqueId(),
preferredReference.getSpanId(),
// should we do OR across passed references?
Expand Down Expand Up @@ -490,6 +496,7 @@ public static class Builder {
private BaggageRestrictionManager baggageRestrictionManager = new DefaultBaggageRestrictionManager();
private boolean expandExceptionLogs;
private final JaegerObjectFactory objectFactory;
private boolean useTraceId128Bit;

public Builder(String serviceName) {
this(serviceName, new JaegerObjectFactory());
Expand Down Expand Up @@ -577,6 +584,11 @@ public Builder withMetrics(Metrics metrics) {
return this;
}

public Builder withTraceId128Bit() {
this.useTraceId128Bit = true;
return this;
}

public Builder withTag(String key, String value) {
tags.put(key, value);
return this;
Expand Down Expand Up @@ -670,4 +682,8 @@ JaegerSpanContext setBaggage(JaegerSpan jaegerSpan, String key, String value) {
boolean isExpandExceptionLogs() {
return this.expandExceptionLogs;
}

public boolean isUseTraceId128Bit() {
return this.useTraceId128Bit;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright (c) 2018, The Jaeger Authors
*
* 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 io.jaegertracing.internal.exceptions;

public class TraceIdOutOfBoundException extends RuntimeException {

private static final long serialVersionUID = 2332452744805504972L;

public TraceIdOutOfBoundException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ private B3TextMapCodec(Builder builder) {

@Override
public void inject(JaegerSpanContext spanContext, TextMap carrier) {
carrier.put(TRACE_ID_NAME, HexCodec.toLowerHex(spanContext.getTraceId()));
carrier.put(TRACE_ID_NAME, // Use HexCode instead of getTraceId to ensure zipkin compatibility
HexCodec.toLowerHex(spanContext.getTraceIdHigh(), spanContext.getTraceIdLow()));
if (spanContext.getParentId() != 0L) { // Conventionally, parent id == 0 means the root span
carrier.put(PARENT_SPAN_ID_NAME, HexCodec.toLowerHex(spanContext.getParentId()));
}
Expand All @@ -93,7 +94,8 @@ public void inject(JaegerSpanContext spanContext, TextMap carrier) {

@Override
public JaegerSpanContext extract(TextMap carrier) {
Long traceId = null;
Long traceIdLow = null;
Long traceIdHigh = 0L; // It's enough to check for a null low trace id
Long spanId = null;
Long parentId = 0L; // Conventionally, parent id == 0 means the root span
byte flags = 0;
Expand All @@ -105,7 +107,8 @@ public JaegerSpanContext extract(TextMap carrier) {
flags |= SAMPLED_FLAG;
}
} else if (entry.getKey().equalsIgnoreCase(TRACE_ID_NAME)) {
traceId = HexCodec.lowerHexToUnsignedLong(entry.getValue());
traceIdLow = HexCodec.lowerHexToUnsignedLong(entry.getValue());
traceIdHigh = HexCodec.higherHexToUnsignedLong(entry.getValue());
} else if (entry.getKey().equalsIgnoreCase(PARENT_SPAN_ID_NAME)) {
parentId = HexCodec.lowerHexToUnsignedLong(entry.getValue());
} else if (entry.getKey().equalsIgnoreCase(SPAN_ID_NAME)) {
Expand All @@ -122,9 +125,10 @@ public JaegerSpanContext extract(TextMap carrier) {
}
}

if (null != traceId && null != parentId && null != spanId) {
if (null != traceIdLow && null != parentId && null != spanId) {
JaegerSpanContext spanContext = objectFactory.createSpanContext(
traceId,
traceIdHigh,
traceIdLow,
spanId,
parentId,
flags,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@

package io.jaegertracing.internal.propagation;

import lombok.extern.slf4j.Slf4j;

// copy/pasted from brave.internal.HexCodec 4.1.1 to avoid build complexity
@Slf4j
final class HexCodec {

/**
Expand All @@ -26,13 +29,30 @@ final class HexCodec {
static Long lowerHexToUnsignedLong(String lowerHex) {
int length = lowerHex.length();
if (length < 1 || length > 32) {
log.debug("token {} size is out of bounds [1, 32]", lowerHex);
return null;
}

// trim off any high bits
int beginIndex = length > 16 ? length - 16 : 0;

return lowerHexToUnsignedLong(lowerHex, beginIndex);
return hexToUnsignedLong(lowerHex, beginIndex, Math.min(beginIndex + 16, lowerHex.length()));
}

/**
* Parses a 1 to 32 character higher-hex string with no prefix into an unsigned long, tossing any
* bits lower than 64.
*
* @return a 64 bit long, meaning that negative values are the overflow of Java's 32 bit long
*/
static Long higherHexToUnsignedLong(String higherHex) {
int length = higherHex.length();
if (length > 32 || length < 1) {
log.debug("token {} size is out of bounds [1, 32]", higherHex);
return null;
}

return hexToUnsignedLong(higherHex, 0, Math.max(length - 16, 0));
}

/**
Expand All @@ -41,9 +61,9 @@ static Long lowerHexToUnsignedLong(String lowerHex) {
*
* @return a 64 bit long, meaning that negative values are the overflow of Java's 32 bit long
*/
static Long lowerHexToUnsignedLong(String lowerHex, int index) {
static Long hexToUnsignedLong(String lowerHex, int index, int endIndex) {
long result = 0;
for (int endIndex = Math.min(index + 16, lowerHex.length()); index < endIndex; index++) {
for (; index < endIndex; index++) {
char c = lowerHex.charAt(index);
result <<= 4;
if (c >= '0' && c <= '9') {
Expand Down
Loading

0 comments on commit 88a8497

Please sign in to comment.