generated from TrueCloudLab/basic
[#1] metrics: Add metrics pkg
Signed-off-by: Dmitrii Stepanov <d.stepanov@yadro.com>
This commit is contained in:
parent
6b3d863d81
commit
cf41206fec
5 changed files with 273 additions and 0 deletions
112
metrics/desc.go
Normal file
112
metrics/desc.go
Normal file
|
@ -0,0 +1,112 @@
|
|||
package metrics
|
||||
|
||||
import (
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
)
|
||||
|
||||
// Descriptions contains metric Description suitable for further processing.
|
||||
// The only reason for it to exist is `prometheus.Desc` disallowing field access directly.
|
||||
// https://github.com/prometheus/client_golang/pull/326
|
||||
// https://github.com/prometheus/client_golang/issues/516
|
||||
// https://github.com/prometheus/client_golang/issues/222
|
||||
type Description struct {
|
||||
Name string `json:"name"`
|
||||
Help string `json:"help"`
|
||||
Type string `json:"type"`
|
||||
ConstantLabels prometheus.Labels `json:"constant_labels,omitempty"`
|
||||
VariableLabels []string `json:"variable_labels,omitempty"`
|
||||
}
|
||||
|
||||
// NewGauge returns new registered prometheus.Gauge.
|
||||
func NewGauge(opts prometheus.GaugeOpts) prometheus.Gauge {
|
||||
value := prometheus.NewGauge(opts)
|
||||
mustRegister(value, Description{
|
||||
Name: prometheus.BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
|
||||
Type: dto.MetricType_GAUGE.String(),
|
||||
Help: opts.Help,
|
||||
ConstantLabels: opts.ConstLabels,
|
||||
})
|
||||
return value
|
||||
}
|
||||
|
||||
// NewGaugeVec returns new registered *prometheus.GaugeVec.
|
||||
func NewGaugeVec(opts prometheus.GaugeOpts, labelNames []string) *prometheus.GaugeVec {
|
||||
value := prometheus.NewGaugeVec(opts, labelNames)
|
||||
mustRegister(value, Description{
|
||||
Name: prometheus.BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
|
||||
Type: dto.MetricType_GAUGE.String(),
|
||||
Help: opts.Help,
|
||||
ConstantLabels: opts.ConstLabels,
|
||||
VariableLabels: labelNames,
|
||||
})
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
// NewGaugeFunc returns new registered prometheus.GaugeFunc.
|
||||
func NewGaugeFunc(opts prometheus.GaugeOpts, f func() float64) prometheus.GaugeFunc {
|
||||
value := prometheus.NewGaugeFunc(opts, f)
|
||||
mustRegister(value, Description{
|
||||
Name: prometheus.BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
|
||||
Type: dto.MetricType_GAUGE.String(),
|
||||
Help: opts.Help,
|
||||
ConstantLabels: opts.ConstLabels,
|
||||
})
|
||||
return value
|
||||
}
|
||||
|
||||
// NewCounter returns new registered prometheus.Counter.
|
||||
func NewCounter(opts prometheus.CounterOpts) prometheus.Counter {
|
||||
value := prometheus.NewCounter(opts)
|
||||
mustRegister(value, Description{
|
||||
Name: prometheus.BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
|
||||
Type: dto.MetricType_COUNTER.String(),
|
||||
Help: opts.Help,
|
||||
ConstantLabels: opts.ConstLabels,
|
||||
})
|
||||
return value
|
||||
}
|
||||
|
||||
// NewCounterVec returns new registered *prometheus.CounterVec.
|
||||
func NewCounterVec(opts prometheus.CounterOpts, labels []string) *prometheus.CounterVec {
|
||||
value := prometheus.NewCounterVec(opts, labels)
|
||||
mustRegister(value, Description{
|
||||
Name: prometheus.BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
|
||||
Type: dto.MetricType_COUNTER.String(),
|
||||
Help: opts.Help,
|
||||
ConstantLabels: opts.ConstLabels,
|
||||
VariableLabels: labels,
|
||||
})
|
||||
return value
|
||||
}
|
||||
|
||||
// NewHistogramVec returns new registered *prometheus.HistogramVec.
|
||||
func NewHistogramVec(opts prometheus.HistogramOpts, labelNames []string) *prometheus.HistogramVec {
|
||||
value := prometheus.NewHistogramVec(opts, labelNames)
|
||||
mustRegister(value, Description{
|
||||
Name: prometheus.BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
|
||||
Type: dto.MetricType_HISTOGRAM.String(),
|
||||
Help: opts.Help,
|
||||
ConstantLabels: opts.ConstLabels,
|
||||
VariableLabels: labelNames,
|
||||
})
|
||||
return value
|
||||
}
|
||||
|
||||
// DescribeAll returns descriptions for all registered metrics.
|
||||
func DescribeAll() []Description {
|
||||
registeredDescriptionsMtx.Lock()
|
||||
defer registeredDescriptionsMtx.Unlock()
|
||||
|
||||
ds := make([]Description, len(registeredDescriptions))
|
||||
copy(ds, registeredDescriptions)
|
||||
return ds
|
||||
}
|
||||
|
||||
func mustRegister(c prometheus.Collector, desc Description) {
|
||||
registry.MustRegister(c)
|
||||
registeredDescriptionsMtx.Lock()
|
||||
defer registeredDescriptionsMtx.Unlock()
|
||||
registeredDescriptions = append(registeredDescriptions, desc)
|
||||
}
|
64
metrics/desc_test.go
Normal file
64
metrics/desc_test.go
Normal file
|
@ -0,0 +1,64 @@
|
|||
package metrics
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestDescribeAll(t *testing.T) {
|
||||
const (
|
||||
namespace = "my_ns"
|
||||
subsystem = "mysub"
|
||||
)
|
||||
NewCounter(prometheus.CounterOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "my_counter",
|
||||
})
|
||||
|
||||
labels := []string{"label1", "label2"}
|
||||
NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "my_gauge",
|
||||
}, labels)
|
||||
|
||||
constLabels := prometheus.Labels{
|
||||
"const1": "abc",
|
||||
"const2": "xyz",
|
||||
}
|
||||
NewCounter(prometheus.CounterOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "with_const_labels",
|
||||
ConstLabels: constLabels,
|
||||
})
|
||||
|
||||
descriptions := DescribeAll()
|
||||
|
||||
seen := make(map[string]bool)
|
||||
for i := range descriptions {
|
||||
if !strings.HasPrefix(descriptions[i].Name, namespace) {
|
||||
continue
|
||||
}
|
||||
|
||||
require.False(t, seen[descriptions[i].Name], "metric %s was seen twice", descriptions[i].Name)
|
||||
seen[descriptions[i].Name] = true
|
||||
|
||||
switch descriptions[i].Name {
|
||||
case prometheus.BuildFQName(namespace, subsystem, "my_counter"):
|
||||
require.True(t, len(descriptions[i].VariableLabels) == 0)
|
||||
case prometheus.BuildFQName(namespace, subsystem, "my_gauge"):
|
||||
require.Equal(t, labels, descriptions[i].VariableLabels)
|
||||
case prometheus.BuildFQName(namespace, subsystem, "with_const_labels"):
|
||||
require.Equal(t, len(constLabels), len(descriptions[i].ConstantLabels))
|
||||
require.Equal(t, constLabels, descriptions[i].ConstantLabels)
|
||||
default:
|
||||
require.FailNow(t, "unexpected metric name: %s", descriptions[i].Name)
|
||||
}
|
||||
}
|
||||
require.Equal(t, 3, len(seen), "not all registered metrics were iterated over")
|
||||
}
|
25
metrics/go.mod
Normal file
25
metrics/go.mod
Normal file
|
@ -0,0 +1,25 @@
|
|||
module git.frostfs.info/TrueCloudLab/frostfs-platform/metrics
|
||||
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/prometheus/client_golang v1.15.1
|
||||
github.com/prometheus/client_model v0.3.0
|
||||
github.com/stretchr/testify v1.8.3
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/common v0.42.0 // indirect
|
||||
github.com/prometheus/procfs v0.9.0 // indirect
|
||||
github.com/rogpeppe/go-internal v1.10.0 // indirect
|
||||
golang.org/x/sys v0.6.0 // indirect
|
||||
google.golang.org/protobuf v1.30.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
45
metrics/go.sum
Normal file
45
metrics/go.sum
Normal file
|
@ -0,0 +1,45 @@
|
|||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI=
|
||||
github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk=
|
||||
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
|
||||
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
|
||||
github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
|
||||
github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
|
||||
github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
|
||||
github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
|
||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
27
metrics/registry.go
Normal file
27
metrics/registry.go
Normal file
|
@ -0,0 +1,27 @@
|
|||
package metrics
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/collectors"
|
||||
)
|
||||
|
||||
var (
|
||||
registry = prometheus.NewRegistry()
|
||||
// registeredDescriptionsMtx protects collectors slice.
|
||||
// It should not be acessed concurrently, but we can easily forget this in future, thus this mutex.
|
||||
registeredDescriptionsMtx sync.Mutex
|
||||
registeredDescriptions []Description
|
||||
)
|
||||
|
||||
func init() {
|
||||
registry.MustRegister(collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}))
|
||||
registry.MustRegister(collectors.NewGoCollector())
|
||||
}
|
||||
|
||||
// Register registers custom collectors to registry.
|
||||
// Should be used with metrics from other packages.
|
||||
func Register(customCollectors ...prometheus.Collector) {
|
||||
registry.MustRegister(customCollectors...)
|
||||
}
|
Loading…
Reference in a new issue