diff options
Diffstat (limited to '')
28 files changed, 5195 insertions, 0 deletions
diff --git a/src/go/collectors/go.d.plugin/pkg/prometheus/client.go b/src/go/collectors/go.d.plugin/pkg/prometheus/client.go new file mode 100644 index 000000000..3365b270c --- /dev/null +++ b/src/go/collectors/go.d.plugin/pkg/prometheus/client.go @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package prometheus + +import ( + "bufio" + "bytes" + "compress/gzip" + "fmt" + "io" + "net/http" + "net/url" + "os" + "path/filepath" + + "github.com/netdata/netdata/go/go.d.plugin/pkg/prometheus/selector" + "github.com/netdata/netdata/go/go.d.plugin/pkg/web" +) + +type ( + // Prometheus is a helper for scrape and parse prometheus format metrics. + Prometheus interface { + // ScrapeSeries and parse prometheus format metrics + ScrapeSeries() (Series, error) + Scrape() (MetricFamilies, error) + HTTPClient() *http.Client + } + + prometheus struct { + client *http.Client + request web.Request + filepath string + + sr selector.Selector + + parser promTextParser + + buf *bytes.Buffer + gzipr *gzip.Reader + bodyBuf *bufio.Reader + } +) + +const ( + acceptHeader = `text/plain;version=0.0.4;q=1,*/*;q=0.1` +) + +// New creates a Prometheus instance. +func New(client *http.Client, request web.Request) Prometheus { + return &prometheus{ + client: client, + request: request, + buf: bytes.NewBuffer(make([]byte, 0, 16000)), + } +} + +// NewWithSelector creates a Prometheus instance with the selector. +func NewWithSelector(client *http.Client, request web.Request, sr selector.Selector) Prometheus { + p := &prometheus{ + client: client, + request: request, + sr: sr, + buf: bytes.NewBuffer(make([]byte, 0, 16000)), + parser: promTextParser{sr: sr}, + } + + if v, err := url.Parse(request.URL); err == nil && v.Scheme == "file" { + p.filepath = filepath.Join(v.Host, v.Path) + } + + return p +} + +func (p *prometheus) HTTPClient() *http.Client { + return p.client +} + +// ScrapeSeries scrapes metrics, parses and sorts +func (p *prometheus) ScrapeSeries() (Series, error) { + p.buf.Reset() + + if err := p.fetch(p.buf); err != nil { + return nil, err + } + + return p.parser.parseToSeries(p.buf.Bytes()) +} + +func (p *prometheus) Scrape() (MetricFamilies, error) { + p.buf.Reset() + + if err := p.fetch(p.buf); err != nil { + return nil, err + } + + return p.parser.parseToMetricFamilies(p.buf.Bytes()) +} + +func (p *prometheus) fetch(w io.Writer) error { + // TODO: should be a separate text file prom client + if p.filepath != "" { + f, err := os.Open(p.filepath) + if err != nil { + return err + } + defer f.Close() + + _, err = io.Copy(w, f) + + return err + } + + req, err := web.NewHTTPRequest(p.request) + if err != nil { + return err + } + + req.Header.Add("Accept", acceptHeader) + req.Header.Add("Accept-Encoding", "gzip") + + resp, err := p.client.Do(req) + if err != nil { + return err + } + + defer func() { + _, _ = io.Copy(io.Discard, resp.Body) + _ = resp.Body.Close() + }() + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("server '%s' returned HTTP status code %d (%s)", req.URL, resp.StatusCode, resp.Status) + } + + if resp.Header.Get("Content-Encoding") != "gzip" { + _, err = io.Copy(w, resp.Body) + return err + } + + if p.gzipr == nil { + p.bodyBuf = bufio.NewReader(resp.Body) + p.gzipr, err = gzip.NewReader(p.bodyBuf) + if err != nil { + return err + } + } else { + p.bodyBuf.Reset(resp.Body) + _ = p.gzipr.Reset(p.bodyBuf) + } + + _, err = io.Copy(w, p.gzipr) + _ = p.gzipr.Close() + + return err +} diff --git a/src/go/collectors/go.d.plugin/pkg/prometheus/client_test.go b/src/go/collectors/go.d.plugin/pkg/prometheus/client_test.go new file mode 100644 index 000000000..76199800a --- /dev/null +++ b/src/go/collectors/go.d.plugin/pkg/prometheus/client_test.go @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package prometheus + +import ( + "bytes" + "compress/gzip" + "net/http" + "net/http/httptest" + "os" + "strings" + "testing" + + "github.com/netdata/netdata/go/go.d.plugin/pkg/prometheus/selector" + "github.com/netdata/netdata/go/go.d.plugin/pkg/web" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var ( + testData, _ = os.ReadFile("testdata/testdata.txt") + testDataNoMeta, _ = os.ReadFile("testdata/testdata.nometa.txt") +) + +func Test_testClientDataIsValid(t *testing.T) { + for name, data := range map[string][]byte{ + "testData": testData, + } { + require.NotNilf(t, data, name) + } +} + +func TestPrometheus404(t *testing.T) { + tsMux := http.NewServeMux() + tsMux.HandleFunc("/metrics", func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(404) + }) + ts := httptest.NewServer(tsMux) + defer ts.Close() + + req := web.Request{URL: ts.URL + "/metrics"} + prom := New(http.DefaultClient, req) + res, err := prom.ScrapeSeries() + + assert.Error(t, err) + assert.Nil(t, res) +} + +func TestPrometheusPlain(t *testing.T) { + tsMux := http.NewServeMux() + tsMux.HandleFunc("/metrics", func(w http.ResponseWriter, r *http.Request) { + _, _ = w.Write(testData) + }) + ts := httptest.NewServer(tsMux) + defer ts.Close() + + req := web.Request{URL: ts.URL + "/metrics"} + prom := New(http.DefaultClient, req) + res, err := prom.ScrapeSeries() + + assert.NoError(t, err) + verifyTestData(t, res) +} + +func TestPrometheusPlainWithSelector(t *testing.T) { + tsMux := http.NewServeMux() + tsMux.HandleFunc("/metrics", func(w http.ResponseWriter, r *http.Request) { + _, _ = w.Write(testData) + }) + ts := httptest.NewServer(tsMux) + defer ts.Close() + + req := web.Request{URL: ts.URL + "/metrics"} + sr, err := selector.Parse("go_gc*") + require.NoError(t, err) + prom := NewWithSelector(http.DefaultClient, req, sr) + + res, err := prom.ScrapeSeries() + require.NoError(t, err) + + for _, v := range res { + assert.Truef(t, strings.HasPrefix(v.Name(), "go_gc"), v.Name()) + } +} + +func TestPrometheusGzip(t *testing.T) { + counter := 0 + rawTestData := [][]byte{testData, testDataNoMeta} + tsMux := http.NewServeMux() + tsMux.HandleFunc("/metrics", func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Encoding", "gzip") + w.WriteHeader(200) + gz := new(bytes.Buffer) + ww := gzip.NewWriter(gz) + _, _ = ww.Write(rawTestData[counter]) + _ = ww.Close() + _, _ = gz.WriteTo(w) + counter++ + }) + ts := httptest.NewServer(tsMux) + defer ts.Close() + + req := web.Request{URL: ts.URL + "/metrics"} + prom := New(http.DefaultClient, req) + + for i := 0; i < 2; i++ { + res, err := prom.ScrapeSeries() + assert.NoError(t, err) + verifyTestData(t, res) + } +} + +func TestPrometheusReadFromFile(t *testing.T) { + req := web.Request{URL: "file://testdata/testdata.txt"} + prom := NewWithSelector(http.DefaultClient, req, nil) + + for i := 0; i < 2; i++ { + res, err := prom.ScrapeSeries() + assert.NoError(t, err) + verifyTestData(t, res) + } +} + +func verifyTestData(t *testing.T, ms Series) { + assert.Equal(t, 410, len(ms)) + assert.Equal(t, "go_gc_duration_seconds", ms[0].Labels.Get("__name__")) + assert.Equal(t, "0.25", ms[0].Labels.Get("quantile")) + assert.InDelta(t, 4.9351e-05, ms[0].Value, 0.0001) + + notExistYet := ms.FindByName("not_exist_yet") + assert.NotNil(t, notExistYet) + assert.Len(t, notExistYet, 0) + + targetInterval := ms.FindByName("prometheus_target_interval_length_seconds") + assert.Len(t, targetInterval, 5) +} diff --git a/src/go/collectors/go.d.plugin/pkg/prometheus/metric_family.go b/src/go/collectors/go.d.plugin/pkg/prometheus/metric_family.go new file mode 100644 index 000000000..dde08801e --- /dev/null +++ b/src/go/collectors/go.d.plugin/pkg/prometheus/metric_family.go @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package prometheus + +import ( + "github.com/prometheus/common/model" + "github.com/prometheus/prometheus/model/labels" +) + +type ( + MetricFamilies map[string]*MetricFamily + + MetricFamily struct { + name string + help string + typ model.MetricType + metrics []Metric + } + Metric struct { + labels []labels.Label + gauge *Gauge + counter *Counter + summary *Summary + histogram *Histogram + untyped *Untyped + } + Gauge struct { + value float64 + } + Counter struct { + value float64 + } + Summary struct { + sum float64 + count float64 + quantiles []Quantile + } + Quantile struct { + quantile float64 + value float64 + } + Histogram struct { + sum float64 + count float64 + buckets []Bucket + } + Bucket struct { + upperBound float64 + cumulativeCount float64 + } + Untyped struct { + value float64 + } +) + +func (mfs MetricFamilies) Len() int { + return len(mfs) +} + +func (mfs MetricFamilies) Get(name string) *MetricFamily { + return (mfs)[name] +} + +func (mfs MetricFamilies) GetGauge(name string) *MetricFamily { + return mfs.get(name, model.MetricTypeGauge) +} + +func (mfs MetricFamilies) GetCounter(name string) *MetricFamily { + return mfs.get(name, model.MetricTypeCounter) +} + +func (mfs MetricFamilies) GetSummary(name string) *MetricFamily { + return mfs.get(name, model.MetricTypeSummary) +} + +func (mfs MetricFamilies) GetHistogram(name string) *MetricFamily { + return mfs.get(name, model.MetricTypeHistogram) +} + +func (mfs MetricFamilies) get(name string, typ model.MetricType) *MetricFamily { + mf := mfs.Get(name) + if mf == nil || mf.typ != typ { + return nil + } + return mf +} + +func (mf *MetricFamily) Name() string { return mf.name } +func (mf *MetricFamily) Help() string { return mf.help } +func (mf *MetricFamily) Type() model.MetricType { return mf.typ } +func (mf *MetricFamily) Metrics() []Metric { return mf.metrics } + +func (m *Metric) Labels() labels.Labels { return m.labels } +func (m *Metric) Gauge() *Gauge { return m.gauge } +func (m *Metric) Counter() *Counter { return m.counter } +func (m *Metric) Summary() *Summary { return m.summary } +func (m *Metric) Histogram() *Histogram { return m.histogram } +func (m *Metric) Untyped() *Untyped { return m.untyped } + +func (g Gauge) Value() float64 { return g.value } +func (c Counter) Value() float64 { return c.value } +func (u Untyped) Value() float64 { return u.value } + +func (s Summary) Count() float64 { return s.count } +func (s Summary) Sum() float64 { return s.sum } +func (s Summary) Quantiles() []Quantile { return s.quantiles } + +func (q Quantile) Quantile() float64 { return q.quantile } +func (q Quantile) Value() float64 { return q.value } + +func (h Histogram) Count() float64 { return h.count } +func (h Histogram) Sum() float64 { return h.sum } +func (h Histogram) Buckets() []Bucket { return h.buckets } + +func (b Bucket) UpperBound() float64 { return b.upperBound } +func (b Bucket) CumulativeCount() float64 { return b.cumulativeCount } diff --git a/src/go/collectors/go.d.plugin/pkg/prometheus/metric_family_test.go b/src/go/collectors/go.d.plugin/pkg/prometheus/metric_family_test.go new file mode 100644 index 000000000..f373996da --- /dev/null +++ b/src/go/collectors/go.d.plugin/pkg/prometheus/metric_family_test.go @@ -0,0 +1,356 @@ +package prometheus + +import ( + "testing" + + "github.com/prometheus/common/model" + "github.com/prometheus/prometheus/model/labels" + "github.com/stretchr/testify/assert" +) + +func TestMetricFamilies_Len(t *testing.T) { + tests := map[string]struct { + mfs MetricFamilies + wantLen int + }{ + "initialized with two elements": { + mfs: MetricFamilies{"1": nil, "2": nil}, + wantLen: 2, + }, + "not initialized": { + mfs: nil, + wantLen: 0, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + assert.Equal(t, test.mfs.Len(), test.wantLen) + }) + } +} + +func TestMetricFamilies_Get(t *testing.T) { + const n = "metric" + + tests := map[string]struct { + mfs MetricFamilies + wantMF *MetricFamily + }{ + "etric is found": { + mfs: MetricFamilies{n: &MetricFamily{name: n}}, + wantMF: &MetricFamily{name: n}, + }, + "metric is not found": { + mfs: MetricFamilies{"!" + n: &MetricFamily{name: n}}, + wantMF: nil, + }, + "not initialized": { + mfs: nil, + wantMF: nil, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + assert.Equal(t, test.mfs.Get(n), test.wantMF) + }) + } +} + +func TestMetricFamilies_GetGauge(t *testing.T) { + const n = "metric" + + tests := map[string]struct { + mfs MetricFamilies + wantMF *MetricFamily + }{ + "metric is found and is Gauge": { + mfs: MetricFamilies{n: &MetricFamily{name: n, typ: model.MetricTypeGauge}}, + wantMF: &MetricFamily{name: n, typ: model.MetricTypeGauge}, + }, + "metric is found but it is not Gauge": { + mfs: MetricFamilies{n: &MetricFamily{name: n, typ: model.MetricTypeUnknown}}, + wantMF: nil, + }, + "metric is not found": { + mfs: MetricFamilies{"!" + n: &MetricFamily{name: n, typ: model.MetricTypeGauge}}, + wantMF: nil, + }, + "not initialized": { + mfs: nil, + wantMF: nil, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + assert.Equal(t, test.mfs.GetGauge(n), test.wantMF) + }) + } +} + +func TestMetricFamilies_GetCounter(t *testing.T) { + const n = "metric" + + tests := map[string]struct { + mfs MetricFamilies + wantMF *MetricFamily + }{ + "metric is found and is Counter": { + mfs: MetricFamilies{n: &MetricFamily{name: n, typ: model.MetricTypeCounter}}, + wantMF: &MetricFamily{name: n, typ: model.MetricTypeCounter}, + }, + "metric is found but it is not Counter": { + mfs: MetricFamilies{n: &MetricFamily{name: n, typ: model.MetricTypeGauge}}, + wantMF: nil, + }, + "metric is not found": { + mfs: MetricFamilies{"!" + n: &MetricFamily{name: n, typ: model.MetricTypeGauge}}, + wantMF: nil, + }, + "not initialized": { + mfs: nil, + wantMF: nil, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + assert.Equal(t, test.mfs.GetCounter(n), test.wantMF) + }) + } +} + +func TestMetricFamilies_GetSummary(t *testing.T) { + const n = "metric" + + tests := map[string]struct { + mfs MetricFamilies + wantMF *MetricFamily + }{ + "metric is found and is Summary": { + mfs: MetricFamilies{n: &MetricFamily{name: n, typ: model.MetricTypeSummary}}, + wantMF: &MetricFamily{name: n, typ: model.MetricTypeSummary}, + }, + "metric is found but it is not Summary": { + mfs: MetricFamilies{n: &MetricFamily{name: n, typ: model.MetricTypeGauge}}, + wantMF: nil, + }, + "metric is not found": { + mfs: MetricFamilies{"!" + n: &MetricFamily{name: n, typ: model.MetricTypeGauge}}, + wantMF: nil, + }, + "not initialized": { + mfs: nil, + wantMF: nil, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + assert.Equal(t, test.mfs.GetSummary(n), test.wantMF) + }) + } +} + +func TestMetricFamilies_GetHistogram(t *testing.T) { + const n = "metric" + + tests := map[string]struct { + mfs MetricFamilies + wantMF *MetricFamily + }{ + "metric is found and is Histogram": { + mfs: MetricFamilies{n: &MetricFamily{name: n, typ: model.MetricTypeHistogram}}, + wantMF: &MetricFamily{name: n, typ: model.MetricTypeHistogram}, + }, + "metric is found but it is not Histogram": { + mfs: MetricFamilies{n: &MetricFamily{name: n, typ: model.MetricTypeGauge}}, + wantMF: nil, + }, + "metric is not found": { + mfs: MetricFamilies{"!" + n: &MetricFamily{name: n, typ: model.MetricTypeGauge}}, + wantMF: nil, + }, + "not initialized": { + mfs: nil, + wantMF: nil, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + assert.Equal(t, test.mfs.GetHistogram(n), test.wantMF) + }) + } +} + +func TestMetricFamily_Name(t *testing.T) { + mf := &MetricFamily{name: "name"} + assert.Equal(t, mf.Name(), "name") +} + +func TestMetricFamily_Type(t *testing.T) { + mf := &MetricFamily{typ: model.MetricTypeGauge} + assert.Equal(t, mf.Type(), model.MetricTypeGauge) +} + +func TestMetricFamily_Help(t *testing.T) { + mf := &MetricFamily{help: "help"} + assert.Equal(t, mf.Help(), "help") +} + +func TestMetricFamily_Metrics(t *testing.T) { + metrics := []Metric{{gauge: &Gauge{value: 1}, counter: &Counter{value: 1}}} + mf := &MetricFamily{metrics: metrics} + assert.Equal(t, mf.Metrics(), metrics) +} + +func TestMetric_Labels(t *testing.T) { + lbs := labels.Labels{{Name: "1", Value: "1"}, {Name: "2", Value: "2"}} + m := &Metric{labels: lbs} + assert.Equal(t, m.Labels(), lbs) +} + +func TestMetric_Gauge(t *testing.T) { + tests := map[string]struct { + m *Metric + want *Gauge + }{ + "gauge set": { + m: &Metric{gauge: &Gauge{value: 1}}, + want: &Gauge{value: 1}, + }, + "gauge not set": { + m: &Metric{}, + want: nil, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + assert.Equal(t, test.m.Gauge(), test.want) + }) + } +} + +func TestMetric_Counter(t *testing.T) { + tests := map[string]struct { + m *Metric + want *Counter + }{ + "counter set": { + m: &Metric{counter: &Counter{value: 1}}, + want: &Counter{value: 1}, + }, + "counter not set": { + m: &Metric{}, + want: nil, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + assert.Equal(t, test.m.Counter(), test.want) + }) + } +} + +func TestMetric_Summary(t *testing.T) { + tests := map[string]struct { + m *Metric + want *Summary + }{ + "summary set": { + m: &Metric{summary: &Summary{sum: 0.1, count: 3}}, + want: &Summary{sum: 0.1, count: 3}, + }, + "summary not set": { + m: &Metric{}, + want: nil, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + assert.Equal(t, test.m.Summary(), test.want) + }) + } +} + +func TestMetric_Histogram(t *testing.T) { + tests := map[string]struct { + m *Metric + want *Histogram + }{ + "histogram set": { + m: &Metric{histogram: &Histogram{sum: 0.1, count: 3}}, + want: &Histogram{sum: 0.1, count: 3}, + }, + "histogram not set": { + m: &Metric{}, + want: nil, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + assert.Equal(t, test.m.Histogram(), test.want) + }) + } +} + +func TestGauge_Value(t *testing.T) { + assert.Equal(t, Gauge{value: 1}.Value(), 1.0) +} + +func TestCounter_Value(t *testing.T) { + assert.Equal(t, Counter{value: 1}.Value(), 1.0) +} + +func TestSummary_Sum(t *testing.T) { + assert.Equal(t, Summary{sum: 1}.Sum(), 1.0) +} + +func TestSummary_Count(t *testing.T) { + assert.Equal(t, Summary{count: 1}.Count(), 1.0) +} + +func TestSummary_Quantiles(t *testing.T) { + assert.Equal(t, + Summary{quantiles: []Quantile{{quantile: 0.1, value: 1}}}.Quantiles(), + []Quantile{{quantile: 0.1, value: 1}}, + ) +} + +func TestQuantile_Value(t *testing.T) { + assert.Equal(t, Quantile{value: 1}.Value(), 1.0) +} + +func TestQuantile_Quantile(t *testing.T) { + assert.Equal(t, Quantile{quantile: 0.1}.Quantile(), 0.1) +} + +func TestHistogram_Sum(t *testing.T) { + assert.Equal(t, Histogram{sum: 1}.Sum(), 1.0) +} + +func TestHistogram_Count(t *testing.T) { + assert.Equal(t, Histogram{count: 1}.Count(), 1.0) +} + +func TestHistogram_Buckets(t *testing.T) { + assert.Equal(t, + Histogram{buckets: []Bucket{{upperBound: 0.1, cumulativeCount: 1}}}.Buckets(), + []Bucket{{upperBound: 0.1, cumulativeCount: 1}}, + ) +} + +func TestBucket_UpperBound(t *testing.T) { + assert.Equal(t, Bucket{upperBound: 0.1}.UpperBound(), 0.1) +} + +func TestBucket_CumulativeCount(t *testing.T) { + assert.Equal(t, Bucket{cumulativeCount: 1}.CumulativeCount(), 1.0) +} diff --git a/src/go/collectors/go.d.plugin/pkg/prometheus/metric_series.go b/src/go/collectors/go.d.plugin/pkg/prometheus/metric_series.go new file mode 100644 index 000000000..31914f4b2 --- /dev/null +++ b/src/go/collectors/go.d.plugin/pkg/prometheus/metric_series.go @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package prometheus + +import ( + "sort" + + "github.com/prometheus/prometheus/model/labels" +) + +type ( + // SeriesSample is a pair of label set and value + SeriesSample struct { + Labels labels.Labels + Value float64 + } + + // Series is a list of SeriesSample + Series []SeriesSample +) + +// Name the __name__ label value +func (s SeriesSample) Name() string { + return s.Labels[0].Value +} + +// Add appends a metric. +func (s *Series) Add(kv SeriesSample) { + *s = append(*s, kv) +} + +// Reset resets the buffer to be empty, +// but it retains the underlying storage for use by future writes. +func (s *Series) Reset() { + *s = (*s)[:0] +} + +// Sort sorts data. +func (s Series) Sort() { + sort.Sort(s) +} + +// Len returns metric length. +func (s Series) Len() int { + return len(s) +} + +// Less reports whether the element with +// index i should sort before the element with index j. +func (s Series) Less(i, j int) bool { + return s[i].Name() < s[j].Name() +} + +// Swap swaps the elements with indexes i and j. +func (s Series) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} + +// FindByName finds metrics where it's __name__ label matches given name. +// It expects the metrics is sorted. +// Complexity: O(log(N)) +func (s Series) FindByName(name string) Series { + from := sort.Search(len(s), func(i int) bool { + return s[i].Name() >= name + }) + if from == len(s) || s[from].Name() != name { // not found + return Series{} + } + until := from + 1 + for until < len(s) && s[until].Name() == name { + until++ + } + return s[from:until] +} + +// FindByNames finds metrics where it's __name__ label matches given any of names. +// It expects the metrics is sorted. +// Complexity: O(log(N)) +func (s Series) FindByNames(names ...string) Series { + switch len(names) { + case 0: + return Series{} + case 1: + return s.FindByName(names[0]) + } + var result Series + for _, name := range names { + result = append(result, s.FindByName(name)...) + } + return result +} + +// Max returns the max value. +// It does NOT expect the metrics is sorted. +// Complexity: O(N) +func (s Series) Max() float64 { + switch len(s) { + case 0: + return 0 + case 1: + return s[0].Value + } + max := s[0].Value + for _, kv := range s[1:] { + if max < kv.Value { + max = kv.Value + } + } + return max +} diff --git a/src/go/collectors/go.d.plugin/pkg/prometheus/metric_series_test.go b/src/go/collectors/go.d.plugin/pkg/prometheus/metric_series_test.go new file mode 100644 index 000000000..80c805474 --- /dev/null +++ b/src/go/collectors/go.d.plugin/pkg/prometheus/metric_series_test.go @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package prometheus + +import ( + "testing" + + "github.com/prometheus/prometheus/model/labels" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TODO: write better tests + +const ( + testName1 = "logback_events_total" + testName2 = "jvm_threads_peak" +) + +func newTestSeries() Series { + return Series{ + { + Value: 10, + Labels: labels.Labels{ + {Name: "__name__", Value: testName1}, + {Name: "level", Value: "error"}, + }, + }, + { + Value: 20, + Labels: labels.Labels{ + {Name: "__name__", Value: testName1}, + {Name: "level", Value: "warn"}, + }, + }, + { + Value: 5, + Labels: labels.Labels{ + {Name: "__name__", Value: testName1}, + {Name: "level", Value: "info"}, + }, + }, + { + Value: 15, + Labels: labels.Labels{ + {Name: "__name__", Value: testName1}, + {Name: "level", Value: "debug"}, + }, + }, + { + Value: 26, + Labels: labels.Labels{ + {Name: "__name__", Value: testName2}, + }, + }, + } +} + +func TestSeries_Name(t *testing.T) { + m := newTestSeries() + + assert.Equal(t, testName1, m[0].Name()) + assert.Equal(t, testName1, m[1].Name()) + +} + +func TestSeries_Add(t *testing.T) { + m := newTestSeries() + + require.Len(t, m, 5) + m.Add(SeriesSample{}) + assert.Len(t, m, 6) +} + +func TestSeries_FindByName(t *testing.T) { + m := newTestSeries() + m.Sort() + assert.Len(t, Series{}.FindByName(testName1), 0) + assert.Len(t, m.FindByName(testName1), len(m)-1) +} + +func TestSeries_FindByNames(t *testing.T) { + m := newTestSeries() + m.Sort() + assert.Len(t, m.FindByNames(), 0) + assert.Len(t, m.FindByNames(testName1), len(m)-1) + assert.Len(t, m.FindByNames(testName1, testName2), len(m)) +} + +func TestSeries_Len(t *testing.T) { + m := newTestSeries() + + assert.Equal(t, len(m), m.Len()) +} + +func TestSeries_Less(t *testing.T) { + m := newTestSeries() + + assert.False(t, m.Less(0, 1)) + assert.True(t, m.Less(4, 0)) +} + +func TestSeries_Max(t *testing.T) { + m := newTestSeries() + + assert.Equal(t, float64(26), m.Max()) + +} + +func TestSeries_Reset(t *testing.T) { + m := newTestSeries() + m.Reset() + + assert.Len(t, m, 0) + +} + +func TestSeries_Sort(t *testing.T) { + { + m := newTestSeries() + m.Sort() + assert.Equal(t, testName2, m[0].Name()) + } + { + m := Series{} + assert.Equal(t, 0.0, m.Max()) + } +} + +func TestSeries_Swap(t *testing.T) { + m := newTestSeries() + + m0 := m[0] + m1 := m[1] + + m.Swap(0, 1) + + assert.Equal(t, m0, m[1]) + assert.Equal(t, m1, m[0]) +} diff --git a/src/go/collectors/go.d.plugin/pkg/prometheus/parse.go b/src/go/collectors/go.d.plugin/pkg/prometheus/parse.go new file mode 100644 index 000000000..958d66289 --- /dev/null +++ b/src/go/collectors/go.d.plugin/pkg/prometheus/parse.go @@ -0,0 +1,414 @@ +package prometheus + +import ( + "errors" + "fmt" + "io" + "regexp" + "strconv" + "strings" + + "github.com/netdata/netdata/go/go.d.plugin/pkg/prometheus/selector" + + "github.com/prometheus/common/model" + "github.com/prometheus/prometheus/model/labels" + "github.com/prometheus/prometheus/model/textparse" +) + +const ( + quantileLabel = "quantile" + bucketLabel = "le" +) + +const ( + countSuffix = "_count" + sumSuffix = "_sum" + bucketSuffix = "_bucket" +) + +type promTextParser struct { + metrics MetricFamilies + series Series + + sr selector.Selector + + currMF *MetricFamily + currSeries labels.Labels + + summaries map[uint64]*Summary + histograms map[uint64]*Histogram + + isCount bool + isSum bool + isQuantile bool + isBucket bool + + currQuantile float64 + currBucket float64 +} + +func (p *promTextParser) parseToSeries(text []byte) (Series, error) { + p.series.Reset() + + parser := textparse.NewPromParser(text) + for { + entry, err := parser.Next() + if err != nil { + if errors.Is(err, io.EOF) { + break + } + if entry == textparse.EntryInvalid && strings.HasPrefix(err.Error(), "invalid metric type") { + continue + } + return nil, fmt.Errorf("failed to parse prometheus metrics: %v", err) + } + + switch entry { + case textparse.EntrySeries: + p.currSeries = p.currSeries[:0] + + parser.Metric(&p.currSeries) + + if p.sr != nil && !p.sr.Matches(p.currSeries) { + continue + } + + _, _, val := parser.Series() + p.series.Add(SeriesSample{Labels: copyLabels(p.currSeries), Value: val}) + } + } + + p.series.Sort() + + return p.series, nil +} + +var reSpace = regexp.MustCompile(`\s+`) + +func (p *promTextParser) parseToMetricFamilies(text []byte) (MetricFamilies, error) { + p.reset() + + parser := textparse.NewPromParser(text) + for { + entry, err := parser.Next() + if err != nil { + if errors.Is(err, io.EOF) { + break + } + if entry == textparse.EntryInvalid && strings.HasPrefix(err.Error(), "invalid metric type") { + continue + } + return nil, fmt.Errorf("failed to parse prometheus metrics: %v", err) + } + + switch entry { + case textparse.EntryHelp: + name, help := parser.Help() + p.setMetricFamilyByName(string(name)) + p.currMF.help = string(help) + if strings.IndexByte(p.currMF.help, '\n') != -1 { + // convert multiline to one line because HELP is used as the chart title. + p.currMF.help = reSpace.ReplaceAllString(strings.TrimSpace(p.currMF.help), " ") + } + case textparse.EntryType: + name, typ := parser.Type() + p.setMetricFamilyByName(string(name)) + p.currMF.typ = typ + case textparse.EntrySeries: + p.currSeries = p.currSeries[:0] + + parser.Metric(&p.currSeries) + + if p.sr != nil && !p.sr.Matches(p.currSeries) { + continue + } + + p.setMetricFamilyBySeries() + + _, _, value := parser.Series() + + switch p.currMF.typ { + case model.MetricTypeGauge: + p.addGauge(value) + case model.MetricTypeCounter: + p.addCounter(value) + case model.MetricTypeSummary: + p.addSummary(value) + case model.MetricTypeHistogram: + p.addHistogram(value) + case model.MetricTypeUnknown: + p.addUnknown(value) + } + } + } + + for k, v := range p.metrics { + if len(v.Metrics()) == 0 { + delete(p.metrics, k) + } + } + + return p.metrics, nil +} + +func (p *promTextParser) setMetricFamilyByName(name string) { + mf, ok := p.metrics[name] + if !ok { + mf = &MetricFamily{name: name, typ: model.MetricTypeUnknown} + p.metrics[name] = mf + } + p.currMF = mf +} + +func (p *promTextParser) setMetricFamilyBySeries() { + p.isSum, p.isCount, p.isQuantile, p.isBucket = false, false, false, false + p.currQuantile, p.currBucket = 0, 0 + + name := p.currSeries[0].Value + + if p.currMF != nil && p.currMF.name == name { + if p.currMF.typ == model.MetricTypeSummary { + p.setQuantile() + } + return + } + + typ := model.MetricTypeUnknown + + switch { + case strings.HasSuffix(name, sumSuffix): + n := strings.TrimSuffix(name, sumSuffix) + if mf, ok := p.metrics[n]; ok && isSummaryOrHistogram(mf.typ) { + p.isSum = true + p.currSeries[0].Value = n + p.currMF = mf + return + } + case strings.HasSuffix(name, countSuffix): + n := strings.TrimSuffix(name, countSuffix) + if mf, ok := p.metrics[n]; ok && isSummaryOrHistogram(mf.typ) { + p.isCount = true + p.currSeries[0].Value = n + p.currMF = mf + return + } + case strings.HasSuffix(name, bucketSuffix): + n := strings.TrimSuffix(name, bucketSuffix) + if mf, ok := p.metrics[n]; ok && isSummaryOrHistogram(mf.typ) { + p.currSeries[0].Value = n + p.setBucket() + p.currMF = mf + return + } + if p.currSeries.Has(bucketLabel) { + p.currSeries[0].Value = n + p.setBucket() + name = n + typ = model.MetricTypeHistogram + } + case p.currSeries.Has(quantileLabel): + typ = model.MetricTypeSummary + p.setQuantile() + } + + p.setMetricFamilyByName(name) + if p.currMF.typ == "" || p.currMF.typ == model.MetricTypeUnknown { + p.currMF.typ = typ + } +} + +func (p *promTextParser) setQuantile() { + if lbs, v, ok := removeLabel(p.currSeries, quantileLabel); ok { + p.isQuantile = true + p.currSeries = lbs + p.currQuantile, _ = strconv.ParseFloat(v, 64) + } +} + +func (p *promTextParser) setBucket() { + if lbs, v, ok := removeLabel(p.currSeries, bucketLabel); ok { + p.isBucket = true + p.currSeries = lbs + p.currBucket, _ = strconv.ParseFloat(v, 64) + } +} + +func (p *promTextParser) addGauge(value float64) { + p.currSeries = p.currSeries[1:] // remove "__name__" + + if v := len(p.currMF.metrics); v == cap(p.currMF.metrics) { + p.currMF.metrics = append(p.currMF.metrics, Metric{ + labels: copyLabels(p.currSeries), + gauge: &Gauge{value: value}, + }) + } else { + p.currMF.metrics = p.currMF.metrics[:v+1] + if p.currMF.metrics[v].gauge == nil { + p.currMF.metrics[v].gauge = &Gauge{} + } + p.currMF.metrics[v].gauge.value = value + p.currMF.metrics[v].labels = p.currMF.metrics[v].labels[:0] + p.currMF.metrics[v].labels = append(p.currMF.metrics[v].labels, p.currSeries...) + } +} + +func (p *promTextParser) addCounter(value float64) { + p.currSeries = p.currSeries[1:] // remove "__name__" + + if v := len(p.currMF.metrics); v == cap(p.currMF.metrics) { + p.currMF.metrics = append(p.currMF.metrics, Metric{ + labels: copyLabels(p.currSeries), + counter: &Counter{value: value}, + }) + } else { + p.currMF.metrics = p.currMF.metrics[:v+1] + if p.currMF.metrics[v].counter == nil { + p.currMF.metrics[v].counter = &Counter{} + } + p.currMF.metrics[v].counter.value = value + p.currMF.metrics[v].labels = p.currMF.metrics[v].labels[:0] + p.currMF.metrics[v].labels = append(p.currMF.metrics[v].labels, p.currSeries...) + } +} + +func (p *promTextParser) addUnknown(value float64) { + p.currSeries = p.currSeries[1:] // remove "__name__" + + if v := len(p.currMF.metrics); v == cap(p.currMF.metrics) { + p.currMF.metrics = append(p.currMF.metrics, Metric{ + labels: copyLabels(p.currSeries), + untyped: &Untyped{value: value}, + }) + } else { + p.currMF.metrics = p.currMF.metrics[:v+1] + if p.currMF.metrics[v].untyped == nil { + p.currMF.metrics[v].untyped = &Untyped{} + } + p.currMF.metrics[v].untyped.value = value + p.currMF.metrics[v].labels = p.currMF.metrics[v].labels[:0] + p.currMF.metrics[v].labels = append(p.currMF.metrics[v].labels, p.currSeries...) + } +} + +func (p *promTextParser) addSummary(value float64) { + hash := p.currSeries.Hash() + + p.currSeries = p.currSeries[1:] // remove "__name__" + + s, ok := p.summaries[hash] + if !ok { + if v := len(p.currMF.metrics); v == cap(p.currMF.metrics) { + s = &Summary{} + p.currMF.metrics = append(p.currMF.metrics, Metric{ + labels: copyLabels(p.currSeries), + summary: s, + }) + } else { + p.currMF.metrics = p.currMF.metrics[:v+1] + if p.currMF.metrics[v].summary == nil { + p.currMF.metrics[v].summary = &Summary{} + } + p.currMF.metrics[v].summary.sum = 0 + p.currMF.metrics[v].summary.count = 0 + p.currMF.metrics[v].summary.quantiles = p.currMF.metrics[v].summary.quantiles[:0] + p.currMF.metrics[v].labels = p.currMF.metrics[v].labels[:0] + p.currMF.metrics[v].labels = append(p.currMF.metrics[v].labels, p.currSeries...) + s = p.currMF.metrics[v].summary + } + + p.summaries[hash] = s + } + + switch { + case p.isQuantile: + s.quantiles = append(s.quantiles, Quantile{quantile: p.currQuantile, value: value}) + case p.isSum: + s.sum = value + case p.isCount: + s.count = value + } +} + +func (p *promTextParser) addHistogram(value float64) { + hash := p.currSeries.Hash() + + p.currSeries = p.currSeries[1:] // remove "__name__" + + h, ok := p.histograms[hash] + if !ok { + if v := len(p.currMF.metrics); v == cap(p.currMF.metrics) { + h = &Histogram{} + p.currMF.metrics = append(p.currMF.metrics, Metric{ + labels: copyLabels(p.currSeries), + histogram: h, + }) + } else { + p.currMF.metrics = p.currMF.metrics[:v+1] + if p.currMF.metrics[v].histogram == nil { + p.currMF.metrics[v].histogram = &Histogram{} + } + p.currMF.metrics[v].histogram.sum = 0 + p.currMF.metrics[v].histogram.count = 0 + p.currMF.metrics[v].histogram.buckets = p.currMF.metrics[v].histogram.buckets[:0] + p.currMF.metrics[v].labels = p.currMF.metrics[v].labels[:0] + p.currMF.metrics[v].labels = append(p.currMF.metrics[v].labels, p.currSeries...) + h = p.currMF.metrics[v].histogram + } + + p.histograms[hash] = h + } + + switch { + case p.isBucket: + h.buckets = append(h.buckets, Bucket{upperBound: p.currBucket, cumulativeCount: value}) + case p.isSum: + h.sum = value + case p.isCount: + h.count = value + } +} + +func (p *promTextParser) reset() { + p.currMF = nil + p.currSeries = p.currSeries[:0] + + if p.metrics == nil { + p.metrics = make(MetricFamilies) + } + for _, mf := range p.metrics { + mf.help = "" + mf.typ = "" + mf.metrics = mf.metrics[:0] + } + + if p.summaries == nil { + p.summaries = make(map[uint64]*Summary) + } + for k := range p.summaries { + delete(p.summaries, k) + } + + if p.histograms == nil { + p.histograms = make(map[uint64]*Histogram) + } + for k := range p.histograms { + delete(p.histograms, k) + } +} + +func copyLabels(lbs []labels.Label) []labels.Label { + return append([]labels.Label(nil), lbs...) +} + +func removeLabel(lbs labels.Labels, name string) (labels.Labels, string, bool) { + for i, v := range lbs { + if v.Name == name { + return append(lbs[:i], lbs[i+1:]...), v.Value, true + } + } + return lbs, "", false +} + +func isSummaryOrHistogram(typ model.MetricType) bool { + return typ == model.MetricTypeSummary || typ == model.MetricTypeHistogram +} diff --git a/src/go/collectors/go.d.plugin/pkg/prometheus/parse_test.go b/src/go/collectors/go.d.plugin/pkg/prometheus/parse_test.go new file mode 100644 index 000000000..453011c07 --- /dev/null +++ b/src/go/collectors/go.d.plugin/pkg/prometheus/parse_test.go @@ -0,0 +1,1675 @@ +package prometheus + +import ( + "bytes" + "fmt" + "math" + "os" + "testing" + + "github.com/netdata/netdata/go/go.d.plugin/pkg/prometheus/selector" + + "github.com/prometheus/common/model" + "github.com/prometheus/prometheus/model/labels" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var ( + dataMultilineHelp, _ = os.ReadFile("testdata/multiline-help.txt") + + dataGaugeMeta, _ = os.ReadFile("testdata/gauge-meta.txt") + dataGaugeNoMeta, _ = os.ReadFile("testdata/gauge-no-meta.txt") + dataCounterMeta, _ = os.ReadFile("testdata/counter-meta.txt") + dataCounterNoMeta, _ = os.ReadFile("testdata/counter-no-meta.txt") + dataSummaryMeta, _ = os.ReadFile("testdata/summary-meta.txt") + dataSummaryNoMeta, _ = os.ReadFile("testdata/summary-no-meta.txt") + dataHistogramMeta, _ = os.ReadFile("testdata/histogram-meta.txt") + dataHistogramNoMeta, _ = os.ReadFile("testdata/histogram-no-meta.txt") + dataAllTypes = joinData( + dataGaugeMeta, dataGaugeNoMeta, dataCounterMeta, dataCounterNoMeta, + dataSummaryMeta, dataSummaryNoMeta, dataHistogramMeta, dataHistogramNoMeta, + ) +) + +func Test_testParseDataIsValid(t *testing.T) { + for name, data := range map[string][]byte{ + "dataMultilineHelp": dataMultilineHelp, + "dataGaugeMeta": dataGaugeMeta, + "dataGaugeNoMeta": dataGaugeNoMeta, + "dataCounterMeta": dataCounterMeta, + "dataCounterNoMeta": dataCounterNoMeta, + "dataSummaryMeta": dataSummaryMeta, + "dataSummaryNoMeta": dataSummaryNoMeta, + "dataHistogramMeta": dataHistogramMeta, + "dataHistogramNoMeta": dataHistogramNoMeta, + "dataAllTypes": dataAllTypes, + } { + require.NotNilf(t, data, name) + } +} + +func TestPromTextParser_parseToMetricFamilies(t *testing.T) { + tests := map[string]struct { + input []byte + want MetricFamilies + }{ + "Gauge with multiline HELP": { + input: dataMultilineHelp, + want: MetricFamilies{ + "test_gauge_metric_1": { + name: "test_gauge_metric_1", + help: "First line. Second line.", + typ: model.MetricTypeGauge, + metrics: []Metric{ + { + labels: labels.Labels{{Name: "label1", Value: "value1"}}, + gauge: &Gauge{value: 11}, + }, + }, + }, + }, + }, + "Gauge with meta parsed as Gauge": { + input: dataGaugeMeta, + want: MetricFamilies{ + "test_gauge_metric_1": { + name: "test_gauge_metric_1", + help: "Test Gauge Metric 1", + typ: model.MetricTypeGauge, + metrics: []Metric{ + { + labels: labels.Labels{{Name: "label1", Value: "value1"}}, + gauge: &Gauge{value: 11}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value2"}}, + gauge: &Gauge{value: 12}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value3"}}, + gauge: &Gauge{value: 13}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value4"}}, + gauge: &Gauge{value: 14}, + }, + }, + }, + "test_gauge_metric_2": { + name: "test_gauge_metric_2", + typ: model.MetricTypeGauge, + metrics: []Metric{ + { + labels: labels.Labels{{Name: "label1", Value: "value1"}}, + gauge: &Gauge{value: 11}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value2"}}, + gauge: &Gauge{value: 12}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value3"}}, + gauge: &Gauge{value: 13}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value4"}}, + gauge: &Gauge{value: 14}, + }, + }, + }, + }, + }, + "Counter with meta parsed as Counter": { + input: dataCounterMeta, + want: MetricFamilies{ + "test_counter_metric_1_total": { + name: "test_counter_metric_1_total", + help: "Test Counter Metric 1", + typ: model.MetricTypeCounter, + metrics: []Metric{ + { + labels: labels.Labels{{Name: "label1", Value: "value1"}}, + counter: &Counter{value: 11}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value2"}}, + counter: &Counter{value: 12}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value3"}}, + counter: &Counter{value: 13}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value4"}}, + counter: &Counter{value: 14}, + }, + }, + }, + "test_counter_metric_2_total": { + name: "test_counter_metric_2_total", + typ: model.MetricTypeCounter, + metrics: []Metric{ + { + labels: labels.Labels{{Name: "label1", Value: "value1"}}, + counter: &Counter{value: 11}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value2"}}, + counter: &Counter{value: 12}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value3"}}, + counter: &Counter{value: 13}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value4"}}, + counter: &Counter{value: 14}, + }, + }, + }, + }, + }, + "Summary with meta parsed as Summary": { + input: dataSummaryMeta, + want: MetricFamilies{ + "test_summary_1_duration_microseconds": { + name: "test_summary_1_duration_microseconds", + help: "Test Summary Metric 1", + typ: model.MetricTypeSummary, + metrics: []Metric{ + { + labels: labels.Labels{{Name: "label1", Value: "value1"}}, + summary: &Summary{ + sum: 283201.29, + count: 31, + quantiles: []Quantile{ + {quantile: 0.5, value: 4931.921}, + {quantile: 0.9, value: 4932.921}, + {quantile: 0.99, value: 4933.921}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value2"}}, + summary: &Summary{ + sum: 283201.29, + count: 31, + quantiles: []Quantile{ + {quantile: 0.5, value: 4931.921}, + {quantile: 0.9, value: 4932.921}, + {quantile: 0.99, value: 4933.921}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value3"}}, + summary: &Summary{ + sum: 283201.29, + count: 31, + quantiles: []Quantile{ + {quantile: 0.5, value: 4931.921}, + {quantile: 0.9, value: 4932.921}, + {quantile: 0.99, value: 4933.921}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value4"}}, + summary: &Summary{ + sum: 283201.29, + count: 31, + quantiles: []Quantile{ + {quantile: 0.5, value: 4931.921}, + {quantile: 0.9, value: 4932.921}, + {quantile: 0.99, value: 4933.921}, + }, + }, + }, + }, + }, + "test_summary_2_duration_microseconds": { + name: "test_summary_2_duration_microseconds", + typ: model.MetricTypeSummary, + metrics: []Metric{ + { + labels: labels.Labels{{Name: "label1", Value: "value1"}}, + summary: &Summary{ + sum: 383201.29, + count: 41, + quantiles: []Quantile{ + {quantile: 0.5, value: 5931.921}, + {quantile: 0.9, value: 5932.921}, + {quantile: 0.99, value: 5933.921}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value2"}}, + summary: &Summary{ + sum: 383201.29, + count: 41, + quantiles: []Quantile{ + {quantile: 0.5, value: 5931.921}, + {quantile: 0.9, value: 5932.921}, + {quantile: 0.99, value: 5933.921}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value3"}}, + summary: &Summary{ + sum: 383201.29, + count: 41, + quantiles: []Quantile{ + {quantile: 0.5, value: 5931.921}, + {quantile: 0.9, value: 5932.921}, + {quantile: 0.99, value: 5933.921}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value4"}}, + summary: &Summary{ + sum: 383201.29, + count: 41, + quantiles: []Quantile{ + {quantile: 0.5, value: 5931.921}, + {quantile: 0.9, value: 5932.921}, + {quantile: 0.99, value: 5933.921}, + }, + }, + }, + }, + }, + }, + }, + "Histogram with meta parsed as Histogram": { + input: dataHistogramMeta, + want: MetricFamilies{ + "test_histogram_1_duration_seconds": { + name: "test_histogram_1_duration_seconds", + help: "Test Histogram Metric 1", + typ: model.MetricTypeHistogram, + metrics: []Metric{ + { + labels: labels.Labels{{Name: "label1", Value: "value1"}}, + histogram: &Histogram{ + sum: 0.00147889, + count: 6, + buckets: []Bucket{ + {upperBound: 0.1, cumulativeCount: 4}, + {upperBound: 0.5, cumulativeCount: 5}, + {upperBound: math.Inf(1), cumulativeCount: 6}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value2"}}, + histogram: &Histogram{ + sum: 0.00147889, + count: 6, + buckets: []Bucket{ + {upperBound: 0.1, cumulativeCount: 4}, + {upperBound: 0.5, cumulativeCount: 5}, + {upperBound: math.Inf(1), cumulativeCount: 6}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value3"}}, + histogram: &Histogram{ + sum: 0.00147889, + count: 6, + buckets: []Bucket{ + {upperBound: 0.1, cumulativeCount: 4}, + {upperBound: 0.5, cumulativeCount: 5}, + {upperBound: math.Inf(1), cumulativeCount: 6}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value4"}}, + histogram: &Histogram{ + sum: 0.00147889, + count: 6, + buckets: []Bucket{ + {upperBound: 0.1, cumulativeCount: 4}, + {upperBound: 0.5, cumulativeCount: 5}, + {upperBound: math.Inf(1), cumulativeCount: 6}, + }, + }, + }, + }, + }, + "test_histogram_2_duration_seconds": { + name: "test_histogram_2_duration_seconds", + typ: model.MetricTypeHistogram, + metrics: []Metric{ + { + labels: labels.Labels{{Name: "label1", Value: "value1"}}, + histogram: &Histogram{ + sum: 0.00247889, + count: 9, + buckets: []Bucket{ + {upperBound: 0.1, cumulativeCount: 7}, + {upperBound: 0.5, cumulativeCount: 8}, + {upperBound: math.Inf(1), cumulativeCount: 9}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value2"}}, + histogram: &Histogram{ + sum: 0.00247889, + count: 9, + buckets: []Bucket{ + {upperBound: 0.1, cumulativeCount: 7}, + {upperBound: 0.5, cumulativeCount: 8}, + {upperBound: math.Inf(1), cumulativeCount: 9}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value3"}}, + histogram: &Histogram{ + sum: 0.00247889, + count: 9, + buckets: []Bucket{ + {upperBound: 0.1, cumulativeCount: 7}, + {upperBound: 0.5, cumulativeCount: 8}, + {upperBound: math.Inf(1), cumulativeCount: 9}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value4"}}, + histogram: &Histogram{ + sum: 0.00247889, + count: 9, + buckets: []Bucket{ + {upperBound: 0.1, cumulativeCount: 7}, + {upperBound: 0.5, cumulativeCount: 8}, + {upperBound: math.Inf(1), cumulativeCount: 9}, + }, + }, + }, + }, + }, + }, + }, + "Gauge no meta parsed as Untyped": { + input: dataGaugeNoMeta, + want: MetricFamilies{ + "test_gauge_no_meta_metric_1": { + name: "test_gauge_no_meta_metric_1", + typ: model.MetricTypeUnknown, + metrics: []Metric{ + { + labels: labels.Labels{{Name: "label1", Value: "value1"}}, + untyped: &Untyped{value: 11}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value2"}}, + untyped: &Untyped{value: 12}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value3"}}, + untyped: &Untyped{value: 13}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value4"}}, + untyped: &Untyped{value: 14}, + }, + }, + }, + "test_gauge_no_meta_metric_2": { + name: "test_gauge_no_meta_metric_2", + typ: model.MetricTypeUnknown, + metrics: []Metric{ + { + labels: labels.Labels{{Name: "label1", Value: "value1"}}, + untyped: &Untyped{value: 11}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value2"}}, + untyped: &Untyped{value: 12}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value3"}}, + untyped: &Untyped{value: 13}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value4"}}, + untyped: &Untyped{value: 14}, + }, + }, + }, + }, + }, + "Counter no meta parsed as Untyped": { + input: dataCounterNoMeta, + want: MetricFamilies{ + "test_counter_no_meta_metric_1_total": { + name: "test_counter_no_meta_metric_1_total", + typ: model.MetricTypeUnknown, + metrics: []Metric{ + { + labels: labels.Labels{{Name: "label1", Value: "value1"}}, + untyped: &Untyped{value: 11}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value2"}}, + untyped: &Untyped{value: 12}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value3"}}, + untyped: &Untyped{value: 13}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value4"}}, + untyped: &Untyped{value: 14}, + }, + }, + }, + "test_counter_no_meta_metric_2_total": { + name: "test_counter_no_meta_metric_2_total", + typ: model.MetricTypeUnknown, + metrics: []Metric{ + { + labels: labels.Labels{{Name: "label1", Value: "value1"}}, + untyped: &Untyped{value: 11}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value2"}}, + untyped: &Untyped{value: 12}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value3"}}, + untyped: &Untyped{value: 13}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value4"}}, + untyped: &Untyped{value: 14}, + }, + }, + }, + }, + }, + "Summary no meta parsed as Summary": { + input: dataSummaryNoMeta, + want: MetricFamilies{ + "test_summary_no_meta_1_duration_microseconds": { + name: "test_summary_no_meta_1_duration_microseconds", + typ: model.MetricTypeSummary, + metrics: []Metric{ + { + labels: labels.Labels{{Name: "label1", Value: "value1"}}, + summary: &Summary{ + sum: 283201.29, + count: 31, + quantiles: []Quantile{ + {quantile: 0.5, value: 4931.921}, + {quantile: 0.9, value: 4932.921}, + {quantile: 0.99, value: 4933.921}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value2"}}, + summary: &Summary{ + sum: 283201.29, + count: 31, + quantiles: []Quantile{ + {quantile: 0.5, value: 4931.921}, + {quantile: 0.9, value: 4932.921}, + {quantile: 0.99, value: 4933.921}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value3"}}, + summary: &Summary{ + sum: 283201.29, + count: 31, + quantiles: []Quantile{ + {quantile: 0.5, value: 4931.921}, + {quantile: 0.9, value: 4932.921}, + {quantile: 0.99, value: 4933.921}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value4"}}, + summary: &Summary{ + sum: 283201.29, + count: 31, + quantiles: []Quantile{ + {quantile: 0.5, value: 4931.921}, + {quantile: 0.9, value: 4932.921}, + {quantile: 0.99, value: 4933.921}, + }, + }, + }, + }, + }, + "test_summary_no_meta_2_duration_microseconds": { + name: "test_summary_no_meta_2_duration_microseconds", + typ: model.MetricTypeSummary, + metrics: []Metric{ + { + labels: labels.Labels{{Name: "label1", Value: "value1"}}, + summary: &Summary{ + sum: 383201.29, + count: 41, + quantiles: []Quantile{ + {quantile: 0.5, value: 5931.921}, + {quantile: 0.9, value: 5932.921}, + {quantile: 0.99, value: 5933.921}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value2"}}, + summary: &Summary{ + sum: 383201.29, + count: 41, + quantiles: []Quantile{ + {quantile: 0.5, value: 5931.921}, + {quantile: 0.9, value: 5932.921}, + {quantile: 0.99, value: 5933.921}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value3"}}, + summary: &Summary{ + sum: 383201.29, + count: 41, + quantiles: []Quantile{ + {quantile: 0.5, value: 5931.921}, + {quantile: 0.9, value: 5932.921}, + {quantile: 0.99, value: 5933.921}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value4"}}, + summary: &Summary{ + sum: 383201.29, + count: 41, + quantiles: []Quantile{ + {quantile: 0.5, value: 5931.921}, + {quantile: 0.9, value: 5932.921}, + {quantile: 0.99, value: 5933.921}, + }, + }, + }, + }, + }, + }, + }, + "Histogram no meta parsed as Histogram": { + input: dataHistogramNoMeta, + want: MetricFamilies{ + "test_histogram_no_meta_1_duration_seconds": { + name: "test_histogram_no_meta_1_duration_seconds", + typ: model.MetricTypeHistogram, + metrics: []Metric{ + { + labels: labels.Labels{{Name: "label1", Value: "value1"}}, + histogram: &Histogram{ + sum: 0.00147889, + count: 6, + buckets: []Bucket{ + {upperBound: 0.1, cumulativeCount: 4}, + {upperBound: 0.5, cumulativeCount: 5}, + {upperBound: math.Inf(1), cumulativeCount: 6}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value2"}}, + histogram: &Histogram{ + sum: 0.00147889, + count: 6, + buckets: []Bucket{ + {upperBound: 0.1, cumulativeCount: 4}, + {upperBound: 0.5, cumulativeCount: 5}, + {upperBound: math.Inf(1), cumulativeCount: 6}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value3"}}, + histogram: &Histogram{ + sum: 0.00147889, + count: 6, + buckets: []Bucket{ + {upperBound: 0.1, cumulativeCount: 4}, + {upperBound: 0.5, cumulativeCount: 5}, + {upperBound: math.Inf(1), cumulativeCount: 6}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value4"}}, + histogram: &Histogram{ + sum: 0.00147889, + count: 6, + buckets: []Bucket{ + {upperBound: 0.1, cumulativeCount: 4}, + {upperBound: 0.5, cumulativeCount: 5}, + {upperBound: math.Inf(1), cumulativeCount: 6}, + }, + }, + }, + }, + }, + "test_histogram_no_meta_2_duration_seconds": { + name: "test_histogram_no_meta_2_duration_seconds", + typ: model.MetricTypeHistogram, + metrics: []Metric{ + { + labels: labels.Labels{{Name: "label1", Value: "value1"}}, + histogram: &Histogram{ + sum: 0.00247889, + count: 9, + buckets: []Bucket{ + {upperBound: 0.1, cumulativeCount: 7}, + {upperBound: 0.5, cumulativeCount: 8}, + {upperBound: math.Inf(1), cumulativeCount: 9}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value2"}}, + histogram: &Histogram{ + sum: 0.00247889, + count: 9, + buckets: []Bucket{ + {upperBound: 0.1, cumulativeCount: 7}, + {upperBound: 0.5, cumulativeCount: 8}, + {upperBound: math.Inf(1), cumulativeCount: 9}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value3"}}, + histogram: &Histogram{ + sum: 0.00247889, + count: 9, + buckets: []Bucket{ + {upperBound: 0.1, cumulativeCount: 7}, + {upperBound: 0.5, cumulativeCount: 8}, + {upperBound: math.Inf(1), cumulativeCount: 9}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value4"}}, + histogram: &Histogram{ + sum: 0.00247889, + count: 9, + buckets: []Bucket{ + {upperBound: 0.1, cumulativeCount: 7}, + {upperBound: 0.5, cumulativeCount: 8}, + {upperBound: math.Inf(1), cumulativeCount: 9}, + }, + }, + }, + }, + }, + }, + }, + "All types": { + input: dataAllTypes, + want: MetricFamilies{ + "test_gauge_metric_1": { + name: "test_gauge_metric_1", + help: "Test Gauge Metric 1", + typ: model.MetricTypeGauge, + metrics: []Metric{ + { + labels: labels.Labels{{Name: "label1", Value: "value1"}}, + gauge: &Gauge{value: 11}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value2"}}, + gauge: &Gauge{value: 12}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value3"}}, + gauge: &Gauge{value: 13}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value4"}}, + gauge: &Gauge{value: 14}, + }, + }, + }, + "test_gauge_metric_2": { + name: "test_gauge_metric_2", + typ: model.MetricTypeGauge, + metrics: []Metric{ + { + labels: labels.Labels{{Name: "label1", Value: "value1"}}, + gauge: &Gauge{value: 11}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value2"}}, + gauge: &Gauge{value: 12}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value3"}}, + gauge: &Gauge{value: 13}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value4"}}, + gauge: &Gauge{value: 14}, + }, + }, + }, + "test_counter_metric_1_total": { + name: "test_counter_metric_1_total", + help: "Test Counter Metric 1", + typ: model.MetricTypeCounter, + metrics: []Metric{ + { + labels: labels.Labels{{Name: "label1", Value: "value1"}}, + counter: &Counter{value: 11}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value2"}}, + counter: &Counter{value: 12}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value3"}}, + counter: &Counter{value: 13}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value4"}}, + counter: &Counter{value: 14}, + }, + }, + }, + "test_counter_metric_2_total": { + name: "test_counter_metric_2_total", + typ: model.MetricTypeCounter, + metrics: []Metric{ + { + labels: labels.Labels{{Name: "label1", Value: "value1"}}, + counter: &Counter{value: 11}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value2"}}, + counter: &Counter{value: 12}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value3"}}, + counter: &Counter{value: 13}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value4"}}, + counter: &Counter{value: 14}, + }, + }, + }, + "test_summary_1_duration_microseconds": { + name: "test_summary_1_duration_microseconds", + help: "Test Summary Metric 1", + typ: model.MetricTypeSummary, + metrics: []Metric{ + { + labels: labels.Labels{{Name: "label1", Value: "value1"}}, + summary: &Summary{ + sum: 283201.29, + count: 31, + quantiles: []Quantile{ + {quantile: 0.5, value: 4931.921}, + {quantile: 0.9, value: 4932.921}, + {quantile: 0.99, value: 4933.921}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value2"}}, + summary: &Summary{ + sum: 283201.29, + count: 31, + quantiles: []Quantile{ + {quantile: 0.5, value: 4931.921}, + {quantile: 0.9, value: 4932.921}, + {quantile: 0.99, value: 4933.921}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value3"}}, + summary: &Summary{ + sum: 283201.29, + count: 31, + quantiles: []Quantile{ + {quantile: 0.5, value: 4931.921}, + {quantile: 0.9, value: 4932.921}, + {quantile: 0.99, value: 4933.921}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value4"}}, + summary: &Summary{ + sum: 283201.29, + count: 31, + quantiles: []Quantile{ + {quantile: 0.5, value: 4931.921}, + {quantile: 0.9, value: 4932.921}, + {quantile: 0.99, value: 4933.921}, + }, + }, + }, + }, + }, + "test_summary_2_duration_microseconds": { + name: "test_summary_2_duration_microseconds", + typ: model.MetricTypeSummary, + metrics: []Metric{ + { + labels: labels.Labels{{Name: "label1", Value: "value1"}}, + summary: &Summary{ + sum: 383201.29, + count: 41, + quantiles: []Quantile{ + {quantile: 0.5, value: 5931.921}, + {quantile: 0.9, value: 5932.921}, + {quantile: 0.99, value: 5933.921}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value2"}}, + summary: &Summary{ + sum: 383201.29, + count: 41, + quantiles: []Quantile{ + {quantile: 0.5, value: 5931.921}, + {quantile: 0.9, value: 5932.921}, + {quantile: 0.99, value: 5933.921}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value3"}}, + summary: &Summary{ + sum: 383201.29, + count: 41, + quantiles: []Quantile{ + {quantile: 0.5, value: 5931.921}, + {quantile: 0.9, value: 5932.921}, + {quantile: 0.99, value: 5933.921}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value4"}}, + summary: &Summary{ + sum: 383201.29, + count: 41, + quantiles: []Quantile{ + {quantile: 0.5, value: 5931.921}, + {quantile: 0.9, value: 5932.921}, + {quantile: 0.99, value: 5933.921}, + }, + }, + }, + }, + }, + "test_histogram_1_duration_seconds": { + name: "test_histogram_1_duration_seconds", + help: "Test Histogram Metric 1", + typ: model.MetricTypeHistogram, + metrics: []Metric{ + { + labels: labels.Labels{{Name: "label1", Value: "value1"}}, + histogram: &Histogram{ + sum: 0.00147889, + count: 6, + buckets: []Bucket{ + {upperBound: 0.1, cumulativeCount: 4}, + {upperBound: 0.5, cumulativeCount: 5}, + {upperBound: math.Inf(1), cumulativeCount: 6}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value2"}}, + histogram: &Histogram{ + sum: 0.00147889, + count: 6, + buckets: []Bucket{ + {upperBound: 0.1, cumulativeCount: 4}, + {upperBound: 0.5, cumulativeCount: 5}, + {upperBound: math.Inf(1), cumulativeCount: 6}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value3"}}, + histogram: &Histogram{ + sum: 0.00147889, + count: 6, + buckets: []Bucket{ + {upperBound: 0.1, cumulativeCount: 4}, + {upperBound: 0.5, cumulativeCount: 5}, + {upperBound: math.Inf(1), cumulativeCount: 6}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value4"}}, + histogram: &Histogram{ + sum: 0.00147889, + count: 6, + buckets: []Bucket{ + {upperBound: 0.1, cumulativeCount: 4}, + {upperBound: 0.5, cumulativeCount: 5}, + {upperBound: math.Inf(1), cumulativeCount: 6}, + }, + }, + }, + }, + }, + "test_histogram_2_duration_seconds": { + name: "test_histogram_2_duration_seconds", + typ: model.MetricTypeHistogram, + metrics: []Metric{ + { + labels: labels.Labels{{Name: "label1", Value: "value1"}}, + histogram: &Histogram{ + sum: 0.00247889, + count: 9, + buckets: []Bucket{ + {upperBound: 0.1, cumulativeCount: 7}, + {upperBound: 0.5, cumulativeCount: 8}, + {upperBound: math.Inf(1), cumulativeCount: 9}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value2"}}, + histogram: &Histogram{ + sum: 0.00247889, + count: 9, + buckets: []Bucket{ + {upperBound: 0.1, cumulativeCount: 7}, + {upperBound: 0.5, cumulativeCount: 8}, + {upperBound: math.Inf(1), cumulativeCount: 9}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value3"}}, + histogram: &Histogram{ + sum: 0.00247889, + count: 9, + buckets: []Bucket{ + {upperBound: 0.1, cumulativeCount: 7}, + {upperBound: 0.5, cumulativeCount: 8}, + {upperBound: math.Inf(1), cumulativeCount: 9}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value4"}}, + histogram: &Histogram{ + sum: 0.00247889, + count: 9, + buckets: []Bucket{ + {upperBound: 0.1, cumulativeCount: 7}, + {upperBound: 0.5, cumulativeCount: 8}, + {upperBound: math.Inf(1), cumulativeCount: 9}, + }, + }, + }, + }, + }, + "test_gauge_no_meta_metric_1": { + name: "test_gauge_no_meta_metric_1", + typ: model.MetricTypeUnknown, + metrics: []Metric{ + { + labels: labels.Labels{{Name: "label1", Value: "value1"}}, + untyped: &Untyped{value: 11}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value2"}}, + untyped: &Untyped{value: 12}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value3"}}, + untyped: &Untyped{value: 13}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value4"}}, + untyped: &Untyped{value: 14}, + }, + }, + }, + "test_gauge_no_meta_metric_2": { + name: "test_gauge_no_meta_metric_2", + typ: model.MetricTypeUnknown, + metrics: []Metric{ + { + labels: labels.Labels{{Name: "label1", Value: "value1"}}, + untyped: &Untyped{value: 11}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value2"}}, + untyped: &Untyped{value: 12}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value3"}}, + untyped: &Untyped{value: 13}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value4"}}, + untyped: &Untyped{value: 14}, + }, + }, + }, + "test_counter_no_meta_metric_1_total": { + name: "test_counter_no_meta_metric_1_total", + typ: model.MetricTypeUnknown, + metrics: []Metric{ + { + labels: labels.Labels{{Name: "label1", Value: "value1"}}, + untyped: &Untyped{value: 11}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value2"}}, + untyped: &Untyped{value: 12}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value3"}}, + untyped: &Untyped{value: 13}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value4"}}, + untyped: &Untyped{value: 14}, + }, + }, + }, + "test_counter_no_meta_metric_2_total": { + name: "test_counter_no_meta_metric_2_total", + typ: model.MetricTypeUnknown, + metrics: []Metric{ + { + labels: labels.Labels{{Name: "label1", Value: "value1"}}, + untyped: &Untyped{value: 11}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value2"}}, + untyped: &Untyped{value: 12}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value3"}}, + untyped: &Untyped{value: 13}, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value4"}}, + untyped: &Untyped{value: 14}, + }, + }, + }, + "test_summary_no_meta_1_duration_microseconds": { + name: "test_summary_no_meta_1_duration_microseconds", + typ: model.MetricTypeSummary, + metrics: []Metric{ + { + labels: labels.Labels{{Name: "label1", Value: "value1"}}, + summary: &Summary{ + sum: 283201.29, + count: 31, + quantiles: []Quantile{ + {quantile: 0.5, value: 4931.921}, + {quantile: 0.9, value: 4932.921}, + {quantile: 0.99, value: 4933.921}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value2"}}, + summary: &Summary{ + sum: 283201.29, + count: 31, + quantiles: []Quantile{ + {quantile: 0.5, value: 4931.921}, + {quantile: 0.9, value: 4932.921}, + {quantile: 0.99, value: 4933.921}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value3"}}, + summary: &Summary{ + sum: 283201.29, + count: 31, + quantiles: []Quantile{ + {quantile: 0.5, value: 4931.921}, + {quantile: 0.9, value: 4932.921}, + {quantile: 0.99, value: 4933.921}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value4"}}, + summary: &Summary{ + sum: 283201.29, + count: 31, + quantiles: []Quantile{ + {quantile: 0.5, value: 4931.921}, + {quantile: 0.9, value: 4932.921}, + {quantile: 0.99, value: 4933.921}, + }, + }, + }, + }, + }, + "test_summary_no_meta_2_duration_microseconds": { + name: "test_summary_no_meta_2_duration_microseconds", + typ: model.MetricTypeSummary, + metrics: []Metric{ + { + labels: labels.Labels{{Name: "label1", Value: "value1"}}, + summary: &Summary{ + sum: 383201.29, + count: 41, + quantiles: []Quantile{ + {quantile: 0.5, value: 5931.921}, + {quantile: 0.9, value: 5932.921}, + {quantile: 0.99, value: 5933.921}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value2"}}, + summary: &Summary{ + sum: 383201.29, + count: 41, + quantiles: []Quantile{ + {quantile: 0.5, value: 5931.921}, + {quantile: 0.9, value: 5932.921}, + {quantile: 0.99, value: 5933.921}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value3"}}, + summary: &Summary{ + sum: 383201.29, + count: 41, + quantiles: []Quantile{ + {quantile: 0.5, value: 5931.921}, + {quantile: 0.9, value: 5932.921}, + {quantile: 0.99, value: 5933.921}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value4"}}, + summary: &Summary{ + sum: 383201.29, + count: 41, + quantiles: []Quantile{ + {quantile: 0.5, value: 5931.921}, + {quantile: 0.9, value: 5932.921}, + {quantile: 0.99, value: 5933.921}, + }, + }, + }, + }, + }, + "test_histogram_no_meta_1_duration_seconds": { + name: "test_histogram_no_meta_1_duration_seconds", + typ: model.MetricTypeHistogram, + metrics: []Metric{ + { + labels: labels.Labels{{Name: "label1", Value: "value1"}}, + histogram: &Histogram{ + sum: 0.00147889, + count: 6, + buckets: []Bucket{ + {upperBound: 0.1, cumulativeCount: 4}, + {upperBound: 0.5, cumulativeCount: 5}, + {upperBound: math.Inf(1), cumulativeCount: 6}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value2"}}, + histogram: &Histogram{ + sum: 0.00147889, + count: 6, + buckets: []Bucket{ + {upperBound: 0.1, cumulativeCount: 4}, + {upperBound: 0.5, cumulativeCount: 5}, + {upperBound: math.Inf(1), cumulativeCount: 6}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value3"}}, + histogram: &Histogram{ + sum: 0.00147889, + count: 6, + buckets: []Bucket{ + {upperBound: 0.1, cumulativeCount: 4}, + {upperBound: 0.5, cumulativeCount: 5}, + {upperBound: math.Inf(1), cumulativeCount: 6}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value4"}}, + histogram: &Histogram{ + sum: 0.00147889, + count: 6, + buckets: []Bucket{ + {upperBound: 0.1, cumulativeCount: 4}, + {upperBound: 0.5, cumulativeCount: 5}, + {upperBound: math.Inf(1), cumulativeCount: 6}, + }, + }, + }, + }, + }, + "test_histogram_no_meta_2_duration_seconds": { + name: "test_histogram_no_meta_2_duration_seconds", + typ: model.MetricTypeHistogram, + metrics: []Metric{ + { + labels: labels.Labels{{Name: "label1", Value: "value1"}}, + histogram: &Histogram{ + sum: 0.00247889, + count: 9, + buckets: []Bucket{ + {upperBound: 0.1, cumulativeCount: 7}, + {upperBound: 0.5, cumulativeCount: 8}, + {upperBound: math.Inf(1), cumulativeCount: 9}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value2"}}, + histogram: &Histogram{ + sum: 0.00247889, + count: 9, + buckets: []Bucket{ + {upperBound: 0.1, cumulativeCount: 7}, + {upperBound: 0.5, cumulativeCount: 8}, + {upperBound: math.Inf(1), cumulativeCount: 9}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value3"}}, + histogram: &Histogram{ + sum: 0.00247889, + count: 9, + buckets: []Bucket{ + {upperBound: 0.1, cumulativeCount: 7}, + {upperBound: 0.5, cumulativeCount: 8}, + {upperBound: math.Inf(1), cumulativeCount: 9}, + }, + }, + }, + { + labels: labels.Labels{{Name: "label1", Value: "value4"}}, + histogram: &Histogram{ + sum: 0.00247889, + count: 9, + buckets: []Bucket{ + {upperBound: 0.1, cumulativeCount: 7}, + {upperBound: 0.5, cumulativeCount: 8}, + {upperBound: math.Inf(1), cumulativeCount: 9}, + }, + }, + }, + }, + }, + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + var p promTextParser + + for i := 0; i < 10; i++ { + t.Run(fmt.Sprintf("parse num %d", i+1), func(t *testing.T) { + mfs, err := p.parseToMetricFamilies(test.input) + if len(test.want) > 0 { + assert.Equal(t, test.want, mfs) + } else { + assert.Error(t, err) + } + }) + } + }) + } +} + +func TestPromTextParser_parseToMetricFamiliesWithSelector(t *testing.T) { + sr, err := selector.Parse(`test_gauge_metric_1{label1="value2"}`) + require.NoError(t, err) + + p := promTextParser{sr: sr} + + txt := []byte(` +test_gauge_metric_1{label1="value1"} 1 +test_gauge_metric_1{label1="value2"} 1 +test_gauge_metric_2{label1="value1"} 1 +test_gauge_metric_2{label1="value2"} 1 +`) + + want := MetricFamilies{ + "test_gauge_metric_1": &MetricFamily{ + name: "test_gauge_metric_1", + typ: model.MetricTypeUnknown, + metrics: []Metric{ + {labels: labels.Labels{{Name: "label1", Value: "value2"}}, untyped: &Untyped{value: 1}}, + }, + }, + } + + mfs, err := p.parseToMetricFamilies(txt) + + require.NoError(t, err) + assert.Equal(t, want, mfs) +} + +func TestPromTextParser_parseToSeries(t *testing.T) { + tests := map[string]struct { + input []byte + want Series + }{ + "All types": { + input: []byte(` +# HELP test_gauge_metric_1 Test Gauge Metric 1 +# TYPE test_gauge_metric_1 gauge +test_gauge_metric_1{label1="value1"} 11 +test_gauge_no_meta_metric_1{label1="value1"} 11 +# HELP test_counter_metric_1_total Test Counter Metric 1 +# TYPE test_counter_metric_1_total counter +test_counter_metric_1_total{label1="value1"} 11 +test_counter_no_meta_metric_1_total{label1="value1"} 11 +# HELP test_summary_1_duration_microseconds Test Summary Metric 1 +# TYPE test_summary_1_duration_microseconds summary +test_summary_1_duration_microseconds{label1="value1",quantile="0.5"} 4931.921 +test_summary_1_duration_microseconds{label1="value1",quantile="0.9"} 4932.921 +test_summary_1_duration_microseconds{label1="value1",quantile="0.99"} 4933.921 +test_summary_1_duration_microseconds_sum{label1="value1"} 283201.29 +test_summary_1_duration_microseconds_count{label1="value1"} 31 +test_summary_no_meta_1_duration_microseconds{label1="value1",quantile="0.5"} 4931.921 +test_summary_no_meta_1_duration_microseconds{label1="value1",quantile="0.9"} 4932.921 +test_summary_no_meta_1_duration_microseconds{label1="value1",quantile="0.99"} 4933.921 +test_summary_no_meta_1_duration_microseconds_sum{label1="value1"} 283201.29 +test_summary_no_meta_1_duration_microseconds_count{label1="value1"} 31 +# HELP test_histogram_1_duration_seconds Test Histogram Metric 1 +# TYPE test_histogram_1_duration_seconds histogram +test_histogram_1_duration_seconds_bucket{label1="value1",le="0.1"} 4 +test_histogram_1_duration_seconds_bucket{label1="value1",le="0.5"} 5 +test_histogram_1_duration_seconds_bucket{label1="value1",le="+Inf"} 6 +test_histogram_1_duration_seconds_sum{label1="value1"} 0.00147889 +test_histogram_1_duration_seconds_count{label1="value1"} 6 +test_histogram_no_meta_1_duration_seconds_bucket{label1="value1",le="0.1"} 4 +test_histogram_no_meta_1_duration_seconds_bucket{label1="value1",le="0.5"} 5 +test_histogram_no_meta_1_duration_seconds_bucket{label1="value1",le="+Inf"} 6 +test_histogram_no_meta_1_duration_seconds_sum{label1="value1"} 0.00147889 +test_histogram_no_meta_1_duration_seconds_count{label1="value1"} 6 +`), + want: Series{ + // Gauge + { + Labels: labels.Labels{ + {Name: "__name__", Value: "test_gauge_metric_1"}, + {Name: "label1", Value: "value1"}, + }, + Value: 11, + }, + { + Labels: labels.Labels{ + {Name: "__name__", Value: "test_gauge_no_meta_metric_1"}, + {Name: "label1", Value: "value1"}, + }, + Value: 11, + }, + // Counter + { + Labels: labels.Labels{ + {Name: "__name__", Value: "test_counter_metric_1_total"}, + {Name: "label1", Value: "value1"}, + }, + Value: 11, + }, + { + Labels: labels.Labels{ + {Name: "__name__", Value: "test_counter_no_meta_metric_1_total"}, + {Name: "label1", Value: "value1"}, + }, + Value: 11, + }, + //// Summary + { + Labels: labels.Labels{ + {Name: "__name__", Value: "test_summary_1_duration_microseconds"}, + {Name: "label1", Value: "value1"}, + {Name: "quantile", Value: "0.5"}, + }, + Value: 4931.921, + }, + { + Labels: labels.Labels{ + {Name: "__name__", Value: "test_summary_1_duration_microseconds"}, + {Name: "label1", Value: "value1"}, + {Name: "quantile", Value: "0.9"}, + }, + Value: 4932.921, + }, + { + Labels: labels.Labels{ + {Name: "__name__", Value: "test_summary_1_duration_microseconds"}, + {Name: "label1", Value: "value1"}, + {Name: "quantile", Value: "0.99"}, + }, + Value: 4933.921, + }, + { + Labels: labels.Labels{ + {Name: "__name__", Value: "test_summary_1_duration_microseconds_sum"}, + {Name: "label1", Value: "value1"}, + }, + Value: 283201.29, + }, + { + Labels: labels.Labels{ + {Name: "__name__", Value: "test_summary_1_duration_microseconds_count"}, + {Name: "label1", Value: "value1"}, + }, + Value: 31, + }, + { + Labels: labels.Labels{ + {Name: "__name__", Value: "test_summary_no_meta_1_duration_microseconds"}, + {Name: "label1", Value: "value1"}, + {Name: "quantile", Value: "0.5"}, + }, + Value: 4931.921, + }, + { + Labels: labels.Labels{ + {Name: "__name__", Value: "test_summary_no_meta_1_duration_microseconds"}, + {Name: "label1", Value: "value1"}, + {Name: "quantile", Value: "0.9"}, + }, + Value: 4932.921, + }, + { + Labels: labels.Labels{ + {Name: "__name__", Value: "test_summary_no_meta_1_duration_microseconds"}, + {Name: "label1", Value: "value1"}, + {Name: "quantile", Value: "0.99"}, + }, + Value: 4933.921, + }, + { + Labels: labels.Labels{ + {Name: "__name__", Value: "test_summary_no_meta_1_duration_microseconds_sum"}, + {Name: "label1", Value: "value1"}, + }, + Value: 283201.29, + }, + { + Labels: labels.Labels{ + {Name: "__name__", Value: "test_summary_no_meta_1_duration_microseconds_count"}, + {Name: "label1", Value: "value1"}, + }, + Value: 31, + }, + // Histogram + { + Labels: labels.Labels{ + {Name: "__name__", Value: "test_histogram_1_duration_seconds_bucket"}, + {Name: "label1", Value: "value1"}, + {Name: "le", Value: "0.1"}, + }, + Value: 4, + }, + { + Labels: labels.Labels{ + {Name: "__name__", Value: "test_histogram_1_duration_seconds_bucket"}, + {Name: "label1", Value: "value1"}, + {Name: "le", Value: "0.5"}, + }, + Value: 5, + }, + { + Labels: labels.Labels{ + {Name: "__name__", Value: "test_histogram_1_duration_seconds_bucket"}, + {Name: "label1", Value: "value1"}, + {Name: "le", Value: "+Inf"}, + }, + Value: 6, + }, + { + Labels: labels.Labels{ + {Name: "__name__", Value: "test_histogram_1_duration_seconds_sum"}, + {Name: "label1", Value: "value1"}, + }, + Value: 0.00147889, + }, + { + Labels: labels.Labels{ + {Name: "__name__", Value: "test_histogram_1_duration_seconds_count"}, + {Name: "label1", Value: "value1"}, + }, + Value: 6, + }, + + { + Labels: labels.Labels{ + {Name: "__name__", Value: "test_histogram_no_meta_1_duration_seconds_bucket"}, + {Name: "label1", Value: "value1"}, + {Name: "le", Value: "0.1"}, + }, + Value: 4, + }, + { + Labels: labels.Labels{ + {Name: "__name__", Value: "test_histogram_no_meta_1_duration_seconds_bucket"}, + {Name: "label1", Value: "value1"}, + {Name: "le", Value: "0.5"}, + }, + Value: 5, + }, + { + Labels: labels.Labels{ + {Name: "__name__", Value: "test_histogram_no_meta_1_duration_seconds_bucket"}, + {Name: "label1", Value: "value1"}, + {Name: "le", Value: "+Inf"}, + }, + Value: 6, + }, + { + Labels: labels.Labels{ + {Name: "__name__", Value: "test_histogram_no_meta_1_duration_seconds_sum"}, + {Name: "label1", Value: "value1"}, + }, + Value: 0.00147889, + }, + { + Labels: labels.Labels{ + {Name: "__name__", Value: "test_histogram_no_meta_1_duration_seconds_count"}, + {Name: "label1", Value: "value1"}, + }, + Value: 6, + }, + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + var p promTextParser + + for i := 0; i < 10; i++ { + t.Run(fmt.Sprintf("parse num %d", i+1), func(t *testing.T) { + series, err := p.parseToSeries(test.input) + + if len(test.want) > 0 { + test.want.Sort() + assert.Equal(t, test.want, series) + } else { + assert.Error(t, err) + } + }) + } + }) + } +} + +func TestPromTextParser_parseToSeriesWithSelector(t *testing.T) { + sr, err := selector.Parse(`test_gauge_metric_1{label1="value2"}`) + require.NoError(t, err) + + p := promTextParser{sr: sr} + + txt := []byte(` +test_gauge_metric_1{label1="value1"} 1 +test_gauge_metric_1{label1="value2"} 1 +test_gauge_metric_2{label1="value1"} 1 +test_gauge_metric_2{label1="value2"} 1 +`) + + want := Series{SeriesSample{ + Labels: labels.Labels{ + {Name: "__name__", Value: "test_gauge_metric_1"}, + {Name: "label1", Value: "value2"}, + }, + Value: 1, + }} + + series, err := p.parseToSeries(txt) + + require.NoError(t, err) + assert.Equal(t, want, series) +} + +func joinData(data ...[]byte) []byte { + var buf bytes.Buffer + for _, v := range data { + _, _ = buf.Write(v) + _ = buf.WriteByte('\n') + } + return buf.Bytes() +} diff --git a/src/go/collectors/go.d.plugin/pkg/prometheus/selector/README.md b/src/go/collectors/go.d.plugin/pkg/prometheus/selector/README.md new file mode 100644 index 000000000..75682c38d --- /dev/null +++ b/src/go/collectors/go.d.plugin/pkg/prometheus/selector/README.md @@ -0,0 +1,102 @@ +<!-- +title: "Time series selector" +custom_edit_url: "/src/go/collectors/go.d.plugin/pkg/prometheus/selector/README.md" +sidebar_label: "Time series selector" +learn_status: "Published" +learn_rel_path: "Developers/External plugins/go.d.plugin/Helper Packages" +--> + +# Time series selector + +Selectors allow selecting and filtering of a set of time series. + +## Simple Selector + +In the simplest form you need to specify only a metric name. + +### Syntax + +```cmd + <line> ::= <metric_name_pattern> + <metric_name_pattern> ::= simple pattern +``` + +The metric name pattern syntax is [simple pattern](/src/libnetdata/simple_pattern/README.md). + +### Examples + +This example selects all time series that have the `go_memstats_alloc_bytes` metric name: + +```cmd +go_memstats_alloc_bytes +``` + +This example selects all time series with metric names starts with `go_memstats_`: + +```cmd +go_memstats_* +``` + +This example selects all time series with metric names starts with `go_` except `go_memstats_`: + +```cmd +!go_memstats_* go_* +``` + +## Advanced Selector + +It is possible to filter these time series further by appending a comma separated list of label matchers in curly braces (`{}`). + +### Syntax + +```cmd + <line> ::= [ <metric_name_pattern> ]{ <list_of_selectors> } + <metric_name_pattern> ::= simple pattern + <list_of_selectors> ::= a comma separated list <label_name><op><label_value_pattern> + <label_name> ::= an exact label name + <op> ::= [ '=', '!=', '=~', '!~', '=*', '!*' ] + <label_value_pattern> ::= a label value pattern, depends on <op> +``` + +The metric name pattern syntax is [simple pattern](/src/libnetdata/simple_pattern/README.md). + +Label matching operators: + +- `=`: Match labels that are exactly equal to the provided string. +- `!=`: Match labels that are not equal to the provided string. +- `=~`: Match labels that [regex-match](https://golang.org/pkg/regexp/syntax/) the provided string. +- `!~`: Match labels that do not [regex-match](https://golang.org/pkg/regexp/syntax/) the provided string. +- `=*`: Match labels that [simple-pattern-match](/src/libnetdata/simple_pattern/README.md) the provided string. +- `!*`: Match labels that do not [simple-pattern-match](/src/libnetdata/simple_pattern/README.md) the provided string. + +### Examples + +This example selects all time series that: + +- have the `node_cooling_device_cur_state` metric name and +- label `type` value not equal to `Fan`: + +```cmd +node_cooling_device_cur_state{type!="Fan"} +``` + +This example selects all time series that: + +- have the `node_filesystem_size_bytes` metric name and +- label `device` value is either `/dev/nvme0n1p1` or `/dev/nvme0n1p2` and +- label `fstype` is equal to `ext4` + +```cmd +node_filesystem_size_bytes{device=~"/dev/nvme0n1p1$|/dev/nvme0n1p2$",fstype="ext4"} +``` + +Label matchers can also be applied to metric names by matching against the internal `__name__` label. + +For example, the expression `node_filesystem_size_bytes` is equivalent to `{__name__="node_filesystem_size_bytes"}`. +This allows using all operators (other than `=*`) for metric names matching. + +The following expression selects all metrics that have a name starting with `node_`: + +```cmd +{__name__=*"node_*"} +``` diff --git a/src/go/collectors/go.d.plugin/pkg/prometheus/selector/expr.go b/src/go/collectors/go.d.plugin/pkg/prometheus/selector/expr.go new file mode 100644 index 000000000..6f61cf3a5 --- /dev/null +++ b/src/go/collectors/go.d.plugin/pkg/prometheus/selector/expr.go @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package selector + +import "fmt" + +type Expr struct { + Allow []string `yaml:"allow,omitempty" json:"allow"` + Deny []string `yaml:"deny,omitempty" json:"deny"` +} + +func (e Expr) Empty() bool { + return len(e.Allow) == 0 && len(e.Deny) == 0 + +} + +func (e Expr) Parse() (Selector, error) { + if e.Empty() { + return nil, nil + } + + var srs []Selector + var allow Selector + var deny Selector + + for _, item := range e.Allow { + sr, err := Parse(item) + if err != nil { + return nil, fmt.Errorf("parse selector '%s': %v", item, err) + } + srs = append(srs, sr) + } + + switch len(srs) { + case 0: + allow = trueSelector{} + case 1: + allow = srs[0] + default: + allow = Or(srs[0], srs[1], srs[2:]...) + } + + srs = srs[:0] + for _, item := range e.Deny { + sr, err := Parse(item) + if err != nil { + return nil, fmt.Errorf("parse selector '%s': %v", item, err) + } + srs = append(srs, sr) + } + + switch len(srs) { + case 0: + deny = falseSelector{} + case 1: + deny = srs[0] + default: + deny = Or(srs[0], srs[1], srs[2:]...) + } + + return And(allow, Not(deny)), nil +} diff --git a/src/go/collectors/go.d.plugin/pkg/prometheus/selector/expr_test.go b/src/go/collectors/go.d.plugin/pkg/prometheus/selector/expr_test.go new file mode 100644 index 000000000..598cef9b8 --- /dev/null +++ b/src/go/collectors/go.d.plugin/pkg/prometheus/selector/expr_test.go @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package selector + +import ( + "testing" + + "github.com/prometheus/prometheus/model/labels" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestExpr_Empty(t *testing.T) { + tests := map[string]struct { + expr Expr + expected bool + }{ + "empty: both allow and deny": { + expr: Expr{ + Allow: []string{}, + Deny: []string{}, + }, + expected: true, + }, + "nil: both allow and deny": { + expected: true, + }, + "nil, empty: allow, deny": { + expr: Expr{ + Deny: []string{""}, + }, + expected: false, + }, + "empty, nil: allow, deny": { + expr: Expr{ + Allow: []string{""}, + }, + expected: false, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + if test.expected { + assert.True(t, test.expr.Empty()) + } else { + assert.False(t, test.expr.Empty()) + } + }) + } +} + +func TestExpr_Parse(t *testing.T) { + tests := map[string]struct { + expr Expr + expectedSr Selector + expectedErr bool + }{ + "not set: both allow and deny": { + expr: Expr{}, + }, + "set: both allow and deny": { + expr: Expr{ + Allow: []string{ + "go_memstats_*", + "node_*", + }, + Deny: []string{ + "go_memstats_frees_total", + "node_cooling_*", + }, + }, + expectedSr: andSelector{ + lhs: orSelector{ + lhs: mustSPName("go_memstats_*"), + rhs: mustSPName("node_*"), + }, + rhs: Not(orSelector{ + lhs: mustSPName("go_memstats_frees_total"), + rhs: mustSPName("node_cooling_*"), + }), + }, + }, + "set: only includes": { + expr: Expr{ + Allow: []string{ + "go_memstats_*", + "node_*", + }, + }, + expectedSr: andSelector{ + lhs: orSelector{ + lhs: mustSPName("go_memstats_*"), + rhs: mustSPName("node_*"), + }, + rhs: Not(falseSelector{}), + }, + }, + "set: only excludes": { + expr: Expr{ + Deny: []string{ + "go_memstats_frees_total", + "node_cooling_*", + }, + }, + expectedSr: andSelector{ + lhs: trueSelector{}, + rhs: Not(orSelector{ + lhs: mustSPName("go_memstats_frees_total"), + rhs: mustSPName("node_cooling_*"), + }), + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + m, err := test.expr.Parse() + + if test.expectedErr { + assert.Error(t, err) + } else { + assert.Equal(t, test.expectedSr, m) + } + }) + } +} + +func TestExprSelector_Matches(t *testing.T) { + tests := map[string]struct { + expr Expr + lbs labels.Labels + expectedMatches bool + }{ + "allow matches: single pattern": { + expr: Expr{ + Allow: []string{"go_*"}, + }, + lbs: []labels.Label{{Name: labels.MetricName, Value: "go_memstats_alloc_bytes"}}, + expectedMatches: true, + }, + "allow matches: several patterns": { + expr: Expr{ + Allow: []string{"node_*", "go_*"}, + }, + lbs: []labels.Label{{Name: labels.MetricName, Value: "go_memstats_alloc_bytes"}}, + expectedMatches: true, + }, + "allow not matches": { + expr: Expr{ + Allow: []string{"node_*"}, + }, + lbs: []labels.Label{{Name: labels.MetricName, Value: "go_memstats_alloc_bytes"}}, + expectedMatches: false, + }, + "deny matches: single pattern": { + expr: Expr{ + Deny: []string{"go_*"}, + }, + lbs: []labels.Label{{Name: labels.MetricName, Value: "go_memstats_alloc_bytes"}}, + expectedMatches: false, + }, + "deny matches: several patterns": { + expr: Expr{ + Deny: []string{"node_*", "go_*"}, + }, + lbs: []labels.Label{{Name: labels.MetricName, Value: "go_memstats_alloc_bytes"}}, + expectedMatches: false, + }, + "deny not matches": { + expr: Expr{ + Deny: []string{"node_*"}, + }, + lbs: []labels.Label{{Name: labels.MetricName, Value: "go_memstats_alloc_bytes"}}, + expectedMatches: true, + }, + "allow and deny matches: single pattern": { + expr: Expr{ + Allow: []string{"go_*"}, + Deny: []string{"go_*"}, + }, + lbs: []labels.Label{{Name: labels.MetricName, Value: "go_memstats_alloc_bytes"}}, + expectedMatches: false, + }, + "allow and deny matches: several patterns": { + expr: Expr{ + Allow: []string{"node_*", "go_*"}, + Deny: []string{"node_*", "go_*"}, + }, + lbs: []labels.Label{{Name: labels.MetricName, Value: "go_memstats_alloc_bytes"}}, + expectedMatches: false, + }, + "allow matches and deny not matches": { + expr: Expr{ + Allow: []string{"go_*"}, + Deny: []string{"node_*"}, + }, + lbs: []labels.Label{{Name: labels.MetricName, Value: "go_memstats_alloc_bytes"}}, + expectedMatches: true, + }, + "allow not matches and deny matches": { + expr: Expr{ + Allow: []string{"node_*"}, + Deny: []string{"go_*"}, + }, + lbs: []labels.Label{{Name: labels.MetricName, Value: "go_memstats_alloc_bytes"}}, + expectedMatches: false, + }, + "allow not matches and deny not matches": { + expr: Expr{ + Allow: []string{"node_*"}, + Deny: []string{"node_*"}, + }, + lbs: []labels.Label{{Name: labels.MetricName, Value: "go_memstats_alloc_bytes"}}, + expectedMatches: false, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + sr, err := test.expr.Parse() + require.NoError(t, err) + + if test.expectedMatches { + assert.True(t, sr.Matches(test.lbs)) + } else { + assert.False(t, sr.Matches(test.lbs)) + } + }) + } +} diff --git a/src/go/collectors/go.d.plugin/pkg/prometheus/selector/logical.go b/src/go/collectors/go.d.plugin/pkg/prometheus/selector/logical.go new file mode 100644 index 000000000..1556d1715 --- /dev/null +++ b/src/go/collectors/go.d.plugin/pkg/prometheus/selector/logical.go @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package selector + +import ( + "github.com/prometheus/prometheus/model/labels" +) + +type ( + trueSelector struct{} + falseSelector struct{} + negSelector struct{ s Selector } + andSelector struct{ lhs, rhs Selector } + orSelector struct{ lhs, rhs Selector } +) + +func (trueSelector) Matches(_ labels.Labels) bool { return true } +func (falseSelector) Matches(_ labels.Labels) bool { return false } +func (s negSelector) Matches(lbs labels.Labels) bool { return !s.s.Matches(lbs) } +func (s andSelector) Matches(lbs labels.Labels) bool { return s.lhs.Matches(lbs) && s.rhs.Matches(lbs) } +func (s orSelector) Matches(lbs labels.Labels) bool { return s.lhs.Matches(lbs) || s.rhs.Matches(lbs) } + +// True returns a selector which always returns true +func True() Selector { + return trueSelector{} +} + +// And returns a selector which returns true only if all of it's sub-selectors return true +func And(lhs, rhs Selector, others ...Selector) Selector { + s := andSelector{lhs: lhs, rhs: rhs} + if len(others) == 0 { + return s + } + return And(s, others[0], others[1:]...) +} + +// Or returns a selector which returns true if any of it's sub-selectors return true +func Or(lhs, rhs Selector, others ...Selector) Selector { + s := orSelector{lhs: lhs, rhs: rhs} + if len(others) == 0 { + return s + } + return Or(s, others[0], others[1:]...) +} + +// Not returns a selector which returns the negation of the sub-selector's result +func Not(s Selector) Selector { + return negSelector{s} +} diff --git a/src/go/collectors/go.d.plugin/pkg/prometheus/selector/logical_test.go b/src/go/collectors/go.d.plugin/pkg/prometheus/selector/logical_test.go new file mode 100644 index 000000000..239c7f715 --- /dev/null +++ b/src/go/collectors/go.d.plugin/pkg/prometheus/selector/logical_test.go @@ -0,0 +1,226 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package selector + +import ( + "testing" + + "github.com/prometheus/prometheus/model/labels" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestTrueSelector_Matches(t *testing.T) { + tests := map[string]struct { + sr trueSelector + lbs labels.Labels + expected bool + }{ + "not empty labels": { + lbs: labels.Labels{{Name: labels.MetricName, Value: "name"}}, + expected: true, + }, + "empty labels": { + expected: true, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + if test.expected { + assert.True(t, test.sr.Matches(test.lbs)) + } else { + assert.False(t, test.sr.Matches(test.lbs)) + } + }) + } +} + +func TestFalseSelector_Matches(t *testing.T) { + tests := map[string]struct { + sr falseSelector + lbs labels.Labels + expected bool + }{ + "not empty labels": { + lbs: labels.Labels{{Name: labels.MetricName, Value: "name"}}, + expected: false, + }, + "empty labels": { + expected: false, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + if test.expected { + assert.True(t, test.sr.Matches(test.lbs)) + } else { + assert.False(t, test.sr.Matches(test.lbs)) + } + }) + } +} + +func TestNegSelector_Matches(t *testing.T) { + tests := map[string]struct { + sr negSelector + lbs labels.Labels + expected bool + }{ + "true matcher": { + sr: negSelector{trueSelector{}}, + lbs: labels.Labels{{Name: labels.MetricName, Value: "name"}}, + expected: false, + }, + "false matcher": { + sr: negSelector{falseSelector{}}, + lbs: labels.Labels{{Name: labels.MetricName, Value: "name"}}, + expected: true, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + if test.expected { + assert.True(t, test.sr.Matches(test.lbs)) + } else { + assert.False(t, test.sr.Matches(test.lbs)) + } + }) + } +} + +func TestAndSelector_Matches(t *testing.T) { + tests := map[string]struct { + sr andSelector + lbs labels.Labels + expected bool + }{ + "true, true": { + sr: andSelector{lhs: trueSelector{}, rhs: trueSelector{}}, + expected: true, + }, + "true, false": { + sr: andSelector{lhs: trueSelector{}, rhs: falseSelector{}}, + expected: false, + }, + "false, true": { + sr: andSelector{lhs: trueSelector{}, rhs: falseSelector{}}, + expected: false, + }, + "false, false": { + sr: andSelector{lhs: falseSelector{}, rhs: falseSelector{}}, + expected: false, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + assert.Equal(t, test.expected, test.sr.Matches(test.lbs)) + }) + } +} + +func TestOrSelector_Matches(t *testing.T) { + tests := map[string]struct { + sr orSelector + lbs labels.Labels + expected bool + }{ + "true, true": { + sr: orSelector{lhs: trueSelector{}, rhs: trueSelector{}}, + expected: true, + }, + "true, false": { + sr: orSelector{lhs: trueSelector{}, rhs: falseSelector{}}, + expected: true, + }, + "false, true": { + sr: orSelector{lhs: trueSelector{}, rhs: falseSelector{}}, + expected: true, + }, + "false, false": { + sr: orSelector{lhs: falseSelector{}, rhs: falseSelector{}}, + expected: false, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + assert.Equal(t, test.expected, test.sr.Matches(test.lbs)) + }) + } +} + +func Test_And(t *testing.T) { + tests := map[string]struct { + srs []Selector + expected Selector + }{ + "2 selectors": { + srs: []Selector{trueSelector{}, trueSelector{}}, + expected: andSelector{ + lhs: trueSelector{}, + rhs: trueSelector{}, + }, + }, + "4 selectors": { + srs: []Selector{trueSelector{}, trueSelector{}, trueSelector{}, trueSelector{}}, + expected: andSelector{ + lhs: andSelector{ + lhs: andSelector{ + lhs: trueSelector{}, + rhs: trueSelector{}, + }, + rhs: trueSelector{}, + }, + rhs: trueSelector{}}, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + require.GreaterOrEqual(t, len(test.srs), 2) + + s := And(test.srs[0], test.srs[1], test.srs[2:]...) + assert.Equal(t, test.expected, s) + }) + } +} + +func Test_Or(t *testing.T) { + tests := map[string]struct { + srs []Selector + expected Selector + }{ + "2 selectors": { + srs: []Selector{trueSelector{}, trueSelector{}}, + expected: orSelector{ + lhs: trueSelector{}, + rhs: trueSelector{}, + }, + }, + "4 selectors": { + srs: []Selector{trueSelector{}, trueSelector{}, trueSelector{}, trueSelector{}}, + expected: orSelector{ + lhs: orSelector{ + lhs: orSelector{ + lhs: trueSelector{}, + rhs: trueSelector{}, + }, + rhs: trueSelector{}, + }, + rhs: trueSelector{}}, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + require.GreaterOrEqual(t, len(test.srs), 2) + + s := Or(test.srs[0], test.srs[1], test.srs[2:]...) + assert.Equal(t, test.expected, s) + }) + } +} diff --git a/src/go/collectors/go.d.plugin/pkg/prometheus/selector/parse.go b/src/go/collectors/go.d.plugin/pkg/prometheus/selector/parse.go new file mode 100644 index 000000000..29c1d4fbf --- /dev/null +++ b/src/go/collectors/go.d.plugin/pkg/prometheus/selector/parse.go @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package selector + +import ( + "fmt" + "regexp" + "strings" + + "github.com/netdata/netdata/go/go.d.plugin/pkg/matcher" +) + +var ( + reLV = regexp.MustCompile(`^(?P<label_name>[a-zA-Z0-9_]+)(?P<op>=~|!~|=\*|!\*|=|!=)"(?P<pattern>.+)"$`) +) + +func Parse(expr string) (Selector, error) { + var srs []Selector + lvs := strings.Split(unsugarExpr(expr), ",") + + for _, lv := range lvs { + sr, err := parseSelector(lv) + if err != nil { + return nil, err + } + srs = append(srs, sr) + } + + switch len(srs) { + case 0: + return nil, nil + case 1: + return srs[0], nil + default: + return And(srs[0], srs[1], srs[2:]...), nil + } +} + +func parseSelector(line string) (Selector, error) { + sub := reLV.FindStringSubmatch(strings.TrimSpace(line)) + if sub == nil { + return nil, fmt.Errorf("invalid selector syntax: '%s'", line) + } + + name, op, pattern := sub[1], sub[2], strings.Trim(sub[3], "\"") + + var m matcher.Matcher + var err error + + switch op { + case OpEqual, OpNegEqual: + m, err = matcher.NewStringMatcher(pattern, true, true) + case OpRegexp, OpNegRegexp: + m, err = matcher.NewRegExpMatcher(pattern) + case OpSimplePatterns, OpNegSimplePatterns: + m, err = matcher.NewSimplePatternsMatcher(pattern) + default: + err = fmt.Errorf("unknown matching operator: %s", op) + } + if err != nil { + return nil, err + } + + sr := labelSelector{ + name: name, + m: m, + } + + if neg := strings.HasPrefix(op, "!"); neg { + return Not(sr), nil + } + return sr, nil +} + +func unsugarExpr(expr string) string { + // name => __name__=*"name" + // name{label="value"} => __name__=*"name",label="value" + // {label="value"} => label="value" + expr = strings.TrimSpace(expr) + + switch idx := strings.IndexByte(expr, '{'); true { + case idx == -1: + expr = fmt.Sprintf(`__name__%s"%s"`, + OpSimplePatterns, + strings.TrimSpace(expr), + ) + case idx == 0: + expr = strings.Trim(expr, "{}") + default: + expr = fmt.Sprintf(`__name__%s"%s",%s`, + OpSimplePatterns, + strings.TrimSpace(expr[:idx]), + strings.Trim(expr[idx:], "{}"), + ) + } + return expr +} diff --git a/src/go/collectors/go.d.plugin/pkg/prometheus/selector/parse_test.go b/src/go/collectors/go.d.plugin/pkg/prometheus/selector/parse_test.go new file mode 100644 index 000000000..ba764e039 --- /dev/null +++ b/src/go/collectors/go.d.plugin/pkg/prometheus/selector/parse_test.go @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package selector + +import ( + "fmt" + "testing" + + "github.com/netdata/netdata/go/go.d.plugin/pkg/matcher" + + "github.com/prometheus/prometheus/model/labels" + "github.com/stretchr/testify/assert" +) + +func TestParse(t *testing.T) { + tests := map[string]struct { + input string + expectedSr Selector + expectedErr bool + }{ + "sp op: only metric name": { + input: "go_memstats_alloc_bytes !go_memstats_* *", + expectedSr: mustSPName("go_memstats_alloc_bytes !go_memstats_* *"), + }, + "string op: metric name with labels": { + input: fmt.Sprintf(`go_memstats_*{label%s"value"}`, OpEqual), + expectedSr: andSelector{ + lhs: mustSPName("go_memstats_*"), + rhs: mustString("label", "value"), + }, + }, + "neg string op: metric name with labels": { + input: fmt.Sprintf(`go_memstats_*{label%s"value"}`, OpNegEqual), + expectedSr: andSelector{ + lhs: mustSPName("go_memstats_*"), + rhs: Not(mustString("label", "value")), + }, + }, + "regexp op: metric name with labels": { + input: fmt.Sprintf(`go_memstats_*{label%s"valu.+"}`, OpRegexp), + expectedSr: andSelector{ + lhs: mustSPName("go_memstats_*"), + rhs: mustRegexp("label", "valu.+"), + }, + }, + "neg regexp op: metric name with labels": { + input: fmt.Sprintf(`go_memstats_*{label%s"valu.+"}`, OpNegRegexp), + expectedSr: andSelector{ + lhs: mustSPName("go_memstats_*"), + rhs: Not(mustRegexp("label", "valu.+")), + }, + }, + "sp op: metric name with labels": { + input: fmt.Sprintf(`go_memstats_*{label%s"valu*"}`, OpSimplePatterns), + expectedSr: andSelector{ + lhs: mustSPName("go_memstats_*"), + rhs: mustSP("label", "valu*"), + }, + }, + "neg sp op: metric name with labels": { + input: fmt.Sprintf(`go_memstats_*{label%s"valu*"}`, OpNegSimplePatterns), + expectedSr: andSelector{ + lhs: mustSPName("go_memstats_*"), + rhs: Not(mustSP("label", "valu*")), + }, + }, + "metric name with several labels": { + input: fmt.Sprintf(`go_memstats_*{label1%s"value1",label2%s"value2"}`, OpEqual, OpEqual), + expectedSr: andSelector{ + lhs: andSelector{ + lhs: mustSPName("go_memstats_*"), + rhs: mustString("label1", "value1"), + }, + rhs: mustString("label2", "value2"), + }, + }, + "only labels (unsugar)": { + input: fmt.Sprintf(`{__name__%s"go_memstats_*",label1%s"value1",label2%s"value2"}`, + OpSimplePatterns, OpEqual, OpEqual), + expectedSr: andSelector{ + lhs: andSelector{ + lhs: mustSPName("go_memstats_*"), + rhs: mustString("label1", "value1"), + }, + rhs: mustString("label2", "value2"), + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + sr, err := Parse(test.input) + + if test.expectedErr { + assert.Error(t, err) + } else { + assert.Equal(t, test.expectedSr, sr) + } + }) + } +} + +func mustSPName(pattern string) Selector { + return mustSP(labels.MetricName, pattern) +} + +func mustString(name string, pattern string) Selector { + return labelSelector{name: name, m: matcher.Must(matcher.NewStringMatcher(pattern, true, true))} +} + +func mustRegexp(name string, pattern string) Selector { + return labelSelector{name: name, m: matcher.Must(matcher.NewRegExpMatcher(pattern))} +} + +func mustSP(name string, pattern string) Selector { + return labelSelector{name: name, m: matcher.Must(matcher.NewSimplePatternsMatcher(pattern))} +} diff --git a/src/go/collectors/go.d.plugin/pkg/prometheus/selector/selector.go b/src/go/collectors/go.d.plugin/pkg/prometheus/selector/selector.go new file mode 100644 index 000000000..28203fca1 --- /dev/null +++ b/src/go/collectors/go.d.plugin/pkg/prometheus/selector/selector.go @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package selector + +import ( + "github.com/netdata/netdata/go/go.d.plugin/pkg/matcher" + + "github.com/prometheus/prometheus/model/labels" +) + +type Selector interface { + Matches(lbs labels.Labels) bool +} + +const ( + OpEqual = "=" + OpNegEqual = "!=" + OpRegexp = "=~" + OpNegRegexp = "!~" + OpSimplePatterns = "=*" + OpNegSimplePatterns = "!*" +) + +type labelSelector struct { + name string + m matcher.Matcher +} + +func (s labelSelector) Matches(lbs labels.Labels) bool { + if s.name == labels.MetricName { + return s.m.MatchString(lbs[0].Value) + } + if label, ok := lookupLabel(s.name, lbs[1:]); ok { + return s.m.MatchString(label.Value) + } + return false +} + +type Func func(lbs labels.Labels) bool + +func (fn Func) Matches(lbs labels.Labels) bool { + return fn(lbs) +} + +func lookupLabel(name string, lbs labels.Labels) (labels.Label, bool) { + for _, label := range lbs { + if label.Name == name { + return label, true + } + } + return labels.Label{}, false +} diff --git a/src/go/collectors/go.d.plugin/pkg/prometheus/selector/selector_test.go b/src/go/collectors/go.d.plugin/pkg/prometheus/selector/selector_test.go new file mode 100644 index 000000000..aa3110b03 --- /dev/null +++ b/src/go/collectors/go.d.plugin/pkg/prometheus/selector/selector_test.go @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package selector + +import ( + "testing" +) + +func TestLabelMatcher_Matches(t *testing.T) { + +} diff --git a/src/go/collectors/go.d.plugin/pkg/prometheus/testdata/counter-meta.txt b/src/go/collectors/go.d.plugin/pkg/prometheus/testdata/counter-meta.txt new file mode 100644 index 000000000..53eccda63 --- /dev/null +++ b/src/go/collectors/go.d.plugin/pkg/prometheus/testdata/counter-meta.txt @@ -0,0 +1,11 @@ +# HELP test_counter_metric_1_total Test Counter Metric 1 +# TYPE test_counter_metric_1_total counter +test_counter_metric_1_total{label1="value1"} 11 +test_counter_metric_1_total{label1="value2"} 12 +test_counter_metric_1_total{label1="value3"} 13 +test_counter_metric_1_total{label1="value4"} 14 +# TYPE test_counter_metric_2_total counter +test_counter_metric_2_total{label1="value1"} 11 +test_counter_metric_2_total{label1="value2"} 12 +test_counter_metric_2_total{label1="value3"} 13 +test_counter_metric_2_total{label1="value4"} 14 diff --git a/src/go/collectors/go.d.plugin/pkg/prometheus/testdata/counter-no-meta.txt b/src/go/collectors/go.d.plugin/pkg/prometheus/testdata/counter-no-meta.txt new file mode 100644 index 000000000..afb11b9b8 --- /dev/null +++ b/src/go/collectors/go.d.plugin/pkg/prometheus/testdata/counter-no-meta.txt @@ -0,0 +1,8 @@ +test_counter_no_meta_metric_1_total{label1="value1"} 11 +test_counter_no_meta_metric_1_total{label1="value2"} 12 +test_counter_no_meta_metric_1_total{label1="value3"} 13 +test_counter_no_meta_metric_1_total{label1="value4"} 14 +test_counter_no_meta_metric_2_total{label1="value1"} 11 +test_counter_no_meta_metric_2_total{label1="value2"} 12 +test_counter_no_meta_metric_2_total{label1="value3"} 13 +test_counter_no_meta_metric_2_total{label1="value4"} 14 diff --git a/src/go/collectors/go.d.plugin/pkg/prometheus/testdata/gauge-meta.txt b/src/go/collectors/go.d.plugin/pkg/prometheus/testdata/gauge-meta.txt new file mode 100644 index 000000000..c0773a426 --- /dev/null +++ b/src/go/collectors/go.d.plugin/pkg/prometheus/testdata/gauge-meta.txt @@ -0,0 +1,11 @@ +# HELP test_gauge_metric_1 Test Gauge Metric 1 +# TYPE test_gauge_metric_1 gauge +test_gauge_metric_1{label1="value1"} 11 +test_gauge_metric_1{label1="value2"} 12 +test_gauge_metric_1{label1="value3"} 13 +test_gauge_metric_1{label1="value4"} 14 +# TYPE test_gauge_metric_2 gauge +test_gauge_metric_2{label1="value1"} 11 +test_gauge_metric_2{label1="value2"} 12 +test_gauge_metric_2{label1="value3"} 13 +test_gauge_metric_2{label1="value4"} 14 diff --git a/src/go/collectors/go.d.plugin/pkg/prometheus/testdata/gauge-no-meta.txt b/src/go/collectors/go.d.plugin/pkg/prometheus/testdata/gauge-no-meta.txt new file mode 100644 index 000000000..e89e0e4d9 --- /dev/null +++ b/src/go/collectors/go.d.plugin/pkg/prometheus/testdata/gauge-no-meta.txt @@ -0,0 +1,8 @@ +test_gauge_no_meta_metric_1{label1="value1"} 11 +test_gauge_no_meta_metric_1{label1="value2"} 12 +test_gauge_no_meta_metric_1{label1="value3"} 13 +test_gauge_no_meta_metric_1{label1="value4"} 14 +test_gauge_no_meta_metric_2{label1="value1"} 11 +test_gauge_no_meta_metric_2{label1="value2"} 12 +test_gauge_no_meta_metric_2{label1="value3"} 13 +test_gauge_no_meta_metric_2{label1="value4"} 14 diff --git a/src/go/collectors/go.d.plugin/pkg/prometheus/testdata/histogram-meta.txt b/src/go/collectors/go.d.plugin/pkg/prometheus/testdata/histogram-meta.txt new file mode 100644 index 000000000..9b4b8a965 --- /dev/null +++ b/src/go/collectors/go.d.plugin/pkg/prometheus/testdata/histogram-meta.txt @@ -0,0 +1,43 @@ +# HELP test_histogram_1_duration_seconds Test Histogram Metric 1 +# TYPE test_histogram_1_duration_seconds histogram +test_histogram_1_duration_seconds_bucket{label1="value1",le="0.1"} 4 +test_histogram_1_duration_seconds_bucket{label1="value1",le="0.5"} 5 +test_histogram_1_duration_seconds_bucket{label1="value1",le="+Inf"} 6 +test_histogram_1_duration_seconds_sum{label1="value1"} 0.00147889 +test_histogram_1_duration_seconds_count{label1="value1"} 6 +test_histogram_1_duration_seconds_bucket{label1="value2",le="0.1"} 4 +test_histogram_1_duration_seconds_bucket{label1="value2",le="0.5"} 5 +test_histogram_1_duration_seconds_bucket{label1="value2",le="+Inf"} 6 +test_histogram_1_duration_seconds_sum{label1="value2"} 0.00147889 +test_histogram_1_duration_seconds_count{label1="value2"} 6 +test_histogram_1_duration_seconds_bucket{label1="value3",le="0.1"} 4 +test_histogram_1_duration_seconds_bucket{label1="value3",le="0.5"} 5 +test_histogram_1_duration_seconds_bucket{label1="value3",le="+Inf"} 6 +test_histogram_1_duration_seconds_sum{label1="value3"} 0.00147889 +test_histogram_1_duration_seconds_count{label1="value3"} 6 +test_histogram_1_duration_seconds_bucket{label1="value4",le="0.1"} 4 +test_histogram_1_duration_seconds_bucket{label1="value4",le="0.5"} 5 +test_histogram_1_duration_seconds_bucket{label1="value4",le="+Inf"} 6 +test_histogram_1_duration_seconds_sum{label1="value4"} 0.00147889 +test_histogram_1_duration_seconds_count{label1="value4"} 6 +# TYPE test_histogram_2_duration_seconds histogram +test_histogram_2_duration_seconds_bucket{label1="value1",le="0.1"} 7 +test_histogram_2_duration_seconds_bucket{label1="value1",le="0.5"} 8 +test_histogram_2_duration_seconds_bucket{label1="value1",le="+Inf"} 9 +test_histogram_2_duration_seconds_sum{label1="value1"} 0.00247889 +test_histogram_2_duration_seconds_count{label1="value1"} 9 +test_histogram_2_duration_seconds_bucket{label1="value2",le="0.1"} 7 +test_histogram_2_duration_seconds_bucket{label1="value2",le="0.5"} 8 +test_histogram_2_duration_seconds_bucket{label1="value2",le="+Inf"} 9 +test_histogram_2_duration_seconds_sum{label1="value2"} 0.00247889 +test_histogram_2_duration_seconds_count{label1="value2"} 9 +test_histogram_2_duration_seconds_bucket{label1="value3",le="0.1"} 7 +test_histogram_2_duration_seconds_bucket{label1="value3",le="0.5"} 8 +test_histogram_2_duration_seconds_bucket{label1="value3",le="+Inf"} 9 +test_histogram_2_duration_seconds_sum{label1="value3"} 0.00247889 +test_histogram_2_duration_seconds_count{label1="value3"} 9 +test_histogram_2_duration_seconds_bucket{label1="value4",le="0.1"} 7 +test_histogram_2_duration_seconds_bucket{label1="value4",le="0.5"} 8 +test_histogram_2_duration_seconds_bucket{label1="value4",le="+Inf"} 9 +test_histogram_2_duration_seconds_sum{label1="value4"} 0.00247889 +test_histogram_2_duration_seconds_count{label1="value4"} 9 diff --git a/src/go/collectors/go.d.plugin/pkg/prometheus/testdata/histogram-no-meta.txt b/src/go/collectors/go.d.plugin/pkg/prometheus/testdata/histogram-no-meta.txt new file mode 100644 index 000000000..49def677c --- /dev/null +++ b/src/go/collectors/go.d.plugin/pkg/prometheus/testdata/histogram-no-meta.txt @@ -0,0 +1,40 @@ +test_histogram_no_meta_1_duration_seconds_bucket{label1="value1",le="0.1"} 4 +test_histogram_no_meta_1_duration_seconds_bucket{label1="value1",le="0.5"} 5 +test_histogram_no_meta_1_duration_seconds_bucket{label1="value1",le="+Inf"} 6 +test_histogram_no_meta_1_duration_seconds_sum{label1="value1"} 0.00147889 +test_histogram_no_meta_1_duration_seconds_count{label1="value1"} 6 +test_histogram_no_meta_1_duration_seconds_bucket{label1="value2",le="0.1"} 4 +test_histogram_no_meta_1_duration_seconds_bucket{label1="value2",le="0.5"} 5 +test_histogram_no_meta_1_duration_seconds_bucket{label1="value2",le="+Inf"} 6 +test_histogram_no_meta_1_duration_seconds_sum{label1="value2"} 0.00147889 +test_histogram_no_meta_1_duration_seconds_count{label1="value2"} 6 +test_histogram_no_meta_1_duration_seconds_bucket{label1="value3",le="0.1"} 4 +test_histogram_no_meta_1_duration_seconds_bucket{label1="value3",le="0.5"} 5 +test_histogram_no_meta_1_duration_seconds_bucket{label1="value3",le="+Inf"} 6 +test_histogram_no_meta_1_duration_seconds_sum{label1="value3"} 0.00147889 +test_histogram_no_meta_1_duration_seconds_count{label1="value3"} 6 +test_histogram_no_meta_1_duration_seconds_bucket{label1="value4",le="0.1"} 4 +test_histogram_no_meta_1_duration_seconds_bucket{label1="value4",le="0.5"} 5 +test_histogram_no_meta_1_duration_seconds_bucket{label1="value4",le="+Inf"} 6 +test_histogram_no_meta_1_duration_seconds_sum{label1="value4"} 0.00147889 +test_histogram_no_meta_1_duration_seconds_count{label1="value4"} 6 +test_histogram_no_meta_2_duration_seconds_bucket{label1="value1",le="0.1"} 7 +test_histogram_no_meta_2_duration_seconds_bucket{label1="value1",le="0.5"} 8 +test_histogram_no_meta_2_duration_seconds_bucket{label1="value1",le="+Inf"} 9 +test_histogram_no_meta_2_duration_seconds_sum{label1="value1"} 0.00247889 +test_histogram_no_meta_2_duration_seconds_count{label1="value1"} 9 +test_histogram_no_meta_2_duration_seconds_bucket{label1="value2",le="0.1"} 7 +test_histogram_no_meta_2_duration_seconds_bucket{label1="value2",le="0.5"} 8 +test_histogram_no_meta_2_duration_seconds_bucket{label1="value2",le="+Inf"} 9 +test_histogram_no_meta_2_duration_seconds_sum{label1="value2"} 0.00247889 +test_histogram_no_meta_2_duration_seconds_count{label1="value2"} 9 +test_histogram_no_meta_2_duration_seconds_bucket{label1="value3",le="0.1"} 7 +test_histogram_no_meta_2_duration_seconds_bucket{label1="value3",le="0.5"} 8 +test_histogram_no_meta_2_duration_seconds_bucket{label1="value3",le="+Inf"} 9 +test_histogram_no_meta_2_duration_seconds_sum{label1="value3"} 0.00247889 +test_histogram_no_meta_2_duration_seconds_count{label1="value3"} 9 +test_histogram_no_meta_2_duration_seconds_bucket{label1="value4",le="0.1"} 7 +test_histogram_no_meta_2_duration_seconds_bucket{label1="value4",le="0.5"} 8 +test_histogram_no_meta_2_duration_seconds_bucket{label1="value4",le="+Inf"} 9 +test_histogram_no_meta_2_duration_seconds_sum{label1="value4"} 0.00247889 +test_histogram_no_meta_2_duration_seconds_count{label1="value4"} 9 diff --git a/src/go/collectors/go.d.plugin/pkg/prometheus/testdata/multiline-help.txt b/src/go/collectors/go.d.plugin/pkg/prometheus/testdata/multiline-help.txt new file mode 100644 index 000000000..f1598fcce --- /dev/null +++ b/src/go/collectors/go.d.plugin/pkg/prometheus/testdata/multiline-help.txt @@ -0,0 +1,3 @@ +# HELP test_gauge_metric_1 \n First line.\n Second line.\n +# TYPE test_gauge_metric_1 gauge +test_gauge_metric_1{label1="value1"} 11 diff --git a/src/go/collectors/go.d.plugin/pkg/prometheus/testdata/summary-meta.txt b/src/go/collectors/go.d.plugin/pkg/prometheus/testdata/summary-meta.txt new file mode 100644 index 000000000..3056e8076 --- /dev/null +++ b/src/go/collectors/go.d.plugin/pkg/prometheus/testdata/summary-meta.txt @@ -0,0 +1,43 @@ +# HELP test_summary_1_duration_microseconds Test Summary Metric 1 +# TYPE test_summary_1_duration_microseconds summary +test_summary_1_duration_microseconds{label1="value1",quantile="0.5"} 4931.921 +test_summary_1_duration_microseconds{label1="value1",quantile="0.9"} 4932.921 +test_summary_1_duration_microseconds{label1="value1",quantile="0.99"} 4933.921 +test_summary_1_duration_microseconds_sum{label1="value1"} 283201.29 +test_summary_1_duration_microseconds_count{label1="value1"} 31 +test_summary_1_duration_microseconds{label1="value2",quantile="0.5"} 4931.921 +test_summary_1_duration_microseconds{label1="value2",quantile="0.9"} 4932.921 +test_summary_1_duration_microseconds{label1="value2",quantile="0.99"} 4933.921 +test_summary_1_duration_microseconds_sum{label1="value2"} 283201.29 +test_summary_1_duration_microseconds_count{label1="value2"} 31 +test_summary_1_duration_microseconds{label1="value3",quantile="0.5"} 4931.921 +test_summary_1_duration_microseconds{label1="value3",quantile="0.9"} 4932.921 +test_summary_1_duration_microseconds{label1="value3",quantile="0.99"} 4933.921 +test_summary_1_duration_microseconds_sum{label1="value3"} 283201.29 +test_summary_1_duration_microseconds_count{label1="value3"} 31 +test_summary_1_duration_microseconds{label1="value4",quantile="0.5"} 4931.921 +test_summary_1_duration_microseconds{label1="value4",quantile="0.9"} 4932.921 +test_summary_1_duration_microseconds{label1="value4",quantile="0.99"} 4933.921 +test_summary_1_duration_microseconds_sum{label1="value4"} 283201.29 +test_summary_1_duration_microseconds_count{label1="value4"} 31 +# TYPE test_summary_2_duration_microseconds summary +test_summary_2_duration_microseconds{label1="value1",quantile="0.5"} 5931.921 +test_summary_2_duration_microseconds{label1="value1",quantile="0.9"} 5932.921 +test_summary_2_duration_microseconds{label1="value1",quantile="0.99"} 5933.921 +test_summary_2_duration_microseconds_sum{label1="value1"} 383201.29 +test_summary_2_duration_microseconds_count{label1="value1"} 41 +test_summary_2_duration_microseconds{label1="value2",quantile="0.5"} 5931.921 +test_summary_2_duration_microseconds{label1="value2",quantile="0.9"} 5932.921 +test_summary_2_duration_microseconds{label1="value2",quantile="0.99"} 5933.921 +test_summary_2_duration_microseconds_sum{label1="value2"} 383201.29 +test_summary_2_duration_microseconds_count{label1="value2"} 41 +test_summary_2_duration_microseconds{label1="value3",quantile="0.5"} 5931.921 +test_summary_2_duration_microseconds{label1="value3",quantile="0.9"} 5932.921 +test_summary_2_duration_microseconds{label1="value3",quantile="0.99"} 5933.921 +test_summary_2_duration_microseconds_sum{label1="value3"} 383201.29 +test_summary_2_duration_microseconds_count{label1="value3"} 41 +test_summary_2_duration_microseconds{label1="value4",quantile="0.5"} 5931.921 +test_summary_2_duration_microseconds{label1="value4",quantile="0.9"} 5932.921 +test_summary_2_duration_microseconds{label1="value4",quantile="0.99"} 5933.921 +test_summary_2_duration_microseconds_sum{label1="value4"} 383201.29 +test_summary_2_duration_microseconds_count{label1="value4"} 41 diff --git a/src/go/collectors/go.d.plugin/pkg/prometheus/testdata/summary-no-meta.txt b/src/go/collectors/go.d.plugin/pkg/prometheus/testdata/summary-no-meta.txt new file mode 100644 index 000000000..e66564bb7 --- /dev/null +++ b/src/go/collectors/go.d.plugin/pkg/prometheus/testdata/summary-no-meta.txt @@ -0,0 +1,40 @@ +test_summary_no_meta_1_duration_microseconds{label1="value1",quantile="0.5"} 4931.921 +test_summary_no_meta_1_duration_microseconds{label1="value1",quantile="0.9"} 4932.921 +test_summary_no_meta_1_duration_microseconds{label1="value1",quantile="0.99"} 4933.921 +test_summary_no_meta_1_duration_microseconds_sum{label1="value1"} 283201.29 +test_summary_no_meta_1_duration_microseconds_count{label1="value1"} 31 +test_summary_no_meta_1_duration_microseconds{label1="value2",quantile="0.5"} 4931.921 +test_summary_no_meta_1_duration_microseconds{label1="value2",quantile="0.9"} 4932.921 +test_summary_no_meta_1_duration_microseconds{label1="value2",quantile="0.99"} 4933.921 +test_summary_no_meta_1_duration_microseconds_sum{label1="value2"} 283201.29 +test_summary_no_meta_1_duration_microseconds_count{label1="value2"} 31 +test_summary_no_meta_1_duration_microseconds{label1="value3",quantile="0.5"} 4931.921 +test_summary_no_meta_1_duration_microseconds{label1="value3",quantile="0.9"} 4932.921 +test_summary_no_meta_1_duration_microseconds{label1="value3",quantile="0.99"} 4933.921 +test_summary_no_meta_1_duration_microseconds_sum{label1="value3"} 283201.29 +test_summary_no_meta_1_duration_microseconds_count{label1="value3"} 31 +test_summary_no_meta_1_duration_microseconds{label1="value4",quantile="0.5"} 4931.921 +test_summary_no_meta_1_duration_microseconds{label1="value4",quantile="0.9"} 4932.921 +test_summary_no_meta_1_duration_microseconds{label1="value4",quantile="0.99"} 4933.921 +test_summary_no_meta_1_duration_microseconds_sum{label1="value4"} 283201.29 +test_summary_no_meta_1_duration_microseconds_count{label1="value4"} 31 +test_summary_no_meta_2_duration_microseconds{label1="value1",quantile="0.5"} 5931.921 +test_summary_no_meta_2_duration_microseconds{label1="value1",quantile="0.9"} 5932.921 +test_summary_no_meta_2_duration_microseconds{label1="value1",quantile="0.99"} 5933.921 +test_summary_no_meta_2_duration_microseconds_sum{label1="value1"} 383201.29 +test_summary_no_meta_2_duration_microseconds_count{label1="value1"} 41 +test_summary_no_meta_2_duration_microseconds{label1="value2",quantile="0.5"} 5931.921 +test_summary_no_meta_2_duration_microseconds{label1="value2",quantile="0.9"} 5932.921 +test_summary_no_meta_2_duration_microseconds{label1="value2",quantile="0.99"} 5933.921 +test_summary_no_meta_2_duration_microseconds_sum{label1="value2"} 383201.29 +test_summary_no_meta_2_duration_microseconds_count{label1="value2"} 41 +test_summary_no_meta_2_duration_microseconds{label1="value3",quantile="0.5"} 5931.921 +test_summary_no_meta_2_duration_microseconds{label1="value3",quantile="0.9"} 5932.921 +test_summary_no_meta_2_duration_microseconds{label1="value3",quantile="0.99"} 5933.921 +test_summary_no_meta_2_duration_microseconds_sum{label1="value3"} 383201.29 +test_summary_no_meta_2_duration_microseconds_count{label1="value3"} 41 +test_summary_no_meta_2_duration_microseconds{label1="value4",quantile="0.5"} 5931.921 +test_summary_no_meta_2_duration_microseconds{label1="value4",quantile="0.9"} 5932.921 +test_summary_no_meta_2_duration_microseconds{label1="value4",quantile="0.99"} 5933.921 +test_summary_no_meta_2_duration_microseconds_sum{label1="value4"} 383201.29 +test_summary_no_meta_2_duration_microseconds_count{label1="value4"} 41 diff --git a/src/go/collectors/go.d.plugin/pkg/prometheus/testdata/testdata.nometa.txt b/src/go/collectors/go.d.plugin/pkg/prometheus/testdata/testdata.nometa.txt new file mode 100644 index 000000000..e760ad268 --- /dev/null +++ b/src/go/collectors/go.d.plugin/pkg/prometheus/testdata/testdata.nometa.txt @@ -0,0 +1,410 @@ +go_gc_duration_seconds{quantile="0"} 4.9351e-05 +go_gc_duration_seconds{quantile="0.25"} 7.424100000000001e-05 +go_gc_duration_seconds{quantile="0.5"} 8.3835e-05 +go_gc_duration_seconds{quantile="0.75"} 0.000106744 +go_gc_duration_seconds{quantile="1"} 0.002072195 +go_gc_duration_seconds_sum 0.012139815 +go_gc_duration_seconds_count 99 +go_goroutines 33 +go_memstats_alloc_bytes 1.7518624e+07 +go_memstats_alloc_bytes_total 8.3062296e+08 +go_memstats_buck_hash_sys_bytes 1.494637e+06 +go_memstats_frees_total 4.65658e+06 +go_memstats_gc_sys_bytes 1.107968e+06 +go_memstats_heap_alloc_bytes 1.7518624e+07 +go_memstats_heap_idle_bytes 6.668288e+06 +go_memstats_heap_inuse_bytes 1.8956288e+07 +go_memstats_heap_objects 72755 +go_memstats_heap_released_bytes_total 0 +go_memstats_heap_sys_bytes 2.5624576e+07 +go_memstats_last_gc_time_seconds 1.4843955586166437e+09 +go_memstats_lookups_total 2089 +go_memstats_mallocs_total 4.729335e+06 +go_memstats_mcache_inuse_bytes 9600 +go_memstats_mcache_sys_bytes 16384 +go_memstats_mspan_inuse_bytes 211520 +go_memstats_mspan_sys_bytes 245760 +go_memstats_next_gc_bytes 2.033527e+07 +go_memstats_other_sys_bytes 2.077323e+06 +go_memstats_stack_inuse_bytes 1.6384e+06 +go_memstats_stack_sys_bytes 1.6384e+06 +go_memstats_sys_bytes 3.2205048e+07 +http_request_duration_microseconds{handler="alerts",quantile="0.5"} NaN +http_request_duration_microseconds{handler="alerts",quantile="0.9"} NaN +http_request_duration_microseconds{handler="alerts",quantile="0.99"} NaN +http_request_duration_microseconds_sum{handler="alerts"} 0 +http_request_duration_microseconds_count{handler="alerts"} 0 +http_request_duration_microseconds{handler="config",quantile="0.5"} NaN +http_request_duration_microseconds{handler="config",quantile="0.9"} NaN +http_request_duration_microseconds{handler="config",quantile="0.99"} NaN +http_request_duration_microseconds_sum{handler="config"} 0 +http_request_duration_microseconds_count{handler="config"} 0 +http_request_duration_microseconds{handler="consoles",quantile="0.5"} NaN +http_request_duration_microseconds{handler="consoles",quantile="0.9"} NaN +http_request_duration_microseconds{handler="consoles",quantile="0.99"} NaN +http_request_duration_microseconds_sum{handler="consoles"} 0 +http_request_duration_microseconds_count{handler="consoles"} 0 +http_request_duration_microseconds{handler="drop_series",quantile="0.5"} NaN +http_request_duration_microseconds{handler="drop_series",quantile="0.9"} NaN +http_request_duration_microseconds{handler="drop_series",quantile="0.99"} NaN +http_request_duration_microseconds_sum{handler="drop_series"} 0 +http_request_duration_microseconds_count{handler="drop_series"} 0 +http_request_duration_microseconds{handler="federate",quantile="0.5"} NaN +http_request_duration_microseconds{handler="federate",quantile="0.9"} NaN +http_request_duration_microseconds{handler="federate",quantile="0.99"} NaN +http_request_duration_microseconds_sum{handler="federate"} 0 +http_request_duration_microseconds_count{handler="federate"} 0 +http_request_duration_microseconds{handler="flags",quantile="0.5"} NaN +http_request_duration_microseconds{handler="flags",quantile="0.9"} NaN +http_request_duration_microseconds{handler="flags",quantile="0.99"} NaN +http_request_duration_microseconds_sum{handler="flags"} 0 +http_request_duration_microseconds_count{handler="flags"} 0 +http_request_duration_microseconds{handler="graph",quantile="0.5"} 771.655 +http_request_duration_microseconds{handler="graph",quantile="0.9"} 1761.823 +http_request_duration_microseconds{handler="graph",quantile="0.99"} 1761.823 +http_request_duration_microseconds_sum{handler="graph"} 5803.93 +http_request_duration_microseconds_count{handler="graph"} 3 +http_request_duration_microseconds{handler="heap",quantile="0.5"} NaN +http_request_duration_microseconds{handler="heap",quantile="0.9"} NaN +http_request_duration_microseconds{handler="heap",quantile="0.99"} NaN +http_request_duration_microseconds_sum{handler="heap"} 0 +http_request_duration_microseconds_count{handler="heap"} 0 +http_request_duration_microseconds{handler="label_values",quantile="0.5"} 325.401 +http_request_duration_microseconds{handler="label_values",quantile="0.9"} 414.708 +http_request_duration_microseconds{handler="label_values",quantile="0.99"} 414.708 +http_request_duration_microseconds_sum{handler="label_values"} 3995.574 +http_request_duration_microseconds_count{handler="label_values"} 3 +http_request_duration_microseconds{handler="options",quantile="0.5"} NaN +http_request_duration_microseconds{handler="options",quantile="0.9"} NaN +http_request_duration_microseconds{handler="options",quantile="0.99"} NaN +http_request_duration_microseconds_sum{handler="options"} 0 +http_request_duration_microseconds_count{handler="options"} 0 +http_request_duration_microseconds{handler="prometheus",quantile="0.5"} 1351.859 +http_request_duration_microseconds{handler="prometheus",quantile="0.9"} 1714.035 +http_request_duration_microseconds{handler="prometheus",quantile="0.99"} 2833.523 +http_request_duration_microseconds_sum{handler="prometheus"} 661851.54 +http_request_duration_microseconds_count{handler="prometheus"} 462 +http_request_duration_microseconds{handler="query",quantile="0.5"} 3885.448 +http_request_duration_microseconds{handler="query",quantile="0.9"} 4390.558 +http_request_duration_microseconds{handler="query",quantile="0.99"} 4390.558 +http_request_duration_microseconds_sum{handler="query"} 26074.11 +http_request_duration_microseconds_count{handler="query"} 6 +http_request_duration_microseconds{handler="query_range",quantile="0.5"} NaN +http_request_duration_microseconds{handler="query_range",quantile="0.9"} NaN +http_request_duration_microseconds{handler="query_range",quantile="0.99"} NaN +http_request_duration_microseconds_sum{handler="query_range"} 0 +http_request_duration_microseconds_count{handler="query_range"} 0 +http_request_duration_microseconds{handler="rules",quantile="0.5"} NaN +http_request_duration_microseconds{handler="rules",quantile="0.9"} NaN +http_request_duration_microseconds{handler="rules",quantile="0.99"} NaN +http_request_duration_microseconds_sum{handler="rules"} 0 +http_request_duration_microseconds_count{handler="rules"} 0 +http_request_duration_microseconds{handler="series",quantile="0.5"} NaN +http_request_duration_microseconds{handler="series",quantile="0.9"} NaN +http_request_duration_microseconds{handler="series",quantile="0.99"} NaN +http_request_duration_microseconds_sum{handler="series"} 0 +http_request_duration_microseconds_count{handler="series"} 0 +http_request_duration_microseconds{handler="static",quantile="0.5"} 212.311 +http_request_duration_microseconds{handler="static",quantile="0.9"} 265.174 +http_request_duration_microseconds{handler="static",quantile="0.99"} 265.174 +http_request_duration_microseconds_sum{handler="static"} 6458.621 +http_request_duration_microseconds_count{handler="static"} 3 +http_request_duration_microseconds{handler="status",quantile="0.5"} NaN +http_request_duration_microseconds{handler="status",quantile="0.9"} NaN +http_request_duration_microseconds{handler="status",quantile="0.99"} NaN +http_request_duration_microseconds_sum{handler="status"} 0 +http_request_duration_microseconds_count{handler="status"} 0 +http_request_duration_microseconds{handler="targets",quantile="0.5"} NaN +http_request_duration_microseconds{handler="targets",quantile="0.9"} NaN +http_request_duration_microseconds{handler="targets",quantile="0.99"} NaN +http_request_duration_microseconds_sum{handler="targets"} 0 +http_request_duration_microseconds_count{handler="targets"} 0 +http_request_duration_microseconds{handler="version",quantile="0.5"} NaN +http_request_duration_microseconds{handler="version",quantile="0.9"} NaN +http_request_duration_microseconds{handler="version",quantile="0.99"} NaN +http_request_duration_microseconds_sum{handler="version"} 0 +http_request_duration_microseconds_count{handler="version"} 0 +http_request_size_bytes{handler="alerts",quantile="0.5"} NaN +http_request_size_bytes{handler="alerts",quantile="0.9"} NaN +http_request_size_bytes{handler="alerts",quantile="0.99"} NaN +http_request_size_bytes_sum{handler="alerts"} 0 +http_request_size_bytes_count{handler="alerts"} 0 +http_request_size_bytes{handler="config",quantile="0.5"} NaN +http_request_size_bytes{handler="config",quantile="0.9"} NaN +http_request_size_bytes{handler="config",quantile="0.99"} NaN +http_request_size_bytes_sum{handler="config"} 0 +http_request_size_bytes_count{handler="config"} 0 +http_request_size_bytes{handler="consoles",quantile="0.5"} NaN +http_request_size_bytes{handler="consoles",quantile="0.9"} NaN +http_request_size_bytes{handler="consoles",quantile="0.99"} NaN +http_request_size_bytes_sum{handler="consoles"} 0 +http_request_size_bytes_count{handler="consoles"} 0 +http_request_size_bytes{handler="drop_series",quantile="0.5"} NaN +http_request_size_bytes{handler="drop_series",quantile="0.9"} NaN +http_request_size_bytes{handler="drop_series",quantile="0.99"} NaN +http_request_size_bytes_sum{handler="drop_series"} 0 +http_request_size_bytes_count{handler="drop_series"} 0 +http_request_size_bytes{handler="federate",quantile="0.5"} NaN +http_request_size_bytes{handler="federate",quantile="0.9"} NaN +http_request_size_bytes{handler="federate",quantile="0.99"} NaN +http_request_size_bytes_sum{handler="federate"} 0 +http_request_size_bytes_count{handler="federate"} 0 +http_request_size_bytes{handler="flags",quantile="0.5"} NaN +http_request_size_bytes{handler="flags",quantile="0.9"} NaN +http_request_size_bytes{handler="flags",quantile="0.99"} NaN +http_request_size_bytes_sum{handler="flags"} 0 +http_request_size_bytes_count{handler="flags"} 0 +http_request_size_bytes{handler="graph",quantile="0.5"} 367 +http_request_size_bytes{handler="graph",quantile="0.9"} 389 +http_request_size_bytes{handler="graph",quantile="0.99"} 389 +http_request_size_bytes_sum{handler="graph"} 1145 +http_request_size_bytes_count{handler="graph"} 3 +http_request_size_bytes{handler="heap",quantile="0.5"} NaN +http_request_size_bytes{handler="heap",quantile="0.9"} NaN +http_request_size_bytes{handler="heap",quantile="0.99"} NaN +http_request_size_bytes_sum{handler="heap"} 0 +http_request_size_bytes_count{handler="heap"} 0 +http_request_size_bytes{handler="label_values",quantile="0.5"} 416 +http_request_size_bytes{handler="label_values",quantile="0.9"} 416 +http_request_size_bytes{handler="label_values",quantile="0.99"} 416 +http_request_size_bytes_sum{handler="label_values"} 1248 +http_request_size_bytes_count{handler="label_values"} 3 +http_request_size_bytes{handler="options",quantile="0.5"} NaN +http_request_size_bytes{handler="options",quantile="0.9"} NaN +http_request_size_bytes{handler="options",quantile="0.99"} NaN +http_request_size_bytes_sum{handler="options"} 0 +http_request_size_bytes_count{handler="options"} 0 +http_request_size_bytes{handler="prometheus",quantile="0.5"} 238 +http_request_size_bytes{handler="prometheus",quantile="0.9"} 238 +http_request_size_bytes{handler="prometheus",quantile="0.99"} 238 +http_request_size_bytes_sum{handler="prometheus"} 109956 +http_request_size_bytes_count{handler="prometheus"} 462 +http_request_size_bytes{handler="query",quantile="0.5"} 531 +http_request_size_bytes{handler="query",quantile="0.9"} 531 +http_request_size_bytes{handler="query",quantile="0.99"} 531 +http_request_size_bytes_sum{handler="query"} 3186 +http_request_size_bytes_count{handler="query"} 6 +http_request_size_bytes{handler="query_range",quantile="0.5"} NaN +http_request_size_bytes{handler="query_range",quantile="0.9"} NaN +http_request_size_bytes{handler="query_range",quantile="0.99"} NaN +http_request_size_bytes_sum{handler="query_range"} 0 +http_request_size_bytes_count{handler="query_range"} 0 +http_request_size_bytes{handler="rules",quantile="0.5"} NaN +http_request_size_bytes{handler="rules",quantile="0.9"} NaN +http_request_size_bytes{handler="rules",quantile="0.99"} NaN +http_request_size_bytes_sum{handler="rules"} 0 +http_request_size_bytes_count{handler="rules"} 0 +http_request_size_bytes{handler="series",quantile="0.5"} NaN +http_request_size_bytes{handler="series",quantile="0.9"} NaN +http_request_size_bytes{handler="series",quantile="0.99"} NaN +http_request_size_bytes_sum{handler="series"} 0 +http_request_size_bytes_count{handler="series"} 0 +http_request_size_bytes{handler="static",quantile="0.5"} 379 +http_request_size_bytes{handler="static",quantile="0.9"} 379 +http_request_size_bytes{handler="static",quantile="0.99"} 379 +http_request_size_bytes_sum{handler="static"} 1137 +http_request_size_bytes_count{handler="static"} 3 +http_request_size_bytes{handler="status",quantile="0.5"} NaN +http_request_size_bytes{handler="status",quantile="0.9"} NaN +http_request_size_bytes{handler="status",quantile="0.99"} NaN +http_request_size_bytes_sum{handler="status"} 0 +http_request_size_bytes_count{handler="status"} 0 +http_request_size_bytes{handler="targets",quantile="0.5"} NaN +http_request_size_bytes{handler="targets",quantile="0.9"} NaN +http_request_size_bytes{handler="targets",quantile="0.99"} NaN +http_request_size_bytes_sum{handler="targets"} 0 +http_request_size_bytes_count{handler="targets"} 0 +http_request_size_bytes{handler="version",quantile="0.5"} NaN +http_request_size_bytes{handler="version",quantile="0.9"} NaN +http_request_size_bytes{handler="version",quantile="0.99"} NaN +http_request_size_bytes_sum{handler="version"} 0 +http_request_size_bytes_count{handler="version"} 0 +http_requests_total{code="200",handler="graph",method="get"} 3 +http_requests_total{code="200",handler="label_values",method="get"} 3 +http_requests_total{code="200",handler="prometheus",method="get"} 462 +http_requests_total{code="200",handler="query",method="get"} 6 +http_requests_total{code="200",handler="static",method="get"} 3 +http_response_size_bytes{handler="alerts",quantile="0.5"} NaN +http_response_size_bytes{handler="alerts",quantile="0.9"} NaN +http_response_size_bytes{handler="alerts",quantile="0.99"} NaN +http_response_size_bytes_sum{handler="alerts"} 0 +http_response_size_bytes_count{handler="alerts"} 0 +http_response_size_bytes{handler="config",quantile="0.5"} NaN +http_response_size_bytes{handler="config",quantile="0.9"} NaN +http_response_size_bytes{handler="config",quantile="0.99"} NaN +http_response_size_bytes_sum{handler="config"} 0 +http_response_size_bytes_count{handler="config"} 0 +http_response_size_bytes{handler="consoles",quantile="0.5"} NaN +http_response_size_bytes{handler="consoles",quantile="0.9"} NaN +http_response_size_bytes{handler="consoles",quantile="0.99"} NaN +http_response_size_bytes_sum{handler="consoles"} 0 +http_response_size_bytes_count{handler="consoles"} 0 +http_response_size_bytes{handler="drop_series",quantile="0.5"} NaN +http_response_size_bytes{handler="drop_series",quantile="0.9"} NaN +http_response_size_bytes{handler="drop_series",quantile="0.99"} NaN +http_response_size_bytes_sum{handler="drop_series"} 0 +http_response_size_bytes_count{handler="drop_series"} 0 +http_response_size_bytes{handler="federate",quantile="0.5"} NaN +http_response_size_bytes{handler="federate",quantile="0.9"} NaN +http_response_size_bytes{handler="federate",quantile="0.99"} NaN +http_response_size_bytes_sum{handler="federate"} 0 +http_response_size_bytes_count{handler="federate"} 0 +http_response_size_bytes{handler="flags",quantile="0.5"} NaN +http_response_size_bytes{handler="flags",quantile="0.9"} NaN +http_response_size_bytes{handler="flags",quantile="0.99"} NaN +http_response_size_bytes_sum{handler="flags"} 0 +http_response_size_bytes_count{handler="flags"} 0 +http_response_size_bytes{handler="graph",quantile="0.5"} 3619 +http_response_size_bytes{handler="graph",quantile="0.9"} 3619 +http_response_size_bytes{handler="graph",quantile="0.99"} 3619 +http_response_size_bytes_sum{handler="graph"} 10857 +http_response_size_bytes_count{handler="graph"} 3 +http_response_size_bytes{handler="heap",quantile="0.5"} NaN +http_response_size_bytes{handler="heap",quantile="0.9"} NaN +http_response_size_bytes{handler="heap",quantile="0.99"} NaN +http_response_size_bytes_sum{handler="heap"} 0 +http_response_size_bytes_count{handler="heap"} 0 +http_response_size_bytes{handler="label_values",quantile="0.5"} 642 +http_response_size_bytes{handler="label_values",quantile="0.9"} 642 +http_response_size_bytes{handler="label_values",quantile="0.99"} 642 +http_response_size_bytes_sum{handler="label_values"} 1926 +http_response_size_bytes_count{handler="label_values"} 3 +http_response_size_bytes{handler="options",quantile="0.5"} NaN +http_response_size_bytes{handler="options",quantile="0.9"} NaN +http_response_size_bytes{handler="options",quantile="0.99"} NaN +http_response_size_bytes_sum{handler="options"} 0 +http_response_size_bytes_count{handler="options"} 0 +http_response_size_bytes{handler="prometheus",quantile="0.5"} 3033 +http_response_size_bytes{handler="prometheus",quantile="0.9"} 3123 +http_response_size_bytes{handler="prometheus",quantile="0.99"} 3128 +http_response_size_bytes_sum{handler="prometheus"} 1.374097e+06 +http_response_size_bytes_count{handler="prometheus"} 462 +http_response_size_bytes{handler="query",quantile="0.5"} 776 +http_response_size_bytes{handler="query",quantile="0.9"} 781 +http_response_size_bytes{handler="query",quantile="0.99"} 781 +http_response_size_bytes_sum{handler="query"} 4656 +http_response_size_bytes_count{handler="query"} 6 +http_response_size_bytes{handler="query_range",quantile="0.5"} NaN +http_response_size_bytes{handler="query_range",quantile="0.9"} NaN +http_response_size_bytes{handler="query_range",quantile="0.99"} NaN +http_response_size_bytes_sum{handler="query_range"} 0 +http_response_size_bytes_count{handler="query_range"} 0 +http_response_size_bytes{handler="rules",quantile="0.5"} NaN +http_response_size_bytes{handler="rules",quantile="0.9"} NaN +http_response_size_bytes{handler="rules",quantile="0.99"} NaN +http_response_size_bytes_sum{handler="rules"} 0 +http_response_size_bytes_count{handler="rules"} 0 +http_response_size_bytes{handler="series",quantile="0.5"} NaN +http_response_size_bytes{handler="series",quantile="0.9"} NaN +http_response_size_bytes{handler="series",quantile="0.99"} NaN +http_response_size_bytes_sum{handler="series"} 0 +http_response_size_bytes_count{handler="series"} 0 +http_response_size_bytes{handler="static",quantile="0.5"} 6316 +http_response_size_bytes{handler="static",quantile="0.9"} 6316 +http_response_size_bytes{handler="static",quantile="0.99"} 6316 +http_response_size_bytes_sum{handler="static"} 18948 +http_response_size_bytes_count{handler="static"} 3 +http_response_size_bytes{handler="status",quantile="0.5"} NaN +http_response_size_bytes{handler="status",quantile="0.9"} NaN +http_response_size_bytes{handler="status",quantile="0.99"} NaN +http_response_size_bytes_sum{handler="status"} 0 +http_response_size_bytes_count{handler="status"} 0 +http_response_size_bytes{handler="targets",quantile="0.5"} NaN +http_response_size_bytes{handler="targets",quantile="0.9"} NaN +http_response_size_bytes{handler="targets",quantile="0.99"} NaN +http_response_size_bytes_sum{handler="targets"} 0 +http_response_size_bytes_count{handler="targets"} 0 +http_response_size_bytes{handler="version",quantile="0.5"} NaN +http_response_size_bytes{handler="version",quantile="0.9"} NaN +http_response_size_bytes{handler="version",quantile="0.99"} NaN +http_response_size_bytes_sum{handler="version"} 0 +http_response_size_bytes_count{handler="version"} 0 +prometheus_build_info{branch="",goversion="go1.7.3",revision="",version=""} 1 +prometheus_config_last_reload_success_timestamp_seconds 1.484395547e+09 +prometheus_config_last_reload_successful 1 +prometheus_evaluator_duration_seconds{quantile="0.01"} 1.7890000000000002e-06 +prometheus_evaluator_duration_seconds{quantile="0.05"} 1.7890000000000002e-06 +prometheus_evaluator_duration_seconds{quantile="0.5"} 1.7890000000000002e-06 +prometheus_evaluator_duration_seconds{quantile="0.9"} 1.7890000000000002e-06 +prometheus_evaluator_duration_seconds{quantile="0.99"} 1.7890000000000002e-06 +prometheus_evaluator_duration_seconds_sum 1.7890000000000002e-06 +prometheus_evaluator_duration_seconds_count 1 +prometheus_evaluator_iterations_skipped_total 0 +prometheus_notifications_dropped_total 0 +prometheus_notifications_queue_capacity 10000 +prometheus_notifications_queue_length 0 +prometheus_rule_evaluation_failures_total{rule_type="alerting"} 0 +prometheus_rule_evaluation_failures_total{rule_type="recording"} 0 +prometheus_sd_azure_refresh_duration_seconds{quantile="0.5"} NaN +prometheus_sd_azure_refresh_duration_seconds{quantile="0.9"} NaN +prometheus_sd_azure_refresh_duration_seconds{quantile="0.99"} NaN +prometheus_sd_azure_refresh_duration_seconds_sum 0 +prometheus_sd_azure_refresh_duration_seconds_count 0 +prometheus_sd_azure_refresh_failures_total 0 +prometheus_sd_consul_rpc_duration_seconds{call="service",endpoint="catalog",quantile="0.5"} NaN +prometheus_sd_consul_rpc_duration_seconds{call="service",endpoint="catalog",quantile="0.9"} NaN +prometheus_sd_consul_rpc_duration_seconds{call="service",endpoint="catalog",quantile="0.99"} NaN +prometheus_sd_consul_rpc_duration_seconds_sum{call="service",endpoint="catalog"} 0 +prometheus_sd_consul_rpc_duration_seconds_count{call="service",endpoint="catalog"} 0 +prometheus_sd_consul_rpc_duration_seconds{call="services",endpoint="catalog",quantile="0.5"} NaN +prometheus_sd_consul_rpc_duration_seconds{call="services",endpoint="catalog",quantile="0.9"} NaN +prometheus_sd_consul_rpc_duration_seconds{call="services",endpoint="catalog",quantile="0.99"} NaN +prometheus_sd_consul_rpc_duration_seconds_sum{call="services",endpoint="catalog"} 0 +prometheus_sd_consul_rpc_duration_seconds_count{call="services",endpoint="catalog"} 0 +prometheus_sd_consul_rpc_failures_total 0 +prometheus_sd_dns_lookup_failures_total 0 +prometheus_sd_dns_lookups_total 0 +prometheus_sd_ec2_refresh_duration_seconds{quantile="0.5"} NaN +prometheus_sd_ec2_refresh_duration_seconds{quantile="0.9"} NaN +prometheus_sd_ec2_refresh_duration_seconds{quantile="0.99"} NaN +prometheus_sd_ec2_refresh_duration_seconds_sum 0 +prometheus_sd_ec2_refresh_duration_seconds_count 0 +prometheus_sd_ec2_refresh_failures_total 0 +prometheus_sd_file_read_errors_total 0 +prometheus_sd_file_scan_duration_seconds{quantile="0.5"} NaN +prometheus_sd_file_scan_duration_seconds{quantile="0.9"} NaN +prometheus_sd_file_scan_duration_seconds{quantile="0.99"} NaN +prometheus_sd_file_scan_duration_seconds_sum 0 +prometheus_sd_file_scan_duration_seconds_count 0 +prometheus_sd_gce_refresh_duration{quantile="0.5"} NaN +prometheus_sd_gce_refresh_duration{quantile="0.9"} NaN +prometheus_sd_gce_refresh_duration{quantile="0.99"} NaN +prometheus_sd_gce_refresh_duration_sum 0 +prometheus_sd_gce_refresh_duration_count 0 +prometheus_sd_gce_refresh_failures_total 0 +prometheus_sd_kubernetes_events_total{event="add",role="endpoints"} 0 +prometheus_sd_kubernetes_events_total{event="add",role="node"} 0 +prometheus_sd_kubernetes_events_total{event="add",role="pod"} 0 +prometheus_sd_kubernetes_events_total{event="add",role="service"} 0 +prometheus_sd_kubernetes_events_total{event="delete",role="endpoints"} 0 +prometheus_sd_kubernetes_events_total{event="delete",role="node"} 0 +prometheus_sd_kubernetes_events_total{event="delete",role="pod"} 0 +prometheus_sd_kubernetes_events_total{event="delete",role="service"} 0 +prometheus_sd_kubernetes_events_total{event="update",role="endpoints"} 0 +prometheus_sd_kubernetes_events_total{event="update",role="node"} 0 +prometheus_sd_kubernetes_events_total{event="update",role="pod"} 0 +prometheus_sd_kubernetes_events_total{event="update",role="service"} 0 +prometheus_sd_marathon_refresh_duration_seconds{quantile="0.5"} NaN +prometheus_sd_marathon_refresh_duration_seconds{quantile="0.9"} NaN +prometheus_sd_marathon_refresh_duration_seconds{quantile="0.99"} NaN +prometheus_sd_marathon_refresh_duration_seconds_sum 0 +prometheus_sd_marathon_refresh_duration_seconds_count 0 +prometheus_sd_marathon_refresh_failures_total 0 +prometheus_target_interval_length_seconds{interval="50ms",quantile="0.01"} 0.046182157 +prometheus_target_interval_length_seconds{interval="50ms",quantile="0.05"} 0.047306979000000006 +prometheus_target_interval_length_seconds{interval="50ms",quantile="0.5"} 0.050381782 +prometheus_target_interval_length_seconds{interval="50ms",quantile="0.9"} 0.052614556 +prometheus_target_interval_length_seconds{interval="50ms",quantile="0.99"} 0.054404386000000006 +prometheus_target_interval_length_seconds_sum{interval="50ms"} 34.512091221999995 +prometheus_target_interval_length_seconds_count{interval="50ms"} 685 +prometheus_target_scrape_pool_sync_total{scrape_job="prometheus"} 1 +prometheus_target_skipped_scrapes_total 0 +prometheus_target_sync_length_seconds{scrape_job="prometheus",quantile="0.01"} 0.00020043300000000002 +prometheus_target_sync_length_seconds{scrape_job="prometheus",quantile="0.05"} 0.00020043300000000002 +prometheus_target_sync_length_seconds{scrape_job="prometheus",quantile="0.5"} 0.00020043300000000002 +prometheus_target_sync_length_seconds{scrape_job="prometheus",quantile="0.9"} 0.00020043300000000002 +prometheus_target_sync_length_seconds{scrape_job="prometheus",quantile="0.99"} 0.00020043300000000002 +prometheus_target_sync_length_seconds_sum{scrape_job="prometheus"} 0.00020043300000000002 +prometheus_target_sync_length_seconds_count{scrape_job="prometheus"} 1 +prometheus_treecache_watcher_goroutines 0 +prometheus_treecache_zookeeper_failures_total 0 diff --git a/src/go/collectors/go.d.plugin/pkg/prometheus/testdata/testdata.txt b/src/go/collectors/go.d.plugin/pkg/prometheus/testdata/testdata.txt new file mode 100644 index 000000000..c7f2a7af0 --- /dev/null +++ b/src/go/collectors/go.d.plugin/pkg/prometheus/testdata/testdata.txt @@ -0,0 +1,528 @@ +# HELP go_gc_duration_seconds A summary of the GC invocation durations. +# TYPE go_gc_duration_seconds summary +go_gc_duration_seconds{quantile="0"} 4.9351e-05 +go_gc_duration_seconds{quantile="0.25"} 7.424100000000001e-05 +go_gc_duration_seconds{quantile="0.5"} 8.3835e-05 +go_gc_duration_seconds{quantile="0.75"} 0.000106744 +go_gc_duration_seconds{quantile="1"} 0.002072195 +go_gc_duration_seconds_sum 0.012139815 +go_gc_duration_seconds_count 99 +# HELP go_goroutines Number of goroutines that currently exist. +# TYPE go_goroutines gauge +go_goroutines 33 +# HELP go_memstats_alloc_bytes Number of bytes allocated and still in use. +# TYPE go_memstats_alloc_bytes gauge +go_memstats_alloc_bytes 1.7518624e+07 +# HELP go_memstats_alloc_bytes_total Total number of bytes allocated, even if freed. +# TYPE go_memstats_alloc_bytes_total counter +go_memstats_alloc_bytes_total 8.3062296e+08 +# HELP go_memstats_buck_hash_sys_bytes Number of bytes used by the profiling bucket hash table. +# TYPE go_memstats_buck_hash_sys_bytes gauge +go_memstats_buck_hash_sys_bytes 1.494637e+06 +# HELP go_memstats_frees_total Total number of frees. +# TYPE go_memstats_frees_total counter +go_memstats_frees_total 4.65658e+06 +# HELP go_memstats_gc_sys_bytes Number of bytes used for garbage collection system metadata. +# TYPE go_memstats_gc_sys_bytes gauge +go_memstats_gc_sys_bytes 1.107968e+06 +# HELP go_memstats_heap_alloc_bytes Number of heap bytes allocated and still in use. +# TYPE go_memstats_heap_alloc_bytes gauge +go_memstats_heap_alloc_bytes 1.7518624e+07 +# HELP go_memstats_heap_idle_bytes Number of heap bytes waiting to be used. +# TYPE go_memstats_heap_idle_bytes gauge +go_memstats_heap_idle_bytes 6.668288e+06 +# HELP go_memstats_heap_inuse_bytes Number of heap bytes that are in use. +# TYPE go_memstats_heap_inuse_bytes gauge +go_memstats_heap_inuse_bytes 1.8956288e+07 +# HELP go_memstats_heap_objects Number of allocated objects. +# TYPE go_memstats_heap_objects gauge +go_memstats_heap_objects 72755 +# HELP go_memstats_heap_released_bytes_total Total number of heap bytes released to OS. +# TYPE go_memstats_heap_released_bytes_total counter +go_memstats_heap_released_bytes_total 0 +# HELP go_memstats_heap_sys_bytes Number of heap bytes obtained from system. +# TYPE go_memstats_heap_sys_bytes gauge +go_memstats_heap_sys_bytes 2.5624576e+07 +# HELP go_memstats_last_gc_time_seconds Number of seconds since 1970 of last garbage collection. +# TYPE go_memstats_last_gc_time_seconds gauge +go_memstats_last_gc_time_seconds 1.4843955586166437e+09 +# HELP go_memstats_lookups_total Total number of pointer lookups. +# TYPE go_memstats_lookups_total counter +go_memstats_lookups_total 2089 +# HELP go_memstats_mallocs_total Total number of mallocs. +# TYPE go_memstats_mallocs_total counter +go_memstats_mallocs_total 4.729335e+06 +# HELP go_memstats_mcache_inuse_bytes Number of bytes in use by mcache structures. +# TYPE go_memstats_mcache_inuse_bytes gauge +go_memstats_mcache_inuse_bytes 9600 +# HELP go_memstats_mcache_sys_bytes Number of bytes used for mcache structures obtained from system. +# TYPE go_memstats_mcache_sys_bytes gauge +go_memstats_mcache_sys_bytes 16384 +# HELP go_memstats_mspan_inuse_bytes Number of bytes in use by mspan structures. +# TYPE go_memstats_mspan_inuse_bytes gauge +go_memstats_mspan_inuse_bytes 211520 +# HELP go_memstats_mspan_sys_bytes Number of bytes used for mspan structures obtained from system. +# TYPE go_memstats_mspan_sys_bytes gauge +go_memstats_mspan_sys_bytes 245760 +# HELP go_memstats_next_gc_bytes Number of heap bytes when next garbage collection will take place. +# TYPE go_memstats_next_gc_bytes gauge +go_memstats_next_gc_bytes 2.033527e+07 +# HELP go_memstats_other_sys_bytes Number of bytes used for other system allocations. +# TYPE go_memstats_other_sys_bytes gauge +go_memstats_other_sys_bytes 2.077323e+06 +# HELP go_memstats_stack_inuse_bytes Number of bytes in use by the stack allocator. +# TYPE go_memstats_stack_inuse_bytes gauge +go_memstats_stack_inuse_bytes 1.6384e+06 +# HELP go_memstats_stack_sys_bytes Number of bytes obtained from system for stack allocator. +# TYPE go_memstats_stack_sys_bytes gauge +go_memstats_stack_sys_bytes 1.6384e+06 +# HELP go_memstats_sys_bytes Number of bytes obtained by system. Sum of all system allocations. +# TYPE go_memstats_sys_bytes gauge +go_memstats_sys_bytes 3.2205048e+07 +# HELP http_request_duration_microseconds The HTTP request latencies in microseconds. +# TYPE http_request_duration_microseconds summary +http_request_duration_microseconds{handler="alerts",quantile="0.5"} NaN +http_request_duration_microseconds{handler="alerts",quantile="0.9"} NaN +http_request_duration_microseconds{handler="alerts",quantile="0.99"} NaN +http_request_duration_microseconds_sum{handler="alerts"} 0 +http_request_duration_microseconds_count{handler="alerts"} 0 +http_request_duration_microseconds{handler="config",quantile="0.5"} NaN +http_request_duration_microseconds{handler="config",quantile="0.9"} NaN +http_request_duration_microseconds{handler="config",quantile="0.99"} NaN +http_request_duration_microseconds_sum{handler="config"} 0 +http_request_duration_microseconds_count{handler="config"} 0 +http_request_duration_microseconds{handler="consoles",quantile="0.5"} NaN +http_request_duration_microseconds{handler="consoles",quantile="0.9"} NaN +http_request_duration_microseconds{handler="consoles",quantile="0.99"} NaN +http_request_duration_microseconds_sum{handler="consoles"} 0 +http_request_duration_microseconds_count{handler="consoles"} 0 +http_request_duration_microseconds{handler="drop_series",quantile="0.5"} NaN +http_request_duration_microseconds{handler="drop_series",quantile="0.9"} NaN +http_request_duration_microseconds{handler="drop_series",quantile="0.99"} NaN +http_request_duration_microseconds_sum{handler="drop_series"} 0 +http_request_duration_microseconds_count{handler="drop_series"} 0 +http_request_duration_microseconds{handler="federate",quantile="0.5"} NaN +http_request_duration_microseconds{handler="federate",quantile="0.9"} NaN +http_request_duration_microseconds{handler="federate",quantile="0.99"} NaN +http_request_duration_microseconds_sum{handler="federate"} 0 +http_request_duration_microseconds_count{handler="federate"} 0 +http_request_duration_microseconds{handler="flags",quantile="0.5"} NaN +http_request_duration_microseconds{handler="flags",quantile="0.9"} NaN +http_request_duration_microseconds{handler="flags",quantile="0.99"} NaN +http_request_duration_microseconds_sum{handler="flags"} 0 +http_request_duration_microseconds_count{handler="flags"} 0 +http_request_duration_microseconds{handler="graph",quantile="0.5"} 771.655 +http_request_duration_microseconds{handler="graph",quantile="0.9"} 1761.823 +http_request_duration_microseconds{handler="graph",quantile="0.99"} 1761.823 +http_request_duration_microseconds_sum{handler="graph"} 5803.93 +http_request_duration_microseconds_count{handler="graph"} 3 +http_request_duration_microseconds{handler="heap",quantile="0.5"} NaN +http_request_duration_microseconds{handler="heap",quantile="0.9"} NaN +http_request_duration_microseconds{handler="heap",quantile="0.99"} NaN +http_request_duration_microseconds_sum{handler="heap"} 0 +http_request_duration_microseconds_count{handler="heap"} 0 +http_request_duration_microseconds{handler="label_values",quantile="0.5"} 325.401 +http_request_duration_microseconds{handler="label_values",quantile="0.9"} 414.708 +http_request_duration_microseconds{handler="label_values",quantile="0.99"} 414.708 +http_request_duration_microseconds_sum{handler="label_values"} 3995.574 +http_request_duration_microseconds_count{handler="label_values"} 3 +http_request_duration_microseconds{handler="options",quantile="0.5"} NaN +http_request_duration_microseconds{handler="options",quantile="0.9"} NaN +http_request_duration_microseconds{handler="options",quantile="0.99"} NaN +http_request_duration_microseconds_sum{handler="options"} 0 +http_request_duration_microseconds_count{handler="options"} 0 +http_request_duration_microseconds{handler="prometheus",quantile="0.5"} 1351.859 +http_request_duration_microseconds{handler="prometheus",quantile="0.9"} 1714.035 +http_request_duration_microseconds{handler="prometheus",quantile="0.99"} 2833.523 +http_request_duration_microseconds_sum{handler="prometheus"} 661851.54 +http_request_duration_microseconds_count{handler="prometheus"} 462 +http_request_duration_microseconds{handler="query",quantile="0.5"} 3885.448 +http_request_duration_microseconds{handler="query",quantile="0.9"} 4390.558 +http_request_duration_microseconds{handler="query",quantile="0.99"} 4390.558 +http_request_duration_microseconds_sum{handler="query"} 26074.11 +http_request_duration_microseconds_count{handler="query"} 6 +http_request_duration_microseconds{handler="query_range",quantile="0.5"} NaN +http_request_duration_microseconds{handler="query_range",quantile="0.9"} NaN +http_request_duration_microseconds{handler="query_range",quantile="0.99"} NaN +http_request_duration_microseconds_sum{handler="query_range"} 0 +http_request_duration_microseconds_count{handler="query_range"} 0 +http_request_duration_microseconds{handler="rules",quantile="0.5"} NaN +http_request_duration_microseconds{handler="rules",quantile="0.9"} NaN +http_request_duration_microseconds{handler="rules",quantile="0.99"} NaN +http_request_duration_microseconds_sum{handler="rules"} 0 +http_request_duration_microseconds_count{handler="rules"} 0 +http_request_duration_microseconds{handler="series",quantile="0.5"} NaN +http_request_duration_microseconds{handler="series",quantile="0.9"} NaN +http_request_duration_microseconds{handler="series",quantile="0.99"} NaN +http_request_duration_microseconds_sum{handler="series"} 0 +http_request_duration_microseconds_count{handler="series"} 0 +http_request_duration_microseconds{handler="static",quantile="0.5"} 212.311 +http_request_duration_microseconds{handler="static",quantile="0.9"} 265.174 +http_request_duration_microseconds{handler="static",quantile="0.99"} 265.174 +http_request_duration_microseconds_sum{handler="static"} 6458.621 +http_request_duration_microseconds_count{handler="static"} 3 +http_request_duration_microseconds{handler="status",quantile="0.5"} NaN +http_request_duration_microseconds{handler="status",quantile="0.9"} NaN +http_request_duration_microseconds{handler="status",quantile="0.99"} NaN +http_request_duration_microseconds_sum{handler="status"} 0 +http_request_duration_microseconds_count{handler="status"} 0 +http_request_duration_microseconds{handler="targets",quantile="0.5"} NaN +http_request_duration_microseconds{handler="targets",quantile="0.9"} NaN +http_request_duration_microseconds{handler="targets",quantile="0.99"} NaN +http_request_duration_microseconds_sum{handler="targets"} 0 +http_request_duration_microseconds_count{handler="targets"} 0 +http_request_duration_microseconds{handler="version",quantile="0.5"} NaN +http_request_duration_microseconds{handler="version",quantile="0.9"} NaN +http_request_duration_microseconds{handler="version",quantile="0.99"} NaN +http_request_duration_microseconds_sum{handler="version"} 0 +http_request_duration_microseconds_count{handler="version"} 0 +# HELP http_request_size_bytes The HTTP request sizes in bytes. +# TYPE http_request_size_bytes summary +http_request_size_bytes{handler="alerts",quantile="0.5"} NaN +http_request_size_bytes{handler="alerts",quantile="0.9"} NaN +http_request_size_bytes{handler="alerts",quantile="0.99"} NaN +http_request_size_bytes_sum{handler="alerts"} 0 +http_request_size_bytes_count{handler="alerts"} 0 +http_request_size_bytes{handler="config",quantile="0.5"} NaN +http_request_size_bytes{handler="config",quantile="0.9"} NaN +http_request_size_bytes{handler="config",quantile="0.99"} NaN +http_request_size_bytes_sum{handler="config"} 0 +http_request_size_bytes_count{handler="config"} 0 +http_request_size_bytes{handler="consoles",quantile="0.5"} NaN +http_request_size_bytes{handler="consoles",quantile="0.9"} NaN +http_request_size_bytes{handler="consoles",quantile="0.99"} NaN +http_request_size_bytes_sum{handler="consoles"} 0 +http_request_size_bytes_count{handler="consoles"} 0 +http_request_size_bytes{handler="drop_series",quantile="0.5"} NaN +http_request_size_bytes{handler="drop_series",quantile="0.9"} NaN +http_request_size_bytes{handler="drop_series",quantile="0.99"} NaN +http_request_size_bytes_sum{handler="drop_series"} 0 +http_request_size_bytes_count{handler="drop_series"} 0 +http_request_size_bytes{handler="federate",quantile="0.5"} NaN +http_request_size_bytes{handler="federate",quantile="0.9"} NaN +http_request_size_bytes{handler="federate",quantile="0.99"} NaN +http_request_size_bytes_sum{handler="federate"} 0 +http_request_size_bytes_count{handler="federate"} 0 +http_request_size_bytes{handler="flags",quantile="0.5"} NaN +http_request_size_bytes{handler="flags",quantile="0.9"} NaN +http_request_size_bytes{handler="flags",quantile="0.99"} NaN +http_request_size_bytes_sum{handler="flags"} 0 +http_request_size_bytes_count{handler="flags"} 0 +http_request_size_bytes{handler="graph",quantile="0.5"} 367 +http_request_size_bytes{handler="graph",quantile="0.9"} 389 +http_request_size_bytes{handler="graph",quantile="0.99"} 389 +http_request_size_bytes_sum{handler="graph"} 1145 +http_request_size_bytes_count{handler="graph"} 3 +http_request_size_bytes{handler="heap",quantile="0.5"} NaN +http_request_size_bytes{handler="heap",quantile="0.9"} NaN +http_request_size_bytes{handler="heap",quantile="0.99"} NaN +http_request_size_bytes_sum{handler="heap"} 0 +http_request_size_bytes_count{handler="heap"} 0 +http_request_size_bytes{handler="label_values",quantile="0.5"} 416 +http_request_size_bytes{handler="label_values",quantile="0.9"} 416 +http_request_size_bytes{handler="label_values",quantile="0.99"} 416 +http_request_size_bytes_sum{handler="label_values"} 1248 +http_request_size_bytes_count{handler="label_values"} 3 +http_request_size_bytes{handler="options",quantile="0.5"} NaN +http_request_size_bytes{handler="options",quantile="0.9"} NaN +http_request_size_bytes{handler="options",quantile="0.99"} NaN +http_request_size_bytes_sum{handler="options"} 0 +http_request_size_bytes_count{handler="options"} 0 +http_request_size_bytes{handler="prometheus",quantile="0.5"} 238 +http_request_size_bytes{handler="prometheus",quantile="0.9"} 238 +http_request_size_bytes{handler="prometheus",quantile="0.99"} 238 +http_request_size_bytes_sum{handler="prometheus"} 109956 +http_request_size_bytes_count{handler="prometheus"} 462 +http_request_size_bytes{handler="query",quantile="0.5"} 531 +http_request_size_bytes{handler="query",quantile="0.9"} 531 +http_request_size_bytes{handler="query",quantile="0.99"} 531 +http_request_size_bytes_sum{handler="query"} 3186 +http_request_size_bytes_count{handler="query"} 6 +http_request_size_bytes{handler="query_range",quantile="0.5"} NaN +http_request_size_bytes{handler="query_range",quantile="0.9"} NaN +http_request_size_bytes{handler="query_range",quantile="0.99"} NaN +http_request_size_bytes_sum{handler="query_range"} 0 +http_request_size_bytes_count{handler="query_range"} 0 +http_request_size_bytes{handler="rules",quantile="0.5"} NaN +http_request_size_bytes{handler="rules",quantile="0.9"} NaN +http_request_size_bytes{handler="rules",quantile="0.99"} NaN +http_request_size_bytes_sum{handler="rules"} 0 +http_request_size_bytes_count{handler="rules"} 0 +http_request_size_bytes{handler="series",quantile="0.5"} NaN +http_request_size_bytes{handler="series",quantile="0.9"} NaN +http_request_size_bytes{handler="series",quantile="0.99"} NaN +http_request_size_bytes_sum{handler="series"} 0 +http_request_size_bytes_count{handler="series"} 0 +http_request_size_bytes{handler="static",quantile="0.5"} 379 +http_request_size_bytes{handler="static",quantile="0.9"} 379 +http_request_size_bytes{handler="static",quantile="0.99"} 379 +http_request_size_bytes_sum{handler="static"} 1137 +http_request_size_bytes_count{handler="static"} 3 +http_request_size_bytes{handler="status",quantile="0.5"} NaN +http_request_size_bytes{handler="status",quantile="0.9"} NaN +http_request_size_bytes{handler="status",quantile="0.99"} NaN +http_request_size_bytes_sum{handler="status"} 0 +http_request_size_bytes_count{handler="status"} 0 +http_request_size_bytes{handler="targets",quantile="0.5"} NaN +http_request_size_bytes{handler="targets",quantile="0.9"} NaN +http_request_size_bytes{handler="targets",quantile="0.99"} NaN +http_request_size_bytes_sum{handler="targets"} 0 +http_request_size_bytes_count{handler="targets"} 0 +http_request_size_bytes{handler="version",quantile="0.5"} NaN +http_request_size_bytes{handler="version",quantile="0.9"} NaN +http_request_size_bytes{handler="version",quantile="0.99"} NaN +http_request_size_bytes_sum{handler="version"} 0 +http_request_size_bytes_count{handler="version"} 0 +# HELP http_requests_total Total number of HTTP requests made. +# TYPE http_requests_total counter +http_requests_total{code="200",handler="graph",method="get"} 3 +http_requests_total{code="200",handler="label_values",method="get"} 3 +http_requests_total{code="200",handler="prometheus",method="get"} 462 +http_requests_total{code="200",handler="query",method="get"} 6 +http_requests_total{code="200",handler="static",method="get"} 3 +# HELP http_response_size_bytes The HTTP response sizes in bytes. +# TYPE http_response_size_bytes summary +http_response_size_bytes{handler="alerts",quantile="0.5"} NaN +http_response_size_bytes{handler="alerts",quantile="0.9"} NaN +http_response_size_bytes{handler="alerts",quantile="0.99"} NaN +http_response_size_bytes_sum{handler="alerts"} 0 +http_response_size_bytes_count{handler="alerts"} 0 +http_response_size_bytes{handler="config",quantile="0.5"} NaN +http_response_size_bytes{handler="config",quantile="0.9"} NaN +http_response_size_bytes{handler="config",quantile="0.99"} NaN +http_response_size_bytes_sum{handler="config"} 0 +http_response_size_bytes_count{handler="config"} 0 +http_response_size_bytes{handler="consoles",quantile="0.5"} NaN +http_response_size_bytes{handler="consoles",quantile="0.9"} NaN +http_response_size_bytes{handler="consoles",quantile="0.99"} NaN +http_response_size_bytes_sum{handler="consoles"} 0 +http_response_size_bytes_count{handler="consoles"} 0 +http_response_size_bytes{handler="drop_series",quantile="0.5"} NaN +http_response_size_bytes{handler="drop_series",quantile="0.9"} NaN +http_response_size_bytes{handler="drop_series",quantile="0.99"} NaN +http_response_size_bytes_sum{handler="drop_series"} 0 +http_response_size_bytes_count{handler="drop_series"} 0 +http_response_size_bytes{handler="federate",quantile="0.5"} NaN +http_response_size_bytes{handler="federate",quantile="0.9"} NaN +http_response_size_bytes{handler="federate",quantile="0.99"} NaN +http_response_size_bytes_sum{handler="federate"} 0 +http_response_size_bytes_count{handler="federate"} 0 +http_response_size_bytes{handler="flags",quantile="0.5"} NaN +http_response_size_bytes{handler="flags",quantile="0.9"} NaN +http_response_size_bytes{handler="flags",quantile="0.99"} NaN +http_response_size_bytes_sum{handler="flags"} 0 +http_response_size_bytes_count{handler="flags"} 0 +http_response_size_bytes{handler="graph",quantile="0.5"} 3619 +http_response_size_bytes{handler="graph",quantile="0.9"} 3619 +http_response_size_bytes{handler="graph",quantile="0.99"} 3619 +http_response_size_bytes_sum{handler="graph"} 10857 +http_response_size_bytes_count{handler="graph"} 3 +http_response_size_bytes{handler="heap",quantile="0.5"} NaN +http_response_size_bytes{handler="heap",quantile="0.9"} NaN +http_response_size_bytes{handler="heap",quantile="0.99"} NaN +http_response_size_bytes_sum{handler="heap"} 0 +http_response_size_bytes_count{handler="heap"} 0 +http_response_size_bytes{handler="label_values",quantile="0.5"} 642 +http_response_size_bytes{handler="label_values",quantile="0.9"} 642 +http_response_size_bytes{handler="label_values",quantile="0.99"} 642 +http_response_size_bytes_sum{handler="label_values"} 1926 +http_response_size_bytes_count{handler="label_values"} 3 +http_response_size_bytes{handler="options",quantile="0.5"} NaN +http_response_size_bytes{handler="options",quantile="0.9"} NaN +http_response_size_bytes{handler="options",quantile="0.99"} NaN +http_response_size_bytes_sum{handler="options"} 0 +http_response_size_bytes_count{handler="options"} 0 +http_response_size_bytes{handler="prometheus",quantile="0.5"} 3033 +http_response_size_bytes{handler="prometheus",quantile="0.9"} 3123 +http_response_size_bytes{handler="prometheus",quantile="0.99"} 3128 +http_response_size_bytes_sum{handler="prometheus"} 1.374097e+06 +http_response_size_bytes_count{handler="prometheus"} 462 +http_response_size_bytes{handler="query",quantile="0.5"} 776 +http_response_size_bytes{handler="query",quantile="0.9"} 781 +http_response_size_bytes{handler="query",quantile="0.99"} 781 +http_response_size_bytes_sum{handler="query"} 4656 +http_response_size_bytes_count{handler="query"} 6 +http_response_size_bytes{handler="query_range",quantile="0.5"} NaN +http_response_size_bytes{handler="query_range",quantile="0.9"} NaN +http_response_size_bytes{handler="query_range",quantile="0.99"} NaN +http_response_size_bytes_sum{handler="query_range"} 0 +http_response_size_bytes_count{handler="query_range"} 0 +http_response_size_bytes{handler="rules",quantile="0.5"} NaN +http_response_size_bytes{handler="rules",quantile="0.9"} NaN +http_response_size_bytes{handler="rules",quantile="0.99"} NaN +http_response_size_bytes_sum{handler="rules"} 0 +http_response_size_bytes_count{handler="rules"} 0 +http_response_size_bytes{handler="series",quantile="0.5"} NaN +http_response_size_bytes{handler="series",quantile="0.9"} NaN +http_response_size_bytes{handler="series",quantile="0.99"} NaN +http_response_size_bytes_sum{handler="series"} 0 +http_response_size_bytes_count{handler="series"} 0 +http_response_size_bytes{handler="static",quantile="0.5"} 6316 +http_response_size_bytes{handler="static",quantile="0.9"} 6316 +http_response_size_bytes{handler="static",quantile="0.99"} 6316 +http_response_size_bytes_sum{handler="static"} 18948 +http_response_size_bytes_count{handler="static"} 3 +http_response_size_bytes{handler="status",quantile="0.5"} NaN +http_response_size_bytes{handler="status",quantile="0.9"} NaN +http_response_size_bytes{handler="status",quantile="0.99"} NaN +http_response_size_bytes_sum{handler="status"} 0 +http_response_size_bytes_count{handler="status"} 0 +http_response_size_bytes{handler="targets",quantile="0.5"} NaN +http_response_size_bytes{handler="targets",quantile="0.9"} NaN +http_response_size_bytes{handler="targets",quantile="0.99"} NaN +http_response_size_bytes_sum{handler="targets"} 0 +http_response_size_bytes_count{handler="targets"} 0 +http_response_size_bytes{handler="version",quantile="0.5"} NaN +http_response_size_bytes{handler="version",quantile="0.9"} NaN +http_response_size_bytes{handler="version",quantile="0.99"} NaN +http_response_size_bytes_sum{handler="version"} 0 +http_response_size_bytes_count{handler="version"} 0 +# HELP prometheus_build_info A metric with a constant '1' value labeled by version, revision, branch, and goversion from which prometheus was built. +# TYPE prometheus_build_info gauge +prometheus_build_info{branch="",goversion="go1.7.3",revision="",version=""} 1 +# HELP prometheus_config_last_reload_success_timestamp_seconds Timestamp of the last successful configuration reload. +# TYPE prometheus_config_last_reload_success_timestamp_seconds gauge +prometheus_config_last_reload_success_timestamp_seconds 1.484395547e+09 +# HELP prometheus_config_last_reload_successful Whether the last configuration reload attempt was successful. +# TYPE prometheus_config_last_reload_successful gauge +prometheus_config_last_reload_successful 1 +# HELP prometheus_evaluator_duration_seconds The duration of rule group evaluations. +# TYPE prometheus_evaluator_duration_seconds summary +prometheus_evaluator_duration_seconds{quantile="0.01"} 1.7890000000000002e-06 +prometheus_evaluator_duration_seconds{quantile="0.05"} 1.7890000000000002e-06 +prometheus_evaluator_duration_seconds{quantile="0.5"} 1.7890000000000002e-06 +prometheus_evaluator_duration_seconds{quantile="0.9"} 1.7890000000000002e-06 +prometheus_evaluator_duration_seconds{quantile="0.99"} 1.7890000000000002e-06 +prometheus_evaluator_duration_seconds_sum 1.7890000000000002e-06 +prometheus_evaluator_duration_seconds_count 1 +# HELP prometheus_evaluator_iterations_skipped_total The total number of rule group evaluations skipped due to throttled metric storage. +# TYPE prometheus_evaluator_iterations_skipped_total counter +prometheus_evaluator_iterations_skipped_total 0 +# HELP prometheus_notifications_dropped_total Total number of alerts dropped due to alert manager missing in configuration. +# TYPE prometheus_notifications_dropped_total counter +prometheus_notifications_dropped_total 0 +# HELP prometheus_notifications_queue_capacity The capacity of the alert notifications queue. +# TYPE prometheus_notifications_queue_capacity gauge +prometheus_notifications_queue_capacity 10000 +# HELP prometheus_notifications_queue_length The number of alert notifications in the queue. +# TYPE prometheus_notifications_queue_length gauge +prometheus_notifications_queue_length 0 +# HELP prometheus_rule_evaluation_failures_total The total number of rule evaluation failures. +# TYPE prometheus_rule_evaluation_failures_total counter +prometheus_rule_evaluation_failures_total{rule_type="alerting"} 0 +prometheus_rule_evaluation_failures_total{rule_type="recording"} 0 +# HELP prometheus_sd_azure_refresh_duration_seconds The duration of a Azure-SD refresh in seconds. +# TYPE prometheus_sd_azure_refresh_duration_seconds summary +prometheus_sd_azure_refresh_duration_seconds{quantile="0.5"} NaN +prometheus_sd_azure_refresh_duration_seconds{quantile="0.9"} NaN +prometheus_sd_azure_refresh_duration_seconds{quantile="0.99"} NaN +prometheus_sd_azure_refresh_duration_seconds_sum 0 +prometheus_sd_azure_refresh_duration_seconds_count 0 +# HELP prometheus_sd_azure_refresh_failures_total Number of Azure-SD refresh failures. +# TYPE prometheus_sd_azure_refresh_failures_total counter +prometheus_sd_azure_refresh_failures_total 0 +# HELP prometheus_sd_consul_rpc_duration_seconds The duration of a Consul RPC call in seconds. +# TYPE prometheus_sd_consul_rpc_duration_seconds summary +prometheus_sd_consul_rpc_duration_seconds{call="service",endpoint="catalog",quantile="0.5"} NaN +prometheus_sd_consul_rpc_duration_seconds{call="service",endpoint="catalog",quantile="0.9"} NaN +prometheus_sd_consul_rpc_duration_seconds{call="service",endpoint="catalog",quantile="0.99"} NaN +prometheus_sd_consul_rpc_duration_seconds_sum{call="service",endpoint="catalog"} 0 +prometheus_sd_consul_rpc_duration_seconds_count{call="service",endpoint="catalog"} 0 +prometheus_sd_consul_rpc_duration_seconds{call="services",endpoint="catalog",quantile="0.5"} NaN +prometheus_sd_consul_rpc_duration_seconds{call="services",endpoint="catalog",quantile="0.9"} NaN +prometheus_sd_consul_rpc_duration_seconds{call="services",endpoint="catalog",quantile="0.99"} NaN +prometheus_sd_consul_rpc_duration_seconds_sum{call="services",endpoint="catalog"} 0 +prometheus_sd_consul_rpc_duration_seconds_count{call="services",endpoint="catalog"} 0 +# HELP prometheus_sd_consul_rpc_failures_total The number of Consul RPC call failures. +# TYPE prometheus_sd_consul_rpc_failures_total counter +prometheus_sd_consul_rpc_failures_total 0 +# HELP prometheus_sd_dns_lookup_failures_total The number of DNS-SD lookup failures. +# TYPE prometheus_sd_dns_lookup_failures_total counter +prometheus_sd_dns_lookup_failures_total 0 +# HELP prometheus_sd_dns_lookups_total The number of DNS-SD lookups. +# TYPE prometheus_sd_dns_lookups_total counter +prometheus_sd_dns_lookups_total 0 +# HELP prometheus_sd_ec2_refresh_duration_seconds The duration of a EC2-SD refresh in seconds. +# TYPE prometheus_sd_ec2_refresh_duration_seconds summary +prometheus_sd_ec2_refresh_duration_seconds{quantile="0.5"} NaN +prometheus_sd_ec2_refresh_duration_seconds{quantile="0.9"} NaN +prometheus_sd_ec2_refresh_duration_seconds{quantile="0.99"} NaN +prometheus_sd_ec2_refresh_duration_seconds_sum 0 +prometheus_sd_ec2_refresh_duration_seconds_count 0 +# HELP prometheus_sd_ec2_refresh_failures_total The number of EC2-SD scrape failures. +# TYPE prometheus_sd_ec2_refresh_failures_total counter +prometheus_sd_ec2_refresh_failures_total 0 +# HELP prometheus_sd_file_read_errors_total The number of File-SD read errors. +# TYPE prometheus_sd_file_read_errors_total counter +prometheus_sd_file_read_errors_total 0 +# HELP prometheus_sd_file_scan_duration_seconds The duration of the File-SD scan in seconds. +# TYPE prometheus_sd_file_scan_duration_seconds summary +prometheus_sd_file_scan_duration_seconds{quantile="0.5"} NaN +prometheus_sd_file_scan_duration_seconds{quantile="0.9"} NaN +prometheus_sd_file_scan_duration_seconds{quantile="0.99"} NaN +prometheus_sd_file_scan_duration_seconds_sum 0 +prometheus_sd_file_scan_duration_seconds_count 0 +# HELP prometheus_sd_gce_refresh_duration The duration of a GCE-SD refresh in seconds. +# TYPE prometheus_sd_gce_refresh_duration summary +prometheus_sd_gce_refresh_duration{quantile="0.5"} NaN +prometheus_sd_gce_refresh_duration{quantile="0.9"} NaN +prometheus_sd_gce_refresh_duration{quantile="0.99"} NaN +prometheus_sd_gce_refresh_duration_sum 0 +prometheus_sd_gce_refresh_duration_count 0 +# HELP prometheus_sd_gce_refresh_failures_total The number of GCE-SD refresh failures. +# TYPE prometheus_sd_gce_refresh_failures_total counter +prometheus_sd_gce_refresh_failures_total 0 +# HELP prometheus_sd_kubernetes_events_total The number of Kubernetes events handled. +# TYPE prometheus_sd_kubernetes_events_total counter +prometheus_sd_kubernetes_events_total{event="add",role="endpoints"} 0 +prometheus_sd_kubernetes_events_total{event="add",role="node"} 0 +prometheus_sd_kubernetes_events_total{event="add",role="pod"} 0 +prometheus_sd_kubernetes_events_total{event="add",role="service"} 0 +prometheus_sd_kubernetes_events_total{event="delete",role="endpoints"} 0 +prometheus_sd_kubernetes_events_total{event="delete",role="node"} 0 +prometheus_sd_kubernetes_events_total{event="delete",role="pod"} 0 +prometheus_sd_kubernetes_events_total{event="delete",role="service"} 0 +prometheus_sd_kubernetes_events_total{event="update",role="endpoints"} 0 +prometheus_sd_kubernetes_events_total{event="update",role="node"} 0 +prometheus_sd_kubernetes_events_total{event="update",role="pod"} 0 +prometheus_sd_kubernetes_events_total{event="update",role="service"} 0 +# HELP prometheus_sd_marathon_refresh_duration_seconds The duration of a Marathon-SD refresh in seconds. +# TYPE prometheus_sd_marathon_refresh_duration_seconds summary +prometheus_sd_marathon_refresh_duration_seconds{quantile="0.5"} NaN +prometheus_sd_marathon_refresh_duration_seconds{quantile="0.9"} NaN +prometheus_sd_marathon_refresh_duration_seconds{quantile="0.99"} NaN +prometheus_sd_marathon_refresh_duration_seconds_sum 0 +prometheus_sd_marathon_refresh_duration_seconds_count 0 +# HELP prometheus_sd_marathon_refresh_failures_total The number of Marathon-SD refresh failures. +# TYPE prometheus_sd_marathon_refresh_failures_total counter +prometheus_sd_marathon_refresh_failures_total 0 +# HELP prometheus_target_interval_length_seconds Actual intervals between scrapes. +# TYPE prometheus_target_interval_length_seconds summary +prometheus_target_interval_length_seconds{interval="50ms",quantile="0.01"} 0.046182157 +prometheus_target_interval_length_seconds{interval="50ms",quantile="0.05"} 0.047306979000000006 +prometheus_target_interval_length_seconds{interval="50ms",quantile="0.5"} 0.050381782 +prometheus_target_interval_length_seconds{interval="50ms",quantile="0.9"} 0.052614556 +prometheus_target_interval_length_seconds{interval="50ms",quantile="0.99"} 0.054404386000000006 +prometheus_target_interval_length_seconds_sum{interval="50ms"} 34.512091221999995 +prometheus_target_interval_length_seconds_count{interval="50ms"} 685 +# HELP prometheus_target_scrape_pool_sync_total Total number of syncs that were executed on a scrape pool. +# TYPE prometheus_target_scrape_pool_sync_total counter +prometheus_target_scrape_pool_sync_total{scrape_job="prometheus"} 1 +# HELP prometheus_target_skipped_scrapes_total Total number of scrapes that were skipped because the metric storage was throttled. +# TYPE prometheus_target_skipped_scrapes_total counter +prometheus_target_skipped_scrapes_total 0 +# HELP prometheus_target_sync_length_seconds Actual interval to sync the scrape pool. +# TYPE prometheus_target_sync_length_seconds summary +prometheus_target_sync_length_seconds{scrape_job="prometheus",quantile="0.01"} 0.00020043300000000002 +prometheus_target_sync_length_seconds{scrape_job="prometheus",quantile="0.05"} 0.00020043300000000002 +prometheus_target_sync_length_seconds{scrape_job="prometheus",quantile="0.5"} 0.00020043300000000002 +prometheus_target_sync_length_seconds{scrape_job="prometheus",quantile="0.9"} 0.00020043300000000002 +prometheus_target_sync_length_seconds{scrape_job="prometheus",quantile="0.99"} 0.00020043300000000002 +prometheus_target_sync_length_seconds_sum{scrape_job="prometheus"} 0.00020043300000000002 +prometheus_target_sync_length_seconds_count{scrape_job="prometheus"} 1 +# HELP prometheus_treecache_watcher_goroutines The current number of watcher goroutines. +# TYPE prometheus_treecache_watcher_goroutines gauge +prometheus_treecache_watcher_goroutines 0 +# HELP prometheus_treecache_zookeeper_failures_total The total number of ZooKeeper failures. +# TYPE prometheus_treecache_zookeeper_failures_total counter +prometheus_treecache_zookeeper_failures_total 0
\ No newline at end of file |