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.
15 "golang.org/x/tools/internal/event"
16 "golang.org/x/tools/internal/event/core"
17 "golang.org/x/tools/internal/event/export/metric"
18 "golang.org/x/tools/internal/event/label"
21 func New() *Exporter {
25 type Exporter struct {
30 func (e *Exporter) ProcessEvent(ctx context.Context, ev core.Event, ln label.Map) context.Context {
31 if !event.IsMetric(ev) {
36 metrics := metric.Entries.Get(ln).([]metric.Data)
37 for _, data := range metrics {
39 // We keep the metrics in name sorted order so the page is stable and easy
40 // to read. We do this with an insertion sort rather than sorting the list
42 index := sort.Search(len(e.metrics), func(i int) bool {
43 return e.metrics[i].Handle() >= name
45 if index >= len(e.metrics) || e.metrics[index].Handle() != name {
46 // we have a new metric, so we need to make a space for it
48 e.metrics = make([]metric.Data, len(old)+1)
49 copy(e.metrics, old[:index])
50 copy(e.metrics[index+1:], old[index:])
52 e.metrics[index] = data
57 func (e *Exporter) header(w http.ResponseWriter, name, description string, isGauge, isHistogram bool) {
65 fmt.Fprintf(w, "# HELP %s %s\n", name, description)
66 fmt.Fprintf(w, "# TYPE %s %s\n", name, kind)
69 func (e *Exporter) row(w http.ResponseWriter, name string, group []label.Label, extra string, value interface{}) {
71 buf := &bytes.Buffer{}
72 fmt.Fprint(buf, group)
77 fmt.Fprint(buf, extra)
84 fmt.Fprintf(w, " %v\n", value)
87 func (e *Exporter) Serve(w http.ResponseWriter, r *http.Request) {
90 for _, data := range e.metrics {
91 switch data := data.(type) {
92 case *metric.Int64Data:
93 e.header(w, data.Info.Name, data.Info.Description, data.IsGauge, false)
94 for i, group := range data.Groups() {
95 e.row(w, data.Info.Name, group, "", data.Rows[i])
98 case *metric.Float64Data:
99 e.header(w, data.Info.Name, data.Info.Description, data.IsGauge, false)
100 for i, group := range data.Groups() {
101 e.row(w, data.Info.Name, group, "", data.Rows[i])
104 case *metric.HistogramInt64Data:
105 e.header(w, data.Info.Name, data.Info.Description, false, true)
106 for i, group := range data.Groups() {
108 for j, b := range data.Info.Buckets {
109 e.row(w, data.Info.Name+"_bucket", group, fmt.Sprintf(`le="%v"`, b), row.Values[j])
111 e.row(w, data.Info.Name+"_bucket", group, `le="+Inf"`, row.Count)
112 e.row(w, data.Info.Name+"_count", group, "", row.Count)
113 e.row(w, data.Info.Name+"_sum", group, "", row.Sum)
116 case *metric.HistogramFloat64Data:
117 e.header(w, data.Info.Name, data.Info.Description, false, true)
118 for i, group := range data.Groups() {
120 for j, b := range data.Info.Buckets {
121 e.row(w, data.Info.Name+"_bucket", group, fmt.Sprintf(`le="%v"`, b), row.Values[j])
123 e.row(w, data.Info.Name+"_bucket", group, `le="+Inf"`, row.Count)
124 e.row(w, data.Info.Name+"_count", group, "", row.Count)
125 e.row(w, data.Info.Name+"_sum", group, "", row.Sum)