Remove Timestamp and change start/end times to use epoch nanos (#646)

Signed-off-by: Bogdan Drutu <bogdandrutu@gmail.com>
This commit is contained in:
Bogdan Drutu 2019-10-28 19:51:39 -07:00 committed by GitHub
parent 618e656e5f
commit ce1cd9c3bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 60 additions and 387 deletions

View File

@ -18,7 +18,6 @@ package io.opentelemetry.exporters.inmemory;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import io.opentelemetry.sdk.common.Timestamp;
import io.opentelemetry.sdk.trace.SpanData; import io.opentelemetry.sdk.trace.SpanData;
import io.opentelemetry.sdk.trace.TracerSdk; import io.opentelemetry.sdk.trace.TracerSdk;
import io.opentelemetry.sdk.trace.export.SimpleSpansProcessor; import io.opentelemetry.sdk.trace.export.SimpleSpansProcessor;
@ -104,9 +103,9 @@ public class InMemorySpanExporterTest {
.setSpanId(io.opentelemetry.trace.SpanId.getInvalid()) .setSpanId(io.opentelemetry.trace.SpanId.getInvalid())
.setName("span") .setName("span")
.setKind(io.opentelemetry.trace.Span.Kind.SERVER) .setKind(io.opentelemetry.trace.Span.Kind.SERVER)
.setStartTimestamp(Timestamp.create(100, 100)) .setStartEpochNanos(100_000_000_100L)
.setStatus(io.opentelemetry.trace.Status.OK) .setStatus(io.opentelemetry.trace.Status.OK)
.setEndTimestamp(Timestamp.create(200, 200)) .setEndEpochNanos(200_000_000_200L)
.build(); .build();
} }
} }

View File

