metrics

package
v0.0.5 Latest Latest
Warning

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

Go to latest
Published: Sep 13, 2024 License: Apache-2.0 Imports: 2 Imported by: 0

Documentation

Overview

Package metrics provides an API for counters, gauges, and histograms.

Metric Types

The metrics package provides types for three metrics: counters, gauges, and histograms.

  • A Counter is a number that can only increase over time. It never decreases. You can use a counter to measure things like the number of HTTP requests your program has processed so far.
  • A Gauge is a number that can increase or decrease over time. You can use a gauge to measure things like the current amount of memory your program is using, in bytes.
  • A Histogram is a collection of numbers that are grouped into buckets. You can use a histogram to measure things like the latency of every HTTP request your program has received so far.

Declaring Metrics

Declare metrics using NewCounter, NewGauge, or NewHistogram. We recommend you declare metrics at package scope.

var (
	exampleCount = metrics.NewCounter(
		"example_count",
		"An example counter",
	)
	exampleGauge = metrics.NewGauge(
		"example_gauge",
		"An example gauge",
	)
	exampleHistogram = metrics.NewHistogram(
		"example_histogram",
		"An example histogram",
		[]float64{1, 10, 100, 1000, 10000},
	)
)

Updating Metrics

Every metric type has a set of methods you can use to update the metric. Counters can be added to. Gauges can be set. Histograms can have values added to them.

func main() {
	exampleCount.Add(1)
	exampleGauge.Set(2)
	exampleHistogram.Put(3)
}

Metric Labels

You can declare a metric with a set of key-value labels. For example, if you have a metric that measures the latency of handling HTTP requests, you can declare the metric with a label that identifies the URL of the request (e.g., "/users/foo").

You can declare a labeled metric using NewCounterMap, NewGaugeMap, or NewHistogramMap. Service Weaver represents metric labels using structs. For example, here's how to declare a counter with labels "foo" and "bar":

type labels struct {
    Foo string
    Bar string
}
var exampleLabeledCounter = xcweaver.NewCounterMap[labels](
    "example_labeled_counter",
    `An example counter with labels "foo" and "bar"`,
)

Use the Get method to get a metric with the provided set of label values.

func main() {
    // Get the counter with foo="a" and bar="b".
    counter := exampleLabeledCounter.Get(labels{Foo: "a", Bar: "b"})
    counter.Add(1)
}

More precisely, labels are represented as a comparable struct of type L. We say a label struct L is valid if every field of L is a string, bool, or integer type and is exported. For example, the following are valid label structs:

struct{}         // an empty struct
struct{X string} // a struct with one field
struct{X, Y int} // a struct with two fields

The following are invalid label structs:

struct{x string}   // unexported field
string             // not a struct
struct{X chan int} // unsupported label type (i.e. chan int)

Note that the order of the fields within a label struct is unimportant. For example, if one program exports a metric with labels

struct{X, Y string}

another program can safely export the same metric with labels

struct{Y, X string}

To adhere to popular metric naming conventions, the first letter of every label is lowercased by default. The Foo label for example is exported as "foo", not "Foo". You can override this behavior and provide a custom label name using a xcweaver annotation.

type labels struct {
    Foo string                           // exported as "foo"
    Bar string `xcweaver:"my_custom_name"` // exported as "my_custom_name"
}

Exporting Metrics

Service Weaver integrates metrics into the environment where your application is deployed. If you deploy a Service Weaver application to Google Cloud, for example, metrics are automatically exported to the Google Cloud Metrics Explorer where they can be queried, aggregated, and graphed. Refer to your deployer documentation for details.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Counter

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

A Counter is a float-valued, monotonically increasing metric. For example, you can use a Counter to count the number of requests received, the number of requests that resulted in an error, etc.

func NewCounter

func NewCounter(name, help string) *Counter

NewCounter returns a new Counter. It is typically called during package initialization since it panics if called more than once in the same process with the same name. Use NewCounterMap to make a Counter with labels.

func (*Counter) Add

func (c *Counter) Add(delta float64)

Add increases the counter by delta. It panics if the delta is negative.

func (*Counter) Inc

func (c *Counter) Inc()

Inc increases the counter by one.

func (*Counter) Name

func (c *Counter) Name() string

Name returns the name of the counter.

type CounterMap

type CounterMap[L comparable] struct {
	// contains filtered or unexported fields
}

A CounterMap is a collection of Counters with the same name and label schema but with different label values. See package documentation for a description of L.

Example
package main

import (
	"github.com/XCWeaver/xcweaver/metrics"
)

func main() {
	// At package scope.
	type carLabels struct {
		Make  string
		Model string
	}

	var (
		carCounts  = metrics.NewCounterMap[carLabels]("car_count", "The number of cars")
		civicCount = carCounts.Get(carLabels{"Honda", "Civic"})
		camryCount = carCounts.Get(carLabels{"Toyota", "Camry"})
		f150Count  = carCounts.Get(carLabels{"Ford", "F-150"})
	)

	// In your code.
	civicCount.Add(1)
	camryCount.Add(2)
	f150Count.Add(150)
}
Output:

func NewCounterMap

func NewCounterMap[L comparable](name, help string) *CounterMap[L]

NewCounterMap returns a new CounterMap. It is typically called during package initialization since it panics if called more than once in the same process with the same name.

func (*CounterMap[L]) Get

func (c *CounterMap[L]) Get(labels L) *Counter

Get returns the Counter with the provided labels, constructing it if it doesn't already exist. Multiple calls to Get with the same labels will return the same Counter.

func (*CounterMap[L]) Name

func (c *CounterMap[L]) Name() string

