Files
gocommon/metric/metric.go
2023-11-16 19:56:47 +09:00

109 lines
2.1 KiB
Go

package metric
import (
"crypto/md5"
"encoding/binary"
"encoding/hex"
"encoding/json"
"math"
"os"
"sync"
)
const (
METRIC_HEAD_INLINE = byte(1)
METRIC_TAIL_INLINE = byte(2)
)
type MetricType int
const (
MetricCounter = MetricType(1)
MetricGuage = MetricType(2)
metric_key_size = 8
)
type MetricDescription struct {
Key string
Type MetricType
Name string `json:",omitempty"`
Help string `json:",omitempty"`
ConstLabels map[string]string `json:",omitempty"`
}
type writeRequest struct {
key string
val float64
}
type metricCollection struct {
writerChan chan *writeRequest
}
var mc = metricCollection{
writerChan: make(chan *writeRequest, 100),
}
type MetricWriter func(float64)
func (mc *metricCollection) metricWriter() {
// head + metric_key_size + 8byte + tail + cr = 19
var buff [20]byte
buff[0] = METRIC_HEAD_INLINE
buff[17] = METRIC_TAIL_INLINE
buff[18] = '\n'
for req := range mc.writerChan {
copy(buff[1:], []byte(req.key))
binary.BigEndian.PutUint64(buff[9:], math.Float64bits(req.val))
os.Stdout.Write(buff[:])
}
}
var metricWriterFlag sync.Once
func NewMetric(mt MetricType, name string, help string, constLabel ...string) (writer MetricWriter) {
metricWriterFlag.Do(func() {
go mc.metricWriter()
})
hash := md5.New()
hash.Write([]byte(name))
var constLabels map[string]string
if len(constLabel) > 0 {
constLabels = make(map[string]string)
for i := 0; i < len(constLabel); i = i + 2 {
constLabels[constLabel[i]] = ""
hash.Write([]byte(constLabel[i]))
}
for i := 1; i < len(constLabel); i = i + 2 {
constLabels[constLabel[i-1]] = constLabel[i]
hash.Write([]byte(constLabel[i]))
}
}
key := hex.EncodeToString(hash.Sum(nil))[:metric_key_size]
temp, _ := json.Marshal(MetricDescription{
Key: key,
Type: mt,
Name: name,
Help: help,
ConstLabels: constLabels,
})
writer = func(val float64) {
mc.writerChan <- &writeRequest{
key: key,
val: val,
}
}
output := append([]byte{METRIC_HEAD_INLINE}, temp...)
output = append(output, METRIC_TAIL_INLINE, '\n')
os.Stdout.Write(output)
return
}