All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.undefinedlabs.scope.Span Maven / Gradle / Ivy

package com.undefinedlabs.scope;

import com.undefinedlabs.scope.events.log.LogEvent;
import com.undefinedlabs.scope.statistics.Statistics;
import com.undefinedlabs.scope.utils.tag.TagKeys;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Span implements io.opentracing.Span {

  private final ScopeTracer tracer;
  private final SpanContext context;
  private final long startTimeMicroseconds;
  private final long startTimeNanoTicks;
  private final boolean computeDurationViaNanoTicks;
  private long durationMicroseconds;
  private long durationNanoTicks;
  private final Map tags;
  private final List references;
  private List logs;
  private String operationName;
  private boolean finished = false;
  private boolean markUnfinished = false;

  protected Span(
      final ScopeTracer tracer,
      final String operationName,
      final SpanContext context,
      final long startTimeMicroseconds,
      final long startTimeNanoTicks,
      final boolean computeDurationViaNanoTicks,
      final Map tags,
      final List references) {
    this.tracer = tracer;
    this.operationName = operationName;
    this.context = context;
    this.startTimeMicroseconds = startTimeMicroseconds;
    this.startTimeNanoTicks = startTimeNanoTicks;
    this.computeDurationViaNanoTicks = computeDurationViaNanoTicks;
    this.tags = new HashMap<>();
    this.references = references != null ? new ArrayList<>(references) : null;

    for (Map.Entry tag : tags.entrySet()) {
      setTagAsObject(tag.getKey(), tag.getValue());
    }
  }

  @Override
  public io.opentracing.SpanContext context() {
    return this.context;
  }

  @Override
  public io.opentracing.Span setTag(String key, String value) {
    return setTagAsObject(key, value);
  }

  @Override
  public io.opentracing.Span setTag(String key, boolean value) {
    return setTagAsObject(key, value);
  }

  @Override
  public io.opentracing.Span setTag(String key, Number value) {
    return setTagAsObject(key, value);
  }

  public io.opentracing.Span setTag(String key, Object value) {
    return setTagAsObject(key, value);
  }

  @Override
  public  io.opentracing.Span setTag(io.opentracing.tag.Tag tag, T value) {
    return setTagAsObject(tag.getKey(), value);
  }

  @Override
  public io.opentracing.Span log(Map fields) {
    return this.log(this.tracer.clock().currentTimeMicros(), fields);
  }

  @Override
  public io.opentracing.Span log(long timestampMicroseconds, Map fields) {
    synchronized (this) {
      if (fields == null) {
        return this;
      }

      if (logs == null) {
        this.logs = new ArrayList<>();
      }

      this.logs.add(new SpanEventData(timestampMicroseconds, (Map) fields));
    }

    return this;
  }

  @Override
  public io.opentracing.Span log(String event) {
    return this.log(this.tracer.clock().currentTimeMicros(), event);
  }

  @Override
  public io.opentracing.Span log(long timestampMicroseconds, String event) {
    return this.log(
        timestampMicroseconds,
        this.tracer
            .eventFieldsFactory()
            .createFields(LogEvent.newBuilder().withMessage(event).build()));
  }

  @Override
  public io.opentracing.Span setBaggageItem(String key, String value) {
    synchronized (this) {
      this.context.getBaggage().put(key, value);
    }

    return this;
  }

  @Override
  public String getBaggageItem(String key) {
    synchronized (this) {
      return this.context.getBaggage().get(key);
    }
  }

  @Override
  public io.opentracing.Span setOperationName(String operationName) {
    synchronized (this) {
      this.operationName = operationName;
    }

    return this;
  }

  @Override
  public void finish() {
    if (this.computeDurationViaNanoTicks) {
      final long durationNanos = this.tracer.clock().currentNanoTicks() - this.startTimeNanoTicks;
      final long durationMicros = durationNanos / 1000;

      finishWithDuration(durationMicros, durationNanos);
    } else {
      finish(this.tracer.clock().currentTimeMicros());
    }
  }

  @Override
  public void finish(long finishMicros) {
    final long durationMicros = finishMicros - this.startTimeMicroseconds;
    final long durationNanos = durationMicros * 1000;

    finishWithDuration(durationMicros, durationNanos);
  }

  private void finishWithDuration(final long durationMicros, final long durationNanos) {
    synchronized (this) {
      if (this.finished) {
        return;
      }

      this.finished = true;
      this.durationMicroseconds = durationMicros;
      this.durationNanoTicks = durationNanos;
    }

    this.tracer.registerFinishedSpan(this);
    this.tracer.reportSpan(this);
    Statistics.INSTANCE.registerFinishedSpan(this);
  }

  public long getStartMicros() {
    synchronized (this) {
      return this.startTimeMicroseconds;
    }
  }

  public long getStartNanos() {
    synchronized (this) {
      return this.startTimeNanoTicks;
    }
  }

  public ScopeTracer getTracer() {
    return tracer;
  }

  public long getDurationMicros() {
    synchronized (this) {
      return this.durationMicroseconds;
    }
  }

  public long getDurationNanos() {
    synchronized (this) {
      return this.durationNanoTicks;
    }
  }

  public String getOperationName() {
    synchronized (this) {
      return this.operationName;
    }
  }

  public Map getTags() {
    synchronized (this) {
      return Collections.unmodifiableMap(new HashMap<>(tags));
    }
  }

  public List getReferences() {
    synchronized (this) {
      if (references == null) {
        return Collections.emptyList();
      }

      return Collections.unmodifiableList(references);
    }
  }

  public List getLogs() {
    synchronized (this) {
      return this.logs != null ? Collections.unmodifiableList(new ArrayList<>(logs)) : null;
    }
  }

  private io.opentracing.Span setTagAsObject(String key, Object value) {
    synchronized (this) {
      this.tags.put(key, value);
    }

    return this;
  }

  public io.opentracing.Span markUnfinished() {
    synchronized (this) {
      if (markUnfinished) {
        return this;
      }

      this.markUnfinished = true;
      this.tags.put(TagKeys.UNFINISHED, true);
    }

    return this;
  }

  public boolean isUnfinished() {
    synchronized (this) {
      return this.markUnfinished;
    }
  }

  @Override
  public String toString() {
    synchronized (this) {
      return this.context.toString() + " - " + this.operationName;
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy