touchstone

package module
v0.1.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 19, 2024 License: Apache-2.0 Imports: 7 Imported by: 21

README

touchstone

Touchstone is an integration between go.uber.org/fx and prometheus.

Build Status codecov.io Go Report Card Quality Gate Status Apache V2 License GitHub Release GoDoc

Summary

Touchstone provides easy bootstrapping of a prometheus client environment within a go.uber.org/fx application container. Key features include:

  • External configuration that can drive how the Registry and other components are initialized
  • Simple constructors that allow individual metrics to fully participate in dependency injection
  • Prebundled HTTP metrics with a simpler and more efficient instrumentation than what promhttp provides

Table of Contents

Code of Conduct

This project and everyone participating in it are governed by the XMiDT Code Of Conduct. By participating, you agree to this Code.

Install

go get -u github.com/xmidt-org/touchstone

Contributing

Refer to CONTRIBUTING.md.

Documentation

Overview

Package touchstone is an integration between go.uber.org/fx and prometheus.

Example
type In struct {
	fx.In
	Counter  prometheus.Counter   `name:"example_counter"`
	GaugeVec *prometheus.GaugeVec `name:"example_gaugevec"`
}

_ = fx.New(
	fx.Logger(log.New(io.Discard, "", 0)),
	fx.Supply(
		// this Config instance can come from anywhere
		Config{
			DefaultNamespace: "example",
			DefaultSubsystem: "touchstone",
		},
	),
	Provide(),
	Counter(prometheus.CounterOpts{
		// this will use the default namespace and subsystem
		Name: "example_counter",
	}),
	GaugeVec(prometheus.GaugeOpts{
		Subsystem: "override",
		Name:      "example_gaugevec",
	}, "label"),
	fx.Invoke(
		func(in In) {
			in.Counter.Inc()
			in.GaugeVec.WithLabelValues("value").Add(2.0)

			fmt.Println("counter", testutil.ToFloat64(in.Counter))
			fmt.Println("gaugevec", testutil.ToFloat64(in.GaugeVec))
		},
	),
)
Output:

counter 1
gaugevec 2

Index

Examples

Constants

View Source
const (
	// Module is the name of the fx module that touchstone components
	// are provided within.
	Module = "touchstone"
)

Variables

View Source
var (
	// ErrNoMetricName indicates that a prometheus *Opts struct did not set the Name field.
	ErrNoMetricName = errors.New("A metric Name is required")
)

Functions

func ApplyDefaults added in v0.1.0

func ApplyDefaults(dst, src interface{}) (result interface{})

ApplyDefaults ensures that any field in dst that is the zero value takes a default from the corresponding field in src. If a field in dst doesn't exist in src, that field is skipped.

This function always returns a non-nil pointer to the same type of struct that dst refers to:

  • If dst is a struct value, a new instance of dst is created and defaults are applied to that instance. The pointer to the new instance is returned.

  • If dst is a non-nil pointer to a struct, defaults are applied to that instance. The dst pointer is returned.

  • If dst is a nil pointer to a struct, a new instance of the struct is created and defaults are applied to that instance. The pointer to the new instance is returned.

  • If dst is any other type, this function panics.

The src parameter represents the defaults to apply to dst:

  • If src is nil or a nil pointer, this function does not apply any defaults but still executes the logic for dst. In particular, a new zero-value dst struct will be returned if dst is a nil pointer to struct or a struct value.

  • If src is a struct value or a non-nil pointer to struct, defaults are taken from src and applied to dst.

  • If src is any other type, this function panics.

The primary use case for this function is setting up default options for prometheus metrics:

// note that this can be any struct with fields named the same
// as the prometheus xxxOpts struct
defaults := prometheus.CounterOpts{
  Namespace: "default",
  // can set any other fields as defaults
}

co := prometheus.CounterOpts{
  Name: "my_counter",
}

ApplyDefaults(&co, defaults) // in-place transfer to co
c := prometheus.NewCounter(co)

The result of ApplyDefaults is safe for casting to *dst, even if dst is nil:

defaults := prometheus.Opts{
  Namespace: "default",
  Subsystem: "default",
}

// creates a new opts
co := ApplyDefaults((*prometheus.CounterOpts)(nil), defaults).(*prometheus.CounterOpts)

// creates a new opts which is a clone of dst
go := ApplyDefaults(prometheus.GaugeOpts{Name: "cloneme"}, defaults).(*prometheus.GaugeOpts)

