2021-06-09 06:03:31 +02:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
2021-08-20 11:45:34 +02:00
|
|
|
"errors"
|
2021-06-09 06:03:31 +02:00
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
"os"
|
2021-08-20 11:45:34 +02:00
|
|
|
"os/signal"
|
|
|
|
"syscall"
|
2021-06-09 06:03:31 +02:00
|
|
|
|
2021-08-20 11:45:34 +02:00
|
|
|
"github.com/ClusterCockpit/cc-metric-store/lineprotocol"
|
2021-06-09 06:03:31 +02:00
|
|
|
)
|
|
|
|
|
2021-08-20 11:45:34 +02:00
|
|
|
type MetricStore interface {
|
|
|
|
AddMetrics(key string, ts int64, metrics []lineprotocol.Metric) error
|
|
|
|
GetMetric(key string, metric string, from int64, to int64) ([]float64, int64, error)
|
2021-06-09 06:03:31 +02:00
|
|
|
}
|
|
|
|
|
2021-08-20 11:45:34 +02:00
|
|
|
type Config struct {
|
|
|
|
MetricClasses map[string]struct {
|
|
|
|
Frequency int `json:"frequency"`
|
|
|
|
Metrics []string `json:"metrics"`
|
|
|
|
} `json:"metrics"`
|
2021-06-09 06:03:31 +02:00
|
|
|
}
|
|
|
|
|
2021-08-20 11:45:34 +02:00
|
|
|
var conf Config
|
|
|
|
var metricStores map[string]MetricStore = map[string]MetricStore{}
|
2021-06-09 06:03:31 +02:00
|
|
|
|
|
|
|
func loadConfiguration(file string) Config {
|
|
|
|
var config Config
|
|
|
|
configFile, err := os.Open(file)
|
|
|
|
defer configFile.Close()
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err.Error())
|
|
|
|
}
|
|
|
|
jsonParser := json.NewDecoder(configFile)
|
|
|
|
jsonParser.Decode(&config)
|
|
|
|
return config
|
|
|
|
}
|
|
|
|
|
2021-08-20 11:45:34 +02:00
|
|
|
// TODO: Change MetricStore API so that we do not have to do string concat?
|
|
|
|
// Nested hashmaps could be an alternative.
|
|
|
|
func buildKey(line *lineprotocol.Line) (string, error) {
|
|
|
|
cluster, ok := line.Tags["cluster"]
|
|
|
|
if !ok {
|
|
|
|
return "", errors.New("missing cluster tag")
|
|
|
|
}
|
|
|
|
|
|
|
|
host, ok := line.Tags["host"]
|
|
|
|
if !ok {
|
|
|
|
return "", errors.New("missing host tag")
|
|
|
|
}
|
2021-06-09 06:03:31 +02:00
|
|
|
|
2021-08-20 11:45:34 +02:00
|
|
|
cpu, ok := line.Tags["cpu"]
|
|
|
|
if ok {
|
|
|
|
return cluster + ":" + host + ":" + cpu, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return cluster + ":" + host, nil
|
|
|
|
}
|
2021-06-09 06:03:31 +02:00
|
|
|
|
2021-08-20 11:45:34 +02:00
|
|
|
func handleLine(line *lineprotocol.Line) {
|
|
|
|
// log.Printf("line: %v\n", line)
|
|
|
|
|
|
|
|
store := metricStores[line.Measurement]
|
|
|
|
key, err := buildKey(line)
|
2021-06-09 06:03:31 +02:00
|
|
|
if err != nil {
|
2021-08-20 11:45:34 +02:00
|
|
|
log.Println(err)
|
2021-06-09 06:03:31 +02:00
|
|
|
}
|
2021-08-20 11:45:34 +02:00
|
|
|
|
|
|
|
err = store.AddMetrics(key, line.Ts.Unix(), line.Fields)
|
|
|
|
}
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
conf = loadConfiguration("config.json")
|
|
|
|
|
|
|
|
for class, info := range conf.MetricClasses {
|
|
|
|
metricStores[class] = newMemoryStore(info.Metrics, 1000, info.Frequency)
|
2021-06-09 06:03:31 +02:00
|
|
|
}
|
|
|
|
|
2021-08-20 11:45:34 +02:00
|
|
|
sigs := make(chan os.Signal, 1)
|
|
|
|
done := make(chan bool, 1)
|
|
|
|
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
|
|
|
go func() {
|
|
|
|
_ = <-sigs
|
|
|
|
done <- true
|
|
|
|
}()
|
|
|
|
|
|
|
|
err := lineprotocol.ReceiveNats("nats://localhost:4222", handleLine, done)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
2021-06-09 06:03:31 +02:00
|
|
|
}
|