package metrics import ( "fmt" "strings" "time" "github.com/prometheus/client_golang/prometheus" ) const objectSubsystem = "object" type ( methodCount struct { success metric[prometheus.Counter] total metric[prometheus.Counter] } objectServiceMetrics struct { getCounter methodCount putCounter methodCount headCounter methodCount searchCounter methodCount deleteCounter methodCount 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] putPayload metric[prometheus.Counter] getPayload metric[prometheus.Counter] shardMetrics metric[*prometheus.GaugeVec] shardsReadonly metric[*prometheus.GaugeVec] } ) const ( shardIDLabelKey = "shard" counterTypeLabelKey = "type" containerIDLabelKey = "cid" ) func newObjectMethodCallCounter(name string) methodCount { return methodCount{ success: 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{ Namespace: namespace, Subsystem: objectSubsystem, Name: fmt.Sprintf("%s_req_count", name), Help: fmt.Sprintf("Total number of %s requests processed", name), }), } } func (m methodCount) mustRegister() { mustRegister(m.success) mustRegister(m.total) } func (m methodCount) Inc(success bool) { m.total.value.Inc() if success { m.success.value.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) metric[prometheus.Counter] { return 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) metric[prometheus.Counter] { return 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) metric[*prometheus.GaugeVec] { return newGaugeVec(prometheus.GaugeOpts{ Namespace: namespace, Subsystem: objectSubsystem, Name: name, Help: help, }, 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) } 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.value.Add(float64(d)) } func (m objectServiceMetrics) AddPutReqDuration(d time.Duration) { m.putDuration.value.Add(float64(d)) } func (m objectServiceMetrics) AddHeadReqDuration(d time.Duration) { m.headDuration.value.Add(float64(d)) } func (m objectServiceMetrics) AddSearchReqDuration(d time.Duration) { m.searchDuration.value.Add(float64(d)) } func (m objectServiceMetrics) AddDeleteReqDuration(d time.Duration) { m.deleteDuration.value.Add(float64(d)) } func (m objectServiceMetrics) AddRangeReqDuration(d time.Duration) { m.rangeDuration.value.Add(float64(d)) } func (m objectServiceMetrics) AddRangeHashReqDuration(d time.Duration) { m.rangeHashDuration.value.Add(float64(d)) } func (m objectServiceMetrics) AddPutPayload(ln int) { m.putPayload.value.Add(float64(ln)) } func (m objectServiceMetrics) AddGetPayload(ln int) { m.getPayload.value.Add(float64(ln)) } func (m objectServiceMetrics) AddToObjectCounter(shardID, objectType string, delta int) { m.shardMetrics.value.With( prometheus.Labels{ shardIDLabelKey: shardID, counterTypeLabelKey: objectType, }, ).Add(float64(delta)) } func (m objectServiceMetrics) SetObjectCounter(shardID, objectType string, v uint64) { m.shardMetrics.value.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.value.With( prometheus.Labels{ shardIDLabelKey: shardID, }, ).Set(flag) }