[#29] Add type to metrics description

Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
This commit is contained in:
Denis Kirillov 2023-04-10 12:22:11 +03:00
parent 6c6fd0e9a5
commit 385f336a17
4 changed files with 48 additions and 16 deletions

2
go.mod
View file

@ -8,6 +8,7 @@ require (
github.com/fasthttp/router v1.4.1 github.com/fasthttp/router v1.4.1
github.com/nspcc-dev/neo-go v0.101.0 github.com/nspcc-dev/neo-go v0.101.0
github.com/prometheus/client_golang v1.13.0 github.com/prometheus/client_golang v1.13.0
github.com/prometheus/client_model v0.2.0
github.com/spf13/pflag v1.0.5 github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.15.0 github.com/spf13/viper v1.15.0
github.com/stretchr/testify v1.8.1 github.com/stretchr/testify v1.8.1
@ -68,7 +69,6 @@ require (
github.com/pelletier/go-toml/v2 v2.0.6 // indirect github.com/pelletier/go-toml/v2 v2.0.6 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/common v0.37.0 // indirect
github.com/prometheus/procfs v0.8.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect

View file

@ -4,17 +4,20 @@ import (
"encoding/json" "encoding/json"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
dto "github.com/prometheus/client_model/go"
) )
var appMetricsDesc = map[string]map[string]Description{ var appMetricsDesc = map[string]map[string]Description{
poolSubsystem: { poolSubsystem: {
overallErrorsMetric: Description{ overallErrorsMetric: Description{
Type: dto.MetricType_GAUGE,
Namespace: namespace, Namespace: namespace,
Subsystem: poolSubsystem, Subsystem: poolSubsystem,
Name: overallErrorsMetric, Name: overallErrorsMetric,
Help: "Total number of errors in pool", Help: "Total number of errors in pool",
}, },
overallNodeErrorsMetric: Description{ overallNodeErrorsMetric: Description{
Type: dto.MetricType_GAUGE,
Namespace: namespace, Namespace: namespace,
Subsystem: poolSubsystem, Subsystem: poolSubsystem,
Name: overallNodeErrorsMetric, Name: overallNodeErrorsMetric,
@ -22,6 +25,7 @@ var appMetricsDesc = map[string]map[string]Description{
VariableLabels: []string{"node"}, VariableLabels: []string{"node"},
}, },
overallNodeRequestsMetric: Description{ overallNodeRequestsMetric: Description{
Type: dto.MetricType_GAUGE,
Namespace: namespace, Namespace: namespace,
Subsystem: poolSubsystem, Subsystem: poolSubsystem,
Name: overallNodeRequestsMetric, Name: overallNodeRequestsMetric,
@ -29,6 +33,7 @@ var appMetricsDesc = map[string]map[string]Description{
VariableLabels: []string{"node"}, VariableLabels: []string{"node"},
}, },
currentErrorMetric: Description{ currentErrorMetric: Description{
Type: dto.MetricType_GAUGE,
Namespace: namespace, Namespace: namespace,
Subsystem: poolSubsystem, Subsystem: poolSubsystem,
Name: currentErrorMetric, Name: currentErrorMetric,
@ -36,6 +41,7 @@ var appMetricsDesc = map[string]map[string]Description{
VariableLabels: []string{"node"}, VariableLabels: []string{"node"},
}, },
avgRequestDurationMetric: Description{ avgRequestDurationMetric: Description{
Type: dto.MetricType_GAUGE,
Namespace: namespace, Namespace: namespace,
Subsystem: poolSubsystem, Subsystem: poolSubsystem,
Name: avgRequestDurationMetric, Name: avgRequestDurationMetric,
@ -45,12 +51,14 @@ var appMetricsDesc = map[string]map[string]Description{
}, },
stateSubsystem: { stateSubsystem: {
healthMetric: Description{ healthMetric: Description{
Type: dto.MetricType_GAUGE,
Namespace: namespace, Namespace: namespace,
Subsystem: stateSubsystem, Subsystem: stateSubsystem,
Name: healthMetric, Name: healthMetric,
Help: "Current HTTP gateway state", Help: "Current HTTP gateway state",
}, },
versionInfoMetric: Description{ versionInfoMetric: Description{
Type: dto.MetricType_GAUGE,
Namespace: namespace, Namespace: namespace,
Subsystem: stateSubsystem, Subsystem: stateSubsystem,
Name: versionInfoMetric, Name: versionInfoMetric,
@ -61,6 +69,7 @@ var appMetricsDesc = map[string]map[string]Description{
} }
type Description struct { type Description struct {
Type dto.MetricType
Namespace string Namespace string
Subsystem string Subsystem string
Name string Name string
@ -76,11 +85,13 @@ type KeyValue struct {
func (d *Description) MarshalJSON() ([]byte, error) { func (d *Description) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct { return json.Marshal(&struct {
Type string `json:"type"`
FQName string `json:"name"` FQName string `json:"name"`
Help string `json:"help"` Help string `json:"help"`
ConstantLabels []KeyValue `json:"constant_labels"` ConstantLabels []KeyValue `json:"constant_labels"`
VariableLabels []string `json:"variable_labels"` VariableLabels []string `json:"variable_labels"`
}{ }{
Type: d.Type.String(),
FQName: d.BuildFQName(), FQName: d.BuildFQName(),
Help: d.Help, Help: d.Help,
ConstantLabels: d.ConstantLabels, ConstantLabels: d.ConstantLabels,
@ -122,13 +133,19 @@ func newOpts(description Description) prometheus.Opts {
} }
} }
func newGauge(description Description) prometheus.Gauge { func mustNewGauge(description Description) prometheus.Gauge {
if description.Type != dto.MetricType_GAUGE {
panic("invalid metric type")
}
return prometheus.NewGauge( return prometheus.NewGauge(
prometheus.GaugeOpts(newOpts(description)), prometheus.GaugeOpts(newOpts(description)),
) )
} }
func newGaugeVec(description Description) *prometheus.GaugeVec { func mustNewGaugeVec(description Description) *prometheus.GaugeVec {
if description.Type != dto.MetricType_GAUGE {
panic("invalid metric type")
}
return prometheus.NewGaugeVec( return prometheus.NewGaugeVec(
prometheus.GaugeOpts(newOpts(description)), prometheus.GaugeOpts(newOpts(description)),
description.VariableLabels, description.VariableLabels,

View file

@ -8,17 +8,28 @@ import (
"os" "os"
"testing" "testing"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
type mock struct{}
func (m mock) Statistic() pool.Statistic {
return pool.Statistic{}
}
var metricsPath = flag.String("out", "", "File to export http gateway metrics to.") var metricsPath = flag.String("out", "", "File to export http gateway metrics to.")
func TestDescribeAll(t *testing.T) { func TestDescribeAll(t *testing.T) {
// to check correct metrics type mapping
_ = NewGateMetrics(mock{})
flag.Parse() flag.Parse()
require.NotEmpty(t, metricsPath, "flag 'out' must be provided to dump metrics description") require.NotEmpty(t, metricsPath, "flag 'out' must be provided to dump metrics description")
data, err := json.Marshal(DescribeAll()) desc := DescribeAll()
data, err := json.Marshal(desc)
require.NoError(t, err) require.NoError(t, err)
err = os.WriteFile(*metricsPath, data, 0644) err = os.WriteFile(*metricsPath, data, 0644)

View file

@ -56,6 +56,10 @@ const (
HealthStatusShuttingDown HealthStatus = 3 HealthStatusShuttingDown HealthStatus = 3
) )
type StatisticScraper interface {
Statistic() pool.Statistic
}
type GateMetrics struct { type GateMetrics struct {
stateMetrics stateMetrics
poolMetricsCollector poolMetricsCollector
@ -67,7 +71,7 @@ type stateMetrics struct {
} }
type poolMetricsCollector struct { type poolMetricsCollector struct {
pool *pool.Pool scraper StatisticScraper
overallErrors prometheus.Gauge overallErrors prometheus.Gauge
overallNodeErrors *prometheus.GaugeVec overallNodeErrors *prometheus.GaugeVec
overallNodeRequests *prometheus.GaugeVec overallNodeRequests *prometheus.GaugeVec
@ -76,7 +80,7 @@ type poolMetricsCollector struct {
} }
// NewGateMetrics creates new metrics for http gate. // NewGateMetrics creates new metrics for http gate.
func NewGateMetrics(p *pool.Pool) *GateMetrics { func NewGateMetrics(p StatisticScraper) *GateMetrics {
stateMetric := newStateMetrics() stateMetric := newStateMetrics()
stateMetric.register() stateMetric.register()
@ -96,8 +100,8 @@ func (g *GateMetrics) Unregister() {
func newStateMetrics() *stateMetrics { func newStateMetrics() *stateMetrics {
return &stateMetrics{ return &stateMetrics{
healthCheck: newGauge(appMetricsDesc[stateSubsystem][healthMetric]), healthCheck: mustNewGauge(appMetricsDesc[stateSubsystem][healthMetric]),
versionInfo: newGaugeVec(appMetricsDesc[stateSubsystem][versionInfoMetric]), versionInfo: mustNewGaugeVec(appMetricsDesc[stateSubsystem][versionInfoMetric]),
} }
} }
@ -119,14 +123,14 @@ func (m stateMetrics) SetVersion(ver string) {
m.versionInfo.WithLabelValues(ver).Set(1) m.versionInfo.WithLabelValues(ver).Set(1)
} }
func newPoolMetricsCollector(p *pool.Pool) *poolMetricsCollector { func newPoolMetricsCollector(p StatisticScraper) *poolMetricsCollector {
return &poolMetricsCollector{ return &poolMetricsCollector{
pool: p, scraper: p,
overallErrors: newGauge(appMetricsDesc[poolSubsystem][overallErrorsMetric]), overallErrors: mustNewGauge(appMetricsDesc[poolSubsystem][overallErrorsMetric]),
overallNodeErrors: newGaugeVec(appMetricsDesc[poolSubsystem][overallNodeErrorsMetric]), overallNodeErrors: mustNewGaugeVec(appMetricsDesc[poolSubsystem][overallNodeErrorsMetric]),
overallNodeRequests: newGaugeVec(appMetricsDesc[poolSubsystem][overallNodeRequestsMetric]), overallNodeRequests: mustNewGaugeVec(appMetricsDesc[poolSubsystem][overallNodeRequestsMetric]),
currentErrors: newGaugeVec(appMetricsDesc[poolSubsystem][currentErrorMetric]), currentErrors: mustNewGaugeVec(appMetricsDesc[poolSubsystem][currentErrorMetric]),
requestDuration: newGaugeVec(appMetricsDesc[poolSubsystem][avgRequestDurationMetric]), requestDuration: mustNewGaugeVec(appMetricsDesc[poolSubsystem][avgRequestDurationMetric]),
} }
} }
@ -152,7 +156,7 @@ func (m *poolMetricsCollector) register() {
} }
func (m *poolMetricsCollector) updateStatistic() { func (m *poolMetricsCollector) updateStatistic() {
stat := m.pool.Statistic() stat := m.scraper.Statistic()
m.overallNodeErrors.Reset() m.overallNodeErrors.Reset()
m.overallNodeRequests.Reset() m.overallNodeRequests.Reset()