@@ -137,6 +137,7 @@ public class Span {
137137 private final long begin ;
138138 private long end = 0 ;
139139 private final String name ;
140+ private final long traceIdHigh ;
140141 private final long traceId ;
141142 private List <Long > parents = new ArrayList <>();
142143 private final long spanId ;
@@ -166,6 +167,7 @@ public Span(Span current, Span savedSpan) {
166167 this .begin = current .getBegin ();
167168 this .end = current .getEnd ();
168169 this .name = current .getName ();
170+ this .traceIdHigh = current .getTraceIdHigh ();
169171 this .traceId = current .getTraceId ();
170172 this .parents = current .getParents ();
171173 this .spanId = current .getSpanId ();
@@ -179,36 +181,61 @@ public Span(Span current, Span savedSpan) {
179181 this .savedSpan = savedSpan ;
180182 }
181183
184+ /**
185+ * @deprecated please use {@link SpanBuilder}
186+ */
187+ @ Deprecated
182188 public Span (long begin , long end , String name , long traceId , List <Long > parents ,
183189 long spanId , boolean remote , boolean exportable , String processId ) {
184190 this (begin , end , name , traceId , parents , spanId , remote , exportable , processId ,
185191 null );
186192 }
187193
194+ /**
195+ * @deprecated please use {@link SpanBuilder}
196+ */
197+ @ Deprecated
188198 public Span (long begin , long end , String name , long traceId , List <Long > parents ,
189199 long spanId , boolean remote , boolean exportable , String processId ,
190200 Span savedSpan ) {
191- if (begin > 0 ) { // conventionally, 0 indicates unset
201+ this (new SpanBuilder ()
202+ .begin (begin )
203+ .end (end )
204+ .name (name )
205+ .traceId (traceId )
206+ .parents (parents )
207+ .spanId (spanId )
208+ .remote (remote )
209+ .exportable (exportable )
210+ .processId (processId )
211+ .savedSpan (savedSpan ));
212+ }
213+
214+ Span (SpanBuilder builder ) {
215+ if (builder .begin > 0 ) { // conventionally, 0 indicates unset
192216 this .startNanos = null ; // don't know the start tick
193- this .begin = begin ;
217+ this .begin = builder . begin ;
194218 } else {
195219 this .startNanos = nanoTime ();
196220 this .begin = System .currentTimeMillis ();
197221 }
198- if (end > 0 ) {
199- this .end = end ;
200- this .durationMicros = (end - begin ) * 1000 ;
222+ if (builder . end > 0 ) {
223+ this .end = builder . end ;
224+ this .durationMicros = (this . end - this . begin ) * 1000 ;
201225 }
202- this .name = name != null ? name : "" ;
203- this .traceId = traceId ;
204- this .parents = parents ;
205- this .spanId = spanId ;
206- this .remote = remote ;
207- this .exportable = exportable ;
208- this .processId = processId ;
209- this .savedSpan = savedSpan ;
226+ this .name = builder .name != null ? builder .name : "" ;
227+ this .traceIdHigh = builder .traceIdHigh ;
228+ this .traceId = builder .traceId ;
229+ this .parents .addAll (builder .parents );
230+ this .spanId = builder .spanId ;
231+ this .remote = builder .remote ;
232+ this .exportable = builder .exportable ;
233+ this .processId = builder .processId ;
234+ this .savedSpan = builder .savedSpan ;
210235 this .tags = new ConcurrentHashMap <>();
236+ this .tags .putAll (builder .tags );
211237 this .logs = new ConcurrentLinkedQueue <>();
238+ this .logs .addAll (builder .logs );
212239 }
213240
214241 public static SpanBuilder builder () {
@@ -358,7 +385,30 @@ public long getSpanId() {
358385 }
359386
360387 /**
361- * A pseudo-unique (random) number assigned to the trace associated with this span
388+ * When non-zero, the trace containing this span uses 128-bit trace identifiers.
389+ *
390+ * <p>{@code traceIdHigh} corresponds to the high bits in big-endian format and
391+ * {@link #getTraceId()} corresponds to the low bits.
392+ *
393+ * <p>Ex. to convert the two fields to a 128bit opaque id array, you'd use code like below.
394+ * <pre>{@code
395+ * ByteBuffer traceId128 = ByteBuffer.allocate(16);
396+ * traceId128.putLong(span.getTraceIdHigh());
397+ * traceId128.putLong(span.getTraceId());
398+ * traceBytes = traceId128.array();
399+ * }</pre>
400+ *
401+ * @see #traceIdString()
402+ * @since 1.0.11
403+ */
404+ public long getTraceIdHigh () {
405+ return this .traceIdHigh ;
406+ }
407+
408+ /**
409+ * Unique 8-byte identifier for a trace, set on all spans within it.
410+ *
411+ * @see #getTraceIdHigh() for notes about 128-bit trace identifiers
362412 */
363413 public long getTraceId () {
364414 return this .traceId ;
@@ -413,8 +463,27 @@ public boolean isExportable() {
413463 return this .exportable ;
414464 }
415465
466+ /**
467+ * Returns the 16 or 32 character hex representation of the span's trace ID
468+ *
469+ * @since 1.0.11
470+ */
471+ public String traceIdString () {
472+ if (this .traceIdHigh != 0 ) {
473+ char [] result = new char [32 ];
474+ writeHexLong (result , 0 , this .traceIdHigh );
475+ writeHexLong (result , 16 , this .traceId );
476+ return new String (result );
477+ }
478+ char [] result = new char [16 ];
479+ writeHexLong (result , 0 , this .traceId );
480+ return new String (result );
481+ }
482+
416483 /**
417484 * Represents given long id as 16-character lower-hex string
485+ *
486+ * @see #traceIdString()
418487 */
419488 public static String idToHex (long id ) {
420489 char [] data = new char [16 ];
@@ -449,29 +518,40 @@ static void writeHexByte(char[] data, int pos, byte b) {
449518 public static long hexToId (String hexString ) {
450519 Assert .hasText (hexString , "Can't convert empty hex string to long" );
451520 int length = hexString .length ();
452- if (length < 1 || length > 32 ) throw new IllegalArgumentException ("Malformed id" );
521+ if (length < 1 || length > 32 ) throw new IllegalArgumentException ("Malformed id: " + hexString );
453522
454523 // trim off any high bits
455- int i = length > 16 ? length - 16 : 0 ;
524+ int beginIndex = length > 16 ? length - 16 : 0 ;
525+
526+ return hexToId (hexString , beginIndex );
527+ }
456528
529+ /**
530+ * Parses a 16 character lower-hex string with no prefix into an unsigned long, starting at the
531+ * specified index.
532+ *
533+ * @since 1.0.11
534+ */
535+ public static long hexToId (String lowerHex , int index ) {
536+ Assert .hasText (lowerHex , "Can't convert empty hex string to long" );
457537 long result = 0 ;
458- for (; i < length ; i ++) {
459- char c = hexString .charAt (i );
538+ for (int endIndex = Math . min ( index + 16 , lowerHex . length ()); index < endIndex ; index ++) {
539+ char c = lowerHex .charAt (index );
460540 result <<= 4 ;
461541 if (c >= '0' && c <= '9' ) {
462542 result |= c - '0' ;
463543 } else if (c >= 'a' && c <= 'f' ) {
464544 result |= c - 'a' + 10 ;
465545 } else {
466- throw new IllegalArgumentException ("Malformed id" );
546+ throw new IllegalArgumentException ("Malformed id: " + lowerHex );
467547 }
468548 }
469549 return result ;
470550 }
471551
472552 @ Override
473553 public String toString () {
474- return "[Trace: " + idToHex ( this . traceId ) + ", Span: " + idToHex (this .spanId )
554+ return "[Trace: " + traceIdString ( ) + ", Span: " + idToHex (this .spanId )
475555 + ", Parent: " + getParentIdIfPresent () + ", exportable:" + this .exportable + "]" ;
476556 }
477557
@@ -481,31 +561,36 @@ private String getParentIdIfPresent() {
481561
482562 @ Override
483563 public int hashCode () {
484- final int prime = 31 ;
485- int result = 1 ;
486- result = prime * result + (int ) (this .spanId ^ (this .spanId >>> 32 ));
487- result = prime * result + (int ) (this .traceId ^ (this .traceId >>> 32 ));
488- return result ;
564+ int h = 1 ;
565+ h *= 1000003 ;
566+ h ^= (this .traceIdHigh >>> 32 ) ^ this .traceIdHigh ;
567+ h *= 1000003 ;
568+ h ^= (this .traceId >>> 32 ) ^ this .traceId ;
569+ h *= 1000003 ;
570+ h ^= (this .spanId >>> 32 ) ^ this .spanId ;
571+ h *= 1000003 ;
572+ return h ;
489573 }
490574
491575 @ Override
492- public boolean equals (Object obj ) {
493- if (this == obj )
576+ public boolean equals (Object o ) {
577+ if (o == this ) {
494578 return true ;
495- if ( obj == null )
496- return false ;
497- if ( getClass () != obj . getClass ())
498- return false ;
499- Span other = ( Span ) obj ;
500- if (this .spanId != other .spanId )
501- return false ;
502- return this . traceId == other . traceId ;
579+ }
580+ if ( o instanceof Span ) {
581+ Span that = ( Span ) o ;
582+ return ( this . traceIdHigh == that . traceIdHigh )
583+ && ( this . traceId == that . traceId )
584+ && (this .spanId == that .spanId );
585+ }
586+ return false ;
503587 }
504588
505589 public static class SpanBuilder {
506590 private long begin ;
507591 private long end ;
508592 private String name ;
593+ private long traceIdHigh ;
509594 private long traceId ;
510595 private ArrayList <Long > parents = new ArrayList <>();
511596 private long spanId ;
@@ -541,6 +626,11 @@ public Span.SpanBuilder name(String name) {
541626 return this ;
542627 }
543628
629+ public Span .SpanBuilder traceIdHigh (long traceIdHigh ) {
630+ this .traceIdHigh = traceIdHigh ;
631+ return this ;
632+ }
633+
544634 public Span .SpanBuilder traceId (long traceId ) {
545635 this .traceId = traceId ;
546636 return this ;
@@ -602,22 +692,12 @@ public Span.SpanBuilder savedSpan(Span savedSpan) {
602692 }
603693
604694 public Span build () {
605- Span span = new Span (this .begin , this .end , this .name , this .traceId ,
606- this .parents , this .spanId , this .remote , this .exportable ,
607- this .processId , this .savedSpan );
608- span .logs .addAll (this .logs );
609- span .tags .putAll (this .tags );
610- return span ;
695+ return new Span (this );
611696 }
612697
613698 @ Override
614699 public String toString () {
615- return "SpanBuilder{" + "begin=" + this .begin + ", end=" + this .end
616- + ", name=" + this .name + ", traceId=" + this .traceId + ", parents="
617- + this .parents + ", spanId=" + this .spanId + ", remote=" + this .remote
618- + ", exportable=" + this .exportable + ", processId='" + this .processId
619- + '\'' + ", savedSpan=" + this .savedSpan + ", logs=" + this .logs
620- + ", tags=" + this .tags + '}' ;
700+ return new Span (this ).toString ();
621701 }
622702 }
623703}
0 commit comments