diff --git a/cmd/frostfs-ir/metrics.go b/cmd/frostfs-ir/metrics.go index 39b432c7..dd982b78 100644 --- a/cmd/frostfs-ir/metrics.go +++ b/cmd/frostfs-ir/metrics.go @@ -1,7 +1,7 @@ package main import ( - "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/metrics" + "git.frostfs.info/TrueCloudLab/frostfs-observability/metrics" ) func newMetricsComponent() *httpComponent { diff --git a/cmd/frostfs-node/metrics.go b/cmd/frostfs-node/metrics.go index cf621086..19b4af51 100644 --- a/cmd/frostfs-node/metrics.go +++ b/cmd/frostfs-node/metrics.go @@ -2,7 +2,7 @@ package main import ( metricsconfig "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/config/metrics" - "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/metrics" + "git.frostfs.info/TrueCloudLab/frostfs-observability/metrics" ) func metricsComponent(c *cfg) (*httpComponent, bool) { diff --git a/pkg/metrics/desc.go b/pkg/metrics/desc.go deleted file mode 100644 index 612435b2..00000000 --- a/pkg/metrics/desc.go +++ /dev/null @@ -1,109 +0,0 @@ -package metrics - -import ( - "github.com/prometheus/client_golang/prometheus" - dto "github.com/prometheus/client_model/go" -) - -type metric[T prometheus.Collector] struct { - value T - desc Description -} - -// 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"` -} - -func newGauge(opts prometheus.GaugeOpts) metric[prometheus.Gauge] { - return metric[prometheus.Gauge]{ - value: prometheus.NewGauge(opts), - desc: Description{ - Name: prometheus.BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), - Type: dto.MetricType_GAUGE.String(), - Help: opts.Help, - ConstantLabels: opts.ConstLabels, - }, - } -} - -func newGaugeVec(opts prometheus.GaugeOpts, labelNames []string) metric[*prometheus.GaugeVec] { - return metric[*prometheus.GaugeVec]{ - value: prometheus.NewGaugeVec(opts, labelNames), - desc: Description{ - Name: prometheus.BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), - Type: dto.MetricType_GAUGE.String(), - Help: opts.Help, - ConstantLabels: opts.ConstLabels, - VariableLabels: labelNames, - }, - } -} - -func newGaugeFunc(opts prometheus.GaugeOpts, f func() float64) metric[prometheus.GaugeFunc] { - return metric[prometheus.GaugeFunc]{ - value: prometheus.NewGaugeFunc(opts, f), - desc: Description{ - Name: prometheus.BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), - Type: dto.MetricType_GAUGE.String(), - Help: opts.Help, - ConstantLabels: opts.ConstLabels, - }, - } -} - -func newCounter(opts prometheus.CounterOpts) metric[prometheus.Counter] { - return metric[prometheus.Counter]{ - value: prometheus.NewCounter(opts), - desc: Description{ - Name: prometheus.BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), - Type: dto.MetricType_COUNTER.String(), - Help: opts.Help, - ConstantLabels: opts.ConstLabels, - }, - } -} - -func newCounterVec(opts prometheus.CounterOpts, labels []string) metric[*prometheus.CounterVec] { - return metric[*prometheus.CounterVec]{ - value: prometheus.NewCounterVec(opts, labels), - desc: Description{ - Name: prometheus.BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), - Type: dto.MetricType_COUNTER.String(), - Help: opts.Help, - ConstantLabels: opts.ConstLabels, - VariableLabels: labels, - }, - } -} - -func newHistogramVec(opts prometheus.HistogramOpts, labelNames []string) metric[*prometheus.HistogramVec] { - return metric[*prometheus.HistogramVec]{ - value: prometheus.NewHistogramVec(opts, labelNames), - desc: Description{ - Name: prometheus.BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), - Type: dto.MetricType_HISTOGRAM.String(), - Help: opts.Help, - ConstantLabels: opts.ConstLabels, - VariableLabels: labelNames, - }, - } -} - -// DescribeAll returns descriptions for all registered metrics. -func DescribeAll() ([]Description, error) { - registeredDescriptionsMtx.Lock() - defer registeredDescriptionsMtx.Unlock() - - ds := make([]Description, len(registeredDescriptions)) - copy(ds, registeredDescriptions) - return ds, nil -} diff --git a/pkg/metrics/desc_test.go b/pkg/metrics/desc_test.go deleted file mode 100644 index 28b5e213..00000000 --- a/pkg/metrics/desc_test.go +++ /dev/null @@ -1,65 +0,0 @@ -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" - ) - mustRegister(newCounter(prometheus.CounterOpts{ - Namespace: namespace, - Subsystem: subsystem, - Name: "my_counter", - })) - - labels := []string{"label1", "label2"} - mustRegister(newGaugeVec(prometheus.GaugeOpts{ - Namespace: namespace, - Subsystem: subsystem, - Name: "my_gauge", - }, labels)) - - constLabels := prometheus.Labels{ - "const1": "abc", - "const2": "xyz", - } - mustRegister(newCounter(prometheus.CounterOpts{ - Namespace: namespace, - Subsystem: subsystem, - Name: "with_const_labels", - ConstLabels: constLabels, - })) - - descriptions, err := DescribeAll() - require.NoError(t, err) - - 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") -} diff --git a/pkg/metrics/engine.go b/pkg/metrics/engine.go index 28fc1e02..4e78f4ac 100644 --- a/pkg/metrics/engine.go +++ b/pkg/metrics/engine.go @@ -5,24 +5,25 @@ import ( "strings" "time" + "git.frostfs.info/TrueCloudLab/frostfs-observability/metrics" "github.com/prometheus/client_golang/prometheus" ) type ( engineMetrics struct { - listContainersDuration metric[prometheus.Counter] - estimateContainerSizeDuration metric[prometheus.Counter] - deleteDuration metric[prometheus.Counter] - existsDuration metric[prometheus.Counter] - getDuration metric[prometheus.Counter] - headDuration metric[prometheus.Counter] - inhumeDuration metric[prometheus.Counter] - putDuration metric[prometheus.Counter] - rangeDuration metric[prometheus.Counter] - searchDuration metric[prometheus.Counter] - listObjectsDuration metric[prometheus.Counter] - containerSize metric[*prometheus.GaugeVec] - payloadSize metric[*prometheus.GaugeVec] + listContainersDuration prometheus.Counter + estimateContainerSizeDuration prometheus.Counter + deleteDuration prometheus.Counter + existsDuration prometheus.Counter + getDuration prometheus.Counter + headDuration prometheus.Counter + inhumeDuration prometheus.Counter + putDuration prometheus.Counter + rangeDuration prometheus.Counter + searchDuration prometheus.Counter + listObjectsDuration prometheus.Counter + containerSize *prometheus.GaugeVec + payloadSize *prometheus.GaugeVec } ) @@ -46,8 +47,8 @@ func newEngineMetrics() engineMetrics { } } -func newEngineCounter(name, help string) metric[prometheus.Counter] { - return newCounter(prometheus.CounterOpts{ +func newEngineCounter(name, help string) prometheus.Counter { + return metrics.NewCounter(prometheus.CounterOpts{ Namespace: namespace, Subsystem: engineSubsystem, Name: name, @@ -55,15 +56,15 @@ func newEngineCounter(name, help string) metric[prometheus.Counter] { }) } -func newEngineMethodDurationCounter(method string) metric[prometheus.Counter] { +func newEngineMethodDurationCounter(method string) prometheus.Counter { return newEngineCounter( fmt.Sprintf("%s_duration", method), fmt.Sprintf("Accumulated duration of engine %s operations", strings.ReplaceAll(method, "_", " ")), ) } -func newEngineGaugeVector(name, help string, labels []string) metric[*prometheus.GaugeVec] { - return newGaugeVec(prometheus.GaugeOpts{ +func newEngineGaugeVector(name, help string, labels []string) *prometheus.GaugeVec { + return metrics.NewGaugeVec(prometheus.GaugeOpts{ Namespace: namespace, Subsystem: engineSubsystem, Name: name, @@ -71,70 +72,54 @@ func newEngineGaugeVector(name, help string, labels []string) metric[*prometheus }, labels) } -func (m engineMetrics) register() { - mustRegister(m.listContainersDuration) - mustRegister(m.estimateContainerSizeDuration) - mustRegister(m.deleteDuration) - mustRegister(m.existsDuration) - mustRegister(m.getDuration) - mustRegister(m.headDuration) - mustRegister(m.inhumeDuration) - mustRegister(m.putDuration) - mustRegister(m.rangeDuration) - mustRegister(m.searchDuration) - mustRegister(m.listObjectsDuration) - mustRegister(m.containerSize) - mustRegister(m.payloadSize) -} - func (m engineMetrics) AddListContainersDuration(d time.Duration) { - m.listObjectsDuration.value.Add(float64(d)) + m.listObjectsDuration.Add(float64(d)) } func (m engineMetrics) AddEstimateContainerSizeDuration(d time.Duration) { - m.estimateContainerSizeDuration.value.Add(float64(d)) + m.estimateContainerSizeDuration.Add(float64(d)) } func (m engineMetrics) AddDeleteDuration(d time.Duration) { - m.deleteDuration.value.Add(float64(d)) + m.deleteDuration.Add(float64(d)) } func (m engineMetrics) AddExistsDuration(d time.Duration) { - m.existsDuration.value.Add(float64(d)) + m.existsDuration.Add(float64(d)) } func (m engineMetrics) AddGetDuration(d time.Duration) { - m.getDuration.value.Add(float64(d)) + m.getDuration.Add(float64(d)) } func (m engineMetrics) AddHeadDuration(d time.Duration) { - m.headDuration.value.Add(float64(d)) + m.headDuration.Add(float64(d)) } func (m engineMetrics) AddInhumeDuration(d time.Duration) { - m.inhumeDuration.value.Add(float64(d)) + m.inhumeDuration.Add(float64(d)) } func (m engineMetrics) AddPutDuration(d time.Duration) { - m.putDuration.value.Add(float64(d)) + m.putDuration.Add(float64(d)) } func (m engineMetrics) AddRangeDuration(d time.Duration) { - m.rangeDuration.value.Add(float64(d)) + m.rangeDuration.Add(float64(d)) } func (m engineMetrics) AddSearchDuration(d time.Duration) { - m.searchDuration.value.Add(float64(d)) + m.searchDuration.Add(float64(d)) } func (m engineMetrics) AddListObjectsDuration(d time.Duration) { - m.listObjectsDuration.value.Add(float64(d)) + m.listObjectsDuration.Add(float64(d)) } func (m engineMetrics) AddToContainerSize(cnrID string, size int64) { - m.containerSize.value.With(prometheus.Labels{containerIDLabelKey: cnrID}).Add(float64(size)) + m.containerSize.With(prometheus.Labels{containerIDLabelKey: cnrID}).Add(float64(size)) } func (m engineMetrics) AddToPayloadCounter(shardID string, size int64) { - m.payloadSize.value.With(prometheus.Labels{shardIDLabelKey: shardID}).Add(float64(size)) + m.payloadSize.With(prometheus.Labels{shardIDLabelKey: shardID}).Add(float64(size)) } diff --git a/pkg/metrics/gc.go b/pkg/metrics/gc.go index c4d5ecb5..2457c0c6 100644 --- a/pkg/metrics/gc.go +++ b/pkg/metrics/gc.go @@ -4,6 +4,7 @@ import ( "fmt" "time" + "git.frostfs.info/TrueCloudLab/frostfs-observability/metrics" "github.com/prometheus/client_golang/prometheus" ) @@ -25,40 +26,33 @@ type GCMetrics interface { } type gcMetrics struct { - runDuration metric[*prometheus.CounterVec] - deletedCounter metric[*prometheus.CounterVec] - expCollectDuration metric[*prometheus.CounterVec] - inhumedCounter metric[*prometheus.CounterVec] -} - -func (m *gcMetrics) register() { - mustRegister(m.runDuration) - mustRegister(m.deletedCounter) - mustRegister(m.expCollectDuration) - mustRegister(m.inhumedCounter) + runDuration *prometheus.CounterVec + deletedCounter *prometheus.CounterVec + expCollectDuration *prometheus.CounterVec + inhumedCounter *prometheus.CounterVec } func newGCMetrics() *gcMetrics { return &gcMetrics{ - runDuration: newCounterVec(prometheus.CounterOpts{ + runDuration: metrics.NewCounterVec(prometheus.CounterOpts{ Namespace: namespace, Subsystem: gcSubsystem, Name: "delete_duration_seconds", Help: "The total time of GC runs to delete objects from disk", }, []string{gcShardID, gcSuccess}), - deletedCounter: newCounterVec(prometheus.CounterOpts{ + deletedCounter: metrics.NewCounterVec(prometheus.CounterOpts{ Namespace: namespace, Subsystem: gcSubsystem, Name: "deleted_objects_count", Help: "Total count of objects GC deleted or failed to delete from disk", }, []string{gcShardID, gcStatus}), - expCollectDuration: newCounterVec(prometheus.CounterOpts{ + expCollectDuration: metrics.NewCounterVec(prometheus.CounterOpts{ Namespace: namespace, Subsystem: gcSubsystem, Name: "marking_duration_seconds", Help: "The total time of GC runs to mark expired objects as removed", }, []string{gcShardID, gcSuccess, gcObjectType}), - inhumedCounter: newCounterVec(prometheus.CounterOpts{ + inhumedCounter: metrics.NewCounterVec(prometheus.CounterOpts{ Namespace: namespace, Subsystem: gcSubsystem, Name: "marked_for_removal_objects_count", @@ -68,19 +62,19 @@ func newGCMetrics() *gcMetrics { } func (m *gcMetrics) AddRunDuration(shardID string, d time.Duration, success bool) { - m.runDuration.value.With(prometheus.Labels{ + m.runDuration.With(prometheus.Labels{ gcShardID: shardID, gcSuccess: fmt.Sprintf("%v", success), }).Add(d.Seconds()) } func (m *gcMetrics) AddDeletedCount(shardID string, deleted, failed uint64) { - m.deletedCounter.value.With( + m.deletedCounter.With( prometheus.Labels{ gcShardID: shardID, gcStatus: gcDeleted, }).Add(float64(deleted)) - m.deletedCounter.value.With( + m.deletedCounter.With( prometheus.Labels{ gcShardID: shardID, gcStatus: gcFailed, @@ -88,7 +82,7 @@ func (m *gcMetrics) AddDeletedCount(shardID string, deleted, failed uint64) { } func (m *gcMetrics) AddExpiredObjectCollectionDuration(shardID string, d time.Duration, success bool, objectType string) { - m.expCollectDuration.value.With(prometheus.Labels{ + m.expCollectDuration.With(prometheus.Labels{ gcShardID: shardID, gcSuccess: fmt.Sprintf("%v", success), gcObjectType: objectType, @@ -96,7 +90,7 @@ func (m *gcMetrics) AddExpiredObjectCollectionDuration(shardID string, d time.Du } func (m *gcMetrics) AddInhumedObjectCount(shardID string, count uint64, objectType string) { - m.inhumedCounter.value.With( + m.inhumedCounter.With( prometheus.Labels{ gcShardID: shardID, gcObjectType: objectType, diff --git a/pkg/metrics/innerring.go b/pkg/metrics/innerring.go index bff9184e..9d8b76bf 100644 --- a/pkg/metrics/innerring.go +++ b/pkg/metrics/innerring.go @@ -4,6 +4,7 @@ import ( "strconv" "time" + "git.frostfs.info/TrueCloudLab/frostfs-observability/metrics" "github.com/prometheus/client_golang/prometheus" ) @@ -15,27 +16,27 @@ const ( // InnerRingServiceMetrics contains metrics collected by inner ring. type InnerRingServiceMetrics struct { - epoch metric[prometheus.Gauge] - health metric[prometheus.Gauge] - eventDuration metric[*prometheus.HistogramVec] + epoch prometheus.Gauge + health prometheus.Gauge + eventDuration *prometheus.HistogramVec } // NewInnerRingMetrics returns new instance of metrics collectors for inner ring. func NewInnerRingMetrics() *InnerRingServiceMetrics { var ( - epoch = newGauge(prometheus.GaugeOpts{ + epoch = metrics.NewGauge(prometheus.GaugeOpts{ Namespace: namespace, Subsystem: innerRingSubsystem, Name: "epoch", Help: "Current epoch as seen by inner-ring node.", }) - health = newGauge(prometheus.GaugeOpts{ + health = metrics.NewGauge(prometheus.GaugeOpts{ Namespace: namespace, Subsystem: innerRingSubsystem, Name: "health", Help: "Current inner-ring node state.", }) - eventDuration = newHistogramVec(prometheus.HistogramOpts{ + eventDuration = metrics.NewHistogramVec(prometheus.HistogramOpts{ Namespace: namespace, Subsystem: innerRingSubsystem, Name: "event_duration_seconds", @@ -43,10 +44,6 @@ func NewInnerRingMetrics() *InnerRingServiceMetrics { }, []string{innerRingLabelType, innerRingLabelSuccess}) ) - mustRegister(epoch) - mustRegister(health) - mustRegister(eventDuration) - return &InnerRingServiceMetrics{ epoch: epoch, health: health, @@ -56,16 +53,16 @@ func NewInnerRingMetrics() *InnerRingServiceMetrics { // SetEpoch updates epoch metrics. func (m InnerRingServiceMetrics) SetEpoch(epoch uint64) { - m.epoch.value.Set(float64(epoch)) + m.epoch.Set(float64(epoch)) } // SetHealth updates health metrics. func (m InnerRingServiceMetrics) SetHealth(s int32) { - m.health.value.Set(float64(s)) + m.health.Set(float64(s)) } func (m InnerRingServiceMetrics) AddEvent(d time.Duration, typ string, success bool) { - m.eventDuration.value.With(prometheus.Labels{ + m.eventDuration.With(prometheus.Labels{ innerRingLabelType: typ, innerRingLabelSuccess: strconv.FormatBool(success), }).Observe(d.Seconds()) diff --git a/pkg/metrics/node.go b/pkg/metrics/node.go index 526e460c..8819ba15 100644 --- a/pkg/metrics/node.go +++ b/pkg/metrics/node.go @@ -2,6 +2,7 @@ package metrics import ( "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/tree" + "git.frostfs.info/TrueCloudLab/frostfs-observability/metrics" "github.com/prometheus/client_golang/prometheus" ) @@ -15,39 +16,31 @@ type NodeMetrics struct { writeCacheMetrics *writeCacheMetrics treeService *treeServiceMetrics - epoch metric[prometheus.Gauge] + epoch prometheus.Gauge gc *gcMetrics } func NewNodeMetrics() *NodeMetrics { objectService := newObjectServiceMetrics() - objectService.register() engine := newEngineMetrics() - engine.register() state := newStateMetrics() - state.register() replicator := newReplicatorMetrics() - replicator.register() treeService := newTreeServiceMetrics() - treeService.register() - epoch := newGauge(prometheus.GaugeOpts{ + epoch := metrics.NewGauge(prometheus.GaugeOpts{ Namespace: namespace, Subsystem: innerRingSubsystem, Name: "epoch", Help: "Current epoch as seen by inner-ring node.", }) - mustRegister(epoch) writeCacheMetrics := newWriteCacheMetrics() - writeCacheMetrics.register() gc := newGCMetrics() - gc.register() return &NodeMetrics{ objectServiceMetrics: objectService, @@ -63,7 +56,7 @@ func NewNodeMetrics() *NodeMetrics { // SetEpoch updates epoch metric. func (m *NodeMetrics) SetEpoch(epoch uint64) { - m.epoch.value.Set(float64(epoch)) + m.epoch.Set(float64(epoch)) } // WriteCache returns WriteCache metrics. diff --git a/pkg/metrics/object.go b/pkg/metrics/object.go index 5ec57574..87916414 100644 --- a/pkg/metrics/object.go +++ b/pkg/metrics/object.go @@ -5,6 +5,7 @@ import ( "strings" "time" + "git.frostfs.info/TrueCloudLab/frostfs-observability/metrics" "github.com/prometheus/client_golang/prometheus" ) @@ -12,8 +13,8 @@ const objectSubsystem = "object" type ( methodCount struct { - success metric[prometheus.Counter] - total metric[prometheus.Counter] + success prometheus.Counter + total prometheus.Counter } objectServiceMetrics struct { @@ -25,19 +26,19 @@ type ( rangeCounter methodCount rangeHashCounter methodCount - getDuration metric[prometheus.Counter] - putDuration metric[prometheus.Counter] - headDuration metric[prometheus.Counter] - searchDuration metric[prometheus.Counter] - deleteDuration metric[prometheus.Counter] - rangeDuration metric[prometheus.Counter] - rangeHashDuration metric[prometheus.Counter] + getDuration prometheus.Counter + putDuration prometheus.Counter + headDuration prometheus.Counter + searchDuration prometheus.Counter + deleteDuration prometheus.Counter + rangeDuration prometheus.Counter + rangeHashDuration prometheus.Counter - putPayload metric[prometheus.Counter] - getPayload metric[prometheus.Counter] + putPayload prometheus.Counter + getPayload prometheus.Counter - shardMetrics metric[*prometheus.GaugeVec] - shardsReadonly metric[*prometheus.GaugeVec] + shardMetrics *prometheus.GaugeVec + shardsReadonly *prometheus.GaugeVec } ) @@ -49,13 +50,13 @@ const ( func newObjectMethodCallCounter(name string) methodCount { return methodCount{ - success: newCounter(prometheus.CounterOpts{ + success: metrics.NewCounter(prometheus.CounterOpts{ Namespace: namespace, Subsystem: objectSubsystem, Name: fmt.Sprintf("%s_req_count_success", name), Help: fmt.Sprintf("The number of successful %s requests processed", name), }), - total: newCounter(prometheus.CounterOpts{ + total: metrics.NewCounter(prometheus.CounterOpts{ Namespace: namespace, Subsystem: objectSubsystem, Name: fmt.Sprintf("%s_req_count", name), @@ -64,15 +65,10 @@ func newObjectMethodCallCounter(name string) methodCount { } } -func (m methodCount) mustRegister() { - mustRegister(m.success) - mustRegister(m.total) -} - func (m methodCount) Inc(success bool) { - m.total.value.Inc() + m.total.Inc() if success { - m.success.value.Inc() + m.success.Inc() } } @@ -99,8 +95,8 @@ func newObjectServiceMetrics() objectServiceMetrics { } } -func newObjectMethodPayloadCounter(method string) metric[prometheus.Counter] { - return newCounter(prometheus.CounterOpts{ +func newObjectMethodPayloadCounter(method string) prometheus.Counter { + return metrics.NewCounter(prometheus.CounterOpts{ Namespace: namespace, Subsystem: objectSubsystem, Name: fmt.Sprintf("%s_payload", method), @@ -108,8 +104,8 @@ func newObjectMethodPayloadCounter(method string) metric[prometheus.Counter] { }) } -func newObjectMethodDurationCounter(method string) metric[prometheus.Counter] { - return newCounter(prometheus.CounterOpts{ +func newObjectMethodDurationCounter(method string) prometheus.Counter { + return metrics.NewCounter(prometheus.CounterOpts{ Namespace: namespace, Subsystem: objectSubsystem, Name: fmt.Sprintf("%s_req_duration", method), @@ -117,8 +113,8 @@ func newObjectMethodDurationCounter(method string) metric[prometheus.Counter] { }) } -func newObjectGaugeVector(name, help string, labels []string) metric[*prometheus.GaugeVec] { - return newGaugeVec(prometheus.GaugeOpts{ +func newObjectGaugeVector(name, help string, labels []string) *prometheus.GaugeVec { + return metrics.NewGaugeVec(prometheus.GaugeOpts{ Namespace: namespace, Subsystem: objectSubsystem, Name: name, @@ -126,30 +122,6 @@ func newObjectGaugeVector(name, help string, labels []string) metric[*prometheus }, labels) } -func (m objectServiceMetrics) register() { - m.getCounter.mustRegister() - m.putCounter.mustRegister() - m.headCounter.mustRegister() - m.searchCounter.mustRegister() - m.deleteCounter.mustRegister() - m.rangeCounter.mustRegister() - m.rangeHashCounter.mustRegister() - - mustRegister(m.getDuration) - mustRegister(m.putDuration) - mustRegister(m.headDuration) - mustRegister(m.searchDuration) - mustRegister(m.deleteDuration) - mustRegister(m.rangeDuration) - mustRegister(m.rangeHashDuration) - - mustRegister(m.putPayload) - mustRegister(m.getPayload) - - mustRegister(m.shardMetrics) - mustRegister(m.shardsReadonly) -} - func (m objectServiceMetrics) IncGetReqCounter(success bool) { m.getCounter.Inc(success) } @@ -179,43 +151,43 @@ func (m objectServiceMetrics) IncRangeHashReqCounter(success bool) { } func (m objectServiceMetrics) AddGetReqDuration(d time.Duration) { - m.getDuration.value.Add(float64(d)) + m.getDuration.Add(float64(d)) } func (m objectServiceMetrics) AddPutReqDuration(d time.Duration) { - m.putDuration.value.Add(float64(d)) + m.putDuration.Add(float64(d)) } func (m objectServiceMetrics) AddHeadReqDuration(d time.Duration) { - m.headDuration.value.Add(float64(d)) + m.headDuration.Add(float64(d)) } func (m objectServiceMetrics) AddSearchReqDuration(d time.Duration) { - m.searchDuration.value.Add(float64(d)) + m.searchDuration.Add(float64(d)) } func (m objectServiceMetrics) AddDeleteReqDuration(d time.Duration) { - m.deleteDuration.value.Add(float64(d)) + m.deleteDuration.Add(float64(d)) } func (m objectServiceMetrics) AddRangeReqDuration(d time.Duration) { - m.rangeDuration.value.Add(float64(d)) + m.rangeDuration.Add(float64(d)) } func (m objectServiceMetrics) AddRangeHashReqDuration(d time.Duration) { - m.rangeHashDuration.value.Add(float64(d)) + m.rangeHashDuration.Add(float64(d)) } func (m objectServiceMetrics) AddPutPayload(ln int) { - m.putPayload.value.Add(float64(ln)) + m.putPayload.Add(float64(ln)) } func (m objectServiceMetrics) AddGetPayload(ln int) { - m.getPayload.value.Add(float64(ln)) + m.getPayload.Add(float64(ln)) } func (m objectServiceMetrics) AddToObjectCounter(shardID, objectType string, delta int) { - m.shardMetrics.value.With( + m.shardMetrics.With( prometheus.Labels{ shardIDLabelKey: shardID, counterTypeLabelKey: objectType, @@ -224,7 +196,7 @@ func (m objectServiceMetrics) AddToObjectCounter(shardID, objectType string, del } func (m objectServiceMetrics) SetObjectCounter(shardID, objectType string, v uint64) { - m.shardMetrics.value.With( + m.shardMetrics.With( prometheus.Labels{ shardIDLabelKey: shardID, counterTypeLabelKey: objectType, @@ -237,7 +209,7 @@ func (m objectServiceMetrics) SetReadonly(shardID string, readonly bool) { if readonly { flag = 1 } - m.shardsReadonly.value.With( + m.shardsReadonly.With( prometheus.Labels{ shardIDLabelKey: shardID, }, diff --git a/pkg/metrics/registry.go b/pkg/metrics/registry.go deleted file mode 100644 index eef613d0..00000000 --- a/pkg/metrics/registry.go +++ /dev/null @@ -1,42 +0,0 @@ -package metrics - -import ( - "net/http" - "sync" - - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/collectors" - "github.com/prometheus/client_golang/prometheus/promhttp" -) - -// Handler returns an http.Handler for the local registry. -func Handler() http.Handler { - promhttp.Handler() - return promhttp.InstrumentMetricHandler( - registry, - promhttp.HandlerFor(registry, promhttp.HandlerOpts{})) -} - -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()) -} - -func mustRegister[T prometheus.Collector](cs ...metric[T]) { - for i := range cs { - registry.MustRegister(cs[i].value) - } - registeredDescriptionsMtx.Lock() - for i := range cs { - registeredDescriptions = append(registeredDescriptions, cs[i].desc) - } - registeredDescriptionsMtx.Unlock() -} diff --git a/pkg/metrics/replicator.go b/pkg/metrics/replicator.go index 55f736c6..0deafe91 100644 --- a/pkg/metrics/replicator.go +++ b/pkg/metrics/replicator.go @@ -1,29 +1,32 @@ package metrics -import "github.com/prometheus/client_golang/prometheus" +import ( + "git.frostfs.info/TrueCloudLab/frostfs-observability/metrics" + "github.com/prometheus/client_golang/prometheus" +) const replicatorSubsystem = "replicator" type replicatorMetrics struct { - inFlightRequests metric[prometheus.Gauge] - processedObjects metric[prometheus.Counter] - totalReplicatedPayloadSize metric[prometheus.Counter] + inFlightRequests prometheus.Gauge + processedObjects prometheus.Counter + totalReplicatedPayloadSize prometheus.Counter } func (m replicatorMetrics) IncInFlightRequest() { - m.inFlightRequests.value.Inc() + m.inFlightRequests.Inc() } func (m replicatorMetrics) DecInFlightRequest() { - m.inFlightRequests.value.Dec() + m.inFlightRequests.Dec() } func (m replicatorMetrics) IncProcessedObjects() { - m.processedObjects.value.Inc() + m.processedObjects.Inc() } func (m replicatorMetrics) AddPayloadSize(size int64) { - m.totalReplicatedPayloadSize.value.Add(float64(size)) + m.totalReplicatedPayloadSize.Add(float64(size)) } func newReplicatorMetrics() replicatorMetrics { @@ -34,14 +37,8 @@ func newReplicatorMetrics() replicatorMetrics { } } -func (m replicatorMetrics) register() { - mustRegister(m.inFlightRequests) - mustRegister(m.processedObjects) - mustRegister(m.totalReplicatedPayloadSize) -} - -func newReplicatorCounter(name, help string) metric[prometheus.Counter] { - return newCounter(prometheus.CounterOpts{ +func newReplicatorCounter(name, help string) prometheus.Counter { + return metrics.NewCounter(prometheus.CounterOpts{ Namespace: namespace, Subsystem: replicatorSubsystem, Name: name, @@ -49,8 +46,8 @@ func newReplicatorCounter(name, help string) metric[prometheus.Counter] { }) } -func newReplicatorGauge(name, help string) metric[prometheus.Gauge] { - return newGauge(prometheus.GaugeOpts{ +func newReplicatorGauge(name, help string) prometheus.Gauge { + return metrics.NewGauge(prometheus.GaugeOpts{ Namespace: namespace, Subsystem: replicatorSubsystem, Name: name, diff --git a/pkg/metrics/state.go b/pkg/metrics/state.go index dce0402c..89384991 100644 --- a/pkg/metrics/state.go +++ b/pkg/metrics/state.go @@ -1,16 +1,19 @@ package metrics -import "github.com/prometheus/client_golang/prometheus" +import ( + "git.frostfs.info/TrueCloudLab/frostfs-observability/metrics" + "github.com/prometheus/client_golang/prometheus" +) const stateSubsystem = "state" type stateMetrics struct { - healthCheck metric[prometheus.Gauge] + healthCheck prometheus.Gauge } func newStateMetrics() stateMetrics { return stateMetrics{ - healthCheck: newGauge(prometheus.GaugeOpts{ + healthCheck: metrics.NewGauge(prometheus.GaugeOpts{ Namespace: namespace, Subsystem: stateSubsystem, Name: "health", @@ -19,10 +22,6 @@ func newStateMetrics() stateMetrics { } } -func (m stateMetrics) register() { - mustRegister(m.healthCheck) -} - func (m stateMetrics) SetHealth(s int32) { - m.healthCheck.value.Set(float64(s)) + m.healthCheck.Set(float64(s)) } diff --git a/pkg/metrics/treeservice.go b/pkg/metrics/treeservice.go index 135f6e6d..903ef349 100644 --- a/pkg/metrics/treeservice.go +++ b/pkg/metrics/treeservice.go @@ -4,33 +4,34 @@ import ( "fmt" "time" + "git.frostfs.info/TrueCloudLab/frostfs-observability/metrics" "github.com/prometheus/client_golang/prometheus" ) const treeServiceLabelSuccess = "success" type treeServiceMetrics struct { - replicateTaskDuration metric[*prometheus.HistogramVec] - replicateWaitDuration metric[*prometheus.HistogramVec] - syncOpDuration metric[*prometheus.HistogramVec] + replicateTaskDuration *prometheus.HistogramVec + replicateWaitDuration *prometheus.HistogramVec + syncOpDuration *prometheus.HistogramVec } func newTreeServiceMetrics() *treeServiceMetrics { const treeServiceSubsystem = "treeservice" return &treeServiceMetrics{ - replicateTaskDuration: newHistogramVec(prometheus.HistogramOpts{ + replicateTaskDuration: metrics.NewHistogramVec(prometheus.HistogramOpts{ Namespace: namespace, Subsystem: treeServiceSubsystem, Name: "replicate_task_duration_seconds", Help: "Duration of individual replication tasks executed as part of replication loops", }, []string{treeServiceLabelSuccess}), - replicateWaitDuration: newHistogramVec(prometheus.HistogramOpts{ + replicateWaitDuration: metrics.NewHistogramVec(prometheus.HistogramOpts{ Namespace: namespace, Subsystem: treeServiceSubsystem, Name: "replicate_wait_duration_seconds", Help: "Duration of overall waiting time for replication loops", }, []string{treeServiceLabelSuccess}), - syncOpDuration: newHistogramVec(prometheus.HistogramOpts{ + syncOpDuration: metrics.NewHistogramVec(prometheus.HistogramOpts{ Namespace: namespace, Subsystem: treeServiceSubsystem, Name: "sync_duration_seconds", @@ -39,26 +40,20 @@ func newTreeServiceMetrics() *treeServiceMetrics { } } -func (m *treeServiceMetrics) register() { - mustRegister(m.replicateTaskDuration) - mustRegister(m.replicateWaitDuration) - mustRegister(m.syncOpDuration) -} - func (m *treeServiceMetrics) AddReplicateTaskDuration(d time.Duration, success bool) { - m.replicateTaskDuration.value.With(prometheus.Labels{ + m.replicateTaskDuration.With(prometheus.Labels{ treeServiceLabelSuccess: fmt.Sprintf("%v", success), }).Observe(d.Seconds()) } func (m *treeServiceMetrics) AddReplicateWaitDuration(d time.Duration, success bool) { - m.replicateWaitDuration.value.With(prometheus.Labels{ + m.replicateWaitDuration.With(prometheus.Labels{ treeServiceLabelSuccess: fmt.Sprintf("%v", success), }).Observe(d.Seconds()) } func (m *treeServiceMetrics) AddSyncDuration(d time.Duration, success bool) { - m.syncOpDuration.value.With(prometheus.Labels{ + m.syncOpDuration.With(prometheus.Labels{ treeServiceLabelSuccess: fmt.Sprintf("%v", success), }).Observe(d.Seconds()) } diff --git a/pkg/metrics/writecache.go b/pkg/metrics/writecache.go index 74c33084..3c56aa2b 100644 --- a/pkg/metrics/writecache.go +++ b/pkg/metrics/writecache.go @@ -5,6 +5,7 @@ import ( "sync" "time" + "git.frostfs.info/TrueCloudLab/frostfs-observability/metrics" "github.com/prometheus/client_golang/prometheus" ) @@ -37,18 +38,18 @@ type WriteCacheMetrics interface { } type writeCacheMetrics struct { - getDuration metric[*prometheus.HistogramVec] - putDuration metric[*prometheus.HistogramVec] - deleteDuration metric[*prometheus.HistogramVec] + getDuration *prometheus.HistogramVec + putDuration *prometheus.HistogramVec + deleteDuration *prometheus.HistogramVec - flushCounter metric[*prometheus.CounterVec] - evictCounter metric[*prometheus.CounterVec] + flushCounter *prometheus.CounterVec + evictCounter *prometheus.CounterVec - actualCount metric[*prometheus.GaugeVec] + actualCount *prometheus.GaugeVec - estimatedSize metric[*prometheus.GaugeVec] + estimatedSize *prometheus.GaugeVec - modeMetrics map[shardIDMode]metric[prometheus.GaugeFunc] + modeMetrics map[shardIDMode]prometheus.GaugeFunc modeValues map[string]string modeMtx sync.RWMutex } @@ -63,46 +64,46 @@ func newWriteCacheMetrics() *writeCacheMetrics { actualCount: newWCGaugeVec("actual_objects_count", "Actual objects count in writecache", []string{wcShardID, wcStorage}), estimatedSize: newWCGaugeVec("estimated_size_bytes", "Estimated writecache size", []string{wcShardID, wcStorage}), modeMtx: sync.RWMutex{}, - modeMetrics: make(map[shardIDMode]metric[prometheus.GaugeFunc]), + modeMetrics: make(map[shardIDMode]prometheus.GaugeFunc), modeValues: make(map[string]string), } } func (m *writeCacheMetrics) AddGetDuration(shardID string, success bool, d time.Duration, storageType string) { - setWriteCacheDuration(m.getDuration.value, shardID, success, d, storageType) + setWriteCacheDuration(m.getDuration, shardID, success, d, storageType) } func (m *writeCacheMetrics) AddDeleteDuration(shardID string, success bool, d time.Duration, storageType string) { - setWriteCacheDuration(m.deleteDuration.value, shardID, success, d, storageType) + setWriteCacheDuration(m.deleteDuration, shardID, success, d, storageType) } func (m *writeCacheMetrics) AddPutDuration(shardID string, success bool, d time.Duration, storageType string) { - setWriteCacheDuration(m.putDuration.value, shardID, success, d, storageType) + setWriteCacheDuration(m.putDuration, shardID, success, d, storageType) } func (m *writeCacheMetrics) IncActualCount(shardID string, storageType string) { - m.actualCount.value.With(prometheus.Labels{ + m.actualCount.With(prometheus.Labels{ wcShardID: shardID, wcStorage: storageType, }).Inc() } func (m *writeCacheMetrics) DecActualCount(shardID string, storageType string) { - m.actualCount.value.With(prometheus.Labels{ + m.actualCount.With(prometheus.Labels{ wcShardID: shardID, wcStorage: storageType, }).Dec() } func (m *writeCacheMetrics) SetActualCount(shardID string, count uint64, storageType string) { - m.actualCount.value.With(prometheus.Labels{ + m.actualCount.With(prometheus.Labels{ wcShardID: shardID, wcStorage: storageType, }).Set(float64(count)) } func (m *writeCacheMetrics) SetEstimateSize(shardID string, size uint64, storageType string) { - m.estimatedSize.value.With(prometheus.Labels{ + m.estimatedSize.With(prometheus.Labels{ wcShardID: shardID, wcStorage: storageType, }).Set(float64(size)) @@ -121,7 +122,7 @@ func (m *writeCacheMetrics) SetMode(shardID string, mode string) { return } - metric := newGaugeFunc( + metric := metrics.NewGaugeFunc( prometheus.GaugeOpts{ Namespace: namespace, Subsystem: wcSubsystem, @@ -141,12 +142,11 @@ func (m *writeCacheMetrics) SetMode(shardID string, mode string) { } return 0 }) - mustRegister(metric) m.modeMetrics[key] = metric } func (m *writeCacheMetrics) IncFlushCounter(shardID string, success bool, storageType string) { - m.flushCounter.value.With(prometheus.Labels{ + m.flushCounter.With(prometheus.Labels{ wcShardID: shardID, wcSuccess: fmt.Sprintf("%v", success), wcStorage: storageType, @@ -154,22 +154,12 @@ func (m *writeCacheMetrics) IncFlushCounter(shardID string, success bool, storag } func (m *writeCacheMetrics) IncEvictCounter(shardID string, storageType string) { - m.evictCounter.value.With(prometheus.Labels{ + m.evictCounter.With(prometheus.Labels{ wcShardID: shardID, wcStorage: storageType, }).Inc() } -func (m *writeCacheMetrics) register() { - mustRegister(m.getDuration) - mustRegister(m.putDuration) - mustRegister(m.deleteDuration) - mustRegister(m.actualCount) - mustRegister(m.estimatedSize) - mustRegister(m.flushCounter) - mustRegister(m.evictCounter) -} - func setWriteCacheDuration(m *prometheus.HistogramVec, shardID string, success bool, d time.Duration, storageType string) { m.With( prometheus.Labels{ @@ -180,17 +170,17 @@ func setWriteCacheDuration(m *prometheus.HistogramVec, shardID string, success b ).Observe(float64(d)) } -func newWCMethodDurationCounter(method string) metric[*prometheus.HistogramVec] { - return newHistogramVec(prometheus.HistogramOpts{ +func newWCMethodDurationCounter(method string) *prometheus.HistogramVec { + return metrics.NewHistogramVec(prometheus.HistogramOpts{ Namespace: namespace, Subsystem: wcSubsystem, Name: fmt.Sprintf("%s_req_duration_seconds", method), Help: fmt.Sprintf("Accumulated %s request process duration", method), - }, []string{wcShardID, wcSuccess, wcStorage}) + }, []string{wcShardID, wcSuccess}) } -func newWCOperationCounterVec(operation string, labels []string) metric[*prometheus.CounterVec] { - return newCounterVec(prometheus.CounterOpts{ +func newWCOperationCounterVec(operation string, labels []string) *prometheus.CounterVec { + return metrics.NewCounterVec(prometheus.CounterOpts{ Namespace: namespace, Subsystem: wcSubsystem, Name: fmt.Sprintf("%s_operation_count", operation), @@ -198,8 +188,8 @@ func newWCOperationCounterVec(operation string, labels []string) metric[*prometh }, labels) } -func newWCGaugeVec(name, help string, labels []string) metric[*prometheus.GaugeVec] { - return newGaugeVec(prometheus.GaugeOpts{ +func newWCGaugeVec(name, help string, labels []string) *prometheus.GaugeVec { + return metrics.NewGaugeVec(prometheus.GaugeOpts{ Namespace: namespace, Subsystem: wcSubsystem, Name: name, diff --git a/scripts/export-metrics/main.go b/scripts/export-metrics/main.go index 694eea38..f29eca37 100644 --- a/scripts/export-metrics/main.go +++ b/scripts/export-metrics/main.go @@ -6,7 +6,8 @@ import ( "fmt" "os" - "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/metrics" + local_metrics "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/metrics" + "git.frostfs.info/TrueCloudLab/frostfs-observability/metrics" ) var ( @@ -25,10 +26,10 @@ func main() { var filename string switch { case *node != "": - _ = metrics.NewNodeMetrics() + _ = local_metrics.NewNodeMetrics() filename = *node case *ir != "": - _ = metrics.NewInnerRingMetrics() + _ = local_metrics.NewInnerRingMetrics() filename = *ir default: @@ -36,11 +37,7 @@ func main() { os.Exit(1) } - ds, err := metrics.DescribeAll() - if err != nil { - fmt.Fprintf(os.Stderr, "Could not parse metric descriptions: %v\n", err) - os.Exit(1) - } + ds := metrics.DescribeAll() data, err := json.Marshal(ds) if err != nil {