2025-06-27 01:11:54 +09:00
|
|
|
package metric
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"crypto/md5"
|
|
|
|
|
"encoding/hex"
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"fmt"
|
|
|
|
|
"os"
|
|
|
|
|
"path"
|
2025-07-02 11:30:41 +09:00
|
|
|
"runtime"
|
2025-06-27 01:11:54 +09:00
|
|
|
"sort"
|
|
|
|
|
"strings"
|
|
|
|
|
"sync/atomic"
|
|
|
|
|
|
|
|
|
|
"repositories.action2quare.com/ayo/gocommon/logger"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type MetricDescription struct {
|
|
|
|
|
Key string
|
|
|
|
|
Type MetricType
|
|
|
|
|
Name string `json:",omitempty"`
|
|
|
|
|
Help string `json:",omitempty"`
|
|
|
|
|
ConstLabels map[string]string `json:",omitempty"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type Exporter interface {
|
|
|
|
|
RegisterMetric(*MetricDescription)
|
|
|
|
|
UpdateMetric(string, float64)
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-02 11:30:41 +09:00
|
|
|
type MetricPipe struct {
|
|
|
|
|
pipe *os.File
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (mp MetricPipe) Close() {
|
|
|
|
|
mp.pipe.Close()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (mp MetricPipe) writeLine(line string) {
|
|
|
|
|
mp.pipe.WriteString(line + "\n")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewMetricPipe(pipeName string) MetricPipe {
|
|
|
|
|
switch runtime.GOOS {
|
|
|
|
|
case "linux":
|
|
|
|
|
pipeName = "/tmp/" + pipeName
|
|
|
|
|
case "windows":
|
|
|
|
|
pipeName = `\\.\pipe\` + pipeName
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
f, _ := os.Open(pipeName)
|
|
|
|
|
return MetricPipe{
|
|
|
|
|
pipe: f,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-27 01:11:54 +09:00
|
|
|
type MetricWriter interface {
|
|
|
|
|
Add(int64)
|
|
|
|
|
Set(int64)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type metric_empty struct{}
|
|
|
|
|
|
|
|
|
|
func (mw *metric_empty) Set(int64) {}
|
|
|
|
|
func (mw *metric_empty) Add(int64) {}
|
|
|
|
|
|
|
|
|
|
var MetricWriterNil = MetricWriter(&metric_empty{})
|
|
|
|
|
|
|
|
|
|
type metric_int64 struct {
|
2025-07-02 11:30:41 +09:00
|
|
|
key string
|
2025-06-27 01:11:54 +09:00
|
|
|
valptr *int64
|
2025-07-02 11:30:41 +09:00
|
|
|
pipe MetricPipe
|
2025-06-27 01:11:54 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (mw *metric_int64) printOut() {
|
2025-07-02 11:30:41 +09:00
|
|
|
loaded := atomic.LoadInt64(mw.valptr)
|
|
|
|
|
mw.pipe.writeLine(fmt.Sprintf("%s:%d", mw.key, loaded))
|
2025-06-27 01:11:54 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (mw *metric_int64) Set(newval int64) {
|
|
|
|
|
atomic.StoreInt64(mw.valptr, newval)
|
|
|
|
|
mw.printOut()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (mw *metric_int64) Add(inc int64) {
|
|
|
|
|
atomic.AddInt64(mw.valptr, inc)
|
|
|
|
|
mw.printOut()
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-02 11:30:41 +09:00
|
|
|
func NewMetric(pipe MetricPipe, mt MetricType, name string, help string, constLabels map[string]string) (writer MetricWriter) {
|
2025-06-27 01:11:54 +09:00
|
|
|
if !metricEnabled {
|
|
|
|
|
return MetricWriterNil
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-02 11:30:41 +09:00
|
|
|
if constLabels == nil {
|
|
|
|
|
constLabels = map[string]string{}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
constLabels["pid"] = fmt.Sprintf("%d", os.Getpid())
|
2025-06-27 01:11:54 +09:00
|
|
|
var disorder []struct {
|
|
|
|
|
k string
|
|
|
|
|
v string
|
|
|
|
|
}
|
|
|
|
|
for k, v := range constLabels {
|
|
|
|
|
disorder = append(disorder, struct {
|
|
|
|
|
k string
|
|
|
|
|
v string
|
|
|
|
|
}{k: strings.ToLower(k), v: strings.ToLower(v)})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sort.Slice(disorder, func(i, j int) bool {
|
|
|
|
|
return disorder[i].k < disorder[j].k
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
hash := md5.New()
|
|
|
|
|
hash.Write([]byte(strings.ToLower(name)))
|
|
|
|
|
for _, d := range disorder {
|
|
|
|
|
hash.Write([]byte(d.k))
|
|
|
|
|
hash.Write([]byte(d.v))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
key := hex.EncodeToString(hash.Sum(nil))[:metric_key_size]
|
|
|
|
|
temp, _ := json.Marshal(MetricDescription{
|
|
|
|
|
Key: key,
|
|
|
|
|
Type: mt,
|
|
|
|
|
Name: name,
|
|
|
|
|
Help: help,
|
|
|
|
|
ConstLabels: constLabels,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
impl := &metric_int64{
|
2025-07-02 11:30:41 +09:00
|
|
|
key: key,
|
2025-06-27 01:11:54 +09:00
|
|
|
valptr: new(int64),
|
2025-07-02 11:30:41 +09:00
|
|
|
pipe: pipe,
|
2025-06-27 01:11:54 +09:00
|
|
|
}
|
|
|
|
|
|
2025-07-02 11:30:41 +09:00
|
|
|
pipe.writeLine(string(temp))
|
2025-06-27 01:11:54 +09:00
|
|
|
// writer
|
|
|
|
|
|
|
|
|
|
return impl
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var metricEnabled = false
|
|
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
|
if path.Base(os.Args[0]) == "houston" {
|
|
|
|
|
logger.Println("metrics are going to be generated for myself(houston)")
|
|
|
|
|
metricEnabled = true
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 {
|
|
|
|
|
stats := strings.SplitN(string(fn), " ", 3)
|
|
|
|
|
parentname := strings.Trim(stats[1], "()")
|
|
|
|
|
|
|
|
|
|
if path.Base(parentname) == "houston" {
|
|
|
|
|
logger.Println("metrics are going to be generated for houston")
|
|
|
|
|
metricEnabled = true
|
|
|
|
|
} else {
|
|
|
|
|
logger.Println("metrics are NOT going to be generated. parent is not houston :", filename, string(fn))
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
logger.Println("metrics are NOT going to be generated. ppid proc is missing :", filename)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
logger.Println("metrics are NOT going to be generated. parent process is missing. ppid :", ppid)
|
|
|
|
|
}
|
|
|
|
|
}
|