Name returns the name of the CounterMap.

type Gauge

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

A Gauge is a float-valued metric that can hold an arbitrary numerical value, which can increase or decrease over time. For example, you can use a Gauge to measure the current memory usage or the current number of outstanding requests.

func NewGauge

func NewGauge(name, help string) *Gauge

NewGauge returns a new Gauge. It is typically called during package initialization since it panics if called more than once in the same process with the same name. Use NewGaugeMap to make a Gauge with labels.

func (*Gauge) Add

func (g *Gauge) Add(delta float64)

Add adds the provided delta to the gauge's value.

func (*Gauge) Name

func (g *Gauge) Name() string

Name returns the name of the Gauge.

func (*Gauge) Set

func (g *Gauge) Set(val float64)

Set sets the gauge to the given value, overwriting any previous value.

func (*Gauge) Sub

func (g *Gauge) Sub(delta float64)

Sub subtracts the provided delta from the gauge's value.

type GaugeMap

type GaugeMap[L comparable] struct {
	// contains filtered or unexported fields
}

A GaugeMap is a collection of Gauges with the same name and label schema but with different label values. See package documentation for a description of L.

Example
package main

import (
	"github.com/XCWeaver/xcweaver/metrics"
)

func main() {
	// At package scope.
	type tempLabels struct {
		Room  string
		Index int
	}

	var (
		temps          = metrics.NewGaugeMap[tempLabels]("temperature", "Temperature, in Fahrenheit")
		livingRoomTemp = temps.Get(tempLabels{"Living Room", 0})
		bathroomTemp   = temps.Get(tempLabels{"Bathroom", 0})
		bedroom0Temp   = temps.Get(tempLabels{"Bedroom", 0})
		bedroom1Temp   = temps.Get(tempLabels{"Bedroom", 1})
	)

	// In your code.
	livingRoomTemp.Set(78.4)
	bathroomTemp.Set(65.3)
	bedroom0Temp.Set(84.1)
	bedroom1Temp.Set(80.9)
	livingRoomTemp.Add(1.2)
	bathroomTemp.Sub(2.1)
}
Output:

func NewGaugeMap

func NewGaugeMap[L comparable](name, help string) *GaugeMap[L]

NewGaugeMap returns a new GaugeMap. It is typically called during package initialization since it panics if called more than once in the same process with the same name.

func (*GaugeMap[L]) Get

func (g *GaugeMap[L]) Get(labels L) *Gauge

Get returns the Gauge with the provided labels, constructing it if it doesn't already exist. Multiple calls to Get with the same labels will return the same Gauge.

func (*GaugeMap[L]) Name

func (g *GaugeMap[L]) Name() string

Name returns the name of the GaugeMap.

type Histogram

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

A Histogram is a metric that counts the number of values that fall in specified ranges (i.e. buckets). For example, you can use a Histogram to measure the distribution of request latencies.

func NewHistogram

func NewHistogram(name, help string, bounds []float64) *Histogram

NewHistogram returns a new Histogram. It is typically called during package initialization since it panics if called more than once in the same process with the same name. Use NewHistogram to make a Histogram with labels.

The bucket boundaries must be strictly increasing. Given n boundary values, the histogram will contain n+1 buckets, organized as follows:

  • bucket[0] is the underflow bucket, which counts values in the range [-inf, bounds[0]).
  • bucket[n] is the overflow bucket, which counts values in the range [bounds[n-1], +inf).
  • bucket[i], for 0 < i < n, is a bucket that counts values in the range [bounds[i-1], bounds[i]).

For example, given the bounds [0, 10, 100], we have the following buckets:

  • Bucket 0: (-inf, 0]
  • Bucket 1: [0, 10)
  • Bucket 2: [10, 100)
  • Bucket 3: [100, +inf)

func (*Histogram) Name

func (h *Histogram) Name() string

Name returns the name of the histogram.

func (*Histogram) Put

func (h *Histogram) Put(val float64)

Put records a value in its bucket.

type HistogramMap

type HistogramMap[L comparable] struct {
	// contains filtered or unexported fields
}

A HistogramMap is a collection of Histograms with the same name and label schema but with different label values. See package documentation for a description of L.

Example
package main

import (
	"github.com/XCWeaver/xcweaver/metrics"
)

func main() {
	// At package scope.
	type latencyLabels struct {
		Endpoint string
	}

	var (
		latencies = metrics.NewHistogramMap[latencyLabels](
			"http_request_latency_nanoseconds",
			"HTTP request latency, in nanoseconds, by endpoint",
			[]float64{10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000},
		)
		fooLatency     = latencies.Get(latencyLabels{"/foo"})
		barLatency     = latencies.Get(latencyLabels{"/bar"})
		metricsLatency = latencies.Get(latencyLabels{"/metrics"})
	)

	// In your code.
	fooLatency.Put(8714.5)
	barLatency.Put(491.7)
	metricsLatency.Put(375.0)
}
Output:

func NewHistogramMap

func NewHistogramMap[L comparable](name, help string, bounds []float64) *HistogramMap[L]

NewHistogramMap returns a new HistogramMap. It is typically called during package initialization since it panics if called more than once in the same process with the same name.

func (*HistogramMap[L]) Get

func (h *HistogramMap[L]) Get(labels L) *Histogram

Get returns the Histogram with the provided labels, constructing it if it doesn't already exist. Multiple calls to Get with the same labels will return the same Histogram.

func (*HistogramMap[L]) Name

func (h *HistogramMap[L]) Name() string

Name returns the name of the HistogramMap.

Jump to

Keyboard shortcuts

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