add a demo plugin for prober (#586)

* add a demo plugin for prober

* update demo plugin
This commit is contained in:
yubo 2021-02-23 11:41:38 +08:00 committed by GitHub
parent 322cbf27dc
commit b055bc73c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 248 additions and 55 deletions

View File

@ -4,15 +4,15 @@ import (
// remote
// _ "github.com/didi/nightingale/src/modules/monapi/plugins/api"
// telegraf style
_ "github.com/didi/nightingale/src/modules/monapi/plugins/elasticsearch"
_ "github.com/didi/nightingale/src/modules/monapi/plugins/github"
_ "github.com/didi/nightingale/src/modules/monapi/plugins/haproxy"
_ "github.com/didi/nightingale/src/modules/monapi/plugins/mongodb"
_ "github.com/didi/nightingale/src/modules/monapi/plugins/mysql"
_ "github.com/didi/nightingale/src/modules/monapi/plugins/prometheus"
_ "github.com/didi/nightingale/src/modules/monapi/plugins/redis"
_ "github.com/didi/nightingale/src/modules/monapi/plugins/nginx"
_ "github.com/didi/nightingale/src/modules/monapi/plugins/elasticsearch"
_ "github.com/didi/nightingale/src/modules/monapi/plugins/prometheus"
_ "github.com/didi/nightingale/src/modules/monapi/plugins/rabbitmq"
_ "github.com/didi/nightingale/src/modules/monapi/plugins/haproxy"
_ "github.com/didi/nightingale/src/modules/monapi/plugins/redis"
_ "github.com/didi/nightingale/src/modules/monapi/plugins/tengine"
_ "github.com/didi/nightingale/src/modules/monapi/plugins/zookeeper"

View File

@ -0,0 +1,62 @@
package demo
import (
"github.com/didi/nightingale/src/modules/monapi/collector"
"github.com/didi/nightingale/src/modules/monapi/plugins/demo/demo"
"github.com/didi/nightingale/src/toolkits/i18n"
"github.com/influxdata/telegraf"
)
func init() {
collector.CollectorRegister(NewDemoCollector()) // for monapi
i18n.DictRegister(langDict)
}
type DemoCollector struct {
*collector.BaseCollector
}
func NewDemoCollector() *DemoCollector {
return &DemoCollector{BaseCollector: collector.NewBaseCollector(
"demo",
collector.RemoteCategory,
func() collector.TelegrafPlugin { return &DemoRule{} },
)}
}
var (
langDict = map[string]map[string]string{
"zh": map[string]string{
"Period": "周期",
"The period of the function, in seconds": "函数周期,单位 秒",
"Count": "数量",
"The Count of the series": "指标数量",
},
}
)
type DemoRule struct {
Period int `label:"Period" json:"period,required" description:"The period of the function, in seconds" default:"3600"`
Count int `label:"Count" json:"count,required" enum:"[1, 2, 4, 8, 16]" description:"The Count of the series" default:"8"`
}
func (p *DemoRule) Validate() error {
if p.Period == 0 {
p.Period = 3600
}
if p.Count == 0 {
p.Period = 8
}
return nil
}
func (p *DemoRule) TelegrafInput() (telegraf.Input, error) {
if err := p.Validate(); err != nil {
return nil, err
}
return &demo.Demo{
Period: p.Period,
Count: p.Count,
}, nil
}

View File

@ -0,0 +1,63 @@
package demo
import (
"math"
"strconv"
"time"
"github.com/influxdata/telegraf"
)
type Demo struct {
Period int `toml:"period"`
Count int `toml:"count"`
initDone bool
cos *cos
}
func (d *Demo) SampleConfig() string {
return `
## The period of the function, in seconds
period = 600
## The Count of the series
count = 3
`
}
func (d *Demo) Description() string {
return "telegraf demo plugin"
}
func (d *Demo) Init() {
d.cos = &cos{
period: float64(d.Period),
offset: (d.Period / d.Count),
}
d.initDone = true
}
func (d *Demo) Gather(acc telegraf.Accumulator) error {
if !d.initDone {
d.Init()
}
fields := make(map[string]interface{})
tags := map[string]string{}
for i := 0; i < d.Count; i++ {
tags["n"] = strconv.Itoa(i)
fields["value"] = d.cos.value(i)
acc.AddFields("demo", fields, tags)
}
return nil
}
type cos struct {
period float64
offset int
}
func (c *cos) value(i int) float64 {
return math.Cos(2 * math.Pi * (float64(time.Now().Unix()+int64(c.offset*i)) / c.period))
}

View File

@ -0,0 +1,14 @@
package demo
import (
"testing"
"github.com/didi/nightingale/src/modules/monapi/plugins"
)
func TestCollect(t *testing.T) {
plugins.PluginTest(t, &DemoRule{
Period: 3600,
Count: 10,
})
}

View File

@ -6,9 +6,7 @@ import (
"net/http/httptest"
"testing"
"github.com/didi/nightingale/src/common/dataobj"
"github.com/didi/nightingale/src/modules/prober/manager"
"github.com/influxdata/telegraf"
"github.com/didi/nightingale/src/modules/monapi/plugins"
)
const sampleTextFormat = `# HELP test_metric An untyped metric with a timestamp
@ -50,39 +48,7 @@ func TestCollect(t *testing.T) {
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, sampleTextFormat) }))
defer s.Close()
PluginTest(t, &PrometheusRule{
plugins.PluginTest(t, &PrometheusRule{
URLs: []string{s.URL},
})
}
type telegrafPlugin interface {
TelegrafInput() (telegraf.Input, error)
}
func PluginTest(t *testing.T, plugin telegrafPlugin) telegraf.Input {
input, err := plugin.TelegrafInput()
if err != nil {
t.Error(err)
}
PluginInputTest(t, input)
return input
}
func PluginInputTest(t *testing.T, input telegraf.Input) {
metrics := []*dataobj.MetricValue{}
acc, err := manager.NewAccumulator(manager.AccumulatorOptions{Name: "plugin-test", Metrics: &metrics})
if err != nil {
t.Error(err)
}
if err = input.Gather(acc); err != nil {
t.Error(err)
}
for k, v := range metrics {
t.Logf("%d %s %s %f", k, v.CounterType, v.PK(), v.Value)
}
}

View File

@ -3,7 +3,11 @@ package plugins
import (
"fmt"
"reflect"
"testing"
"github.com/didi/nightingale/src/common/dataobj"
"github.com/didi/nightingale/src/modules/prober/manager"
"github.com/influxdata/telegraf"
"github.com/toolkits/pkg/logger"
)
@ -60,3 +64,35 @@ func SetValue(in interface{}, value interface{}, fields ...string) error {
rv.Set(reflect.Indirect(reflect.ValueOf(value)))
return nil
}
type telegrafPlugin interface {
TelegrafInput() (telegraf.Input, error)
}
func PluginTest(t *testing.T, plugin telegrafPlugin) telegraf.Input {
input, err := plugin.TelegrafInput()
if err != nil {
t.Error(err)
}
PluginInputTest(t, input)
return input
}
func PluginInputTest(t *testing.T, input telegraf.Input) {
metrics := []*dataobj.MetricValue{}
acc, err := manager.NewAccumulator(manager.AccumulatorOptions{Name: "plugin-test", Metrics: &metrics})
if err != nil {
t.Error(err)
}
if err = input.Gather(acc); err != nil {
t.Error(err)
}
for k, v := range metrics {
t.Logf("%d %s %s %f", k, v.CounterType, v.PK(), v.Value)
}
}

View File

@ -5,20 +5,39 @@ import (
"fmt"
"net/http"
"net/http/httptest"
"reflect"
"testing"
"time"
"github.com/didi/nightingale/src/models"
"github.com/didi/nightingale/src/modules/monapi/plugins/prometheus"
"github.com/didi/nightingale/src/modules/monapi/collector"
"github.com/didi/nightingale/src/modules/prober/config"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/inputs/prometheus"
)
const sampleTextFormat = `
# HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge
go_goroutines 15 1490802350000
# HELP test_guage guage
# TYPE test_guage gauge
test_guauge{label="1"} 1.1
test_guauge{label="2"} 1.2
test_guauge{label="3"} 1.3
`
func TestManager(t *testing.T) {
collector.CollectorRegister(&fakeCollector{BaseCollector: collector.NewBaseCollector(
"fake",
collector.RemoteCategory,
func() collector.TelegrafPlugin { return &fakeRule{} },
)})
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, sampleTextFormat) }))
defer s.Close()
promRule := prometheus.PrometheusRule{URLs: []string{s.URL}}
b, err := json.Marshal(promRule)
b, err := json.Marshal(fakeRule{URLs: []string{s.URL}})
if err != nil {
t.Fatal(err)
}
@ -28,7 +47,7 @@ func TestManager(t *testing.T) {
Nid: 2,
Step: 3,
Timeout: 4,
CollectType: "prometheus",
CollectType: "fake",
Name: "prom-test",
Region: "default",
Data: json.RawMessage(b),
@ -54,13 +73,46 @@ func TestManager(t *testing.T) {
}
}
const sampleTextFormat = `
# HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge
go_goroutines 15 1490802350000
# HELP test_guage guage
# TYPE test_guage gauge
test_guauge{label="1"} 1.1
test_guauge{label="2"} 1.2
test_guauge{label="3"} 1.3
`
type fakeCollector struct {
*collector.BaseCollector
}
type fakeRule struct {
URLs []string `label:"URLs" json:"urls,required" description:"An array of urls to scrape metrics from" example:"http://my-service-exporter:8080/metrics"`
ResponseTimeout int `label:"RESP Timeout" json:"response_timeout" default:"3" description:"Specify timeout duration for slower prometheus clients"`
}
func (p *fakeRule) Validate() error {
if len(p.URLs) == 0 || p.URLs[0] == "" {
return fmt.Errorf(" prometheus.rule unable to get urls")
}
return nil
}
func (p *fakeRule) TelegrafInput() (telegraf.Input, error) {
if err := p.Validate(); err != nil {
return nil, err
}
input := &prometheus.Prometheus{
URLs: p.URLs,
URLTag: "target",
MetricVersion: 2,
}
if err := setValue(&input.ResponseTimeout.Duration,
time.Second*time.Duration(p.ResponseTimeout)); err != nil {
return nil, err
}
return input, nil
}
func setValue(in interface{}, value interface{}) error {
rv := reflect.Indirect(reflect.ValueOf(in))
if !rv.IsValid() || !rv.CanSet() {
return fmt.Errorf("invalid argument IsValid %v CanSet %v", rv.IsValid(), rv.CanSet())
}
rv.Set(reflect.Indirect(reflect.ValueOf(value)))
return nil
}