@ -69,11 +69,10 @@ final class Adapter {
target.setTraceId(TraceProtoUtils.toProtoTraceId(span.getTraceId())); target.setTraceId(TraceProtoUtils.toProtoTraceId(span.getTraceId()));
target.setSpanId(TraceProtoUtils.toProtoSpanId(span.getSpanId())); target.setSpanId(TraceProtoUtils.toProtoSpanId(span.getSpanId()));
target.setOperationName(span.getName()); target.setOperationName(span.getName());
Timestamp startTimestamp = TraceProtoUtils.toProtoTimestamp(span.getStartTimestamp()); Timestamp startTimestamp = Timestamps.fromNanos(span.getStartEpochNanos());
target.setStartTime(startTimestamp); target.setStartTime(startTimestamp);
target.setDuration( target.setDuration(
Timestamps.between( Timestamps.between(startTimestamp, Timestamps.fromNanos(span.getEndEpochNanos())));
startTimestamp, TraceProtoUtils.toProtoTimestamp(span.getEndTimestamp())));
target.addAllTags(toKeyValues(span.getAttributes())); target.addAllTags(toKeyValues(span.getAttributes()));
target.addAllLogs(toJaegerLogs(span.getTimedEvents())); target.addAllLogs(toJaegerLogs(span.getTimedEvents()));

View File

@ -22,9 +22,9 @@ import static org.junit.Assert.assertTrue;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.protobuf.util.Durations; import com.google.protobuf.util.Durations;
import com.google.protobuf.util.Timestamps;
import io.opentelemetry.exporters.jaeger.proto.api_v2.Model; import io.opentelemetry.exporters.jaeger.proto.api_v2.Model;
import io.opentelemetry.exporters.otprotocol.TraceProtoUtils; import io.opentelemetry.exporters.otprotocol.TraceProtoUtils;
import io.opentelemetry.sdk.common.Timestamp;
import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.trace.SpanData; import io.opentelemetry.sdk.trace.SpanData;
import io.opentelemetry.sdk.trace.SpanData.TimedEvent; import io.opentelemetry.sdk.trace.SpanData.TimedEvent;
@ -58,10 +58,8 @@ public class AdapterTest {
long duration = 900; // ms long duration = 900; // ms
long startMs = System.currentTimeMillis(); long startMs = System.currentTimeMillis();
long endMs = startMs + duration; long endMs = startMs + duration;
Timestamp startTime = toTimestamp(startMs);
Timestamp endTime = toTimestamp(endMs);
SpanData span = getSpanData(startTime, endTime); SpanData span = getSpanData(startMs, endMs);
List<SpanData> spans = Collections.singletonList(span); List<SpanData> spans = Collections.singletonList(span);
Collection<Model.Span> jaegerSpans = Adapter.toJaeger(spans); Collection<Model.Span> jaegerSpans = Adapter.toJaeger(spans);
@ -75,22 +73,15 @@ public class AdapterTest {
long duration = 900; // ms long duration = 900; // ms
long startMs = System.currentTimeMillis(); long startMs = System.currentTimeMillis();
long endMs = startMs + duration; long endMs = startMs + duration;
Timestamp startTime = toTimestamp(startMs);
Timestamp endTime = toTimestamp(endMs);
SpanData span = getSpanData(startTime, endTime); SpanData span = getSpanData(startMs, endMs);
// test // test
Model.Span jaegerSpan = Adapter.toJaeger(span); Model.Span jaegerSpan = Adapter.toJaeger(span);
assertEquals(TraceProtoUtils.toProtoTraceId(span.getTraceId()), jaegerSpan.getTraceId()); assertEquals(TraceProtoUtils.toProtoTraceId(span.getTraceId()), jaegerSpan.getTraceId());
assertEquals(TraceProtoUtils.toProtoSpanId(span.getSpanId()), jaegerSpan.getSpanId()); assertEquals(TraceProtoUtils.toProtoSpanId(span.getSpanId()), jaegerSpan.getSpanId());
assertEquals("GET /api/endpoint", jaegerSpan.getOperationName()); assertEquals("GET /api/endpoint", jaegerSpan.getOperationName());
assertEquals( assertEquals(Timestamps.fromMillis(startMs), jaegerSpan.getStartTime());
com.google.protobuf.Timestamp.newBuilder()
.setSeconds(startTime.getSeconds())
.setNanos(startTime.getNanos())
.build(),
jaegerSpan.getStartTime());
assertEquals(duration, Durations.toMillis(jaegerSpan.getDuration())); assertEquals(duration, Durations.toMillis(jaegerSpan.getDuration()));
assertEquals(4, jaegerSpan.getTagsCount()); assertEquals(4, jaegerSpan.getTagsCount());
@ -223,7 +214,7 @@ public class AdapterTest {
return TimedEvent.create(epochNanos, "the log message", attributes); return TimedEvent.create(epochNanos, "the log message", attributes);
} }
private static SpanData getSpanData(Timestamp startTime, Timestamp endTime) { private static SpanData getSpanData(long startMs, long endMs) {
AttributeValue valueB = AttributeValue.booleanAttributeValue(true); AttributeValue valueB = AttributeValue.booleanAttributeValue(true);
Map<String, AttributeValue> attributes = ImmutableMap.of("valueB", valueB); Map<String, AttributeValue> attributes = ImmutableMap.of("valueB", valueB);
@ -234,8 +225,8 @@ public class AdapterTest {
.setSpanId(SpanId.fromLowerBase16(SPAN_ID, 0)) .setSpanId(SpanId.fromLowerBase16(SPAN_ID, 0))
.setParentSpanId(SpanId.fromLowerBase16(PARENT_SPAN_ID, 0)) .setParentSpanId(SpanId.fromLowerBase16(PARENT_SPAN_ID, 0))
.setName("GET /api/endpoint") .setName("GET /api/endpoint")
.setStartTimestamp(startTime) .setStartEpochNanos(TimeUnit.MILLISECONDS.toNanos(startMs))
.setEndTimestamp(endTime) .setEndEpochNanos(TimeUnit.MILLISECONDS.toNanos(endMs))
.setAttributes(attributes) .setAttributes(attributes)
.setTimedEvents(Collections.singletonList(getTimedEvent())) .setTimedEvents(Collections.singletonList(getTimedEvent()))
.setLinks(Collections.singletonList(link)) .setLinks(Collections.singletonList(link))
@ -253,10 +244,6 @@ public class AdapterTest {
Tracestate.builder().build()); Tracestate.builder().build());
} }
private static Timestamp toTimestamp(long ms) {
return Timestamp.create(ms / 1000, (int) ((ms % 1000) * 1000000));
}
@Nullable @Nullable
private static Model.KeyValue getValue(List<Model.KeyValue> tagsList, String s) { private static Model.KeyValue getValue(List<Model.KeyValue> tagsList, String s) {
for (Model.KeyValue kv : tagsList) { for (Model.KeyValue kv : tagsList) {

View File

@ -33,7 +33,6 @@ import io.opentelemetry.exporters.jaeger.proto.api_v2.Collector.PostSpansRequest
import io.opentelemetry.exporters.jaeger.proto.api_v2.CollectorServiceGrpc; import io.opentelemetry.exporters.jaeger.proto.api_v2.CollectorServiceGrpc;
import io.opentelemetry.exporters.jaeger.proto.api_v2.Model; import io.opentelemetry.exporters.jaeger.proto.api_v2.Model;
import io.opentelemetry.exporters.otprotocol.TraceProtoUtils; import io.opentelemetry.exporters.otprotocol.TraceProtoUtils;
import io.opentelemetry.sdk.common.Timestamp;
import io.opentelemetry.sdk.trace.SpanData; import io.opentelemetry.sdk.trace.SpanData;
import io.opentelemetry.trace.Link; import io.opentelemetry.trace.Link;
import io.opentelemetry.trace.Span.Kind; import io.opentelemetry.trace.Span.Kind;
@ -42,6 +41,7 @@ import io.opentelemetry.trace.Status;
import io.opentelemetry.trace.TraceId; import io.opentelemetry.trace.TraceId;
import java.net.InetAddress; import java.net.InetAddress;
import java.util.Collections; import java.util.Collections;
import java.util.concurrent.TimeUnit;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
@ -77,15 +77,13 @@ public class JaegerGrpcSpanExporterTest {
long duration = 900; // ms long duration = 900; // ms
long startMs = System.currentTimeMillis(); long startMs = System.currentTimeMillis();
long endMs = startMs + duration; long endMs = startMs + duration;
Timestamp startTime = Timestamp.create(startMs / 1000, (int) ((startMs % 1000) * 1000000));
Timestamp endTime = Timestamp.create(endMs / 1000, (int) ((endMs % 1000) * 1000000));
SpanData span = SpanData span =
SpanData.newBuilder() SpanData.newBuilder()
.setTraceId(TraceId.fromLowerBase16(TRACE_ID, 0)) .setTraceId(TraceId.fromLowerBase16(TRACE_ID, 0))
.setSpanId(SpanId.fromLowerBase16(SPAN_ID, 0)) .setSpanId(SpanId.fromLowerBase16(SPAN_ID, 0))
.setName("GET /api/endpoint") .setName("GET /api/endpoint")
.setStartTimestamp(startTime) .setStartEpochNanos(TimeUnit.MILLISECONDS.toNanos(startMs))
.setEndTimestamp(endTime) .setEndEpochNanos(TimeUnit.MILLISECONDS.toNanos(endMs))
.setStatus(Status.OK) .setStatus(Status.OK)
.setKind(Kind.CONSUMER) .setKind(Kind.CONSUMER)
.setLinks(Collections.<Link>emptyList()) .setLinks(Collections.<Link>emptyList())

View File

@ -20,7 +20,6 @@ import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap; import static java.util.Collections.singletonMap;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import io.opentelemetry.sdk.common.Timestamp;
import io.opentelemetry.sdk.trace.SpanData; import io.opentelemetry.sdk.trace.SpanData;
import io.opentelemetry.sdk.trace.export.SpanExporter.ResultCode; import io.opentelemetry.sdk.trace.export.SpanExporter.ResultCode;
import io.opentelemetry.trace.AttributeValue; import io.opentelemetry.trace.AttributeValue;
@ -40,8 +39,8 @@ public class LoggingExporterTest {
SpanData.newBuilder() SpanData.newBuilder()
.setTraceId(new TraceId(1234L, 6789L)) .setTraceId(new TraceId(1234L, 6789L))
.setSpanId(new SpanId(9876L)) .setSpanId(new SpanId(9876L))
.setStartTimestamp(Timestamp.fromNanos(epochNanos)) .setStartEpochNanos(epochNanos)
.setEndTimestamp(Timestamp.fromNanos(epochNanos + 1000)) .setEndEpochNanos(epochNanos + 1000)
.setStatus(Status.OK) .setStatus(Status.OK)
.setName("testSpan") .setName("testSpan")
.setKind(Kind.INTERNAL) .setKind(Kind.INTERNAL)

View File

@ -17,7 +17,6 @@
package io.opentelemetry.exporters.otprotocol; package io.opentelemetry.exporters.otprotocol;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import com.google.protobuf.Timestamp;
import io.opentelemetry.proto.trace.v1.ConstantSampler; import io.opentelemetry.proto.trace.v1.ConstantSampler;
import io.opentelemetry.sdk.trace.Sampler; import io.opentelemetry.sdk.trace.Sampler;
import io.opentelemetry.sdk.trace.Samplers; import io.opentelemetry.sdk.trace.Samplers;
@ -53,19 +52,6 @@ public class TraceProtoUtils {
return ByteString.copyFrom(traceIdBytes); return ByteString.copyFrom(traceIdBytes);
} }
/**
* Converts a opentelemetry Timestamp into a protobuf Timestamp.
*
* @param timestamp the opentelemetry Timestamp to convert.
* @return the protobuf Timestamp representation.
*/
public static Timestamp toProtoTimestamp(io.opentelemetry.sdk.common.Timestamp timestamp) {
return Timestamp.newBuilder()
.setNanos(timestamp.getNanos())
.setSeconds(timestamp.getSeconds())
.build();
}
/** /**
* Returns a {@code TraceConfig} from the given proto. * Returns a {@code TraceConfig} from the given proto.
* *

View File

@ -21,7 +21,6 @@ import static org.junit.Assert.assertTrue;
import io.opentelemetry.exporters.inmemory.InMemorySpanExporter; import io.opentelemetry.exporters.inmemory.InMemorySpanExporter;
import io.opentelemetry.opentracingshim.TraceShim; import io.opentelemetry.opentracingshim.TraceShim;
import io.opentelemetry.sdk.common.Timestamp;
import io.opentelemetry.sdk.distributedcontext.DistributedContextManagerSdk; import io.opentelemetry.sdk.distributedcontext.DistributedContextManagerSdk;
import io.opentelemetry.sdk.trace.SpanData; import io.opentelemetry.sdk.trace.SpanData;
import io.opentelemetry.sdk.trace.TracerSdk; import io.opentelemetry.sdk.trace.TracerSdk;
@ -195,7 +194,7 @@ public final class TestUtils {
} }
/** /**
* Sorts the specified {@code List} of {@code Span} by their {@code Span.Timestamp} values, * Sorts the specified {@code List} of {@code Span} by their start epoch timestamp values,
* returning it as a new {@code List}. * returning it as a new {@code List}.
*/ */
public static List<SpanData> sortByStartTime(List<SpanData> spans) { public static List<SpanData> sortByStartTime(List<SpanData> spans) {
@ -205,7 +204,7 @@ public final class TestUtils {
new Comparator<SpanData>() { new Comparator<SpanData>() {
@Override @Override
public int compare(SpanData o1, SpanData o2) { public int compare(SpanData o1, SpanData o2) {
return compareTimestamps(o1.getStartTimestamp(), o2.getStartTimestamp()); return Long.compare(o1.getStartEpochNanos(), o2.getStartEpochNanos());
} }
}); });
return sortedSpans; return sortedSpans;
@ -215,25 +214,9 @@ public final class TestUtils {
public static void assertSameTrace(List<SpanData> spans) { public static void assertSameTrace(List<SpanData> spans) {
for (int i = 0; i < spans.size() - 1; i++) { for (int i = 0; i < spans.size() - 1; i++) {
// TODO - Include nanos in this comparison. // TODO - Include nanos in this comparison.
assertTrue( assertTrue(spans.get(spans.size() - 1).getEndEpochNanos() >= spans.get(i).getEndEpochNanos());
spans.get(spans.size() - 1).getEndTimestamp().getSeconds()
>= spans.get(i).getEndTimestamp().getSeconds());
assertEquals(spans.get(spans.size() - 1).getTraceId(), spans.get(i).getTraceId()); assertEquals(spans.get(spans.size() - 1).getTraceId(), spans.get(i).getTraceId());
assertEquals(spans.get(spans.size() - 1).getSpanId(), spans.get(i).getParentSpanId()); assertEquals(spans.get(spans.size() - 1).getSpanId(), spans.get(i).getParentSpanId());
} }
} }
// TODO: this comparator code is duplicated in another TestUtils class. find a common home for it.
private static final Comparator<Timestamp> COMPARATOR =
new Comparator<Timestamp>() {
@Override
public int compare(Timestamp t1, Timestamp t2) {
int secDiff = Long.compare(t1.getSeconds(), t2.getSeconds());
return (secDiff != 0) ? secDiff : Integer.compare(t1.getNanos(), t2.getNanos());
}
};
public static int compareTimestamps(Timestamp x, Timestamp y) {
return COMPARATOR.compare(x, y);
}
} }

View File

@ -1,130 +0,0 @@
/*
* Copyright 2019, OpenTelemetry 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.opentelemetry.sdk.common;
import com.google.auto.value.AutoValue;
import java.math.BigDecimal;
import java.math.RoundingMode;
import javax.annotation.concurrent.Immutable;
/**
* A representation of an instant in time. The instant is the number of nanoseconds after the number
* of seconds since the Unix Epoch.
*
* <p>Defined here instead of using {@code Instant} because the API needs to be Java 1.7 compatible.
*
* @since 0.1.0
*/
@Immutable
@AutoValue
public abstract class Timestamp {
private static final long MAX_SECONDS = 315576000000L;
private static final int MAX_NANOS = 999999999;
private static final long MILLIS_PER_SECOND = 1000L;
private static final long NANOS_PER_SECOND = 1000L * 1000L * 1000L;
private static final long NANOS_PER_MILLI = 1000L * 1000L;
Timestamp() {}
/**
* Creates a new timestamp from given seconds and nanoseconds.
*
* @param seconds Represents seconds of UTC time since Unix epoch 1970-01-01T00:00:00Z. Must be
* from from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z inclusive.
* @param nanos Non-negative fractions of a second at nanosecond resolution. Negative second
* values with fractions must still have non-negative nanos values that count forward in time.
* Must be from 0 to 999,999,999 inclusive.
* @return new {@code Timestamp} with specified fields.
* @throws IllegalArgumentException if the arguments are out of range.
* @since 0.1.0
*/
public static Timestamp create(long seconds, int nanos) {
if (seconds < -MAX_SECONDS) {
throw new IllegalArgumentException(
"'seconds' is less than minimum (" + -MAX_SECONDS + "): " + seconds);
}
if (seconds > MAX_SECONDS) {
throw new IllegalArgumentException(
"'seconds' is greater than maximum (" + MAX_SECONDS + "): " + seconds);
}
if (nanos < 0) {
throw new IllegalArgumentException("'nanos' is less than zero: " + nanos);
}
if (nanos > MAX_NANOS) {
throw new IllegalArgumentException(
"'nanos' is greater than maximum (" + MAX_NANOS + "): " + nanos);
}
return new AutoValue_Timestamp(seconds, nanos);
}
/**
* Creates a new timestamp from the given milliseconds.
*
* @param epochMilli the timestamp represented in milliseconds since epoch.
* @return new {@code Timestamp} with specified fields.
* @throws IllegalArgumentException if the number of milliseconds is out of the range that can be
* represented by {@code Timestamp}.
* @since 0.1.0
*/
public static Timestamp fromMillis(long epochMilli) {
long secs = floorDiv(epochMilli, MILLIS_PER_SECOND);
int mos = (int) floorMod(epochMilli, MILLIS_PER_SECOND);
return create(secs, (int) (mos * NANOS_PER_MILLI)); // Safe int * NANOS_PER_MILLI
}
/**
* Creates a new timestamp from the given milliseconds.
*
* @param epochNanos the timestamp represented in nanoseconds since epoch.
* @return new {@code Timestamp} with specified fields.
* @throws IllegalArgumentException if the number of milliseconds is out of the range that can be
* represented by {@code Timestamp}.
* @since 0.1.0
*/
public static Timestamp fromNanos(long epochNanos) {
long secs = floorDiv(epochNanos, NANOS_PER_SECOND);
int nanos = (int) floorMod(epochNanos, NANOS_PER_SECOND);
return create(secs, nanos); // Safe int * NANOS_PER_MILLI
}
/**
* Returns the number of seconds since the Unix Epoch represented by this timestamp.
*
* @return the number of seconds since the Unix Epoch.
* @since 0.1.0
*/
public abstract long getSeconds();
/**
* Returns the number of nanoseconds after the number of seconds since the Unix Epoch represented
* by this timestamp.
*
* @return the number of nanoseconds after the number of seconds since the Unix Epoch.
* @since 0.1.0
*/
public abstract int getNanos();
// Returns the result of dividing x by y rounded using floor.
private static long floorDiv(long x, long y) {
return BigDecimal.valueOf(x).divide(BigDecimal.valueOf(y), 0, RoundingMode.FLOOR).longValue();
}
// Returns the floor modulus "x - (floorDiv(x, y) * y)"
private static long floorMod(long x, long y) {
return x - floorDiv(x, y) * y;
}
}

View File

@ -23,7 +23,7 @@ import javax.annotation.concurrent.Immutable;
* This class provides a mechanism for calculating the epoch time using {@link System#nanoTime()} * This class provides a mechanism for calculating the epoch time using {@link System#nanoTime()}
* and a reference epoch timestamp. * and a reference epoch timestamp.
* *
* <p>This is needed because Java has millisecond granularity for Timestamp and tracing events are * <p>This is needed because Java has millisecond granularity for epoch times and tracing events are
* recorded more often. * recorded more often.
* *
* <p>This clock needs to be re-created periodically in order to re-sync with the kernel clock, and * <p>This clock needs to be re-created periodically in order to re-sync with the kernel clock, and

View File

@ -20,7 +20,6 @@ import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.collect.EvictingQueue; import com.google.common.collect.EvictingQueue;
import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.Clock;
import io.opentelemetry.sdk.common.Timestamp;
import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.trace.config.TraceConfig; import io.opentelemetry.sdk.trace.config.TraceConfig;
import io.opentelemetry.trace.AttributeValue; import io.opentelemetry.trace.AttributeValue;
@ -149,8 +148,6 @@ final class RecordEventsReadableSpan implements ReadableSpan, Span {
@Override @Override
public SpanData toSpanData() { public SpanData toSpanData() {
Timestamp startTimestamp = Timestamp.fromNanos(startEpochNanos);
Timestamp endTimestamp = Timestamp.fromNanos(getEndEpochNanos());
SpanContext spanContext = getSpanContext(); SpanContext spanContext = getSpanContext();
return SpanData.newBuilder() return SpanData.newBuilder()
.setName(getName()) .setName(getName())
@ -159,8 +156,8 @@ final class RecordEventsReadableSpan implements ReadableSpan, Span {
.setTraceFlags(spanContext.getTraceFlags()) .setTraceFlags(spanContext.getTraceFlags())
.setTracestate(spanContext.getTracestate()) .setTracestate(spanContext.getTracestate())
.setAttributes(getAttributes()) .setAttributes(getAttributes())
.setStartTimestamp(startTimestamp) .setStartEpochNanos(startEpochNanos)
.setEndTimestamp(endTimestamp) .setEndEpochNanos(getEndEpochNanos())
.setKind(kind) .setKind(kind)
.setLinks(getLinks()) .setLinks(getLinks())
.setParentSpanId(parentSpanId) .setParentSpanId(parentSpanId)

View File

@ -17,7 +17,6 @@
package io.opentelemetry.sdk.trace; package io.opentelemetry.sdk.trace;
import com.google.auto.value.AutoValue; import com.google.auto.value.AutoValue;
import io.opentelemetry.sdk.common.Timestamp;
import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.trace.AttributeValue; import io.opentelemetry.trace.AttributeValue;
import io.opentelemetry.trace.Event; import io.opentelemetry.trace.Event;
@ -107,12 +106,12 @@ public abstract class SpanData {
public abstract Kind getKind(); public abstract Kind getKind();
/** /**
* Returns the start {@code Timestamp} of this {@code Span}. * Returns the start epoch timestamp in nanos of this {@code Span}.
* *
* @return the start {@code Timestamp} of this {@code Span}. * @return the start epoch timestamp in nanos of this {@code Span}.
* @since 0.1.0 * @since 0.1.0
*/ */
public abstract Timestamp getStartTimestamp(); public abstract long getStartEpochNanos();
/** /**
* Returns the attributes recorded for this {@code Span}. * Returns the attributes recorded for this {@code Span}.
@ -147,12 +146,12 @@ public abstract class SpanData {
public abstract Status getStatus(); public abstract Status getStatus();
/** /**
* Returns the end {@code Timestamp}. * Returns the end epoch timestamp in nanos of this {@code Span}.
* *
* @return the end {@code Timestamp}. * @return the end epoch timestamp in nanos of this {@code Span}.
* @since 0.1.0 * @since 0.1.0
*/ */
public abstract Timestamp getEndTimestamp(); public abstract long getEndEpochNanos();
/** /**
* An immutable implementation of {@link Link}. * An immutable implementation of {@link Link}.
@ -211,9 +210,9 @@ public abstract class SpanData {
} }
/** /**
* Returns the {@code Timestamp} of this event. * Returns the epoch time in nanos of this event.
* *
* @return the {@code Timestamp} of this event. * @return the epoch time in nanos of this event.
* @since 0.1.0 * @since 0.1.0
*/ */
public abstract long getEpochNanos(); public abstract long getEpochNanos();
@ -336,24 +335,22 @@ public abstract class SpanData {
public abstract Builder setName(String name); public abstract Builder setName(String name);
/** /**
* Set the start timestamp of the span. Must not be null. * Set the start timestamp of the span.
* *
* @param timestamp the start Timestamp * @param epochNanos the start epoch timestamp in nanos.
* @return this * @return this
* @see Timestamp
* @since 0.1.0 * @since 0.1.0
*/ */
public abstract Builder setStartTimestamp(Timestamp timestamp); public abstract Builder setStartEpochNanos(long epochNanos);
/** /**
* Set the end timestamp of the span. Must not be null. * Set the end timestamp of the span.
* *
* @param timestamp the end Timestamp * @param epochNanos the end epoch timestamp in nanos.
* @return this * @return this
* @see Timestamp
* @since 0.1.0 * @since 0.1.0
*/ */
public abstract Builder setEndTimestamp(Timestamp timestamp); public abstract Builder setEndEpochNanos(long epochNanos);
/** /**
* Set the attributes that are associated with this span, as a Map of String keys to * Set the attributes that are associated with this span, as a Map of String keys to

View File

@ -23,7 +23,7 @@ import java.util.Collections;
import java.util.Map; import java.util.Map;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
/** Timed event that uses nanoTime to represent the Timestamp. */ /** Timed event. */
@Immutable @Immutable
abstract class TimedEvent { abstract class TimedEvent {

View File

@ -1,126 +0,0 @@
/*
* Copyright 2019, OpenTelemetry 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.opentelemetry.sdk.common;
import static com.google.common.truth.Truth.assertThat;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Unit tests for {@link Timestamp}. */
@RunWith(JUnit4.class)
public class TimestampTest {
@Rule public ExpectedException thrown = ExpectedException.none();
@Test
public void timestampCreate() {
assertThat(Timestamp.create(24, 42).getSeconds()).isEqualTo(24);
assertThat(Timestamp.create(24, 42).getNanos()).isEqualTo(42);
assertThat(Timestamp.create(-24, 42).getSeconds()).isEqualTo(-24);
assertThat(Timestamp.create(-24, 42).getNanos()).isEqualTo(42);
assertThat(Timestamp.create(315576000000L, 999999999).getSeconds()).isEqualTo(315576000000L);
assertThat(Timestamp.create(315576000000L, 999999999).getNanos()).isEqualTo(999999999);
assertThat(Timestamp.create(-315576000000L, 999999999).getSeconds()).isEqualTo(-315576000000L);
assertThat(Timestamp.create(-315576000000L, 999999999).getNanos()).isEqualTo(999999999);
}
@Test
public void create_SecondsTooLow() {
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("'seconds' is less than minimum (-315576000000): -315576000001");
Timestamp.create(-315576000001L, 0);
}
@Test
public void create_SecondsTooHigh() {
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("'seconds' is greater than maximum (315576000000): 315576000001");
Timestamp.create(315576000001L, 0);
}
@Test
public void create_NanosTooLow_PositiveTime() {
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("'nanos' is less than zero: -1");
Timestamp.create(1, -1);
}
@Test
public void create_NanosTooHigh_PositiveTime() {
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("'nanos' is greater than maximum (999999999): 1000000000");
Timestamp.create(1, 1000000000);
}
@Test
public void create_NanosTooLow_NegativeTime() {
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("'nanos' is less than zero: -1");
Timestamp.create(-1, -1);
}
@Test
public void create_NanosTooHigh_NegativeTime() {
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("'nanos' is greater than maximum (999999999): 1000000000");
Timestamp.create(-1, 1000000000);
}
@Test
public void timestampFromMillis() {
assertThat(Timestamp.fromMillis(0)).isEqualTo(Timestamp.create(0, 0));
assertThat(Timestamp.fromMillis(987)).isEqualTo(Timestamp.create(0, 987000000));
assertThat(Timestamp.fromMillis(3456)).isEqualTo(Timestamp.create(3, 456000000));
}
@Test
public void timestampFromMillis_Negative() {
assertThat(Timestamp.fromMillis(-1)).isEqualTo(Timestamp.create(-1, 999000000));
assertThat(Timestamp.fromMillis(-999)).isEqualTo(Timestamp.create(-1, 1000000));
assertThat(Timestamp.fromMillis(-3456)).isEqualTo(Timestamp.create(-4, 544000000));
}
@Test
public void fromMillis_TooLow() {
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("'seconds' is less than minimum (-315576000000): -315576000001");
Timestamp.fromMillis(-315576000001000L);
}
@Test
public void fromMillis_TooHigh() {
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("'seconds' is greater than maximum (315576000000): 315576000001");
Timestamp.fromMillis(315576000001000L);
}
@Test
public void timestamp_Equal() {
// Positive tests.
assertThat(Timestamp.create(0, 0)).isEqualTo(Timestamp.create(0, 0));
assertThat(Timestamp.create(24, 42)).isEqualTo(Timestamp.create(24, 42));
assertThat(Timestamp.create(-24, 42)).isEqualTo(Timestamp.create(-24, 42));
// Negative tests.
assertThat(Timestamp.create(25, 42)).isNotEqualTo(Timestamp.create(24, 42));
assertThat(Timestamp.create(24, 43)).isNotEqualTo(Timestamp.create(24, 42));
assertThat(Timestamp.create(-25, 42)).isNotEqualTo(Timestamp.create(-24, 42));
assertThat(Timestamp.create(-24, 43)).isNotEqualTo(Timestamp.create(-24, 42));
}
}

View File

@ -20,7 +20,6 @@ import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import io.opentelemetry.sdk.common.Timestamp;
import io.opentelemetry.sdk.internal.TestClock; import io.opentelemetry.sdk.internal.TestClock;
import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.trace.config.TraceConfig; import io.opentelemetry.sdk.trace.config.TraceConfig;
@ -101,8 +100,8 @@ public class RecordEventsReadableSpanTest {
Collections.<SpanData.TimedEvent>emptyList(), Collections.<SpanData.TimedEvent>emptyList(),
Collections.singletonList(link), Collections.singletonList(link),
SPAN_NAME, SPAN_NAME,
Timestamp.fromNanos(startEpochNanos), startEpochNanos,
Timestamp.fromNanos(startEpochNanos), startEpochNanos,
Status.OK); Status.OK);
} }
@ -130,8 +129,8 @@ public class RecordEventsReadableSpanTest {
Collections.singletonList(timedEvent), Collections.singletonList(timedEvent),
Collections.singletonList(link), Collections.singletonList(link),
SPAN_NEW_NAME, SPAN_NEW_NAME,
Timestamp.fromNanos(startEpochNanos), startEpochNanos,
Timestamp.fromNanos(testClock.now()), testClock.now(),
Status.OK); Status.OK);
} finally { } finally {
span.end(); span.end();
@ -159,8 +158,8 @@ public class RecordEventsReadableSpanTest {
Collections.singletonList(timedEvent), Collections.singletonList(timedEvent),
Collections.singletonList(link), Collections.singletonList(link),
SPAN_NEW_NAME, SPAN_NEW_NAME,
Timestamp.fromNanos(startEpochNanos), startEpochNanos,
Timestamp.fromNanos(testClock.now()), testClock.now(),
Status.CANCELLED); Status.CANCELLED);
} }
@ -473,8 +472,8 @@ public class RecordEventsReadableSpanTest {
List<SpanData.TimedEvent> timedEvents, List<SpanData.TimedEvent> timedEvents,
List<Link> links, List<Link> links,
String spanName, String spanName,
Timestamp startTime, long startEpochNanos,
Timestamp endTime, long endEpochNanos,
Status status) { Status status) {
assertThat(spanData.getTraceId()).isEqualTo(traceId); assertThat(spanData.getTraceId()).isEqualTo(traceId);
assertThat(spanData.getSpanId()).isEqualTo(spanId); assertThat(spanData.getSpanId()).isEqualTo(spanId);
@ -485,8 +484,8 @@ public class RecordEventsReadableSpanTest {
assertThat(spanData.getAttributes()).isEqualTo(attributes); assertThat(spanData.getAttributes()).isEqualTo(attributes);
assertThat(spanData.getTimedEvents()).isEqualTo(timedEvents); assertThat(spanData.getTimedEvents()).isEqualTo(timedEvents);
assertThat(spanData.getLinks()).isEqualTo(links); assertThat(spanData.getLinks()).isEqualTo(links);
assertThat(spanData.getStartTimestamp()).isEqualTo(startTime); assertThat(spanData.getStartEpochNanos()).isEqualTo(startEpochNanos);
assertThat(spanData.getEndTimestamp()).isEqualTo(endTime); assertThat(spanData.getEndEpochNanos()).isEqualTo(endEpochNanos);
assertThat(spanData.getStatus().getCanonicalCode()).isEqualTo(status.getCanonicalCode()); assertThat(spanData.getStatus().getCanonicalCode()).isEqualTo(status.getCanonicalCode());
} }
@ -542,8 +541,8 @@ public class RecordEventsReadableSpanTest {
.setName(name) .setName(name)
.setKind(kind) .setKind(kind)
.setStatus(Status.OK) .setStatus(Status.OK)
.setStartTimestamp(Timestamp.fromNanos(startEpochNanos)) .setStartEpochNanos(startEpochNanos)
.setEndTimestamp(Timestamp.fromNanos(endEpochNanos)) .setEndEpochNanos(endEpochNanos)
.setTimedEvents( .setTimedEvents(
Arrays.asList( Arrays.asList(
SpanData.TimedEvent.create(firstEventEpochNanos, "event1", event1Attributes), SpanData.TimedEvent.create(firstEventEpochNanos, "event1", event1Attributes),

View File

@ -20,7 +20,6 @@ import static java.util.Collections.emptyList;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import io.opentelemetry.sdk.common.Timestamp;
import io.opentelemetry.sdk.trace.SpanData.TimedEvent; import io.opentelemetry.sdk.trace.SpanData.TimedEvent;
import io.opentelemetry.trace.AttributeValue; import io.opentelemetry.trace.AttributeValue;
import io.opentelemetry.trace.Link; import io.opentelemetry.trace.Link;
@ -34,6 +33,7 @@ import io.opentelemetry.trace.Tracestate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.concurrent.TimeUnit;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.ExpectedException; import org.junit.rules.ExpectedException;
@ -43,6 +43,8 @@ import org.junit.runners.JUnit4;
/** Unit tests for {@link SpanData}. */ /** Unit tests for {@link SpanData}. */
@RunWith(JUnit4.class) @RunWith(JUnit4.class)
public class SpanDataTest { public class SpanDataTest {
private static final long START_EPOCH_NANOS = TimeUnit.SECONDS.toNanos(3000) + 200;
private static final long END_EPOCH_NANOS = TimeUnit.SECONDS.toNanos(3001) + 255;
@Rule public final ExpectedException thrown = ExpectedException.none(); @Rule public final ExpectedException thrown = ExpectedException.none();
@Test @Test
@ -103,8 +105,8 @@ public class SpanDataTest {
.setSpanId(SpanId.getInvalid()) .setSpanId(SpanId.getInvalid())
.setTraceId(TraceId.getInvalid()) .setTraceId(TraceId.getInvalid())
.setName("spanName") .setName("spanName")
.setStartTimestamp(Timestamp.create(3000, 200)) .setStartEpochNanos(START_EPOCH_NANOS)
.setEndTimestamp(Timestamp.create(3001, 255)) .setEndEpochNanos(END_EPOCH_NANOS)
.setKind(Kind.SERVER) .setKind(Kind.SERVER)
.setStatus(Status.OK); .setStatus(Status.OK);
} }

View File

@ -16,7 +16,6 @@
package io.opentelemetry.sdk.trace; package io.opentelemetry.sdk.trace;
import io.opentelemetry.sdk.common.Timestamp;
import io.opentelemetry.sdk.trace.config.TraceConfig; import io.opentelemetry.sdk.trace.config.TraceConfig;
import io.opentelemetry.trace.AttributeValue; import io.opentelemetry.trace.AttributeValue;
import io.opentelemetry.trace.Span; import io.opentelemetry.trace.Span;
@ -27,6 +26,7 @@ import io.opentelemetry.trace.TraceId;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.TimeUnit;
/** Common utilities for unit tests. */ /** Common utilities for unit tests. */
public final class TestUtils { public final class TestUtils {
@ -57,9 +57,9 @@ public final class TestUtils {
.setSpanId(SpanId.getInvalid()) .setSpanId(SpanId.getInvalid())
.setName("span") .setName("span")
.setKind(Kind.SERVER) .setKind(Kind.SERVER)
.setStartTimestamp(Timestamp.create(100, 100)) .setStartEpochNanos(TimeUnit.SECONDS.toNanos(100) + 100)
.setStatus(Status.OK) .setStatus(Status.OK)
.setEndTimestamp(Timestamp.create(200, 200)) .setEndEpochNanos(TimeUnit.SECONDS.toNanos(200) + 200)
.build(); .build();
} }

View File

@ -19,7 +19,6 @@ package io.opentelemetry.sdk.contrib.trace.testbed;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import io.opentelemetry.exporters.inmemory.InMemorySpanExporter; import io.opentelemetry.exporters.inmemory.InMemorySpanExporter;
import io.opentelemetry.sdk.common.Timestamp;
import io.opentelemetry.sdk.trace.SpanData; import io.opentelemetry.sdk.trace.SpanData;
import io.opentelemetry.sdk.trace.TracerSdk; import io.opentelemetry.sdk.trace.TracerSdk;
import io.opentelemetry.sdk.trace.export.SimpleSpansProcessor; import io.opentelemetry.sdk.trace.export.SimpleSpansProcessor;
@ -191,7 +190,7 @@ public final class TestUtils {
} }
/** /**
* Sorts the specified {@code List} of {@code Span} by their {@code Span.Timestamp} values, * Sorts the specified {@code List} of {@code Span} by their start epoch timestamp values,
* returning it as a new {@code List}. * returning it as a new {@code List}.
*/ */
public static List<SpanData> sortByStartTime(List<SpanData> spans) { public static List<SpanData> sortByStartTime(List<SpanData> spans) {
@ -201,7 +200,7 @@ public final class TestUtils {
new Comparator<SpanData>() { new Comparator<SpanData>() {
@Override @Override
public int compare(SpanData o1, SpanData o2) { public int compare(SpanData o1, SpanData o2) {
return compareTimestamps(o1.getStartTimestamp(), o2.getStartTimestamp()); return Long.compare(o1.getStartEpochNanos(), o2.getStartEpochNanos());
} }
}); });
return sortedSpans; return sortedSpans;
@ -211,26 +210,10 @@ public final class TestUtils {
public static void assertSameTrace(List<SpanData> spans) { public static void assertSameTrace(List<SpanData> spans) {
for (int i = 0; i < spans.size() - 1; i++) { for (int i = 0; i < spans.size() - 1; i++) {
// TODO - Include nanos in this comparison. // TODO - Include nanos in this comparison.
assertThat( assertThat(spans.get(spans.size() - 1).getEndEpochNanos() >= spans.get(i).getEndEpochNanos())
spans.get(spans.size() - 1).getEndTimestamp().getSeconds()
>= spans.get(i).getEndTimestamp().getSeconds())
.isTrue(); .isTrue();
assertThat(spans.get(spans.size() - 1).getTraceId()).isEqualTo(spans.get(i).getTraceId()); assertThat(spans.get(spans.size() - 1).getTraceId()).isEqualTo(spans.get(i).getTraceId());
assertThat(spans.get(spans.size() - 1).getSpanId()).isEqualTo(spans.get(i).getParentSpanId()); assertThat(spans.get(spans.size() - 1).getSpanId()).isEqualTo(spans.get(i).getParentSpanId());
} }
} }
// TODO: this comparator code is duplicated in another TestUtils class. find a common home for it.
private static final Comparator<Timestamp> COMPARATOR =
new Comparator<Timestamp>() {
@Override
public int compare(Timestamp t1, Timestamp t2) {
int secDiff = Long.compare(t1.getSeconds(), t2.getSeconds());
return (secDiff != 0) ? secDiff : Integer.compare(t1.getNanos(), t2.getNanos());
}
};
public static int compareTimestamps(Timestamp x, Timestamp y) {
return COMPARATOR.compare(x, y);
}
} }