2018-03-12 08:48:16 +00:00
|
|
|
package biz
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2021-12-06 12:24:22 +00:00
|
|
|
"errors"
|
|
|
|
"fmt"
|
2018-03-22 08:13:54 +00:00
|
|
|
"os"
|
2018-03-12 08:48:16 +00:00
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/cuigh/auxo/ext/times"
|
2021-12-06 12:24:22 +00:00
|
|
|
"github.com/cuigh/auxo/util/cast"
|
2018-03-12 08:48:16 +00:00
|
|
|
"github.com/cuigh/auxo/util/lazy"
|
2021-12-06 12:24:22 +00:00
|
|
|
"github.com/cuigh/swirl/misc"
|
|
|
|
client "github.com/prometheus/client_golang/api"
|
2018-03-12 08:48:16 +00:00
|
|
|
papi "github.com/prometheus/client_golang/api/prometheus/v1"
|
2021-12-06 12:24:22 +00:00
|
|
|
"github.com/prometheus/common/model"
|
2018-03-12 08:48:16 +00:00
|
|
|
)
|
|
|
|
|
2021-12-06 12:24:22 +00:00
|
|
|
type MetricBiz interface {
|
|
|
|
Enabled() bool
|
2022-01-06 08:54:14 +00:00
|
|
|
GetMatrix(ctx context.Context, query, legend string, start, end time.Time) (data *MatrixData, err error)
|
|
|
|
GetScalar(ctx context.Context, query string, t time.Time) (data float64, err error)
|
|
|
|
GetVector(ctx context.Context, query, label string, t time.Time) (data *VectorData, err error)
|
2021-12-06 12:24:22 +00:00
|
|
|
}
|
2018-03-12 08:48:16 +00:00
|
|
|
|
2021-12-06 12:24:22 +00:00
|
|
|
func NewMetric(setting *misc.Setting) MetricBiz {
|
|
|
|
b := &metricBiz{prometheus: setting.Metric.Prometheus}
|
|
|
|
b.api.New = b.createAPI
|
|
|
|
return b
|
2018-03-12 08:48:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type metricBiz struct {
|
2021-12-06 12:24:22 +00:00
|
|
|
prometheus string
|
|
|
|
api lazy.Value
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *metricBiz) createAPI() (api interface{}, err error) {
|
|
|
|
if b.prometheus == "" {
|
|
|
|
return nil, errors.New("prometheus address is not configured")
|
|
|
|
}
|
|
|
|
|
|
|
|
var c client.Client
|
|
|
|
if c, err = client.NewClient(client.Config{Address: b.prometheus}); err == nil {
|
|
|
|
api = papi.NewAPI(c)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *metricBiz) Enabled() bool {
|
|
|
|
return b.prometheus != ""
|
|
|
|
}
|
|
|
|
|
2022-01-06 08:54:14 +00:00
|
|
|
func (b *metricBiz) GetMatrix(ctx context.Context, query, legend string, start, end time.Time) (data *MatrixData, err error) {
|
2021-12-06 12:24:22 +00:00
|
|
|
if !b.Enabled() {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-03-12 08:48:16 +00:00
|
|
|
api, err := b.getAPI()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
period := end.Sub(start)
|
2022-01-06 08:54:14 +00:00
|
|
|
value, _, err := api.QueryRange(ctx, query, papi.Range{
|
2018-03-12 08:48:16 +00:00
|
|
|
Start: start,
|
|
|
|
End: end,
|
|
|
|
Step: b.calcStep(period),
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-12-06 12:24:22 +00:00
|
|
|
data = &MatrixData{}
|
|
|
|
matrix := value.(model.Matrix)
|
2018-03-12 08:48:16 +00:00
|
|
|
for _, stream := range matrix {
|
2018-04-02 08:19:12 +00:00
|
|
|
data.Legend = append(data.Legend, b.formatLabel(legend, stream.Metric))
|
2021-12-06 12:24:22 +00:00
|
|
|
line := MatrixLine{Name: b.formatLabel(legend, stream.Metric)}
|
2018-03-12 08:48:16 +00:00
|
|
|
for _, v := range stream.Values {
|
2021-12-06 12:24:22 +00:00
|
|
|
p := MatrixPoint{
|
2018-03-12 08:48:16 +00:00
|
|
|
X: int64(v.Timestamp),
|
|
|
|
Y: float64(v.Value),
|
|
|
|
}
|
|
|
|
line.Data = append(line.Data, p)
|
|
|
|
}
|
2018-04-02 08:19:12 +00:00
|
|
|
data.Series = append(data.Series, line)
|
2018-03-12 08:48:16 +00:00
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-01-06 08:54:14 +00:00
|
|
|
func (b *metricBiz) GetScalar(ctx context.Context, query string, t time.Time) (v float64, err error) {
|
2021-12-06 12:24:22 +00:00
|
|
|
if !b.Enabled() {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-03-13 10:48:16 +00:00
|
|
|
api, err := b.getAPI()
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
|
2022-01-06 08:54:14 +00:00
|
|
|
value, _, err := api.Query(ctx, query, t)
|
2018-03-13 10:48:16 +00:00
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
|
2021-12-06 12:24:22 +00:00
|
|
|
//scalar := value.(*model.Scalar)
|
|
|
|
vector := value.(model.Vector)
|
2018-04-02 08:19:12 +00:00
|
|
|
if len(vector) > 0 {
|
|
|
|
sample := vector[0]
|
|
|
|
return float64(sample.Value), nil
|
|
|
|
}
|
|
|
|
return 0, nil
|
2018-03-13 10:48:16 +00:00
|
|
|
}
|
|
|
|
|
2022-01-06 08:54:14 +00:00
|
|
|
func (b *metricBiz) GetVector(ctx context.Context, query, label string, t time.Time) (data *VectorData, err error) {
|
2021-12-06 12:24:22 +00:00
|
|
|
if !b.Enabled() {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-03-22 08:13:54 +00:00
|
|
|
var api papi.API
|
|
|
|
api, err = b.getAPI()
|
2018-03-13 10:48:16 +00:00
|
|
|
if err != nil {
|
2018-03-22 08:13:54 +00:00
|
|
|
return
|
2018-03-13 10:48:16 +00:00
|
|
|
}
|
|
|
|
|
2021-12-06 12:24:22 +00:00
|
|
|
var value model.Value
|
2022-01-06 08:54:14 +00:00
|
|
|
value, _, err = api.Query(ctx, query, t)
|
2018-03-13 10:48:16 +00:00
|
|
|
if err != nil {
|
2018-03-22 08:13:54 +00:00
|
|
|
return
|
2018-03-13 10:48:16 +00:00
|
|
|
}
|
|
|
|
|
2021-12-06 12:24:22 +00:00
|
|
|
data = &VectorData{}
|
|
|
|
vector := value.(model.Vector)
|
2018-03-13 10:48:16 +00:00
|
|
|
for _, sample := range vector {
|
2021-12-06 12:24:22 +00:00
|
|
|
cv := VectorValue{
|
2018-04-02 08:19:12 +00:00
|
|
|
Name: b.formatLabel(label, sample.Metric),
|
|
|
|
Value: float64(sample.Value),
|
2018-03-22 08:13:54 +00:00
|
|
|
}
|
2018-04-02 08:19:12 +00:00
|
|
|
data.Data = append(data.Data, cv)
|
|
|
|
data.Legend = append(data.Legend, cv.Name)
|
2018-03-13 10:48:16 +00:00
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-03-12 08:48:16 +00:00
|
|
|
func (b *metricBiz) calcStep(period time.Duration) (step time.Duration) {
|
|
|
|
if period >= times.Day {
|
2018-04-03 03:57:59 +00:00
|
|
|
step = 8 * time.Minute
|
2018-03-12 08:48:16 +00:00
|
|
|
} else if period >= 12*time.Hour {
|
2018-04-03 03:57:59 +00:00
|
|
|
step = 4 * time.Minute
|
2018-03-12 08:48:16 +00:00
|
|
|
} else if period >= 6*time.Hour {
|
2018-04-03 03:57:59 +00:00
|
|
|
step = 2 * time.Minute
|
2018-03-12 08:48:16 +00:00
|
|
|
} else if period >= 3*time.Hour {
|
|
|
|
step = time.Minute
|
2018-04-03 03:57:59 +00:00
|
|
|
} else {
|
|
|
|
step = 30 * time.Second
|
2018-03-12 08:48:16 +00:00
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *metricBiz) getAPI() (api papi.API, err error) {
|
|
|
|
v, err := b.api.Get()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return v.(papi.API), nil
|
|
|
|
}
|
2018-03-22 08:13:54 +00:00
|
|
|
|
2021-12-06 12:24:22 +00:00
|
|
|
func (b *metricBiz) formatLabel(label string, metric model.Metric) string {
|
2018-03-22 08:13:54 +00:00
|
|
|
return os.Expand(label, func(key string) string {
|
2021-12-06 12:24:22 +00:00
|
|
|
if s := string(metric[model.LabelName(key)]); s != "" {
|
2018-03-22 08:13:54 +00:00
|
|
|
return s
|
|
|
|
}
|
|
|
|
return "[" + key + "]"
|
|
|
|
})
|
|
|
|
}
|
2021-12-06 12:24:22 +00:00
|
|
|
|
|
|
|
type MatrixData struct {
|
|
|
|
Legend []string `json:"legend"`
|
|
|
|
Series []MatrixLine `json:"series"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type MatrixLine struct {
|
|
|
|
Name string `json:"name"`
|
|
|
|
Data []MatrixPoint `json:"data"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type MatrixPoint struct {
|
|
|
|
X int64 `json:"x"`
|
|
|
|
Y float64 `json:"y"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *MatrixPoint) MarshalJSON() ([]byte, error) {
|
|
|
|
return cast.StringToBytes(fmt.Sprintf("[%v,%v]", p.X, p.Y)), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type VectorData struct {
|
|
|
|
Legend []string `json:"legend"`
|
|
|
|
Data []VectorValue `json:"data"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type VectorValue struct {
|
|
|
|
Name string `json:"name"`
|
|
|
|
Value float64 `json:"value"`
|
|
|
|
}
|