package client import ( "math" _ "net/http/pprof" "sync/atomic" "unsafe" "github.com/prometheus/client_golang/prometheus" "repositories.action2quare.com/ayo/gocommon/metric" ) type metricDesc struct { *prometheus.Desc val *uint64 valueType prometheus.ValueType } type exporterForPrometheus struct { metricPtr unsafe.Pointer // []metricDesc } func newExporterForPrometheus() *exporterForPrometheus { return &exporterForPrometheus{ metricPtr: unsafe.Pointer(new([]metricDesc)), } } type metricValueAccessor struct { ptr *uint64 } func (va *metricValueAccessor) set(val float64) { atomic.StoreUint64(va.ptr, math.Float64bits(val)) } func convertValueType(in metric.MetricType) prometheus.ValueType { switch in { case metric.MetricCounter: return prometheus.CounterValue case metric.MetricGuage: return prometheus.GaugeValue } return prometheus.UntypedValue } func (e *exporterForPrometheus) registMetric(namespace string, desc metric.MetricDescription) metricValueAccessor { ptr := atomic.LoadPointer(&e.metricPtr) container := *(*[]metricDesc)(ptr) newcont := make([]metricDesc, len(container)+1) copy(newcont, container) newval := new(uint64) newcont[len(container)] = metricDesc{ Desc: prometheus.NewDesc(prometheus.BuildFQName(namespace, "", desc.Name), desc.Help, nil, desc.ConstLabels), val: newval, valueType: convertValueType(desc.Type), } atomic.StorePointer(&e.metricPtr, unsafe.Pointer(&newcont)) return metricValueAccessor{ ptr: newval, } } func (e *exporterForPrometheus) Describe(ch chan<- *prometheus.Desc) { ptr := atomic.LoadPointer(&e.metricPtr) container := *(*[]metricDesc)(ptr) for _, v := range container { ch <- v.Desc } } func (e *exporterForPrometheus) Collect(ch chan<- prometheus.Metric) { ptr := atomic.LoadPointer(&e.metricPtr) container := *(*[]metricDesc)(ptr) for _, v := range container { ch <- prometheus.MustNewConstMetric(v.Desc, v.valueType, math.Float64frombits(atomic.LoadUint64(v.val))) } }