Add optional Prometheus exporter to telegraf.

This will allow Telegraf plugins to be useful with Prometheus.
This is disabled by default.
This commit is contained in:
Brian Brazil 2015-06-20 15:00:49 +01:00
parent 05924b9d09
commit 45d9aec62e
3 changed files with 100 additions and 3 deletions

View File

@ -5,18 +5,21 @@ import (
"log" "log"
"net/url" "net/url"
"os" "os"
"regexp"
"sort" "sort"
"sync" "sync"
"time" "time"
"github.com/influxdb/influxdb/client" "github.com/influxdb/influxdb/client"
"github.com/influxdb/telegraf/plugins" "github.com/influxdb/telegraf/plugins"
"github.com/prometheus/client_golang/prometheus"
) )
type runningPlugin struct { type runningPlugin struct {
name string name string
plugin plugins.Plugin plugin plugins.Plugin
config *ConfiguredPlugin config *ConfiguredPlugin
mu sync.Mutex
} }
type Agent struct { type Agent struct {
@ -53,6 +56,7 @@ func NewAgent(config *Config) (*Agent, error) {
} }
config.Tags["host"] = agent.Hostname config.Tags["host"] = agent.Hostname
prometheus.MustRegister(agent)
return agent, nil return agent, nil
} }
@ -97,7 +101,7 @@ func (a *Agent) LoadPlugins() ([]string, error) {
return nil, err return nil, err
} }
a.plugins = append(a.plugins, &runningPlugin{name, plugin, config}) a.plugins = append(a.plugins, &runningPlugin{name, plugin, config, sync.Mutex{}})
names = append(names, name) names = append(names, name)
} }
@ -125,7 +129,9 @@ func (a *Agent) crankParallel() error {
acc.Prefix = plugin.name + "_" acc.Prefix = plugin.name + "_"
acc.Config = plugin.config acc.Config = plugin.config
plugin.mu.Lock()
plugin.plugin.Gather(&acc) plugin.plugin.Gather(&acc)
plugin.mu.Unlock()
points <- &acc points <- &acc
}(plugin) }(plugin)
@ -156,7 +162,9 @@ func (a *Agent) crank() error {
for _, plugin := range a.plugins { for _, plugin := range a.plugins {
acc.Prefix = plugin.name + "_" acc.Prefix = plugin.name + "_"
acc.Config = plugin.config acc.Config = plugin.config
plugin.mu.Lock()
err := plugin.plugin.Gather(&acc) err := plugin.plugin.Gather(&acc)
plugin.mu.Unlock()
if err != nil { if err != nil {
return err return err
} }
@ -180,7 +188,9 @@ func (a *Agent) crankSeparate(shutdown chan struct{}, plugin *runningPlugin) err
acc.Prefix = plugin.name + "_" acc.Prefix = plugin.name + "_"
acc.Config = plugin.config acc.Config = plugin.config
plugin.mu.Lock()
err := plugin.plugin.Gather(&acc) err := plugin.plugin.Gather(&acc)
plugin.mu.Unlock()
if err != nil { if err != nil {
return err return err
} }
@ -200,6 +210,56 @@ func (a *Agent) crankSeparate(shutdown chan struct{}, plugin *runningPlugin) err
} }
} }
// Implements prometheus.Collector
func (a *Agent) Describe(ch chan<- *prometheus.Desc) {
prometheus.NewGauge(prometheus.GaugeOpts{Name: "Dummy", Help: "Dummy"}).Describe(ch)
}
// Implements prometheus.Collector
func (a *Agent) Collect(ch chan<- prometheus.Metric) {
var wg sync.WaitGroup
invalidNameCharRE := regexp.MustCompile(`[^a-zA-Z0-9_]`)
for _, plugin := range a.plugins {
wg.Add(1)
go func(plugin *runningPlugin) {
defer wg.Done()
var acc BatchPoints
acc.Prefix = plugin.name + "_"
plugin.mu.Lock()
err := plugin.plugin.Gather(&acc)
plugin.mu.Unlock()
if err != nil {
return
}
for _, point := range acc.Points {
var value float64
switch point.Fields["value"].(type) {
case float64, int64:
value = point.Fields["value"].(float64)
default:
continue
}
tags := map[string]string{}
for k, v := range point.Tags {
tags[invalidNameCharRE.ReplaceAllString(k, "_")] = v
}
desc := prometheus.NewDesc(invalidNameCharRE.ReplaceAllString(point.Measurement, "_"), point.Measurement, nil, tags)
metric, err := prometheus.NewConstMetric(desc, prometheus.UntypedValue, value)
if err == nil {
ch <- metric
}
}
}(plugin)
}
wg.Wait()
}
func (a *Agent) TestAllPlugins() error { func (a *Agent) TestAllPlugins() error {
var names []string var names []string

View File

@ -4,12 +4,14 @@ import (
"flag" "flag"
"fmt" "fmt"
"log" "log"
"net/http"
"os" "os"
"os/signal" "os/signal"
"strings" "strings"
"github.com/influxdb/telegraf" "github.com/influxdb/telegraf"
_ "github.com/influxdb/telegraf/plugins/all" _ "github.com/influxdb/telegraf/plugins/all"
"github.com/prometheus/client_golang/prometheus"
) )
var fDebug = flag.Bool("debug", false, "show metrics as they're generated to stdout") var fDebug = flag.Bool("debug", false, "show metrics as they're generated to stdout")
@ -117,5 +119,21 @@ func main() {
f.Close() f.Close()
} }
pc := &telegraf.PrometheusCollector{ListenAddress: ""}
err = config.ApplyPrometheusCollector(pc)
if err != nil {
log.Fatal(err)
}
if pc.ListenAddress != "" {
http.Handle("/metrics", prometheus.Handler())
log.Printf("Listening on %s for Prometheus", pc.ListenAddress)
go func() {
err := http.ListenAndServe(pc.ListenAddress, nil)
if err != nil {
log.Fatal(err)
}
}()
}
ag.Run(shutdown) ag.Run(shutdown)
} }

