package metric import ( "maps" "math" "sync/atomic" "github.com/prometheus/client_golang/prometheus" "repositories.action2quare.com/ayo/gocommon/logger" ) const ( METRIC_HEAD_INLINE = byte(14) METRIC_TAIL_INLINE = byte(15) ) type MetricType int const ( MetricCounter = MetricType(1) MetricGuage = MetricType(2) metric_key_size = 8 ) func convertValueType(in MetricType) prometheus.ValueType { switch in { case MetricCounter: return prometheus.CounterValue case MetricGuage: return prometheus.GaugeValue } return prometheus.UntypedValue } type prometheusMetricDesc struct { *prometheus.Desc valueType prometheus.ValueType valptr *uint64 key string } type PrometheusCollector struct { namespace string metrics map[string]*prometheusMetricDesc registry *prometheus.Registry } func (pc *PrometheusCollector) Describe(ch chan<- *prometheus.Desc) { for _, v := range pc.metrics { logger.Println("collector describe :", v.Desc.String()) ch <- v.Desc } } func (pc *PrometheusCollector) Collect(ch chan<- prometheus.Metric) { for _, v := range pc.metrics { value := atomic.LoadUint64(v.valptr) cm, err := prometheus.NewConstMetric(v.Desc, v.valueType, math.Float64frombits(value)) if err == nil { ch <- cm } } } func (pc *PrometheusCollector) RegisterMetric(md *MetricDescription) *PrometheusCollector { nm := &prometheusMetricDesc{ Desc: prometheus.NewDesc(prometheus.BuildFQName("ou", "", md.Name), md.Help, nil, md.ConstLabels), valueType: convertValueType(md.Type), valptr: new(uint64), key: md.Key, } next := NewPrometheusCollector(pc.namespace, pc.registry) maps.Copy(next.metrics, pc.metrics) next.metrics[nm.key] = nm pc.registry.Unregister(pc) pc.registry.Register(next) return next } func (pc *PrometheusCollector) UpdateMetric(key string, val float64) { if m := pc.metrics[key]; m != nil { atomic.StoreUint64(m.valptr, math.Float64bits(val)) } } func (pc *PrometheusCollector) UnregisterMetric(key string) *PrometheusCollector { next := NewPrometheusCollector(pc.namespace, pc.registry) maps.Copy(next.metrics, pc.metrics) delete(next.metrics, key) pc.registry.Unregister(pc) pc.registry.Register(next) return next } func NewPrometheusCollector(namespace string, registry *prometheus.Registry) *PrometheusCollector { return &PrometheusCollector{ namespace: namespace, metrics: make(map[string]*prometheusMetricDesc), registry: registry, } }