33import java .io .Closeable ;
44import java .io .IOException ;
55import java .util .ArrayList ;
6+ import java .util .Arrays ;
67import java .util .Collections ;
78import java .util .HashSet ;
89import java .util .List ;
910import java .util .Locale ;
1011import java .util .Map ;
11- import java .util .Objects ;
1212import java .util .Set ;
1313import java .util .UUID ;
1414import java .util .concurrent .Executors ;
1717import java .util .concurrent .TimeUnit ;
1818import java .util .stream .Collectors ;
1919
20- import brave .handler .MutableSpan ;
21- import brave .handler .SpanHandler ;
22- import brave .propagation .TraceContext ;
2320import com .wavefront .internal .reporter .WavefrontInternalReporter ;
21+ import com .wavefront .java_sdk .com .google .common .collect .Iterators ;
2422import com .wavefront .java_sdk .com .google .common .collect .Sets ;
2523import com .wavefront .sdk .common .NamedThreadFactory ;
2624import com .wavefront .sdk .common .Pair ;
3230import org .apache .commons .logging .Log ;
3331import org .apache .commons .logging .LogFactory ;
3432
33+ import org .springframework .cloud .sleuth .TraceContext ;
34+ import org .springframework .cloud .sleuth .exporter .FinishedSpan ;
35+ import org .springframework .util .StringUtils ;
36+
3537import static com .wavefront .internal .SpanDerivedMetricsUtils .TRACING_DERIVED_PREFIX ;
3638import static com .wavefront .internal .SpanDerivedMetricsUtils .reportHeartbeats ;
3739import static com .wavefront .internal .SpanDerivedMetricsUtils .reportWavefrontGeneratedData ;
6668 * {@link UUID#timestamp()} on UUIDs converted here, or in other Wavefront code, as it might
6769 * throw.
6870 */
69- final class WavefrontSleuthSpanHandler extends SpanHandler implements Runnable , Closeable {
71+ public final class WavefrontSleuthSpanHandler implements Runnable , Closeable {
7072 private static final Log LOG = LogFactory .getLog (WavefrontSleuthSpanHandler .class );
7173
7274 // https://github.com/wavefrontHQ/wavefront-proxy/blob/3dd1fa11711a04de2d9d418e2269f0f9fb464f36/proxy/src/main/java/com/wavefront/agent/listeners/tracing/ZipkinPortUnificationHandler.java#L114-L114
@@ -75,7 +77,21 @@ final class WavefrontSleuthSpanHandler extends SpanHandler implements Runnable,
7577 private final static String DEFAULT_SOURCE = "wavefront-spring-boot" ;
7678 private final static String WAVEFRONT_GENERATED_COMPONENT = "wavefront-generated" ;
7779
78- final LinkedBlockingQueue <Pair <TraceContext , MutableSpan >> spanBuffer ;
80+ private static final int LONG_BYTES = Long .SIZE / Byte .SIZE ;
81+
82+ private static final int BYTE_BASE16 = 2 ;
83+
84+ private static final int LONG_BASE16 = BYTE_BASE16 * LONG_BYTES ;
85+
86+ private static final int TRACE_ID_HEX_SIZE = 2 * LONG_BASE16 ;
87+
88+ private static final String ALPHABET = "0123456789abcdef" ;
89+
90+ private static final int ASCII_CHARACTERS = 128 ;
91+
92+ private static final byte [] DECODING = buildDecodingArray ();
93+
94+ final LinkedBlockingQueue <Pair <TraceContext , FinishedSpan >> spanBuffer ;
7995 final WavefrontSender wavefrontSender ;
8096 final WavefrontInternalReporter wfInternalReporter ;
8197 final Set <String > traceDerivedCustomTagKeys ;
@@ -144,7 +160,7 @@ final class WavefrontSleuthSpanHandler extends SpanHandler implements Runnable,
144160
145161 // Exact same behavior as WavefrontSpanReporter
146162 // https://github.com/wavefrontHQ/wavefront-opentracing-sdk-java/blob/f1f08d8daf7b692b9b61dcd5bc24ca6befa8e710/src/main/java/com/wavefront/opentracing/reporting/WavefrontSpanReporter.java#L163-L179
147- @ Override public boolean end (TraceContext context , MutableSpan span , Cause cause ) {
163+ public boolean end (TraceContext context , FinishedSpan span ) {
148164 spansReceived .increment ();
149165 if (!spanBuffer .offer (Pair .of (context , span ))) {
150166 spansDropped .increment ();
@@ -160,30 +176,48 @@ List<Pair<String, String>> getDefaultTags() {
160176 return Collections .unmodifiableList (this .defaultTags );
161177 }
162178
163- private void send (TraceContext context , MutableSpan span ) {
164- UUID traceId = new UUID (context .traceIdHigh (), context .traceId ());
165- UUID spanId = new UUID (0L , context .spanId ());
179+ private String padLeftWithZeros (String string , int length ) {
180+ if (string .length () >= length ) {
181+ return string ;
182+ }
183+ else {
184+ StringBuilder sb = new StringBuilder (length );
185+ for (int i = string .length (); i < length ; i ++) {
186+ sb .append ('0' );
187+ }
188+
189+ return sb .append (string ).toString ();
190+ }
191+ }
192+
193+ private void send (TraceContext context , FinishedSpan span ) {
194+ String traceIdString = padLeftWithZeros (context .traceId (), TRACE_ID_HEX_SIZE );
195+ String traceIdHigh = traceIdString .substring (0 , traceIdString .length () / 2 );
196+ String traceIdLow = traceIdString .substring (traceIdString .length () / 2 );
197+ UUID traceId = new UUID (longFromBase16String (traceIdHigh ), longFromBase16String (traceIdLow ));
198+ UUID spanId = new UUID (0L , longFromBase16String (context .spanId ()));
166199
167200 // NOTE: wavefront-opentracing-sdk-java and wavefront-proxy differ, but we prefer the former.
168201 // https://github.com/wavefrontHQ/wavefront-opentracing-sdk-java/blob/f1f08d8daf7b692b9b61dcd5bc24ca6befa8e710/src/main/java/com/wavefront/opentracing/reporting/WavefrontSpanReporter.java#L187-L190
169202 // https://github.com/wavefrontHQ/wavefront-proxy/blob/3dd1fa11711a04de2d9d418e2269f0f9fb464f36/proxy/src/main/java/com/wavefront/agent/listeners/tracing/ZipkinPortUnificationHandler.java#L248-L252
170203 List <UUID > parents = null ;
171- if (context .parentIdAsLong () != 0L ) {
172- parents = Collections .singletonList (new UUID (0L , context .parentIdAsLong ()));
204+ String parentId = context .parentId ();
205+ if (StringUtils .hasText (parentId ) && longFromBase16String (parentId ) != 0L ) {
206+ parents = Collections .singletonList (new UUID (0L , longFromBase16String (parentId )));
173207 }
174208 List <UUID > followsFrom = null ;
175209
176210 // https://github.com/wavefrontHQ/wavefront-proxy/blob/3dd1fa11711a04de2d9d418e2269f0f9fb464f36/proxy/src/main/java/com/wavefront/agent/listeners/tracing/ZipkinPortUnificationHandler.java#L344-L345
177- String name = span .name ();
211+ String name = span .getName ();
178212 if (name == null ) name = DEFAULT_SPAN_NAME ;
179213
180214 // Start and duration become 0L if unset. Any positive duration rounds up to 1 millis.
181- long startMillis = span .startTimestamp () / 1000L , finishMillis = span .finishTimestamp () / 1000L ;
182- long durationMicros = span .finishTimestamp () - span .startTimestamp ();
215+ long startMillis = span .getStartTimestamp () / 1000L , finishMillis = span .getEndTimestamp () / 1000L ;
216+ long durationMicros = span .getEndTimestamp () - span .getStartTimestamp ();
183217 long durationMillis = startMillis != 0 && finishMillis != 0L ? Math .max (finishMillis - startMillis , 1L ) : 0L ;
184218
185219 List <SpanLog > spanLogs = convertAnnotationsToSpanLogs (span );
186- TagList tags = new TagList (defaultTagKeys , defaultTags , context , span );
220+ TagList tags = new TagList (defaultTagKeys , defaultTags , span );
187221
188222 try {
189223 wavefrontSender .sendSpan (name , startMillis , durationMillis , source , traceId , spanId ,
@@ -212,6 +246,38 @@ private void send(TraceContext context, MutableSpan span) {
212246 }
213247 }
214248
249+ private static byte [] buildDecodingArray () {
250+ byte [] decoding = new byte [ASCII_CHARACTERS ];
251+ Arrays .fill (decoding , (byte ) -1 );
252+ for (int i = 0 ; i < ALPHABET .length (); i ++) {
253+ char c = ALPHABET .charAt (i );
254+ decoding [c ] = (byte ) i ;
255+ }
256+ return decoding ;
257+ }
258+
259+ /**
260+ * Returns the {@code long} value whose base16 representation is stored in the first
261+ * 16 chars of {@code chars} starting from the {@code offset}.
262+ * @param chars the base16 representation of the {@code long}.
263+ */
264+ private static long longFromBase16String (CharSequence chars ) {
265+ int offset = 0 ;
266+ return (decodeByte (chars .charAt (offset ), chars .charAt (offset + 1 )) & 0xFFL ) << 56
267+ | (decodeByte (chars .charAt (offset + 2 ), chars .charAt (offset + 3 )) & 0xFFL ) << 48
268+ | (decodeByte (chars .charAt (offset + 4 ), chars .charAt (offset + 5 )) & 0xFFL ) << 40
269+ | (decodeByte (chars .charAt (offset + 6 ), chars .charAt (offset + 7 )) & 0xFFL ) << 32
270+ | (decodeByte (chars .charAt (offset + 8 ), chars .charAt (offset + 9 )) & 0xFFL ) << 24
271+ | (decodeByte (chars .charAt (offset + 10 ), chars .charAt (offset + 11 )) & 0xFFL ) << 16
272+ | (decodeByte (chars .charAt (offset + 12 ), chars .charAt (offset + 13 )) & 0xFFL ) << 8
273+ | (decodeByte (chars .charAt (offset + 14 ), chars .charAt (offset + 15 )) & 0xFFL );
274+ }
275+
276+ private static byte decodeByte (char hi , char lo ) {
277+ int decoded = DECODING [hi ] << 4 | DECODING [lo ];
278+ return (byte ) decoded ;
279+ }
280+
215281 /**
216282 * Extracted for test isolation and as parsing otherwise implies multiple-returns or scanning
217283 * later.
@@ -225,18 +291,20 @@ static final class TagList extends ArrayList<Pair<String, String>> {
225291
226292 TagList (
227293 Set <String > defaultTagKeys ,
228- List <Pair <String , String >> defaultTags ,
229- TraceContext context ,
230- MutableSpan span
294+ List <Pair <String , String >> defaultTags ,FinishedSpan span
231295 ){
232- super (defaultTags .size () + span .tagCount ());
233- boolean debug = context .debug (), hasAnnotations = span .annotationCount () > 0 ;
234- isError = span .error () != null ;
296+ super (defaultTags .size () + span .getTags ().size ());
297+ // TODO: OTel doesn't have a notion of debug
298+ boolean debug = false ;
299+ boolean hasAnnotations = span .getEvents ().size () > 0 ;
300+ isError = span .getError () != null ;
235301
236- int tagCount = span .tagCount ();
302+ int tagCount = span .getTags (). size ();
237303 addAll (defaultTags );
238304 for (int i = 0 ; i < tagCount ; i ++) {
239- String key = span .tagKeyAt (i ), value = span .tagValueAt (i );
305+ String tagKey = Iterators .get (span .getTags ().keySet ().iterator (), i );
306+ String tagValue = Iterators .get (span .getTags ().values ().iterator (), i );
307+ String key = tagKey , value = tagValue ;
240308 String lcKey = key .toLowerCase (Locale .ROOT );
241309 if (lcKey .equals (ERROR_TAG_KEY )) {
242310 isError = true ;
@@ -261,8 +329,8 @@ static final class TagList extends ArrayList<Pair<String, String>> {
261329 if (debug ) add (Pair .of (DEBUG_TAG_KEY , "true" ));
262330
263331 // https://github.com/wavefrontHQ/wavefront-proxy/blob/3dd1fa11711a04de2d9d418e2269f0f9fb464f36/proxy/src/main/java/com/wavefront/agent/listeners/tracing/ZipkinPortUnificationHandler.java#L254-L266
264- if (span .kind () != null ) {
265- String kind = span .kind ().toString ().toLowerCase ();
332+ if (span .getKind () != null ) {
333+ String kind = span .getKind ().toString ().toLowerCase ();
266334 add (Pair .of ("span.kind" , kind ));
267335 if (hasAnnotations ) {
268336 add (Pair .of ("_spanSecondaryId" , kind ));
@@ -273,20 +341,21 @@ static final class TagList extends ArrayList<Pair<String, String>> {
273341 if (hasAnnotations ) add (Pair .of (SPAN_LOG_KEY , "true" ));
274342
275343 // https://github.com/wavefrontHQ/wavefront-proxy/blob/3dd1fa11711a04de2d9d418e2269f0f9fb464f36/proxy/src/main/java/com/wavefront/agent/listeners/tracing/ZipkinPortUnificationHandler.java#L324-L327
276- if (span .localIp () != null ) {
277- add (Pair .of ("ipv4" , span .localIp ())); // NOTE: this could be IPv6!!
344+ if (span .getLocalIp () != null ) {
345+ add (Pair .of ("ipv4" , span .getLocalIp ())); // NOTE: this could be IPv6!!
278346 }
279347 }
280348 }
281349
282350 // https://github.com/wavefrontHQ/wavefront-proxy/blob/3dd1fa11711a04de2d9d418e2269f0f9fb464f36/proxy/src/main/java/com/wavefront/agent/listeners/tracing/ZipkinPortUnificationHandler.java#L397-L402
283- static List <SpanLog > convertAnnotationsToSpanLogs (MutableSpan span ) {
284- int annotationCount = span .annotationCount ();
351+ static List <SpanLog > convertAnnotationsToSpanLogs (FinishedSpan span ) {
352+ int annotationCount = span .getEvents (). size ();
285353 if (annotationCount == 0 ) return Collections .emptyList ();
286354 List <SpanLog > spanLogs = new ArrayList <>(annotationCount );
287355 for (int i = 0 ; i < annotationCount ; i ++) {
288- long epochMicros = span .annotationTimestampAt (i );
289- String value = span .annotationValueAt (i );
356+ Map .Entry <Long , String > entry = Iterators .get (span .getEvents ().iterator (), i );
357+ long epochMicros = entry .getKey ();
358+ String value = entry .getValue ();
290359 spanLogs .add (new SpanLog (epochMicros , Collections .singletonMap ("annotation" , value )));
291360 }
292361 return spanLogs ;
@@ -295,7 +364,7 @@ static List<SpanLog> convertAnnotationsToSpanLogs(MutableSpan span) {
295364 @ Override public void run () {
296365 while (!stop ) {
297366 try {
298- Pair <TraceContext , MutableSpan > contextAndSpan = spanBuffer .take ();
367+ Pair <TraceContext , FinishedSpan > contextAndSpan = spanBuffer .take ();
299368 send (contextAndSpan ._1 , contextAndSpan ._2 );
300369 } catch (InterruptedException ex ) {
301370 if (LOG .isInfoEnabled ()) {
0 commit comments