3
3
import java .io .Closeable ;
4
4
import java .io .IOException ;
5
5
import java .util .ArrayList ;
6
+ import java .util .Arrays ;
6
7
import java .util .Collections ;
7
8
import java .util .HashSet ;
8
9
import java .util .List ;
9
10
import java .util .Locale ;
10
11
import java .util .Map ;
11
- import java .util .Objects ;
12
12
import java .util .Set ;
13
13
import java .util .UUID ;
14
14
import java .util .concurrent .Executors ;
17
17
import java .util .concurrent .TimeUnit ;
18
18
import java .util .stream .Collectors ;
19
19
20
- import brave .handler .MutableSpan ;
21
- import brave .handler .SpanHandler ;
22
- import brave .propagation .TraceContext ;
23
20
import com .wavefront .internal .reporter .WavefrontInternalReporter ;
21
+ import com .wavefront .java_sdk .com .google .common .collect .Iterators ;
24
22
import com .wavefront .java_sdk .com .google .common .collect .Sets ;
25
23
import com .wavefront .sdk .common .NamedThreadFactory ;
26
24
import com .wavefront .sdk .common .Pair ;
32
30
import org .apache .commons .logging .Log ;
33
31
import org .apache .commons .logging .LogFactory ;
34
32
33
+ import org .springframework .cloud .sleuth .TraceContext ;
34
+ import org .springframework .cloud .sleuth .exporter .FinishedSpan ;
35
+ import org .springframework .util .StringUtils ;
36
+
35
37
import static com .wavefront .internal .SpanDerivedMetricsUtils .TRACING_DERIVED_PREFIX ;
36
38
import static com .wavefront .internal .SpanDerivedMetricsUtils .reportHeartbeats ;
37
39
import static com .wavefront .internal .SpanDerivedMetricsUtils .reportWavefrontGeneratedData ;
66
68
* {@link UUID#timestamp()} on UUIDs converted here, or in other Wavefront code, as it might
67
69
* throw.
68
70
*/
69
- final class WavefrontSleuthSpanHandler extends SpanHandler implements Runnable , Closeable {
71
+ public final class WavefrontSleuthSpanHandler implements Runnable , Closeable {
70
72
private static final Log LOG = LogFactory .getLog (WavefrontSleuthSpanHandler .class );
71
73
72
74
// 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,
75
77
private final static String DEFAULT_SOURCE = "wavefront-spring-boot" ;
76
78
private final static String WAVEFRONT_GENERATED_COMPONENT = "wavefront-generated" ;
77
79
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 ;
79
95
final WavefrontSender wavefrontSender ;
80
96
final WavefrontInternalReporter wfInternalReporter ;
81
97
final Set <String > traceDerivedCustomTagKeys ;
@@ -144,7 +160,7 @@ final class WavefrontSleuthSpanHandler extends SpanHandler implements Runnable,
144
160
145
161
// Exact same behavior as WavefrontSpanReporter
146
162
// 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 ) {
148
164
spansReceived .increment ();
149
165
if (!spanBuffer .offer (Pair .of (context , span ))) {
150
166
spansDropped .increment ();
@@ -160,31 +176,49 @@ List<Pair<String, String>> getDefaultTags() {
160
176
return Collections .unmodifiableList (this .defaultTags );
161
177
}
162
178
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 ()));
166
199
167
200
// NOTE: wavefront-opentracing-sdk-java and wavefront-proxy differ, but we prefer the former.
168
201
// https://github.com/wavefrontHQ/wavefront-opentracing-sdk-java/blob/f1f08d8daf7b692b9b61dcd5bc24ca6befa8e710/src/main/java/com/wavefront/opentracing/reporting/WavefrontSpanReporter.java#L187-L190
169
202
// https://github.com/wavefrontHQ/wavefront-proxy/blob/3dd1fa11711a04de2d9d418e2269f0f9fb464f36/proxy/src/main/java/com/wavefront/agent/listeners/tracing/ZipkinPortUnificationHandler.java#L248-L252
170
203
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 )));
173
207
}
174
208
List <UUID > followsFrom = null ;
175
209
176
210
// 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 ();
178
212
if (name == null ) name = DEFAULT_SPAN_NAME ;
179
213
180
214
// 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 ;
215
+ long startMillis = span .getStartTimestamp () / 1000L , finishMillis = span .getEndTimestamp () / 1000L ;
182
216
long durationMillis = startMillis != 0 && finishMillis != 0L ? Math .max (finishMillis - startMillis , 1L ) : 0L ;
183
- long durationMicros = span .startTimestamp () != 0L && span .finishTimestamp () != 0L ?
184
- span .finishTimestamp () - span .startTimestamp () : 0 ;
217
+ long durationMicros = span .getStartTimestamp () != 0L && span .getEndTimestamp () != 0L ?
218
+ span .getEndTimestamp () - span .getStartTimestamp () : 0 ;
185
219
186
220
List <SpanLog > spanLogs = convertAnnotationsToSpanLogs (span );
187
- TagList tags = new TagList (defaultTagKeys , defaultTags , context , span );
221
+ TagList tags = new TagList (defaultTagKeys , defaultTags , span );
188
222
189
223
try {
190
224
wavefrontSender .sendSpan (name , startMillis , durationMillis , source , traceId , spanId ,
@@ -213,6 +247,38 @@ private void send(TraceContext context, MutableSpan span) {
213
247
}
214
248
}
215
249
250
+ private static byte [] buildDecodingArray () {
251
+ byte [] decoding = new byte [ASCII_CHARACTERS ];
252
+ Arrays .fill (decoding , (byte ) -1 );
253
+ for (int i = 0 ; i < ALPHABET .length (); i ++) {
254
+ char c = ALPHABET .charAt (i );
255
+ decoding [c ] = (byte ) i ;
256
+ }
257
+ return decoding ;
258
+ }
259
+
260
+ /**
261
+ * Returns the {@code long} value whose base16 representation is stored in the first
262
+ * 16 chars of {@code chars} starting from the {@code offset}.
263
+ * @param chars the base16 representation of the {@code long}.
264
+ */
265
+ private static long longFromBase16String (CharSequence chars ) {
266
+ int offset = 0 ;
267
+ return (decodeByte (chars .charAt (offset ), chars .charAt (offset + 1 )) & 0xFFL ) << 56
268
+ | (decodeByte (chars .charAt (offset + 2 ), chars .charAt (offset + 3 )) & 0xFFL ) << 48
269
+ | (decodeByte (chars .charAt (offset + 4 ), chars .charAt (offset + 5 )) & 0xFFL ) << 40
270
+ | (decodeByte (chars .charAt (offset + 6 ), chars .charAt (offset + 7 )) & 0xFFL ) << 32
271
+ | (decodeByte (chars .charAt (offset + 8 ), chars .charAt (offset + 9 )) & 0xFFL ) << 24
272
+ | (decodeByte (chars .charAt (offset + 10 ), chars .charAt (offset + 11 )) & 0xFFL ) << 16
273
+ | (decodeByte (chars .charAt (offset + 12 ), chars .charAt (offset + 13 )) & 0xFFL ) << 8
274
+ | (decodeByte (chars .charAt (offset + 14 ), chars .charAt (offset + 15 )) & 0xFFL );
275
+ }
276
+
277
+ private static byte decodeByte (char hi , char lo ) {
278
+ int decoded = DECODING [hi ] << 4 | DECODING [lo ];
279
+ return (byte ) decoded ;
280
+ }
281
+
216
282
/**
217
283
* Extracted for test isolation and as parsing otherwise implies multiple-returns or scanning
218
284
* later.
@@ -227,17 +293,20 @@ static final class TagList extends ArrayList<Pair<String, String>> {
227
293
TagList (
228
294
Set <String > defaultTagKeys ,
229
295
List <Pair <String , String >> defaultTags ,
230
- TraceContext context ,
231
- MutableSpan span
296
+ FinishedSpan span
232
297
){
233
- super (defaultTags .size () + span .tagCount ());
234
- boolean debug = context .debug (), hasAnnotations = span .annotationCount () > 0 ;
235
- isError = span .error () != null ;
298
+ super (defaultTags .size () + span .getTags ().size ());
299
+ // TODO: OTel doesn't have a notion of debug
300
+ boolean debug = false ;
301
+ boolean hasAnnotations = span .getEvents ().size () > 0 ;
302
+ isError = span .getError () != null ;
236
303
237
- int tagCount = span .tagCount ();
304
+ int tagCount = span .getTags (). size ();
238
305
addAll (defaultTags );
239
306
for (int i = 0 ; i < tagCount ; i ++) {
240
- String key = span .tagKeyAt (i ), value = span .tagValueAt (i );
307
+ String tagKey = Iterators .get (span .getTags ().keySet ().iterator (), i );
308
+ String tagValue = Iterators .get (span .getTags ().values ().iterator (), i );
309
+ String key = tagKey , value = tagValue ;
241
310
String lcKey = key .toLowerCase (Locale .ROOT );
242
311
if (lcKey .equals (ERROR_TAG_KEY )) {
243
312
isError = true ;
@@ -262,8 +331,8 @@ static final class TagList extends ArrayList<Pair<String, String>> {
262
331
if (debug ) add (Pair .of (DEBUG_TAG_KEY , "true" ));
263
332
264
333
// https://github.com/wavefrontHQ/wavefront-proxy/blob/3dd1fa11711a04de2d9d418e2269f0f9fb464f36/proxy/src/main/java/com/wavefront/agent/listeners/tracing/ZipkinPortUnificationHandler.java#L254-L266
265
- if (span .kind () != null ) {
266
- String kind = span .kind ().toString ().toLowerCase ();
334
+ if (span .getKind () != null ) {
335
+ String kind = span .getKind ().toString ().toLowerCase ();
267
336
add (Pair .of ("span.kind" , kind ));
268
337
if (hasAnnotations ) {
269
338
add (Pair .of ("_spanSecondaryId" , kind ));
@@ -274,20 +343,21 @@ static final class TagList extends ArrayList<Pair<String, String>> {
274
343
if (hasAnnotations ) add (Pair .of (SPAN_LOG_KEY , "true" ));
275
344
276
345
// https://github.com/wavefrontHQ/wavefront-proxy/blob/3dd1fa11711a04de2d9d418e2269f0f9fb464f36/proxy/src/main/java/com/wavefront/agent/listeners/tracing/ZipkinPortUnificationHandler.java#L324-L327
277
- if (span .localIp () != null ) {
278
- add (Pair .of ("ipv4" , span .localIp ())); // NOTE: this could be IPv6!!
346
+ if (span .getLocalIp () != null ) {
347
+ add (Pair .of ("ipv4" , span .getLocalIp ())); // NOTE: this could be IPv6!!
279
348
}
280
349
}
281
350
}
282
351
283
352
// https://github.com/wavefrontHQ/wavefront-proxy/blob/3dd1fa11711a04de2d9d418e2269f0f9fb464f36/proxy/src/main/java/com/wavefront/agent/listeners/tracing/ZipkinPortUnificationHandler.java#L397-L402
284
- static List <SpanLog > convertAnnotationsToSpanLogs (MutableSpan span ) {
285
- int annotationCount = span .annotationCount ();
353
+ static List <SpanLog > convertAnnotationsToSpanLogs (FinishedSpan span ) {
354
+ int annotationCount = span .getEvents (). size ();
286
355
if (annotationCount == 0 ) return Collections .emptyList ();
287
356
List <SpanLog > spanLogs = new ArrayList <>(annotationCount );
288
357
for (int i = 0 ; i < annotationCount ; i ++) {
289
- long epochMicros = span .annotationTimestampAt (i );
290
- String value = span .annotationValueAt (i );
358
+ Map .Entry <Long , String > entry = Iterators .get (span .getEvents ().iterator (), i );
359
+ long epochMicros = entry .getKey ();
360
+ String value = entry .getValue ();
291
361
spanLogs .add (new SpanLog (epochMicros , Collections .singletonMap ("annotation" , value )));
292
362
}
293
363
return spanLogs ;
@@ -296,7 +366,7 @@ static List<SpanLog> convertAnnotationsToSpanLogs(MutableSpan span) {
296
366
@ Override public void run () {
297
367
while (!stop ) {
298
368
try {
299
- Pair <TraceContext , MutableSpan > contextAndSpan = spanBuffer .take ();
369
+ Pair <TraceContext , FinishedSpan > contextAndSpan = spanBuffer .take ();
300
370
send (contextAndSpan ._1 , contextAndSpan ._2 );
301
371
} catch (InterruptedException ex ) {
302
372
if (LOG .isInfoEnabled ()) {
0 commit comments