Span.java 11.9 KB
Newer Older
P
pengys5 已提交
1
package org.skywalking.apm.trace;
2

3 4
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
P
pengys5 已提交
5

6 7
import java.io.ByteArrayOutputStream;
import java.io.IOException;
P
pengys5 已提交
8
import java.util.*;
wu-sheng's avatar
wu-sheng 已提交
9

10 11 12
/**
 * Span is a concept from OpenTracing Spec, also from Google Dapper Paper.
 * Traces in OpenTracing are defined implicitly by their Spans.
P
pengys5 已提交
13
 * <p>
14 15
 * Know more things about span concept:
 * {@see https://github.com/opentracing/specification/blob/master/specification.md#the-opentracing-data-model}
P
pengys5 已提交
16
 * <p>
17 18
 * Created by wusheng on 2017/2/17.
 */
19
public class Span {
20
    @Expose
21
    @SerializedName(value = "si")
wu-sheng's avatar
wu-sheng 已提交
22 23
    private int spanId;

24
    @Expose
25
    @SerializedName(value = "ps")
wu-sheng's avatar
wu-sheng 已提交
26 27 28 29 30
    private int parentSpanId;

    /**
     * The start time of this Span.
     */
31
    @Expose
32
    @SerializedName(value = "st")
wu-sheng's avatar
wu-sheng 已提交
33 34 35 36 37
    private long startTime;

    /**
     * The end time of this Span.
     */
38
    @Expose
39
    @SerializedName(value = "et")
wu-sheng's avatar
wu-sheng 已提交
40 41 42 43 44 45 46
    private long endTime;

    /**
     * The operation name ot this Span.
     * If you want to know, how to set an operation name,
     * {@see https://github.com/opentracing/specification/blob/master/specification.md#start-a-new-span}
     */
47
    @Expose
48
    @SerializedName(value = "on")
wu-sheng's avatar
wu-sheng 已提交
49 50 51 52
    private String operationName;

    /**
     * Tag is a concept from OpenTracing spec.
P
pengys5 已提交
53
     * <p>
wu-sheng's avatar
wu-sheng 已提交
54 55
     * {@see https://github.com/opentracing/specification/blob/master/specification.md#set-a-span-tag}
     */
56
    @Expose
57
    @SerializedName(value = "ts")
58 59 60
    private final Map<String, String> tagsWithStr;

    @Expose
61
    @SerializedName(value = "tb")
62 63 64
    private final Map<String, Boolean> tagsWithBool;

    @Expose
65
    @SerializedName(value = "ti")
66
    private final Map<String, Integer> tagsWithInt;
wu-sheng's avatar
wu-sheng 已提交
67 68 69

    /**
     * Log is a concept from OpenTracing spec.
P
pengys5 已提交
70
     * <p>
wu-sheng's avatar
wu-sheng 已提交
71 72
     * {@see https://github.com/opentracing/specification/blob/master/specification.md#log-structured-data}
     */
73
    @Expose
74
    @SerializedName(value = "lo")
wu-sheng's avatar
wu-sheng 已提交
75
    private final List<LogData> logs;
wu-sheng's avatar
wu-sheng 已提交
76 77

    /**
78
     * Create a new span, by given span id, parent span id and operationName.
wu-sheng's avatar
wu-sheng 已提交
79 80
     * This span must belong a {@link TraceSegment}, also is a part of Distributed Trace.
     *
P
pengys5 已提交
81 82 83
     * @param spanId        given by the creator, and must be unique id in the {@link TraceSegment}
     * @param parentSpanId  given by the creator, and must be an existed span id in the {@link TraceSegment}. Value -1
     *                      means no parent span if this {@link TraceSegment}.
wu-sheng's avatar
wu-sheng 已提交
84 85
     * @param operationName {@link #operationName}
     */
86
    protected Span(int spanId, int parentSpanId, String operationName) {
87 88 89 90
        this(spanId, parentSpanId, operationName, System.currentTimeMillis());
    }

