package metric import ( "crypto/md5" "encoding/binary" "encoding/hex" "encoding/json" "fmt" "math" "os" "repositories.action2quare.com/ayo/gocommon/logger" ) 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 NewMetric func(MetricType, string, string, map[string]string) MetricWriter func init() { NewMetric = func(MetricType, string, string, map[string]string) MetricWriter { return func(val float64) {} } ppid := os.Getppid() if parent, _ := os.FindProcess(ppid); parent != nil { filename := fmt.Sprintf(`/proc/%d/stat`, os.Getppid()) if fn, err := os.ReadFile(filename); err == nil { if string(fn) == "houston" { logger.Println("metrics are activated for houston") go mc.metricWriter() NewMetric = newMetricImpl } else { logger.Println("metrics are NOT activated") } } else { logger.Println("metrics are NOT activated") } } else { logger.Println("metrics are NOT activated") } } func newMetricImpl(mt MetricType, name string, help string, constLabels map[string]string) (writer MetricWriter) { hash := md5.New() hash.Write([]byte(name)) 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 }