Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201028153306-37f0764111ff / internal / lsp / debug / trace.go
1 // Copyright 2019 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package debug
6
7 import (
8         "bytes"
9         "context"
10         "fmt"
11         "html/template"
12         "net/http"
13         "sort"
14         "strings"
15         "sync"
16         "time"
17
18         "golang.org/x/tools/internal/event"
19         "golang.org/x/tools/internal/event/core"
20         "golang.org/x/tools/internal/event/export"
21         "golang.org/x/tools/internal/event/label"
22 )
23
24 var traceTmpl = template.Must(template.Must(baseTemplate.Clone()).Parse(`
25 {{define "title"}}Trace Information{{end}}
26 {{define "body"}}
27         {{range .Traces}}<a href="/trace/{{.Name}}">{{.Name}}</a> last: {{.Last.Duration}}, longest: {{.Longest.Duration}}<br>{{end}}
28         {{if .Selected}}
29                 <H2>{{.Selected.Name}}</H2>
30                 {{if .Selected.Last}}<H3>Last</H3><ul>{{template "details" .Selected.Last}}</ul>{{end}}
31                 {{if .Selected.Longest}}<H3>Longest</H3><ul>{{template "details" .Selected.Longest}}</ul>{{end}}
32         {{end}}
33 {{end}}
34 {{define "details"}}
35         <li>{{.Offset}} {{.Name}} {{.Duration}} {{.Tags}}</li>
36         {{if .Events}}<ul class=events>{{range .Events}}<li>{{.Offset}} {{.Tags}}</li>{{end}}</ul>{{end}}
37         {{if .Children}}<ul>{{range .Children}}{{template "details" .}}{{end}}</ul>{{end}}
38 {{end}}
39 `))
40
41 type traces struct {
42         mu         sync.Mutex
43         sets       map[string]*traceSet
44         unfinished map[export.SpanContext]*traceData
45 }
46
47 type traceResults struct {
48         Traces   []*traceSet
49         Selected *traceSet
50 }
51
52 type traceSet struct {
53         Name    string
54         Last    *traceData
55         Longest *traceData
56 }
57
58 type traceData struct {
59         TraceID  export.TraceID
60         SpanID   export.SpanID
61         ParentID export.SpanID
62         Name     string
63         Start    time.Time
64         Finish   time.Time
65         Offset   time.Duration
66         Duration time.Duration
67         Tags     string
68         Events   []traceEvent
69         Children []*traceData
70 }
71
72 type traceEvent struct {
73         Time   time.Time
74         Offset time.Duration
75         Tags   string
76 }
77
78 func (t *traces) ProcessEvent(ctx context.Context, ev core.Event, lm label.Map) context.Context {
79         t.mu.Lock()
80         defer t.mu.Unlock()
81         span := export.GetSpan(ctx)
82         if span == nil {
83                 return ctx
84         }
85
86         switch {
87         case event.IsStart(ev):
88                 if t.sets == nil {
89                         t.sets = make(map[string]*traceSet)
90                         t.unfinished = make(map[export.SpanContext]*traceData)
91                 }
92                 // just starting, add it to the unfinished map
93                 td := &traceData{
94                         TraceID:  span.ID.TraceID,
95                         SpanID:   span.ID.SpanID,
96                         ParentID: span.ParentID,
97                         Name:     span.Name,
98                         Start:    span.Start().At(),
99                         Tags:     renderLabels(span.Start()),
100                 }
101                 t.unfinished[span.ID] = td
102                 // and wire up parents if we have them
103                 if !span.ParentID.IsValid() {
104                         return ctx
105                 }
106                 parentID := export.SpanContext{TraceID: span.ID.TraceID, SpanID: span.ParentID}
107                 parent, found := t.unfinished[parentID]
108                 if !found {
109                         // trace had an invalid parent, so it cannot itself be valid
110                         return ctx
111                 }
112                 parent.Children = append(parent.Children, td)
113
114         case event.IsEnd(ev):
115                 // finishing, must be already in the map
116                 td, found := t.unfinished[span.ID]
117                 if !found {
118                         return ctx // if this happens we are in a bad place
119                 }
120                 delete(t.unfinished, span.ID)
121
122                 td.Finish = span.Finish().At()
123                 td.Duration = span.Finish().At().Sub(span.Start().At())
124                 events := span.Events()
125                 td.Events = make([]traceEvent, len(events))
126                 for i, event := range events {
127                         td.Events[i] = traceEvent{
128                                 Time: event.At(),
129                                 Tags: renderLabels(event),
130                         }
131                 }
132
133                 set, ok := t.sets[span.Name]
134                 if !ok {
135                         set = &traceSet{Name: span.Name}
136                         t.sets[span.Name] = set
137                 }
138                 set.Last = td
139                 if set.Longest == nil || set.Last.Duration > set.Longest.Duration {
140                         set.Longest = set.Last
141                 }
142                 if !td.ParentID.IsValid() {
143                         fillOffsets(td, td.Start)
144                 }
145         }
146         return ctx
147 }
148
149 func (t *traces) getData(req *http.Request) interface{} {
150         if len(t.sets) == 0 {
151                 return nil
152         }
153         data := traceResults{}
154         data.Traces = make([]*traceSet, 0, len(t.sets))
155         for _, set := range t.sets {
156                 data.Traces = append(data.Traces, set)
157         }
158         sort.Slice(data.Traces, func(i, j int) bool { return data.Traces[i].Name < data.Traces[j].Name })
159         if bits := strings.SplitN(req.URL.Path, "/trace/", 2); len(bits) > 1 {
160                 data.Selected = t.sets[bits[1]]
161         }
162         return data
163 }
164
165 func fillOffsets(td *traceData, start time.Time) {
166         td.Offset = td.Start.Sub(start)
167         for i := range td.Events {
168                 td.Events[i].Offset = td.Events[i].Time.Sub(start)
169         }
170         for _, child := range td.Children {
171                 fillOffsets(child, start)
172         }
173 }
174
175 func renderLabels(labels label.List) string {
176         buf := &bytes.Buffer{}
177         for index := 0; labels.Valid(index); index++ {
178                 if l := labels.Label(index); l.Valid() {
179                         fmt.Fprintf(buf, "%v ", l)
180                 }
181         }
182         return buf.String()
183 }