mirror of
https://github.com/golang/go
synced 2024-11-18 10:54:40 -07:00
cmd/trace: make span tables pretty
Mostly same as golang.org/cl/102156, except the parts that deal with different data types. Change-Id: I061b858b73898725e3bf175ed022c2e3e55fc485 Reviewed-on: https://go-review.googlesource.com/103158 Reviewed-by: Andrew Bonventre <andybons@golang.org>
This commit is contained in:
parent
9761a162f0
commit
3ac17f86be
@ -8,6 +8,7 @@ import (
|
||||
"log"
|
||||
"math"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -111,21 +112,41 @@ func httpUserSpan(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
var data []spanDesc
|
||||
|
||||
var maxTotal int64
|
||||
for id, spans := range allSpans {
|
||||
for _, s := range spans {
|
||||
if !filter.match(id, s) {
|
||||
continue
|
||||
}
|
||||
data = append(data, s)
|
||||
if maxTotal < s.TotalTime {
|
||||
maxTotal = s.TotalTime
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sortby := r.FormValue("sortby")
|
||||
_, ok := reflect.TypeOf(spanDesc{}).FieldByNameFunc(func(s string) bool {
|
||||
return s == sortby
|
||||
})
|
||||
if !ok {
|
||||
sortby = "TotalTime"
|
||||
}
|
||||
sort.Slice(data, func(i, j int) bool {
|
||||
ival := reflect.ValueOf(data[i]).FieldByName(sortby).Int()
|
||||
jval := reflect.ValueOf(data[j]).FieldByName(sortby).Int()
|
||||
return ival > jval
|
||||
})
|
||||
|
||||
err = templUserSpanType.Execute(w, struct {
|
||||
Data []spanDesc
|
||||
Title string
|
||||
MaxTotal int64
|
||||
Data []spanDesc
|
||||
Name string
|
||||
}{
|
||||
Data: data,
|
||||
Title: filter.name})
|
||||
MaxTotal: maxTotal,
|
||||
Data: data,
|
||||
Name: filter.name,
|
||||
})
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("failed to execute template: %v", err), http.StatusInternalServerError)
|
||||
return
|
||||
@ -1113,40 +1134,121 @@ func isUserAnnotationEvent(ev *trace.Event) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
var templUserSpanType = template.Must(template.New("").Parse(`
|
||||
<html>
|
||||
<body>
|
||||
<h2>{{.Title}}</h2>
|
||||
<table border="1" sortable="1">
|
||||
var templUserSpanType = template.Must(template.New("").Funcs(template.FuncMap{
|
||||
"prettyDuration": func(nsec int64) template.HTML {
|
||||
d := time.Duration(nsec) * time.Nanosecond
|
||||
return template.HTML(niceDuration(d))
|
||||
},
|
||||
"percent": func(dividened, divisor int64) template.HTML {
|
||||
if divisor == 0 {
|
||||
return ""
|
||||
}
|
||||
return template.HTML(fmt.Sprintf("(%.1f%%)", float64(dividened)/float64(divisor)*100))
|
||||
},
|
||||
"barLen": func(dividened, divisor int64) template.HTML {
|
||||
if divisor == 0 {
|
||||
return "0"
|
||||
}
|
||||
return template.HTML(fmt.Sprintf("%.2f%%", float64(dividened)/float64(divisor)*100))
|
||||
},
|
||||
"unknownTime": func(desc spanDesc) int64 {
|
||||
sum := desc.ExecTime + desc.IOTime + desc.BlockTime + desc.SyscallTime + desc.SchedWaitTime
|
||||
if sum < desc.TotalTime {
|
||||
return desc.TotalTime - sum
|
||||
}
|
||||
return 0
|
||||
},
|
||||
}).Parse(`
|
||||
<!DOCTYPE html>
|
||||
<title>Goroutine {{.Name}}</title>
|
||||
<style>
|
||||
th {
|
||||
background-color: #050505;
|
||||
color: #fff;
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
.details tr:hover {
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
.details td {
|
||||
text-align: right;
|
||||
border: 1px solid #000;
|
||||
}
|
||||
.details td.id {
|
||||
text-align: left;
|
||||
}
|
||||
.stacked-bar-graph {
|
||||
width: 300px;
|
||||
height: 10px;
|
||||
color: #414042;
|
||||
white-space: nowrap;
|
||||
font-size: 5px;
|
||||
}
|
||||
.stacked-bar-graph span {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
float: left;
|
||||
padding: 0;
|
||||
}
|
||||
.unknown-time { background-color: #636363; }
|
||||
.exec-time { background-color: #d7191c; }
|
||||
.io-time { background-color: #fdae61; }
|
||||
.block-time { background-color: #d01c8b; }
|
||||
.syscall-time { background-color: #7b3294; }
|
||||
.sched-time { background-color: #2c7bb6; }
|
||||
</style>
|
||||
|
||||
<script>
|
||||
function reloadTable(key, value) {
|
||||
let params = new URLSearchParams(window.location.search);
|
||||
params.set(key, value);
|
||||
window.location.search = params.toString();
|
||||
}
|
||||
</script>
|
||||
|
||||
<h2>{{.Name}}</h2>
|
||||
|
||||
<table class="details">
|
||||
<tr>
|
||||
<th> Goroutine </th>
|
||||
<th> Task </th>
|
||||
<th> Total time, ns </th>
|
||||
<th> Execution time, ns </th>
|
||||
<th> Network wait time, ns </th>
|
||||
<th> Sync block time, ns </th>
|
||||
<th> Blocking syscall time, ns </th>
|
||||
<th> Scheduler wait time, ns </th>
|
||||
<th> GC sweeping time, ns </th>
|
||||
<th> GC pause time, ns </th>
|
||||
<th> Logs </th>
|
||||
<th onclick="reloadTable('sortby', 'TotalTime')"> Total</th>
|
||||
<th></th>
|
||||
<th onclick="reloadTable('sortby', 'ExecTime')" class="exec-time"> Execution</th>
|
||||
<th onclick="reloadTable('sortby', 'IOTime')" class="io-time"> Network wait</th>
|
||||
<th onclick="reloadTable('sortby', 'BlockTime')" class="block-time"> Sync block </th>
|
||||
<th onclick="reloadTable('sortby', 'SyscallTime')" class="syscall-time"> Blocking syscall</th>
|
||||
<th onclick="reloadTable('sortby', 'SchedWaitTime')" class="sched-time"> Scheduler wait</th>
|
||||
<th onclick="reloadTable('sortby', 'SweepTime')"> GC sweeping</th>
|
||||
<th onclick="reloadTable('sortby', 'GCTime')"> GC pause</th>
|
||||
</tr>
|
||||
{{range .Data}}
|
||||
<tr>
|
||||
<td> <a href="/trace?goid={{.G}}">{{.G}}</a> </td>
|
||||
<td> <a href="/trace?taskid={{.TaskID}}">{{.TaskID}}</a> </td>
|
||||
<td> {{.TotalTime}} </td>
|
||||
<td> {{.ExecTime}} </td>
|
||||
<td> {{.IOTime}} </td>
|
||||
<td> {{.BlockTime}} </td>
|
||||
<td> {{.SyscallTime}} </td>
|
||||
<td> {{.SchedWaitTime}} </td>
|
||||
<td> {{.SweepTime}} </td>
|
||||
<td> {{.GCTime}} </td>
|
||||
<td> /* TODO */ </td>
|
||||
<td> {{prettyDuration .TotalTime}} </td>
|
||||
<td>
|
||||
<div class="stacked-bar-graph">
|
||||
{{if unknownTime .}}<span style="width:{{barLen (unknownTime .) $.MaxTotal}}" class="unknown-time"> </span>{{end}}
|
||||
{{if .ExecTime}}<span style="width:{{barLen .ExecTime $.MaxTotal}}" class="exec-time"> </span>{{end}}
|
||||
{{if .IOTime}}<span style="width:{{barLen .IOTime $.MaxTotal}}" class="io-time"> </span>{{end}}
|
||||
{{if .BlockTime}}<span style="width:{{barLen .BlockTime $.MaxTotal}}" class="block-time"> </span>{{end}}
|
||||
{{if .SyscallTime}}<span style="width:{{barLen .SyscallTime $.MaxTotal}}" class="syscall-time"> </span>{{end}}
|
||||
{{if .SchedWaitTime}}<span style="width:{{barLen .SchedWaitTime $.MaxTotal}}" class="sched-time"> </span>{{end}}
|
||||
</div>
|
||||
</td>
|
||||
<td> {{prettyDuration .ExecTime}}</td>
|
||||
<td> {{prettyDuration .IOTime}}</td>
|
||||
<td> {{prettyDuration .BlockTime}}</td>
|
||||
<td> {{prettyDuration .SyscallTime}}</td>
|
||||
<td> {{prettyDuration .SchedWaitTime}}</td>
|
||||
<td> {{prettyDuration .SweepTime}} {{percent .SweepTime .TotalTime}}</td>
|
||||
<td> {{prettyDuration .GCTime}} {{percent .GCTime .TotalTime}}</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
`))
|
||||
|
Loading…
Reference in New Issue
Block a user