Documentation ¶
Overview ¶
Package pally is a simple, atomic-based metrics library. It interoperates seamlessly with both Prometheus and Tally, providing ready-to-use Prometheus text and Protocol Buffer endpoints, differential updates to StatsD- or M3-based systems, and excellent performance along the hot path.
Metric Names ¶
Pally requires that all metric names and labels be valid both in Tally and in Prometheus. Concretely, this means that metric names, label keys, and label values should match the regular expression `^[a-zA-Z_][a-zA-Z0-9_]*$`.
Counters And Gauges ¶
Pally offers two simple metric types: counters and gauges. Counters represent an ever-accumulating total, like a car's odometer. Gauges represent a point-in-time measurement, like a car's speedometer. In Pally, both counters and gauges must have all their labels specified ahead of time.
Vectors ¶
In many real-world situations, it's impossible to know all the labels for a metric ahead of time. For example, you may want to track the number of requests your server receives by caller; in most cases, you can't list all the possible callers ahead of time. To accomodate these situations, Pally offers vectors.
Vectors represent a collection of metrics that have some constant labels, but some labels assigned at runtime. At vector construction time, you must specify the variable label keys; in our example, we'd supply "caller_name" as the only variable label. At runtime, pass the values for the variable labels to the Get (or MustGet) method on the vector. The number of label values must match the configured number of label keys, and they must be supplied in the same order. Vectors create metrics on demand, caching them for efficient repeated access.
registry := NewRegistry() requestsByCaller := registry.NewCounterVector(Opts{ Name: "requests", Help: "Total requests by caller name.", ConstLabels: Labels{ "zone": "us-west-1", "service": "my_service_name", }, // At runtime, we'll supply the caller name. VariableLabels: []string{"caller_name"}, }) // In real-world use, we'd do this in a handler function (and we'd // probably use the safer Get variant). vec.MustGet("some_calling_service").Inc()
Example (DependencyInjection) ¶
package main import ( "context" "net/http" "time" "go.uber.org/yarpc/internal/pally" "github.com/uber-go/tally" ) // If you'd prefer to use pure dependency injection and scope your metrics // to a single struct, create a new pally.Registry in your struct's // constructor. In this case, we're also exporting our metrics to a Tally // scope, which can report to StatsD- or M3-aware systems. type Resolver struct { registry *pally.Registry watches pally.Gauge resolves pally.CounterVector stopTallyExport context.CancelFunc } func NewResolver(scope tally.Scope) (*Resolver, error) { reg := pally.NewRegistry() stop, err := reg.Push(scope, time.Second) if err != nil { return nil, err } watches, err := _reg.NewGauge(pally.Opts{ Name: "watch_count", Help: "Current number of active service name watches.", ConstLabels: pally.Labels{ "foo": "bar", }, }) if err != nil { return nil, err } resolves, err := _reg.NewCounterVector(pally.Opts{ Name: "resolve_count", Help: "Total name resolves by path.", ConstLabels: pally.Labels{ "foo": "bar", }, VariableLabels: []string{"service"}, }) if err != nil { return nil, err } return &Resolver{ registry: reg, watches: watches, resolves: resolves, stopTallyExport: stop, }, nil } func (r *Resolver) Watch() { r.watches.Inc() } func (r *Resolver) Resolve(name string) { if c, err := r.resolves.Get(name); err == nil { c.Inc() } } func (r *Resolver) Close() { r.stopTallyExport() } func (r *Resolver) ServeHTTP(w http.ResponseWriter, req *http.Request) { // Our registry can report its own metrics via a Prometheus-compatible HTTP // handler. r.registry.ServeHTTP(w, req) } func main() { scope := tally.NewTestScope("testing", nil /* labels */) reg, err := NewResolver(scope) if err != nil { panic(err.Error()) } reg.Watch() reg.Resolve("some_service") }
Output:
Example (GlobalMetrics) ¶
package main import ( "go.uber.org/yarpc/internal/pally" "github.com/prometheus/client_golang/prometheus" ) // For expvar-style usage (where all metrics are package-global), create a // package-global pally.Registry and use the Must* constructors. This // guarantees that all your metrics are unique. var ( _reg = pally.NewRegistry( // Also register all metrics with the package-global Prometheus // registry. pally.Federated(prometheus.DefaultRegisterer), ) _watches = _reg.MustGauge(pally.Opts{ Name: "watch_count", Help: "Current number of active service name watches.", ConstLabels: pally.Labels{ "foo": "bar", }, }) _resolvesPerName = _reg.MustCounterVector(pally.Opts{ Name: "resolve_count", Help: "Total name resolves by service.", ConstLabels: pally.Labels{ "foo": "bar", }, VariableLabels: []string{"service"}, }) ) func main() { _watches.Store(42) _resolvesPerName.MustGet("some_service").Inc() }
Output:
Index ¶
- type Counter
- type CounterVector
- type Gauge
- type GaugeVector
- type Labels
- type Opts
- type Registry
- func (r *Registry) MustCounter(opts Opts) Counter
- func (r *Registry) MustCounterVector(opts Opts) CounterVector
- func (r *Registry) MustGauge(opts Opts) Gauge
- func (r *Registry) MustGaugeVector(opts Opts) GaugeVector
- func (r *Registry) NewCounter(opts Opts) (Counter, error)
- func (r *Registry) NewCounterVector(opts Opts) (CounterVector, error)
- func (r *Registry) NewGauge(opts Opts) (Gauge, error)
- func (r *Registry) NewGaugeVector(opts Opts) (GaugeVector, error)
- func (r *Registry) Push(scope tally.Scope, tick time.Duration) (context.CancelFunc, error)
- func (r *Registry) ServeHTTP(w http.ResponseWriter, req *http.Request)
- type RegistryOption
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Counter ¶
A Counter is a monotonically increasing value, like a car's odometer.
Counters are exported to Prometheus as a snapshot of the current total, and to Tally as a diff since the last export.
type CounterVector ¶
type CounterVector interface { // For a description of Get, MustGet, and vector types in general, see the // package-level documentation on vectors. Get(...string) (Counter, error) MustGet(...string) Counter }
A CounterVector is a collection of Counters that share a name and some constant labels, but also have an enumerated set of variable labels.
type Gauge ¶
type Gauge interface { Inc() int64 Dec() int64 Add(int64) int64 Sub(int64) int64 Store(int64) Load() int64 }
A Gauge is a point-in-time measurement, like a car's speedometer.
Gauges are exported to both Prometheus and Tally by simply reporting the current value.
type GaugeVector ¶
type GaugeVector interface { // For a description of Get, MustGet, and vector types in general, see the // package-level documentation on vectors. Get(...string) (Gauge, error) MustGet(...string) Gauge }
A GaugeVector is a collection of Gauges that share a name and some constant labels, but also have an enumerated set of variable labels.
type Opts ¶
type Opts struct { Name string Help string ConstLabels Labels VariableLabels []string // only meaningful for vectors DisableTally bool }
Opts configure an individual metric or vector.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
A Registry is a collection of metrics, usually scoped to a single package or object. Each Registry is also its own http.Handler, and can serve Prometheus-flavored text and protocol buffer pages for metrics introspection or scraping.
func NewRegistry ¶
func NewRegistry(opts ...RegistryOption) *Registry
NewRegistry constructs a new Registry.
func (*Registry) MustCounter ¶
MustCounter constructs a new Counter. It panics if it encounters an error.
func (*Registry) MustCounterVector ¶
func (r *Registry) MustCounterVector(opts Opts) CounterVector
MustCounterVector constructs a new CounterVector. It panics if it encounters an error.
func (*Registry) MustGauge ¶
MustGauge constructs a new Gauge. It panics if it encounters an error.
func (*Registry) MustGaugeVector ¶
func (r *Registry) MustGaugeVector(opts Opts) GaugeVector
MustGaugeVector constructs a new GaugeVector. It panics if it encounters an error.
func (*Registry) NewCounter ¶
NewCounter constructs a new Counter.
func (*Registry) NewCounterVector ¶
func (r *Registry) NewCounterVector(opts Opts) (CounterVector, error)
NewCounterVector constructs a new CounterVector.
func (*Registry) NewGaugeVector ¶
func (r *Registry) NewGaugeVector(opts Opts) (GaugeVector, error)
NewGaugeVector constructs a new CounterVector.
func (*Registry) Push ¶
Push starts a goroutine that periodically exports all registered metrics to a Tally scope. Each Registry can only push to a single Scope; calling Push a second time returns an error.
In practice, this isn't a problem because Tally scopes natively support tee'ing to multiple backends.
type RegistryOption ¶
type RegistryOption func(*Registry)
A RegistryOption configures a Registry.
func Federated ¶
func Federated(prom prometheus.Registerer) RegistryOption
Federated links a pally.Registry with a prometheus.Registerer, so that all metrics created in one also appear in the other.
func Labeled ¶
func Labeled(ls Labels) RegistryOption
Labeled adds constant labels to a Registry. All metrics created by a Registry inherit its constant labels.