Add ability to generate config from available plugins

This commit is contained in:
Evan Phoenix 2015-05-18 15:10:11 -07:00
parent b2c5d95737
commit 82cbc4daa2
7 changed files with 195 additions and 23 deletions

View File

@ -16,6 +16,7 @@ var fDebug = flag.Bool("debug", false, "show metrics as they're generated to std
var fTest = flag.Bool("test", false, "gather metrics, print them out, and exit") var fTest = flag.Bool("test", false, "gather metrics, print them out, and exit")
var fConfig = flag.String("config", "", "configuration file to load") var fConfig = flag.String("config", "", "configuration file to load")
var fVersion = flag.Bool("version", false, "display the version") var fVersion = flag.Bool("version", false, "display the version")
var fSampleConfig = flag.Bool("sample-config", false, "print out full sample configuration")
var Version = "unreleased" var Version = "unreleased"
@ -27,6 +28,11 @@ func main() {
return return
} }
if *fSampleConfig {
tivan.PrintSampleConfig()
return
}
var ( var (
config *tivan.Config config *tivan.Config
err error err error

View File

@ -8,6 +8,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/influxdb/tivan/plugins"
"github.com/naoina/toml" "github.com/naoina/toml"
"github.com/naoina/toml/ast" "github.com/naoina/toml/ast"
) )
@ -113,3 +114,74 @@ func (c *Config) ListTags() string {
return strings.Join(tags, " ") return strings.Join(tags, " ")
} }
type hasConfig interface {
BasicConfig() string
}
type hasDescr interface {
Description() string
}
var header = `# Tivan configuration
# Tivan is entirely plugin driven. All metrics are gathered from the
# declared plugins.
# Even if a plugin has no configuration, it must be declared in here
# to be active. Declaring a plugin means just specifying the name
# as a section with no variables.
# Configuration for influxdb server to send metrics to
# [influxdb]
# url = "http://10.20.2.4"
# username = "tivan"
# password = "metricsmetricsmetricsmetrics"
# database = "tivan"
# user_agent = "tivan"
# tags = { "dc": "us-east-1" }
# Tags can also be specified via a normal map, but only one form at a time:
# [influxdb.tags]
# dc = "us-east-1"
# PLUGINS
`
func PrintSampleConfig() {
fmt.Printf(header)
var names []string
for name, _ := range plugins.Plugins {
names = append(names, name)
}
sort.Strings(names)
for _, name := range names {
creator := plugins.Plugins[name]
plugin := creator()
fmt.Printf("# %s\n[%s]\n", plugin.Description(), name)
var config string
config = strings.TrimSpace(plugin.SampleConfig())
if config == "" {
fmt.Printf(" # no configuration\n\n")
} else {
fmt.Printf("\n")
lines := strings.Split(config, "\n")
for _, line := range lines {
fmt.Printf("%s\n", line)
}
fmt.Printf("\n")
}
}
}

View File

