Skip to content
This repository was archived by the owner on Aug 6, 2024. It is now read-only.

Commit 5d0414f

Browse files
committed
Merge branch '2.2.x'
2 parents 830722f + 02bb7b9 commit 5d0414f

File tree

4 files changed

+172
-58
lines changed

4 files changed

+172
-58
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.wavefront.spring.autoconfigure;
2+
3+
import java.io.Closeable;
4+
import java.io.IOException;
5+
6+
import brave.handler.MutableSpan;
7+
import brave.handler.SpanHandler;
8+
import brave.propagation.TraceContext;
9+
10+
import org.springframework.cloud.sleuth.brave.bridge.BraveFinishedSpan;
11+
import org.springframework.cloud.sleuth.brave.bridge.BraveTraceContext;
12+
13+
class WavefrontSleuthBraveSpanHandler extends SpanHandler implements Runnable, Closeable {
14+
15+
final WavefrontSleuthSpanHandler spanHandler;
16+
17+
WavefrontSleuthBraveSpanHandler(WavefrontSleuthSpanHandler spanHandler) {
18+
this.spanHandler = spanHandler;
19+
}
20+
21+
@Override
22+
public boolean end(TraceContext context, MutableSpan span, Cause cause) {
23+
return spanHandler.end(BraveTraceContext.fromBrave(context), BraveFinishedSpan.fromBrave(span));
24+
}
25+
26+
@Override
27+
public void close() throws IOException {
28+
this.spanHandler.close();
29+
}
30+
31+
@Override
32+
public void run() {
33+
this.spanHandler.run();
34+
}
35+
}

wavefront-spring-boot/src/main/java/com/wavefront/spring/autoconfigure/WavefrontSleuthSpanHandler.java

Lines changed: 103 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
import java.io.Closeable;
44
import java.io.IOException;
55
import java.util.ArrayList;
6+
import java.util.Arrays;
67
import java.util.Collections;
78
import java.util.HashSet;
89
import java.util.List;
910
import java.util.Locale;
1011
import java.util.Map;
11-
import java.util.Objects;
1212
import java.util.Set;
1313
import java.util.UUID;
1414
import java.util.concurrent.Executors;
@@ -17,10 +17,8 @@
1717
import java.util.concurrent.TimeUnit;
1818
import java.util.stream.Collectors;
1919

20-
import brave.handler.MutableSpan;
21-
import brave.handler.SpanHandler;
22-
import brave.propagation.TraceContext;
2320
import com.wavefront.internal.reporter.WavefrontInternalReporter;
21+
import com.wavefront.java_sdk.com.google.common.collect.Iterators;
2422
import com.wavefront.java_sdk.com.google.common.collect.Sets;
2523
import com.wavefront.sdk.common.NamedThreadFactory;
2624
import com.wavefront.sdk.common.Pair;
@@ -32,6 +30,10 @@
3230
import org.apache.commons.logging.Log;
3331
import 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+
3537
import static com.wavefront.internal.SpanDerivedMetricsUtils.TRACING_DERIVED_PREFIX;
3638
import static com.wavefront.internal.SpanDerivedMetricsUtils.reportHeartbeats;
3739
import static com.wavefront.internal.SpanDerivedMetricsUtils.reportWavefrontGeneratedData;
@@ -66,7 +68,7 @@
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,31 +176,49 @@ 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;
215+
long startMillis = span.getStartTimestamp() / 1000L, finishMillis = span.getEndTimestamp() / 1000L;
182216
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;
185219

186220
List<SpanLog> spanLogs = convertAnnotationsToSpanLogs(span);
187-
TagList tags = new TagList(defaultTagKeys, defaultTags, context, span);
221+
TagList tags = new TagList(defaultTagKeys, defaultTags, span);
188222

