Add Prometheus provider (#3555)
Allows to load a scalar metrics from prometheus
Example config:
```
meters:
- name: pv
type: custom
power:
source: prometheus
uri: http://prometheus:9090
query: "scalar(p_realtime)"
```
This commit is contained in:
parent
d93cf01108
commit
c5f6ffc51a
3 changed files with 111 additions and 1 deletions
5
go.mod
5
go.mod
|
|
@ -63,6 +63,7 @@ require (
|
|||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/philippseith/signalr v0.5.3-0.20211205201131-d57b5a34379a
|
||||
github.com/prometheus/client_golang v1.12.2
|
||||
github.com/prometheus/common v0.34.0
|
||||
github.com/robertkrimen/otto v0.0.0-20211024170158-b87d35c0b86f
|
||||
github.com/samber/lo v1.21.0
|
||||
github.com/shurcooL/graphql v0.0.0-20220520033453-bdb1221e171e
|
||||
|
|
@ -118,6 +119,7 @@ require (
|
|||
github.com/influxdata/line-protocol v0.0.0-20210922203350-b1ad95c89adf // indirect
|
||||
github.com/itchyny/timefmt-go v0.1.3 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.15.5 // indirect
|
||||
github.com/leodido/go-urn v1.2.1 // indirect
|
||||
github.com/magiconair/properties v1.8.6 // indirect
|
||||
|
|
@ -129,6 +131,8 @@ require (
|
|||
github.com/miekg/dns v1.1.49 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/onsi/ginkgo v1.16.5 // indirect
|
||||
github.com/onsi/gomega v1.19.0 // indirect
|
||||
github.com/pascaldekloe/name v1.0.1 // indirect
|
||||
|
|
@ -137,7 +141,6 @@ require (
|
|||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.34.0 // indirect
|
||||
github.com/prometheus/procfs v0.7.3 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/shopspring/decimal v1.3.1 // indirect
|
||||
|
|
|
|||
2
go.sum
2
go.sum
|
|
@ -532,6 +532,7 @@ github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFF
|
|||
github.com/jpfielding/go-http-digest v0.0.0-20211006141426-fbc93758452e h1:iLmt7czLE9ophoU4xZcckVNCXp+auTvVSQ9MGTWbgBY=
|
||||
github.com/jpfielding/go-http-digest v0.0.0-20211006141426-fbc93758452e/go.mod h1:oLt6zF2euTyCg2Cxz01B3VC5SJcPpKpYnOAqvO+480s=
|
||||
github.com/jpfielding/gowirelog v0.0.0-20200123170752-df8f8dccb721/go.mod h1:R8b6Hefiy6MSxbJ8dbF9Gkaa/LwFh9meFV0i9hkR5i8=
|
||||
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
|
||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
|
|
@ -679,6 +680,7 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY
|
|||
github.com/muka/go-bluetooth v0.0.0-20220219050759-674a63b8741a h1:fnzS9RRQW8B5AgNCxkN0vJ/AoX+Xfqk3sAYon3iVrzA=
|
||||
github.com/muka/go-bluetooth v0.0.0-20220219050759-674a63b8741a/go.mod h1:dMCjicU6vRBk34dqOmIZm0aod6gUwZXOXzBROqGous0=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mxschmitt/golang-combinations v1.1.0 h1:WlIZCnDm+Xlb2pRPf+R/qPKlGOU1w8lpN69/uy5z+Zg=
|
||||
github.com/mxschmitt/golang-combinations v1.1.0/go.mod h1:RbMhWvfCelHR6WROvT2bVfxJvZHoEvBj71SKe+H0MYU=
|
||||
|
|
|
|||
105
provider/prometheus.go
Normal file
105
provider/prometheus.go
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
package provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/evcc-io/evcc/util/request"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
v1 "github.com/prometheus/client_golang/api/prometheus/v1"
|
||||
"github.com/prometheus/common/model"
|
||||
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/prometheus/client_golang/api"
|
||||
)
|
||||
|
||||
// Prometheus provider
|
||||
type Prometheus struct {
|
||||
log *util.Logger
|
||||
clientV1Api v1.API
|
||||
query string
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
func init() {
|
||||
registry.Add("prometheus", NewPrometheusFromConfig)
|
||||
}
|
||||
|
||||
func NewPrometheusFromConfig(other map[string]interface{}) (IntProvider, error) {
|
||||
cc := struct {
|
||||
api.Config `mapstructure:",squash"`
|
||||
Query string
|
||||
Timeout time.Duration
|
||||
}{
|
||||
Timeout: request.Timeout,
|
||||
}
|
||||
|
||||
if err := util.DecodeOther(other, &cc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log := util.NewLogger("prometheus")
|
||||
|
||||
client, err := api.NewClient(cc.Config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p := NewPrometheus(log, client, cc.Query, cc.Timeout)
|
||||
|
||||
return p, err
|
||||
}
|
||||
|
||||
func NewPrometheus(log *util.Logger, client api.Client, query string, timeout time.Duration) *Prometheus {
|
||||
p := &Prometheus{
|
||||
log: log,
|
||||
clientV1Api: v1.NewAPI(client),
|
||||
query: query,
|
||||
timeout: timeout,
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *Prometheus) Query() (model.Value, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), p.timeout)
|
||||
defer cancel()
|
||||
res, warn, err := p.clientV1Api.Query(ctx, p.query, time.Now())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.log.TRACE.Printf("query %q: %+v", p.query, res)
|
||||
if len(warn) > 0 {
|
||||
p.log.WARN.Printf("query %q returned warnings: %v", p.query, warn)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
var _ FloatProvider = (*Prometheus)(nil)
|
||||
|
||||
// FloatGetter expects scalar value from query response as float
|
||||
func (p *Prometheus) FloatGetter() func() (float64, error) {
|
||||
return func() (float64, error) {
|
||||
res, err := p.Query()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if res.Type() != model.ValScalar {
|
||||
return 0, fmt.Errorf("query returned value of type %q, expected %q, consider wrapping query in scalar()", res.Type().String(), model.ValScalar.String())
|
||||
}
|
||||
scalarVal := res.(*model.Scalar)
|
||||
return float64(scalarVal.Value), nil
|
||||
}
|
||||
}
|
||||
|
||||
var _ IntProvider = (*Prometheus)(nil)
|
||||
|
||||
// IntGetter expects scalar value from query response as int
|
||||
func (p *Prometheus) IntGetter() func() (int64, error) {
|
||||
floatGetter := p.FloatGetter()
|
||||
return func() (int64, error) {
|
||||
float, err := floatGetter()
|
||||
return int64(math.Round(float)), err
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue