Add unit to start, end and event timestamp accepting methods in Span. (#1969)
* Add unit to timestamp accepting methods in Span. * end timestamp * Merge * Merge * Add Instant versions too
This commit is contained in:
		
							parent
							
								
									9063c385d9
								
							
						
					
					
						commit
						1883c578bd
					
				| 
						 | 
				
			
			@ -10,6 +10,7 @@ import io.opentelemetry.api.common.Attributes;
 | 
			
		|||
import io.opentelemetry.api.internal.Utils;
 | 
			
		||||
import io.opentelemetry.context.Context;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
import java.util.concurrent.TimeUnit;
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import javax.annotation.concurrent.ThreadSafe;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -107,7 +108,7 @@ final class DefaultTracer implements Tracer {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public NoopSpanBuilder setStartTimestamp(long startTimestamp) {
 | 
			
		||||
    public NoopSpanBuilder setStartTimestamp(long startTimestamp, TimeUnit unit) {
 | 
			
		||||
      Utils.checkArgument(startTimestamp >= 0, "Negative startTimestamp");
 | 
			
		||||
      return this;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,6 +7,7 @@ package io.opentelemetry.api.trace;
 | 
			
		|||
 | 
			
		||||
import io.opentelemetry.api.common.AttributeKey;
 | 
			
		||||
import io.opentelemetry.api.common.Attributes;
 | 
			
		||||
import java.util.concurrent.TimeUnit;
 | 
			
		||||
import javax.annotation.concurrent.Immutable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -71,7 +72,7 @@ final class PropagatedSpan implements Span {
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public Span addEvent(String name, long timestamp) {
 | 
			
		||||
  public Span addEvent(String name, long timestamp, TimeUnit unit) {
 | 
			
		||||
    return this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -81,7 +82,7 @@ final class PropagatedSpan implements Span {
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public Span addEvent(String name, Attributes attributes, long timestamp) {
 | 
			
		||||
  public Span addEvent(String name, Attributes attributes, long timestamp, TimeUnit unit) {
 | 
			
		||||
    return this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -114,7 +115,7 @@ final class PropagatedSpan implements Span {
 | 
			
		|||
  public void end() {}
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public void end(long timestamp) {}
 | 
			
		||||
  public void end(long timestamp, TimeUnit unit) {}
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public SpanContext getSpanContext() {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,10 +5,15 @@
 | 
			
		|||
 | 
			
		||||
package io.opentelemetry.api.trace;
 | 
			
		||||
 | 
			
		||||
import static java.util.concurrent.TimeUnit.NANOSECONDS;
 | 
			
		||||
import static java.util.concurrent.TimeUnit.SECONDS;
 | 
			
		||||
 | 
			
		||||
import io.opentelemetry.api.common.AttributeKey;
 | 
			
		||||
import io.opentelemetry.api.common.Attributes;
 | 
			
		||||
import io.opentelemetry.context.Context;
 | 
			
		||||
import io.opentelemetry.context.ImplicitContextKeyed;
 | 
			
		||||
import java.time.Instant;
 | 
			
		||||
import java.util.concurrent.TimeUnit;
 | 
			
		||||
import javax.annotation.Nonnull;
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import javax.annotation.concurrent.ThreadSafe;
 | 
			
		||||
| 
						 | 
				
			
			@ -199,10 +204,32 @@ public interface Span extends ImplicitContextKeyed {
 | 
			
		|||
   * occurred.
 | 
			
		||||
   *
 | 
			
		||||
   * @param name the name of the event.
 | 
			
		||||
   * @param timestamp the explicit event timestamp in nanos since epoch.
 | 
			
		||||
   * @param timestamp the explicit event timestamp since epoch.
 | 
			
		||||
   * @param unit the unit of the timestamp
 | 
			
		||||
   * @return this.
 | 
			
		||||
   */
 | 
			
		||||
  Span addEvent(String name, long timestamp);
 | 
			
		||||
  Span addEvent(String name, long timestamp, TimeUnit unit);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Adds an event to the {@link Span} with the given {@code timestamp}, as nanos since epoch. Note,
 | 
			
		||||
   * this {@code timestamp} is not the same as {@link System#nanoTime()} but may be computed using
 | 
			
		||||
   * it, for example, by taking a difference of readings from {@link System#nanoTime()} and adding
 | 
			
		||||
   * to the span start time.
 | 
			
		||||
   *
 | 
			
		||||
   * <p>When possible, it is preferred to use {@link #addEvent(String)} at the time the event
 | 
			
		||||
   * occurred.
 | 
			
		||||
   *
 | 
			
		||||
   * @param name the name of the event.
 | 
			
		||||
   * @param timestamp the explicit event timestamp since epoch.
 | 
			
		||||
   * @return this.
 | 
			
		||||
   */
 | 
			
		||||
  default Span addEvent(String name, Instant timestamp) {
 | 
			
		||||
    if (timestamp == null) {
 | 
			
		||||
      return addEvent(name);
 | 
			
		||||
    }
 | 
			
		||||
    return addEvent(
 | 
			
		||||
        name, SECONDS.toNanos(timestamp.getEpochSecond()) + timestamp.getNano(), NANOSECONDS);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Adds an event to the {@link Span} with the given {@link Attributes}. The timestamp of the event
 | 
			
		||||
| 
						 | 
				
			
			@ -227,10 +254,37 @@ public interface Span extends ImplicitContextKeyed {
 | 
			
		|||
   * @param name the name of the event.
 | 
			
		||||
   * @param attributes the attributes that will be added; these are associated with this event, not
 | 
			
		||||
   *     the {@code Span} as for {@code setAttribute()}.
 | 
			
		||||
   * @param timestamp the explicit event timestamp in nanos since epoch.
 | 
			
		||||
   * @param timestamp the explicit event timestamp since epoch.
 | 
			
		||||
   * @param unit the unit of the timestamp
 | 
			
		||||
   * @return this.
 | 
			
		||||
   */
 | 
			
		||||
  Span addEvent(String name, Attributes attributes, long timestamp);
 | 
			
		||||
  Span addEvent(String name, Attributes attributes, long timestamp, TimeUnit unit);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Adds an event to the {@link Span} with the given {@link Attributes} and {@code timestamp}.
 | 
			
		||||
   * Note, this {@code timestamp} is not the same as {@link System#nanoTime()} but may be computed
 | 
			
		||||
   * using it, for example, by taking a difference of readings from {@link System#nanoTime()} and
 | 
			
		||||
   * adding to the span start time.
 | 
			
		||||
   *
 | 
			
		||||
   * <p>When possible, it is preferred to use {@link #addEvent(String)} at the time the event
 | 
			
		||||
   * occurred.
 | 
			
		||||
   *
 | 
			
		||||
   * @param name the name of the event.
 | 
			
		||||
   * @param attributes the attributes that will be added; these are associated with this event, not
 | 
			
		||||
   *     the {@code Span} as for {@code setAttribute()}.
 | 
			
		||||
   * @param timestamp the explicit event timestamp since epoch.
 | 
			
		||||
   * @return this.
 | 
			
		||||
   */
 | 
			
		||||
  default Span addEvent(String name, Attributes attributes, Instant timestamp) {
 | 
			
		||||
    if (timestamp == null) {
 | 
			
		||||
      return addEvent(name, attributes);
 | 
			
		||||
    }
 | 
			
		||||
    return addEvent(
 | 
			
		||||
        name,
 | 
			
		||||
        attributes,
 | 
			
		||||
        SECONDS.toNanos(timestamp.getEpochSecond()) + timestamp.getNano(),
 | 
			
		||||
        NANOSECONDS);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Sets the status to the {@code Span}.
 | 
			
		||||
| 
						 | 
				
			
			@ -312,10 +366,31 @@ public interface Span extends ImplicitContextKeyed {
 | 
			
		|||
   * <p>Use this method for specifying explicit end options, such as end {@code Timestamp}. When no
 | 
			
		||||
   * explicit values are required, use {@link #end()}.
 | 
			
		||||
   *
 | 
			
		||||
   * @param timestamp the explicit timestamp, as nanos from the epoch, for this {@code Span}. {@code
 | 
			
		||||
   *     0} indicates current time should be used.
 | 
			
		||||
   * @param timestamp the explicit timestamp from the epoch, for this {@code Span}. {@code 0}
 | 
			
		||||
   *     indicates current time should be used.
 | 
			
		||||
   * @param unit the unit of the timestamp
 | 
			
		||||
   */
 | 
			
		||||
  void end(long timestamp);
 | 
			
		||||
  void end(long timestamp, TimeUnit unit);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Marks the end of {@code Span} execution with the specified timestamp.
 | 
			
		||||
   *
 | 
			
		||||
   * <p>Only the timing of the first end call for a given {@code Span} will be recorded, and
 | 
			
		||||
   * implementations are free to ignore all further calls.
 | 
			
		||||
   *
 | 
			
		||||
   * <p>Use this method for specifying explicit end options, such as end {@code Timestamp}. When no
 | 
			
		||||
   * explicit values are required, use {@link #end()}.
 | 
			
		||||
   *
 | 
			
		||||
   * @param timestamp the explicit timestamp from the epoch, for this {@code Span}. {@code 0}
 | 
			
		||||
   *     indicates current time should be used.
 | 
			
		||||
   */
 | 
			
		||||
  default void end(Instant timestamp) {
 | 
			
		||||
    if (timestamp == null) {
 | 
			
		||||
      end();
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    end(SECONDS.toNanos(timestamp.getEpochSecond()) + timestamp.getNano(), NANOSECONDS);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Returns the {@code SpanContext} associated with this {@code Span}.
 | 
			
		||||
| 
						 | 
				
			
			@ -570,11 +645,32 @@ public interface Span extends ImplicitContextKeyed {
 | 
			
		|||
     *
 | 
			
		||||
     * <p>Important this is NOT equivalent with System.nanoTime().
 | 
			
		||||
     *
 | 
			
		||||
     * @param startTimestamp the explicit start timestamp of the newly created {@code Span} in nanos
 | 
			
		||||
     *     since epoch.
 | 
			
		||||
     * @param startTimestamp the explicit start timestamp from the epoch of the newly created {@code
 | 
			
		||||
     *     Span}.
 | 
			
		||||
     * @param unit the unit of the timestamp.
 | 
			
		||||
     * @return this.
 | 
			
		||||
     */
 | 
			
		||||
    Builder setStartTimestamp(long startTimestamp);
 | 
			
		||||
    Builder setStartTimestamp(long startTimestamp, TimeUnit unit);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets an explicit start timestamp for the newly created {@code Span}.
 | 
			
		||||
     *
 | 
			
		||||
     * <p>Use this method to specify an explicit start timestamp. If not called, the implementation
 | 
			
		||||
     * will use the timestamp value at {@link #startSpan()} time, which should be the default case.
 | 
			
		||||
     *
 | 
			
		||||
     * <p>Important this is NOT equivalent with System.nanoTime().
 | 
			
		||||
     *
 | 
			
		||||
     * @param startTimestamp the explicit start timestamp from the epoch of the newly created {@code
 | 
			
		||||
     *     Span}.
 | 
			
		||||
     * @return this.
 | 
			
		||||
     */
 | 
			
		||||
    default Builder setStartTimestamp(Instant startTimestamp) {
 | 
			
		||||
      if (startTimestamp == null) {
 | 
			
		||||
        return this;
 | 
			
		||||
      }
 | 
			
		||||
      return setStartTimestamp(
 | 
			
		||||
          SECONDS.toNanos(startTimestamp.getEpochSecond()) + startTimestamp.getNano(), NANOSECONDS);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Starts a new {@link Span}.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,6 +15,8 @@ import static io.opentelemetry.api.common.AttributeKey.stringKey;
 | 
			
		|||
import static org.assertj.core.api.Assertions.assertThat;
 | 
			
		||||
 | 
			
		||||
import io.opentelemetry.api.common.Attributes;
 | 
			
		||||
import java.time.Instant;
 | 
			
		||||
import java.util.concurrent.TimeUnit;
 | 
			
		||||
import org.junit.jupiter.api.Test;
 | 
			
		||||
 | 
			
		||||
class PropagatedSpanTest {
 | 
			
		||||
| 
						 | 
				
			
			@ -41,15 +43,18 @@ class PropagatedSpanTest {
 | 
			
		|||
    span.setAttribute(doubleArrayKey("NullArrayDouble"), null);
 | 
			
		||||
    span.setAttribute((String) null, null);
 | 
			
		||||
    span.addEvent("event");
 | 
			
		||||
    span.addEvent("event", 0);
 | 
			
		||||
    span.addEvent("event", 0, TimeUnit.NANOSECONDS);
 | 
			
		||||
    span.addEvent("event", Instant.EPOCH);
 | 
			
		||||
    span.addEvent("event", Attributes.of(booleanKey("MyBooleanAttributeKey"), true));
 | 
			
		||||
    span.addEvent("event", Attributes.of(booleanKey("MyBooleanAttributeKey"), true), 0);
 | 
			
		||||
    span.addEvent(
 | 
			
		||||
        "event", Attributes.of(booleanKey("MyBooleanAttributeKey"), true), 0, TimeUnit.NANOSECONDS);
 | 
			
		||||
    span.setStatus(StatusCode.OK);
 | 
			
		||||
    span.setStatus(StatusCode.OK, "null");
 | 
			
		||||
    span.recordException(new IllegalStateException());
 | 
			
		||||
    span.recordException(new IllegalStateException(), Attributes.empty());
 | 
			
		||||
    span.end();
 | 
			
		||||
    span.end(0);
 | 
			
		||||
    span.end(0, TimeUnit.NANOSECONDS);
 | 
			
		||||
    span.end(Instant.EPOCH);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,6 +12,8 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
 | 
			
		|||
import io.opentelemetry.api.common.Attributes;
 | 
			
		||||
import io.opentelemetry.api.trace.Span.Kind;
 | 
			
		||||
import io.opentelemetry.context.Context;
 | 
			
		||||
import java.time.Instant;
 | 
			
		||||
import java.util.concurrent.TimeUnit;
 | 
			
		||||
import org.junit.jupiter.api.Test;
 | 
			
		||||
 | 
			
		||||
/** Unit tests for {@link Span.Builder}. */
 | 
			
		||||
| 
						 | 
				
			
			@ -32,7 +34,8 @@ class SpanBuilderTest {
 | 
			
		|||
    spanBuilder.setAttribute("key", .12345);
 | 
			
		||||
    spanBuilder.setAttribute("key", true);
 | 
			
		||||
    spanBuilder.setAttribute(stringKey("key"), "value");
 | 
			
		||||
    spanBuilder.setStartTimestamp(12345L);
 | 
			
		||||
    spanBuilder.setStartTimestamp(12345L, TimeUnit.NANOSECONDS);
 | 
			
		||||
    spanBuilder.setStartTimestamp(Instant.EPOCH);
 | 
			
		||||
    assertThat(spanBuilder.startSpan().getSpanContext().isValid()).isFalse();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -47,7 +50,7 @@ class SpanBuilderTest {
 | 
			
		|||
    Span.Builder spanBuilder = tracer.spanBuilder("MySpanName");
 | 
			
		||||
    assertThrows(
 | 
			
		||||
        IllegalArgumentException.class,
 | 
			
		||||
        () -> spanBuilder.setStartTimestamp(-1),
 | 
			
		||||
        () -> spanBuilder.setStartTimestamp(-1, TimeUnit.NANOSECONDS),
 | 
			
		||||
        "Negative startTimestamp");
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -82,7 +82,8 @@ class SpanConverter {
 | 
			
		|||
            .spanBuilder(ocSpanData.getName())
 | 
			
		||||
            .setStartTimestamp(
 | 
			
		||||
                TimeUnit.SECONDS.toNanos(ocSpanData.getStartTimestamp().getSeconds())
 | 
			
		||||
                    + ocSpanData.getStartTimestamp().getNanos());
 | 
			
		||||
                    + ocSpanData.getStartTimestamp().getNanos(),
 | 
			
		||||
                TimeUnit.NANOSECONDS);
 | 
			
		||||
    if (ocSpanData.getKind() != null) {
 | 
			
		||||
      builder.setSpanKind(mapKind(ocSpanData.getKind()));
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -167,7 +168,8 @@ class SpanConverter {
 | 
			
		|||
              AttributeKey.longKey(MESSAGE_EVENT_ATTRIBUTE_KEY_SIZE_COMPRESSED),
 | 
			
		||||
              event.getEvent().getCompressedMessageSize()),
 | 
			
		||||
          TimeUnit.SECONDS.toNanos(event.getTimestamp().getSeconds())
 | 
			
		||||
              + event.getTimestamp().getNanos());
 | 
			
		||||
              + event.getTimestamp().getNanos(),
 | 
			
		||||
          TimeUnit.NANOSECONDS);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -190,7 +192,8 @@ class SpanConverter {
 | 
			
		|||
          annotation.getEvent().getDescription(),
 | 
			
		||||
          attributesBuilder.build(),
 | 
			
		||||
          TimeUnit.SECONDS.toNanos(annotation.getTimestamp().getSeconds())
 | 
			
		||||
              + annotation.getTimestamp().getNanos());
 | 
			
		||||
              + annotation.getTimestamp().getNanos(),
 | 
			
		||||
          TimeUnit.NANOSECONDS);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -105,7 +105,8 @@ class SpanConverterTest {
 | 
			
		|||
            "First annotation!",
 | 
			
		||||
            Attributes.builder().put("Attribute1", false).put("Attribute2", 123).build(),
 | 
			
		||||
            TimeUnit.SECONDS.toNanos(annotations.get(0).getTimestamp().getSeconds())
 | 
			
		||||
                + annotations.get(0).getTimestamp().getNanos());
 | 
			
		||||
                + annotations.get(0).getTimestamp().getNanos(),
 | 
			
		||||
            TimeUnit.NANOSECONDS);
 | 
			
		||||
    verify(spanSpy, times(1))
 | 
			
		||||
        .addEvent(
 | 
			
		||||
            "Second annotation!",
 | 
			
		||||
| 
						 | 
				
			
			@ -114,7 +115,8 @@ class SpanConverterTest {
 | 
			
		|||
                .put("Attribute2", "attributeValue")
 | 
			
		||||
                .build(),
 | 
			
		||||
            TimeUnit.SECONDS.toNanos(annotations.get(1).getTimestamp().getSeconds())
 | 
			
		||||
                + annotations.get(1).getTimestamp().getNanos());
 | 
			
		||||
                + annotations.get(1).getTimestamp().getNanos(),
 | 
			
		||||
            TimeUnit.NANOSECONDS);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
| 
						 | 
				
			
			@ -145,7 +147,8 @@ class SpanConverterTest {
 | 
			
		|||
                .put("message.event.size.compressed", 34)
 | 
			
		||||
                .build(),
 | 
			
		||||
            TimeUnit.SECONDS.toNanos(messageEvents.get(0).getTimestamp().getSeconds())
 | 
			
		||||
                + messageEvents.get(0).getTimestamp().getNanos());
 | 
			
		||||
                + messageEvents.get(0).getTimestamp().getNanos(),
 | 
			
		||||
            TimeUnit.NANOSECONDS);
 | 
			
		||||
    verify(spanSpy, times(1))
 | 
			
		||||
        .addEvent(
 | 
			
		||||
            "8",
 | 
			
		||||
| 
						 | 
				
			
			@ -155,7 +158,8 @@ class SpanConverterTest {
 | 
			
		|||
                .put("message.event.size.compressed", 180)
 | 
			
		||||
                .build(),
 | 
			
		||||
            TimeUnit.SECONDS.toNanos(messageEvents.get(1).getTimestamp().getSeconds())
 | 
			
		||||
                + messageEvents.get(1).getTimestamp().getNanos());
 | 
			
		||||
                + messageEvents.get(1).getTimestamp().getNanos(),
 | 
			
		||||
            TimeUnit.NANOSECONDS);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private static RecordEventsSpanImpl createOpenCensusSpan() {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,6 +20,7 @@ import java.io.UnsupportedEncodingException;
 | 
			
		|||
import java.net.URI;
 | 
			
		||||
import java.net.URISyntaxException;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.concurrent.TimeUnit;
 | 
			
		||||
import org.junit.jupiter.api.BeforeEach;
 | 
			
		||||
import org.junit.jupiter.api.Test;
 | 
			
		||||
import org.junit.jupiter.api.extension.ExtendWith;
 | 
			
		||||
| 
						 | 
				
			
			@ -59,8 +60,9 @@ class TracezZPageHandlerTest {
 | 
			
		|||
 | 
			
		||||
    Span runningSpan = tracer.spanBuilder(RUNNING_SPAN).startSpan();
 | 
			
		||||
 | 
			
		||||
    Span latencySpan = tracer.spanBuilder(LATENCY_SPAN).setStartTimestamp(1L).startSpan();
 | 
			
		||||
    latencySpan.end(10002);
 | 
			
		||||
    Span latencySpan =
 | 
			
		||||
        tracer.spanBuilder(LATENCY_SPAN).setStartTimestamp(1L, TimeUnit.NANOSECONDS).startSpan();
 | 
			
		||||
    latencySpan.end(10002, TimeUnit.NANOSECONDS);
 | 
			
		||||
 | 
			
		||||
    Span errorSpan = tracer.spanBuilder(ERROR_SPAN).startSpan();
 | 
			
		||||
    errorSpan.setStatus(StatusCode.ERROR);
 | 
			
		||||
| 
						 | 
				
			
			@ -142,32 +144,41 @@ class TracezZPageHandlerTest {
 | 
			
		|||
  void summaryTable_linkForLatencyBasedSpans_OnePerBoundary() {
 | 
			
		||||
    OutputStream output = new ByteArrayOutputStream();
 | 
			
		||||
    // Boundary 0, >1us
 | 
			
		||||
    Span latencySpanSubtype0 = tracer.spanBuilder(LATENCY_SPAN).setStartTimestamp(1L).startSpan();
 | 
			
		||||
    latencySpanSubtype0.end(1002);
 | 
			
		||||
    Span latencySpanSubtype0 =
 | 
			
		||||
        tracer.spanBuilder(LATENCY_SPAN).setStartTimestamp(1L, TimeUnit.NANOSECONDS).startSpan();
 | 
			
		||||
    latencySpanSubtype0.end(1002, TimeUnit.NANOSECONDS);
 | 
			
		||||
    // Boundary 1, >10us
 | 
			
		||||
    Span latencySpanSubtype1 = tracer.spanBuilder(LATENCY_SPAN).setStartTimestamp(1L).startSpan();
 | 
			
		||||
    latencySpanSubtype1.end(10002);
 | 
			
		||||
    Span latencySpanSubtype1 =
 | 
			
		||||
        tracer.spanBuilder(LATENCY_SPAN).setStartTimestamp(1L, TimeUnit.NANOSECONDS).startSpan();
 | 
			
		||||
    latencySpanSubtype1.end(10002, TimeUnit.NANOSECONDS);
 | 
			
		||||
    // Boundary 2, >100us
 | 
			
		||||
    Span latencySpanSubtype2 = tracer.spanBuilder(LATENCY_SPAN).setStartTimestamp(1L).startSpan();
 | 
			
		||||
    latencySpanSubtype2.end(100002);
 | 
			
		||||
    Span latencySpanSubtype2 =
 | 
			
		||||
        tracer.spanBuilder(LATENCY_SPAN).setStartTimestamp(1L, TimeUnit.NANOSECONDS).startSpan();
 | 
			
		||||
    latencySpanSubtype2.end(100002, TimeUnit.NANOSECONDS);
 | 
			
		||||
    // Boundary 3, >1ms
 | 
			
		||||
    Span latencySpanSubtype3 = tracer.spanBuilder(LATENCY_SPAN).setStartTimestamp(1L).startSpan();
 | 
			
		||||
    latencySpanSubtype3.end(1000002);
 | 
			
		||||
    Span latencySpanSubtype3 =
 | 
			
		||||
        tracer.spanBuilder(LATENCY_SPAN).setStartTimestamp(1L, TimeUnit.NANOSECONDS).startSpan();
 | 
			
		||||
    latencySpanSubtype3.end(1000002, TimeUnit.NANOSECONDS);
 | 
			
		||||
    // Boundary 4, >10ms
 | 
			
		||||
    Span latencySpanSubtype4 = tracer.spanBuilder(LATENCY_SPAN).setStartTimestamp(1L).startSpan();
 | 
			
		||||
    latencySpanSubtype4.end(10000002);
 | 
			
		||||
    Span latencySpanSubtype4 =
 | 
			
		||||
        tracer.spanBuilder(LATENCY_SPAN).setStartTimestamp(1L, TimeUnit.NANOSECONDS).startSpan();
 | 
			
		||||
    latencySpanSubtype4.end(10000002, TimeUnit.NANOSECONDS);
 | 
			
		||||
    // Boundary 5, >100ms
 | 
			
		||||
    Span latencySpanSubtype5 = tracer.spanBuilder(LATENCY_SPAN).setStartTimestamp(1L).startSpan();
 | 
			
		||||
    latencySpanSubtype5.end(100000002);
 | 
			
		||||
    Span latencySpanSubtype5 =
 | 
			
		||||
        tracer.spanBuilder(LATENCY_SPAN).setStartTimestamp(1L, TimeUnit.NANOSECONDS).startSpan();
 | 
			
		||||
    latencySpanSubtype5.end(100000002, TimeUnit.NANOSECONDS);
 | 
			
		||||
    // Boundary 6, >1s
 | 
			
		||||
    Span latencySpanSubtype6 = tracer.spanBuilder(LATENCY_SPAN).setStartTimestamp(1L).startSpan();
 | 
			
		||||
    latencySpanSubtype6.end(1000000002);
 | 
			
		||||
    Span latencySpanSubtype6 =
 | 
			
		||||
        tracer.spanBuilder(LATENCY_SPAN).setStartTimestamp(1L, TimeUnit.NANOSECONDS).startSpan();
 | 
			
		||||
    latencySpanSubtype6.end(1000000002, TimeUnit.NANOSECONDS);
 | 
			
		||||
    // Boundary 7, >10s
 | 
			
		||||
    Span latencySpanSubtype7 = tracer.spanBuilder(LATENCY_SPAN).setStartTimestamp(1L).startSpan();
 | 
			
		||||
    latencySpanSubtype7.end(10000000002L);
 | 
			
		||||
    Span latencySpanSubtype7 =
 | 
			
		||||
        tracer.spanBuilder(LATENCY_SPAN).setStartTimestamp(1L, TimeUnit.NANOSECONDS).startSpan();
 | 
			
		||||
    latencySpanSubtype7.end(10000000002L, TimeUnit.NANOSECONDS);
 | 
			
		||||
    // Boundary 8, >100s
 | 
			
		||||
    Span latencySpanSubtype8 = tracer.spanBuilder(LATENCY_SPAN).setStartTimestamp(1L).startSpan();
 | 
			
		||||
    latencySpanSubtype8.end(100000000002L);
 | 
			
		||||
    Span latencySpanSubtype8 =
 | 
			
		||||
        tracer.spanBuilder(LATENCY_SPAN).setStartTimestamp(1L, TimeUnit.NANOSECONDS).startSpan();
 | 
			
		||||
    latencySpanSubtype8.end(100000000002L, TimeUnit.NANOSECONDS);
 | 
			
		||||
 | 
			
		||||
    TracezZPageHandler tracezZPageHandler = new TracezZPageHandler(dataAggregator);
 | 
			
		||||
    tracezZPageHandler.emitHtml(emptyQueryMap, output);
 | 
			
		||||
| 
						 | 
				
			
			@ -205,14 +216,18 @@ class TracezZPageHandlerTest {
 | 
			
		|||
  void summaryTable_linkForLatencyBasedSpans_MultipleForOneBoundary() {
 | 
			
		||||
    OutputStream output = new ByteArrayOutputStream();
 | 
			
		||||
    // 4 samples in boundary 5, >100ms
 | 
			
		||||
    Span latencySpan100ms1 = tracer.spanBuilder(LATENCY_SPAN).setStartTimestamp(1L).startSpan();
 | 
			
		||||
    latencySpan100ms1.end(112931232L);
 | 
			
		||||
    Span latencySpan100ms2 = tracer.spanBuilder(LATENCY_SPAN).setStartTimestamp(1L).startSpan();
 | 
			
		||||
    latencySpan100ms2.end(138694322L);
 | 
			
		||||
    Span latencySpan100ms3 = tracer.spanBuilder(LATENCY_SPAN).setStartTimestamp(1L).startSpan();
 | 
			
		||||
    latencySpan100ms3.end(154486482L);
 | 
			
		||||
    Span latencySpan100ms4 = tracer.spanBuilder(LATENCY_SPAN).setStartTimestamp(1L).startSpan();
 | 
			
		||||
    latencySpan100ms4.end(194892582L);
 | 
			
		||||
    Span latencySpan100ms1 =
 | 
			
		||||
        tracer.spanBuilder(LATENCY_SPAN).setStartTimestamp(1L, TimeUnit.NANOSECONDS).startSpan();
 | 
			
		||||
    latencySpan100ms1.end(112931232L, TimeUnit.NANOSECONDS);
 | 
			
		||||
    Span latencySpan100ms2 =
 | 
			
		||||
        tracer.spanBuilder(LATENCY_SPAN).setStartTimestamp(1L, TimeUnit.NANOSECONDS).startSpan();
 | 
			
		||||
    latencySpan100ms2.end(138694322L, TimeUnit.NANOSECONDS);
 | 
			
		||||
    Span latencySpan100ms3 =
 | 
			
		||||
        tracer.spanBuilder(LATENCY_SPAN).setStartTimestamp(1L, TimeUnit.NANOSECONDS).startSpan();
 | 
			
		||||
    latencySpan100ms3.end(154486482L, TimeUnit.NANOSECONDS);
 | 
			
		||||
    Span latencySpan100ms4 =
 | 
			
		||||
        tracer.spanBuilder(LATENCY_SPAN).setStartTimestamp(1L, TimeUnit.NANOSECONDS).startSpan();
 | 
			
		||||
    latencySpan100ms4.end(194892582L, TimeUnit.NANOSECONDS);
 | 
			
		||||
 | 
			
		||||
    TracezZPageHandler tracezZPageHandler = new TracezZPageHandler(dataAggregator);
 | 
			
		||||
    tracezZPageHandler.emitHtml(emptyQueryMap, output);
 | 
			
		||||
| 
						 | 
				
			
			@ -270,10 +285,12 @@ class TracezZPageHandlerTest {
 | 
			
		|||
  @Test
 | 
			
		||||
  void spanDetails_emitLatencySpanDetailsCorrectly() {
 | 
			
		||||
    OutputStream output = new ByteArrayOutputStream();
 | 
			
		||||
    Span latencySpan1 = tracer.spanBuilder(LATENCY_SPAN).setStartTimestamp(1L).startSpan();
 | 
			
		||||
    latencySpan1.end(10002);
 | 
			
		||||
    Span latencySpan2 = tracer.spanBuilder(LATENCY_SPAN).setStartTimestamp(1L).startSpan();
 | 
			
		||||
    latencySpan2.end(10002);
 | 
			
		||||
    Span latencySpan1 =
 | 
			
		||||
        tracer.spanBuilder(LATENCY_SPAN).setStartTimestamp(1L, TimeUnit.NANOSECONDS).startSpan();
 | 
			
		||||
    latencySpan1.end(10002, TimeUnit.NANOSECONDS);
 | 
			
		||||
    Span latencySpan2 =
 | 
			
		||||
        tracer.spanBuilder(LATENCY_SPAN).setStartTimestamp(1L, TimeUnit.NANOSECONDS).startSpan();
 | 
			
		||||
    latencySpan2.end(10002, TimeUnit.NANOSECONDS);
 | 
			
		||||
    Map<String, String> queryMap =
 | 
			
		||||
        ImmutableMap.of("zspanname", LATENCY_SPAN, "ztype", "1", "zsubtype", "1");
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -31,6 +31,7 @@ import java.io.StringWriter;
 | 
			
		|||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.concurrent.TimeUnit;
 | 
			
		||||
import java.util.logging.Level;
 | 
			
		||||
import java.util.logging.Logger;
 | 
			
		||||
import javax.annotation.Nonnull;
 | 
			
		||||
| 
						 | 
				
			
			@ -317,11 +318,11 @@ final class RecordEventsReadableSpan implements ReadWriteSpan {
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public ReadWriteSpan addEvent(String name, long timestamp) {
 | 
			
		||||
  public ReadWriteSpan addEvent(String name, long timestamp, TimeUnit unit) {
 | 
			
		||||
    if (name == null) {
 | 
			
		||||
      return this;
 | 
			
		||||
    }
 | 
			
		||||
    addTimedEvent(Event.create(timestamp, name, Attributes.empty(), 0));
 | 
			
		||||
    addTimedEvent(Event.create(unit.toNanos(timestamp), name, Attributes.empty(), 0));
 | 
			
		||||
    return this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -341,14 +342,14 @@ final class RecordEventsReadableSpan implements ReadWriteSpan {
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public ReadWriteSpan addEvent(String name, Attributes attributes, long timestamp) {
 | 
			
		||||
  public ReadWriteSpan addEvent(String name, Attributes attributes, long timestamp, TimeUnit unit) {
 | 
			
		||||
    if (name == null) {
 | 
			
		||||
      return this;
 | 
			
		||||
    }
 | 
			
		||||
    int totalAttributeCount = attributes.size();
 | 
			
		||||
    addTimedEvent(
 | 
			
		||||
        Event.create(
 | 
			
		||||
            timestamp,
 | 
			
		||||
            unit.toNanos(timestamp),
 | 
			
		||||
            name,
 | 
			
		||||
            copyAndLimitAttributes(attributes, traceConfig.getMaxNumberOfAttributesPerEvent()),
 | 
			
		||||
            totalAttributeCount));
 | 
			
		||||
| 
						 | 
				
			
			@ -408,7 +409,7 @@ final class RecordEventsReadableSpan implements ReadWriteSpan {
 | 
			
		|||
    if (exception == null) {
 | 
			
		||||
      return this;
 | 
			
		||||
    }
 | 
			
		||||
    long timestamp = clock.now();
 | 
			
		||||
    long timestampNanos = clock.now();
 | 
			
		||||
 | 
			
		||||
    Attributes.Builder attributes = Attributes.builder();
 | 
			
		||||
    attributes.put(SemanticAttributes.EXCEPTION_TYPE, exception.getClass().getCanonicalName());
 | 
			
		||||
| 
						 | 
				
			
			@ -423,7 +424,11 @@ final class RecordEventsReadableSpan implements ReadWriteSpan {
 | 
			
		|||
      attributes.putAll(additionalAttributes);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    addEvent(SemanticAttributes.EXCEPTION_EVENT_NAME, attributes.build(), timestamp);
 | 
			
		||||
    addEvent(
 | 
			
		||||
        SemanticAttributes.EXCEPTION_EVENT_NAME,
 | 
			
		||||
        attributes.build(),
 | 
			
		||||
        timestampNanos,
 | 
			
		||||
        TimeUnit.NANOSECONDS);
 | 
			
		||||
    return this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -448,8 +453,11 @@ final class RecordEventsReadableSpan implements ReadWriteSpan {
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public void end(long timestamp) {
 | 
			
		||||
    endInternal(timestamp == 0 ? clock.now() : timestamp);
 | 
			
		||||
  public void end(long timestamp, TimeUnit unit) {
 | 
			
		||||
    if (unit == null) {
 | 
			
		||||
      unit = TimeUnit.NANOSECONDS;
 | 
			
		||||
    }
 | 
			
		||||
    endInternal(timestamp == 0 ? clock.now() : unit.toNanos(timestamp));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private void endInternal(long endEpochNanos) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,6 +34,7 @@ import java.util.ArrayList;
 | 
			
		|||
import java.util.Collections;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
import java.util.concurrent.TimeUnit;
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
 | 
			
		||||
/** {@link SpanBuilderSdk} is SDK implementation of {@link Span.Builder}. */
 | 
			
		||||
| 
						 | 
				
			
			@ -165,9 +166,9 @@ final class SpanBuilderSdk implements Span.Builder {
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public Span.Builder setStartTimestamp(long startTimestamp) {
 | 
			
		||||
  public Span.Builder setStartTimestamp(long startTimestamp, TimeUnit unit) {
 | 
			
		||||
    Utils.checkArgument(startTimestamp >= 0, "Negative startTimestamp");
 | 
			
		||||
    startEpochNanos = startTimestamp;
 | 
			
		||||
    startEpochNanos = unit.toNanos(startTimestamp);
 | 
			
		||||
    return this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,6 +38,7 @@ import io.opentelemetry.sdk.trace.data.SpanData.Link;
 | 
			
		|||
import io.opentelemetry.sdk.trace.data.SpanData.Status;
 | 
			
		||||
import java.io.PrintWriter;
 | 
			
		||||
import java.io.StringWriter;
 | 
			
		||||
import java.time.Instant;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
| 
						 | 
				
			
			@ -481,11 +482,62 @@ class RecordEventsReadableSpanTest {
 | 
			
		|||
    try {
 | 
			
		||||
      span.addEvent("event1");
 | 
			
		||||
      span.addEvent("event2", Attributes.of(stringKey("e1key"), "e1Value"));
 | 
			
		||||
      span.addEvent("event3", 10, TimeUnit.SECONDS);
 | 
			
		||||
      span.addEvent("event4", Instant.ofEpochSecond(20));
 | 
			
		||||
      span.addEvent(
 | 
			
		||||
          "event5", Attributes.builder().put("foo", "bar").build(), 30, TimeUnit.MILLISECONDS);
 | 
			
		||||
      span.addEvent(
 | 
			
		||||
          "event6", Attributes.builder().put("foo", "bar").build(), Instant.ofEpochMilli(1000));
 | 
			
		||||
    } finally {
 | 
			
		||||
      span.end();
 | 
			
		||||
    }
 | 
			
		||||
    List<Event> events = span.toSpanData().getEvents();
 | 
			
		||||
    assertThat(events.size()).isEqualTo(2);
 | 
			
		||||
    assertThat(events).hasSize(6);
 | 
			
		||||
    assertThat(events.get(0))
 | 
			
		||||
        .satisfies(
 | 
			
		||||
            event -> {
 | 
			
		||||
              assertThat(event.getName()).isEqualTo("event1");
 | 
			
		||||
              assertThat(event.getAttributes()).isEqualTo(Attributes.empty());
 | 
			
		||||
              assertThat(event.getEpochNanos()).isEqualTo(START_EPOCH_NANOS);
 | 
			
		||||
            });
 | 
			
		||||
    assertThat(events.get(1))
 | 
			
		||||
        .satisfies(
 | 
			
		||||
            event -> {
 | 
			
		||||
              assertThat(event.getName()).isEqualTo("event2");
 | 
			
		||||
              assertThat(event.getAttributes())
 | 
			
		||||
                  .isEqualTo(Attributes.of(stringKey("e1key"), "e1Value"));
 | 
			
		||||
              assertThat(event.getEpochNanos()).isEqualTo(START_EPOCH_NANOS);
 | 
			
		||||
            });
 | 
			
		||||
    assertThat(events.get(2))
 | 
			
		||||
        .satisfies(
 | 
			
		||||
            event -> {
 | 
			
		||||
              assertThat(event.getName()).isEqualTo("event3");
 | 
			
		||||
              assertThat(event.getAttributes()).isEqualTo(Attributes.empty());
 | 
			
		||||
              assertThat(event.getEpochNanos()).isEqualTo(TimeUnit.SECONDS.toNanos(10));
 | 
			
		||||
            });
 | 
			
		||||
    assertThat(events.get(3))
 | 
			
		||||
        .satisfies(
 | 
			
		||||
            event -> {
 | 
			
		||||
              assertThat(event.getName()).isEqualTo("event4");
 | 
			
		||||
              assertThat(event.getAttributes()).isEqualTo(Attributes.empty());
 | 
			
		||||
              assertThat(event.getEpochNanos()).isEqualTo(TimeUnit.SECONDS.toNanos(20));
 | 
			
		||||
            });
 | 
			
		||||
    assertThat(events.get(4))
 | 
			
		||||
        .satisfies(
 | 
			
		||||
            event -> {
 | 
			
		||||
              assertThat(event.getName()).isEqualTo("event5");
 | 
			
		||||
              assertThat(event.getAttributes())
 | 
			
		||||
                  .isEqualTo(Attributes.builder().put("foo", "bar").build());
 | 
			
		||||
              assertThat(event.getEpochNanos()).isEqualTo(TimeUnit.MILLISECONDS.toNanos(30));
 | 
			
		||||
            });
 | 
			
		||||
    assertThat(events.get(5))
 | 
			
		||||
        .satisfies(
 | 
			
		||||
            event -> {
 | 
			
		||||
              assertThat(event.getName()).isEqualTo("event6");
 | 
			
		||||
              assertThat(event.getAttributes())
 | 
			
		||||
                  .isEqualTo(Attributes.builder().put("foo", "bar").build());
 | 
			
		||||
              assertThat(event.getEpochNanos()).isEqualTo(TimeUnit.MILLISECONDS.toNanos(1000));
 | 
			
		||||
            });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
| 
						 | 
				
			
			@ -511,6 +563,20 @@ class RecordEventsReadableSpanTest {
 | 
			
		|||
    assertThat(spanData.getTotalAttributeCount()).isEqualTo(2 * maxNumberOfAttributes);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  void endWithTimestamp_numeric() {
 | 
			
		||||
    RecordEventsReadableSpan span1 = createTestRootSpan();
 | 
			
		||||
    span1.end(10, TimeUnit.NANOSECONDS);
 | 
			
		||||
    assertThat(span1.toSpanData().getEndEpochNanos()).isEqualTo(10);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  void endWithTimestamp_instant() {
 | 
			
		||||
    RecordEventsReadableSpan span1 = createTestRootSpan();
 | 
			
		||||
    span1.end(Instant.ofEpochMilli(10));
 | 
			
		||||
    assertThat(span1.toSpanData().getEndEpochNanos()).isEqualTo(TimeUnit.MILLISECONDS.toNanos(10));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  void droppingAndAddingAttributes() {
 | 
			
		||||
    final int maxNumberOfAttributes = 8;
 | 
			
		||||
| 
						 | 
				
			
			@ -690,11 +756,15 @@ class RecordEventsReadableSpanTest {
 | 
			
		|||
    span.setStatus(null, null);
 | 
			
		||||
    span.updateName(null);
 | 
			
		||||
    span.addEvent(null);
 | 
			
		||||
    span.addEvent(null, 0);
 | 
			
		||||
    span.addEvent(null, null);
 | 
			
		||||
    span.addEvent(null, null, 0);
 | 
			
		||||
    span.addEvent(null, 0, null);
 | 
			
		||||
    span.addEvent(null, (Attributes) null);
 | 
			
		||||
    span.addEvent(null, (Instant) null);
 | 
			
		||||
    span.addEvent(null, null, 0, null);
 | 
			
		||||
    span.addEvent(null, null, null);
 | 
			
		||||
    span.recordException(null);
 | 
			
		||||
    span.end(0);
 | 
			
		||||
    span.end(0, TimeUnit.NANOSECONDS);
 | 
			
		||||
    span.end(1, null);
 | 
			
		||||
    span.end(null);
 | 
			
		||||
 | 
			
		||||
    // Ignored the bad calls
 | 
			
		||||
    SpanData data = span.toSpanData();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,9 +34,11 @@ import io.opentelemetry.sdk.trace.data.SpanData;
 | 
			
		|||
import io.opentelemetry.sdk.trace.data.SpanData.Link;
 | 
			
		||||
import io.opentelemetry.sdk.trace.samplers.Sampler;
 | 
			
		||||
import io.opentelemetry.sdk.trace.samplers.SamplingResult;
 | 
			
		||||
import java.time.Instant;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.concurrent.TimeUnit;
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import org.junit.jupiter.api.BeforeEach;
 | 
			
		||||
import org.junit.jupiter.api.Test;
 | 
			
		||||
| 
						 | 
				
			
			@ -793,11 +795,36 @@ class SpanBuilderSdkTest {
 | 
			
		|||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  void startTimestamp_numeric() {
 | 
			
		||||
    RecordEventsReadableSpan span =
 | 
			
		||||
        (RecordEventsReadableSpan)
 | 
			
		||||
            tracerSdk
 | 
			
		||||
                .spanBuilder(SPAN_NAME)
 | 
			
		||||
                .setStartTimestamp(10, TimeUnit.NANOSECONDS)
 | 
			
		||||
                .startSpan();
 | 
			
		||||
    span.end();
 | 
			
		||||
    assertThat(span.toSpanData().getStartEpochNanos()).isEqualTo(10);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  void startTimestamp_instant() {
 | 
			
		||||
    RecordEventsReadableSpan span =
 | 
			
		||||
        (RecordEventsReadableSpan)
 | 
			
		||||
            tracerSdk
 | 
			
		||||
                .spanBuilder(SPAN_NAME)
 | 
			
		||||
                .setStartTimestamp(Instant.ofEpochMilli(100))
 | 
			
		||||
                .startSpan();
 | 
			
		||||
    span.end();
 | 
			
		||||
    assertThat(span.toSpanData().getStartEpochNanos())
 | 
			
		||||
        .isEqualTo(TimeUnit.MILLISECONDS.toNanos(100));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  void startTimestamp_null() {
 | 
			
		||||
    assertThrows(
 | 
			
		||||
        IllegalArgumentException.class,
 | 
			
		||||
        () -> tracerSdk.spanBuilder(SPAN_NAME).setStartTimestamp(-1),
 | 
			
		||||
        () -> tracerSdk.spanBuilder(SPAN_NAME).setStartTimestamp(-1, TimeUnit.NANOSECONDS),
 | 
			
		||||
        "Negative startTimestamp");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue