metrics

package module
v1.12.0 Latest Latest
Warning

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

Go to latest
Published: Feb 5, 2020 License: MIT Imports: 14 Imported by: 0

README

Build Status GoDoc Go Report codecov

metrics - lightweight package for exporting metrics in Prometheus format

Features
  • Lightweight. Has minimal number of third-party dependencies and all these deps are small. See this article for details.
  • Easy to use. See the API docs.
  • Fast.
  • Allows exporting distinct metric sets via distinct endpoints. See Set.
  • Supports easy-to-use histograms, which just work without any tuning. Read more about VictoriaMetrics histograms at this article.
Limitations
Usage
import "github.com/VictoriaMetrics/metrics"

// Register various time series.
// Time series name may contain labels in Prometheus format - see below.
var (
	// Register counter without labels.
	requestsTotal = metrics.NewCounter("requests_total")

	// Register summary with a single label.
	requestDuration = metrics.NewSummary(`requests_duration_seconds{path="/foobar/baz"}`)

	// Register gauge with two labels.
	queueSize = metrics.NewGauge(`queue_size{queue="foobar",topic="baz"}`, func() float64 {
		return float64(foobarQueue.Len())
	})

	// Register histogram with a single label.
	responseSize = metrics.NewHistogram(`response_size{path="/foo/bar"}`)
)

// ...
func requestHandler() {
	// Increment requestTotal counter.
	requestsTotal.Inc()

	startTime := time.Now()
	processRequest()
	// Update requestDuration summary.
	requestDuration.UpdateDuration(startTime)

	// Update responseSize histogram.
	responseSize.Update(responseSize)
}

// Expose the registered metrics at `/metrics` path.
http.HandleFunc("/metrics", func(w http.ResponseWriter, req *http.Request) {
	metrics.WritePrometheus(w, true)
})

See docs for more info.

Users
FAQ
Why the metrics API isn't compatible with github.com/prometheus/client_golang?

Because the github.com/prometheus/client_golang is too complex and is hard to use.

Why the metrics.WritePrometheus doesn't expose documentation for each metric?

Because this documentation is ignored by Prometheus. The documentation is for users. Just add comments in the source code or in other suitable place explaining each metric exposed from your application.

How to implement CounterVec in metrics?

Just use GetOrCreateCounter instead of CounterVec.With. See this example for details.

Why Histogram buckets contain vmrange labels instead of le labels like in Prometheus histograms?

Buckets with vmrange labels occupy less disk space comparing to Promethes-style buckets with le labels, because vmrange buckets don't include counters for the previous ranges. VictoriaMetrics provides prometheus_buckets function, which converts vmrange buckets to Prometheus-style buckets with le labels. This is useful for building heatmaps in Grafana. Additionally, its' histogram_quantile function transparently handles histogram buckets with vmrange labels.

Documentation

Overview

Package metrics implements Prometheus-compatible metrics for applications.

This package is lightweight alternative to https://github.com/prometheus/client_golang with simpler API and smaller dependencies.

Usage:

  1. Register the required metrics via New* functions.
  2. Expose them to `/metrics` page via WritePrometheus.
  3. Update the registered metrics during application lifetime.

The package has been extracted from https://victoriametrics.com/

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func SetTTL

func SetTTL(ttl time.Duration)

func WritePrometheus

func WritePrometheus(w io.Writer, exposeProcessMetrics bool)

WritePrometheus writes all the registered metrics in Prometheus format to w.

If exposeProcessMetrics is true, then various `go_*` and `process_*` metrics are exposed for the current process.

The WritePrometheus func is usually called inside "/metrics" handler:

http.HandleFunc("/metrics", func(w http.ResponseWriter, req *http.Request) {
    metrics.WritePrometheus(w, true)
})
Example
package main

import (
	"net/http"

	"github.com/faceair/metrics"
)

func main() {
	// Export all the registered metrics in Prometheus format at `/metrics` http path.
	http.HandleFunc("/metrics", func(w http.ResponseWriter, req *http.Request) {
		metrics.WritePrometheus(w, true)
	})
}
Output:

Types

type Counter

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