    /**
91
     * Create a new span, by given span id, parent span id, operationName and startTime.
92 93
     * This span must belong a {@link TraceSegment}, also is a part of Distributed Trace.
     *
P
pengys5 已提交
94 95 96
     * @param spanId        given by the creator, and must be unique id in the {@link TraceSegment}
     * @param parentSpanId  given by the creator, and must be an existed span id in the {@link TraceSegment}. Value -1
     *                      means no parent span if this {@link TraceSegment}.
97
     * @param operationName {@link #operationName}
P
pengys5 已提交
98
     * @param startTime     given start timestamp.
99
     */
100
    protected Span(int spanId, int parentSpanId, String operationName, long startTime) {
101
        this();
wu-sheng's avatar
wu-sheng 已提交
102 103
        this.spanId = spanId;
        this.parentSpanId = parentSpanId;
104
        this.startTime = startTime;
wu-sheng's avatar
wu-sheng 已提交
105
        this.operationName = operationName;
wu-sheng's avatar
wu-sheng 已提交
106 107 108 109 110 111
    }

    /**
     * Create a new span, by given span id and no parent span id.
     * No parent span id means that, this Span is the first span of the {@link TraceSegment}
     *
P
pengys5 已提交
112
     * @param spanId        given by the creator, and must be unique id in the {@link TraceSegment}
wu-sheng's avatar
wu-sheng 已提交
113 114
     * @param operationName {@link #operationName}
     */
115
    public Span(int spanId, String operationName) {
wu-sheng's avatar
wu-sheng 已提交
116 117 118
        this(spanId, -1, operationName);
    }

119 120 121 122
    /**
     * Create a new span, by given span id and give startTime but no parent span id,
     * No parent span id means that, this Span is the first span of the {@link TraceSegment}
     *
P
pengys5 已提交
123
     * @param spanId        given by the creator, and must be unique id in the {@link TraceSegment}
124
     * @param operationName {@link #operationName}
P
pengys5 已提交
125
     * @param startTime     given start time of span
126 127 128 129 130
     */
    public Span(int spanId, String operationName, long startTime) {
        this(spanId, -1, operationName, startTime);
    }

131 132 133
    /**
     * Create a new span, by given span id and given parent {@link Span}.
     *
P
pengys5 已提交
134 135
     * @param spanId        given by the creator, and must be unique id in the {@link TraceSegment}
     * @param parentSpan    {@link Span}
136 137
     * @param operationName {@link #operationName}
     */
138
    public Span(int spanId, Span parentSpan, String operationName) {
139 140 141 142
        this(spanId, parentSpan.spanId, operationName, System.currentTimeMillis());
    }

    /**
143 144
     * Create a new span, by given span id, parent span, operationName and startTime.
     * This span must belong a {@link TraceSegment}, also is a part of Distributed Trace.
145
     *
P
pengys5 已提交
146 147
     * @param spanId        given by the creator, and must be unique id in the {@link TraceSegment}
     * @param parentSpan    {@link Span}
148
     * @param operationName {@link #operationName}
P
pengys5 已提交
149
     * @param startTime     given start timestamp
150 151 152
     */
    public Span(int spanId, Span parentSpan, String operationName, long startTime) {
        this(spanId, parentSpan.spanId, operationName, startTime);
153 154
    }

155
    /**
156
     * Create a new/empty span.
157
     */
158
    public Span() {
159 160 161
        tagsWithStr = new HashMap<String, String>(5);
        tagsWithBool = new HashMap<String, Boolean>(1);
        tagsWithInt = new HashMap<String, Integer>(2);
162 163 164
        logs = new LinkedList<LogData>();
    }

wu-sheng's avatar
wu-sheng 已提交
165 166 167 168 169 170
    /**
     * Finish the active Span.
     * When it is finished, it will be archived by the given {@link TraceSegment}, which owners it.
     *
     * @param owner of the Span.
     */
171
    public void finish(TraceSegment owner) {
172 173 174 175 176 177 178 179
        this.finish(owner, System.currentTimeMillis());
    }

