vmchain

package module
v0.0.0-...-90e37c6 Latest Latest
Warning

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

Go to latest
Published: Feb 14, 2026 License: MIT Imports: 7 Imported by: 1

README

Victoria Metrics chains

This library provides fast and convenient management of metrics recording in VictoriaMetrics. The idea: VM metrics, regardless of how they are created, through New* constructors or through GetOrCreate* adapters, only accept the full metric name as a string. This is not a problem when metrics do not contain any labels or labels have a known number with known values, for example:

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

But as soon as dynamic labels appear, there is no other way than to use concatenation

GetOrCreateCounter(`foo{stage="` + stageName + `",groupID="` + strconv.Itoa(groupID) + `"}`).Inc()

or fmt package

GetOrCreateCounter(fmt.Sprintf(`foo{stage="%s",groupID="%d"}`, stageName, groupID)).Inc()

Both of these methods are inconvenient to use and produce allocations, which causes a GC pressure and are slow in general.

Let's see what this library offers instead.

Solution Concept

Let's start with a typical usage example:

import "github.com/koykov/vmchain"

func myfunc() {
    stageName := "auth"
    groupID := 123
    vmchain.Counter("myservice_feature_counter").
        WithLabel("stage", stageName).
        WithAnyLabel("groupID", groupID).
        Add(123)
}

As a result of this code, a metric name will be created from the starting name "myservice_feature_counter", string label stage and numeric label groupID, and the final name will be myservice_feature_counter{stage="auth",groupID="123"}. Then, if the metric with this name is called for the first time, it will be registered in VM and its value will be updated. If the metric has been registered before, it will simply change its value.

The advantages of using the library are:

  • avoid to produce allocations
  • the WithAnyChain method eliminates the need to use the strconv package, i.e., another allocation
  • the chain-building approach - through a chain of calls to the WithChain/WithAnyChain methods there is no need to use concatenation or fmt package, and labels are added to the metric name in a convenient and obvious way

Allocations are given such heightened attention because the very idea of metrics is to measure what is happening in the project, but not to add an overhead to it. This is especially important in high-load projects, where every extra allocation in the hot path can lead to GC issues.

API

Currently, four main metric types are supported:

All these wrappers are combined into the Chain entity, which is a storage for the metrics themselves, internal buffers, and other auxiliary mechanisms. The library by default already contains an initialized chain and provides access to it through convenient functions Gauge, Counter, FloatCounter, and Histogram, located in default.go.

You can create your own chain using the NewChain function and use it as needed.

Performance

The project versus/vmchain demonstrates comparative benchmarks of four competitors:

and shows the following results:

BenchmarkVMChain/normal-8    	        11848255	       101.2 ns/op	       0 B/op	       0 allocs/op
BenchmarkVMChain/parallel-8             29461041	       45.63 ns/op	       0 B/op	       0 allocs/op
BenchmarkStringsBuilder/normal-8     	 9529771	       143.8 ns/op	     147 B/op	       3 allocs/op
BenchmarkStringsBuilder/parallel-8   	 4162002	       437.9 ns/op	     147 B/op	       3 allocs/op
BenchmarkConcat/normal-8             	 7849113	       130.3 ns/op	      83 B/op	       2 allocs/op
BenchmarkConcat/parallel-8           	 5054778	       305.5 ns/op	      83 B/op	       2 allocs/op
BenchmarkFmt/normal-8                	 3316862	       318.0 ns/op	     112 B/op	       3 allocs/op
BenchmarkFmt/parallel-8              	 3262021	       512.3 ns/op	     112 B/op	       3 allocs/op

The higher speed of vmchain is primarily achieved due to allocation-free work, which is a very significant advantage in high-load projects.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Chain

type Chain interface {
	// Gauge initialize with initName a gauge chain and return it.
	Gauge(initName string, f func() float64) GaugeChain
	// Counter initialize with initName a counter chain and return it.
	Counter(initName string) CounterChain
	// FloatCounter initialize with initName a float counter chain and return it.
	FloatCounter(initName string) FloatCounterChain
	// Histogram initialize with initName a histogram chain and return it.
	Histogram(initName string) HistogramChain
}

Chain represents a set for chains of metrics.

