From 53fb14051cefa2ff77e66a3ec43f7d8886933269 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Fri, 15 Jan 2016 16:47:45 +0800 Subject: [PATCH 1/6] Adds initial interfaces based on api-go This is mostly a port from python, except for a couple notes. * Adds an IllegalArgumentException to `fromXXX`, if the input is malformed. * Adds `EncodedTraceContext` type as Java cannot return multiple results. Any other changes are unintentional. See https://github.com/opentracing/api-go/tree/master/opentracing --- .../src/main/java/opentracing/Span.java | 93 +++++++++++++++++++ .../main/java/opentracing/TraceContext.java | 66 +++++++++++++ .../java/opentracing/TraceContextCodec.java | 71 ++++++++++++++ .../java/opentracing/TraceContextSource.java | 48 ++++++++++ .../src/main/java/opentracing/Tracer.java | 54 +++++++++++ 5 files changed, 332 insertions(+) create mode 100644 opentracing/src/main/java/opentracing/Span.java create mode 100644 opentracing/src/main/java/opentracing/TraceContext.java create mode 100644 opentracing/src/main/java/opentracing/TraceContextCodec.java create mode 100644 opentracing/src/main/java/opentracing/TraceContextSource.java create mode 100644 opentracing/src/main/java/opentracing/Tracer.java diff --git a/opentracing/src/main/java/opentracing/Span.java b/opentracing/src/main/java/opentracing/Span.java new file mode 100644 index 00000000..df2b1bc9 --- /dev/null +++ b/opentracing/src/main/java/opentracing/Span.java @@ -0,0 +1,93 @@ +/** + * Copyright 2016 The OpenTracing 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 opentracing; + +import java.util.Formatter; + +/** + * Span represents an active, un-finished span in the opentracing system. + * + *