Counter is a counter.

It may be used as a gauge if Dec and Set are called.

Example
package main

import (
	"fmt"
	"github.com/faceair/metrics"
)

func main() {
	// Define a counter in global scope.
	var c = metrics.NewCounter(`metric_total{label1="value1", label2="value2"}`)

	// Increment the counter when needed.
	for i := 0; i < 10; i++ {
		c.Inc()
	}
	n := c.Get()
	fmt.Println(n)

}
Output:

10
Example (Vec)
package main

import (
	"fmt"
	"github.com/faceair/metrics"
)

func main() {
	for i := 0; i < 3; i++ {
		// Dynamically construct metric name and pass it to GetOrCreateCounter.
		name := fmt.Sprintf(`metric_total{label1=%q, label2="%d"}`, "value1", i)
		metrics.GetOrCreateCounter(name).Add(i + 1)
	}

	// Read counter values.
	for i := 0; i < 3; i++ {
		name := fmt.Sprintf(`metric_total{label1=%q, label2="%d"}`, "value1", i)
		n := metrics.GetOrCreateCounter(name).Get()
		fmt.Println(n)
	}

}
Output:

1
2
3

func GetOrCreateCounter

func GetOrCreateCounter(name string) *Counter

GetOrCreateCounter returns registered counter with the given name or creates new counter if the registry doesn't contain counter with the given name.

name must be valid Prometheus-compatible metric with possible labels. For instance,

  • foo
  • foo{bar="baz"}
  • foo{bar="baz",aaa="b"}

The returned counter is safe to use from concurrent goroutines.

Performance tip: prefer NewCounter instead of GetOrCreateCounter.

func NewCounter

func NewCounter(name string) *Counter

NewCounter registers and returns new counter with the given name.

name must be valid Prometheus-compatible metric with possible labels. For instance,

  • foo
  • foo{bar="baz"}
  • foo{bar="baz",aaa="b"}

The returned counter is safe to use from concurrent goroutines.

func (*Counter) Add

func (c *Counter) Add(n int)

Add adds n to c.

func (*Counter) Dec

func (c *Counter) Dec()

Dec decrements c.

func (*Counter) Get

func (c *Counter) Get() uint64

Get returns the current value for c.

func (*Counter) Inc

func (c *Counter) Inc()

Inc increments c.

func (*Counter) Set

func (c *Counter) Set(n uint64)

Set sets c value to n.

type FloatCounter

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

FloatCounter is a float64 counter guarded by RWmutex.

It may be used as a gauge if Add and Sub are called.

Example
package main

import (
	"fmt"
	"github.com/faceair/metrics"
)

func main() {
	// Define a float64 counter in global scope.
	var fc = metrics.NewFloatCounter(`float_metric_total{label1="value1", label2="value2"}`)

	// Add to the counter when needed.
	for i := 0; i < 10; i++ {
		fc.Add(1.01)
	}
	n := fc.Get()
	fmt.Println(n)

}
Output:

10.1
Example (Vec)
package main

import (
	"fmt"
	"github.com/faceair/metrics"
)

func main() {
	for i := 0; i < 3; i++ {
		// Dynamically construct metric name and pass it to GetOrCreateFloatCounter.
		name := fmt.Sprintf(`float_metric_total{label1=%q, label2="%d"}`, "value1", i)
		metrics.GetOrCreateFloatCounter(name).Add(float64(i) + 1.01)
	}

	// Read counter values.
	for i := 0; i < 3; i++ {
		name := fmt.Sprintf(`float_metric_total{label1=%q, label2="%d"}`, "value1", i)
		n := metrics.GetOrCreateFloatCounter(name).Get()
		fmt.Println(n)
	}

}
Output:

1.01
2.01
3.01

func GetOrCreateFloatCounter

func GetOrCreateFloatCounter(name string) *FloatCounter

GetOrCreateFloatCounter returns registered FloatCounter with the given name or creates new FloatCounter if the registry doesn't contain FloatCounter with the given name.

name must be valid Prometheus-compatible metric with possible labels. For instance,

  • foo
  • foo{bar="baz"}
  • foo{bar="baz",aaa="b"}

