package metrics import ( "fmt" "strings" "time" "git.frostfs.info/TrueCloudLab/frostfs-observability/metrics" "github.com/prometheus/client_golang/prometheus" ) const objectSubsystem = "object" type ( methodCount struct { success prometheus.Counter total prometheus.Counter } objectServiceMetrics struct { getCounter methodCount putCounter methodCount headCounter methodCount searchCounter methodCount deleteCounter methodCount rangeCounter methodCount rangeHashCounter methodCount getDuration prometheus.Counter putDuration prometheus.Counter headDuration prometheus.Counter searchDuration prometheus.Counter deleteDuration prometheus.Counter rangeDuration prometheus.Counter rangeHashDuration prometheus.Counter putPayload prometheus.Counter getPayload prometheus.Counter shardMetrics *prometheus.GaugeVec shardsReadonly *prometheus.GaugeVec } ) const ( shardIDLabelKey = "shard" counterTypeLabelKey = "type" containerIDLabelKey = "cid" ) func newObjectMethodCallCounter(name string) methodCount { return methodCount{ 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: metrics.NewCounter(prometheus.CounterOpts{ Namespace: namespace, Subsystem: objectSubsystem, Name: fmt.Sprintf("%s_req_count", name), Help: fmt.Sprintf("Total number of %s requests processed", name), }), } } func (m methodCount) Inc(success bool) { m.total.Inc() if success { m.success.Inc() } } func newObjectServiceMetrics() objectServiceMetrics { return objectServiceMetrics{ getCounter: newObjectMethodCallCounter("get"), putCounter: newObjectMethodCallCounter("put"), headCounter: newObjectMethodCallCounter("head"), searchCounter: newObjectMethodCallCounter("search"), deleteCounter: newObjectMethodCallCounter("delete"), rangeCounter: newObjectMethodCallCounter("range"), rangeHashCounter: newObjectMethodCallCounter("range_hash"), getDuration: newObjectMethodDurationCounter("get"), putDuration: newObjectMethodDurationCounter("put"), headDuration: newObjectMethodDurationCounter("head"), searchDuration: newObjectMethodDurationCounter("search"), deleteDuration: newObjectMethodDurationCounter("delete"), rangeDuration: newObjectMethodDurationCounter("range"), rangeHashDuration: newObjectMethodDurationCounter("range_hash"), putPayload: newObjectMethodPayloadCounter("put"), getPayload: newObjectMethodPayloadCounter("get"), shardMetrics: newObjectGaugeVector("counter", "Objects counters per shards", []string{shardIDLabelKey, counterTypeLabelKey}), shardsReadonly: newObjectGaugeVector("readonly", "Shard state", []string{shardIDLabelKey}), } } func newObjectMethodPayloadCounter(method string) prometheus.Counter { return metrics.NewCounter(prometheus.CounterOpts{ Namespace: namespace, Subsystem: objectSubsystem, Name: fmt.Sprintf("%s_payload", method), Help: fmt.Sprintf("Accumulated payload size at object %s method", strings.ReplaceAll(method, "_", " ")), }) } func newObjectMethodDurationCounter(method string) prometheus.Counter { return metrics.NewCounter(prometheus.CounterOpts{ Namespace: namespace, Subsystem: objectSubsystem, Name: fmt.Sprintf("%s_req_duration", method), Help: fmt.Sprintf("Accumulated %s request process duration", strings.ReplaceAll(method, "_", " ")), }) } func newObjectGaugeVector(name, help string, labels []string) *prometheus.GaugeVec { return metrics.NewGaugeVec(prometheus.GaugeOpts{ Namespace: namespace, Subsystem: objectSubsystem, Name: name, Help: help, }, labels) } func (m objectServiceMetrics) IncGetReqCounter(success bool) { m.getCounter.Inc(success) } func (m objectServiceMetrics) IncPutReqCounter(success bool) { m.putCounter.Inc(success) } func (m objectServiceMetrics) IncHeadReqCounter(success bool) { m.headCounter.Inc(success) } func (m objectServiceMetrics) IncSearchReqCounter(success bool) { m.searchCounter.Inc(success) } func (m objectServiceMetrics) IncDeleteReqCounter(success bool) { m.deleteCounter.Inc(success) } func (m objectServiceMetrics) IncRangeReqCounter(success bool) { m.rangeCounter.Inc(success) } func (m objectServiceMetrics) IncRangeHashReqCounter(success bool) { m.rangeHashCounter.Inc(success) } func (m objectServiceMetrics) AddGetReqDuration(d time.Duration) { m.getDuration.Add(float64(d)) } func (m objectServiceMetrics) AddPutReqDuration(d time.Duration) { m.putDuration.Add(float64(d)) } func (m objectServiceMetrics) AddHeadReqDuration(d time.Duration) { m.headDuration.Add(float64(d)) } func (m objectServiceMetrics) AddSearchReqDuration(d time.Duration) { m.searchDuration.Add(float64(d)) } func (m objectServiceMetrics) AddDeleteReqDuration(d time.Duration) { m.deleteDuration.Add(float64(d)) } func (m objectServiceMetrics) AddRangeReqDuration(d time.Duration) { m.rangeDuration.Add(float64(d)) } func (m objectServiceMetrics) AddRangeHashReqDuration(d time.Duration) { m.rangeHashDuration.Add(float64(d)) } func (m objectServiceMetrics) AddPutPayload(ln int) { m.putPayload.Add(float64(ln)) } func (m objectServiceMetrics) AddGetPayload(ln int) { m.getPayload.Add(float64(ln)) } func (m objectServiceMetrics) AddToObjectCounter(shardID, objectType string, delta int) { m.shardMetrics.With( prometheus.Labels{ shardIDLabelKey: shardID, counterTypeLabelKey: objectType, }, ).Add(float64(delta)) } func (m objectServiceMetrics) SetObjectCounter(shardID, objectType string, v uint64) { m.shardMetrics.With( prometheus.Labels{ shardIDLabelKey: shardID, counterTypeLabelKey: objectType, }, ).Set(float64(v)) } func (m objectServiceMetrics) SetReadonly(shardID string, readonly bool) { var flag float64 if readonly { flag = 1 } m.shardsReadonly.With( prometheus.Labels{ shardIDLabelKey: shardID, }, ).Set(flag) }