diff --git a/benchmarks/src/main/java/zipkin/benchmarks/SpanBenchmarks.java b/benchmarks/src/main/java/zipkin/benchmarks/SpanBenchmarks.java index e8a46b0f329..a50b552f4cd 100644 --- a/benchmarks/src/main/java/zipkin/benchmarks/SpanBenchmarks.java +++ b/benchmarks/src/main/java/zipkin/benchmarks/SpanBenchmarks.java @@ -34,6 +34,7 @@ import zipkin.Endpoint; import zipkin.Span; import zipkin.TraceKeys; +import zipkin.internal.Span2; import zipkin.internal.Util; @Measurement(iterations = 5, time = 1) @@ -50,9 +51,11 @@ public class SpanBenchmarks { Endpoint.builder().serviceName("app").ipv4(172 << 24 | 17 << 16 | 2).port(8080).build(); final Span.Builder sharedBuilder; + final Span2.Builder shared2Builder; public SpanBenchmarks() { sharedBuilder = buildClientOnlySpan(Span.builder()).toBuilder(); + shared2Builder = buildClientOnlySpan2().toBuilder(); } @Benchmark @@ -104,6 +107,39 @@ public Span buildClientOnlySpan_clear() { return buildClientOnlySpan(sharedBuilder.clear()); } + @Benchmark + public Span2 buildClientOnlySpan2() { + return buildClientOnlySpan2(Span2.builder()); + } + + static Span2 buildClientOnlySpan2(Span2.Builder builder) { + return builder + .traceId(traceId) + .parentId(traceId) + .id(spanId) + .name("get") + .kind(Span2.Kind.CLIENT) + .localEndpoint(frontend) + .remoteEndpoint(backend) + .timestamp(1472470996199000L) + .duration(207000L) + .addAnnotation(1472470996238000L, Constants.WIRE_SEND) + .addAnnotation(1472470996403000L, Constants.WIRE_RECV) + .putTag(TraceKeys.HTTP_PATH, "/api") + .putTag("clnt/finagle.version", "6.45.0") + .build(); + } + + @Benchmark + public Span2 buildClientOnlySpan2_clear() { + return buildClientOnlySpan2(shared2Builder.clear()); + } + + @Benchmark + public Span2 buildClientOnlySpan2_clone() { + return shared2Builder.clone().build(); + } + @Benchmark public Span buildRpcSpan() { return Span.builder() // web calls app diff --git a/zipkin/pom.xml b/zipkin/pom.xml index d00ec557c80..85b13c68738 100644 --- a/zipkin/pom.xml +++ b/zipkin/pom.xml @@ -33,6 +33,12 @@ + + com.google.auto.value + auto-value + provided + + com.google.code.gson gson diff --git a/zipkin/src/main/java/zipkin/internal/Span2.java b/zipkin/src/main/java/zipkin/internal/Span2.java new file mode 100644 index 00000000000..94de3f57c74 --- /dev/null +++ b/zipkin/src/main/java/zipkin/internal/Span2.java @@ -0,0 +1,412 @@ +/** + * Copyright 2015-2017 The OpenZipkin Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package zipkin.internal; + +import com.google.auto.value.AutoValue; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.TreeMap; +import zipkin.Annotation; +import zipkin.Constants; +import zipkin.Endpoint; +import zipkin.Span; +import zipkin.TraceKeys; + +import static zipkin.internal.Util.checkNotNull; +import static zipkin.internal.Util.lowerHexToUnsignedLong; +import static zipkin.internal.Util.sortedList; +import static zipkin.internal.Util.writeHexLong; + +/** + * + * A trace is a series of spans (often RPC calls) which form a latency tree. + * + *

Spans are usually created by instrumentation in RPC clients or servers, but can also + * represent in-process activity. Annotations in spans are similar to log statements, and are + * sometimes created directly by application developers to indicate events of interest, such as a + * cache miss. + * + *

The root span is where {@link #parentId} is null; it usually has the longest {@link #duration} in the + * trace. + * + *

Span identifiers are packed into longs, but should be treated opaquely. ID encoding is + * 16 or 32 character lower-hex, to avoid signed interpretation. * This is a single-host view of a {@link Span}: the primary way tracers record data. + * + *

Relationship to {@link zipkin.Span}

+ *

This type is intended to replace use of {@link zipkin.Span}. Particularly, tracers represent a + * single-host view of an operation. By making one endpoint implicit for all data, this type does not + * need to repeat endpoints on each data like {@link zipkin.Span span} does. This results in simpler + * and smaller data. + */ +@AutoValue +public abstract class Span2 { // TODO: make serializable when needed between stages in Spark jobs + + /** When non-zero, the trace containing this span uses 128-bit trace identifiers. */ + public abstract long traceIdHigh(); + + /** Unique 8-byte identifier for a trace, set on all spans within it. */ + public abstract long traceId(); + + /** The parent's {@link #id} or null if this the root span in a trace. */ + @Nullable public abstract Long parentId(); + + /** + * Unique 8-byte identifier of this span within a trace. + * + *

A span is uniquely identified in storage by ({@linkplain #traceId}, {@linkplain #id()}). + */ + public abstract long id(); + + /** Indicates the primary span type. */ + public enum Kind { + CLIENT, + SERVER + } + + /** When present, used to interpret {@link #remoteEndpoint} */ + @Nullable public abstract Kind kind(); + + /** + * Span name in lowercase, rpc method for example. + * + *

Conventionally, when the span name isn't known, name = "unknown". + */ + @Nullable public abstract String name(); + + /** + * Epoch microseconds of the start of this span, possibly absent if this an incomplete span. + * + *

This value should be set directly by instrumentation, using the most precise value possible. + * For example, {@code gettimeofday} or multiplying {@link System#currentTimeMillis} by 1000. + * + *

There are three known edge-cases where this could be reported absent: + * + *

    + *
  • A span was allocated but never started (ex not yet received a timestamp)
  • + *
  • The span's start event was lost
  • + *
  • Data about a completed span (ex tags) were sent after the fact
  • + *