The returned FloatCounter is safe to use from concurrent goroutines.

Performance tip: prefer NewFloatCounter instead of GetOrCreateFloatCounter.

func NewFloatCounter

func NewFloatCounter(name string) *FloatCounter

NewFloatCounter registers and returns new counter of float64 type with the given name.

name must be valid Prometheus-compatible metric with possible labels. For instance,

  • foo
  • foo{bar="baz"}
  • foo{bar="baz",aaa="b"}

The returned counter is safe to use from concurrent goroutines.

func (*FloatCounter) Add

func (fc *FloatCounter) Add(n float64)

Add adds n to fc.

func (*FloatCounter) Get

func (fc *FloatCounter) Get() float64

Get returns the current value for fc.

func (*FloatCounter) Set

func (fc *FloatCounter) Set(n float64)

Set sets fc value to n.

func (*FloatCounter) Sub

func (fc *FloatCounter) Sub(n float64)

Sub substracts n from fc.

type Gauge

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

Gauge is a float64 gauge.

See also Counter, which could be used as a gauge with Set and Dec calls.

Example
package main

import (
	"fmt"
	"runtime"

	"github.com/faceair/metrics"
)

func main() {
	// Define a gauge exporting the number of goroutines.
	var g = metrics.NewGauge(`goroutines_count`)
	g.Set(float64(runtime.NumGoroutine()))

	// Obtain gauge value.
	fmt.Println(g.Get())
}
Output:

Example (Vec)
package main

import (
	"fmt"

	"github.com/faceair/metrics"
)

func main() {
	for i := 0; i < 3; i++ {
		// Dynamically construct metric name and pass it to GetOrCreateGauge.
		name := fmt.Sprintf(`metric{label1=%q, label2="%d"}`, "value1", i)
		gauge := metrics.GetOrCreateGauge(name)
		gauge.Set(float64(i))
	}

	// Read counter values.
	for i := 0; i < 3; i++ {
		name := fmt.Sprintf(`metric{label1=%q, label2="%d"}`, "value1", i)
		n := metrics.GetOrCreateGauge(name).Get()
		fmt.Println(n)
	}

}
Output:

0
1
2

func GetOrCreateGauge

func GetOrCreateGauge(name string) *Gauge

GetOrCreateGauge returns registered gauge with the given name or creates new gauge if the registry doesn't contain gauge with the given name.

name must be valid Prometheus-compatible metric with possible labels. For instance,

  • foo
  • foo{bar="baz"}
  • foo{bar="baz",aaa="b"}

The returned gauge is safe to use from concurrent goroutines.

Performance tip: prefer NewGauge instead of GetOrCreateGauge.

func NewGauge

func NewGauge(name string) *Gauge

NewGauge registers and returns gauge with the given name, which calls f to obtain gauge value.

name must be valid Prometheus-compatible metric with possible labels. For instance,

  • foo
  • foo{bar="baz"}
  • foo{bar="baz",aaa="b"}

f must be safe for concurrent calls.

The returned gauge is safe to use from concurrent goroutines.

func (*Gauge) Get

func (g *Gauge) Get() float64

Get returns the current value for g.

func (*Gauge) Set added in v1.12.0

func (g *Gauge) Set(n float64)

Set sets g value to n.

type Histogram

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

Histogram is a histogram for non-negative values with automatically created buckets.

See https://medium.com/@valyala/improving-histogram-usability-for-prometheus-and-grafana-bc7e5df0e350

Each bucket contains a counter for values in the given range. Each non-empty bucket is exposed via the following metric:

<metric_name>_bucket{<optional_tags>,vmrange="<start>...<end>"} <counter>

Where:

  • <metric_name> is the metric name passed to NewHistogram
  • <optional_tags> is optional tags for the <metric_name>, which are passed to NewHistogram
  • <start> and <end> - start and end values for the given bucket
  • <counter> - the number of hits to the given bucket during Update* calls