// can chain with the dynamic factory methods
var f *Factory = /* ... */
var co prometheus.CounterOpts
f.New(ApplyDefaults(co, defaults)) // uses a distinct instance of prometheus.CounterOpts

Note that this function does a shallow copy of any relevant fields. In particular, that means that a slice of buckets will point to the same data in the dst and src after this function returns.

func AsAlreadyRegisteredError added in v0.0.3

func AsAlreadyRegisteredError(err error) *prometheus.AlreadyRegisteredError

AsAlreadyRegisteredError tests if err is a prometheus AlreadyRegisteredError. If it is, a non-nil error is returned. If the error wasn't an AlreadyRegisteredError, this method returns nil.

func CollectorAs added in v0.0.3

func CollectorAs(c prometheus.Collector, target interface{}) bool

CollectorAs attempts to set target to the given collector. The target parameter must be a non-nil pointer to an interface or a prometheus metric type that implements Collector. This function returns true if target was set, false to indicate no conversion was possitble.

As it was inspired by errors.As, this function panics in similar situations where errors.As would panic:

  • if target is the nil interface, e.g. CollectorAs(myMetric, nil) will panic
  • if target is not both a pointer and non-nil
  • if *target is not either:
  • a concrete type that implements prometheus.Collector (e.g. prometheus.CounterVec), OR
  • an arbitrary interface

func Counter

func Counter(o prometheus.CounterOpts) fx.Option

Counter uses a Factory instance from the enclosing fx.App to create and register a prometheus.Counter with the same component name as the metric Name.

If no Name is set, application startup is short-circuited with an error.

func CounterVec

func CounterVec(o prometheus.CounterOpts, labelNames ...string) fx.Option

CounterVec uses a Factory instance from the enclosing fx.App to create and register a *prometheus.CounterVec with the same component name as the metric Name.

If no Name is set, application startup is short-circuited with an error.

func ExistingCollector added in v0.0.3

func ExistingCollector(target interface{}, err error) error

ExistingCollector attempts to use the previously registered collector as target. This function attempts to coerce err to a prometheus.AlreadyRegisteredError, and then coerce the ExistingCollector field to the target.

If err was not a prometheus.AlreadyRegisteredError or if the existing collector was not assignable to the target, this function returns the original error. Otherwise, this function returns nil.

A typical use of this method is to allow client code to ignore already registered errors and just take the previously registered metric:

// using a touchstone Factory:
var f *touchstone.Factory
m, err := f.NewCounterVec(/* ... */)
err = touchstone.ExistingCollector(&m, err) // note the &m to replace m with the existing metric

// using a prometheus Registerer
r := prometheus.NewPedanticRegistry()
cv := prometheus.NewCounterVec(/* ... */)
err := r.Register(cv)
err = touchstone.ExistingCollector(&cv, err) // note the &cv to replace cv with the existing counter vec

func Gauge

func Gauge(o prometheus.GaugeOpts) fx.Option

Gauge uses a Factory instance from the enclosing fx.App to create and register a prometheus.Gauge with the same component name as the metric Name.

If no Name is set, application startup is short-circuited with an error.

func GaugeVec

func GaugeVec(o prometheus.GaugeOpts, labelNames ...string) fx.Option

GaugeVec uses a Factory instance from the enclosing fx.App to create and register a *prometheus.GaugeVec with the same component name as the metric Name.

If no Name is set, application startup is short-circuited with an error.

func Histogram

func Histogram(o prometheus.HistogramOpts) fx.Option

Histogram uses a Factory instance from the enclosing fx.App to create and register a prometheus.Observer with the same component name as the metric Name.

If no Name is set, application startup is short-circuited with an error.

func HistogramVec

func HistogramVec(o prometheus.HistogramOpts, labelNames ...string) fx.Option

HistogramVec uses a Factory instance from the enclosing fx.App to create and register a prometheus.ObserverVec with the same component name as the metric Name.

If no Name is set, application startup is short-circuited with an error.

func Metric

func Metric(name string, target interface{}) fx.Option

Metric emits a named component using the specified target. The target is expected to be a function (constructor) of the same form accepted by fx.Annotated.Target.

If name is empty, application startup is short-circuited with an error.

See: https://pkg.go.dev/go.uber.org/fx#Annotated

func New

func New(cfg Config) (g prometheus.Gatherer, r prometheus.Registerer, err error)

New bootstraps a prometheus registry given a Config instance. Note that the returned Registerer may be decorated to arbitrary depth.