    /**
     * Finish the active Span.
     * When it is finished, it will be archived by the given {@link TraceSegment}, which owners it.
     * At the same out, set the {@link #endTime} as the given endTime
     *
P
pengys5 已提交
180
     * @param owner   of the Span.
181 182
     * @param endTime of the Span.
     */
183
    public void finish(TraceSegment owner, long endTime) {
184
        this.endTime = endTime;
wu-sheng's avatar
wu-sheng 已提交
185 186 187
        owner.archive(this);
    }

188 189 190 191 192
    /**
     * Sets the string name for the logical operation this span represents.
     *
     * @return this Span instance, for chaining
     */
193
    public Span setOperationName(String operationName) {
194 195 196 197
        this.operationName = operationName;
        return this;
    }

wu-sheng's avatar
wu-sheng 已提交
198 199
    /**
     * Set a key:value tag on the Span.
200 201
     *
     * @return this Span instance, for chaining
wu-sheng's avatar
wu-sheng 已提交
202
     */
203
    public Span setTag(String key, String value) {
204
        tagsWithStr.put(key, value);
wu-sheng's avatar
wu-sheng 已提交
205 206 207
        return this;
    }

208
    public Span setTag(String key, boolean value) {
209
        tagsWithBool.put(key, value);
wu-sheng's avatar
wu-sheng 已提交
210 211 212
        return this;
    }

213
    public Span setTag(String key, Integer value) {
214
        tagsWithInt.put(key, value);
wu-sheng's avatar
wu-sheng 已提交
215 216 217 218 219 220 221 222
        return this;
    }

    /**
     * Get all tags from this span, but readonly.
     *
     * @return
     */
223
    public final Map<String, Object> getTags() {
224 225 226 227 228
        Map<String, Object> tags = new HashMap<String, Object>();
        tags.putAll(tagsWithStr);
        tags.putAll(tagsWithBool);
        tags.putAll(tagsWithInt);
        return tags;
wu-sheng's avatar
wu-sheng 已提交
229 230
    }

231 232 233 234 235 236
    /**
     * Get tag value of the given key.
     *
     * @param key the given tag key.
     * @return tag value.
     */
237 238 239 240 241 242 243 244 245 246
    public String getStrTag(String key) {
        return tagsWithStr.get(key);
    }

    public Boolean getBoolTag(String key) {
        return tagsWithBool.get(key);
    }

    public Integer getIntTag(String key) {
        return tagsWithInt.get(key);
247 248
    }

wu-sheng's avatar
wu-sheng 已提交
249
    /**
250
     * This method is from opentracing-java. {@see https://github.com/opentracing/opentracing-java/blob/release-0.20.9/opentracing-api/src/main/java/io/opentracing/Span.java#L91}
P
pengys5 已提交
251
     * <p>
wu-sheng's avatar
wu-sheng 已提交
252
     * Log key:value pairs to the Span with the current walltime timestamp.
P
pengys5 已提交
253
     * <p>
wu-sheng's avatar
wu-sheng 已提交
254 255
     * <p><strong>CAUTIONARY NOTE:</strong> not all Tracer implementations support key:value log fields end-to-end.
     * Caveat emptor.
P
pengys5 已提交
256
     * <p>
wu-sheng's avatar
wu-sheng 已提交
257 258
     * <p>A contrived example (using Guava, which is not required):
     * <pre>{@code
259 260 261 262 263 264 265
     * span.log(
     * ImmutableMap.Builder<String, Object>()
     * .put("event", "soft error")
     * .put("type", "cache timeout")
     * .put("waited.millis", 1500)
     * .build());
     * }</pre>
wu-sheng's avatar
wu-sheng 已提交
266 267
     *
     * @param fields key:value log fields. Tracer implementations should support String, numeric, and boolean values;
P
pengys5 已提交
268
     *               some may also support arbitrary Objects.
wu-sheng's avatar
wu-sheng 已提交
269 270 271
     * @return the Span, for chaining
     * @see Span#log(String)
     */
272
    public Span log(Map<String, String> fields) {
wu-sheng's avatar
wu-sheng 已提交
273 274 275 276 277
        logs.add(new LogData(System.currentTimeMillis(), fields));
        return this;
    }

