Merge pull request #385 from prometheus/beorn7/auto
Add a package promauto that provides auto-registering metrics
This commit is contained in:
commit
e69720d204
|
@ -14,7 +14,9 @@
|
||||||
// Package prometheus is the core instrumentation package. It provides metrics
|
// Package prometheus is the core instrumentation package. It provides metrics
|
||||||
// primitives to instrument code for monitoring. It also offers a registry for
|
// primitives to instrument code for monitoring. It also offers a registry for
|
||||||
// metrics. Sub-packages allow to expose the registered metrics via HTTP
|
// metrics. Sub-packages allow to expose the registered metrics via HTTP
|
||||||
// (package promhttp) or push them to a Pushgateway (package push).
|
// (package promhttp) or push them to a Pushgateway (package push). There is
|
||||||
|
// also a sub-package promauto, which provides metrics constructors with
|
||||||
|
// automatic registration.
|
||||||
//
|
//
|
||||||
// All exported functions and methods are safe to be used concurrently unless
|
// All exported functions and methods are safe to be used concurrently unless
|
||||||
// specified otherwise.
|
// specified otherwise.
|
||||||
|
@ -72,7 +74,10 @@
|
||||||
// The number of exported identifiers in this package might appear a bit
|
// The number of exported identifiers in this package might appear a bit
|
||||||
// overwhelming. However, in addition to the basic plumbing shown in the example
|
// overwhelming. However, in addition to the basic plumbing shown in the example
|
||||||
// above, you only need to understand the different metric types and their
|
// above, you only need to understand the different metric types and their
|
||||||
// vector versions for basic usage.
|
// vector versions for basic usage. Furthermore, if you are not concerned with
|
||||||
|
// fine-grained control of when and how to register metrics with the registry,
|
||||||
|
// have a look at the promauto package, which will effectively allow you to
|
||||||
|
// ignore registration altogether in simple cases.
|
||||||
//
|
//
|
||||||
// Above, you have already touched the Counter and the Gauge. There are two more
|
// Above, you have already touched the Counter and the Gauge. There are two more
|
||||||
// advanced metric types: the Summary and Histogram. A more thorough description
|
// advanced metric types: the Summary and Histogram. A more thorough description
|
||||||
|
|
|
@ -0,0 +1,204 @@
|
||||||
|
// Copyright 2018 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 promauto provides constructors for the usual Prometheus metrics that
|
||||||
|
// return them already registered with the global registry
|
||||||
|
// (prometheus.DefaultRegisterer). This allows very compact code, avoiding any
|
||||||
|
// references to the registry altogether, but all the constructors in this
|
||||||
|
// package will panic if the registration fails.
|
||||||
|
//
|
||||||
|
// The following example is a complete program to create a histogram of normally
|
||||||
|
// distributed random numbers from the math/rand package:
|
||||||
|
//
|
||||||
|
// package main
|
||||||
|
//
|
||||||
|
// import (
|
||||||
|
// "math/rand"
|
||||||
|
// "net/http"
|
||||||
|
//
|
||||||
|
// "github.com/prometheus/client_golang/prometheus"
|
||||||
|
// "github.com/prometheus/client_golang/prometheus/promauto"
|
||||||
|
// "github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
|
// )
|
||||||
|
//
|
||||||
|
// var histogram = promauto.NewHistogram(prometheus.HistogramOpts{
|
||||||
|
// Name: "random_numbers",
|
||||||
|
// Help: "A histogram of normally distributed random numbers.",
|
||||||
|
// Buckets: prometheus.LinearBuckets(-3, .1, 61),
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// func Random() {
|
||||||
|
// for {
|
||||||
|
// histogram.Observe(rand.NormFloat64())
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func main() {
|
||||||
|
// go Random()
|
||||||
|
// http.Handle("/metrics", promhttp.Handler())
|
||||||
|
// http.ListenAndServe(":1971", nil)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Prometheus's version of a minimal hello-world program:
|
||||||
|
//
|
||||||
|
// package main
|
||||||
|
//
|
||||||
|
// import (
|
||||||
|
// "fmt"
|
||||||
|
// "net/http"
|
||||||
|
//
|
||||||
|
// "github.com/prometheus/client_golang/prometheus"
|
||||||
|
// "github.com/prometheus/client_golang/prometheus/promauto"
|
||||||
|
// "github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
|
// )
|
||||||
|
//
|
||||||
|
// func main() {
|
||||||
|
// http.Handle("/", promhttp.InstrumentHandlerCounter(
|
||||||
|
// promauto.NewCounterVec(
|
||||||
|
// prometheus.CounterOpts{
|
||||||
|
// Name: "hello_requests_total",
|
||||||
|
// Help: "Total number of hello-world requests by HTTP code.",
|
||||||
|
// },
|
||||||
|
// []string{"code"},
|
||||||
|
// ),
|
||||||
|
// http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// fmt.Fprint(w, "Hello, world!")
|
||||||
|
// }),
|
||||||
|
// ))
|
||||||
|
// http.Handle("/metrics", promhttp.Handler())
|
||||||
|
// http.ListenAndServe(":1971", nil)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// This appears very handy. So why are these constructors locked away in a
|
||||||
|
// separate package? There are two caveats:
|
||||||
|
//
|
||||||
|
// First, in more complex programs, global state is often quite problematic.
|
||||||
|
// That's the reason why the metrics constructors in the prometheus package do
|
||||||
|
// not interact with the global prometheus.DefaultRegisterer on their own. You
|
||||||
|
// are free to use the Register or MustRegister functions to register them with
|
||||||
|
// the global prometheus.DefaultRegisterer, but you could as well choose a local
|
||||||
|
// Registerer (usually created with prometheus.NewRegistry, but there are other
|
||||||
|
// scenarios, e.g. testing).
|
||||||
|
//
|
||||||
|
// The second issue is that registration may fail, e.g. if a metric inconsistent
|
||||||
|
// with the newly to be registered one is already registered. But how to signal
|
||||||
|
// and handle a panic in the automatic registration with the default registry?
|
||||||
|
// The only way is panicking. While panicking on invalid input provided by the
|
||||||
|
// programmer is certainly fine, things are a bit more subtle in this case: You
|
||||||
|
// might just add another package to the program, and that package (in its init
|
||||||
|
// function) happens to register a metric with the same name as your code. Now,
|
||||||
|
// all of a sudden, either your code or the code of the newly imported package
|
||||||
|
// panics, depending on initialization order, without any opportunity to handle
|
||||||
|
// the case gracefully. Even worse is a scenario where registration happens
|
||||||
|
// later during the runtime (e.g. upon loading some kind of plugin), where the
|
||||||
|
// panic could be triggered long after the code has been deployed to
|
||||||
|
// production. A possibility to panic should be explicitly called out by the
|
||||||
|
// Must… idiom, cf. prometheus.MustRegister. But adding a separate set of
|
||||||
|
// constructors in the prometheus package called MustRegisterNewCounterVec or
|
||||||
|
// similar would be quite unwieldy. Adding an extra MustRegister method to each
|
||||||
|
// metric, returning the registered metric, would result in nice code for those
|
||||||
|
// using the method, but would pollute every single metric interface for
|
||||||
|
// everybody avoiding the global registry.
|
||||||
|
//
|
||||||
|
// To address both issues, the problematic auto-registering and possibly
|
||||||
|
// panicking constructors are all in this package with a clear warning
|
||||||
|
// ahead. And whoever cares about avoiding global state and possibly panicking
|
||||||
|
// function calls can simply ignore the existence of the promauto package
|
||||||
|
// altogether.
|
||||||
|
//
|
||||||
|
// A final note: There is a similar case in the net/http package of the standard
|
||||||
|
// library. It has DefaultServeMux as a global instance of ServeMux, and the
|
||||||
|
// Handle function acts on it, panicking if a handler for the same pattern has
|
||||||
|
// already been registered. However, one might argue that the whole HTTP routing
|
||||||
|
// is usually set up closely together in the same package or file, while
|
||||||
|
// Prometheus metrics tend to be spread widely over the codebase, increasing the
|
||||||
|
// chance of surprising registration failures. Furthermore, the use of global
|
||||||
|
// state in net/http has been criticized widely, and some avoid it altogether.
|
||||||
|
package promauto
|
||||||
|
|
||||||
|
import "github.com/prometheus/client_golang/prometheus"
|
||||||
|
|
||||||
|
// NewCounter works like the function of the same name in the prometheus package
|
||||||
|
// but it automatically registers the Counter with the
|
||||||
|
// prometheus.DefaultRegisterer. If the registration fails, NewCounter panics.
|
||||||
|
func NewCounter(opts prometheus.CounterOpts) prometheus.Counter {
|
||||||
|
c := prometheus.NewCounter(opts)
|
||||||
|
prometheus.MustRegister(c)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCounterVec works like the function of the same name in the prometheus
|
||||||
|
// package but it automatically registers the CounterVec with the
|
||||||
|
// prometheus.DefaultRegisterer. If the registration fails, NewCounterVec
|
||||||
|
// panics.
|
||||||
|
func NewCounterVec(opts prometheus.CounterOpts, labelNames []string) *prometheus.CounterVec {
|
||||||
|
c := prometheus.NewCounterVec(opts, labelNames)
|
||||||
|
prometheus.MustRegister(c)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGauge works like the function of the same name in the prometheus package
|
||||||
|
// but it automatically registers the Gauge with the
|
||||||
|
// prometheus.DefaultRegisterer. If the registration fails, NewGauge panics.
|
||||||
|
func NewGauge(opts prometheus.GaugeOpts) prometheus.Gauge {
|
||||||
|
g := prometheus.NewGauge(opts)
|
||||||
|
prometheus.MustRegister(g)
|
||||||
|
return g
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGaugeVec works like the function of the same name in the prometheus
|
||||||
|
// package but it automatically registers the GaugeVec with the
|
||||||
|
// prometheus.DefaultRegisterer. If the registration fails, NewGaugeVec panics.
|
||||||
|
func NewGaugeVec(opts prometheus.GaugeOpts, labelNames []string) *prometheus.GaugeVec {
|
||||||
|
g := prometheus.NewGaugeVec(opts, labelNames)
|
||||||
|
prometheus.MustRegister(g)
|
||||||
|
return g
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSummary works like the function of the same name in the prometheus package
|
||||||
|
// but it automatically registers the Summary with the
|
||||||
|
// prometheus.DefaultRegisterer. If the registration fails, NewSummary panics.
|
||||||
|
func NewSummary(opts prometheus.SummaryOpts) prometheus.Summary {
|
||||||
|
s := prometheus.NewSummary(opts)
|
||||||
|
prometheus.MustRegister(s)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSummaryVec works like the function of the same name in the prometheus
|
||||||
|
// package but it automatically registers the SummaryVec with the
|
||||||
|
// prometheus.DefaultRegisterer. If the registration fails, NewSummaryVec
|
||||||
|
// panics.
|
||||||
|
func NewSummaryVec(opts prometheus.SummaryOpts, labelNames []string) *prometheus.SummaryVec {
|
||||||
|
s := prometheus.NewSummaryVec(opts, labelNames)
|
||||||
|
prometheus.MustRegister(s)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewHistogram works like the function of the same name in the prometheus
|
||||||
|
// package but it automatically registers the Histogram with the
|
||||||
|
// prometheus.DefaultRegisterer. If the registration fails, NewHistogram panics.
|
||||||
|
func NewHistogram(opts prometheus.HistogramOpts) prometheus.Histogram {
|
||||||
|
h := prometheus.NewHistogram(opts)
|
||||||
|
prometheus.MustRegister(h)
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewHistogramVec works like the function of the same name in the prometheus
|
||||||
|
// package but it automatically registers the HistogramVec with the
|
||||||
|
// prometheus.DefaultRegisterer. If the registration fails, NewHistogramVec
|
||||||
|
// panics.
|
||||||
|
func NewHistogramVec(opts prometheus.HistogramOpts, labelNames []string) *prometheus.HistogramVec {
|
||||||
|
h := prometheus.NewHistogramVec(opts, labelNames)
|
||||||
|
prometheus.MustRegister(h)
|
||||||
|
return h
|
||||||
|
}
|
Loading…
Reference in New Issue