mirror of
https://github.com/golang/go
synced 2024-11-18 16:14:46 -07:00
04208b9e8a
Move the lsp specific telemetry package that just declares the labels under the debug package and call it tag, to make all the usages much more readable. Change-Id: Ic89b3408dd3b8b3d914cc69d81f41b8919aaf424 Reviewed-on: https://go-review.googlesource.com/c/tools/+/222850 Run-TryBot: Ian Cottrell <iancottrell@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com>
215 lines
5.1 KiB
Go
215 lines
5.1 KiB
Go
// Copyright 2019 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package debug
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"html/template"
|
|
"log"
|
|
"net/http"
|
|
"sort"
|
|
"sync"
|
|
|
|
"golang.org/x/tools/internal/lsp/debug/tag"
|
|
"golang.org/x/tools/internal/telemetry/event"
|
|
"golang.org/x/tools/internal/telemetry/metric"
|
|
)
|
|
|
|
var rpcTmpl = template.Must(template.Must(baseTemplate.Clone()).Parse(`
|
|
{{define "title"}}RPC Information{{end}}
|
|
{{define "body"}}
|
|
<H2>Inbound</H2>
|
|
{{template "rpcSection" .Inbound}}
|
|
<H2>Outbound</H2>
|
|
{{template "rpcSection" .Outbound}}
|
|
{{end}}
|
|
{{define "rpcSection"}}
|
|
{{range .}}<P>
|
|
<b>{{.Method}}</b> {{.Started}} <a href="/trace/{{.Method}}">traces</a> ({{.InProgress}} in progress)
|
|
<br>
|
|
<i>Latency</i> {{with .Latency}}{{.Mean}} ({{.Min}}<{{.Max}}){{end}}
|
|
<i>By bucket</i> 0s {{range .Latency.Values}}<b>{{.Count}}</b> {{.Limit}} {{end}}
|
|
<br>
|
|
<i>Received</i> {{with .Received}}{{.Mean}} ({{.Min}}<{{.Max}}){{end}}
|
|
<i>Sent</i> {{with .Sent}}{{.Mean}} ({{.Min}}<{{.Max}}){{end}}
|
|
<br>
|
|
<i>Result codes</i> {{range .Codes}}{{.Key}}={{.Count}} {{end}}
|
|
</P>
|
|
{{end}}
|
|
{{end}}
|
|
`))
|
|
|
|
type rpcs struct {
|
|
mu sync.Mutex
|
|
Inbound []*rpcStats
|
|
Outbound []*rpcStats
|
|
}
|
|
|
|
type rpcStats struct {
|
|
Method string
|
|
Started int64
|
|
Completed int64
|
|
InProgress int64
|
|
Latency rpcTimeHistogram
|
|
Received rpcBytesHistogram
|
|
Sent rpcBytesHistogram
|
|
Codes []*rpcCodeBucket
|
|
}
|
|
|
|
type rpcTimeHistogram struct {
|
|
Sum timeUnits
|
|
Count int64
|
|
Mean timeUnits
|
|
Min timeUnits
|
|
Max timeUnits
|
|
Values []rpcTimeBucket
|
|
}
|
|
|
|
type rpcTimeBucket struct {
|
|
Limit timeUnits
|
|
Count int64
|
|
}
|
|
|
|
type rpcBytesHistogram struct {
|
|
Sum byteUnits
|
|
Count int64
|
|
Mean byteUnits
|
|
Min byteUnits
|
|
Max byteUnits
|
|
Values []rpcBytesBucket
|
|
}
|
|
|
|
type rpcBytesBucket struct {
|
|
Limit byteUnits
|
|
Count int64
|
|
}
|
|
|
|
type rpcCodeBucket struct {
|
|
Key string
|
|
Count int64
|
|
}
|
|
|
|
func (r *rpcs) Metric(ctx context.Context, data event.MetricData) {
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
for i, group := range data.Groups() {
|
|
set := &r.Inbound
|
|
if group.Get(tag.RPCDirection) == tag.Outbound {
|
|
set = &r.Outbound
|
|
}
|
|
method, ok := group.Get(tag.Method).(string)
|
|
if !ok {
|
|
continue
|
|
}
|
|
index := sort.Search(len(*set), func(i int) bool {
|
|
return (*set)[i].Method >= method
|
|
})
|
|
if index >= len(*set) || (*set)[index].Method != method {
|
|
old := *set
|
|
*set = make([]*rpcStats, len(old)+1)
|
|
copy(*set, old[:index])
|
|
copy((*set)[index+1:], old[index:])
|
|
(*set)[index] = &rpcStats{Method: method}
|
|
}
|
|
stats := (*set)[index]
|
|
switch data.Handle() {
|
|
case started:
|
|
stats.Started = data.(*metric.Int64Data).Rows[i]
|
|
case completed:
|
|
status, ok := group.Get(tag.StatusCode).(string)
|
|
if !ok {
|
|
log.Printf("Not status... %v", group)
|
|
continue
|
|
}
|
|
var b *rpcCodeBucket
|
|
for c, entry := range stats.Codes {
|
|
if entry.Key == status {
|
|
b = stats.Codes[c]
|
|
break
|
|
}
|
|
}
|
|
if b == nil {
|
|
b = &rpcCodeBucket{Key: status}
|
|
stats.Codes = append(stats.Codes, b)
|
|
sort.Slice(stats.Codes, func(i int, j int) bool {
|
|
return stats.Codes[i].Key < stats.Codes[j].Key
|
|
})
|
|
}
|
|
b.Count = data.(*metric.Int64Data).Rows[i]
|
|
case latency:
|
|
data := data.(*metric.HistogramFloat64Data)
|
|
row := data.Rows[i]
|
|
stats.Latency.Count = row.Count
|
|
stats.Latency.Sum = timeUnits(row.Sum)
|
|
stats.Latency.Min = timeUnits(row.Min)
|
|
stats.Latency.Max = timeUnits(row.Max)
|
|
stats.Latency.Mean = timeUnits(row.Sum) / timeUnits(row.Count)
|
|
stats.Latency.Values = make([]rpcTimeBucket, len(data.Info.Buckets))
|
|
last := int64(0)
|
|
for i, b := range data.Info.Buckets {
|
|
stats.Latency.Values[i].Limit = timeUnits(b)
|
|
stats.Latency.Values[i].Count = row.Values[i] - last
|
|
last = row.Values[i]
|
|
}
|
|
case sentBytes:
|
|
data := data.(*metric.HistogramInt64Data)
|
|
row := data.Rows[i]
|
|
stats.Sent.Count = row.Count
|
|
stats.Sent.Sum = byteUnits(row.Sum)
|
|
stats.Sent.Min = byteUnits(row.Min)
|
|
stats.Sent.Max = byteUnits(row.Max)
|
|
stats.Sent.Mean = byteUnits(row.Sum) / byteUnits(row.Count)
|
|
case receivedBytes:
|
|
data := data.(*metric.HistogramInt64Data)
|
|
row := data.Rows[i]
|
|
stats.Received.Count = row.Count
|
|
stats.Received.Sum = byteUnits(row.Sum)
|
|
stats.Sent.Min = byteUnits(row.Min)
|
|
stats.Sent.Max = byteUnits(row.Max)
|
|
stats.Received.Mean = byteUnits(row.Sum) / byteUnits(row.Count)
|
|
}
|
|
}
|
|
|
|
for _, set := range [][]*rpcStats{r.Inbound, r.Outbound} {
|
|
for _, stats := range set {
|
|
stats.Completed = 0
|
|
for _, b := range stats.Codes {
|
|
stats.Completed += b.Count
|
|
}
|
|
stats.InProgress = stats.Started - stats.Completed
|
|
}
|
|
}
|
|
}
|
|
|
|
func (r *rpcs) getData(req *http.Request) interface{} {
|
|
return r
|
|
}
|
|
|
|
func units(v float64, suffixes []string) string {
|
|
s := ""
|
|
for _, s = range suffixes {
|
|
n := v / 1000
|
|
if n < 1 {
|
|
break
|
|
}
|
|
v = n
|
|
}
|
|
return fmt.Sprintf("%.2f%s", v, s)
|
|
}
|
|
|
|
type timeUnits float64
|
|
|
|
func (v timeUnits) String() string {
|
|
v = v * 1000 * 1000
|
|
return units(float64(v), []string{"ns", "μs", "ms", "s"})
|
|
}
|
|
|
|
type byteUnits float64
|
|
|
|
func (v byteUnits) String() string {
|
|
return units(float64(v), []string{"B", "KB", "MB", "GB", "TB"})
|
|
}
|