func NewUntypedFunc added in v0.1.1

func NewUntypedFunc(opts prometheus.UntypedOpts, f interface{}) (uf prometheus.UntypedFunc, err error)

NewUntypedFunc is a variant of prometheus.NewUntypedFunc that allows the function to have a more flexible signature. The supplied function f must accept no arguments and must return exactly (1) value that is any scalar numeric type. The complex types are not supported.

In particular, this function is useful when f has the signature func() int. This is the common case for things like queue depth, length of a data structure, etc.

If f is not a function or is a function with an unsupported signature, an error is returned.

func Provide

func Provide() fx.Option

Provide bootstraps a prometheus environment for an uber/fx App. The following component types are provided by this function:

  • prometheus.Gatherer
  • promtheus.Registerer NOTE: Do not rely on the Registerer actually being a *prometheus.Registry. It may be decorated to arbitrary depth.
  • *touchstone.Factory

func Summary

func Summary(o prometheus.SummaryOpts) fx.Option

Summary uses a Factory instance from the enclosing fx.App to create and register a prometheus.Observer with the same component name as the metric Name.

If no Name is set, application startup is short-circuited with an error.

func SummaryVec

func SummaryVec(o prometheus.SummaryOpts, labelNames ...string) fx.Option

SummaryVec uses a Factory instance from the enclosing fx.App to create and register a prometheus.ObserverVec with the same component name as the metric Name.

If no Name is set, application startup is short-circuited with an error.

Types

type Config

type Config struct {
	// DefaultNamespace is the prometheus namespace to apply when a metric has no namespace.
	DefaultNamespace string `json:"defaultNamespace" yaml:"defaultNamespace"`

	// DefaultSubsystem is the prometheus subsystem to apply when a metric has no subsystem.
	DefaultSubsystem string `json:"defaultSubsystem" yaml:"defaultSubsystem"`

	// Pedantic controls whether a pedantic Registerer is used as the prometheus backend.
	//
	// See: https://godoc.org/github.com/prometheus/client_golang/prometheus#NewPedanticRegistry
	Pedantic bool `json:"pedantic" yaml:"pedantic"`

	// DisableGoCollector controls whether the go collector is registered on startup.
	// By default, the go collector is registered.
	//
	// See: https://pkg.go.dev/github.com/prometheus/client_golang/prometheus/collectors#NewGoCollector
	DisableGoCollector bool `json:"disableGoCollector" yaml:"disableGoCollector"`

	// DisableProcessCollector controls whether the process collector is registered on startup.
	// By default, this collector is registered.
	//
	// See: https://pkg.go.dev/github.com/prometheus/client_golang/prometheus/collectors#NewProcessCollector
	DisableProcessCollector bool `json:"disableProcessCollector" yaml:"disableProcessCollector"`

	// DisableBuildInfoCollector controls whether the build info collector is registered on startup.
	// By default, this collector is registered.
	//
	// See: https://pkg.go.dev/github.com/prometheus/client_golang/prometheus/collectors#NewBuildInfoCollector
	DisableBuildInfoCollector bool `json:"disableBuildInfoCollector" yaml:"disableBuildInfoCollector"`
}

Config defines the configuration options for bootstrapping a prometheus-based metrics environment.

type Factory

type Factory struct {
	// contains filtered or unexported fields
}

Factory handles creation and registration of metrics.

This type serves a similar purpose to the promauto package. Instead of registering metrics with a global singleton, it uses the injected prometheus.Registerer. In addition, any DefaultNamespace and DefaultSubsystem set on the Config object are enforced for every metric created through the Factory instance.

If a *zap.Logger is supplied, it is used to log warnings about missing Help in *Opts structs.

This package's functions that match metric types, e.g. Counter, CounterVec, etc, use a Factory instance injected from the enclosing fx.App. Those functions are generally preferred to using a Factory directly, since they emit their metrics as components which can then be injected as needed.

See: https://pkg.go.dev/github.com/prometheus/client_golang/prometheus/promauto

Example
var f *Factory
_ = fx.New(
	fx.Logger(log.New(io.Discard, "", 0)),
	Provide(),
	fx.Populate(&f),
)

c, err := f.NewCounterVec(
	prometheus.CounterOpts{
		Name: "example",
		Help: "here is a lovely example",
	}, "label",
)

if err != nil {
	fmt.Println(err)
	return
}

c.WithLabelValues("value").Inc()
fmt.Println(testutil.ToFloat64(c))
Output:

