cmd/geth: export metrics to InfluxDB (#16979)

* cmd/geth: add flags for metrics export

* cmd/geth: update usage fields for metrics flags

* metrics/influxdb: update reporter logger to adhere to geth logging convention
This commit is contained in:
Anton Evangelatov 2018-07-02 14:51:02 +02:00 committed by Péter Szilágyi
parent 223d943481
commit 1990c9e621
4 changed files with 93 additions and 11 deletions

View File

@ -144,6 +144,15 @@ var (
utils.WhisperMaxMessageSizeFlag, utils.WhisperMaxMessageSizeFlag,
utils.WhisperMinPOWFlag, utils.WhisperMinPOWFlag,
} }
metricsFlags = []cli.Flag{
utils.MetricsEnableInfluxDBFlag,
utils.MetricsInfluxDBEndpointFlag,
utils.MetricsInfluxDBDatabaseFlag,
utils.MetricsInfluxDBUsernameFlag,
utils.MetricsInfluxDBPasswordFlag,
utils.MetricsInfluxDBHostTagFlag,
}
) )
func init() { func init() {
@ -186,6 +195,7 @@ func init() {
app.Flags = append(app.Flags, consoleFlags...) app.Flags = append(app.Flags, consoleFlags...)
app.Flags = append(app.Flags, debug.Flags...) app.Flags = append(app.Flags, debug.Flags...)
app.Flags = append(app.Flags, whisperFlags...) app.Flags = append(app.Flags, whisperFlags...)
app.Flags = append(app.Flags, metricsFlags...)
app.Before = func(ctx *cli.Context) error { app.Before = func(ctx *cli.Context) error {
runtime.GOMAXPROCS(runtime.NumCPU()) runtime.GOMAXPROCS(runtime.NumCPU())
@ -208,6 +218,9 @@ func init() {
log.Debug("Sanitizing Go's GC trigger", "percent", int(gogc)) log.Debug("Sanitizing Go's GC trigger", "percent", int(gogc))
godebug.SetGCPercent(int(gogc)) godebug.SetGCPercent(int(gogc))
// Start metrics export if enabled
utils.SetupMetrics(ctx)
// Start system runtime metrics collection // Start system runtime metrics collection
go metrics.CollectProcessMetrics(3 * time.Second) go metrics.CollectProcessMetrics(3 * time.Second)

View File

@ -206,11 +206,22 @@ var AppHelpFlagGroups = []flagGroup{
{ {
Name: "LOGGING AND DEBUGGING", Name: "LOGGING AND DEBUGGING",
Flags: append([]cli.Flag{ Flags: append([]cli.Flag{
utils.MetricsEnabledFlag,
utils.FakePoWFlag, utils.FakePoWFlag,
utils.NoCompactionFlag, utils.NoCompactionFlag,
}, debug.Flags...), }, debug.Flags...),
}, },
{
Name: "METRICS AND STATS",
Flags: []cli.Flag{
utils.MetricsEnabledFlag,
utils.MetricsEnableInfluxDBFlag,
utils.MetricsInfluxDBEndpointFlag,
utils.MetricsInfluxDBDatabaseFlag,
utils.MetricsInfluxDBUsernameFlag,
utils.MetricsInfluxDBPasswordFlag,
utils.MetricsInfluxDBHostTagFlag,
},
},
{ {
Name: "WHISPER (EXPERIMENTAL)", Name: "WHISPER (EXPERIMENTAL)",
Flags: whisperFlags, Flags: whisperFlags,

View File

@ -27,6 +27,7 @@ import (
"runtime" "runtime"
"strconv" "strconv"
"strings" "strings"
"time"
"github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/accounts/keystore"
@ -48,6 +49,7 @@ import (
"github.com/ethereum/go-ethereum/les" "github.com/ethereum/go-ethereum/les"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/metrics/influxdb"
"github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discover" "github.com/ethereum/go-ethereum/p2p/discover"
@ -360,10 +362,6 @@ var (
Name: "ethstats", Name: "ethstats",
Usage: "Reporting URL of a ethstats service (nodename:secret@host:port)", Usage: "Reporting URL of a ethstats service (nodename:secret@host:port)",
} }
MetricsEnabledFlag = cli.BoolFlag{
Name: metrics.MetricsEnabledFlag,
Usage: "Enable metrics collection and reporting",
}
FakePoWFlag = cli.BoolFlag{ FakePoWFlag = cli.BoolFlag{
Name: "fakepow", Name: "fakepow",
Usage: "Disables proof-of-work verification", Usage: "Disables proof-of-work verification",
@ -532,6 +530,45 @@ var (
Usage: "Minimum POW accepted", Usage: "Minimum POW accepted",
Value: whisper.DefaultMinimumPoW, Value: whisper.DefaultMinimumPoW,
} }
// Metrics flags
MetricsEnabledFlag = cli.BoolFlag{
Name: metrics.MetricsEnabledFlag,
Usage: "Enable metrics collection and reporting",
}
MetricsEnableInfluxDBFlag = cli.BoolFlag{
Name: "metrics.influxdb",
Usage: "Enable metrics export/push to an external InfluxDB database",
}
MetricsInfluxDBEndpointFlag = cli.StringFlag{
Name: "metrics.influxdb.endpoint",
Usage: "InfluxDB API endpoint to report metrics to",
Value: "http://localhost:8086",
}
MetricsInfluxDBDatabaseFlag = cli.StringFlag{
Name: "metrics.influxdb.database",
Usage: "InfluxDB database name to push reported metrics to",
Value: "geth",
}
MetricsInfluxDBUsernameFlag = cli.StringFlag{
Name: "metrics.influxdb.username",
Usage: "Username to authorize access to the database",
Value: "test",
}
MetricsInfluxDBPasswordFlag = cli.StringFlag{
Name: "metrics.influxdb.password",
Usage: "Password to authorize access to the database",
Value: "test",
}
// The `host` tag is part of every measurement sent to InfluxDB. Queries on tags are faster in InfluxDB.
// It is used so that we can group all nodes and average a measurement across all of them, but also so
// that we can select a specific node and inspect its measurements.
// https://docs.influxdata.com/influxdb/v1.4/concepts/key_concepts/#tag-key
MetricsInfluxDBHostTagFlag = cli.StringFlag{
Name: "metrics.influxdb.host.tag",
Usage: "InfluxDB `host` tag attached to all measurements",
Value: "localhost",
}
) )
// MakeDataDir retrieves the currently requested data directory, terminating // MakeDataDir retrieves the currently requested data directory, terminating
@ -1184,6 +1221,27 @@ func SetupNetwork(ctx *cli.Context) {
params.TargetGasLimit = ctx.GlobalUint64(TargetGasLimitFlag.Name) params.TargetGasLimit = ctx.GlobalUint64(TargetGasLimitFlag.Name)
} }
func SetupMetrics(ctx *cli.Context) {
if metrics.Enabled {
log.Info("Enabling metrics collection")
var (
enableExport = ctx.GlobalBool(MetricsEnableInfluxDBFlag.Name)
endpoint = ctx.GlobalString(MetricsInfluxDBEndpointFlag.Name)
database = ctx.GlobalString(MetricsInfluxDBDatabaseFlag.Name)
username = ctx.GlobalString(MetricsInfluxDBUsernameFlag.Name)
password = ctx.GlobalString(MetricsInfluxDBPasswordFlag.Name)
hosttag = ctx.GlobalString(MetricsInfluxDBHostTagFlag.Name)
)
if enableExport {
log.Info("Enabling metrics export to InfluxDB")
go influxdb.InfluxDBWithTags(metrics.DefaultRegistry, 10*time.Second, endpoint, database, username, password, "geth.", map[string]string{
"host": hosttag,
})
}
}
}
// MakeChainDatabase open an LevelDB using the flags passed to the client and will hard crash if it fails. // MakeChainDatabase open an LevelDB using the flags passed to the client and will hard crash if it fails.
func MakeChainDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database { func MakeChainDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database {
var ( var (

View File

@ -2,10 +2,10 @@ package influxdb
import ( import (
"fmt" "fmt"
"log"
uurl "net/url" uurl "net/url"
"time" "time"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/metrics"
"github.com/influxdata/influxdb/client" "github.com/influxdata/influxdb/client"
) )
@ -35,7 +35,7 @@ func InfluxDB(r metrics.Registry, d time.Duration, url, database, username, pass
func InfluxDBWithTags(r metrics.Registry, d time.Duration, url, database, username, password, namespace string, tags map[string]string) { func InfluxDBWithTags(r metrics.Registry, d time.Duration, url, database, username, password, namespace string, tags map[string]string) {
u, err := uurl.Parse(url) u, err := uurl.Parse(url)
if err != nil { if err != nil {
log.Printf("unable to parse InfluxDB url %s. err=%v", url, err) log.Warn("Unable to parse InfluxDB", "url", url, "err", err)
return return
} }
@ -51,7 +51,7 @@ func InfluxDBWithTags(r metrics.Registry, d time.Duration, url, database, userna
cache: make(map[string]int64), cache: make(map[string]int64),
} }
if err := rep.makeClient(); err != nil { if err := rep.makeClient(); err != nil {
log.Printf("unable to make InfluxDB client. err=%v", err) log.Warn("Unable to make InfluxDB client", "err", err)
return return
} }
@ -76,15 +76,15 @@ func (r *reporter) run() {
select { select {
case <-intervalTicker: case <-intervalTicker:
if err := r.send(); err != nil { if err := r.send(); err != nil {
log.Printf("unable to send to InfluxDB. err=%v", err) log.Warn("Unable to send to InfluxDB", "err", err)
} }
case <-pingTicker: case <-pingTicker:
_, _, err := r.client.Ping() _, _, err := r.client.Ping()
if err != nil { if err != nil {
log.Printf("got error while sending a ping to InfluxDB, trying to recreate client. err=%v", err) log.Warn("Got error while sending a ping to InfluxDB, trying to recreate client", "err", err)
if err = r.makeClient(); err != nil { if err = r.makeClient(); err != nil {
log.Printf("unable to make InfluxDB client. err=%v", err) log.Warn("Unable to make InfluxDB client", "err", err)
} }
} }
} }