@ -14,17 +14,27 @@ type Server struct {
} }
type Mysql struct { type Mysql struct {
Disabled bool Servers []*Server
Servers []*Server }
var sampleConfig = `
# specify servers via a url matching:
# [username[:password]@][protocol[(address)]]/[?tls=[true|false|skip-verify]]
#
# If no servers are specified, then localhost is used as the host.
servers = ["localhost"]`
func (m *Mysql) SampleConfig() string {
return sampleConfig
}
func (m *Mysql) Description() string {
return "Read metrics from one or many mysql servers"
} }
var localhost = &Server{} var localhost = &Server{}
func (m *Mysql) Gather(acc plugins.Accumulator) error { func (m *Mysql) Gather(acc plugins.Accumulator) error {
if m.Disabled {
return nil
}
if len(m.Servers) == 0 { if len(m.Servers) == 0 {
// if we can't get stats in this case, thats fine, don't report // if we can't get stats in this case, thats fine, don't report
// an error. // an error.

View File

@ -17,6 +17,39 @@ type Postgresql struct {
Servers []*Server Servers []*Server
} }
var sampleConfig = `
# specify servers via an array of tables
[[postgresql.servers]]
# specify address via a url matching:
# postgres://[pqgotest[:password]]@localhost?sslmode=[disable|verify-ca|verify-full]
# or a simple string:
# host=localhost user=pqotest password=... sslmode=...
#
# All connection parameters are optional. By default, the host is localhost
# and the user is the currently running user. For localhost, we default
# to sslmode=disable as well.
#
address = "localhost"
# A list of databases to pull metrics about. If not specified, metrics for all
# databases are gathered.
# databases = ["app_production", "blah_testing"]
# [[postgresql.servers]]
# address = "influx@remoteserver"
`
func (p *Postgresql) SampleConfig() string {
return sampleConfig
}
func (p *Postgresql) Description() string {
return "Read metrics from one or many postgresql servers"
}
var localhost = &Server{Address: "sslmode=disable"} var localhost = &Server{Address: "sslmode=disable"}
func (p *Postgresql) Gather(acc plugins.Accumulator) error { func (p *Postgresql) Gather(acc plugins.Accumulator) error {

View File

@ -13,14 +13,27 @@ import (
) )
type Redis struct { type Redis struct {
Disabled bool Servers []string
Address string
Servers []string
c net.Conn c net.Conn
buf []byte buf []byte
} }
var sampleConfig = `
# An array of address to gather stats about. Specify an ip on hostname
# with optional port. ie localhost, 10.10.3.33:18832, etc.
#
# If no servers are specified, then localhost is used as the host.
servers = ["localhost"]`
func (r *Redis) SampleConfig() string {
return sampleConfig
}
func (r *Redis) Description() string {
return "Read metrics from one or many redis servers"
}
var Tracking = map[string]string{ var Tracking = map[string]string{
"uptime_in_seconds": "uptime", "uptime_in_seconds": "uptime",
"connected_clients": "clients", "connected_clients": "clients",
@ -59,19 +72,7 @@ var ErrProtocolError = errors.New("redis protocol error")
// Reads stats from all configured servers accumulates stats. // Reads stats from all configured servers accumulates stats.
// Returns one of the errors encountered while gather stats (if any). // Returns one of the errors encountered while gather stats (if any).
func (g *Redis) Gather(acc plugins.Accumulator) error { func (g *Redis) Gather(acc plugins.Accumulator) error {
if g.Disabled { if len(g.Servers) == 0 {
return nil
}
var servers []string
if g.Address != "" {
servers = append(servers, g.Address)
}
servers = append(servers, g.Servers...)
if len(servers) == 0 {
g.gatherServer(":6379", acc) g.gatherServer(":6379", acc)
return nil return nil
} }
@ -80,7 +81,7 @@ func (g *Redis) Gather(acc plugins.Accumulator) error {
var outerr error var outerr error
for _, serv := range servers { for _, serv := range g.Servers {
wg.Add(1) wg.Add(1)
go func(serv string) { go func(serv string) {
defer wg.Done() defer wg.Done()

View File

@ -5,6 +5,8 @@ type Accumulator interface {
} }
type Plugin interface { type Plugin interface {
SampleConfig() string
Description() string
Gather(Accumulator) error Gather(Accumulator) error
} }

View File

@ -46,6 +46,12 @@ type CPUStats struct {
ps PS ps PS
} }
func (_ *CPUStats) Description() string {
return "Read metrics about cpu usage"
}
func (_ *CPUStats) SampleConfig() string { return "" }
func (s *CPUStats) Gather(acc plugins.Accumulator) error { func (s *CPUStats) Gather(acc plugins.Accumulator) error {
times, err := s.ps.CPUTimes() times, err := s.ps.CPUTimes()
if err != nil { if err != nil {
@ -77,6 +83,12 @@ type DiskStats struct {
ps PS ps PS
} }
func (_ *DiskStats) Description() string {
return "Read metrics about disk usage by mount point"
}
func (_ *DiskStats) SampleConfig() string { return "" }
func (s *DiskStats) Gather(acc plugins.Accumulator) error { func (s *DiskStats) Gather(acc plugins.Accumulator) error {
disks, err := s.ps.DiskUsage() disks, err := s.ps.DiskUsage()
if err != nil { if err != nil {
@ -103,6 +115,12 @@ type DiskIOStats struct {
ps PS ps PS
} }
func (_ *DiskIOStats) Description() string {
return "Read metrics about disk IO by device"
}
func (_ *DiskIOStats) SampleConfig() string { return "" }
func (s *DiskIOStats) Gather(acc plugins.Accumulator) error { func (s *DiskIOStats) Gather(acc plugins.Accumulator) error {
diskio, err := s.ps.DiskIO() diskio, err := s.ps.DiskIO()
if err != nil { if err != nil {
@ -131,6 +149,12 @@ type NetIOStats struct {
ps PS ps PS
} }
func (_ *NetIOStats) Description() string {
return "Read metrics about network interface usage"
}
func (_ *NetIOStats) SampleConfig() string { return "" }
func (s *NetIOStats) Gather(acc plugins.Accumulator) error { func (s *NetIOStats) Gather(acc plugins.Accumulator) error {
netio, err := s.ps.NetIO() netio, err := s.ps.NetIO()
if err != nil { if err != nil {
@ -159,6 +183,12 @@ type MemStats struct {
ps PS ps PS
} }
func (_ *MemStats) Description() string {
return "Read metrics about memory usage"
}
func (_ *MemStats) SampleConfig() string { return "" }
func (s *MemStats) Gather(acc plugins.Accumulator) error { func (s *MemStats) Gather(acc plugins.Accumulator) error {
vm, err := s.ps.VMStat() vm, err := s.ps.VMStat()
if err != nil { if err != nil {
@ -186,6 +216,12 @@ type SwapStats struct {
ps PS ps PS
} }
func (_ *SwapStats) Description() string {
return "Read metrics about swap memory usage"
}
func (_ *SwapStats) SampleConfig() string { return "" }
func (s *SwapStats) Gather(acc plugins.Accumulator) error { func (s *SwapStats) Gather(acc plugins.Accumulator) error {
swap, err := s.ps.SwapStat() swap, err := s.ps.SwapStat()
if err != nil { if err != nil {
@ -208,6 +244,12 @@ type DockerStats struct {
ps PS ps PS
} }
func (_ *DockerStats) Description() string {
return "Read metrics about docker containers"
}
func (_ *DockerStats) SampleConfig() string { return "" }
func (s *DockerStats) Gather(acc plugins.Accumulator) error { func (s *DockerStats) Gather(acc plugins.Accumulator) error {
containers, err := s.ps.DockerStat() containers, err := s.ps.DockerStat()
if err != nil { if err != nil {
@ -271,6 +313,12 @@ type SystemStats struct {
ps PS ps PS
} }
func (_ *SystemStats) Description() string {
return "Read metrics about system load"
}
func (_ *SystemStats) SampleConfig() string { return "" }
func (s *SystemStats) add(acc plugins.Accumulator, func (s *SystemStats) add(acc plugins.Accumulator,
name string, val float64, tags map[string]string) { name string, val float64, tags map[string]string) {
if val >= 0 { if val >= 0 {