1

func NewFactory

func NewFactory(cfg Config, l *zap.Logger, r prometheus.Registerer) *Factory

NewFactory produces a Factory that uses the supplied registry.

func (*Factory) DefaultNamespace

func (f *Factory) DefaultNamespace() string

DefaultNamespace returns the namespace used to register metrics when no Namespace is specified in the *Opts struct. This may be empty to indicate that there is no default.

func (*Factory) DefaultSubsystem

func (f *Factory) DefaultSubsystem() string

DefaultSubsystem returns the subsystem used to register metrics when no Subsystem is specified in the *Opts struct. This may be empty to indicate that there is no default.

func (*Factory) New added in v0.0.3

func (f *Factory) New(o interface{}) (m prometheus.Collector, err error)

New creates a dynamically typed metric based on the concrete type passed as options. For example, if passed a prometheus.CounterOpts, this method creates and registers a prometheus.Counter.

The o parameter must be one of the following, or this method panics:

  • prometheus.CounterOpts
  • *prometheus.CounterOpts
  • prometheus.GaugeOpts
  • *prometheus.GaugeOpts
  • prometheus.HistogramOpts
  • *prometheus.HistogramOpts
  • prometheus.SummaryOpts
  • *prometheus.SummaryOpts

func (*Factory) NewCounter

func (f *Factory) NewCounter(o prometheus.CounterOpts) (m prometheus.Counter, err error)

NewCounter creates and registers a new counter using the supplied options.

This method returns an error if the options do not specify a name. Both namespace and subsystem are defaulted appropriately if not set in the options.

See: https://pkg.go.dev/github.com/prometheus/client_golang/prometheus#NewCounter

func (*Factory) NewCounterFunc

func (f *Factory) NewCounterFunc(o prometheus.CounterOpts, fn func() float64) (m prometheus.CounterFunc, err error)

NewCounterFunc creates and registers a new counter backed by the given function.

This method returns an error if the options do not specify a name. Both namespace and subsystem are defaulted appropriately if not set in the options.

See: https://pkg.go.dev/github.com/prometheus/client_golang/prometheus#NewCounterFunc

func (*Factory) NewCounterVec

func (f *Factory) NewCounterVec(o prometheus.CounterOpts, labelNames ...string) (m *prometheus.CounterVec, err error)

NewCounterVec creates and registers a new counter vector using the supplied options.

This method returns an error if the options do not specify a name. Both namespace and subsystem are defaulted appropriately if not set in the options.

See: https://pkg.go.dev/github.com/prometheus/client_golang/prometheus#NewCounterVec

func (*Factory) NewGauge

func (f *Factory) NewGauge(o prometheus.GaugeOpts) (m prometheus.Gauge, err error)

NewGauge creates and registers a new gauge using the supplied options.

This method returns an error if the options do not specify a name. Both namespace and subsystem are defaulted appropriately if not set in the options.

See: https://pkg.go.dev/github.com/prometheus/client_golang/prometheus#NewGauge

func (*Factory) NewGaugeFunc

func (f *Factory) NewGaugeFunc(o prometheus.GaugeOpts, fn func() float64) (m prometheus.GaugeFunc, err error)

NewGaugeFunc creates and registers a new gauge backed by the given function.

This method returns an error if the options do not specify a name. Both namespace and subsystem are defaulted appropriately if not set in the options.

See: https://pkg.go.dev/github.com/prometheus/client_golang/prometheus#NewGaugeFunc

func (*Factory) NewGaugeVec

func (f *Factory) NewGaugeVec(o prometheus.GaugeOpts, labelNames ...string) (m *prometheus.GaugeVec, err error)

NewGaugeVec creates and registers a new gauge vector using the supplied options.

This method returns an error if the options do not specify a name. Both namespace and subsystem are defaulted appropriately if not set in the options.

See: https://pkg.go.dev/github.com/prometheus/client_golang/prometheus#NewGaugeVec

func (*Factory) NewHistogram

func (f *Factory) NewHistogram(o prometheus.HistogramOpts) (m prometheus.Observer, err error)

NewHistogram creates and registers a new observer using the supplied options. The Observer component is backed by a prometheus.Histogram.

This method returns an error if the options do not specify a name. Both namespace and subsystem are defaulted appropriately if not set in the options.

See: https://pkg.go.dev/github.com/prometheus/client_golang/prometheus#NewHistogram

func (*Factory) NewHistogramVec

