diff options
author | appilon <apilon@hashicorp.com> | 2019-02-27 16:43:31 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-02-27 16:43:31 -0500 |
commit | 844b5a68d8af4791755b8f0ad293cc99f5959183 (patch) | |
tree | 255c250a5c9d4801c74092d33b7337d8c14438ff /vendor/golang.org/x/net/trace/events.go | |
parent | 303b299eeb6b06e939e35905e4b34cb410dd9dc3 (diff) | |
parent | 15c0b25d011f37e7c20aeca9eaf461f78285b8d9 (diff) | |
download | terraform-provider-statuscake-844b5a68d8af4791755b8f0ad293cc99f5959183.tar.gz terraform-provider-statuscake-844b5a68d8af4791755b8f0ad293cc99f5959183.tar.zst terraform-provider-statuscake-844b5a68d8af4791755b8f0ad293cc99f5959183.zip |
Merge pull request #27 from terraform-providers/go-modules-2019-02-22
[MODULES] Switch to Go Modules
Diffstat (limited to 'vendor/golang.org/x/net/trace/events.go')
-rw-r--r-- | vendor/golang.org/x/net/trace/events.go | 532 |
1 files changed, 532 insertions, 0 deletions
diff --git a/vendor/golang.org/x/net/trace/events.go b/vendor/golang.org/x/net/trace/events.go new file mode 100644 index 0000000..c646a69 --- /dev/null +++ b/vendor/golang.org/x/net/trace/events.go | |||
@@ -0,0 +1,532 @@ | |||
1 | // Copyright 2015 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 trace | ||
6 | |||
7 | import ( | ||
8 | "bytes" | ||
9 | "fmt" | ||
10 | "html/template" | ||
11 | "io" | ||
12 | "log" | ||
13 | "net/http" | ||
14 | "runtime" | ||
15 | "sort" | ||
16 | "strconv" | ||
17 | "strings" | ||
18 | "sync" | ||
19 | "sync/atomic" | ||
20 | "text/tabwriter" | ||
21 | "time" | ||
22 | ) | ||
23 | |||
24 | const maxEventsPerLog = 100 | ||
25 | |||
26 | type bucket struct { | ||
27 | MaxErrAge time.Duration | ||
28 | String string | ||
29 | } | ||
30 | |||
31 | var buckets = []bucket{ | ||
32 | {0, "total"}, | ||
33 | {10 * time.Second, "errs<10s"}, | ||
34 | {1 * time.Minute, "errs<1m"}, | ||
35 | {10 * time.Minute, "errs<10m"}, | ||
36 | {1 * time.Hour, "errs<1h"}, | ||
37 | {10 * time.Hour, "errs<10h"}, | ||
38 | {24000 * time.Hour, "errors"}, | ||
39 | } | ||
40 | |||
41 | // RenderEvents renders the HTML page typically served at /debug/events. | ||
42 | // It does not do any auth checking. The request may be nil. | ||
43 | // | ||
44 | // Most users will use the Events handler. | ||
45 | func RenderEvents(w http.ResponseWriter, req *http.Request, sensitive bool) { | ||
46 | now := time.Now() | ||
47 | data := &struct { | ||
48 | Families []string // family names | ||
49 | Buckets []bucket | ||
50 | Counts [][]int // eventLog count per family/bucket | ||
51 | |||
52 | // Set when a bucket has been selected. | ||
53 | Family string | ||
54 | Bucket int | ||
55 | EventLogs eventLogs | ||
56 | Expanded bool | ||
57 | }{ | ||
58 | Buckets: buckets, | ||
59 | } | ||
60 | |||
61 | data.Families = make([]string, 0, len(families)) | ||
62 | famMu.RLock() | ||
63 | for name := range families { | ||
64 | data.Families = append(data.Families, name) | ||
65 | } | ||
66 | famMu.RUnlock() | ||
67 | sort.Strings(data.Families) | ||
68 | |||
69 | // Count the number of eventLogs in each family for each error age. | ||
70 | data.Counts = make([][]int, len(data.Families)) | ||
71 | for i, name := range data.Families { | ||
72 | // TODO(sameer): move this loop under the family lock. | ||
73 | f := getEventFamily(name) | ||
74 | data.Counts[i] = make([]int, len(data.Buckets)) | ||
75 | for j, b := range data.Buckets { | ||
76 | data.Counts[i][j] = f.Count(now, b.MaxErrAge) | ||
77 | } | ||
78 | } | ||
79 | |||
80 | if req != nil { | ||
81 | var ok bool | ||
82 | data.Family, data.Bucket, ok = parseEventsArgs(req) | ||
83 | if !ok { | ||
84 | // No-op | ||
85 | } else { | ||
86 | data.EventLogs = getEventFamily(data.Family).Copy(now, buckets[data.Bucket].MaxErrAge) | ||
87 | } | ||
88 | if data.EventLogs != nil { | ||
89 | defer data.EventLogs.Free() | ||
90 | sort.Sort(data.EventLogs) | ||
91 | } | ||
92 | if exp, err := strconv.ParseBool(req.FormValue("exp")); err == nil { | ||
93 | data.Expanded = exp | ||
94 | } | ||
95 | } | ||
96 | |||
97 | famMu.RLock() | ||
98 | defer famMu.RUnlock() | ||
99 | if err := eventsTmpl().Execute(w, data); err != nil { | ||
100 | log.Printf("net/trace: Failed executing template: %v", err) | ||
101 | } | ||
102 | } | ||
103 | |||
104 | func parseEventsArgs(req *http.Request) (fam string, b int, ok bool) { | ||
105 | fam, bStr := req.FormValue("fam"), req.FormValue("b") | ||
106 | if fam == "" || bStr == "" { | ||
107 | return "", 0, false | ||
108 | } | ||
109 | b, err := strconv.Atoi(bStr) | ||
110 | if err != nil || b < 0 || b >= len(buckets) { | ||
111 | return "", 0, false | ||
112 | } | ||
113 | return fam, b, true | ||
114 | } | ||
115 | |||
116 | // An EventLog provides a log of events associated with a specific object. | ||
117 | type EventLog interface { | ||
118 | // Printf formats its arguments with fmt.Sprintf and adds the | ||
119 | // result to the event log. | ||
120 | Printf(format string, a ...interface{}) | ||
121 | |||
122 | // Errorf is like Printf, but it marks this event as an error. | ||
123 | Errorf(format string, a ...interface{}) | ||
124 | |||
125 | // Finish declares that this event log is complete. | ||
126 | // The event log should not be used after calling this method. | ||
127 | Finish() | ||
128 | } | ||
129 | |||
130 | // NewEventLog returns a new EventLog with the specified family name | ||
131 | // and title. | ||
132 | func NewEventLog(family, title string) EventLog { | ||
133 | el := newEventLog() | ||
134 | el.ref() | ||
135 | el.Family, el.Title = family, title | ||
136 | el.Start = time.Now() | ||
137 | el.events = make([]logEntry, 0, maxEventsPerLog) | ||
138 | el.stack = make([]uintptr, 32) | ||
139 | n := runtime.Callers(2, el.stack) | ||
140 | el.stack = el.stack[:n] | ||
141 | |||
142 | getEventFamily(family).add(el) | ||
143 | return el | ||
144 | } | ||
145 | |||
146 | func (el *eventLog) Finish() { | ||
147 | getEventFamily(el.Family).remove(el) | ||
148 | el.unref() // matches ref in New | ||
149 | } | ||
150 | |||
151 | var ( | ||
152 | famMu sync.RWMutex | ||
153 | families = make(map[string]*eventFamily) // family name => family | ||
154 | ) | ||
155 | |||
156 | func getEventFamily(fam string) *eventFamily { | ||
157 | famMu.Lock() | ||
158 | defer famMu.Unlock() | ||
159 | f := families[fam] | ||
160 | if f == nil { | ||
161 | f = &eventFamily{} | ||
162 | families[fam] = f | ||
163 | } | ||
164 | return f | ||
165 | } | ||
166 | |||
167 | type eventFamily struct { | ||
168 | mu sync.RWMutex | ||
169 | eventLogs eventLogs | ||
170 | } | ||
171 | |||
172 | func (f *eventFamily) add(el *eventLog) { | ||
173 | f.mu.Lock() | ||
174 | f.eventLogs = append(f.eventLogs, el) | ||
175 | f.mu.Unlock() | ||
176 | } | ||
177 | |||
178 | func (f *eventFamily) remove(el *eventLog) { | ||
179 | f.mu.Lock() | ||
180 | defer f.mu.Unlock() | ||
181 | for i, el0 := range f.eventLogs { | ||
182 | if el == el0 { | ||
183 | copy(f.eventLogs[i:], f.eventLogs[i+1:]) | ||
184 | f.eventLogs = f.eventLogs[:len(f.eventLogs)-1] | ||
185 | return | ||
186 | } | ||
187 | } | ||
188 | } | ||
189 | |||
190 | func (f *eventFamily) Count(now time.Time, maxErrAge time.Duration) (n int) { | ||
191 | f.mu.RLock() | ||
192 | defer f.mu.RUnlock() | ||
193 | for _, el := range f.eventLogs { | ||
194 | if el.hasRecentError(now, maxErrAge) { | ||
195 | n++ | ||
196 | } | ||
197 | } | ||
198 | return | ||
199 | } | ||
200 | |||
201 | func (f *eventFamily) Copy(now time.Time, maxErrAge time.Duration) (els eventLogs) { | ||
202 | f.mu.RLock() | ||
203 | defer f.mu.RUnlock() | ||
204 | els = make(eventLogs, 0, len(f.eventLogs)) | ||
205 | for _, el := range f.eventLogs { | ||
206 | if el.hasRecentError(now, maxErrAge) { | ||
207 | el.ref() | ||
208 | els = append(els, el) | ||
209 | } | ||
210 | } | ||
211 | return | ||
212 | } | ||
213 | |||
214 | type eventLogs []*eventLog | ||
215 | |||
216 | // Free calls unref on each element of the list. | ||
217 | func (els eventLogs) Free() { | ||
218 | for _, el := range els { | ||
219 | el.unref() | ||
220 | } | ||
221 | } | ||
222 | |||
223 | // eventLogs may be sorted in reverse chronological order. | ||
224 | func (els eventLogs) Len() int { return len(els) } | ||
225 | func (els eventLogs) Less(i, j int) bool { return els[i].Start.After(els[j].Start) } | ||
226 | func (els eventLogs) Swap(i, j int) { els[i], els[j] = els[j], els[i] } | ||
227 | |||
228 | // A logEntry is a timestamped log entry in an event log. | ||
229 | type logEntry struct { | ||
230 | When time.Time | ||
231 | Elapsed time.Duration // since previous event in log | ||
232 | NewDay bool // whether this event is on a different day to the previous event | ||
233 | What string | ||
234 | IsErr bool | ||
235 | } | ||
236 | |||
237 | // WhenString returns a string representation of the elapsed time of the event. | ||
238 | // It will include the date if midnight was crossed. | ||
239 | func (e logEntry) WhenString() string { | ||
240 | if e.NewDay { | ||
241 | return e.When.Format("2006/01/02 15:04:05.000000") | ||
242 | } | ||
243 | return e.When.Format("15:04:05.000000") | ||
244 | } | ||
245 | |||
246 | // An eventLog represents an active event log. | ||
247 | type eventLog struct { | ||
248 | // Family is the top-level grouping of event logs to which this belongs. | ||
249 | Family string | ||
250 | |||
251 | // Title is the title of this event log. | ||
252 | Title string | ||
253 | |||
254 | // Timing information. | ||
255 | Start time.Time | ||
256 | |||
257 | // Call stack where this event log was created. | ||
258 | stack []uintptr | ||
259 | |||
260 | // Append-only sequence of events. | ||
261 | // | ||
262 | // TODO(sameer): change this to a ring buffer to avoid the array copy | ||
263 | // when we hit maxEventsPerLog. | ||
264 | mu sync.RWMutex | ||
265 | events []logEntry | ||
266 | LastErrorTime time.Time | ||
267 | discarded int | ||
268 | |||
269 | refs int32 // how many buckets this is in | ||
270 | } | ||
271 | |||
272 | func (el *eventLog) reset() { | ||
273 | // Clear all but the mutex. Mutexes may not be copied, even when unlocked. | ||
274 | el.Family = "" | ||
275 | el.Title = "" | ||
276 | el.Start = time.Time{} | ||
277 | el.stack = nil | ||
278 | el.events = nil | ||
279 | el.LastErrorTime = time.Time{} | ||
280 | el.discarded = 0 | ||
281 | el.refs = 0 | ||
282 | } | ||
283 | |||
284 | func (el *eventLog) hasRecentError(now time.Time, maxErrAge time.Duration) bool { | ||
285 | if maxErrAge == 0 { | ||
286 | return true | ||
287 | } | ||
288 | el.mu.RLock() | ||
289 | defer el.mu.RUnlock() | ||
290 | return now.Sub(el.LastErrorTime) < maxErrAge | ||
291 | } | ||
292 | |||
293 | // delta returns the elapsed time since the last event or the log start, | ||
294 | // and whether it spans midnight. | ||
295 | // L >= el.mu | ||
296 | func (el *eventLog) delta(t time.Time) (time.Duration, bool) { | ||
297 | if len(el.events) == 0 { | ||
298 | return t.Sub(el.Start), false | ||
299 | } | ||
300 | prev := el.events[len(el.events)-1].When | ||
301 | return t.Sub(prev), prev.Day() != t.Day() | ||
302 | |||
303 | } | ||
304 | |||
305 | func (el *eventLog) Printf(format string, a ...interface{}) { | ||
306 | el.printf(false, format, a...) | ||
307 | } | ||
308 | |||
309 | func (el *eventLog) Errorf(format string, a ...interface{}) { | ||
310 | el.printf(true, format, a...) | ||
311 | } | ||
312 | |||
313 | func (el *eventLog) printf(isErr bool, format string, a ...interface{}) { | ||
314 | e := logEntry{When: time.Now(), IsErr: isErr, What: fmt.Sprintf(format, a...)} | ||
315 | el.mu.Lock() | ||
316 | e.Elapsed, e.NewDay = el.delta(e.When) | ||
317 | if len(el.events) < maxEventsPerLog { | ||
318 | el.events = append(el.events, e) | ||
319 | } else { | ||
320 | // Discard the oldest event. | ||
321 | if el.discarded == 0 { | ||
322 | // el.discarded starts at two to count for the event it | ||
323 | // is replacing, plus the next one that we are about to | ||
324 | // drop. | ||
325 | el.discarded = 2 | ||
326 | } else { | ||
327 | el.discarded++ | ||
328 | } | ||
329 | // TODO(sameer): if this causes allocations on a critical path, | ||
330 | // change eventLog.What to be a fmt.Stringer, as in trace.go. | ||
331 | el.events[0].What = fmt.Sprintf("(%d events discarded)", el.discarded) | ||
332 | // The timestamp of the discarded meta-event should be | ||
333 | // the time of the last event it is representing. | ||
334 | el.events[0].When = el.events[1].When | ||
335 | copy(el.events[1:], el.events[2:]) | ||
336 | el.events[maxEventsPerLog-1] = e | ||
337 | } | ||
338 | if e.IsErr { | ||
339 | el.LastErrorTime = e.When | ||
340 | } | ||
341 | el.mu.Unlock() | ||
342 | } | ||
343 | |||
344 | func (el *eventLog) ref() { | ||
345 | atomic.AddInt32(&el.refs, 1) | ||
346 | } | ||
347 | |||
348 | func (el *eventLog) unref() { | ||
349 | if atomic.AddInt32(&el.refs, -1) == 0 { | ||
350 | freeEventLog(el) | ||
351 | } | ||
352 | } | ||
353 | |||
354 | func (el *eventLog) When() string { | ||
355 | return el.Start.Format("2006/01/02 15:04:05.000000") | ||
356 | } | ||
357 | |||
358 | func (el *eventLog) ElapsedTime() string { | ||
359 | elapsed := time.Since(el.Start) | ||
360 | return fmt.Sprintf("%.6f", elapsed.Seconds()) | ||
361 | } | ||
362 | |||
363 | func (el *eventLog) Stack() string { | ||
364 | buf := new(bytes.Buffer) | ||
365 | tw := tabwriter.NewWriter(buf, 1, 8, 1, '\t', 0) | ||
366 | printStackRecord(tw, el.stack) | ||
367 | tw.Flush() | ||
368 | return buf.String() | ||
369 | } | ||
370 | |||
371 | // printStackRecord prints the function + source line information | ||
372 | // for a single stack trace. | ||
373 | // Adapted from runtime/pprof/pprof.go. | ||
374 | func printStackRecord(w io.Writer, stk []uintptr) { | ||
375 | for _, pc := range stk { | ||
376 | f := runtime.FuncForPC(pc) | ||
377 | if f == nil { | ||
378 | continue | ||
379 | } | ||
380 | file, line := f.FileLine(pc) | ||
381 | name := f.Name() | ||
382 | // Hide runtime.goexit and any runtime functions at the beginning. | ||
383 | if strings.HasPrefix(name, "runtime.") { | ||
384 | continue | ||
385 | } | ||
386 | fmt.Fprintf(w, "# %s\t%s:%d\n", name, file, line) | ||
387 | } | ||
388 | } | ||
389 | |||
390 | func (el *eventLog) Events() []logEntry { | ||
391 | el.mu.RLock() | ||
392 | defer el.mu.RUnlock() | ||
393 | return el.events | ||
394 | } | ||
395 | |||
396 | // freeEventLogs is a freelist of *eventLog | ||
397 | var freeEventLogs = make(chan *eventLog, 1000) | ||
398 | |||
399 | // newEventLog returns a event log ready to use. | ||
400 | func newEventLog() *eventLog { | ||
401 | select { | ||
402 | case el := <-freeEventLogs: | ||
403 | return el | ||
404 | default: | ||
405 | return new(eventLog) | ||
406 | } | ||
407 | } | ||
408 | |||
409 | // freeEventLog adds el to freeEventLogs if there's room. | ||
410 | // This is non-blocking. | ||
411 | func freeEventLog(el *eventLog) { | ||
412 | el.reset() | ||
413 | select { | ||
414 | case freeEventLogs <- el: | ||
415 | default: | ||
416 | } | ||
417 | } | ||
418 | |||
419 | var eventsTmplCache *template.Template | ||
420 | var eventsTmplOnce sync.Once | ||
421 | |||
422 | func eventsTmpl() *template.Template { | ||
423 | eventsTmplOnce.Do(func() { | ||
424 | eventsTmplCache = template.Must(template.New("events").Funcs(template.FuncMap{ | ||
425 | "elapsed": elapsed, | ||
426 | "trimSpace": strings.TrimSpace, | ||
427 | }).Parse(eventsHTML)) | ||
428 | }) | ||
429 | return eventsTmplCache | ||
430 | } | ||
431 | |||
432 | const eventsHTML = ` | ||
433 | <html> | ||
434 | <head> | ||
435 | <title>events</title> | ||
436 | </head> | ||
437 | <style type="text/css"> | ||
438 | body { | ||
439 | font-family: sans-serif; | ||
440 | } | ||
441 | table#req-status td.family { | ||
442 | padding-right: 2em; | ||
443 | } | ||
444 | table#req-status td.active { | ||
445 | padding-right: 1em; | ||
446 | } | ||
447 | table#req-status td.empty { | ||
448 | color: #aaa; | ||
449 | } | ||
450 | table#reqs { | ||
451 | margin-top: 1em; | ||
452 | } | ||
453 | table#reqs tr.first { | ||
454 | {{if $.Expanded}}font-weight: bold;{{end}} | ||
455 | } | ||
456 | table#reqs td { | ||
457 | font-family: monospace; | ||
458 | } | ||
459 | table#reqs td.when { | ||
460 | text-align: right; | ||
461 | white-space: nowrap; | ||
462 | } | ||
463 | table#reqs td.elapsed { | ||
464 | padding: 0 0.5em; | ||
465 | text-align: right; | ||
466 | white-space: pre; | ||
467 | width: 10em; | ||
468 | } | ||
469 | address { | ||
470 | font-size: smaller; | ||
471 | margin-top: 5em; | ||
472 | } | ||
473 | </style> | ||
474 | <body> | ||
475 | |||
476 | <h1>/debug/events</h1> | ||
477 | |||
478 | <table id="req-status"> | ||
479 | {{range $i, $fam := .Families}} | ||
480 | <tr> | ||
481 | <td class="family">{{$fam}}</td> | ||
482 | |||
483 | {{range $j, $bucket := $.Buckets}} | ||
484 | {{$n := index $.Counts $i $j}} | ||
485 | <td class="{{if not $bucket.MaxErrAge}}active{{end}}{{if not $n}}empty{{end}}"> | ||
486 | {{if $n}}<a href="?fam={{$fam}}&b={{$j}}{{if $.Expanded}}&exp=1{{end}}">{{end}} | ||
487 | [{{$n}} {{$bucket.String}}] | ||
488 | {{if $n}}</a>{{end}} | ||
489 | </td> | ||
490 | {{end}} | ||
491 | |||
492 | </tr>{{end}} | ||
493 | </table> | ||
494 | |||
495 | {{if $.EventLogs}} | ||
496 | <hr /> | ||
497 | <h3>Family: {{$.Family}}</h3> | ||
498 | |||
499 | {{if $.Expanded}}<a href="?fam={{$.Family}}&b={{$.Bucket}}">{{end}} | ||
500 | [Summary]{{if $.Expanded}}</a>{{end}} | ||
501 | |||
502 | {{if not $.Expanded}}<a href="?fam={{$.Family}}&b={{$.Bucket}}&exp=1">{{end}} | ||
503 | [Expanded]{{if not $.Expanded}}</a>{{end}} | ||
504 | |||
505 | <table id="reqs"> | ||
506 | <tr><th>When</th><th>Elapsed</th></tr> | ||
507 | {{range $el := $.EventLogs}} | ||
508 | <tr class="first"> | ||
509 | <td class="when">{{$el.When}}</td> | ||
510 | <td class="elapsed">{{$el.ElapsedTime}}</td> | ||
511 | <td>{{$el.Title}} | ||
512 | </tr> | ||
513 | {{if $.Expanded}} | ||
514 | <tr> | ||
515 | <td class="when"></td> | ||
516 | <td class="elapsed"></td> | ||
517 | <td><pre>{{$el.Stack|trimSpace}}</pre></td> | ||
518 | </tr> | ||
519 | {{range $el.Events}} | ||
520 | <tr> | ||
521 | <td class="when">{{.WhenString}}</td> | ||
522 | <td class="elapsed">{{elapsed .Elapsed}}</td> | ||
523 | <td>.{{if .IsErr}}E{{else}}.{{end}}. {{.What}}</td> | ||
524 | </tr> | ||
525 | {{end}} | ||
526 | {{end}} | ||
527 | {{end}} | ||
528 | </table> | ||
529 | {{end}} | ||
530 | </body> | ||
531 | </html> | ||
532 | ` | ||