Documentation
¶
Overview ¶
Package metrics provides a lightweight facade to instrument Go code with counters, gauges and samples, and to deliver them to a pluggable backend.
Model ¶
A Metrics instance owns a Config and a single Sink. Application code emits through the Provider interface (or the package-level proxies that forward to the global instance), and the sink converts the emission into a backend-specific representation:
- Provider.SetGauge retains the last value it is set to.
- Provider.IncrCounter accumulates values.
- Provider.AddSample records an observation for quantile calculation.
- Provider.MeasureSince records elapsed time as a sample, in units of Config.TimerGranularity.
Every emission carries zero or more Tag values, which become labels (Prometheus), dimensions (CloudWatch) or key suffixes (InmemSink).
Key composition ¶
Config.Prepare builds the final metric key from the configured parts, in this order (innermost last):
<GlobalPrefix>_<ServiceName>_<type>_<HostName>_<key>
Each part is included only when the matching option is set: Config.GlobalPrefix, Config.ServiceName (unless Config.EnableServiceLabel turns it into a label), Config.EnableTypePrefix, and Config.HostName (unless Config.EnableHostnameLabel turns it into a label). The result is then matched against Config.AllowedPrefixes and Config.BlockedPrefixes by Config.AllowMetric; blocked metrics are dropped before reaching the sink.
Usage ¶
Create a sink, wire it into the global provider and emit:
sink := metrics.NewInmemSink(10*time.Second, time.Minute)
cfg := metrics.DefaultConfig("billing")
cfg.GlobalTags = []metrics.Tag{{Name: "env", Value: "prod"}}
if _, err := metrics.NewGlobal(cfg, sink); err != nil {
return err
}
defer metrics.MeasureSince("charge_duration", time.Now(),
metrics.Tag{Name: "currency", Value: "usd"})
Prefer declaring metrics up-front with Describe, which validates the tag count on every emission and feeds help text to the Prometheus sink:
var chargeDuration = &metrics.Describe{
Type: metrics.TypeSample,
Name: "charge_duration",
Help: "charge_duration provides the time spent charging a card",
RequiredTags: []string{"currency"},
}
defer chargeDuration.MeasureSince(time.Now(), "usd")
Sinks ¶
The root package ships InmemSink (in-memory aggregation, optionally dumped on a signal by InmemSignal), BlackholeSink and FanoutSink. Network backends live in subpackages: `prometheus` and `cloudwatch`. The `factory` subpackage builds a sink from a URL.
Concurrency ¶
All sinks in this module are safe for concurrent emission, and Metrics.UpdateFilter may be called while other goroutines emit: it replaces the filter rules as a whole. Writing to the fields of a Config that is in use is not synchronized; construct it, pass it to New, and change the filters through Metrics.UpdateFilter afterwards.
Metrics.Close stops the runtime metrics collector started by New.
Index ¶
- Constants
- func AddSample(key string, val float64, tags ...Tag)
- func IncrCounter(key string, val float64, tags ...Tag)
- func MeasureSince(key string, start time.Time, tags ...Tag)
- func SetGauge(key string, val float64, tags ...Tag)
- func StringStartsWithOneOf(value string, items []string) bool
- func UpdateFilter(allow, block []string)
- type AggregateSample
- type BlackholeSink
- type Config
- type Describe
- type FanoutSink
- type GaugeValue
- type InmemSignal
- type InmemSink
- func (i *InmemSink) AddSample(key string, val float64, tags []Tag)
- func (i *InmemSink) Data() []*IntervalMetrics
- func (i *InmemSink) DisplayMetrics() (*Summary, error)
- func (i *InmemSink) IncrCounter(key string, val float64, tags []Tag)
- func (i *InmemSink) SetGauge(key string, val float64, tags []Tag)
- type IntervalMetrics
- type Metrics
- func (m *Metrics) AddSample(key string, val float64, tags ...Tag)
- func (m *Metrics) AllowMetric(key string) bool
- func (m *Metrics) Close()
- func (m *Metrics) Help(providers ...[]*Describe) map[string]string
- func (m *Metrics) IncrCounter(key string, val float64, tags ...Tag)
- func (m *Metrics) MeasureSince(key string, start time.Time, tags ...Tag)
- func (m *Metrics) Prepare(typ string, key string, tags ...Tag) (bool, string, []Tag)
- func (m *Metrics) SetGauge(key string, val float64, tags ...Tag)
- func (m *Metrics) UpdateFilter(allow, block []string)
- type PointValue
- type Provider
- type SampledValue
- type Sink
- type Summary
- type Tag
Constants ¶
const ( TypeCounter = "counter" TypeSample = "sample" TypeGauge = "gauge" )
Metric types, used as the type prefix when Config.EnableTypePrefix is set, and as Describe.Type.
const ( // DefaultSignal is used with DefaultInmemSignal DefaultSignal = syscall.SIGUSR1 )
Variables ¶
This section is empty.
Functions ¶
func AddSample ¶
AddSample emits a sample on the global instance, for timing information where quantiles are used.
func IncrCounter ¶
IncrCounter emits a counter increment on the global instance.
func MeasureSince ¶
MeasureSince emits the time elapsed since start as a sample on the global instance, in units of Config.TimerGranularity.
func SetGauge ¶
SetGauge emits a gauge on the global instance, which should retain the last value it is set to.
func StringStartsWithOneOf ¶ added in v0.2.0
StringStartsWithOneOf returns true if one of items slice is a prefix of specified value.
func UpdateFilter ¶
func UpdateFilter(allow, block []string)
UpdateFilter replaces the prefix filters of the global instance.
Types ¶
type AggregateSample ¶
type AggregateSample struct {
Count int // The count of emitted pairs
Rate float64 // The values rate per time unit (usually 1 second)
Sum float64 // The sum of values
SumSq float64 `json:"-"` // The sum of squared values
Min float64 // Minimum value
Max float64 // Maximum value
LastUpdated time.Time `json:"-"` // When value was last updated
}
AggregateSample is used to hold aggregate metrics about a sample.
It is not safe for concurrent use: callers must serialize Ingest against readers, which InmemSink does with the interval lock.
func (*AggregateSample) Ingest ¶
func (a *AggregateSample) Ingest(v float64, rateDenom float64)
Ingest is used to update a sample with a new value. rateDenom is the length of the aggregation interval in the rate time unit, and must not be zero.
func (*AggregateSample) Mean ¶
func (a *AggregateSample) Mean() float64
Mean computes the mean of the ingested values, or 0 when there are none.
func (*AggregateSample) Stddev ¶
func (a *AggregateSample) Stddev() float64
Stddev computes the standard deviation of the ingested values. It returns 0 for fewer than two values.
The result is derived from the running sums, which loses precision when the values are large relative to their spread.
func (*AggregateSample) String ¶
func (a *AggregateSample) String() string
String returns a human readable summary of the sample, used by InmemSignal when dumping metrics.
type BlackholeSink ¶
type BlackholeSink struct{}
BlackholeSink is used to just blackhole messages. It is the sink installed on the global instance until NewGlobal is called.
func (*BlackholeSink) AddSample ¶
func (*BlackholeSink) AddSample(_ string, _ float64, _ []Tag)
AddSample discards the value.
func (*BlackholeSink) IncrCounter ¶
func (*BlackholeSink) IncrCounter(_ string, _ float64, _ []Tag)
IncrCounter discards the value.
type Config ¶
type Config struct {
// ServiceName is prefixed to keys to separate services,
// or emitted as the "service" label when EnableServiceLabel is set.
ServiceName string
// HostName to use. If not provided and EnableHostname is set,
// DefaultConfig uses os.Hostname.
HostName string
// EnableHostname enables prefixing keys with HostName.
// Ignored when EnableHostnameLabel is set.
EnableHostname bool
// EnableHostnameLabel enables adding HostName as the "host" tag.
// Takes precedence over EnableHostname.
EnableHostnameLabel bool
// EnableServiceLabel enables adding ServiceName as the "service" tag
// instead of prefixing it to the key.
EnableServiceLabel bool
// EnableRuntimeMetrics enables profiling of runtime metrics
// (GC, Goroutines, Memory). New starts a background goroutine for it,
// which runs until Metrics.Close is called.
EnableRuntimeMetrics bool
// EnableTypePrefix prefixes the key with the metric type:
// TypeCounter, TypeGauge or TypeSample.
EnableTypePrefix bool
// TimerGranularity is the unit reported by MeasureSince.
// Defaults to time.Millisecond.
TimerGranularity time.Duration
// ProfileInterval is the interval at which runtime metrics are collected,
// when EnableRuntimeMetrics is set. Defaults to time.Second.
ProfileInterval time.Duration
// GlobalTags are added to every metric.
GlobalTags []Tag
// GlobalPrefix is prepended to every metric key, before all other prefixes.
GlobalPrefix string
// NumberLabelPrefix is prepended to tag values that are 64-bit numbers,
// to keep backends from coercing large IDs into floats.
// A value is treated as a number when it has at least 15 digits.
NumberLabelPrefix string
// AllowedPrefixes is a list of metric key prefixes to allow.
// A key matching one of them is emitted regardless of FilterDefault.
AllowedPrefixes []string
// BlockedPrefixes is a list of metric key prefixes to block.
// A blocked prefix always wins over an allowed one.
BlockedPrefixes []string
// FilterDefault is the verdict for keys that no prefix rule matches:
// true allows them, false drops them.
FilterDefault bool
}
Config is used to configure metrics settings.
The zero value emits nothing: FilterDefault must be set to true, or an explicit AllowedPrefixes list must be provided, for metrics to reach the sink. See Prepare for how the fields combine into the final metric key.
A Config is read on every emission. Copy it into a Metrics with New and change the filters through Metrics.UpdateFilter afterwards; writing to the fields of a Config that is in use is not synchronized.
func DefaultConfig ¶
DefaultConfig provides a sane default configuration: runtime metrics enabled, millisecond timers, no filtering, and the local hostname resolved but not emitted.
func (*Config) AllowMetric ¶ added in v0.4.0
AllowMetric returns whether the metric should be allowed based on the configured prefix filters.
A key matching BlockedPrefixes is dropped, a key matching AllowedPrefixes is emitted, and a key matching neither falls back to FilterDefault.
func (*Config) Help ¶ added in v0.4.0
Help returns the help text of the described metrics, keyed by the final metric name that this configuration produces.
The result is meant for prometheus.Opts.Help, so the exported HELP line matches the metric. Metrics blocked by the configured filters are omitted; Metrics.Help applies the filters in effect instead.
func (*Config) Prepare ¶ added in v0.4.0
Prepare returns the final metric name and tags to emit, and whether the metric passes the configured filters.
The key is assembled from the configured parts, in this order:
<GlobalPrefix>_<ServiceName>_<typ>_<HostName>_<key>
and the returned tags are the given ones followed by GlobalTags plus the optional "host" and "service" labels. The caller's slice is never modified: when tags have to be added, or rewritten for NumberLabelPrefix, the result is a new slice.
type Describe ¶ added in v0.4.0
type Describe struct {
// Type of the metric: TypeCounter, TypeGauge or TypeSample.
// "summary" is accepted as an alias of TypeSample.
Type string
// Name is the metric name
Name string
// Help provides description
Help string
// RequiredTags is a list of metric tags
RequiredTags []string
}
Describe provides metric description.
Declaring metrics as package-level Describe values keeps the name, help text and tag names in one place, and validates on every emission that the caller supplies exactly the expected tag values. Its emit methods always go to the global instance.
func (*Describe) AddSample ¶ added in v0.4.0
AddSample emits the described sample on the global instance. The values must match Describe.RequiredTags in size and order.
func (*Describe) IncrCounter ¶ added in v0.4.0
IncrCounter emits the described counter increment on the global instance. The values must match Describe.RequiredTags in size and order.
func (*Describe) MeasureSince ¶ added in v0.4.0
MeasureSince emits the time elapsed since start as the described sample on the global instance. The values must match Describe.RequiredTags in size and order.
func (*Describe) SetGauge ¶ added in v0.4.0
SetGauge emits the described gauge on the global instance. The values must match Describe.RequiredTags in size and order.
func (*Describe) Tags ¶ added in v0.4.0
Tags constructs tags. The size and order of the vals must match the ones in the description.
On mismatch it logs an error and returns a single "invalid_tags" tag, so a miscounted call is visible in the backend instead of silently emitting under the wrong label set.
type FanoutSink ¶
type FanoutSink []Sink
FanoutSink is used to fan out values to multiple sinks, for example to expose metrics to Prometheus and CloudWatch at once.
Emission is sequential and synchronous, so a slow sink slows down every caller, and a panicking sink prevents the remaining sinks from being called.
func NewFanoutSink ¶
func NewFanoutSink(sinks ...Sink) FanoutSink
NewFanoutSink creates fan-out sink.
func (FanoutSink) AddSample ¶
func (fh FanoutSink) AddSample(key string, val float64, tags []Tag)
AddSample forwards the sample to every sink.
func (FanoutSink) IncrCounter ¶
func (fh FanoutSink) IncrCounter(key string, val float64, tags []Tag)
IncrCounter forwards the counter increment to every sink.
type GaugeValue ¶
type GaugeValue struct {
// Name is the metric name, without the flattened tags.
Name string
// Hash is the aggregation key: the name with its tags appended.
Hash string `json:"-"`
// Value is the last value set in the interval.
Value float64
// Labels are the tags the value was emitted with.
Labels []Tag `json:"-"`
// DisplayLabels is the serializable form of Labels,
// populated by DisplayMetrics.
DisplayLabels map[string]string `json:"Labels"`
}
GaugeValue provides gauge value.
type InmemSignal ¶
type InmemSignal struct {
// contains filtered or unexported fields
}
InmemSignal is used to listen for a given signal, and when received, to dump the current metrics from the InmemSink to an io.Writer.
It is a debugging aid: sending the signal to a running process prints the finished aggregation intervals, without requiring a metrics backend.
func DefaultInmemSignal ¶
func DefaultInmemSignal(inmem *InmemSink) *InmemSignal
DefaultInmemSignal returns a new InmemSignal that responds to SIGUSR1 and writes output to stderr. Windows uses SIGBREAK.
func NewInmemSignal ¶
NewInmemSignal creates a new InmemSignal which listens for a given signal, and dumps the current metrics out to a writer.
It starts a goroutine that runs until Stop is called.
func (*InmemSignal) Stop ¶
func (i *InmemSignal) Stop()
Stop is used to stop the InmemSignal from listening. It is idempotent and safe for concurrent use.
type InmemSink ¶
type InmemSink struct {
// contains filtered or unexported fields
}
InmemSink provides a Sink that does in-memory aggregation without sending metrics over a network. It can be embedded within an application to provide profiling information.
Values are bucketed into fixed aggregation intervals and the oldest buckets are discarded, so memory is bounded by retain/interval times the number of distinct key and tag combinations. Read the aggregated data with Data or DisplayMetrics, or dump it on a signal with InmemSignal.
func NewInmemSink ¶
NewInmemSink is used to construct a new in-memory sink, with an aggregation interval and a maximum retention period.
interval must be greater than zero and retain must be at least twice the interval. Values outside that range are clamped, with an error logged naming the parameter, so a misconfiguration degrades the reported window instead of panicking at the first emission.
func (*InmemSink) AddSample ¶
AddSample records an observation within the current interval, rolled up into an AggregateSample.
func (*InmemSink) Data ¶
func (i *InmemSink) Data() []*IntervalMetrics
Data is used to retrieve all the aggregated metrics, oldest interval first. The last entry is the interval currently being written to.
Every interval is an independent copy, taken under its own lock, including the AggregateSample behind each counter and sample. Reading the result needs no lock and it does not change afterwards. Even a finished interval has to be copied: an emitter can resolve its interval, be descheduled across the bucket rollover, and write to it after it stopped being the current one.
The Tag slices in Labels are shared with the sink and must be treated as read-only.
func (*InmemSink) DisplayMetrics ¶
DisplayMetrics returns a summary of the metrics from the most recent finished interval, with the values sorted by aggregation key.
It returns an error when no interval has been recorded yet. The values come from the snapshot taken by Data, which is an independent copy, so no lock is needed while it is formatted and the result cannot change under the caller.
func (*InmemSink) IncrCounter ¶
IncrCounter accumulates values within the current interval.
type IntervalMetrics ¶
type IntervalMetrics struct {
sync.RWMutex
// The start time of the interval
Interval time.Time
// Gauges maps the key to the last set value
Gauges map[string]GaugeValue
// Counters maps the string key to a sum of the counter
// values
Counters map[string]SampledValue
// Samples maps the key to an AggregateSample,
// which has the rolled up view of a sample
Samples map[string]SampledValue
}
IntervalMetrics stores the aggregated metrics for a specific interval.
The embedded RWMutex guards the maps; hold it while reading them.
func NewIntervalMetrics ¶
func NewIntervalMetrics(intv time.Time) *IntervalMetrics
NewIntervalMetrics creates a new IntervalMetrics for a given interval.
type Metrics ¶
type Metrics struct {
Config
// contains filtered or unexported fields
}
Metrics represents an instance of a metrics sink that can be used to emit.
A Metrics value is safe for concurrent emission, and for concurrent UpdateFilter. It must not be copied.
func New ¶
New is used to create a new instance of Metrics.
The configuration is copied, including its tag and prefix slices, so later changes to conf do not affect the returned instance; use Metrics.UpdateFilter to change the filters. TimerGranularity and ProfileInterval fall back to their defaults when they are not positive. When conf.EnableRuntimeMetrics is set, New starts a collector goroutine that Metrics.Close stops. The error is always nil and exists for API compatibility.
func NewGlobal ¶
NewGlobal is the same as New, but it assigns the metrics object to be used globally as well as returning it.
The instance previously installed as global is not closed; close it first if it was collecting runtime metrics.
func (*Metrics) AddSample ¶
AddSample emits a sample, for timing information where quantiles are used. The metric is dropped when the configured filters block the key.
func (*Metrics) AllowMetric ¶ added in v0.10.151
AllowMetric reports whether the key passes the filters currently in effect.
func (*Metrics) Close ¶ added in v0.10.151
func (m *Metrics) Close()
Close stops the runtime metrics collector started by New. It is idempotent and safe for concurrent use. Emission keeps working after Close; only the background collector is stopped.
func (*Metrics) Help ¶ added in v0.10.151
Help returns the help text of the described metrics, keyed by the final metric name, omitting the metrics blocked by the filters currently in effect. It differs from Config.Help only after UpdateFilter has been called.
func (*Metrics) IncrCounter ¶
IncrCounter emits a counter increment, which should accumulate values. The metric is dropped when the configured filters block the key.
func (*Metrics) MeasureSince ¶
MeasureSince emits the time elapsed since start as a sample, in units of Config.TimerGranularity (milliseconds by default).
It is typically deferred at the top of the measured call:
defer m.MeasureSince("handler_duration", time.Now())
func (*Metrics) Prepare ¶ added in v0.10.151
Prepare returns the final metric name and tags to emit, and whether the metric passes the filters currently in effect.
It assembles the key exactly like Config.Prepare, but takes the filter verdict from the rules installed by UpdateFilter rather than from the embedded Config, which keeps the rules it was constructed with.
func (*Metrics) SetGauge ¶
SetGauge emits a gauge, which should retain the last value it is set to. The metric is dropped when the configured filters block the key.
func (*Metrics) UpdateFilter ¶
UpdateFilter overwrites the existing filter with the given rules. It is safe to call while other goroutines emit metrics: the rules are replaced as a whole, so an emission sees either the old or the new set.
The rules are copied. They do not update the embedded Config, which keeps the values Metrics was constructed with; Metrics.AllowMetric and Metrics.Prepare report the rules in effect.
type PointValue ¶
PointValue provides point value.
It is unused: EmitKey is not part of the Sink interface, because Prometheus has no type that retains an arbitrary number of values. The type is retained for API compatibility only.
type Provider ¶
type Provider interface {
// SetGauge should retain the last value it is set to
SetGauge(key string, val float64, tags ...Tag)
// IncrCounter should accumulate values
IncrCounter(key string, val float64, tags ...Tag)
// AddSample is for timing information, where quantiles are used
AddSample(key string, val float64, tags ...Tag)
// MeasureSince emits the time elapsed since start as a sample
MeasureSince(key string, start time.Time, tags ...Tag)
}
Provider is the interface application code should depend on to emit metrics. It is implemented by *Metrics, and mirrored by the package-level functions that emit to the global instance.
type SampledValue ¶
type SampledValue struct {
// Name is the metric name, without the flattened tags.
Name string
// Hash is the aggregation key: the name with its tags appended.
Hash string `json:"-"`
*AggregateSample
// Mean of the aggregated values, computed by DisplayMetrics.
Mean float64
// Stddev of the aggregated values, computed by DisplayMetrics.
Stddev float64
// Labels are the tags the value was emitted with.
Labels []Tag `json:"-"`
// DisplayLabels is the serializable form of Labels,
// populated by DisplayMetrics.
DisplayLabels map[string]string `json:"Labels"`
}
SampledValue provides sample value.
Mean and Stddev are derived once, when DisplayMetrics formats the value, from the AggregateSample it points to. In a value obtained from InmemSink.Data or DisplayMetrics that AggregateSample is an independent copy, so the three stay consistent with each other and do not change afterwards.
type Sink ¶
type Sink interface {
// SetGauge should retain the last value it is set to
SetGauge(key string, val float64, tags []Tag)
// IncrCounter should accumulate values
IncrCounter(key string, val float64, tags []Tag)
// AddSample is for timing information, where quantiles are used
AddSample(key string, val float64, tags []Tag)
}
The Sink interface is used to transmit metrics information to an external system.
Implementations receive the final key, after Config.Prepare has applied the prefixes and filters, and must be safe for concurrent use. The tags slice may be retained by the sink — InmemSink keeps it as the labels of the aggregated value — so callers must not modify a tags slice after passing it to an emit method.
func NewInmemSinkFromURL ¶
NewInmemSinkFromURL creates an InmemSink from a URL. It is used (and tested) from factory.NewMetricSinkFromURL.
The "interval" and "retain" query parameters are required and must parse as durations, for example:
inmem://localhost?interval=10s&retain=1m
Unlike NewInmemSink, an interval that is not positive or a retention shorter than two intervals is rejected with an error instead of being clamped.
type Summary ¶
type Summary struct {
Timestamp string
Gauges []GaugeValue
Counters []SampledValue
Samples []SampledValue
}
Summary holds a roll-up of metrics info for a given interval, in a shape suitable for JSON serialization on a debug endpoint.
type Tag ¶
type Tag struct {
// Name is the label name. It should be a valid identifier for the
// destination backend: lower case letters, digits and underscores.
Name string
// Value is the label value.
Value string
}
Tag is used to add dimensions to metrics.
A tag becomes a Prometheus label, a CloudWatch dimension, or part of the aggregation key in InmemSink. Every distinct value combination creates a new series in the backend, so keep the cardinality bounded: never tag with user IDs, request IDs or other unbounded values.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package cloudwatch provides a metrics.Sink that publishes to AWS CloudWatch.
|
Package cloudwatch provides a metrics.Sink that publishes to AWS CloudWatch. |
|
Package factory constructs a metrics.Sink from a URL, so the sink can be selected by configuration instead of by import.
|
Package factory constructs a metrics.Sink from a URL, so the sink can be selected by configuration instead of by import. |
|
Package prometheus provides a metrics.Sink backed by the Prometheus client library.
|
Package prometheus provides a metrics.Sink backed by the Prometheus client library. |