Spans are created by the {@link Tracer} interface and {@link #startChild(String)}. + */ +public interface Span { + + /** + * Suitable for serializing over the wire, etc. + */ + TraceContext traceContext(); + + /** + * Denotes the beginning of a subordinate unit of work. + * + * @param operationName name of the operation represened by the new span from the perspective of + * the current service. + * @return a new child Span in "started" state. + */ + Span startChild(String operationName); + + /** + * Sets the end timestamp and records the span. + * + *

This should be the last call made to any span instance, and to do otherwise leads to + * undefined behavior. + */ + void finish(); + + /** + * Adds a tag to the span. + * + *

Tag values can be of arbitrary types, however the treatment of complex types is dependent on + * the underlying tracing system implementation. It is expected that most tracing systems will + * handle primitive types like strings and numbers. If a tracing system cannot understand how to + * handle a particular value type, it may ignore the tag, but shall not panic. + * + *

If there is a pre-existing tag set for {@code key}, it is overwritten. + */ + // overloaded 3x to support the BasicType concern + Span setTag(String key, String value); + + /** Same as {@link #setTag(String, String)}, but for boolean values. */ + Span setTag(String key, boolean value); + + /** Same as {@link #setTag(String, String)}, but for numeric values. */ + // numbers kindof suck.. we've no idea if this is a float, how many bits, etc. + Span setTag(String key, Number value); + + /** + * {@code message} is a format string and can refer to fields in the payload by path, like so: + * + *

{@code
+   *
+   * span.info("first transaction is worth ${transactions[0].amount} ${transactions[0].currency}",
+   *     ImmutableMap.of(
+   *       "transactions", asList(
+   *         Transaction.builder().amount(10).currency("USD").build(),
+   *         Transaction.builder().amount(11).currency("USD").build(),
+   *       )
+   *     )
+   * );
+   * }
+ * + * @param message {@link Formatter format string} that can refer to fields in the args payload. + * @param args arbitrary payload + */ + // See https://github.com/opentracing/opentracing.github.io/issues/30 about parameterization + Span info(String message, Object... args); + + /** Same as {@link #info}, but for warnings. */ + Span warning(String message, Object... args); + + /** Same as {@link #info}, but for errors. */ + Span error(String message, Object... args); +} diff --git a/opentracing/src/main/java/opentracing/TraceContext.java b/opentracing/src/main/java/opentracing/TraceContext.java new file mode 100644 index 00000000..d69f24f9 --- /dev/null +++ b/opentracing/src/main/java/opentracing/TraceContext.java @@ -0,0 +1,66 @@ +/** + * Copyright 2016 The OpenTracing 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 opentracing; + +/** + * TraceContext encpasulates the smallest amount of state needed to describe a Span's identity + * within a larger [potentially distributed] trace. The TraceContext is not intended to encode the + * span's operation name, timing, or log data, but merely any unique identifiers (etc) needed to + * contextualize it within a larger trace tree. + * + *

TraceContexts are sufficient to propagate the, well, *context* of a particular trace between + * processes. + * + *

TraceContext also support a simple string map of "trace attributes". These trace attributes + * are special in that they are propagated *in-band*, presumably alongside application data. See the + * documentation for {@link #setAttribute(String, String)} for more details and some important + * caveats. + */ +public interface TraceContext { + + /** + * Sets a tag on this TraceContext that also propagates to future children per {@link + * TraceContextSource#newChild(TraceContext)}. + * + *

Trace attributes enables powerful functionality given a full-stack opentracing integration + * (e.g., arbitrary application data from a mobile app can make it, transparently, all the way + * into the depths of a storage system), and with it some powerful costs: use this feature with + * care. + * + *

IMPORTANT NOTE #1: This will only propagate trace attributes to *future* children of the + * TraceContextSource#newChild(TraceContext)} and/or the Span that references it. + * + *

IMPORTANT NOTE #2: Use this thoughtfully and with care. Every key and value is copied into + * every local *and remote* child of this TraceContext, and that can add up to a lot of network + * and cpu overhead. + * + *

IMPORTANT NOTE #3: Trace attributes keys have a restricted format: implementations may wish + * to use them as HTTP header keys (or key suffixes), and of course HTTP headers are case + * insensitive. + * + * @param restrictedKey MUST match the regular expression `(?i:[a-z0-9][-a-z0-9]*)` and is + * case-insensitive. That is, it must start with a letter or number, and the remaining characters + * must be letters, numbers, or hyphens. undefined behavior results if the `restrictedKey` does + * not meet these criteria. + */ + TraceContext setAttribute(String restrictedKey, String value); + + /** + * Gets the value for a trace tag given its key. Returns Null if the value isn't found in this + * TraceContext. + * + * @param restrictedKey see {@link #setAttribute(String, String)} notes. + */ + String getAttribute(String restrictedKey); +} diff --git a/opentracing/src/main/java/opentracing/TraceContextCodec.java b/opentracing/src/main/java/opentracing/TraceContextCodec.java new file mode 100644 index 00000000..a0455f09 --- /dev/null +++ b/opentracing/src/main/java/opentracing/TraceContextCodec.java @@ -0,0 +1,71 @@ +/** + * Copyright 2016 The OpenTracing 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 opentracing; + +import java.util.Map; + +/** + * Encodes or Decodes a {@linkplain TraceContext trace context} in binary or text formats. + * + *

The toXXX methods are expected to serialize trace contexts into a pair of values representing + * separately the trace context / span identity, and the trace attributes. This is done specifically + * for binary protocols that may represent tracing identity in a dedicated fixed-length slot in the + * binary message format, so that it can be inspected efficiently by the middleware / routing layers + * without parsing the whole message. + */ +public interface TraceContextCodec { + + /** + * Implementation-specific format of a span's identity along with any trace attributes. + * + * @param encoding, for example {@code byte[]} for binary, or {@code Map} for + * text. + */ + // Can instead explicitly create BinaryEncodedTraceContext, TextEncodedTraceContext, just.. cluttery + interface EncodedTraceContext { + /** Encoded span identifier. */ + E spanIdentity(); + + /** Encoded trace attributes, or null if none were encoded. */ + E traceAttributes(); + } + + /** + * Encodes the trace context into a binary representation of the span's identity and trace + * attributes. + */ + EncodedTraceContext toBinary(TraceContext tc); + + /** + * Decodes a trace context from a binary representation of the span's identity and trace + * attributes. + * + * @throws IllegalArgumentException if the encoded data is malformed. + */ + TraceContext fromBinary(EncodedTraceContext encoded); + + /** + * Encodes the trace context into a text representation of the span's identity and trace + * attributes. + */ + EncodedTraceContext> toText(TraceContext tc); + + /** + * Decodes a trace context from a text representation of the span's identity and trace + * attributes. + * + * @throws IllegalArgumentException if the encoded data is malformed. + */ + TraceContext fromText(EncodedTraceContext> encoded); +} diff --git a/opentracing/src/main/java/opentracing/TraceContextSource.java b/opentracing/src/main/java/opentracing/TraceContextSource.java new file mode 100644 index 00000000..f8f9ea4a --- /dev/null +++ b/opentracing/src/main/java/opentracing/TraceContextSource.java @@ -0,0 +1,48 @@ +/** + * Copyright 2016 The OpenTracing 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 opentracing; + +import java.util.Map; + +/** + * Long-lived interface that knows how to create a root {@linkplain TraceContext} and encode/decode + * any other. + */ +public interface TraceContextSource { + + /** + * Encodes or Decodes a {@linkplain TraceContext trace context} in binary or text formats. + */ + TraceContextCodec codec(); + + /** + * Create a TraceContext which has no parent (and thus begins its own trace). + * + *

A TraceContextSource must always return the same type in successive calls to + * NewRootTraceContext(). + */ + TraceContext newRoot(); + + /** + * Creates a child context for {@code parent}, and returns both that child's own + * TraceContext as well as any Tags that should be added to the child's Span. + */ + ChildTraceContext newChild(TraceContext parent); + + interface ChildTraceContext { + TraceContext child(); + + Map tags(); + } +} diff --git a/opentracing/src/main/java/opentracing/Tracer.java b/opentracing/src/main/java/opentracing/Tracer.java new file mode 100644 index 00000000..f62d1e4d --- /dev/null +++ b/opentracing/src/main/java/opentracing/Tracer.java @@ -0,0 +1,54 @@ +/** + * Copyright 2016 The OpenTracing 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 opentracing; + +/** + * Tracer is a simple, thin interface for Span creation. + */ +public interface Tracer { + + /** + * Create, start, and return a new Span with the given `operationName`, all without specifying a + * parent Span that can be used to incorporate the newly-returned Span into an existing trace. + * + *

Example: + *

{@code
+   * Tracer tracer = ...
+   * Span feed = tracer.startTrace("GetFeed");
+   * Span http = tracer.startTrace("HandleHTTPRequest")
+   *                   .setTag("user_agent", req.UserAgent)
+   *                   .setTag("lucky_number", 42);
+   * }
+ */ + Span startTrace(String operationName); + + /** + * Like {@link #startTrace(String)}, but the returned span is made a child of {@code parent}. + */ + Span joinTrace(String operationName, TraceContext parent); + + /** + * StartSpanWithContext returns a span with the given {@code operationName} and an association + * with {@code context} (rather than creating a fresh root context like {@link + * #startTrace(String)} or a fresh child context like {@link #joinTrace(String, TraceContext)}). + * + *

Note that the following calls are equivalent + *

{@code
+   * Span feed = tracer.startSpanWithContext("GetFeed", traceContextSource.newRoot());
+   * ...
+   * Span feed = tracer.startTrace("GetFeed");
+   * }
+ */ + Span startSpanWithContext(String operationName, TraceContext context); +} From 60d90194e3a190fc63a769dff6366843d239aece Mon Sep 17 00:00:00 2001 From: mck Date: Sun, 31 Jan 2016 11:18:19 +1100 Subject: [PATCH 2/6] Remove TraceContext, as has already been done in the specification. Remove TraceContextSource, as methods from it now belong in Tracer. Remove Tracer.joinTrace(..) as Span.startChild(..) already does this. ref: - https://github.com/opentracing/opentracing.github.io/pull/42 - https://github.com/opentracing/opentracing-java/pull/7 --- .../src/main/java/opentracing/Span.java | 7 +- ...eContextCodec.java => SpanPropagator.java} | 31 ++++----- .../main/java/opentracing/TraceContext.java | 66 ------------------- .../java/opentracing/TraceContextSource.java | 48 -------------- .../src/main/java/opentracing/Tracer.java | 19 +----- 5 files changed, 19 insertions(+), 152 deletions(-) rename opentracing/src/main/java/opentracing/{TraceContextCodec.java => SpanPropagator.java} (54%) delete mode 100644 opentracing/src/main/java/opentracing/TraceContext.java delete mode 100644 opentracing/src/main/java/opentracing/TraceContextSource.java diff --git a/opentracing/src/main/java/opentracing/Span.java b/opentracing/src/main/java/opentracing/Span.java index df2b1bc9..bd965acb 100644 --- a/opentracing/src/main/java/opentracing/Span.java +++ b/opentracing/src/main/java/opentracing/Span.java @@ -22,11 +22,6 @@ */ public interface Span { - /** - * Suitable for serializing over the wire, etc. - */ - TraceContext traceContext(); - /** * Denotes the beginning of a subordinate unit of work. * @@ -64,6 +59,8 @@ public interface Span { // numbers kindof suck.. we've no idea if this is a float, how many bits, etc. Span setTag(String key, Number value); + Span setTraceAttribute(String key, String value); + /** * {@code message} is a format string and can refer to fields in the payload by path, like so: * diff --git a/opentracing/src/main/java/opentracing/TraceContextCodec.java b/opentracing/src/main/java/opentracing/SpanPropagator.java similarity index 54% rename from opentracing/src/main/java/opentracing/TraceContextCodec.java rename to opentracing/src/main/java/opentracing/SpanPropagator.java index a0455f09..92537efd 100644 --- a/opentracing/src/main/java/opentracing/TraceContextCodec.java +++ b/opentracing/src/main/java/opentracing/SpanPropagator.java @@ -16,15 +16,16 @@ import java.util.Map; /** - * Encodes or Decodes a {@linkplain TraceContext trace context} in binary or text formats. + * Encodes or Decodes a {@linkplain Span span} in binary or text formats. * - *

The toXXX methods are expected to serialize trace contexts into a pair of values representing - * separately the trace context / span identity, and the trace attributes. This is done specifically - * for binary protocols that may represent tracing identity in a dedicated fixed-length slot in the + *

The toXXX methods are expected to serialize spans into a pair of values representing + * separately the span / span identity, and the trace attributes. + * + * This is done specifically for binary protocols that may represent tracing identity in a dedicated fixed-length slot in the * binary message format, so that it can be inspected efficiently by the middleware / routing layers * without parsing the whole message. */ -public interface TraceContextCodec { +public interface SpanPropagator { /** * Implementation-specific format of a span's identity along with any trace attributes. @@ -32,8 +33,8 @@ public interface TraceContextCodec { * @param encoding, for example {@code byte[]} for binary, or {@code Map} for * text. */ - // Can instead explicitly create BinaryEncodedTraceContext, TextEncodedTraceContext, just.. cluttery - interface EncodedTraceContext { + // Can instead explicitly create BinaryEncodedSpan, TextEncodedSpan, just.. cluttery + interface EncodedSpan { /** Encoded span identifier. */ E spanIdentity(); @@ -42,30 +43,30 @@ interface EncodedTraceContext { } /** - * Encodes the trace context into a binary representation of the span's identity and trace + * Encodes the span into a binary representation of the span's identity and trace * attributes. */ - EncodedTraceContext toBinary(TraceContext tc); + EncodedSpan toBinary(Span tc); /** - * Decodes a trace context from a binary representation of the span's identity and trace + * Decodes a span from a binary representation of the span's identity and trace * attributes. * * @throws IllegalArgumentException if the encoded data is malformed. */ - TraceContext fromBinary(EncodedTraceContext encoded); + Span fromBinary(EncodedSpan encoded); /** - * Encodes the trace context into a text representation of the span's identity and trace + * Encodes the span into a text representation of the span's identity and trace * attributes. */ - EncodedTraceContext> toText(TraceContext tc); + EncodedSpan> toText(Span tc); /** - * Decodes a trace context from a text representation of the span's identity and trace + * Decodes a span from a text representation of the span's identity and trace * attributes. * * @throws IllegalArgumentException if the encoded data is malformed. */ - TraceContext fromText(EncodedTraceContext> encoded); + Span fromText(EncodedSpan> encoded); } diff --git a/opentracing/src/main/java/opentracing/TraceContext.java b/opentracing/src/main/java/opentracing/TraceContext.java deleted file mode 100644 index d69f24f9..00000000 --- a/opentracing/src/main/java/opentracing/TraceContext.java +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Copyright 2016 The OpenTracing 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 opentracing; - -/** - * TraceContext encpasulates the smallest amount of state needed to describe a Span's identity - * within a larger [potentially distributed] trace. The TraceContext is not intended to encode the - * span's operation name, timing, or log data, but merely any unique identifiers (etc) needed to - * contextualize it within a larger trace tree. - * - *

TraceContexts are sufficient to propagate the, well, *context* of a particular trace between - * processes. - * - *

TraceContext also support a simple string map of "trace attributes". These trace attributes - * are special in that they are propagated *in-band*, presumably alongside application data. See the - * documentation for {@link #setAttribute(String, String)} for more details and some important - * caveats. - */ -public interface TraceContext { - - /** - * Sets a tag on this TraceContext that also propagates to future children per {@link - * TraceContextSource#newChild(TraceContext)}. - * - *

Trace attributes enables powerful functionality given a full-stack opentracing integration - * (e.g., arbitrary application data from a mobile app can make it, transparently, all the way - * into the depths of a storage system), and with it some powerful costs: use this feature with - * care. - * - *

IMPORTANT NOTE #1: This will only propagate trace attributes to *future* children of the - * TraceContextSource#newChild(TraceContext)} and/or the Span that references it. - * - *

IMPORTANT NOTE #2: Use this thoughtfully and with care. Every key and value is copied into - * every local *and remote* child of this TraceContext, and that can add up to a lot of network - * and cpu overhead. - * - *

IMPORTANT NOTE #3: Trace attributes keys have a restricted format: implementations may wish - * to use them as HTTP header keys (or key suffixes), and of course HTTP headers are case - * insensitive. - * - * @param restrictedKey MUST match the regular expression `(?i:[a-z0-9][-a-z0-9]*)` and is - * case-insensitive. That is, it must start with a letter or number, and the remaining characters - * must be letters, numbers, or hyphens. undefined behavior results if the `restrictedKey` does - * not meet these criteria. - */ - TraceContext setAttribute(String restrictedKey, String value); - - /** - * Gets the value for a trace tag given its key. Returns Null if the value isn't found in this - * TraceContext. - * - * @param restrictedKey see {@link #setAttribute(String, String)} notes. - */ - String getAttribute(String restrictedKey); -} diff --git a/opentracing/src/main/java/opentracing/TraceContextSource.java b/opentracing/src/main/java/opentracing/TraceContextSource.java deleted file mode 100644 index f8f9ea4a..00000000 --- a/opentracing/src/main/java/opentracing/TraceContextSource.java +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright 2016 The OpenTracing 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 opentracing; - -import java.util.Map; - -/** - * Long-lived interface that knows how to create a root {@linkplain TraceContext} and encode/decode - * any other. - */ -public interface TraceContextSource { - - /** - * Encodes or Decodes a {@linkplain TraceContext trace context} in binary or text formats. - */ - TraceContextCodec codec(); - - /** - * Create a TraceContext which has no parent (and thus begins its own trace). - * - *

A TraceContextSource must always return the same type in successive calls to - * NewRootTraceContext(). - */ - TraceContext newRoot(); - - /** - * Creates a child context for {@code parent}, and returns both that child's own - * TraceContext as well as any Tags that should be added to the child's Span. - */ - ChildTraceContext newChild(TraceContext parent); - - interface ChildTraceContext { - TraceContext child(); - - Map tags(); - } -} diff --git a/opentracing/src/main/java/opentracing/Tracer.java b/opentracing/src/main/java/opentracing/Tracer.java index f62d1e4d..163fc73c 100644 --- a/opentracing/src/main/java/opentracing/Tracer.java +++ b/opentracing/src/main/java/opentracing/Tracer.java @@ -33,22 +33,5 @@ public interface Tracer { */ Span startTrace(String operationName); - /** - * Like {@link #startTrace(String)}, but the returned span is made a child of {@code parent}. - */ - Span joinTrace(String operationName, TraceContext parent); - - /** - * StartSpanWithContext returns a span with the given {@code operationName} and an association - * with {@code context} (rather than creating a fresh root context like {@link - * #startTrace(String)} or a fresh child context like {@link #joinTrace(String, TraceContext)}). - * - *

Note that the following calls are equivalent - *

{@code
-   * Span feed = tracer.startSpanWithContext("GetFeed", traceContextSource.newRoot());
-   * ...
-   * Span feed = tracer.startTrace("GetFeed");
-   * }
- */ - Span startSpanWithContext(String operationName, TraceContext context); + SpanPropagator getSpanPropagator(); } From ad4252e14f36c8fbde603c296a1f3ee40ad7135a Mon Sep 17 00:00:00 2001 From: mck Date: Fri, 22 Jan 2016 11:53:22 +1100 Subject: [PATCH 3/6] Simplify the logging and timestamped annotations down to a `log(message, payload)` method. Rationale: This is the simplest solution, and an appropriate plumbing API, that solves the use-case of info/error and parameterised message formatting. OpenTracing API may adopt a porcelain API for those info/error logging-style methods down the road once the plumbing api has been battle tested a bit more. reference: https://github.com/opentracing/opentracing-java/pull/9 --- .../src/main/java/opentracing/Span.java | 44 ++++++++----------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/opentracing/src/main/java/opentracing/Span.java b/opentracing/src/main/java/opentracing/Span.java index bd965acb..7aa4f8b1 100644 --- a/opentracing/src/main/java/opentracing/Span.java +++ b/opentracing/src/main/java/opentracing/Span.java @@ -13,8 +13,6 @@ */ package opentracing; -import java.util.Formatter; - /** * Span represents an active, un-finished span in the opentracing system. * @@ -61,30 +59,24 @@ public interface Span { Span setTraceAttribute(String key, String value); - /** - * {@code message} is a format string and can refer to fields in the payload by path, like so: - * - *
{@code
-   *
-   * span.info("first transaction is worth ${transactions[0].amount} ${transactions[0].currency}",
-   *     ImmutableMap.of(
-   *       "transactions", asList(
-   *         Transaction.builder().amount(10).currency("USD").build(),
-   *         Transaction.builder().amount(11).currency("USD").build(),
-   *       )
-   *     )
-   * );
-   * }
+ /** * + * Add a new log event to the Span, accepting an event name string and an optional structured payload argument. + * If specified, the payload argument may be of any type and arbitrary size, + * though implementations are not required to retain all payload arguments + * (or even all parts of all payload arguments). * - * @param message {@link Formatter format string} that can refer to fields in the args payload. - * @param args arbitrary payload - */ - // See https://github.com/opentracing/opentracing.github.io/issues/30 about parameterization - Span info(String message, Object... args); - - /** Same as {@link #info}, but for warnings. */ - Span warning(String message, Object... args); + * The timestamp of this log event is the current time. + **/ + Span log(String eventName, /* @Nullable */ Object payload); - /** Same as {@link #info}, but for errors. */ - Span error(String message, Object... args); + /** + * Add a new log event to the Span, accepting an event name string and an optional structured payload argument. + * If specified, the payload argument may be of any type and arbitrary size, + * though implementations are not required to retain all payload arguments + * (or even all parts of all payload arguments). + * + * The timestamp is specified manually here to represent a past log event. + * The timestamp in microseconds in UTC time. + **/ + Span log(long instantMicroseconds, String eventName, /* @Nullable */ Object payload); } From 87a0c6d5135e277402b160a1741d1209f0ef98b5 Mon Sep 17 00:00:00 2001 From: mck Date: Sun, 21 Feb 2016 19:45:04 +1100 Subject: [PATCH 4/6] Put into place the top-level design that fulfils the new Specification - Only span creation method is in Tracer.startSpan(..) - Add Tracer's inject(..) and join(..) methods reference: https://github.com/opentracing/opentracing-java/pull/10 --- .../src/main/java/opentracing/Span.java | 24 +++---- .../main/java/opentracing/SpanPropagator.java | 72 ------------------- .../src/main/java/opentracing/Tracer.java | 36 ++++++++-- 3 files changed, 40 insertions(+), 92 deletions(-) delete mode 100644 opentracing/src/main/java/opentracing/SpanPropagator.java diff --git a/opentracing/src/main/java/opentracing/Span.java b/opentracing/src/main/java/opentracing/Span.java index 7aa4f8b1..8269a8af 100644 --- a/opentracing/src/main/java/opentracing/Span.java +++ b/opentracing/src/main/java/opentracing/Span.java @@ -16,19 +16,10 @@ /** * Span represents an active, un-finished span in the opentracing system. * - *

Spans are created by the {@link Tracer} interface and {@link #startChild(String)}. + *

Spans are created by the {@link Tracer} interface. */ public interface Span { - /** - * Denotes the beginning of a subordinate unit of work. - * - * @param operationName name of the operation represened by the new span from the perspective of - * the current service. - * @return a new child Span in "started" state. - */ - Span startChild(String operationName); - /** * Sets the end timestamp and records the span. * @@ -38,7 +29,7 @@ public interface Span { void finish(); /** - * Adds a tag to the span. + * Set a key:value tag on the Span. * *

Tag values can be of arbitrary types, however the treatment of complex types is dependent on * the underlying tracing system implementation. It is expected that most tracing systems will @@ -54,10 +45,17 @@ public interface Span { Span setTag(String key, boolean value); /** Same as {@link #setTag(String, String)}, but for numeric values. */ - // numbers kindof suck.. we've no idea if this is a float, how many bits, etc. Span setTag(String key, Number value); - Span setTraceAttribute(String key, String value); + /** + * Set a Baggage item, represented as a simple string:string pair. + * + * Note that newly-set Baggage items are only guaranteed to propagate to future children of the given Span. + */ + Span setBaggageItem(String key, String value); + + /** Get a Baggage item by key. */ + String getBaggageItem(String key); /** * * Add a new log event to the Span, accepting an event name string and an optional structured payload argument. diff --git a/opentracing/src/main/java/opentracing/SpanPropagator.java b/opentracing/src/main/java/opentracing/SpanPropagator.java deleted file mode 100644 index 92537efd..00000000 --- a/opentracing/src/main/java/opentracing/SpanPropagator.java +++ /dev/null @@ -1,72 +0,0 @@ -/** - * Copyright 2016 The OpenTracing 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 opentracing; - -import java.util.Map; - -/** - * Encodes or Decodes a {@linkplain Span span} in binary or text formats. - * - *

The toXXX methods are expected to serialize spans into a pair of values representing - * separately the span / span identity, and the trace attributes. - * - * This is done specifically for binary protocols that may represent tracing identity in a dedicated fixed-length slot in the - * binary message format, so that it can be inspected efficiently by the middleware / routing layers - * without parsing the whole message. - */ -public interface SpanPropagator { - - /** - * Implementation-specific format of a span's identity along with any trace attributes. - * - * @param encoding, for example {@code byte[]} for binary, or {@code Map} for - * text. - */ - // Can instead explicitly create BinaryEncodedSpan, TextEncodedSpan, just.. cluttery - interface EncodedSpan { - /** Encoded span identifier. */ - E spanIdentity(); - - /** Encoded trace attributes, or null if none were encoded. */ - E traceAttributes(); - } - - /** - * Encodes the span into a binary representation of the span's identity and trace - * attributes. - */ - EncodedSpan toBinary(Span tc); - - /** - * Decodes a span from a binary representation of the span's identity and trace - * attributes. - * - * @throws IllegalArgumentException if the encoded data is malformed. - */ - Span fromBinary(EncodedSpan encoded); - - /** - * Encodes the span into a text representation of the span's identity and trace - * attributes. - */ - EncodedSpan> toText(Span tc); - - /** - * Decodes a span from a text representation of the span's identity and trace - * attributes. - * - * @throws IllegalArgumentException if the encoded data is malformed. - */ - Span fromText(EncodedSpan> encoded); -} diff --git a/opentracing/src/main/java/opentracing/Tracer.java b/opentracing/src/main/java/opentracing/Tracer.java index 163fc73c..2808ffa1 100644 --- a/opentracing/src/main/java/opentracing/Tracer.java +++ b/opentracing/src/main/java/opentracing/Tracer.java @@ -13,25 +13,47 @@ */ package opentracing; + /** - * Tracer is a simple, thin interface for Span creation. + * Tracer is a simple, thin interface for Span creation, and Span propagation into different transport formats. */ public interface Tracer { /** - * Create, start, and return a new Span with the given `operationName`, all without specifying a - * parent Span that can be used to incorporate the newly-returned Span into an existing trace. + * Create, start, and return a new Span with the given `operationName`. + * An optional parent Span can be specified used to incorporate the newly-returned Span into an existing trace. * *

Example: *

{@code
    * Tracer tracer = ...
-   * Span feed = tracer.startTrace("GetFeed");
-   * Span http = tracer.startTrace("HandleHTTPRequest")
+   * Span feed = tracer.startTrace("GetFeed", null);
+   * Span http = tracer.startTrace("HandleHTTPRequest", feed)
    *                   .setTag("user_agent", req.UserAgent)
    *                   .setTag("lucky_number", 42);
    * }
*/ - Span startTrace(String operationName); + Span startSpan(String operationName, /* @Nullable */ Span parent); - SpanPropagator getSpanPropagator(); + /** + * Same as {@link #startSpan(String, Span)}, + * but allows to specify a past timestamp in microseconds when the Span was created. + */ + Span startSpan(String operationName, long microseconds, /* @Nullable */ Span parent); + + /** Takes two arguments: + * a Span instance, and + * a “carrier” object in which to inject that Span for cross-process propagation. + * + */ + void inject(Span span, T carrier); + + /** Takes two arguments: + * the operation name for the Span it’s about to create, and + * a “carrier” object from which to extract identifying information needed by the new Span instance. + * + * Unless there’s an error, it returns a freshly-started Span which can be used in the host process like any other. + * (Note that some OpenTracing implementations consider the Spans on either side of an RPC to have the same identity, + * and others consider the caller to be the parent and the receiver to be the child) + */ + Span join(String operationName, T carrier); } From fd5564dd3d40329d98af790a8b56afc5f44cb90e Mon Sep 17 00:00:00 2001 From: mck Date: Mon, 29 Feb 2016 19:36:01 +1100 Subject: [PATCH 5/6] Tracer.startSpan(..) with a builder for specifying the arguments ref https://github.com/opentracing/opentracing-java/pull/12 --- .../src/main/java/opentracing/Tracer.java | 67 ++++++++++++++----- 1 file changed, 51 insertions(+), 16 deletions(-) diff --git a/opentracing/src/main/java/opentracing/Tracer.java b/opentracing/src/main/java/opentracing/Tracer.java index 2808ffa1..7d66f5a9 100644 --- a/opentracing/src/main/java/opentracing/Tracer.java +++ b/opentracing/src/main/java/opentracing/Tracer.java @@ -25,20 +25,19 @@ public interface Tracer { * *

Example: *

{@code
-   * Tracer tracer = ...
-   * Span feed = tracer.startTrace("GetFeed", null);
-   * Span http = tracer.startTrace("HandleHTTPRequest", feed)
-   *                   .setTag("user_agent", req.UserAgent)
-   *                   .setTag("lucky_number", 42);
-   * }
- */ - Span startSpan(String operationName, /* @Nullable */ Span parent); + Tracer tracer = ... - /** - * Same as {@link #startSpan(String, Span)}, - * but allows to specify a past timestamp in microseconds when the Span was created. + Span feed = tracer.buildSpan("GetFeed") + .start(); + + Span http = tracer.buildSpan("HandleHTTPRequest") + .withParent(feed) + .withTag("user_agent", req.UserAgent) + .withTag("lucky_number", 42) + .start(); + } */ - Span startSpan(String operationName, long microseconds, /* @Nullable */ Span parent); + SpanBuilder buildSpan(String operationName); /** Takes two arguments: * a Span instance, and @@ -47,13 +46,49 @@ public interface Tracer { */ void inject(Span span, T carrier); - /** Takes two arguments: - * the operation name for the Span it’s about to create, and + /** Returns a SpanBuilder provided * a “carrier” object from which to extract identifying information needed by the new Span instance. * - * Unless there’s an error, it returns a freshly-started Span which can be used in the host process like any other. + * If the carrier object has no such span stored within it, a new Span is created. + * + * Unless there’s an error, it returns a SpanBuilder. + * The Span generated from the builder can be used in the host process like any other. + * * (Note that some OpenTracing implementations consider the Spans on either side of an RPC to have the same identity, * and others consider the caller to be the parent and the receiver to be the child) */ - Span join(String operationName, T carrier); + SpanBuilder join(T carrier); + + interface SpanBuilder { + + /** Specify the operationName. + * + * If the operationName has already been set (implicitly or explicitly) an IllegalStateException will be thrown. + */ + SpanBuilder withOperationName(String operationName); + + /** Specify the parent span + * + * If the parent has already been set an IllegalStateException will be thrown. + */ + SpanBuilder withParent(Span parent); + + /** Specify a timestamp the Span actually started from. + * + * If the timestamp has already been set an IllegalStateException will be thrown. + */ + SpanBuilder withTimestamp(long microseconds); + + /** Same as {@link Span#setTag(String, String)}, but for the span being built. */ + SpanBuilder withTag(String key, String value); + + /** Same as {@link Span#setTag(String, String)}, but for the span being built. */ + SpanBuilder withTag(String key, boolean value); + + /** Same as {@link Span#setTag(String, String)}, but for the span being built. */ + SpanBuilder withTag(String key, Number value); + + /** Returns the started Span. */ + Span start(); + } } From 7bc6ae10c9302b9e001ce2996424b743006f5013 Mon Sep 17 00:00:00 2001 From: mck Date: Thu, 3 Mar 2016 17:29:58 +1100 Subject: [PATCH 6/6] addressing comments in https://github.com/opentracing/opentracing-java/pull/13 --- .../src/main/java/opentracing/Span.java | 20 +++++++--------- .../src/main/java/opentracing/Tracer.java | 23 ++++++++++++++----- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/opentracing/src/main/java/opentracing/Span.java b/opentracing/src/main/java/opentracing/Span.java index 8269a8af..6b55eff8 100644 --- a/opentracing/src/main/java/opentracing/Span.java +++ b/opentracing/src/main/java/opentracing/Span.java @@ -14,9 +14,9 @@ package opentracing; /** - * Span represents an active, un-finished span in the opentracing system. + * Represents an in-flight span in the opentracing system. * - *

Spans are created by the {@link Tracer} interface. + *

Spans are created by the {@link Tracer#buildSpan} interface. */ public interface Span { @@ -30,13 +30,6 @@ public interface Span { /** * Set a key:value tag on the Span. - * - *

Tag values can be of arbitrary types, however the treatment of complex types is dependent on - * the underlying tracing system implementation. It is expected that most tracing systems will - * handle primitive types like strings and numbers. If a tracing system cannot understand how to - * handle a particular value type, it may ignore the tag, but shall not panic. - * - *

If there is a pre-existing tag set for {@code key}, it is overwritten. */ // overloaded 3x to support the BasicType concern Span setTag(String key, String value); @@ -54,10 +47,13 @@ public interface Span { */ Span setBaggageItem(String key, String value); - /** Get a Baggage item by key. */ + /** Get a Baggage item by key. + * + * Returns null if no entry found, or baggage is not supported in the current implementation. + */ String getBaggageItem(String key); - /** * + /** * Add a new log event to the Span, accepting an event name string and an optional structured payload argument. * If specified, the payload argument may be of any type and arbitrary size, * though implementations are not required to retain all payload arguments @@ -76,5 +72,5 @@ public interface Span { * The timestamp is specified manually here to represent a past log event. * The timestamp in microseconds in UTC time. **/ - Span log(long instantMicroseconds, String eventName, /* @Nullable */ Object payload); + Span log(long timestampMicroseconds, String eventName, /* @Nullable */ Object payload); } diff --git a/opentracing/src/main/java/opentracing/Tracer.java b/opentracing/src/main/java/opentracing/Tracer.java index 7d66f5a9..6390eea6 100644 --- a/opentracing/src/main/java/opentracing/Tracer.java +++ b/opentracing/src/main/java/opentracing/Tracer.java @@ -43,6 +43,10 @@ public interface Tracer { * a Span instance, and * a “carrier” object in which to inject that Span for cross-process propagation. * + * A “carrier” object is some sort of http or rpc envelope, for example HeaderGroup (from Apache HttpComponents). + * + * Attempting to inject to a carrier that has been registered/configured to this Tracer will result in a + * IllegalStateException. */ void inject(Span span, T carrier); @@ -56,9 +60,16 @@ public interface Tracer { * * (Note that some OpenTracing implementations consider the Spans on either side of an RPC to have the same identity, * and others consider the caller to be the parent and the receiver to be the child) + * + * Attempting to join from a carrier that has been registered/configured to this Tracer will result in a + * IllegalStateException. + * + * If the span serialized state is invalid (corrupt, wrong version, etc) inside the carrier this will result in a + * IllegalArgumentException. */ SpanBuilder join(T carrier); + interface SpanBuilder { /** Specify the operationName. @@ -73,12 +84,6 @@ interface SpanBuilder { */ SpanBuilder withParent(Span parent); - /** Specify a timestamp the Span actually started from. - * - * If the timestamp has already been set an IllegalStateException will be thrown. - */ - SpanBuilder withTimestamp(long microseconds); - /** Same as {@link Span#setTag(String, String)}, but for the span being built. */ SpanBuilder withTag(String key, String value); @@ -88,7 +93,13 @@ interface SpanBuilder { /** Same as {@link Span#setTag(String, String)}, but for the span being built. */ SpanBuilder withTag(String key, Number value); + /** Specify a timestamp of when the Span was started, represented in microseconds since epoch. */ + SpanBuilder withStartTimestamp(long microseconds); + /** Returns the started Span. */ Span start(); + + /** Returns the Span, with a started timestamp (represented in microseconds) as specified. */ + Span start(long microseconds); } }