diff --git a/opentracing-api/src/main/java/io/opentracing/Span.java b/opentracing-api/src/main/java/io/opentracing/Span.java
index 5961fcea..8dfc2b3d 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 java.util.Map;
+
/**
* Represents an in-flight span in the opentracing system.
*
@@ -65,25 +67,72 @@ 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.
+ *
+ *
fields);
+
+ /**
+ * Like log(Map<String, Object>), but with an explicit 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).
+ * CAUTIONARY NOTE: not all Tracer implementations support key:value log fields end-to-end.
+ * Caveat emptor.
*
- * The timestamp of this log event is the current time.
- **/
- Span log(String eventName, /* @Nullable */ Object payload);
+ * @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 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);
/**
- * Add a new log event to the Span, accepting an event name string and an optional structured payload argument.
+ * Record an event at 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).
+ * Shorthand for
*
- * 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);
+ * {@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.
@@ -111,4 +160,19 @@ public interface Span extends AutoCloseable {
* @return this Span instance, for chaining
*/
Span setOperationName(String operationName);
+
+ /**
+ * @deprecated use {@link #log(Map)} like this
+ * {@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"))}
+ * or
+ * {@code span.log(timestampMicroseconds, Map.of("event", "exception", "payload", stackTrace))}
+ **/
+ Span log(long timestampMicroseconds, String eventName, /* @Nullable */ Object payload);
}
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 2262d6fd..b6a5e344 100644
--- a/opentracing-impl-java8/src/main/java/io/opentracing/AbstractSpan.java
+++ b/opentracing-impl-java8/src/main/java/io/opentracing/AbstractSpan.java
@@ -15,11 +15,7 @@
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 {
@@ -127,18 +123,46 @@ public final Map getBaggage() {
}
@Override
- public final Span log(String message, /* @Nullable */ Object payload) {
+ public final Span log(String event) {
+ return log(nowMicros(), event);
+ }
+
+ @Override
+ public final Span log(long timestampMicros, String event) {
+ return log(timestampMicros, Collections.singletonMap("event", event));
+ }
+
+ @Override
+ public final Span log(Map fields) {
+ return log(nowMicros(), fields);
+ }
+
+ @Override
+ 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 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 instantMicroseconds, String message, /* @Nullable */ Object payload) {
- logs.add(new LogData(start, message, payload));
+ public final Span log(long timestampMicros, String event, /* @Nullable */ Object payload) {
+ Instant timestamp = Instant.ofEpochSecond(timestampMicros / 1000000, (timestampMicros % 1000000) * 1000);
+ Map fields = new HashMap<>();
+ fields.put("event", event);
+ if (payload != null) {
+ fields.put("payload", payload);
+ }
+ logs.add(new LogData(timestamp, fields));
return this;
}
@@ -148,13 +172,16 @@ public final List getLogs() {
final class LogData {
private final Instant time;
- private final String message;
- private final Object payload;
+ private final Map fields;
- LogData(Instant time, String message, Object payload) {
+ LogData(Instant time, Map fields) {
this.time = time;
- this.message = message;
- this.payload = payload;
+ this.fields = fields;
}
}
+
+ static long nowMicros() {
+ Instant now = Instant.now();
+ return (now.getEpochSecond() * 1000000) + (now.getNano() / 1000);
+ }
}
diff --git a/opentracing-impl/src/main/java/io/opentracing/NoopSpan.java b/opentracing-impl/src/main/java/io/opentracing/NoopSpan.java
index 2e09264f..03c6aa99 100644
--- a/opentracing-impl/src/main/java/io/opentracing/NoopSpan.java
+++ b/opentracing-impl/src/main/java/io/opentracing/NoopSpan.java
@@ -39,34 +39,34 @@ 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(String eventName, Object payload) {
- return this;
- }
+ public Span log(Map fields) { return this; }
@Override
- public Span log(long timestampMicroseconds, String eventName, Object payload) {
- return this;
- }
+ public Span log(long timestampMicroseconds, Map fields) { return this; }
+
+ @Override
+ public Span log(String event) { return this; }
+
+ @Override
+ 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; }
@@ -75,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 15944487..ca062cb4 100644
--- a/opentracing-mock/src/main/java/io/opentracing/mock/MockSpan.java
+++ b/opentracing-mock/src/main/java/io/opentracing/mock/MockSpan.java
@@ -13,10 +13,7 @@
*/
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;
@@ -92,7 +89,7 @@ public synchronized MockContext context() {
@Override
public void finish() {
- this.finish(System.nanoTime() / 1000);
+ this.finish(nowMicros());
}
@Override
@@ -124,15 +121,39 @@ public synchronized Span setTag(String key, Number value) {
return this;
}
+ @Override
+ public final Span log(Map fields) {
+ return log(nowMicros(), fields);
+ }
+ @Override
+ public final Span log(long timestampMicros, Map fields) {
+ this.logEntries.add(new LogEntry(timestampMicros, fields));
+ return this;
+ }
+
+ @Override
+ public Span log(String event) {
+ return this.log(nowMicros(), 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);
+ return this.log(nowMicros(), eventName, payload);
}
@Override
public synchronized Span log(long timestampMicroseconds, String eventName, Object payload) {
- this.logEntries.add(new LogEntry(timestampMicroseconds, eventName, payload));
- return this;
+ Map fields = new HashMap<>();
+ fields.put("event", eventName);
+ if (payload != null) {
+ fields.put("payload", payload);
+ }
+ return this.log(timestampMicroseconds, fields);
}
@Override
@@ -192,25 +213,19 @@ public Iterable> baggageItems() {
public static final class LogEntry {
private final long timestampMicros;
- private final String eventName;
- private final Object payload;
+ private final Map fields;
- public LogEntry(long timestampMicros, String eventName, Object payload) {
+ public LogEntry(long timestampMicros, Map fields) {
this.timestampMicros = timestampMicros;
- this.eventName = eventName;
- this.payload = payload;
+ this.fields = fields;
}
public long timestampMicros() {
return timestampMicros;
}
- public String eventName() {
- return eventName;
- }
-
- public Object payload() {
- return payload;
+ public Map fields() {
+ return fields;
}
}
@@ -237,4 +252,8 @@ public Object payload() {
static long nextId() {
return nextId.addAndGet(1);
}
+
+ static long nowMicros() {
+ return System.currentTimeMillis() * 1000;
+ }
}
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..178c0caf 100644
--- a/opentracing-mock/src/test/java/io/opentracing/mock/MockTracerTest.java
+++ b/opentracing-mock/src/test/java/io/opentracing/mock/MockTracerTest.java
@@ -16,6 +16,7 @@
import io.opentracing.Span;
import org.junit.Test;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -31,7 +32,14 @@ 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:
+ Map fields = new HashMap<>();
+ fields.put("f1", 4);
+ fields.put("f2", "two");
+ span.log(1002, fields);
+ span.log(1003, "event name");
span.finish(2000);
}
List finishedSpans = tracer.finishedSpans();
@@ -50,11 +58,24 @@ 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(3, logs.size());
+ {
+ MockSpan.LogEntry log = logs.get(0);
+ assertEquals(1001, log.timestampMicros());
+ assertEquals("event name", log.fields().get("event"));
+ assertEquals(tracer, log.fields().get("payload"));
+ }
+ {
+ MockSpan.LogEntry log = logs.get(1);
+ assertEquals(1002, log.timestampMicros());
+ 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