forked from TrueCloudLab/frostfs-http-gw
[#29] Add type to metrics description
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
This commit is contained in:
parent
6c6fd0e9a5
commit
385f336a17
4 changed files with 48 additions and 16 deletions
2
go.mod
2
go.mod
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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()
|
||||||
|
|
Loading…
Reference in a new issue