163 lines
3.4 KiB
Go
163 lines
3.4 KiB
Go
|
|
package mock
|
||
|
|
|
||
|
|
import (
|
||
|
|
"math"
|
||
|
|
"math/rand"
|
||
|
|
"time"
|
||
|
|
|
||
|
|
"github.com/influxdata/telegraf"
|
||
|
|
"github.com/influxdata/telegraf/plugins/inputs"
|
||
|
|
)
|
||
|
|
|
||
|
|
type Mock struct {
|
||
|
|
counter int64
|
||
|
|
|
||
|
|
MetricName string `toml:"metric_name"`
|
||
|
|
Tags map[string]string `toml:"tags"`
|
||
|
|
|
||
|
|
Random []*random `toml:"random"`
|
||
|
|
Step []*step `toml:"step"`
|
||
|
|
Stock []*stock `toml:"stock"`
|
||
|
|
SineWave []*sineWave `toml:"sine_wave"`
|
||
|
|
}
|
||
|
|
|
||
|
|
type random struct {
|
||
|
|
Name string `toml:"name"`
|
||
|
|
Min float64 `toml:"min"`
|
||
|
|
Max float64 `toml:"max"`
|
||
|
|
}
|
||
|
|
|
||
|
|
type sineWave struct {
|
||
|
|
Name string `toml:"name"`
|
||
|
|
Amplitude float64 `toml:"amplitude"`
|
||
|
|
Period float64 `toml:"period"`
|
||
|
|
}
|
||
|
|
|
||
|
|
type step struct {
|
||
|
|
latest float64
|
||
|
|
|
||
|
|
Name string `toml:"name"`
|
||
|
|
Start float64 `toml:"min"`
|
||
|
|
Step float64 `toml:"max"`
|
||
|
|
}
|
||
|
|
|
||
|
|
type stock struct {
|
||
|
|
latest float64
|
||
|
|
|
||
|
|
Name string `toml:"name"`
|
||
|
|
Price float64 `toml:"price"`
|
||
|
|
Volatility float64 `toml:"volatility"`
|
||
|
|
}
|
||
|
|
|
||
|
|
const sampleConfig = `
|
||
|
|
## Set the metric name to use for reporting
|
||
|
|
metric_name = "mock"
|
||
|
|
|
||
|
|
## Optional string key-value pairs of tags to add to all metrics
|
||
|
|
# [inputs.mock.tags]
|
||
|
|
# "key" = "value"
|
||
|
|
|
||
|
|
## One or more mock data fields *must* be defined.
|
||
|
|
##
|
||
|
|
## [[inputs.mock.random]]
|
||
|
|
## name = "rand"
|
||
|
|
## min = 1.0
|
||
|
|
## max = 6.0
|
||
|
|
## [[inputs.mock.sine_wave]]
|
||
|
|
## name = "wave"
|
||
|
|
## amplitude = 1.0
|
||
|
|
## period = 0.5
|
||
|
|
## [[inputs.mock.step]]
|
||
|
|
## name = "plus_one"
|
||
|
|
## start = 0.0
|
||
|
|
## step = 1.0
|
||
|
|
## [[inputs.mock.stock]]
|
||
|
|
## name = "abc"
|
||
|
|
## price = 50.00
|
||
|
|
## volatility = 0.2
|
||
|
|
`
|
||
|
|
|
||
|
|
func (m *Mock) SampleConfig() string {
|
||
|
|
return sampleConfig
|
||
|
|
}
|
||
|
|
|
||
|
|
func (m *Mock) Description() string {
|
||
|
|
return "Generate metrics for test and demonstration purposes"
|
||
|
|
}
|
||
|
|
|
||
|
|
func (m *Mock) Init() error {
|
||
|
|
rand.Seed(time.Now().UnixNano())
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (m *Mock) Gather(acc telegraf.Accumulator) error {
|
||
|
|
fields := make(map[string]interface{})
|
||
|
|
m.generateRandomFloat64(fields)
|
||
|
|
m.generateStockPrice(fields)
|
||
|
|
m.generateSineWave(fields)
|
||
|
|
m.generateStep(fields)
|
||
|
|
|
||
|
|
tags := make(map[string]string)
|
||
|
|
for key, value := range m.Tags {
|
||
|
|
tags[key] = value
|
||
|
|
}
|
||
|
|
|
||
|
|
acc.AddFields(m.MetricName, fields, tags)
|
||
|
|
|
||
|
|
m.counter++
|
||
|
|
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// Generate random value between min and max, inclusivly
|
||
|
|
func (m *Mock) generateRandomFloat64(fields map[string]interface{}) {
|
||
|
|
for _, random := range m.Random {
|
||
|
|
fields[random.Name] = random.Min + rand.Float64()*(random.Max-random.Min)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Create sine waves
|
||
|
|
func (m *Mock) generateSineWave(fields map[string]interface{}) {
|
||
|
|
for _, field := range m.SineWave {
|
||
|
|
fields[field.Name] = math.Sin((float64(m.counter) * field.Period * math.Pi)) * field.Amplitude
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Begin at start value and then add step value every tick
|
||
|
|
func (m *Mock) generateStep(fields map[string]interface{}) {
|
||
|
|
for _, step := range m.Step {
|
||
|
|
if m.counter == 0 {
|
||
|
|
step.latest = step.Start
|
||
|
|
} else {
|
||
|
|
step.latest += step.Step
|
||
|
|
}
|
||
|
|
|
||
|
|
fields[step.Name] = step.latest
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Begin at start price and then generate random value
|
||
|
|
func (m *Mock) generateStockPrice(fields map[string]interface{}) {
|
||
|
|
for _, stock := range m.Stock {
|
||
|
|
if stock.latest == 0.0 {
|
||
|
|
stock.latest = stock.Price
|
||
|
|
} else {
|
||
|
|
noise := 2 * (rand.Float64() - 0.5)
|
||
|
|
stock.latest = stock.latest + (stock.latest * stock.Volatility * noise)
|
||
|
|
|
||
|
|
// avoid going below zero
|
||
|
|
if stock.latest < 1.0 {
|
||
|
|
stock.latest = 1.0
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
fields[stock.Name] = stock.latest
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func init() {
|
||
|
|
inputs.Add("mock", func() telegraf.Input {
|
||
|
|
return &Mock{}
|
||
|
|
})
|
||
|
|
}
|