This repository has been archived by the owner on Oct 29, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 137
/
Copy pathtrace.go
121 lines (110 loc) · 2.83 KB
/
trace.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package appdash
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"strings"
"time"
)
// A Trace is a tree of spans.
type Trace struct {
Span // Root span
Sub []*Trace // Children
}
// String returns the Trace as a formatted string.
func (t *Trace) String() string {
b, err := json.MarshalIndent(t, "", " ")
if err != nil {
panic(err)
}
return string(b)
}
// FindSpan recursively searches for a span whose Span ID is spanID in
// t and its descendants. If no such span is found, nil is returned.
func (t *Trace) FindSpan(spanID ID) *Trace {
if t.ID.Span == spanID {
return t
}
for _, sub := range t.Sub {
if s := sub.FindSpan(spanID); s != nil {
return s
}
}
return nil
}
// TreeString returns the Trace as a formatted string that visually
// represents the trace's tree.
func (t *Trace) TreeString() string {
var buf bytes.Buffer
t.treeString(&buf, 0)
return buf.String()
}
func (t *Trace) TimespanEvent() (TimespanEvent, error) {
var events []Event
if err := UnmarshalEvents(t.Annotations, &events); err != nil {
return timespanEvent{}, err
}
start, end, ok := findTraceTimes(events)
if !ok {
return timespanEvent{}, errors.New("time span event not found")
}
return timespanEvent{S: start, E: end}, nil
}
func (t *Trace) treeString(w io.Writer, depth int) {
const indent1 = " "
indent := strings.Repeat(indent1, depth)
if depth == 0 {
fmt.Fprintf(w, "+ Trace %x\n", uint64(t.Span.ID.Trace))
} else {
if depth == 1 {
fmt.Fprint(w, "|")
} else {
fmt.Fprint(w, "|", indent[len(indent1):])
}
fmt.Fprintf(w, "%s+ Span %x", strings.Repeat("-", len(indent1)), uint64(t.Span.ID.Span))
if t.Span.ID.Parent != 0 {
fmt.Fprintf(w, " (parent %x)", uint64(t.Span.ID.Parent))
}
fmt.Fprintln(w)
}
for _, a := range t.Span.Annotations {
if depth == 0 {
fmt.Fprint(w, "| ")
} else {
fmt.Fprint(w, "|", indent[1:], " | ")
}
fmt.Fprintf(w, "%s = %s\n", a.Key, a.Value)
}
for _, sub := range t.Sub {
sub.treeString(w, depth+1)
}
}
// findTraceTimes finds the minimum and maximum timespan event times for the
// given set of events, or returns ok == false if there are no such events.
func findTraceTimes(events []Event) (start, end time.Time, _ bool) {
// Find the start and end time of the trace.
for _, e := range events {
e, ok := e.(TimespanEvent)
if !ok {
continue
}
if start.IsZero() {
start = e.Start()
end = e.End()
continue
}
if v := e.Start(); v.UnixNano() < start.UnixNano() {
start = v
}
if v := e.End(); v.UnixNano() > end.UnixNano() {
end = v
}
}
return start, end, !start.IsZero()
}
type tracesByIDSpan []*Trace
func (t tracesByIDSpan) Len() int { return len(t) }
func (t tracesByIDSpan) Less(i, j int) bool { return t[i].Span.ID.Span < t[j].Span.ID.Span }
func (t tracesByIDSpan) Swap(i, j int) { t[i], t[j] = t[j], t[i] }