Skip to content

Commit

Permalink
Merge pull request #803 from prometheus/beorn7/vec
Browse files Browse the repository at this point in the history
Export MetricVec (again)
  • Loading branch information
beorn7 committed Oct 15, 2020
2 parents 6007b2b + 85aa957 commit e6ea98b
Show file tree
Hide file tree
Showing 8 changed files with 306 additions and 68 deletions.
20 changes: 10 additions & 10 deletions prometheus/counter.go
Expand Up @@ -163,7 +163,7 @@ func (c *counter) updateExemplar(v float64, l Labels) {
// (e.g. number of HTTP requests, partitioned by response code and
// method). Create instances with NewCounterVec.
type CounterVec struct {
*metricVec
*MetricVec
}

// NewCounterVec creates a new CounterVec based on the provided CounterOpts and
Expand All @@ -176,19 +176,19 @@ func NewCounterVec(opts CounterOpts, labelNames []string) *CounterVec {
opts.ConstLabels,
)
return &CounterVec{
metricVec: newMetricVec(desc, func(lvs ...string) Metric {
MetricVec: NewMetricVec(desc, func(lvs ...string) Metric {
if len(lvs) != len(desc.variableLabels) {
panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, lvs))
}
result := &counter{desc: desc, labelPairs: makeLabelPairs(desc, lvs), now: time.Now}
result := &counter{desc: desc, labelPairs: MakeLabelPairs(desc, lvs), now: time.Now}
result.init(result) // Init self-collection.
return result
}),
}
}

