opentelemetry-java-instrume.../src/main/java/com/datadoghq/trace/impl/DDSpan.java

238 lines
6.1 KiB
Java

package com.datadoghq.trace.impl;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.annotation.JsonGetter;
import io.opentracing.Span;
public class DDSpan implements io.opentracing.Span {
protected String operationName;
protected Map<String, Object> tags;
protected final long startTime;
protected long startTimeNano;
protected long durationNano;
protected final DDSpanContext context;
private final static Logger logger = LoggerFactory.getLogger(DDSpan.class);
DDSpan(
String operationName,
Map<String, Object> tags,
long timestampMilliseconds,
DDSpanContext context) {
this.operationName = operationName;
this.tags = tags;
this.context = context;
// record the start time in nano (current milli + nano delta)
if (timestampMilliseconds == 0L) {
this.startTime = System.currentTimeMillis();
} else {
this.startTime = timestampMilliseconds;
}
this.startTimeNano = System.nanoTime();
// track each span of the trace
this.context.getTrace().add(this);
// check DD attributes required
if (this.context.getServiceName() == null) {
throw new IllegalArgumentException("No ServiceName provided");
}
logger.debug(this+": Starting.");
}
public void finish(long stopTimeMillis) {
// formula: millis(stop - start) * 1000 * 1000 + nano(stop - start)
long stopTimeNano = System.nanoTime();
this.durationNano = (stopTimeMillis - startTime) * 1000000L + (stopTimeNano - this.startTimeNano);
logger.debug(this+": finishing.");
// warn if one of the parent's children is not finished
if (this.isRootSpan()) {
logger.debug(this+": Checking all children attached to the current root span");
List<Span> spans = this.context.getTrace();
for (Span span : spans) {
if (((DDSpan) span).getDurationNano() == 0L) {
// FIXME
logger.warn(this+": The parent span is marked as finished but this span isn't. You have to close each children. Trace: "+context().getTrace());
}
}
this.context.getTracer().write(this.context.getTrace());
logger.debug(this+": Sending the trace to the writer");
}
}
public void finish() {
finish(System.currentTimeMillis());
}
public void close() {
this.finish();
}
private boolean isRootSpan() {
return context.getTraceId() == context.getSpanId();
}
public Span setTag(String tag, String value) {
return this.setTag(tag, value);
}
public Span setTag(String tag, boolean value) {
return this.setTag(tag, value);
}
public Span setTag(String tag, Number value) {
return this.setTag(tag, (Object) value);
}
private Span setTag(String tag, Object value) {
this.tags.put(tag, value);
return this;
}
public Span log(Map<String, ?> map) {
return null;
}
public Span log(long l, Map<String, ?> map) {
return null;
}
public Span log(String s) {
return null;
}
public Span log(long l, String s) {
return null;
}
public DDSpanContext context() {
return this.context;
}
public Span setBaggageItem(String key, String value) {
this.context.setBaggageItem(key, value);
return this;
}
public String getBaggageItem(String key) {
return this.context.getBaggageItem(key);
}
public Span setOperationName(String operationName) {
// FIXME operationName is in each constructor --> always IAE
if (this.operationName != null) {
throw new IllegalArgumentException("The operationName is already assigned.");
}
this.operationName = operationName;
return this;
}
public Span log(String s, Object o) {
return null;
}
public Span log(long l, String s, Object o) {
return null;
}
//Getters and JSON serialisation instructions
@JsonGetter(value = "name")
public String getOperationName() {
return operationName;
}
@JsonGetter(value = "meta")
public Map<String, Object> getTags() {
return this.tags;
}
@JsonGetter(value = "start")
public long getStartTime() {
return startTimeNano;
}
@JsonGetter(value = "duration")
public long getDurationNano() {
return durationNano;
}
public String getService() {
return context.getServiceName();
}
@JsonGetter(value = "trace_id")
public long getTraceId() {
return context.getTraceId();
}
@JsonGetter(value = "span_id")
public long getSpanId() {
return context.getSpanId();
}
@JsonGetter(value = "parent_id")
public long getParentId() {
return context.getParentId();
}
@JsonGetter(value = "resource")
public String getResourceName() {
return context.getResourceName() == null ? this.operationName : context.getResourceName();
}
public String getType() {
return context.getSpanType();
}
public int getError() {
return context.getErrorFlag() ? 1 : 0;
}
@Override
public String toString() {
return context.toString();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((context == null) ? 0 : context.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
DDSpan other = (DDSpan) obj;
if (context == null) {
if (other.context != null)
return false;
} else if (!context.equals(other.context))
return false;
return true;
}
}