Skip to content

Commit 58f5b96

Browse files
author
Adrian Cole
committed
Adds zipkin.internal.Span2Codec.JSON
This adds an internal copy of a span json codec issue #1499. This starts internal to ease review and allow incremental progress. The first consumer will be Elasticsearch, as this format removes nested queries. Note: this change also introduces json serialization of Span2, which allows future use in Spark.
1 parent f9fcf15 commit 58f5b96

File tree

8 files changed

+696
-19
lines changed

8 files changed

+696
-19
lines changed

benchmarks/src/main/java/zipkin/benchmarks/CodecBenchmarks.java

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
import zipkin.Codec;
4242
import zipkin.Endpoint;
4343
import zipkin.Span;
44+
import zipkin.internal.Span2;
45+
import zipkin.internal.Span2Codec;
4446

4547
/**
4648
* This compares the speed of the bundled java codec with the approach used in the scala
@@ -154,6 +156,31 @@ public byte[] writeClientSpan_thrift_libthrift() throws TException {
154156
return serialize(clientSpanLibThrift);
155157
}
156158

159+
static final byte[] span2Json = read("/span2.json");
160+
static final Span2 span2 = Span2Codec.JSON.readSpan(span2Json);
161+
static final List<Span2> tenClientSpan2s = Collections.nCopies(10, span2);
162+
static final byte[] tenClientSpan2sJson = Span2Codec.JSON.writeSpans(tenClientSpan2s);
163+
164+
@Benchmark
165+
public Span2 readClientSpan_json_span2() {
166+
return Span2Codec.JSON.readSpan(span2Json);
167+
}
168+
169+
@Benchmark
170+
public List<Span2> readTenClientSpans_json_span2() {
171+
return Span2Codec.JSON.readSpans(tenClientSpan2sJson);
172+
}
173+
174+
@Benchmark
175+
public byte[] writeClientSpan_json_span2() {
176+
return Span2Codec.JSON.writeSpan(span2);
177+
}
178+
179+
@Benchmark
180+
public byte[] writeTenClientSpans_json_span2() {
181+
return Span2Codec.JSON.writeSpans(tenClientSpan2s);
182+
}
183+
157184
static final byte[] rpcSpanJson = read("/span-rpc.json");
158185
static final Span rpcSpan = Codec.JSON.readSpan(rpcSpanJson);
159186
static final byte[] rpcSpanThrift = Codec.THRIFT.writeSpan(rpcSpan);
@@ -227,7 +254,7 @@ public byte[] writeRpcV6Span_thrift_libthrift() throws TException {
227254
// Convenience main entry-point
228255
public static void main(String[] args) throws RunnerException {
229256
Options opt = new OptionsBuilder()
230-
.include(".*" + CodecBenchmarks.class.getSimpleName() + ".*lientSpan.*")
257+
.include(".*" + CodecBenchmarks.class.getSimpleName())
231258
.build();
232259

233260
new Runner(opt).run();

benchmarks/src/main/resources/span-client.json

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -40,25 +40,16 @@
4040
}
4141
],
4242
"binaryAnnotations": [
43-
{
44-
"key": "ca",
45-
"value": true,
46-
"endpoint": {
47-
"serviceName": "frontend",
48-
"ipv4": "127.0.0.1",
49-
"port": 49504
50-
}
51-
},
5243
{
5344
"key": "clnt/finagle.version",
54-
"value": "6.36.0",
45+
"value": "6.45.0",
5546
"endpoint": {
5647
"serviceName": "frontend",
5748
"ipv4": "127.0.0.1"
5849
}
5950
},
6051
{
61-
"key": "http.uri",
52+
"key": "http.path",
6253
"value": "/api",
6354
"endpoint": {
6455
"serviceName": "frontend",
@@ -70,10 +61,9 @@
7061
"value": true,
7162
"endpoint": {
7263
"serviceName": "backend",
73-
"ipv4": "127.0.0.1",
64+
"ipv4": "192.168.99.101",
7465
"port": 9000
7566
}
7667
}
77-
],
78-
"debug": false
68+
]
7969
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"traceId": "86154a4ba6e91385",
3+
"parentId": "86154a4ba6e91385",
4+
"id": "4d1e00c0db9010db",
5+
"kind": "CLIENT",
6+
"name": "get",
7+
"timestamp": 1472470996199000,
8+
"duration": 207000,
9+
"localEndpoint": {
10+
"serviceName": "frontend",
11+
"ipv4": "127.0.0.1"
12+
},
13+
"remoteEndpoint": {
14+
"serviceName": "backend",
15+
"ipv4": "192.168.99.101",
16+
"port": 9000
17+
},
18+
"annotations": [
19+
{
20+
"timestamp": 1472470996238000,
21+
"value": "ws"
22+
},
23+
{
24+
"timestamp": 1472470996403000,
25+
"value": "wr"
26+
}
27+
],
28+
"tags": {
29+
"http.path": "/api",
30+
"clnt/finagle.version": "6.45.0"
31+
}
32+
}

zipkin/src/main/java/zipkin/internal/Span2.java

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
package zipkin.internal;
1515

1616
import com.google.auto.value.AutoValue;
17+
import java.io.ObjectStreamException;
18+
import java.io.Serializable;
19+
import java.io.StreamCorruptedException;
1720
import java.util.ArrayList;
1821
import java.util.Collections;
1922
import java.util.LinkedHashMap;
@@ -27,6 +30,7 @@
2730
import zipkin.Span;
2831
import zipkin.TraceKeys;
2932

33+
import static zipkin.internal.Util.UTF_8;
3034
import static zipkin.internal.Util.checkNotNull;
3135
import static zipkin.internal.Util.lowerHexToUnsignedLong;
3236
import static zipkin.internal.Util.sortedList;
@@ -54,7 +58,8 @@
5458
* and smaller data.
5559
*/
5660
@AutoValue
57-
public abstract class Span2 { // TODO: make serializable when needed between stages in Spark jobs
61+
public abstract class Span2 implements Serializable { // for Spark jobs
62+
private static final long serialVersionUID = 0L;
5863

5964
/** When non-zero, the trace containing this span uses 128-bit trace identifiers. */
6065
public abstract long traceIdHigh();
@@ -409,4 +414,33 @@ public Span2 build() {
409414
);
410415
}
411416
}
417+
418+
@Override
419+
public String toString() {
420+
return new String(Span2Codec.JSON.writeSpan(this), UTF_8);
421+
}
422+
423+
// Since this is an immutable object, and we have json handy, defer to a serialization proxy.
424+
final Object writeReplace() throws ObjectStreamException {
425+
return new SerializedForm(Span2Codec.JSON.writeSpan(this));
426+
}
427+
428+
static final class SerializedForm implements Serializable {
429+
private static final long serialVersionUID = 0L;
430+
431+
private final byte[] bytes;
432+
433+
SerializedForm(byte[] bytes) {
434+
this.bytes = bytes;
435+
}
436+
437+
Object readResolve() throws ObjectStreamException {
438+
try {
439+
return Span2Codec.JSON.readSpan(bytes);
440+
} catch (IllegalArgumentException e) {
441+
e.printStackTrace();
442+
throw new StreamCorruptedException(e.getMessage());
443+
}
444+
}
445+
}
412446
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* Copyright 2015-2017 The OpenZipkin Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5+
* in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License
10+
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11+
* or implied. See the License for the specific language governing permissions and limitations under
12+
* the License.
13+
*/
14+
package zipkin.internal;
15+
16+
import java.util.List;
17+
18+
/** Utilities for working with {@link Span2} */
19+
public interface Span2Codec {
20+
Span2Codec JSON = new Span2JsonCodec();
21+
22+
/** Serialize a span recorded from instrumentation into its binary form. */
23+
byte[] writeSpan(Span2 span);
24+
25+
/** Serialize a list of spans recorded from instrumentation into their binary form. */
26+
byte[] writeSpans(List<Span2> spans);
27+
28+
/** throws {@linkplain IllegalArgumentException} if a span couldn't be decoded */
29+
Span2 readSpan(byte[] bytes);
30+
31+
/** throws {@linkplain IllegalArgumentException} if the spans couldn't be decoded */
32+
List<Span2> readSpans(byte[] bytes);
33+
}

0 commit comments

Comments
 (0)