189223
try {
190224
wavefrontSender.sendSpan(name, startMillis, durationMillis, source, traceId, spanId,
@@ -213,6 +247,38 @@ private void send(TraceContext context, MutableSpan span) {
213247
}
214248
}
215249

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+
216282
/**
217283
* Extracted for test isolation and as parsing otherwise implies multiple-returns or scanning
218284
* later.
@@ -227,17 +293,20 @@ static final class TagList extends ArrayList<Pair<String, String>> {
227293
TagList(
228294
Set<String> defaultTagKeys,
229295
List<Pair<String, String>> defaultTags,
230-
TraceContext context,
231-
MutableSpan span
296+
FinishedSpan span
232297
){
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;
236303

237-
int tagCount = span.tagCount();
304+
int tagCount = span.getTags().size();
238305
addAll(defaultTags);
239306
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;
241310
String lcKey = key.toLowerCase(Locale.ROOT);
242311
if (lcKey.equals(ERROR_TAG_KEY)) {
243312
isError = true;
@@ -262,8 +331,8 @@ static final class TagList extends ArrayList<Pair<String, String>> {
262331
if (debug) add(Pair.of(DEBUG_TAG_KEY, "true"));
263332

264333
// 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();
267336
add(Pair.of("span.kind", kind));
268337
if (hasAnnotations) {
269338
add(Pair.of("_spanSecondaryId", kind));
@@ -274,20 +343,21 @@ static final class TagList extends ArrayList<Pair<String, String>> {
274343
if (hasAnnotations) add(Pair.of(SPAN_LOG_KEY, "true"));
275344

276345
// 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!!
279348
}
280349
}
281350
}
282351

283352
// 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();
286355
if (annotationCount == 0) return Collections.emptyList();
287356
List<SpanLog> spanLogs = new ArrayList<>(annotationCount);
288357
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();
291361
spanLogs.add(new SpanLog(epochMicros, Collections.singletonMap("annotation", value)));
292362
}
293363
return spanLogs;
@@ -296,7 +366,7 @@ static List<SpanLog> convertAnnotationsToSpanLogs(MutableSpan span) {
296366
@Override public void run() {
297367
while (!stop) {
298368
try {
299-
Pair<TraceContext, MutableSpan> contextAndSpan = spanBuffer.take();
369+
Pair<TraceContext, FinishedSpan> contextAndSpan = spanBuffer.take();
300370
send(contextAndSpan._1, contextAndSpan._2);
301371
} catch (InterruptedException ex) {
302372
if (LOG.isInfoEnabled()) {
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.wavefront.spring.autoconfigure;
22

3+
import brave.Tracer;
34
import brave.TracingCustomizer;
45
import brave.handler.SpanHandler;
56
import com.wavefront.sdk.common.WavefrontSender;
@@ -23,30 +24,37 @@
2324
* @author Stephane Nicoll
2425
*/
2526
@Configuration(proxyBeanMethods = false)
26-
@ConditionalOnClass({ SpanNamer.class, TracingCustomizer.class, SpanHandler.class })
27+
@ConditionalOnClass({ SpanNamer.class, MeterRegistry.class, WavefrontConfig.class, WavefrontSender.class })
2728
@AutoConfigureBefore(BraveAutoConfiguration.class)
2829
class WavefrontTracingSleuthConfiguration {
2930

3031
static final String BEAN_NAME = "wavefrontTracingCustomizer";
3132

32-
@Bean(BEAN_NAME)
33-
@ConditionalOnMissingBean(name = BEAN_NAME)
33+
@Bean
3434
@ConditionalOnBean({ MeterRegistry.class, WavefrontConfig.class, WavefrontSender.class })
35-
TracingCustomizer wavefrontTracingCustomizer(MeterRegistry meterRegistry,
36-
WavefrontSender wavefrontSender,
37-
ApplicationTags applicationTags,
38-
WavefrontConfig wavefrontConfig,
39-
WavefrontProperties wavefrontProperties) {
40-
WavefrontSleuthSpanHandler spanHandler = new WavefrontSleuthSpanHandler(
41-
// https://github.com/wavefrontHQ/wavefront-opentracing-sdk-java/blob/f1f08d8daf7b692b9b61dcd5bc24ca6befa8e710/src/main/java/com/wavefront/opentracing/reporting/WavefrontSpanReporter.java#L54
42-
50000, // TODO: maxQueueSize should be a property, ya?
43-
wavefrontSender,
44-
meterRegistry,
45-
wavefrontConfig.source(),
46-
applicationTags,
47-
wavefrontProperties);
48-
49-
return t -> t.traceId128Bit(true).supportsJoin(false).addSpanHandler(spanHandler);
35+
WavefrontSleuthSpanHandler wavefrontSleuthSpanHandler(MeterRegistry meterRegistry,
36+
WavefrontSender wavefrontSender,
37+
ApplicationTags applicationTags,
38+
WavefrontConfig wavefrontConfig,
39+
WavefrontProperties wavefrontProperties) {
40+
return new WavefrontSleuthSpanHandler(
41+
// https://github.com/wavefrontHQ/wavefront-opentracing-sdk-java/blob/f1f08d8daf7b692b9b61dcd5bc24ca6befa8e710/src/main/java/com/wavefront/opentracing/reporting/WavefrontSpanReporter.java#L54
42+
50000, // TODO: maxQueueSize should be a property, ya?
43+
wavefrontSender,
44+
meterRegistry,
45+
wavefrontConfig.source(),
46+
applicationTags,
47+
wavefrontProperties);
5048
}
5149

50+
@Configuration(proxyBeanMethods = false)
51+
@ConditionalOnClass({Tracer.class, TracingCustomizer.class, SpanHandler.class })
52+
static class BraveCustomizerConfiguration {
53+
@Bean(BEAN_NAME)
54+
@ConditionalOnMissingBean(name = BEAN_NAME)
55+
@ConditionalOnBean({ MeterRegistry.class, WavefrontConfig.class, WavefrontSender.class })
56+
TracingCustomizer wavefrontTracingCustomizer(WavefrontSleuthSpanHandler spanHandler) {
57+
return t -> t.traceId128Bit(true).supportsJoin(false).addSpanHandler(new WavefrontSleuthBraveSpanHandler(spanHandler));
58+
}
59+
}
5260
}

wavefront-spring-boot/src/test/java/com/wavefront/spring/autoconfigure/WavefrontAutoConfigurationTests.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,8 @@ void tracingWithSleuthIsConfiguredWithWavefrontSender() {
182182
.with(sleuth())
183183
.run((context) -> {
184184
assertThat(context).hasSingleBean(TracingCustomizer.class);
185-
WavefrontSleuthSpanHandler spanHandler = extractSpanHandler(context.getBean(Tracer.class));
186-
assertThat(spanHandler).hasFieldOrPropertyWithValue("wavefrontSender", sender);
185+
WavefrontSleuthBraveSpanHandler braveSpanHandler = extractSpanHandler(context.getBean(Tracer.class));
186+
assertThat(braveSpanHandler.spanHandler).hasFieldOrPropertyWithValue("wavefrontSender", sender);
187187
});
188188
}
189189

@@ -247,8 +247,8 @@ private ContextConsumer<AssertableApplicationContext> assertSleuthSpanDefaultTag
247247
String serviceName, String cluster, String shard) {
248248
return (context) -> {
249249
assertThat(context).hasSingleBean(TracingCustomizer.class);
250-
WavefrontSleuthSpanHandler spanHandler = extractSpanHandler(context.getBean(Tracer.class));
251-
assertThat(spanHandler.getDefaultTags()).contains(
250+
WavefrontSleuthBraveSpanHandler braveSpanHandler = extractSpanHandler(context.getBean(Tracer.class));
251+
assertThat(braveSpanHandler.spanHandler.getDefaultTags()).contains(
252252
new Pair<>("application", applicationName),
253253
new Pair<>("service", serviceName),
254254
new Pair<>("cluster", cluster),
@@ -266,7 +266,8 @@ void tracingWithSleuthCanBeConfigured() {
266266
.with(sleuth())
267267
.run((context) -> {
268268
assertThat(context).hasSingleBean(TracingCustomizer.class);
269-
WavefrontSleuthSpanHandler spanHandler = extractSpanHandler(context.getBean(Tracer.class));
269+
WavefrontSleuthBraveSpanHandler braveSpanHandler = extractSpanHandler(context.getBean(Tracer.class));
270+
WavefrontSleuthSpanHandler spanHandler = braveSpanHandler.spanHandler;
270271
Set<String> traceDerivedCustomTagKeys = (Set<String>) ReflectionTestUtils.getField(
271272
spanHandler, "traceDerivedCustomTagKeys");
272273
assertThat(traceDerivedCustomTagKeys).containsExactlyInAnyOrder("region", "test");
@@ -392,12 +393,12 @@ void tracingIsNotConfiguredWithNonWavefrontRegistry() {
392393
}
393394

394395
@SuppressWarnings("ConstantConditions")
395-
private WavefrontSleuthSpanHandler extractSpanHandler(Tracer tracer) {
396+
private WavefrontSleuthBraveSpanHandler extractSpanHandler(Tracer tracer) {
396397
SpanHandler[] handlers = (SpanHandler[]) ReflectionTestUtils.getField(
397398
ReflectionTestUtils.getField(
398399
ReflectionTestUtils.getField(tracer, "spanHandler"), "delegate"),
399400
"handlers");
400-
return (WavefrontSleuthSpanHandler) handlers[1];
401+
return (WavefrontSleuthBraveSpanHandler) handlers[1];
401402
}
402403

403404
@SuppressWarnings("unchecked")

0 commit comments

Comments
 (0)