// GetMetricWithLabelValues returns the Counter for the given slice of label
// values (same order as the VariableLabels in Desc). If that combination of
// values (same order as the variable labels in Desc). If that combination of
// label values is accessed for the first time, a new Counter is created.
//
// It is possible to call this method without using the returned Counter to only
Expand All @@ -202,7 +202,7 @@ func NewCounterVec(opts CounterOpts, labelNames []string) *CounterVec {
// Counter with the same label values is created later.
//
// An error is returned if the number of label values is not the same as the
// number of VariableLabels in Desc (minus any curried labels).
// number of variable labels in Desc (minus any curried labels).
//
// Note that for more than one label value, this method is prone to mistakes
// caused by an incorrect order of arguments. Consider GetMetricWith(Labels) as
Expand All @@ -211,27 +211,27 @@ func NewCounterVec(opts CounterOpts, labelNames []string) *CounterVec {
// with a performance overhead (for creating and processing the Labels map).
// See also the GaugeVec example.
func (v *CounterVec) GetMetricWithLabelValues(lvs ...string) (Counter, error) {
metric, err := v.metricVec.getMetricWithLabelValues(lvs...)
metric, err := v.MetricVec.GetMetricWithLabelValues(lvs...)
if metric != nil {
return metric.(Counter), err
}
return nil, err
}

// GetMetricWith returns the Counter for the given Labels map (the label names
// must match those of the VariableLabels in Desc). If that label map is
// must match those of the variable labels in Desc). If that label map is
// accessed for the first time, a new Counter is created. Implications of
// creating a Counter without using it and keeping the Counter for later use are
// the same as for GetMetricWithLabelValues.
//
// An error is returned if the number and names of the Labels are inconsistent
// with those of the VariableLabels in Desc (minus any curried labels).
// with those of the variable labels in Desc (minus any curried labels).
//
// This method is used for the same purpose as
// GetMetricWithLabelValues(...string). See there for pros and cons of the two
// methods.
func (v *CounterVec) GetMetricWith(labels Labels) (Counter, error) {
metric, err := v.metricVec.getMetricWith(labels)
metric, err := v.MetricVec.GetMetricWith(labels)
if metric != nil {
return metric.(Counter), err
}
Expand Down Expand Up @@ -275,7 +275,7 @@ func (v *CounterVec) With(labels Labels) Counter {
// registered with a given registry (usually the uncurried version). The Reset
// method deletes all metrics, even if called on a curried vector.
func (v *CounterVec) CurryWith(labels Labels) (*CounterVec, error) {
vec, err := v.curryWith(labels)
vec, err := v.MetricVec.CurryWith(labels)
if vec != nil {
return &CounterVec{vec}, err
}
Expand Down
2 changes: 1 addition & 1 deletion prometheus/desc.go
Expand Up @@ -51,7 +51,7 @@ type Desc struct {
// constLabelPairs contains precalculated DTO label pairs based on
// the constant labels.
constLabelPairs []*dto.LabelPair
// VariableLabels contains names of labels for which the metric
// variableLabels contains names of labels for which the metric
// maintains variable values.
variableLabels []string
// id is a hash of the values of the ConstLabels and fqName. This
Expand Down
163 changes: 163 additions & 0 deletions prometheus/example_metricvec_test.go
@@ -0,0 +1,163 @@
// Copyright 2020 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package prometheus_test

import (
//lint:ignore SA1019 Need to keep deprecated package for compatibility.
"fmt"

"github.com/golang/protobuf/proto"

dto "github.com/prometheus/client_model/go"

"github.com/prometheus/client_golang/prometheus"
)

// Info implements an info pseudo-metric, which is modeled as a Gauge that
// always has a value of 1. In practice, you would just use a Gauge directly,
// but for this example, we pretend it would be useful to have a “native”
// implementation.
type Info struct {
desc *prometheus.Desc
labelPairs []*dto.LabelPair
}

func (i Info) Desc() *prometheus.Desc {
return i.desc
}

func (i Info) Write(out *dto.Metric) error {
out.Label = i.labelPairs
out.Gauge = &dto.Gauge{Value: proto.Float64(1)}
return nil
}

// InfoVec is the vector version for Info. As an info metric never changes, we
// wouldn't really need to wrap GetMetricWithLabelValues and GetMetricWith
// because Info has no additional methods compared to the vanilla Metric that
// the unwrapped MetricVec methods return. However, to demonstrate all there is
// to do to fully implement a vector for a custom Metric implementation, we do
// it in this example anyway.
type InfoVec struct {
*prometheus.MetricVec
}

func NewInfoVec(name, help string, labelNames []string) *InfoVec {
desc := prometheus.NewDesc(name, help, labelNames, nil)
return &InfoVec{
MetricVec: prometheus.NewMetricVec(desc, func(lvs ...string) prometheus.Metric {
if len(lvs) != len(labelNames) {
panic("inconsistent label cardinality")
}
return Info{desc: desc, labelPairs: prometheus.MakeLabelPairs(desc, lvs)}
}),
}
}

func (v *InfoVec) GetMetricWithLabelValues(lvs ...string) (Info, error) {
metric, err := v.MetricVec.GetMetricWithLabelValues(lvs...)
return metric.(Info), err
}

func (v *InfoVec) GetMetricWith(labels prometheus.Labels) (Info, error) {
metric, err := v.MetricVec.GetMetricWith(labels)
return metric.(Info), err
}

func (v *InfoVec) WithLabelValues(lvs ...string) Info {
i, err := v.GetMetricWithLabelValues(lvs...)
if err != nil {
panic(err)
}
return i
}

func (v *InfoVec) With(labels prometheus.Labels) Info {
i, err := v.GetMetricWith(labels)
if err != nil {
panic(err)
}
return i
}

func (v *InfoVec) CurryWith(labels prometheus.Labels) (*InfoVec, error) {
vec, err := v.MetricVec.CurryWith(labels)
if vec != nil {
return &InfoVec{vec}, err
}
return nil, err
}

func (v *InfoVec) MustCurryWith(labels prometheus.Labels) *InfoVec {
vec, err := v.CurryWith(labels)
if err != nil {
panic(err)
}
return vec
}

func ExampleMetricVec() {

infoVec := NewInfoVec(
"library_version_info",
"Versions of the libraries used in this binary.",
[]string{"library", "version"},
)

infoVec.WithLabelValues("prometheus/client_golang", "1.7.1")
infoVec.WithLabelValues("k8s.io/client-go", "0.18.8")

// Just for demonstration, let's check the state of the InfoVec by
// registering it with a custom registry and then let it collect the
// metrics.
reg := prometheus.NewRegistry()
reg.MustRegister(infoVec)

metricFamilies, err := reg.Gather()
if err != nil || len(metricFamilies) != 1 {
panic("unexpected behavior of custom test registry")
}
fmt.Println(proto.MarshalTextString(metricFamilies[0]))

// Output:
// name: "library_version_info"
// help: "Versions of the libraries used in this binary."
// type: GAUGE
// metric: <
// label: <
// name: "library"
// value: "k8s.io/client-go"
// >
// label: <
// name: "version"
// value: "0.18.8"
// >
// gauge: <
// value: 1
// >
// >
// metric: <
// label: <
// name: "library"
// value: "prometheus/client_golang"
// >
// label: <
// name: "version"
// value: "1.7.1"
// >
// gauge: <
// value: 1
// >
// >
}
20 changes: 10 additions & 10 deletions prometheus/gauge.go
Expand Up @@ -132,7 +132,7 @@ func (g *gauge) Write(out *dto.Metric) error {
// (e.g. number of operations queued, partitioned by user and operation
// type). Create instances with NewGaugeVec.
type GaugeVec struct {
*metricVec
*MetricVec
}

// NewGaugeVec creates a new GaugeVec based on the provided GaugeOpts and
Expand All @@ -145,19 +145,19 @@ func NewGaugeVec(opts GaugeOpts, labelNames []string) *GaugeVec {
opts.ConstLabels,
)
return &GaugeVec{
metricVec: newMetricVec(desc, func(lvs ...string) Metric {
MetricVec: NewMetricVec(desc, func(lvs ...string) Metric {
if len(lvs) != len(desc.variableLabels) {
panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, lvs))
}
result := &gauge{desc: desc, labelPairs: makeLabelPairs(desc, lvs)}
result := &gauge{desc: desc, labelPairs: MakeLabelPairs(desc, lvs)}
result.init(result) // Init self-collection.
return result
}),
}
}

// GetMetricWithLabelValues returns the Gauge for the given slice of label
// values (same order as the VariableLabels in Desc). If that combination of
// values (same order as the variable labels in Desc). If that combination of
// label values is accessed for the first time, a new Gauge is created.
//
// It is possible to call this method without using the returned Gauge to only
Expand All @@ -172,35 +172,35 @@ func NewGaugeVec(opts GaugeOpts, labelNames []string) *GaugeVec {
// example.
//
// An error is returned if the number of label values is not the same as the
// number of VariableLabels in Desc (minus any curried labels).
// number of variable labels in Desc (minus any curried labels).
//
// Note that for more than one label value, this method is prone to mistakes
// caused by an incorrect order of arguments. Consider GetMetricWith(Labels) as
// an alternative to avoid that type of mistake. For higher label numbers, the
// latter has a much more readable (albeit more verbose) syntax, but it comes
// with a performance overhead (for creating and processing the Labels map).
func (v *GaugeVec) GetMetricWithLabelValues(lvs ...string) (Gauge, error) {
metric, err := v.metricVec.getMetricWithLabelValues(lvs...)
metric, err := v.MetricVec.GetMetricWithLabelValues(lvs...)
if metric != nil {
return metric.(Gauge), err
}
return nil, err
}

// GetMetricWith returns the Gauge for the given Labels map (the label names
// must match those of the VariableLabels in Desc). If that label map is
// must match those of the variable labels in Desc). If that label map is
// accessed for the first time, a new Gauge is created. Implications of
// creating a Gauge without using it and keeping the Gauge for later use are
// the same as for GetMetricWithLabelValues.
//
// An error is returned if the number and names of the Labels are inconsistent
// with those of the VariableLabels in Desc (minus any curried labels).
// with those of the variable labels in Desc (minus any curried labels).
//
// This method is used for the same purpose as
// GetMetricWithLabelValues(...string). See there for pros and cons of the two
// methods.
func (v *GaugeVec) GetMetricWith(labels Labels) (Gauge, error) {
metric, err := v.metricVec.getMetricWith(labels)
metric, err := v.MetricVec.GetMetricWith(labels)
if metric != nil {
return metric.(Gauge), err
}
Expand Down Expand Up @@ -244,7 +244,7 @@ func (v *GaugeVec) With(labels Labels) Gauge {
// registered with a given registry (usually the uncurried version). The Reset
// method deletes all metrics, even if called on a curried vector.
func (v *GaugeVec) CurryWith(labels Labels) (*GaugeVec, error) {
vec, err := v.curryWith(labels)
vec, err := v.MetricVec.CurryWith(labels)
if vec != nil {
return &GaugeVec{vec}, err
}
Expand Down

0 comments on commit e6ea98b

Please sign in to comment.