+++ /dev/null
-// 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 prometheus
-
-import (
- "bytes"
- "context"
- "fmt"
- "net/http"
- "sort"
- "sync"
-
- "golang.org/x/tools/internal/event"
- "golang.org/x/tools/internal/event/core"
- "golang.org/x/tools/internal/event/export/metric"
- "golang.org/x/tools/internal/event/label"
-)
-
-func New() *Exporter {
- return &Exporter{}
-}
-
-type Exporter struct {
- mu sync.Mutex
- metrics []metric.Data
-}
-
-func (e *Exporter) ProcessEvent(ctx context.Context, ev core.Event, ln label.Map) context.Context {
- if !event.IsMetric(ev) {
- return ctx
- }
- e.mu.Lock()
- defer e.mu.Unlock()
- metrics := metric.Entries.Get(ln).([]metric.Data)
- for _, data := range metrics {
- name := data.Handle()
- // We keep the metrics in name sorted order so the page is stable and easy
- // to read. We do this with an insertion sort rather than sorting the list
- // each time
- index := sort.Search(len(e.metrics), func(i int) bool {
- return e.metrics[i].Handle() >= name
- })
- if index >= len(e.metrics) || e.metrics[index].Handle() != name {
- // we have a new metric, so we need to make a space for it
- old := e.metrics
- e.metrics = make([]metric.Data, len(old)+1)
- copy(e.metrics, old[:index])
- copy(e.metrics[index+1:], old[index:])
- }
- e.metrics[index] = data
- }
- return ctx
-}
-
-func (e *Exporter) 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 (e *Exporter) row(w http.ResponseWriter, name string, group []label.Label, 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 (e *Exporter) Serve(w http.ResponseWriter, r *http.Request) {
- e.mu.Lock()
- defer e.mu.Unlock()
- for _, data := range e.metrics {
- switch data := data.(type) {
- case *metric.Int64Data:
- e.header(w, data.Info.Name, data.Info.Description, data.IsGauge, false)
- for i, group := range data.Groups() {
- e.row(w, data.Info.Name, group, "", data.Rows[i])
- }
-
- case *metric.Float64Data:
- e.header(w, data.Info.Name, data.Info.Description, data.IsGauge, false)
- for i, group := range data.Groups() {
- e.row(w, data.Info.Name, group, "", data.Rows[i])
- }
-
- case *metric.HistogramInt64Data:
- e.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 {
- e.row(w, data.Info.Name+"_bucket", group, fmt.Sprintf(`le="%v"`, b), row.Values[j])
- }
- e.row(w, data.Info.Name+"_bucket", group, `le="+Inf"`, row.Count)
- e.row(w, data.Info.Name+"_count", group, "", row.Count)
- e.row(w, data.Info.Name+"_sum", group, "", row.Sum)
- }
-
- case *metric.HistogramFloat64Data:
- e.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 {
- e.row(w, data.Info.Name+"_bucket", group, fmt.Sprintf(`le="%v"`, b), row.Values[j])
- }
- e.row(w, data.Info.Name+"_bucket", group, `le="+Inf"`, row.Count)
- e.row(w, data.Info.Name+"_count", group, "", row.Count)
- e.row(w, data.Info.Name+"_sum", group, "", row.Sum)
- }
- }
- }
-}