package org.skywalking.apm.trace;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import org.skywalking.apm.trace.TraceId.DistributedTraceId;
import org.skywalking.apm.trace.TraceId.DistributedTraceIds;
import org.skywalking.apm.trace.TraceId.NewDistributedTraceId;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
/**
* {@link TraceSegment} is a segment or fragment of the distributed trace.
* {@see https://github.com/opentracing/specification/blob/master/specification.md#the-opentracing-data-model}
* A {@link
* TraceSegment} means the segment, which exists in current {@link Thread}. And the distributed trace is formed by multi
* {@link TraceSegment}s, because the distributed trace crosses multi-processes, multi-threads.
* <p>
* Created by wusheng on 2017/2/17.
*/
public class TraceSegment {
private static final String ID_TYPE = "Segment";
/**
* The id of this trace segment.
* Every segment has its unique-global-id.
*/
@Expose
@SerializedName(value = "ts")
private String traceSegmentId;
/**
* The start time of this trace segment.
*/
@Expose
@SerializedName(value = "st")
private long startTime;
/**
* The end time of this trace segment.
*/
@Expose
@SerializedName(value = "et")
private long endTime;
/**
* The refs of parent trace segments, except the primary one.
* For most RPC call, {@link #refs} contains only one element,
* but if this segment is a start span of batch process, the segment faces multi parents,
* at this moment, we use this {@link #refs} to link them.
*/
@Expose
@SerializedName(value = "rs")
private List<TraceSegmentRef> refs;
/**
* The spans belong to this trace segment.
* They all have finished.
* All active spans are hold and controlled by "skywalking-api" module.
*/
@Expose
@SerializedName(value = "ss")
private List<Span> spans;
/**
* The <code>applicationCode</code> represents a name of current application/JVM and indicates which is business
* role in the cluster.
* <p>
* e.g. account_app, billing_app
*/
@Expose
@SerializedName(value = "ac")
private String applicationCode;
/**
* The <code>relatedGlobalTraces</code> represent a set of all related trace. Most time it contains only one
* element, because only one parent {@link TraceSegment} exists, but, in batch scenario, the num becomes greater
* than 1, also meaning multi-parents {@link TraceSegment}.
* <p>
* The difference between <code>relatedGlobalTraces</code> and {@link #refs} is:
* {@link #refs} targets this {@link TraceSegment}'s direct parent,
* <p>
* and
* <p>
* <code>relatedGlobalTraces</code> targets this {@link TraceSegment}'s related call chain, a call chain contains
* multi {@link TraceSegment}s, only using {@link #refs} is not enough for analysis and ui.
*/
@Expose
@SerializedName(value = "gt")
private DistributedTraceIds relatedGlobalTraces;
/**
* The <code>sampled</code> is a flag, which represent, when this {@link TraceSegment} finished, it need to be send
* to Collector.
* <p>
* Its value depends on SamplingService. True, by default.
* <p>
* This value is not serialized.
*/
private boolean sampled;
/**
* Create a trace segment, by the given applicationCode.
*/
public TraceSegment(String applicationCode) {
this();
this.applicationCode = applicationCode;
}
/**
* Create a default/empty trace segment,
* with current time as start time,
* and generate a new segment id.
*/
public TraceSegment() {
this.startTime = System.currentTimeMillis();
this.traceSegmentId = GlobalIdGenerator.generate(ID_TYPE);
this.spans = new LinkedList<Span>();
this.relatedGlobalTraces = new DistributedTraceIds();
this.relatedGlobalTraces.append(new NewDistributedTraceId());
this.sampled = true;
}
/**
* Establish the link between this segment and its parents.
*
* @param refSegment {@link TraceSegmentRef}
*/
public void ref(TraceSegmentRef refSegment) {
if (refs == null) {
refs = new LinkedList<TraceSegmentRef>();
}
if (!refs.contains(refSegment)) {
refs.add(refSegment);
}
}
/**
* Establish the line between this segment and all relative global trace ids.
*
* @param distributedTraceIds multi global trace ids. @see {@link DistributedTraceId}
*/
public void relatedGlobalTraces(List<DistributedTraceId> distributedTraceIds) {
if (distributedTraceIds == null || distributedTraceIds.size() == 0) {
return;
}
for (DistributedTraceId distributedTraceId : distributedTraceIds) {
relatedGlobalTraces.append(distributedTraceId);
}
}
/**
* After {@link Span} is finished, as be controller by "skywalking-api" module,
* notify the {@link TraceSegment} to archive it.
*
* @param finishedSpan
*/
public void archive(Span finishedSpan) {
spans.add(finishedSpan);
}
/**
* Finish this {@link TraceSegment}.
* <p>
* return this, for chaining
*/
public TraceSegment finish() {
this.endTime = System.currentTimeMillis();
return this;
}
public String getTraceSegmentId() {
return traceSegmentId;
}
public long getStartTime() {
return startTime;
}
public long getEndTime() {
return endTime;
}
public List<TraceSegmentRef> getRefs() {
if (refs == null) {
return null;
}
return Collections.unmodifiableList(refs);
}
public List<DistributedTraceId> getRelatedGlobalTraces() {
return relatedGlobalTraces.getRelatedGlobalTraces();
}
public List<Span> getSpans() {
return Collections.unmodifiableList(spans);
}
public String getApplicationCode() {
return applicationCode;
}
public boolean isSampled() {
return sampled;
}
public void setSampled(boolean sampled) {
this.sampled = sampled;
}
@Override
public String toString() {
return "TraceSegment{" +
"traceSegmentId='" + traceSegmentId + '\'' +
", startTime=" + startTime +
", endTime=" + endTime +
", refs=" + refs +
", spans=" + spans +
", applicationCode='" + applicationCode + '\'' +
", relatedGlobalTraces=" + relatedGlobalTraces +
'}';
}
}