func (f *Factory) NewHistogramVec(o prometheus.HistogramOpts, labelNames ...string) (m prometheus.ObserverVec, err error)

NewHistogramVec creates and registers a new observer vector using the supplied options. The ObserverVec component is backed by a prometheus.HistogramVec.

This method returns an error if the options do not specify a name. Both namespace and subsystem are defaulted appropriately if not set in the options.

See: https://pkg.go.dev/github.com/prometheus/client_golang/prometheus#NewHistogramVec

func (*Factory) NewObserver added in v0.0.3

func (f *Factory) NewObserver(o interface{}) (m prometheus.Observer, err error)

NewObserver creates a histogram or a summary, depending on the concrete type of the first parameter. This method panics if o is not a prometheus.HistogramOpts or a prometheus.SummaryOpts.

func (*Factory) NewObserverVec added in v0.0.3

func (f *Factory) NewObserverVec(o interface{}, labelNames ...string) (m prometheus.ObserverVec, err error)

NewObserverVec creates a histogram vector or a summary vector, depending on the concrete type of the first parameter. This method panics if o is not a prometheus.HistogramOpts, a prometheus.SummaryOpts, or a pointer to either.

func (*Factory) NewSummary

func (f *Factory) NewSummary(o prometheus.SummaryOpts) (m prometheus.Observer, err error)

NewSummary creates and registers a new observer using the supplied options. The Observer component is backed by a prometheus.Summary.

This method returns an error if the options do not specify a name. Both namespace and subsystem are defaulted appropriately if not set in the options.

See: https://pkg.go.dev/github.com/prometheus/client_golang/prometheus#NewSummary

func (*Factory) NewSummaryVec

func (f *Factory) NewSummaryVec(o prometheus.SummaryOpts, labelNames ...string) (m prometheus.ObserverVec, err error)

NewSummaryVec creates and registers a new observer vector using the supplied options. The ObserverVec component is backed by a prometheus.SummaryVec.

This method returns an error if the options do not specify a name. Both namespace and subsystem are defaulted appropriately if not set in the options.

See: https://pkg.go.dev/github.com/prometheus/client_golang/prometheus#NewSummaryVec

func (*Factory) NewUntypedFunc

func (f *Factory) NewUntypedFunc(o prometheus.UntypedOpts, fn interface{}) (m prometheus.UntypedFunc, err error)

NewUntypedFunc creates and registers a new metric backed by the given function. The function must be of a signature supported by the package-level NewUntypedFunc.

This method returns an error if the options do not specify a name. Both namespace and subsystem are defaulted appropriately if not set in the options.

See: https://pkg.go.dev/github.com/prometheus/client_golang/prometheus#NewUntypedFunc

func (*Factory) NewVec added in v0.0.3

func (f *Factory) NewVec(o interface{}, labelNames ...string) (m prometheus.Collector, err error)

NewVec creates a dynamically typed metric vector based on the concrete type passed as options. For example, if passed a prometheus.CounterOpts, this method creates and registers a *prometheus.CounterVec.

The o parameter must be one of the following, or this method panics:

  • prometheus.CounterOpts
  • *prometheus.CounterOpts
  • prometheus.GaugeOpts
  • *prometheus.GaugeOpts
  • prometheus.HistogramOpts
  • *prometheus.HistogramOpts
  • prometheus.SummaryOpts
  • *prometheus.SummaryOpts

type In

type In struct {
	fx.In

	// Config is the prometheus configuration.  This is optional,
	// as a zero value for Config will result in a default environment.
	Config Config `optional:"true"`

	// Logger is the *zap.Logger to which this package writes messages.
	// This is optional, and if unset no messages are written.
	Logger *zap.Logger `optional:"true"`
}

In represents the components used by this package to bootstrap a prometheus environment. Provide uses these components.

Directories

Path Synopsis
Package touchbundle provides a simple way to create bundles of metrics from configuration.
Package touchbundle provides a simple way to create bundles of metrics from configuration.
Package touchhttp defines the HTTP-specific behavior for metrics within an uber/fx app which uses the touchstone package.
Package touchhttp defines the HTTP-specific behavior for metrics within an uber/fx app which uses the touchstone package.
Package touchkit adds integration with go-kit's metrics API with prometheus as the backend.
Package touchkit adds integration with go-kit's metrics API with prometheus as the backend.
Package touchtest exposes common prometheus testing utilities.
Package touchtest exposes common prometheus testing utilities.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL