Skip to content
This repository was archived by the owner on May 4, 2019. It is now read-only.

Commit 60ea8d7

Browse files
More efficient zipkin traces streaming (#16)
* efficient zipkin traces streaming * VizceralBridge: use new tracing tags, fix tests
1 parent a7711dd commit 60ea8d7

File tree

10 files changed

+877
-1045
lines changed

10 files changed

+877
-1045
lines changed

tracing-openzipkin/src/main/java/io/netifi/proteus/tracing/TracesStreamer.java

Lines changed: 47 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
99
import com.fasterxml.jackson.databind.module.SimpleDeserializers;
1010
import com.hubspot.jackson.datatype.protobuf.ProtobufModule;
11+
import io.netty.handler.codec.json.JsonObjectDecoder;
12+
import org.reactivestreams.Publisher;
1113
import reactor.core.Exceptions;
1214
import reactor.core.publisher.Flux;
1315
import reactor.core.publisher.Mono;
@@ -22,49 +24,64 @@
2224
public class TracesStreamer {
2325

2426
private final ObjectMapper objectMapper = protoMapper();
25-
private Function<Integer, Mono<InputStream>> inputSource;
27+
private Function<Integer, Publisher<InputStream>> inputSource;
2628

2729
public TracesStreamer(String zipkinUrl,
2830
Mono<HttpClient> client) {
29-
this.inputSource = zipkinServerStream(zipkinUrl, client);
31+
this(zipkinServerStream(zipkinUrl, client));
3032
}
3133

32-
public TracesStreamer(Mono<InputStream> inputSource) {
33-
this.inputSource = v -> inputSource;
34+
public TracesStreamer(Publisher<InputStream> tracesSource) {
35+
this(v -> tracesSource);
36+
}
37+
38+
private TracesStreamer(Function<Integer, Publisher<InputStream>> inputSource) {
39+
this.inputSource = inputSource;
3440
}
3541

3642
public Flux<Trace> streamTraces(int lookbackSeconds) {
3743
return streamTraces(inputSource.apply(lookbackSeconds));
3844
}
3945

40-
Flux<Trace> streamTraces(Mono<InputStream> input) {
41-
return input.map(is -> {
42-
try {
43-
return objectMapper.<Traces>readValue(
44-
is,
45-
new TypeReference<Traces>() {
46-
});
47-
} catch (IOException e) {
48-
throw Exceptions.propagate(e);
49-
}
50-
}).flatMapIterable(Traces::getTracesList)
51-
;
46+
Flux<Trace> streamTraces(Publisher<InputStream> input) {
47+
return Flux.from(input)
48+
.filter(is -> {
49+
try {
50+
return is.available() > 0;
51+
} catch (IOException e) {
52+
throw Exceptions.propagate(e);
53+
}
54+
})
55+
.map(is -> {
56+
try {
57+
return objectMapper.readValue(
58+
is,
59+
new TypeReference<Trace>() {
60+
});
61+
} catch (IOException e) {
62+
throw Exceptions.propagate(e);
63+
}
64+
});
5265
}
5366

54-
private static Function<Integer, Mono<InputStream>> zipkinServerStream(String zipkinUrl,
55-
Mono<HttpClient> client) {
67+
private static Function<Integer, Publisher<InputStream>> zipkinServerStream(String zipkinUrl,
68+
Mono<HttpClient> client) {
5669
return lookbackSeconds -> client
57-
.flatMap(c -> c
58-
.get(zipkinQuery(zipkinUrl, lookbackSeconds))
59-
.flatMap(resp ->
70+
.flatMapMany(c -> c
71+
.get(
72+
zipkinQuery(zipkinUrl, lookbackSeconds),
73+
req -> {
74+
req.context().addHandler(new JsonObjectDecoder(true));
75+
return Mono.empty();
76+
})
77+
.flatMapMany(resp ->
6078
resp.receive()
61-
.aggregate()
6279
.asInputStream()));
6380
}
6481

6582
private static String zipkinQuery(String zipkinUrl, int lookbackSeconds) {
66-
long lookbackMicros = TimeUnit.SECONDS.toMillis(lookbackSeconds);
67-
return zipkinUrl + "?lookback=" + lookbackMicros + "&limit=100000";
83+
long lookbackMillis = TimeUnit.SECONDS.toMillis(lookbackSeconds);
84+
return zipkinUrl + "?lookback=" + lookbackMillis + "&limit=100000";
6885
}
6986

7087
private ObjectMapper protoMapper() {
@@ -79,12 +96,12 @@ public static class CustomProtoModule extends ProtobufModule {
7996
public void setupModule(SetupContext context) {
8097
super.setupModule(context);
8198
SimpleDeserializers deser = new SimpleDeserializers();
82-
deser.addDeserializer(Traces.class, new TracersDeserializer());
99+
deser.addDeserializer(Trace.class, new TracersDeserializer());
83100
context.addDeserializers(deser);
84101
}
85102
}
86103

87-
public static class TracersDeserializer extends StdDeserializer<Traces> {
104+
public static class TracersDeserializer extends StdDeserializer<Trace> {
88105

89106
public TracersDeserializer() {
90107
this(null);
@@ -95,26 +112,12 @@ protected TracersDeserializer(Class<?> vc) {
95112
}
96113

97114
@Override
98-
public Traces deserialize(JsonParser p,
99-
DeserializationContext ctxt) throws IOException {
100-
p.nextToken();
101-
Traces.Builder tracesBuilder = Traces.newBuilder();
102-
while (p.currentToken() != JsonToken.END_ARRAY) {
103-
tracesBuilder.addTraces(nextTrace(p, ctxt));
104-
}
105-
p.nextToken();
106-
return tracesBuilder.build();
107-
}
108-
109-
private Trace nextTrace(JsonParser p,
110-
DeserializationContext ctxt) throws IOException {
115+
public Trace deserialize(JsonParser p,
116+
DeserializationContext ctx) throws IOException {
111117
Trace.Builder traceBuilder = Trace.newBuilder();
112-
p.nextToken();
113-
while (p.currentToken() != JsonToken.END_ARRAY) {
114-
traceBuilder.addSpans(ctxt.readValue(p, Span.class));
115-
p.nextToken();
118+
while (p.nextToken() != JsonToken.END_ARRAY) {
119+
traceBuilder.addSpans(ctx.readValue(p, Span.class));
116120
}
117-
p.nextToken();
118121
return traceBuilder.build();
119122
}
120123
}
Lines changed: 69 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,93 @@
11
package io.netifi.proteus.tracing;
22

3+
import io.netty.channel.ChannelOption;
34
import org.junit.Assert;
4-
import org.junit.Before;
5+
import org.junit.Ignore;
56
import org.junit.Test;
7+
import reactor.core.publisher.Flux;
68
import reactor.core.publisher.Mono;
9+
import reactor.ipc.netty.http.client.HttpClient;
10+
import reactor.ipc.netty.resources.PoolResources;
711

12+
import java.io.ByteArrayInputStream;
813
import java.io.InputStream;
14+
import java.nio.charset.Charset;
15+
import java.nio.charset.StandardCharsets;
916
import java.time.Duration;
1017
import java.util.List;
18+
import java.util.Scanner;
19+
import java.util.concurrent.TimeUnit;
1120

1221
public class ZipkinTracesStreamerTest {
1322

14-
private TracesStreamer tracesStreamer;
23+
private static final int COUNT = 42;
1524

16-
@Before
17-
public void setUp() {
18-
tracesStreamer = new TracesStreamer(zipkinSource());
25+
@Test
26+
public void zipkinServerTracesStreaming() {
27+
TracesStreamer tracesStreamer = new TracesStreamer(zipkinSource(COUNT));
28+
List<Trace> traces = tracesStreamer
29+
.streamTraces(42)
30+
.collectList()
31+
.block(Duration.ofSeconds(10));
32+
Assert.assertEquals(COUNT, traces.size());
1933
}
2034

2135
@Test
22-
public void zipkinServerTracesStreaming() {
36+
public void emptyResponse() {
37+
TracesStreamer tracesStreamer = new TracesStreamer(emptySource());
2338
List<Trace> traces = tracesStreamer
2439
.streamTraces(42)
2540
.collectList()
2641
.block(Duration.ofSeconds(10));
27-
Assert.assertFalse(traces.isEmpty());
42+
Assert.assertTrue(traces.isEmpty());
43+
}
44+
45+
private Flux<InputStream> zipkinSource(int count) {
46+
return Mono.fromCallable(() -> {
47+
try (InputStream trace =
48+
getClass()
49+
.getClassLoader()
50+
.getResourceAsStream("zipkin_trace.json")) {
51+
Charset utf8 = StandardCharsets.UTF_8;
52+
try (java.util.Scanner s = new Scanner(trace, utf8.name())) {
53+
return s.useDelimiter("\\A").hasNext() ? s.next() : "";
54+
}
55+
}
56+
}).flatMapMany(trace ->
57+
Flux.range(1, count)
58+
.map(v -> trace)
59+
.map(this::asInputStream));
60+
}
61+
62+
private InputStream asInputStream(String s) {
63+
return new ByteArrayInputStream(s.getBytes(StandardCharsets.UTF_8));
64+
}
65+
66+
private Flux<InputStream> emptySource() {
67+
return Flux.just(asInputStream(""));
68+
}
69+
70+
@Ignore("requires local zipkin server")
71+
@Test
72+
public void streamerIntegrationTest() {
73+
TracesStreamer streamer = new TracesStreamer("/api/v2/traces",
74+
client());
75+
Flux<Trace> traces = streamer.streamTraces((int) TimeUnit.SECONDS.toSeconds(10));
76+
List<Trace> tracesList = traces.collectList().block();
77+
Assert.assertFalse(tracesList.isEmpty());
2878
}
2979

30-
private Mono<InputStream> zipkinSource() {
31-
return Mono.fromCallable(() ->
32-
getClass().getClassLoader().getResourceAsStream("zipkin.json"));
80+
private Mono<HttpClient> client() {
81+
return Mono.just(HttpClient.builder()
82+
.options(
83+
builder ->
84+
builder
85+
.compression(true)
86+
.poolResources(PoolResources.fixed("proteusZipkinBridge"))
87+
.option(ChannelOption.SO_KEEPALIVE, true)
88+
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 30_000)
89+
.host("127.0.0.1")
90+
.port(9411))
91+
.build());
3392
}
3493
}

0 commit comments

Comments
 (0)