func NewChain

func NewChain(options ...Option) Chain

NewChain makes a new chain set.

type CounterChain

type CounterChain interface {
	WithLabel(name, value string) CounterChain
	WithAnyLabel(name string, value any) CounterChain
	Add(value int)
	AddInt64(value int64)
	Set(value uint64)
	Inc()
	Get() uint64
	Dec()
}

func Counter

func Counter(initName string) CounterChain

Counter return existing or create and return new counter metric.

initName is a base name of a metric (without any labels). It must be valid Prometheus-compatible name. Labels can be added separately using WithLabel chain method:

vmchain.Counter("my_counter_metric_name"). // prepare and return metric with name "my_counter_metric_name"

WithLabel("stage", "area").			// add a label, so metric name became "my_counter_metric_name{stage="area"}
WithLabel("userID", "123).			// add a label, so metric name became "my_counter_metric_name{stage="area",userID="123"}
Inc()								// finally construct full name of underlying counter metric, register it if necessary,
									// and call method Inc.

type FloatCounterChain

type FloatCounterChain interface {
	WithLabel(name, value string) FloatCounterChain
	WithAnyLabel(name string, value any) FloatCounterChain
	Add(value float64)
	Sub(value float64)
	Set(value float64)
	Get() float64
}

func FloatCounter

func FloatCounter(initName string) FloatCounterChain

FloatCounter return existing or create and return new float counter metric.

initName is a base name of a metric (without any labels). It must be valid Prometheus-compatible name. Labels can be added separately using WithLabel chain method:

vmchain.Counter("my_fcounter_metric_name"). // prepare and return metric with name "my_fcounter_metric_name"

WithLabel("stage", "area").			// add a label, so metric name became "my_counter_metric_name{stage="area"}
WithLabel("userID", "123).			// add a label, so metric name became "my_counter_metric_name{stage="area",userID="123"}
Inc()								// finally construct full name of underlying counter metric, register it if necessary,
									// and call method Inc.

type GaugeChain

type GaugeChain interface {
	WithLabel(name, value string) GaugeChain
	WithAnyLabel(name string, value any) GaugeChain
	Add(value float64)
	Set(value float64)
	Inc()
	Get() float64
	Dec()
}

func Gauge

func Gauge(initName string, f func() float64) GaugeChain

Gauge return existing or create and return new gauge metric.

initName is a base name of a metric (without any labels). It must be valid Prometheus-compatible name. Labels can be added separately using WithLabel chain method:

vmchain.Gauge("my_gauge_metric_name"). // prepare and return metric with name "my_gauge_metric_name"

WithLabel("stage", "area").			// add a label, so metric name became "my_gauge_metric_name{stage="area"}
WithLabel("userID", "123).			// add a label, so metric name became "my_gauge_metric_name{stage="area",userID="123"}
Inc()								// finally construct full name of underlying gauge metric, register it if necessary,
									// and call method Inc.

type HistogramChain

type HistogramChain interface {
	WithLabel(name, value string) HistogramChain
	WithAnyLabel(name string, value any) HistogramChain
	Update(value float64)
	UpdateDuration(startTime time.Time)
	VisitNonZeroBuckets(f func(vmrange string, count uint64))
	Reset()
}

func Histogram

func Histogram(initName string) HistogramChain

Histogram return existing or create and return new histogram metric.

initName is a base name of a metric (without any labels). It must be valid Prometheus-compatible name. Labels can be added separately using WithLabel chain method:

vmchain.Histogram("my_histogram_metric_name"). // prepare and return metric with name "my_histogram_metric_name"

WithLabel("stage", "area").			// add a label, so metric name became "my_histogram_metric_name{stage="area"}
WithLabel("userID", "123).			// add a label, so metric name became "my_histogram_metric_name{stage="area",userID="123"}
Inc()								// finally construct full name of underlying gauge metric, register it if necessary,
									// and call method Inc.

type Option

type Option func(c *chain)

func WithVMSet

func WithVMSet(vmset *metrics.Set) Option

WithVMSet sets Victoria Metrics Set to use for metrics storage. Caution! You must register set using metrics.RegisterSet yourself.

Jump to

Keyboard shortcuts

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