    /**
278 279 280 281 282 283 284
     * Record an exception event of the current walltime timestamp.
     *
     * @param t any subclass of {@link Throwable}, which occurs in this span.
     * @return the Span, for chaining
     */
    public Span log(Throwable t) {
        Map<String, String> exceptionFields = new HashMap<String, String>();
wu-sheng's avatar
wu-sheng 已提交
285
        exceptionFields.put("event", "error");
286 287 288 289
        exceptionFields.put("error.kind", t.getClass().getName());
        exceptionFields.put("message", t.getMessage());
        exceptionFields.put("stack", ThrowableTransformer.INSTANCE.convert2String(t, 4000));

290
        return log(exceptionFields);
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320
    }

    private enum ThrowableTransformer {
        INSTANCE;

        private String convert2String(Throwable e, int maxLength) {
            ByteArrayOutputStream buf = null;
            StringBuilder expMessage = new StringBuilder();
            try {
                buf = new ByteArrayOutputStream();
                Throwable causeException = e;
                while (expMessage.length() < maxLength && causeException != null) {
                    causeException.printStackTrace(new java.io.PrintWriter(buf, true));
                    expMessage.append(buf.toString());
                    causeException = causeException.getCause();
                }

            } finally {
                try {
                    buf.close();
                } catch (IOException ioe) {
                }
            }

            return (maxLength > expMessage.length() ? expMessage : expMessage.substring(0, maxLength)).toString();
        }
    }

    /**
     * This method is from opentracing-java. {@see https://github.com/opentracing/opentracing-java/blob/release-0.20.9/opentracing-api/src/main/java/io/opentracing/Span.java#L120}
P
pengys5 已提交
321
     * <p>
wu-sheng's avatar
wu-sheng 已提交
322
     * Record an event at the current walltime timestamp.
P
pengys5 已提交
323
     * <p>
wu-sheng's avatar
wu-sheng 已提交
324
     * Shorthand for
P
pengys5 已提交
325
     * <p>
wu-sheng's avatar
wu-sheng 已提交
326
     * <pre>{@code
327 328
     * span.log(Collections.singletonMap("event", event));
     * }</pre>
wu-sheng's avatar
wu-sheng 已提交
329 330 331 332
     *
     * @param event the event value; often a stable identifier for a moment in the Span lifecycle
     * @return the Span, for chaining
     */
333
    public Span log(String event) {
wu-sheng's avatar
wu-sheng 已提交
334 335 336
        log(Collections.singletonMap("event", event));
        return this;
    }
337 338 339 340

    public int getSpanId() {
        return spanId;
    }
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360

    public int getParentSpanId() {
        return parentSpanId;
    }

    public long getStartTime() {
        return startTime;
    }

    public long getEndTime() {
        return endTime;
    }

    public String getOperationName() {
        return operationName;
    }

    public List<LogData> getLogs() {
        return Collections.unmodifiableList(logs);
    }
wu-sheng's avatar
wu-sheng 已提交
361

362 363 364 365
    public boolean isLeaf() {
        return false;
    }

wu-sheng's avatar
wu-sheng 已提交
366 367 368 369 370 371 372 373 374
    @Override
    public String toString() {
        return "Span{" +
            "spanId=" + spanId +
            ", parentSpanId=" + parentSpanId +
            ", startTime=" + startTime +
            ", operationName='" + operationName + '\'' +
            '}';
    }
375
}