From a8469e8f8fe375b2d6538de1541b5f5ce8b43fca Mon Sep 17 00:00:00 2001 From: Ben Sigelman Date: Fri, 2 Sep 2016 15:39:06 -0700 Subject: [PATCH 01/12] Sketch out key-value logging --- .../src/main/java/io/opentracing/Span.java | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/opentracing-api/src/main/java/io/opentracing/Span.java b/opentracing-api/src/main/java/io/opentracing/Span.java index 5961fcea..9edcdd21 100644 --- a/opentracing-api/src/main/java/io/opentracing/Span.java +++ b/opentracing-api/src/main/java/io/opentracing/Span.java @@ -65,25 +65,18 @@ public interface Span extends AutoCloseable { Span setTag(String key, Number value); /** - * Add a new log event to the Span, accepting an event name string and an optional structured payload argument. + * Log key:value pairs to the Span with the current walltime timestamp. * - * 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 of this log event is the current time. - **/ - Span log(String eventName, /* @Nullable */ Object payload); - + * @param keyValues Alternating key Strings and value Objects. Values may be numeric types, bools, Strings, or + * arbitrary objects, though the treatment of arbitrary Objects varies across Tracer/Span + * implementations. + * @return the Span, for chaining + */ + Span logKeyValues(Object... keyValues); /** - * 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 timestampMicroseconds, String eventName, /* @Nullable */ Object payload); + * Like logKeyValues(Object...), but with an explicit timestamp. + */ + Span logKeyValues(long timestampMicroseconds, Object... keyValues); /** * Sets a baggage item in the Span (and its SpanContext) as a key/value pair. @@ -111,4 +104,13 @@ public interface Span extends AutoCloseable { * @return this Span instance, for chaining */ Span setOperationName(String operationName); + + /** + * DEPRECATED + **/ + Span log(String eventName, /* @Nullable */ Object payload); + /** + * DEPRECATED + **/ + Span log(long timestampMicroseconds, String eventName, /* @Nullable */ Object payload); } From 8b5524d6d301f9be3c1a1e8b11cbf33e88f0ed2d Mon Sep 17 00:00:00 2001 From: Ben Sigelman Date: Sat, 3 Sep 2016 13:34:10 -0700 Subject: [PATCH 02/12] Add a usage example --- opentracing-api/src/main/java/io/opentracing/Span.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/opentracing-api/src/main/java/io/opentracing/Span.java b/opentracing-api/src/main/java/io/opentracing/Span.java index 9edcdd21..b5b82b41 100644 --- a/opentracing-api/src/main/java/io/opentracing/Span.java +++ b/opentracing-api/src/main/java/io/opentracing/Span.java @@ -67,8 +67,16 @@ public interface Span extends AutoCloseable { /** * Log key:value pairs to the Span with the current walltime timestamp. * + *

A contrived example: + *

{@code
+      span.logKeyValues(
+          "size", rpc.size(),  // numeric values
+          "URI", rpc.URI(),  // String values
+          "payload", rpc.payload());  // Object values
+      }
+ * * @param keyValues Alternating key Strings and value Objects. Values may be numeric types, bools, Strings, or - * arbitrary objects, though the treatment of arbitrary Objects varies across Tracer/Span + * arbitrary objects, though the treatment of arbitrary Objects varies across Tracer * implementations. * @return the Span, for chaining */ From 5e0f206cd65220f5e9488d36b8c24e4635250d19 Mon Sep 17 00:00:00 2001 From: Ben Sigelman Date: Sun, 4 Sep 2016 14:30:51 -0700 Subject: [PATCH 03/12] Use a more explicit LogField mechanism --- .../main/java/io/opentracing/LogField.java | 20 +++++++++++++++++++ .../src/main/java/io/opentracing/Span.java | 20 +++++++++---------- 2 files changed, 29 insertions(+), 11 deletions(-) create mode 100644 opentracing-api/src/main/java/io/opentracing/LogField.java diff --git a/opentracing-api/src/main/java/io/opentracing/LogField.java b/opentracing-api/src/main/java/io/opentracing/LogField.java new file mode 100644 index 00000000..ba411f52 --- /dev/null +++ b/opentracing-api/src/main/java/io/opentracing/LogField.java @@ -0,0 +1,20 @@ +package io.opentracing; + +/** + * LogField represents a single key:value pair in a Span.log() record. + * + * The key must always be a String. All Tracer implementations must support values bool, numeric, and String values; + * some may also support arbitrary Object values. + */ +public class LogField { + private final String key; + private final V value; + + public LogField(String key, V value) { + this.key = key; + this.value = value; + } + + public String key() { return key; } + public V value() { return value; } +} diff --git a/opentracing-api/src/main/java/io/opentracing/Span.java b/opentracing-api/src/main/java/io/opentracing/Span.java index b5b82b41..0bc7f2f8 100644 --- a/opentracing-api/src/main/java/io/opentracing/Span.java +++ b/opentracing-api/src/main/java/io/opentracing/Span.java @@ -69,22 +69,20 @@ public interface Span extends AutoCloseable { * *

A contrived example: *

{@code
-      span.logKeyValues(
-          "size", rpc.size(),  // numeric values
-          "URI", rpc.URI(),  // String values
-          "payload", rpc.payload());  // Object values
-      }
+ span.log( + new LogField("size", rpc.size()), // numeric values + new LogField("URI", rpc.URI()), // String values + new LogField("payload", rpc.payload())); // Object values + } * - * @param keyValues Alternating key Strings and value Objects. Values may be numeric types, bools, Strings, or - * arbitrary objects, though the treatment of arbitrary Objects varies across Tracer - * implementations. + * @param fields One or more LogField instances * @return the Span, for chaining */ - Span logKeyValues(Object... keyValues); + Span log(LogField... fields); /** - * Like logKeyValues(Object...), but with an explicit timestamp. + * Like log(LogField...), but with an explicit timestamp. */ - Span logKeyValues(long timestampMicroseconds, Object... keyValues); + Span log(long timestampMicroseconds, LogField... fields); /** * Sets a baggage item in the Span (and its SpanContext) as a key/value pair. From 60896fecc9af2ed1326ddf70b7ba695c9db26c20 Mon Sep 17 00:00:00 2001 From: Ben Sigelman Date: Sun, 11 Sep 2016 14:17:39 -0700 Subject: [PATCH 04/12] Rename to Field and add .of() --- .../main/java/io/opentracing/LogField.java | 20 -------- .../src/main/java/io/opentracing/Span.java | 23 +++++++--- .../main/java/io/opentracing/log/Field.java | 46 +++++++++++++++++++ 3 files changed, 62 insertions(+), 27 deletions(-) delete mode 100644 opentracing-api/src/main/java/io/opentracing/LogField.java create mode 100644 opentracing-api/src/main/java/io/opentracing/log/Field.java diff --git a/opentracing-api/src/main/java/io/opentracing/LogField.java b/opentracing-api/src/main/java/io/opentracing/LogField.java deleted file mode 100644 index ba411f52..00000000 --- a/opentracing-api/src/main/java/io/opentracing/LogField.java +++ /dev/null @@ -1,20 +0,0 @@ -package io.opentracing; - -/** - * LogField represents a single key:value pair in a Span.log() record. - * - * The key must always be a String. All Tracer implementations must support values bool, numeric, and String values; - * some may also support arbitrary Object values. - */ -public class LogField { - private final String key; - private final V value; - - public LogField(String key, V value) { - this.key = key; - this.value = value; - } - - public String key() { return key; } - public V value() { return value; } -} diff --git a/opentracing-api/src/main/java/io/opentracing/Span.java b/opentracing-api/src/main/java/io/opentracing/Span.java index 0bc7f2f8..56421b77 100644 --- a/opentracing-api/src/main/java/io/opentracing/Span.java +++ b/opentracing-api/src/main/java/io/opentracing/Span.java @@ -13,6 +13,8 @@ */ package io.opentracing; +import io.opentracing.log.Field; + /** * Represents an in-flight span in the opentracing system. * @@ -70,19 +72,26 @@ public interface Span extends AutoCloseable { *

A contrived example: *

{@code
      span.log(
-         new LogField("size", rpc.size()),  // numeric values
-         new LogField("URI", rpc.URI()),  // String values
-         new LogField("payload", rpc.payload()));  // Object values
+         Field.of("size", rpc.size()),  // numeric values
+         Field.of("URI", rpc.URI()),  // String values
+         Field.of("payload", rpc.payload()));  // Object values
      }
* - * @param fields One or more LogField instances + * @see io.opentracing.log.Field + * @param fields One or more Field instances * @return the Span, for chaining */ - Span log(LogField... fields); + Span log(Field... fields); /** - * Like log(LogField...), but with an explicit timestamp. + * Like log(Field...), but with an explicit timestamp. + * + * @see io.opentracing.log.Field + * @param timestampMicroseconds The explicit timestamp for the log record. Must be greater than or equal to the + * Span's start timestamp. + * @param fields One or more Field instances + * @return the Span, for chaining */ - Span log(long timestampMicroseconds, LogField... fields); + Span log(long timestampMicroseconds, Field... fields); /** * Sets a baggage item in the Span (and its SpanContext) as a key/value pair. diff --git a/opentracing-api/src/main/java/io/opentracing/log/Field.java b/opentracing-api/src/main/java/io/opentracing/log/Field.java new file mode 100644 index 00000000..2924c5c5 --- /dev/null +++ b/opentracing-api/src/main/java/io/opentracing/log/Field.java @@ -0,0 +1,46 @@ +/** + * 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 io.opentracing.log; + +/** + * Field represents a single key:value pair in a Span.log(...) call. + * + * The key must always be a String. All Tracer implementations must support bool, numeric, and String values; some may + * also support arbitrary Object values. + */ +public class Field { + private final String key; + private final V value; + + /** + * Instantiate an (immutable) Field of value type V + * + * @param key the Field's key; an unrestricted String + * @param value the Field's value; all Tracer implementations should support String, numeric, and bool values. + * Some may also support Object values. + * @param the value type for the returned Field instance + * @return a Field suitable for Span.log(...) invocations + */ + public static Field of(String key, V value) { + return new Field(key, value); + } + + public String key() { return key; } + public V value() { return value; } + + Field(String key, V value) { + this.key = key; + this.value = value; + } +} From 2971087d748686a1a245812348f72cb6ac078eb3 Mon Sep 17 00:00:00 2001 From: Ben Sigelman Date: Sun, 11 Sep 2016 14:49:04 -0700 Subject: [PATCH 05/12] Make the rest of opentracing-java build and test --- .../java/io/opentracing/AbstractSpan.java | 37 +++++++++++------ .../main/java/io/opentracing/NoopSpan.java | 8 ++++ .../java/io/opentracing/mock/MockSpan.java | 40 +++++++++++-------- .../io/opentracing/mock/MockTracerTest.java | 26 +++++++++--- 4 files changed, 77 insertions(+), 34 deletions(-) diff --git a/opentracing-impl-java8/src/main/java/io/opentracing/AbstractSpan.java b/opentracing-impl-java8/src/main/java/io/opentracing/AbstractSpan.java index 2262d6fd..3e481a2d 100644 --- a/opentracing-impl-java8/src/main/java/io/opentracing/AbstractSpan.java +++ b/opentracing-impl-java8/src/main/java/io/opentracing/AbstractSpan.java @@ -13,13 +13,11 @@ */ package io.opentracing; +import io.opentracing.log.Field; + import java.time.Duration; import java.time.Instant; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.concurrent.TimeUnit; abstract class AbstractSpan implements Span, SpanContext { @@ -126,6 +124,18 @@ public final Map getBaggage() { return Collections.unmodifiableMap(baggage); } + @Override + public final Span log(Field... fields) { + return log(System.nanoTime() / 1000, fields); + } + + @Override + public final Span log(long timestampMicros, Field... fields) { + Instant timestamp = Instant.ofEpochSecond(timestampMicros / 1000000, (timestampMicros % 1000000) * 1000); + logs.add(new LogData(timestamp, fields)); + return this; + } + @Override public final Span log(String message, /* @Nullable */ Object payload) { Instant now = Instant.now(); @@ -137,8 +147,13 @@ public final Span log(String message, /* @Nullable */ Object payload) { } @Override - public final Span log(long instantMicroseconds, String message, /* @Nullable */ Object payload) { - logs.add(new LogData(start, message, payload)); + public final Span log(long timestampMicros, String message, /* @Nullable */ Object payload) { + Instant timestamp = Instant.ofEpochSecond(timestampMicros / 1000000, (timestampMicros % 1000000) * 1000); + if (payload == null) { + logs.add(new LogData(timestamp, Field.of("message", message))); + } else { + logs.add(new LogData(timestamp, Field.of("message", message), Field.of("payload", payload))); + } return this; } @@ -148,13 +163,11 @@ public final List getLogs() { final class LogData { private final Instant time; - private final String message; - private final Object payload; + private final List fields; - LogData(Instant time, String message, Object payload) { + LogData(Instant time, Field... fields) { this.time = time; - this.message = message; - this.payload = payload; + this.fields = Arrays.asList(fields); } } } diff --git a/opentracing-impl/src/main/java/io/opentracing/NoopSpan.java b/opentracing-impl/src/main/java/io/opentracing/NoopSpan.java index 2e09264f..9d4e719a 100644 --- a/opentracing-impl/src/main/java/io/opentracing/NoopSpan.java +++ b/opentracing-impl/src/main/java/io/opentracing/NoopSpan.java @@ -13,6 +13,8 @@ */ package io.opentracing; +import io.opentracing.log.Field; + import java.util.Collections; import java.util.Map; @@ -58,6 +60,12 @@ public Span setTag(String key, Number value) { return this; } + @Override + public Span log(Field... fields) { return this; } + + @Override + public Span log(long timestampMicroseconds, Field... fields) { return this; } + @Override public Span log(String eventName, Object payload) { return this; diff --git a/opentracing-mock/src/main/java/io/opentracing/mock/MockSpan.java b/opentracing-mock/src/main/java/io/opentracing/mock/MockSpan.java index 15944487..a5a42bc1 100644 --- a/opentracing-mock/src/main/java/io/opentracing/mock/MockSpan.java +++ b/opentracing-mock/src/main/java/io/opentracing/mock/MockSpan.java @@ -13,14 +13,12 @@ */ package io.opentracing.mock; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.concurrent.atomic.AtomicLong; import io.opentracing.Span; import io.opentracing.SpanContext; +import io.opentracing.log.Field; /** * MockSpans are created via MockTracer.buildSpan(...), but they are also returned via calls to @@ -124,6 +122,17 @@ public synchronized Span setTag(String key, Number value) { return this; } + @Override + public final Span log(Field... fields) { + long nowMicros = System.nanoTime() / 1000; + return log(nowMicros, fields); + } + @Override + public final Span log(long timestampMicros, Field... fields) { + this.logEntries.add(new LogEntry(timestampMicros, fields)); + return this; + } + @Override public Span log(String eventName, Object payload) { return this.log(System.nanoTime() / 1000, eventName, payload); @@ -131,8 +140,11 @@ public Span log(String eventName, Object payload) { @Override public synchronized Span log(long timestampMicroseconds, String eventName, Object payload) { - this.logEntries.add(new LogEntry(timestampMicroseconds, eventName, payload)); - return this; + if (payload == null) { + return this.log(timestampMicroseconds, Field.of("event", eventName)); + } else { + return this.log(timestampMicroseconds, Field.of("event", eventName), Field.of("payload", payload)); + } } @Override @@ -192,25 +204,19 @@ public Iterable> baggageItems() { public static final class LogEntry { private final long timestampMicros; - private final String eventName; - private final Object payload; + private final List fields; - public LogEntry(long timestampMicros, String eventName, Object payload) { + public LogEntry(long timestampMicros, Field... fields) { this.timestampMicros = timestampMicros; - this.eventName = eventName; - this.payload = payload; + this.fields = Arrays.asList(fields); } public long timestampMicros() { return timestampMicros; } - public String eventName() { - return eventName; - } - - public Object payload() { - return payload; + public List fields() { + return fields; } } diff --git a/opentracing-mock/src/test/java/io/opentracing/mock/MockTracerTest.java b/opentracing-mock/src/test/java/io/opentracing/mock/MockTracerTest.java index 5843a87f..3724db65 100644 --- a/opentracing-mock/src/test/java/io/opentracing/mock/MockTracerTest.java +++ b/opentracing-mock/src/test/java/io/opentracing/mock/MockTracerTest.java @@ -14,6 +14,7 @@ package io.opentracing.mock; import io.opentracing.Span; +import io.opentracing.log.Field; import org.junit.Test; import java.util.List; @@ -31,7 +32,10 @@ public void testRootSpan() { Span span = tracer.buildSpan("tester").withStartTimestamp(1000).start(); span.setTag("string", "foo"); span.setTag("int", 7); + // Old style logging: span.log(1001, "event name", tracer); + // New style logging: + span.log(1002, Field.of("f1", 4), Field.of("f2", "two")); span.finish(2000); } List finishedSpans = tracer.finishedSpans(); @@ -50,11 +54,23 @@ public void testRootSpan() { assertEquals(7, tags.get("int")); assertEquals("foo", tags.get("string")); List logs = finishedSpan.logEntries(); - assertEquals(1, logs.size()); - MockSpan.LogEntry log = logs.get(0); - assertEquals(1001, log.timestampMicros()); - assertEquals("event name", log.eventName()); - assertEquals(tracer, log.payload()); + assertEquals(2, logs.size()); + { + MockSpan.LogEntry log = logs.get(0); + assertEquals(1001, log.timestampMicros()); + assertEquals("event", log.fields().get(0).key()); + assertEquals("event name", log.fields().get(0).value()); + assertEquals("payload", log.fields().get(1).key()); + assertEquals(tracer, log.fields().get(1).value()); + } + { + MockSpan.LogEntry log = logs.get(1); + assertEquals(1002, log.timestampMicros()); + assertEquals("f1", log.fields().get(0).key()); + assertEquals(4, log.fields().get(0).value()); + assertEquals("f2", log.fields().get(1).key()); + assertEquals("two", log.fields().get(1).value()); + } } @Test From b086c7dcef8e3bf6bbe50bbdb442a31160525ff7 Mon Sep 17 00:00:00 2001 From: Ben Sigelman Date: Mon, 19 Sep 2016 21:50:46 -0700 Subject: [PATCH 06/12] See how things look with a bare Map --- .../src/main/java/io/opentracing/Span.java | 27 ++++++----- .../main/java/io/opentracing/log/Field.java | 46 ------------------- .../java/io/opentracing/PlaygroundTest.java | 37 --------------- .../java/io/opentracing/AbstractSpan.java | 27 ++++++----- .../main/java/io/opentracing/NoopSpan.java | 6 +-- .../java/io/opentracing/mock/MockSpan.java | 22 ++++----- .../io/opentracing/mock/MockTracerTest.java | 19 ++++---- 7 files changed, 50 insertions(+), 134 deletions(-) delete mode 100644 opentracing-api/src/main/java/io/opentracing/log/Field.java delete mode 100644 opentracing-api/src/test/java/io/opentracing/PlaygroundTest.java diff --git a/opentracing-api/src/main/java/io/opentracing/Span.java b/opentracing-api/src/main/java/io/opentracing/Span.java index 56421b77..46f487df 100644 --- a/opentracing-api/src/main/java/io/opentracing/Span.java +++ b/opentracing-api/src/main/java/io/opentracing/Span.java @@ -13,7 +13,7 @@ */ package io.opentracing; -import io.opentracing.log.Field; +import java.util.Map; /** * Represents an in-flight span in the opentracing system. @@ -69,29 +69,32 @@ public interface Span extends AutoCloseable { /** * Log key:value pairs to the Span with the current walltime timestamp. * - *

A contrived example: + *

A contrived example (using Guava, which is not required): *

{@code
      span.log(
-         Field.of("size", rpc.size()),  // numeric values
-         Field.of("URI", rpc.URI()),  // String values
-         Field.of("payload", rpc.payload()));  // Object values
+         ImmutableMap.Builder()
+             .put("event", "soft error")
+             .put("type", "cache timeout")
+             .put("waited.millis", 1500)
+             .build());
      }
* - * @see io.opentracing.log.Field - * @param fields One or more Field instances + * @param fields key:value log fields. Tracer implementations are expected to support String, numeric, and boolean + * values; some may also support arbitrary Objects. * @return the Span, for chaining */ - Span log(Field... fields); + Span log(Map fields); + /** - * Like log(Field...), but with an explicit timestamp. + * Like log(Map<String, Object>), but with an explicit timestamp. * - * @see io.opentracing.log.Field * @param timestampMicroseconds The explicit timestamp for the log record. Must be greater than or equal to the * Span's start timestamp. - * @param fields One or more Field instances + * @param fields key:value log fields. Tracer implementations are expected to support String, numeric, and boolean + * values; some may also support arbitrary Objects. * @return the Span, for chaining */ - Span log(long timestampMicroseconds, Field... fields); + Span log(long timestampMicroseconds, Map fields); /** * Sets a baggage item in the Span (and its SpanContext) as a key/value pair. diff --git a/opentracing-api/src/main/java/io/opentracing/log/Field.java b/opentracing-api/src/main/java/io/opentracing/log/Field.java deleted file mode 100644 index 2924c5c5..00000000 --- a/opentracing-api/src/main/java/io/opentracing/log/Field.java +++ /dev/null @@ -1,46 +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 io.opentracing.log; - -/** - * Field represents a single key:value pair in a Span.log(...) call. - * - * The key must always be a String. All Tracer implementations must support bool, numeric, and String values; some may - * also support arbitrary Object values. - */ -public class Field { - private final String key; - private final V value; - - /** - * Instantiate an (immutable) Field of value type V - * - * @param key the Field's key; an unrestricted String - * @param value the Field's value; all Tracer implementations should support String, numeric, and bool values. - * Some may also support Object values. - * @param the value type for the returned Field instance - * @return a Field suitable for Span.log(...) invocations - */ - public static Field of(String key, V value) { - return new Field(key, value); - } - - public String key() { return key; } - public V value() { return value; } - - Field(String key, V value) { - this.key = key; - this.value = value; - } -} diff --git a/opentracing-api/src/test/java/io/opentracing/PlaygroundTest.java b/opentracing-api/src/test/java/io/opentracing/PlaygroundTest.java deleted file mode 100644 index 6f2df202..00000000 --- a/opentracing-api/src/test/java/io/opentracing/PlaygroundTest.java +++ /dev/null @@ -1,37 +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 io.opentracing; - -import java.util.Arrays; -import java.util.concurrent.CompletableFuture; -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -public final class PlaygroundTest { - - @Test - public void playground() { - - // Eventhough src/main is Java 7, we can use Java 8 types in tests - CompletableFuture fooCompleted = CompletableFuture.completedFuture("foo"); - assertThat(fooCompleted).isCompleted(); - - assertThat(Arrays.asList("foo", "bar")) - .filteredOn("bar"::equals) // We can use method references - .filteredOn(e -> !e.equals("foo")) // We can also use lambdas - .containsOnly("bar"); - - } -} diff --git a/opentracing-impl-java8/src/main/java/io/opentracing/AbstractSpan.java b/opentracing-impl-java8/src/main/java/io/opentracing/AbstractSpan.java index 3e481a2d..15e3e224 100644 --- a/opentracing-impl-java8/src/main/java/io/opentracing/AbstractSpan.java +++ b/opentracing-impl-java8/src/main/java/io/opentracing/AbstractSpan.java @@ -13,8 +13,6 @@ */ package io.opentracing; -import io.opentracing.log.Field; - import java.time.Duration; import java.time.Instant; import java.util.*; @@ -125,35 +123,36 @@ public final Map getBaggage() { } @Override - public final Span log(Field... fields) { + public final Span log(Map fields) { return log(System.nanoTime() / 1000, fields); } @Override - public final Span log(long timestampMicros, Field... fields) { + public final Span log(long timestampMicros, Map fields) { Instant timestamp = Instant.ofEpochSecond(timestampMicros / 1000000, (timestampMicros % 1000000) * 1000); logs.add(new LogData(timestamp, fields)); return this; } @Override - public final Span log(String message, /* @Nullable */ Object payload) { + public final Span log(String event, /* @Nullable */ Object payload) { Instant now = Instant.now(); return log( TimeUnit.SECONDS.toMicros(now.getEpochSecond()) + TimeUnit.NANOSECONDS.toMicros(now.getNano()), - message, + event, payload); } @Override - public final Span log(long timestampMicros, String message, /* @Nullable */ Object payload) { + public final Span log(long timestampMicros, String event, /* @Nullable */ Object payload) { Instant timestamp = Instant.ofEpochSecond(timestampMicros / 1000000, (timestampMicros % 1000000) * 1000); - if (payload == null) { - logs.add(new LogData(timestamp, Field.of("message", message))); - } else { - logs.add(new LogData(timestamp, Field.of("message", message), Field.of("payload", payload))); + Map fields = new HashMap<>(); + fields.put("event", event); + if (payload != null) { + fields.put("payload", payload); } + logs.add(new LogData(timestamp, fields)); return this; } @@ -163,11 +162,11 @@ public final List getLogs() { final class LogData { private final Instant time; - private final List fields; + private final Map fields; - LogData(Instant time, Field... fields) { + LogData(Instant time, Map fields) { this.time = time; - this.fields = Arrays.asList(fields); + this.fields = fields; } } } diff --git a/opentracing-impl/src/main/java/io/opentracing/NoopSpan.java b/opentracing-impl/src/main/java/io/opentracing/NoopSpan.java index 9d4e719a..58400f88 100644 --- a/opentracing-impl/src/main/java/io/opentracing/NoopSpan.java +++ b/opentracing-impl/src/main/java/io/opentracing/NoopSpan.java @@ -13,8 +13,6 @@ */ package io.opentracing; -import io.opentracing.log.Field; - import java.util.Collections; import java.util.Map; @@ -61,10 +59,10 @@ public Span setTag(String key, Number value) { } @Override - public Span log(Field... fields) { return this; } + public Span log(Map fields) { return this; } @Override - public Span log(long timestampMicroseconds, Field... fields) { return this; } + public Span log(long timestampMicroseconds, Map fields) { return this; } @Override public Span log(String eventName, Object payload) { diff --git a/opentracing-mock/src/main/java/io/opentracing/mock/MockSpan.java b/opentracing-mock/src/main/java/io/opentracing/mock/MockSpan.java index a5a42bc1..c3ddec46 100644 --- a/opentracing-mock/src/main/java/io/opentracing/mock/MockSpan.java +++ b/opentracing-mock/src/main/java/io/opentracing/mock/MockSpan.java @@ -18,7 +18,6 @@ import io.opentracing.Span; import io.opentracing.SpanContext; -import io.opentracing.log.Field; /** * MockSpans are created via MockTracer.buildSpan(...), but they are also returned via calls to @@ -123,12 +122,12 @@ public synchronized Span setTag(String key, Number value) { } @Override - public final Span log(Field... fields) { + public final Span log(Map fields) { long nowMicros = System.nanoTime() / 1000; return log(nowMicros, fields); } @Override - public final Span log(long timestampMicros, Field... fields) { + public final Span log(long timestampMicros, Map fields) { this.logEntries.add(new LogEntry(timestampMicros, fields)); return this; } @@ -140,11 +139,12 @@ public Span log(String eventName, Object payload) { @Override public synchronized Span log(long timestampMicroseconds, String eventName, Object payload) { - if (payload == null) { - return this.log(timestampMicroseconds, Field.of("event", eventName)); - } else { - return this.log(timestampMicroseconds, Field.of("event", eventName), Field.of("payload", payload)); + Map fields = new HashMap<>(); + fields.put("event", eventName); + if (payload != null) { + fields.put("payload", payload); } + return this.log(timestampMicroseconds, fields); } @Override @@ -204,18 +204,18 @@ public Iterable> baggageItems() { public static final class LogEntry { private final long timestampMicros; - private final List fields; + private final Map fields; - public LogEntry(long timestampMicros, Field... fields) { + public LogEntry(long timestampMicros, Map fields) { this.timestampMicros = timestampMicros; - this.fields = Arrays.asList(fields); + this.fields = fields; } public long timestampMicros() { return timestampMicros; } - public List fields() { + public Map fields() { return fields; } } diff --git a/opentracing-mock/src/test/java/io/opentracing/mock/MockTracerTest.java b/opentracing-mock/src/test/java/io/opentracing/mock/MockTracerTest.java index 3724db65..06212727 100644 --- a/opentracing-mock/src/test/java/io/opentracing/mock/MockTracerTest.java +++ b/opentracing-mock/src/test/java/io/opentracing/mock/MockTracerTest.java @@ -14,9 +14,9 @@ package io.opentracing.mock; import io.opentracing.Span; -import io.opentracing.log.Field; import org.junit.Test; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -35,7 +35,10 @@ public void testRootSpan() { // Old style logging: span.log(1001, "event name", tracer); // New style logging: - span.log(1002, Field.of("f1", 4), Field.of("f2", "two")); + Map fields = new HashMap<>(); + fields.put("f1", 4); + fields.put("f2", "two"); + span.log(1002, fields); span.finish(2000); } List finishedSpans = tracer.finishedSpans(); @@ -58,18 +61,14 @@ public void testRootSpan() { { MockSpan.LogEntry log = logs.get(0); assertEquals(1001, log.timestampMicros()); - assertEquals("event", log.fields().get(0).key()); - assertEquals("event name", log.fields().get(0).value()); - assertEquals("payload", log.fields().get(1).key()); - assertEquals(tracer, log.fields().get(1).value()); + assertEquals("event name", log.fields().get("event")); + assertEquals(tracer, log.fields().get("payload")); } { MockSpan.LogEntry log = logs.get(1); assertEquals(1002, log.timestampMicros()); - assertEquals("f1", log.fields().get(0).key()); - assertEquals(4, log.fields().get(0).value()); - assertEquals("f2", log.fields().get(1).key()); - assertEquals("two", log.fields().get(1).value()); + assertEquals(4, log.fields().get("f1")); + assertEquals("two", log.fields().get("f2")); } } From ab1d3ed00bcc20fe375884769dd168eb24e320db Mon Sep 17 00:00:00 2001 From: Ben Sigelman Date: Wed, 21 Sep 2016 21:04:46 -0700 Subject: [PATCH 07/12] Add a better deprecation message --- opentracing-api/src/main/java/io/opentracing/Span.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/opentracing-api/src/main/java/io/opentracing/Span.java b/opentracing-api/src/main/java/io/opentracing/Span.java index 46f487df..c12432a3 100644 --- a/opentracing-api/src/main/java/io/opentracing/Span.java +++ b/opentracing-api/src/main/java/io/opentracing/Span.java @@ -124,11 +124,13 @@ public interface Span extends AutoCloseable { Span setOperationName(String operationName); /** - * DEPRECATED + * @deprecated use {@link #log(Map)} like this + * {@code span.log(Map.of("event", "timeout", "millis", 1500))} **/ Span log(String eventName, /* @Nullable */ Object payload); /** - * DEPRECATED + * @deprecated use {@link #log(Map)} like this + * {@code span.log(timestampMicroseconds, Map.of("event", "timeout", "millis", 1500))} **/ Span log(long timestampMicroseconds, String eventName, /* @Nullable */ Object payload); } From 0e99d9e7d5f952d7ab4fe17b86aae2cbc69fa5d6 Mon Sep 17 00:00:00 2001 From: Ben Sigelman Date: Wed, 21 Sep 2016 21:17:48 -0700 Subject: [PATCH 08/12] Add more betterer comments and more accurate types --- .../src/main/java/io/opentracing/Span.java | 12 ++++++++---- .../src/main/java/io/opentracing/AbstractSpan.java | 8 ++++---- .../src/main/java/io/opentracing/NoopSpan.java | 4 ++-- .../src/main/java/io/opentracing/mock/MockSpan.java | 10 +++++----- 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/opentracing-api/src/main/java/io/opentracing/Span.java b/opentracing-api/src/main/java/io/opentracing/Span.java index c12432a3..be8df014 100644 --- a/opentracing-api/src/main/java/io/opentracing/Span.java +++ b/opentracing-api/src/main/java/io/opentracing/Span.java @@ -83,7 +83,7 @@ public interface Span extends AutoCloseable { * values; some may also support arbitrary Objects. * @return the Span, for chaining */ - Span log(Map fields); + Span log(Map fields); /** * Like log(Map<String, Object>), but with an explicit timestamp. @@ -94,7 +94,7 @@ public interface Span extends AutoCloseable { * values; some may also support arbitrary Objects. * @return the Span, for chaining */ - Span log(long timestampMicroseconds, Map fields); + Span log(long timestampMicroseconds, Map fields); /** * Sets a baggage item in the Span (and its SpanContext) as a key/value pair. @@ -125,12 +125,16 @@ public interface Span extends AutoCloseable { /** * @deprecated use {@link #log(Map)} like this - * {@code span.log(Map.of("event", "timeout", "millis", 1500))} + * {@code span.log(Map.of("event", "timeout"))} + * or + * {@code span.log(timestampMicroseconds, Map.of("event", "exception", "payload", stackTrace))} **/ Span log(String eventName, /* @Nullable */ Object payload); /** * @deprecated use {@link #log(Map)} like this - * {@code span.log(timestampMicroseconds, Map.of("event", "timeout", "millis", 1500))} + * {@code span.log(timestampMicroseconds, Map.of("event", "timeout"))} + * or + * {@code span.log(timestampMicroseconds, Map.of("event", "exception", "payload", stackTrace))} **/ Span log(long timestampMicroseconds, String eventName, /* @Nullable */ Object payload); } diff --git a/opentracing-impl-java8/src/main/java/io/opentracing/AbstractSpan.java b/opentracing-impl-java8/src/main/java/io/opentracing/AbstractSpan.java index 15e3e224..fcd854e0 100644 --- a/opentracing-impl-java8/src/main/java/io/opentracing/AbstractSpan.java +++ b/opentracing-impl-java8/src/main/java/io/opentracing/AbstractSpan.java @@ -123,12 +123,12 @@ public final Map getBaggage() { } @Override - public final Span log(Map fields) { + public final Span log(Map fields) { return log(System.nanoTime() / 1000, fields); } @Override - public final Span log(long timestampMicros, Map fields) { + public final Span log(long timestampMicros, Map fields) { Instant timestamp = Instant.ofEpochSecond(timestampMicros / 1000000, (timestampMicros % 1000000) * 1000); logs.add(new LogData(timestamp, fields)); return this; @@ -162,9 +162,9 @@ public final List getLogs() { final class LogData { private final Instant time; - private final Map fields; + private final Map fields; - LogData(Instant time, Map fields) { + LogData(Instant time, Map fields) { this.time = time; this.fields = fields; } diff --git a/opentracing-impl/src/main/java/io/opentracing/NoopSpan.java b/opentracing-impl/src/main/java/io/opentracing/NoopSpan.java index 58400f88..367dce16 100644 --- a/opentracing-impl/src/main/java/io/opentracing/NoopSpan.java +++ b/opentracing-impl/src/main/java/io/opentracing/NoopSpan.java @@ -59,10 +59,10 @@ public Span setTag(String key, Number value) { } @Override - public Span log(Map fields) { return this; } + public Span log(Map fields) { return this; } @Override - public Span log(long timestampMicroseconds, Map fields) { return this; } + public Span log(long timestampMicroseconds, Map fields) { return this; } @Override public Span log(String eventName, Object payload) { diff --git a/opentracing-mock/src/main/java/io/opentracing/mock/MockSpan.java b/opentracing-mock/src/main/java/io/opentracing/mock/MockSpan.java index c3ddec46..4a2311dc 100644 --- a/opentracing-mock/src/main/java/io/opentracing/mock/MockSpan.java +++ b/opentracing-mock/src/main/java/io/opentracing/mock/MockSpan.java @@ -122,12 +122,12 @@ public synchronized Span setTag(String key, Number value) { } @Override - public final Span log(Map fields) { + public final Span log(Map fields) { long nowMicros = System.nanoTime() / 1000; return log(nowMicros, fields); } @Override - public final Span log(long timestampMicros, Map fields) { + public final Span log(long timestampMicros, Map fields) { this.logEntries.add(new LogEntry(timestampMicros, fields)); return this; } @@ -204,9 +204,9 @@ public Iterable> baggageItems() { public static final class LogEntry { private final long timestampMicros; - private final Map fields; + private final Map fields; - public LogEntry(long timestampMicros, Map fields) { + public LogEntry(long timestampMicros, Map fields) { this.timestampMicros = timestampMicros; this.fields = fields; } @@ -215,7 +215,7 @@ public long timestampMicros() { return timestampMicros; } - public Map fields() { + public Map fields() { return fields; } } From e0821b27d1f3c0479adf3dbc5dc8eb7fc6d6c498 Mon Sep 17 00:00:00 2001 From: Ben Sigelman Date: Thu, 22 Sep 2016 16:35:51 -0700 Subject: [PATCH 09/12] Standardize two common Span.log patterns --- .../src/main/java/io/opentracing/Logs.java | 56 +++++++++++++++++++ .../src/main/java/io/opentracing/Span.java | 13 +++-- .../test/java/io/opentracing/LogsTest.java | 46 +++++++++++++++ 3 files changed, 111 insertions(+), 4 deletions(-) create mode 100644 opentracing-api/src/main/java/io/opentracing/Logs.java create mode 100644 opentracing-api/src/test/java/io/opentracing/LogsTest.java diff --git a/opentracing-api/src/main/java/io/opentracing/Logs.java b/opentracing-api/src/main/java/io/opentracing/Logs.java new file mode 100644 index 00000000..b95f899d --- /dev/null +++ b/opentracing-api/src/main/java/io/opentracing/Logs.java @@ -0,0 +1,56 @@ +/** + * 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 io.opentracing; + +import java.util.HashMap; +import java.util.Map; + +/** + * The "Logs" class/container standardizes and simplifies common @link{io.opentracing.Span#log(Map)} patterns. + * + * @see io.opentracing.Span#log(Map) + */ +public final class Logs { + /** + * EVENT_KEY identifies a String log value that serves as a stable identifier for an event in a Span's lifecycle. + */ + public static final String EVENT_KEY = "event"; + + /** + * MESSAGE_KEY identifies a String log value that's human-readable and descriptive. Messages need not be stable. + */ + public static final String MESSAGE_KEY = "message"; + + /** + * @param eventName the value for the "event" key in the log map + * @return a Map suitable for use with @link{io.opentracing.Span#log(Map)} + * @see Logs#EVENT_KEY + */ + public static Map event(String eventName) { + Map rval = new HashMap(); + rval.put(EVENT_KEY, eventName); + return rval; + } + + /** + * @param messageText the value for the "message" key in the log map + * @return a Map suitable for use with @link{io.opentracing.Span#log(Map)} + * @see Logs#MESSAGE_KEY + */ + public static Map message(String messageText) { + Map rval = new HashMap(); + rval.put(MESSAGE_KEY, messageText); + return rval; + } +} diff --git a/opentracing-api/src/main/java/io/opentracing/Span.java b/opentracing-api/src/main/java/io/opentracing/Span.java index be8df014..74aca7b5 100644 --- a/opentracing-api/src/main/java/io/opentracing/Span.java +++ b/opentracing-api/src/main/java/io/opentracing/Span.java @@ -73,10 +73,15 @@ public interface Span extends AutoCloseable { *
{@code
      span.log(
          ImmutableMap.Builder()
-             .put("event", "soft error")
-             .put("type", "cache timeout")
-             .put("waited.millis", 1500)
-             .build());
+         .put("event", "soft error")
+         .put("type", "cache timeout")
+         .put("waited.millis", 1500)
+         .build());
+     }
+ * + *

Also consider the @{link io.opentracing.Logs} helper: + *

{@code
+     span.log(Logs.event("soft error"));
      }
* * @param fields key:value log fields. Tracer implementations are expected to support String, numeric, and boolean diff --git a/opentracing-api/src/test/java/io/opentracing/LogsTest.java b/opentracing-api/src/test/java/io/opentracing/LogsTest.java new file mode 100644 index 00000000..b1fba7f9 --- /dev/null +++ b/opentracing-api/src/test/java/io/opentracing/LogsTest.java @@ -0,0 +1,46 @@ +/** + * 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 io.opentracing; + +import io.opentracing.Logs; +import io.opentracing.Span; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +public class LogsTest { + @Test + public void testEvent() { + Boolean value = true; + Map expected = new HashMap<>(); + expected.put("event", "foo"); + Span span = mock(Span.class); + span.log(Logs.event("foo")); + verify(span).log(expected); + } + + @Test + public void testMessage() { + Boolean value = true; + Map expected = new HashMap<>(); + expected.put("message", "the quick brown fox"); + Span span = mock(Span.class); + span.log(Logs.message("the quick brown fox")); + verify(span).log(expected); + } +} From 505eb4a78ebe31ef9c8b12938c430543b2ce382d Mon Sep 17 00:00:00 2001 From: Ben Sigelman Date: Thu, 22 Sep 2016 22:08:13 -0700 Subject: [PATCH 10/12] Add a log([ts,] eventName) shortcut Remove `io.opentracing.Logs` for now since it's not doing anything useful anymore. --- .../src/main/java/io/opentracing/Logs.java | 56 ------------------- .../src/main/java/io/opentracing/Span.java | 49 +++++++++++++--- .../test/java/io/opentracing/LogsTest.java | 46 --------------- .../java/io/opentracing/AbstractSpan.java | 10 ++++ .../main/java/io/opentracing/NoopSpan.java | 34 +++++------ .../java/io/opentracing/mock/MockSpan.java | 10 ++++ .../io/opentracing/mock/MockTracerTest.java | 8 ++- 7 files changed, 80 insertions(+), 133 deletions(-) delete mode 100644 opentracing-api/src/main/java/io/opentracing/Logs.java delete mode 100644 opentracing-api/src/test/java/io/opentracing/LogsTest.java diff --git a/opentracing-api/src/main/java/io/opentracing/Logs.java b/opentracing-api/src/main/java/io/opentracing/Logs.java deleted file mode 100644 index b95f899d..00000000 --- a/opentracing-api/src/main/java/io/opentracing/Logs.java +++ /dev/null @@ -1,56 +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 io.opentracing; - -import java.util.HashMap; -import java.util.Map; - -/** - * The "Logs" class/container standardizes and simplifies common @link{io.opentracing.Span#log(Map)} patterns. - * - * @see io.opentracing.Span#log(Map) - */ -public final class Logs { - /** - * EVENT_KEY identifies a String log value that serves as a stable identifier for an event in a Span's lifecycle. - */ - public static final String EVENT_KEY = "event"; - - /** - * MESSAGE_KEY identifies a String log value that's human-readable and descriptive. Messages need not be stable. - */ - public static final String MESSAGE_KEY = "message"; - - /** - * @param eventName the value for the "event" key in the log map - * @return a Map suitable for use with @link{io.opentracing.Span#log(Map)} - * @see Logs#EVENT_KEY - */ - public static Map event(String eventName) { - Map rval = new HashMap(); - rval.put(EVENT_KEY, eventName); - return rval; - } - - /** - * @param messageText the value for the "message" key in the log map - * @return a Map suitable for use with @link{io.opentracing.Span#log(Map)} - * @see Logs#MESSAGE_KEY - */ - public static Map message(String messageText) { - Map rval = new HashMap(); - rval.put(MESSAGE_KEY, messageText); - return rval; - } -} diff --git a/opentracing-api/src/main/java/io/opentracing/Span.java b/opentracing-api/src/main/java/io/opentracing/Span.java index 74aca7b5..c7c10b10 100644 --- a/opentracing-api/src/main/java/io/opentracing/Span.java +++ b/opentracing-api/src/main/java/io/opentracing/Span.java @@ -69,6 +69,8 @@ public interface Span extends AutoCloseable { /** * Log key:value pairs to the Span with the current walltime timestamp. * + * CAUTIONARY NOTE: not all Tracer implementations support key:value log fields end-to-end. Caveat emptor. + * *

A contrived example (using Guava, which is not required): *

{@code
      span.log(
@@ -79,28 +81,57 @@ public interface Span extends AutoCloseable {
          .build());
      }
* - *

Also consider the @{link io.opentracing.Logs} helper: - *

{@code
-     span.log(Logs.event("soft error"));
-     }
- * - * @param fields key:value log fields. Tracer implementations are expected to support String, numeric, and boolean - * values; some may also support arbitrary Objects. + * @param fields key:value log fields. Tracer implementations should support String, numeric, and boolean values; + * some may also support arbitrary Objects. * @return the Span, for chaining + * @see Span#log(String) */ Span log(Map fields); /** * Like log(Map<String, Object>), but with an explicit timestamp. * + * CAUTIONARY NOTE: not all Tracer implementations support key:value log fields end-to-end. Caveat emptor. + * * @param timestampMicroseconds The explicit timestamp for the log record. Must be greater than or equal to the * Span's start timestamp. - * @param fields key:value log fields. Tracer implementations are expected to support String, numeric, and boolean - * values; some may also support arbitrary Objects. + * @param fields key:value log fields. Tracer implementations should support String, numeric, and boolean values; + * some may also support arbitrary Objects. * @return the Span, for chaining + * @see Span#log(long, String) */ Span log(long timestampMicroseconds, Map fields); + /** + * Record an event at the current walltime timestamp. + * + * Shorthand for + * + *
{@code
+     span.log(Collections.singletonMap("event", event));
+     }
+ * + * @param event the event value; often a stable identifier for a moment in the Span lifecycle + * @return the Span, for chaining + */ + Span log(String event); + + /** + * Record an event at a specific timestamp. + * + * Shorthand for + * + *
{@code
+     span.log(timestampMicroseconds, Collections.singletonMap("event", event));
+     }
+ * + * @param timestampMicroseconds The explicit timestamp for the log record. Must be greater than or equal to the + * Span's start timestamp. + * @param event the event value; often a stable identifier for a moment in the Span lifecycle + * @return the Span, for chaining + */ + Span log(long timestampMicroseconds, String event); + /** * Sets a baggage item in the Span (and its SpanContext) as a key/value pair. * diff --git a/opentracing-api/src/test/java/io/opentracing/LogsTest.java b/opentracing-api/src/test/java/io/opentracing/LogsTest.java deleted file mode 100644 index b1fba7f9..00000000 --- a/opentracing-api/src/test/java/io/opentracing/LogsTest.java +++ /dev/null @@ -1,46 +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 io.opentracing; - -import io.opentracing.Logs; -import io.opentracing.Span; -import org.junit.Test; - -import java.util.HashMap; -import java.util.Map; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -public class LogsTest { - @Test - public void testEvent() { - Boolean value = true; - Map expected = new HashMap<>(); - expected.put("event", "foo"); - Span span = mock(Span.class); - span.log(Logs.event("foo")); - verify(span).log(expected); - } - - @Test - public void testMessage() { - Boolean value = true; - Map expected = new HashMap<>(); - expected.put("message", "the quick brown fox"); - Span span = mock(Span.class); - span.log(Logs.message("the quick brown fox")); - verify(span).log(expected); - } -} diff --git a/opentracing-impl-java8/src/main/java/io/opentracing/AbstractSpan.java b/opentracing-impl-java8/src/main/java/io/opentracing/AbstractSpan.java index fcd854e0..87b932a3 100644 --- a/opentracing-impl-java8/src/main/java/io/opentracing/AbstractSpan.java +++ b/opentracing-impl-java8/src/main/java/io/opentracing/AbstractSpan.java @@ -122,6 +122,16 @@ public final Map getBaggage() { return Collections.unmodifiableMap(baggage); } + @Override + public final Span log(String event) { + return log(System.nanoTime() / 1000, event); + } + + @Override + public final Span log(long timestampMicros, String event) { + return log(System.nanoTime() / 1000, Collections.singletonMap("event", event)); + } + @Override public final Span log(Map fields) { return log(System.nanoTime() / 1000, fields); diff --git a/opentracing-impl/src/main/java/io/opentracing/NoopSpan.java b/opentracing-impl/src/main/java/io/opentracing/NoopSpan.java index 367dce16..03c6aa99 100644 --- a/opentracing-impl/src/main/java/io/opentracing/NoopSpan.java +++ b/opentracing-impl/src/main/java/io/opentracing/NoopSpan.java @@ -39,24 +39,16 @@ public void finish() {} public void finish(long finishMicros) {} @Override - public void close() { - finish(); - } + public void close() { finish(); } @Override - public Span setTag(String key, String value) { - return this; - } + public Span setTag(String key, String value) { return this; } @Override - public Span setTag(String key, boolean value) { - return this; - } + public Span setTag(String key, boolean value) { return this; } @Override - public Span setTag(String key, Number value) { - return this; - } + public Span setTag(String key, Number value) { return this; } @Override public Span log(Map fields) { return this; } @@ -65,14 +57,16 @@ public Span setTag(String key, Number value) { public Span log(long timestampMicroseconds, Map fields) { return this; } @Override - public Span log(String eventName, Object payload) { - return this; - } + public Span log(String event) { return this; } @Override - public Span log(long timestampMicroseconds, String eventName, Object payload) { - return this; - } + public Span log(long timestampMicroseconds, String event) { return this; } + + @Override + public Span log(String eventName, Object payload) { return this; } + + @Override + public Span log(long timestampMicroseconds, String eventName, Object payload) { return this; } @Override public Span setBaggageItem(String key, String value) { return this; } @@ -81,8 +75,6 @@ public Span log(long timestampMicroseconds, String eventName, Object payload) { public String getBaggageItem(String key) { return null; } @Override - public Span setOperationName(String operationName) { - return this; - } + public Span setOperationName(String operationName) { return this; } } diff --git a/opentracing-mock/src/main/java/io/opentracing/mock/MockSpan.java b/opentracing-mock/src/main/java/io/opentracing/mock/MockSpan.java index 4a2311dc..cea0aa76 100644 --- a/opentracing-mock/src/main/java/io/opentracing/mock/MockSpan.java +++ b/opentracing-mock/src/main/java/io/opentracing/mock/MockSpan.java @@ -132,6 +132,16 @@ public final Span log(long timestampMicros, Map fields) { return this; } + @Override + public Span log(String event) { + return this.log(System.nanoTime() / 1000, event); + } + + @Override + public Span log(long timestampMicroseconds, String event) { + return this.log(timestampMicroseconds, Collections.singletonMap("event", event)); + } + @Override public Span log(String eventName, Object payload) { return this.log(System.nanoTime() / 1000, eventName, payload); diff --git a/opentracing-mock/src/test/java/io/opentracing/mock/MockTracerTest.java b/opentracing-mock/src/test/java/io/opentracing/mock/MockTracerTest.java index 06212727..178c0caf 100644 --- a/opentracing-mock/src/test/java/io/opentracing/mock/MockTracerTest.java +++ b/opentracing-mock/src/test/java/io/opentracing/mock/MockTracerTest.java @@ -39,6 +39,7 @@ public void testRootSpan() { fields.put("f1", 4); fields.put("f2", "two"); span.log(1002, fields); + span.log(1003, "event name"); span.finish(2000); } List finishedSpans = tracer.finishedSpans(); @@ -57,7 +58,7 @@ public void testRootSpan() { assertEquals(7, tags.get("int")); assertEquals("foo", tags.get("string")); List logs = finishedSpan.logEntries(); - assertEquals(2, logs.size()); + assertEquals(3, logs.size()); { MockSpan.LogEntry log = logs.get(0); assertEquals(1001, log.timestampMicros()); @@ -70,6 +71,11 @@ public void testRootSpan() { assertEquals(4, log.fields().get("f1")); assertEquals("two", log.fields().get("f2")); } + { + MockSpan.LogEntry log = logs.get(2); + assertEquals(1003, log.timestampMicros()); + assertEquals("event name", log.fields().get("event")); + } } @Test From 027764f78331d35e248c98c9b1a92917076291a8 Mon Sep 17 00:00:00 2001 From: Ben Sigelman Date: Fri, 23 Sep 2016 13:03:33 -0700 Subject: [PATCH 11/12] Remove problematic nanoTime() calls --- .../src/main/java/io/opentracing/AbstractSpan.java | 11 ++++++++--- .../src/main/java/io/opentracing/mock/MockSpan.java | 13 ++++++++----- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/opentracing-impl-java8/src/main/java/io/opentracing/AbstractSpan.java b/opentracing-impl-java8/src/main/java/io/opentracing/AbstractSpan.java index 87b932a3..b6a5e344 100644 --- a/opentracing-impl-java8/src/main/java/io/opentracing/AbstractSpan.java +++ b/opentracing-impl-java8/src/main/java/io/opentracing/AbstractSpan.java @@ -124,17 +124,17 @@ public final Map getBaggage() { @Override public final Span log(String event) { - return log(System.nanoTime() / 1000, event); + return log(nowMicros(), event); } @Override public final Span log(long timestampMicros, String event) { - return log(System.nanoTime() / 1000, Collections.singletonMap("event", event)); + return log(timestampMicros, Collections.singletonMap("event", event)); } @Override public final Span log(Map fields) { - return log(System.nanoTime() / 1000, fields); + return log(nowMicros(), fields); } @Override @@ -179,4 +179,9 @@ final class LogData { this.fields = fields; } } + + static long nowMicros() { + Instant now = Instant.now(); + return (now.getEpochSecond() * 1000000) + (now.getNano() / 1000); + } } diff --git a/opentracing-mock/src/main/java/io/opentracing/mock/MockSpan.java b/opentracing-mock/src/main/java/io/opentracing/mock/MockSpan.java index cea0aa76..ca062cb4 100644 --- a/opentracing-mock/src/main/java/io/opentracing/mock/MockSpan.java +++ b/opentracing-mock/src/main/java/io/opentracing/mock/MockSpan.java @@ -89,7 +89,7 @@ public synchronized MockContext context() { @Override public void finish() { - this.finish(System.nanoTime() / 1000); + this.finish(nowMicros()); } @Override @@ -123,8 +123,7 @@ public synchronized Span setTag(String key, Number value) { @Override public final Span log(Map fields) { - long nowMicros = System.nanoTime() / 1000; - return log(nowMicros, fields); + return log(nowMicros(), fields); } @Override public final Span log(long timestampMicros, Map fields) { @@ -134,7 +133,7 @@ public final Span log(long timestampMicros, Map fields) { @Override public Span log(String event) { - return this.log(System.nanoTime() / 1000, event); + return this.log(nowMicros(), event); } @Override @@ -144,7 +143,7 @@ public Span log(long timestampMicroseconds, String event) { @Override public Span log(String eventName, Object payload) { - return this.log(System.nanoTime() / 1000, eventName, payload); + return this.log(nowMicros(), eventName, payload); } @Override @@ -253,4 +252,8 @@ public long timestampMicros() { static long nextId() { return nextId.addAndGet(1); } + + static long nowMicros() { + return System.currentTimeMillis() * 1000; + } } From 7c432f862e697701dacf7b92bfa915e26c4c4379 Mon Sep 17 00:00:00 2001 From: Ben Sigelman Date: Fri, 23 Sep 2016 13:15:50 -0700 Subject: [PATCH 12/12] Boldify cautionary note --- opentracing-api/src/main/java/io/opentracing/Span.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/opentracing-api/src/main/java/io/opentracing/Span.java b/opentracing-api/src/main/java/io/opentracing/Span.java index c7c10b10..8dfc2b3d 100644 --- a/opentracing-api/src/main/java/io/opentracing/Span.java +++ b/opentracing-api/src/main/java/io/opentracing/Span.java @@ -69,7 +69,8 @@ public interface Span extends AutoCloseable { /** * Log key:value pairs to the Span with the current walltime timestamp. * - * CAUTIONARY NOTE: not all Tracer implementations support key:value log fields end-to-end. Caveat emptor. + *

CAUTIONARY NOTE: not all Tracer implementations support key:value log fields end-to-end. + * Caveat emptor. * *

A contrived example (using Guava, which is not required): *

{@code
@@ -91,7 +92,8 @@ public interface Span extends AutoCloseable {
     /**
      * Like log(Map<String, Object>), but with an explicit timestamp.
      *
-     * CAUTIONARY NOTE: not all Tracer implementations support key:value log fields end-to-end. Caveat emptor.
+     * 

CAUTIONARY NOTE: not all Tracer implementations support key:value log fields end-to-end. + * Caveat emptor. * * @param timestampMicroseconds The explicit timestamp for the log record. Must be greater than or equal to the * Span's start timestamp.