View File

@ -36,8 +36,13 @@ type Config struct {
UserAgent string UserAgent string
Tags map[string]string Tags map[string]string
agent *ast.Table agent *ast.Table
plugins map[string]*ast.Table plugins map[string]*ast.Table
prometheusCollector *ast.Table
}
type PrometheusCollector struct {
ListenAddress string
} }
func (c *Config) Plugins() map[string]*ast.Table { func (c *Config) Plugins() map[string]*ast.Table {
@ -85,6 +90,14 @@ func (c *Config) ApplyAgent(v interface{}) error {
return nil return nil
} }
func (c *Config) ApplyPrometheusCollector(v interface{}) error {
if c.prometheusCollector != nil {
return toml.UnmarshalTable(c.prometheusCollector, v)
}
return nil
}
func (c *Config) ApplyPlugin(name string, v interface{}) (*ConfiguredPlugin, error) { func (c *Config) ApplyPlugin(name string, v interface{}) (*ConfiguredPlugin, error) {
cp := &ConfiguredPlugin{Name: name} cp := &ConfiguredPlugin{Name: name}
@ -183,6 +196,8 @@ func LoadConfig(path string) (*Config, error) {
} }
case "agent": case "agent":
c.agent = subtbl c.agent = subtbl
case "prometheus_collector":
c.prometheusCollector = subtbl
default: default:
c.plugins[name] = subtbl c.plugins[name] = subtbl
} }
@ -261,6 +276,10 @@ database = "telegraf" # required.
# debug = false # debug = false
# hostname = "prod3241" # hostname = "prod3241"
[prometheus_collector]
# If set, expose all metrics on this address for Prometheus
# listen_address = ":9115"
# PLUGINS # PLUGINS
` `