Histogram buckets can be converted to Prometheus-like buckets with `le` labels with `prometheus_buckets(<metric_name>_bucket)` function from PromQL extensions in VictoriaMetrics. (see https://github.com/VictoriaMetrics/VictoriaMetrics/wiki/ExtendedPromQL ):

prometheus_buckets(request_duration_bucket)

Time series produced by the Histogram have better compression ratio comparing to Prometheus histogram buckets with `le` labels, since they don't include counters for all the previous buckets.

Zero histogram is usable.

Example
// Define a histogram in global scope.
var h = metrics.NewHistogram(`request_duration_seconds{path="/foo/bar"}`)

// Update the histogram with the duration of processRequest call.
startTime := time.Now()
processRequest()
h.UpdateDuration(startTime)
Output:

Example (Vec)
for i := 0; i < 3; i++ {
	// Dynamically construct metric name and pass it to GetOrCreateHistogram.
	name := fmt.Sprintf(`response_size_bytes{path=%q}`, "/foo/bar")
	response := processRequest()
	metrics.GetOrCreateHistogram(name).Update(float64(len(response)))
}
Output:

func GetOrCreateHistogram

func GetOrCreateHistogram(name string) *Histogram

GetOrCreateHistogram returns registered histogram with the given name or creates new histogram if the registry doesn't contain histogram with the given name.

name must be valid Prometheus-compatible metric with possible labels. For instance,

  • foo
  • foo{bar="baz"}
  • foo{bar="baz",aaa="b"}

The returned histogram is safe to use from concurrent goroutines.

Performance tip: prefer NewHistogram instead of GetOrCreateHistogram.

func NewHistogram

func NewHistogram(name string) *Histogram

NewHistogram creates and returns new histogram with the given name.

name must be valid Prometheus-compatible metric with possible labels. For instance,

  • foo
  • foo{bar="baz"}
  • foo{bar="baz",aaa="b"}

The returned histogram is safe to use from concurrent goroutines.

func (*Histogram) Reset

func (h *Histogram) Reset()

Reset resets the given histogram.

func (*Histogram) Update

func (h *Histogram) Update(v float64)

Update updates h with v.

Negative values and NaNs are ignored.

func (*Histogram) UpdateDuration

func (h *Histogram) UpdateDuration(startTime time.Time)

UpdateDuration updates request duration based on the given startTime.

func (*Histogram) VisitNonZeroBuckets

func (h *Histogram) VisitNonZeroBuckets(f func(vmrange string, count uint64))

VisitNonZeroBuckets calls f for all buckets with non-zero counters.

vmrange contains "<start>...<end>" string with bucket bounds. The lower bound isn't included in the bucket, while the upper bound is included. This is required to be compatible with Prometheus-style histogram buckets with `le` (less or equal) labels.

type Set

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

Set is a set of metrics.

Metrics belonging to a set are exported separately from global metrics.

Set.WritePrometheus must be called for exporting metrics from the set.

Example
package main

import (
	"bytes"
	"fmt"
	"github.com/faceair/metrics"
)

func main() {
	// Create a set with a counter
	s := metrics.NewSet()
	sc := s.NewCounter("set_counter")
	sc.Inc()
	s.NewGauge(`set_gauge{foo="bar"}`, func() float64 { return 42 })

	// Dump metrics from s.
	var bb bytes.Buffer
	s.WritePrometheus(&bb)
	fmt.Printf("set metrics:\n%s\n", bb.String())

}
Output:

set metrics:
set_counter 1
set_gauge{foo="bar"} 42

func NewSet

func NewSet() *Set

NewSet creates new set of metrics.

func (*Set) GetOrCreateCounter

func (s *Set) GetOrCreateCounter(name string) *Counter

GetOrCreateCounter returns registered counter in s with the given name or creates new counter if s doesn't contain counter with the given name.

name must be valid Prometheus-compatible metric with possible labels. For instance,

  • foo
  • foo{bar="baz"}
  • foo{bar="baz",aaa="b"}

The returned counter is safe to use from concurrent goroutines.

Performance tip: prefer NewCounter instead of GetOrCreateCounter.

func (*Set) GetOrCreateFloatCounter

func (s *Set) GetOrCreateFloatCounter(name string) *FloatCounter

GetOrCreateFloatCounter returns registered FloatCounter in s with the given name or creates new FloatCounter if s doesn't contain FloatCounter with the given name.

name must be valid Prometheus-compatible metric with possible labels. For instance,

  • foo
  • foo{bar="baz"}
  • foo{bar="baz",aaa="b"}

The returned FloatCounter is safe to use from concurrent goroutines.

Performance tip: prefer NewFloatCounter instead of GetOrCreateFloatCounter.

func (*Set) GetOrCreateGauge

func (s *Set) GetOrCreateGauge(name string) *Gauge

GetOrCreateGauge returns registered gauge with the given name in s or creates new gauge if s doesn't contain gauge with the given name.

name must be valid Prometheus-compatible metric with possible labels. For instance,

  • foo
  • foo{bar="baz"}
  • foo{bar="baz",aaa="b"}

The returned gauge is safe to use from concurrent goroutines.

Performance tip: prefer NewGauge instead of GetOrCreateGauge.

func (*Set) GetOrCreateHistogram

func (s *Set) GetOrCreateHistogram(name string) *Histogram

GetOrCreateHistogram returns registered histogram in s with the given name or creates new histogram if s doesn't contain histogram with the given name.

name must be valid Prometheus-compatible metric with possible labels. For instance,

  • foo
  • foo{bar="baz"}
  • foo{bar="baz",aaa="b"}

The returned histogram is safe to use from concurrent goroutines.

Performance tip: prefer NewHistogram instead of GetOrCreateHistogram.

func (*Set) GetOrCreateSummary

func (s *Set) GetOrCreateSummary(name string) *Summary

GetOrCreateSummary returns registered summary with the given name in s or creates new summary if s doesn't contain summary with the given name.

name must be valid Prometheus-compatible metric with possible labels. For instance,

  • foo
  • foo{bar="baz"}
  • foo{bar="baz",aaa="b"}

The returned summary is safe to use from concurrent goroutines.

Performance tip: prefer NewSummary instead of GetOrCreateSummary.

func (*Set) GetOrCreateSummaryExt

func (s *Set) GetOrCreateSummaryExt(name string, window time.Duration, quantiles []float64) *Summary

GetOrCreateSummaryExt returns registered summary with the given name, window and quantiles in s or creates new summary if s doesn't contain summary with the given name.

name must be valid Prometheus-compatible metric with possible labels. For instance,

  • foo
  • foo{bar="baz"}
  • foo{bar="baz",aaa="b"}

The returned summary is safe to use from concurrent goroutines.

Performance tip: prefer NewSummaryExt instead of GetOrCreateSummaryExt.

func (*Set) NewCounter

func (s *Set) NewCounter(name string) *Counter

NewCounter registers and returns new counter with the given name in the s.

name must be valid Prometheus-compatible metric with possible labels. For instance,

  • foo
  • foo{bar="baz"}
  • foo{bar="baz",aaa="b"}

The returned counter is safe to use from concurrent goroutines.

func (*Set) NewFloatCounter

func (s *Set) NewFloatCounter(name string) *FloatCounter

NewFloatCounter registers and returns new FloatCounter with the given name in the s.

name must be valid Prometheus-compatible metric with possible labels. For instance,

  • foo
  • foo{bar="baz"}
  • foo{bar="baz",aaa="b"}

The returned FloatCounter is safe to use from concurrent goroutines.

func (*Set) NewGauge

func (s *Set) NewGauge(name string) *Gauge

NewGauge registers and returns gauge with the given name in s, which calls f to obtain gauge value.

name must be valid Prometheus-compatible metric with possible labels. For instance,

  • foo
  • foo{bar="baz"}
  • foo{bar="baz",aaa="b"}

f must be safe for concurrent calls.

The returned gauge is safe to use from concurrent goroutines.

func (*Set) NewHistogram

func (s *Set) NewHistogram(name string) *Histogram

NewHistogram creates and returns new histogram in s with the given name.

name must be valid Prometheus-compatible metric with possible labels. For instance,

  • foo
  • foo{bar="baz"}
  • foo{bar="baz",aaa="b"}

The returned histogram is safe to use from concurrent goroutines.

func (*Set) NewSummary

func (s *Set) NewSummary(name string) *Summary

NewSummary creates and returns new summary with the given name in s.

name must be valid Prometheus-compatible metric with possible labels. For instance,

  • foo
  • foo{bar="baz"}
  • foo{bar="baz",aaa="b"}

The returned summary is safe to use from concurrent goroutines.

func (*Set) NewSummaryExt

func (s *Set) NewSummaryExt(name string, window time.Duration, quantiles []float64) *Summary

NewSummaryExt creates and returns new summary in s with the given name, window and quantiles.

name must be valid Prometheus-compatible metric with possible labels. For instance,

  • foo
  • foo{bar="baz"}
  • foo{bar="baz",aaa="b"}

The returned summary is safe to use from concurrent goroutines.

func (*Set) SetTTL

func (s *Set) SetTTL(ttl time.Duration)

func (*Set) WritePrometheus

func (s *Set) WritePrometheus(w io.Writer)

WritePrometheus writes all the metrics from s to w in Prometheus format.

type Summary

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

Summary implements summary.

Example
package main

import (
	"time"

	"github.com/faceair/metrics"
)

func main() {
	// Define a summary in global scope.
	var s = metrics.NewSummary(`request_duration_seconds{path="/foo/bar"}`)

	// Update the summary with the duration of processRequest call.
	startTime := time.Now()
	processRequest()
	s.UpdateDuration(startTime)
}

func processRequest() string {
	return "foobar"
}
Output:

Example (Vec)
package main

import (
	"fmt"

	"github.com/faceair/metrics"
)

func main() {
	for i := 0; i < 3; i++ {
		// Dynamically construct metric name and pass it to GetOrCreateSummary.
		name := fmt.Sprintf(`response_size_bytes{path=%q}`, "/foo/bar")
		response := processRequest()
		metrics.GetOrCreateSummary(name).Update(float64(len(response)))
	}
}

func processRequest() string {
	return "foobar"
}
Output:

func GetOrCreateSummary

func GetOrCreateSummary(name string) *Summary

GetOrCreateSummary returns registered summary with the given name or creates new summary if the registry doesn't contain summary with the given name.

name must be valid Prometheus-compatible metric with possible labels. For instance,

  • foo
  • foo{bar="baz"}
  • foo{bar="baz",aaa="b"}

The returned summary is safe to use from concurrent goroutines.

Performance tip: prefer NewSummary instead of GetOrCreateSummary.

func GetOrCreateSummaryExt

func GetOrCreateSummaryExt(name string, window time.Duration, quantiles []float64) *Summary

GetOrCreateSummaryExt returns registered summary with the given name, window and quantiles or creates new summary if the registry doesn't contain summary with the given name.

name must be valid Prometheus-compatible metric with possible labels. For instance,

  • foo
  • foo{bar="baz"}
  • foo{bar="baz",aaa="b"}

The returned summary is safe to use from concurrent goroutines.

Performance tip: prefer NewSummaryExt instead of GetOrCreateSummaryExt.

func NewSummary

func NewSummary(name string) *Summary

NewSummary creates and returns new summary with the given name.

name must be valid Prometheus-compatible metric with possible labels. For instance,

  • foo
  • foo{bar="baz"}
  • foo{bar="baz",aaa="b"}

The returned summary is safe to use from concurrent goroutines.

func NewSummaryExt

func NewSummaryExt(name string, window time.Duration, quantiles []float64) *Summary

NewSummaryExt creates and returns new summary with the given name, window and quantiles.

name must be valid Prometheus-compatible metric with possible labels. For instance,

  • foo
  • foo{bar="baz"}
  • foo{bar="baz",aaa="b"}

The returned summary is safe to use from concurrent goroutines.

func (*Summary) Update

func (sm *Summary) Update(v float64)

Update updates the summary.

func (*Summary) UpdateDuration

func (sm *Summary) UpdateDuration(startTime time.Time)

UpdateDuration updates request duration based on the given startTime.

Jump to

Keyboard shortcuts

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