mirror of
https://github.com/golang/go
synced 2024-11-18 18:14:43 -07:00
internal/lsp: add prometheus exporting of all metrics
Change-Id: I1e7ce371d8abd2eb80aad70935695f61b6374ff8 Reviewed-on: https://go-review.googlesource.com/c/tools/+/185347 Run-TryBot: Ian Cottrell <iancottrell@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
parent
75aaabac35
commit
9c57229d8a
111
internal/lsp/debug/prometheus.go
Normal file
111
internal/lsp/debug/prometheus.go
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
// 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 (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"golang.org/x/tools/internal/lsp/telemetry/metric"
|
||||||
|
"golang.org/x/tools/internal/lsp/telemetry/tag"
|
||||||
|
"golang.org/x/tools/internal/lsp/telemetry/worker"
|
||||||
|
)
|
||||||
|
|
||||||
|
type prometheus struct {
|
||||||
|
metrics []metric.Data
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *prometheus) observeMetric(data metric.Data) {
|
||||||
|
name := data.Handle().Name()
|
||||||
|
index := sort.Search(len(p.metrics), func(i int) bool {
|
||||||
|
return p.metrics[i].Handle().Name() >= name
|
||||||
|
})
|
||||||
|
if index >= len(p.metrics) || p.metrics[index].Handle().Name() != name {
|
||||||
|
old := p.metrics
|
||||||
|
p.metrics = make([]metric.Data, len(old)+1)
|
||||||
|
copy(p.metrics, old[:index])
|
||||||
|
copy(p.metrics[index+1:], old[index:])
|
||||||
|
}
|
||||||
|
p.metrics[index] = data
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *prometheus) header(w http.ResponseWriter, name, description string, isGauge, isHistogram bool) {
|
||||||
|
kind := "counter"
|
||||||
|
if isGauge {
|
||||||
|
kind = "gauge"
|
||||||
|
}
|
||||||
|
if isHistogram {
|
||||||
|
kind = "histogram"
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, "# HELP %s %s\n", name, description)
|
||||||
|
fmt.Fprintf(w, "# TYPE %s %s\n", name, kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *prometheus) row(w http.ResponseWriter, name string, group tag.List, extra string, value interface{}) {
|
||||||
|
fmt.Fprint(w, name)
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
fmt.Fprint(buf, group)
|
||||||
|
if extra != "" {
|
||||||
|
if buf.Len() > 0 {
|
||||||
|
fmt.Fprint(buf, ",")
|
||||||
|
}
|
||||||
|
fmt.Fprint(buf, extra)
|
||||||
|
}
|
||||||
|
if buf.Len() > 0 {
|
||||||
|
fmt.Fprint(w, "{")
|
||||||
|
buf.WriteTo(w)
|
||||||
|
fmt.Fprint(w, "}")
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, " %v\n", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *prometheus) serve(w http.ResponseWriter, r *http.Request) {
|
||||||
|
done := make(chan struct{})
|
||||||
|
worker.Do(func() {
|
||||||
|
defer close(done)
|
||||||
|
for _, data := range p.metrics {
|
||||||
|
switch data := data.(type) {
|
||||||
|
case *metric.Int64Data:
|
||||||
|
p.header(w, data.Info.Name, data.Info.Description, data.IsGauge, false)
|
||||||
|
for i, group := range data.Groups() {
|
||||||
|
p.row(w, data.Info.Name, group, "", data.Rows[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
case *metric.Float64Data:
|
||||||
|
p.header(w, data.Info.Name, data.Info.Description, data.IsGauge, false)
|
||||||
|
for i, group := range data.Groups() {
|
||||||
|
p.row(w, data.Info.Name, group, "", data.Rows[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
case *metric.HistogramInt64Data:
|
||||||
|
p.header(w, data.Info.Name, data.Info.Description, false, true)
|
||||||
|
for i, group := range data.Groups() {
|
||||||
|
row := data.Rows[i]
|
||||||
|
for j, b := range data.Info.Buckets {
|
||||||
|
p.row(w, data.Info.Name+"_bucket", group, fmt.Sprintf(`le="%v"`, b), row.Values[j])
|
||||||
|
}
|
||||||
|
p.row(w, data.Info.Name+"_bucket", group, `le="+Inf"`, row.Count)
|
||||||
|
p.row(w, data.Info.Name+"_count", group, "", row.Count)
|
||||||
|
p.row(w, data.Info.Name+"_sum", group, "", row.Sum)
|
||||||
|
}
|
||||||
|
|
||||||
|
case *metric.HistogramFloat64Data:
|
||||||
|
p.header(w, data.Info.Name, data.Info.Description, false, true)
|
||||||
|
for i, group := range data.Groups() {
|
||||||
|
row := data.Rows[i]
|
||||||
|
for j, b := range data.Info.Buckets {
|
||||||
|
p.row(w, data.Info.Name+"_bucket", group, fmt.Sprintf(`le="%v"`, b), row.Values[j])
|
||||||
|
}
|
||||||
|
p.row(w, data.Info.Name+"_bucket", group, `le="+Inf"`, row.Count)
|
||||||
|
p.row(w, data.Info.Name+"_count", group, "", row.Count)
|
||||||
|
p.row(w, data.Info.Name+"_sum", group, "", row.Sum)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
<-done
|
||||||
|
}
|
@ -19,6 +19,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"golang.org/x/tools/internal/lsp/telemetry/metric"
|
||||||
"golang.org/x/tools/internal/span"
|
"golang.org/x/tools/internal/span"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -212,6 +213,8 @@ func Serve(ctx context.Context, addr string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Printf("Debug serving on port: %d", listener.Addr().(*net.TCPAddr).Port)
|
log.Printf("Debug serving on port: %d", listener.Addr().(*net.TCPAddr).Port)
|
||||||
|
prometheus := prometheus{}
|
||||||
|
metric.RegisterObservers(prometheus.observeMetric)
|
||||||
go func() {
|
go func() {
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
mux.HandleFunc("/", Render(mainTmpl, func(*http.Request) interface{} { return data }))
|
mux.HandleFunc("/", Render(mainTmpl, func(*http.Request) interface{} { return data }))
|
||||||
@ -221,6 +224,7 @@ func Serve(ctx context.Context, addr string) error {
|
|||||||
mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
|
mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
|
||||||
mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
|
mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
|
||||||
mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
|
mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
|
||||||
|
mux.HandleFunc("/metrics/", prometheus.serve)
|
||||||
mux.HandleFunc("/cache/", Render(cacheTmpl, getCache))
|
mux.HandleFunc("/cache/", Render(cacheTmpl, getCache))
|
||||||
mux.HandleFunc("/session/", Render(sessionTmpl, getSession))
|
mux.HandleFunc("/session/", Render(sessionTmpl, getSession))
|
||||||
mux.HandleFunc("/view/", Render(viewTmpl, getView))
|
mux.HandleFunc("/view/", Render(viewTmpl, getView))
|
||||||
@ -283,7 +287,7 @@ td.value {
|
|||||||
<a href="/">Main</a>
|
<a href="/">Main</a>
|
||||||
<a href="/info">Info</a>
|
<a href="/info">Info</a>
|
||||||
<a href="/memory">Memory</a>
|
<a href="/memory">Memory</a>
|
||||||
<a href="/debug/">Debug</a>
|
<a href="/metrics">Metrics</a>
|
||||||
<hr>
|
<hr>
|
||||||
<h1>{{template "title" .}}</h1>
|
<h1>{{template "title" .}}</h1>
|
||||||
{{block "body" .}}
|
{{block "body" .}}
|
||||||
|
Loading…
Reference in New Issue
Block a user