From 01fe97211354d13ecaba8a52c82b808b7a7e8393 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 29 Jun 2015 16:11:01 +0300 Subject: [PATCH] cmd, core, eth, metrics, p2p: require enabling metrics --- cmd/geth/main.go | 1 + cmd/geth/monitorcmd.go | 7 +++++- cmd/utils/flags.go | 6 +++++ core/chain_manager.go | 3 ++- eth/backend.go | 51 +++++++++++++++++++++--------------------- eth/fetcher/fetcher.go | 30 ++++++------------------- eth/fetcher/metrics.go | 16 +++++++++++++ metrics/metrics.go | 42 ++++++++++++++++++++++++++++++++++ p2p/metrics.go | 10 ++++----- 9 files changed, 111 insertions(+), 55 deletions(-) create mode 100644 eth/fetcher/metrics.go diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 6a52159eac..3e945687bc 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -272,6 +272,7 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso utils.LogJSONFlag, utils.PProfEanbledFlag, utils.PProfPortFlag, + utils.MetricsEnabledFlag, utils.SolcPathFlag, utils.GpoMinGasPriceFlag, utils.GpoMaxGasPriceFlag, diff --git a/cmd/geth/monitorcmd.go b/cmd/geth/monitorcmd.go index 05965f009b..6a7e1cbb4b 100644 --- a/cmd/geth/monitorcmd.go +++ b/cmd/geth/monitorcmd.go @@ -75,7 +75,12 @@ func monitor(ctx *cli.Context) { if len(monitored) == 0 { list := expandMetrics(metrics, "") sort.Strings(list) - utils.Fatalf("No metrics specified.\n\nAvailable:\n - %s", strings.Join(list, "\n - ")) + + if len(list) > 0 { + utils.Fatalf("No metrics specified.\n\nAvailable:\n - %s", strings.Join(list, "\n - ")) + } else { + utils.Fatalf("No metrics specified.\n\nNo metrics collected (--metrics)\n") + } } sort.Strings(monitored) if cols := len(monitored) / ctx.Int(monitorCommandRowsFlag.Name); cols > 6 { diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 15a577a070..0d59980ec2 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -10,6 +10,8 @@ import ( "path/filepath" "runtime" + "github.com/ethereum/go-ethereum/metrics" + "github.com/codegangsta/cli" "github.com/ethereum/ethash" "github.com/ethereum/go-ethereum/accounts" @@ -187,6 +189,10 @@ var ( Usage: "Port on which the profiler should listen", Value: 6060, } + MetricsEnabledFlag = cli.BoolFlag{ + Name: metrics.MetricsEnabledFlag, + Usage: "Enables metrics collection and reporting", + } // RPC settings RPCEnabledFlag = cli.BoolFlag{ diff --git a/core/chain_manager.go b/core/chain_manager.go index fc1922b3b7..4803119510 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -18,6 +18,7 @@ import ( "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger/glog" + "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/pow" "github.com/ethereum/go-ethereum/rlp" @@ -33,7 +34,7 @@ var ( blockHashPre = []byte("block-hash-") blockNumPre = []byte("block-num-") - blockInsertTimer = metrics.GetOrRegisterTimer("core/BlockInsertions", metrics.DefaultRegistry) + blockInsertTimer = metrics.NewTimer("chain/inserts") ) const ( diff --git a/eth/backend.go b/eth/backend.go index 21ec71b100..4644b8a935 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -11,6 +11,8 @@ import ( "strings" "time" + "github.com/ethereum/go-ethereum/metrics" + "github.com/ethereum/ethash" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" @@ -29,7 +31,6 @@ import ( "github.com/ethereum/go-ethereum/p2p/discover" "github.com/ethereum/go-ethereum/p2p/nat" "github.com/ethereum/go-ethereum/whisper" - "github.com/rcrowley/go-metrics" ) const ( @@ -250,42 +251,42 @@ func New(config *Config) (*Ethereum, error) { return nil, fmt.Errorf("blockchain db err: %v", err) } if db, ok := blockDb.(*ethdb.LDBDatabase); ok { - db.GetTimer = metrics.GetOrRegisterTimer("eth/db/block/user/gets", metrics.DefaultRegistry) - db.PutTimer = metrics.GetOrRegisterTimer("eth/db/block/user/puts", metrics.DefaultRegistry) - db.MissMeter = metrics.GetOrRegisterMeter("eth/db/block/user/misses", metrics.DefaultRegistry) - db.ReadMeter = metrics.GetOrRegisterMeter("eth/db/block/user/reads", metrics.DefaultRegistry) - db.WriteMeter = metrics.GetOrRegisterMeter("eth/db/block/user/writes", metrics.DefaultRegistry) - db.CompTimeMeter = metrics.GetOrRegisterMeter("eth/db/block/compact/time", metrics.DefaultRegistry) - db.CompReadMeter = metrics.GetOrRegisterMeter("eth/db/block/compact/input", metrics.DefaultRegistry) - db.CompWriteMeter = metrics.GetOrRegisterMeter("eth/db/block/compact/output", metrics.DefaultRegistry) + db.GetTimer = metrics.NewTimer("eth/db/block/user/gets") + db.PutTimer = metrics.NewTimer("eth/db/block/user/puts") + db.MissMeter = metrics.NewMeter("eth/db/block/user/misses") + db.ReadMeter = metrics.NewMeter("eth/db/block/user/reads") + db.WriteMeter = metrics.NewMeter("eth/db/block/user/writes") + db.CompTimeMeter = metrics.NewMeter("eth/db/block/compact/time") + db.CompReadMeter = metrics.NewMeter("eth/db/block/compact/input") + db.CompWriteMeter = metrics.NewMeter("eth/db/block/compact/output") } stateDb, err := newdb(filepath.Join(config.DataDir, "state")) if err != nil { return nil, fmt.Errorf("state db err: %v", err) } if db, ok := stateDb.(*ethdb.LDBDatabase); ok { - db.GetTimer = metrics.GetOrRegisterTimer("eth/db/state/user/gets", metrics.DefaultRegistry) - db.PutTimer = metrics.GetOrRegisterTimer("eth/db/state/user/puts", metrics.DefaultRegistry) - db.MissMeter = metrics.GetOrRegisterMeter("eth/db/state/user/misses", metrics.DefaultRegistry) - db.ReadMeter = metrics.GetOrRegisterMeter("eth/db/state/user/reads", metrics.DefaultRegistry) - db.WriteMeter = metrics.GetOrRegisterMeter("eth/db/state/user/writes", metrics.DefaultRegistry) - db.CompTimeMeter = metrics.GetOrRegisterMeter("eth/db/state/compact/time", metrics.DefaultRegistry) - db.CompReadMeter = metrics.GetOrRegisterMeter("eth/db/state/compact/input", metrics.DefaultRegistry) - db.CompWriteMeter = metrics.GetOrRegisterMeter("eth/db/state/compact/output", metrics.DefaultRegistry) + db.GetTimer = metrics.NewTimer("eth/db/state/user/gets") + db.PutTimer = metrics.NewTimer("eth/db/state/user/puts") + db.MissMeter = metrics.NewMeter("eth/db/state/user/misses") + db.ReadMeter = metrics.NewMeter("eth/db/state/user/reads") + db.WriteMeter = metrics.NewMeter("eth/db/state/user/writes") + db.CompTimeMeter = metrics.NewMeter("eth/db/state/compact/time") + db.CompReadMeter = metrics.NewMeter("eth/db/state/compact/input") + db.CompWriteMeter = metrics.NewMeter("eth/db/state/compact/output") } extraDb, err := newdb(filepath.Join(config.DataDir, "extra")) if err != nil { return nil, fmt.Errorf("extra db err: %v", err) } if db, ok := extraDb.(*ethdb.LDBDatabase); ok { - db.GetTimer = metrics.GetOrRegisterTimer("eth/db/extra/user/gets", metrics.DefaultRegistry) - db.PutTimer = metrics.GetOrRegisterTimer("eth/db/extra/user/puts", metrics.DefaultRegistry) - db.MissMeter = metrics.GetOrRegisterMeter("eth/db/extra/user/misses", metrics.DefaultRegistry) - db.ReadMeter = metrics.GetOrRegisterMeter("eth/db/extra/user/reads", metrics.DefaultRegistry) - db.WriteMeter = metrics.GetOrRegisterMeter("eth/db/extra/user/writes", metrics.DefaultRegistry) - db.CompTimeMeter = metrics.GetOrRegisterMeter("eth/db/extra/compact/time", metrics.DefaultRegistry) - db.CompReadMeter = metrics.GetOrRegisterMeter("eth/db/extra/compact/input", metrics.DefaultRegistry) - db.CompWriteMeter = metrics.GetOrRegisterMeter("eth/db/extra/compact/output", metrics.DefaultRegistry) + db.GetTimer = metrics.NewTimer("eth/db/extra/user/gets") + db.PutTimer = metrics.NewTimer("eth/db/extra/user/puts") + db.MissMeter = metrics.NewMeter("eth/db/extra/user/misses") + db.ReadMeter = metrics.NewMeter("eth/db/extra/user/reads") + db.WriteMeter = metrics.NewMeter("eth/db/extra/user/writes") + db.CompTimeMeter = metrics.NewMeter("eth/db/extra/compact/time") + db.CompReadMeter = metrics.NewMeter("eth/db/extra/compact/input") + db.CompWriteMeter = metrics.NewMeter("eth/db/extra/compact/output") } nodeDb := filepath.Join(config.DataDir, "nodes") diff --git a/eth/fetcher/fetcher.go b/eth/fetcher/fetcher.go index 5a1509f89d..256b452e10 100644 --- a/eth/fetcher/fetcher.go +++ b/eth/fetcher/fetcher.go @@ -7,13 +7,11 @@ import ( "math/rand" "time" - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger/glog" - "github.com/rcrowley/go-metrics" "gopkg.in/karalabe/cookiejar.v2/collections/prque" ) @@ -99,14 +97,6 @@ type Fetcher struct { // Testing hooks fetchingHook func([]common.Hash) // Method to call upon starting a block fetch importedHook func(*types.Block) // Method to call upon successful block import - - // Runtime metrics - announceMeter metrics.Meter // Counter for metering the inbound announcements - announceTimer metrics.Timer // Counter and timer for metering the announce forwarding - broadcastMeter metrics.Meter // Counter for metering the inbound propagations - broadcastTimer metrics.Timer // Counter and timer for metering the block forwarding - discardMeter metrics.Meter // Counter for metering the discarded blocks - futureMeter metrics.Meter // Counter for metering future blocks } // New creates a block fetcher to retrieve blocks based on hash announcements. @@ -129,12 +119,6 @@ func New(getBlock blockRetrievalFn, validateBlock blockValidatorFn, broadcastBlo chainHeight: chainHeight, insertChain: insertChain, dropPeer: dropPeer, - announceMeter: metrics.GetOrRegisterMeter("eth/sync/RemoteAnnounces", metrics.DefaultRegistry), - announceTimer: metrics.GetOrRegisterTimer("eth/sync/LocalAnnounces", metrics.DefaultRegistry), - broadcastMeter: metrics.GetOrRegisterMeter("eth/sync/RemoteBroadcasts", metrics.DefaultRegistry), - broadcastTimer: metrics.GetOrRegisterTimer("eth/sync/LocalBroadcasts", metrics.DefaultRegistry), - discardMeter: metrics.GetOrRegisterMeter("eth/sync/DiscardedBlocks", metrics.DefaultRegistry), - futureMeter: metrics.GetOrRegisterMeter("eth/sync/FutureBlocks", metrics.DefaultRegistry), } } @@ -246,7 +230,7 @@ func (f *Fetcher) loop() { case notification := <-f.notify: // A block was announced, make sure the peer isn't DOSing us - f.announceMeter.Mark(1) + announceMeter.Mark(1) count := f.announces[notification.origin] + 1 if count > hashLimit { @@ -265,7 +249,7 @@ func (f *Fetcher) loop() { case op := <-f.inject: // A direct block insertion was requested, try and fill any pending gaps - f.broadcastMeter.Mark(1) + broadcastMeter.Mark(1) f.enqueue(op.origin, op.block) case hash := <-f.done: @@ -384,7 +368,7 @@ func (f *Fetcher) enqueue(peer string, block *types.Block) { // Discard any past or too distant blocks if dist := int64(block.NumberU64()) - int64(f.chainHeight()); dist < -maxUncleDist || dist > maxQueueDist { glog.V(logger.Debug).Infof("Peer %s: discarded block #%d [%x], distance %d", peer, block.NumberU64(), hash.Bytes()[:4], dist) - f.discardMeter.Mark(1) + discardMeter.Mark(1) return } // Schedule the block for future importing @@ -423,11 +407,11 @@ func (f *Fetcher) insert(peer string, block *types.Block) { switch err := f.validateBlock(block, parent); err { case nil: // All ok, quickly propagate to our peers - f.broadcastTimer.UpdateSince(block.ReceivedAt) + broadcastTimer.UpdateSince(block.ReceivedAt) go f.broadcastBlock(block, true) case core.BlockFutureErr: - f.futureMeter.Mark(1) + futureMeter.Mark(1) // Weird future block, don't fail, but neither propagate default: @@ -442,7 +426,7 @@ func (f *Fetcher) insert(peer string, block *types.Block) { return } // If import succeeded, broadcast the block - f.announceTimer.UpdateSince(block.ReceivedAt) + announceTimer.UpdateSince(block.ReceivedAt) go f.broadcastBlock(block, false) // Invoke the testing hook if needed diff --git a/eth/fetcher/metrics.go b/eth/fetcher/metrics.go new file mode 100644 index 0000000000..e46e3c0fbb --- /dev/null +++ b/eth/fetcher/metrics.go @@ -0,0 +1,16 @@ +// Contains the metrics collected by the fetcher. + +package fetcher + +import ( + "github.com/ethereum/go-ethereum/metrics" +) + +var ( + announceMeter = metrics.NewMeter("eth/sync/RemoteAnnounces") + announceTimer = metrics.NewTimer("eth/sync/LocalAnnounces") + broadcastMeter = metrics.NewMeter("eth/sync/RemoteBroadcasts") + broadcastTimer = metrics.NewTimer("eth/sync/LocalBroadcasts") + discardMeter = metrics.NewMeter("eth/sync/DiscardedBlocks") + futureMeter = metrics.NewMeter("eth/sync/FutureBlocks") +) diff --git a/metrics/metrics.go b/metrics/metrics.go index cb0caaae4e..33004ee3b7 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -2,7 +2,9 @@ package metrics import ( + "os" "runtime" + "strings" "time" "github.com/ethereum/go-ethereum/logger" @@ -10,9 +12,49 @@ import ( "github.com/rcrowley/go-metrics" ) +// MetricsEnabledFlag is the CLI flag name to use to enable metrics collections. +var MetricsEnabledFlag = "metrics" + +// enabled is the flag specifying if metrics are enable or not. +var enabled = false + +// Init enables or disables the metrics system. Since we need this to run before +// any other code gets to create meters and timers, we'll actually do an ugly hack +// and peek into the command line args for the metrics flag. +func init() { + for _, arg := range os.Args { + if strings.TrimLeft(arg, "-") == MetricsEnabledFlag { + glog.V(logger.Info).Infof("Enabling metrics collection") + enabled = true + } + } +} + +// NewMeter create a new metrics Meter, either a real one of a NOP stub depending +// on the metrics flag. +func NewMeter(name string) metrics.Meter { + if !enabled { + return new(metrics.NilMeter) + } + return metrics.GetOrRegisterMeter(name, metrics.DefaultRegistry) +} + +// NewTimer create a new metrics Timer, either a real one of a NOP stub depending +// on the metrics flag. +func NewTimer(name string) metrics.Timer { + if !enabled { + return new(metrics.NilTimer) + } + return metrics.GetOrRegisterTimer(name, metrics.DefaultRegistry) +} + // CollectProcessMetrics periodically collects various metrics about the running // process. func CollectProcessMetrics(refresh time.Duration) { + // Short circuit if the metrics system is disabled + if !enabled { + return + } // Create the various data collectors memstats := make([]*runtime.MemStats, 2) diskstats := make([]*DiskStats, 2) diff --git a/p2p/metrics.go b/p2p/metrics.go index fbe5b1e90d..4b519e438e 100644 --- a/p2p/metrics.go +++ b/p2p/metrics.go @@ -5,14 +5,14 @@ package p2p import ( "net" - "github.com/rcrowley/go-metrics" + "github.com/ethereum/go-ethereum/metrics" ) var ( - ingressConnectMeter = metrics.GetOrRegisterMeter("p2p/InboundConnects", metrics.DefaultRegistry) - ingressTrafficMeter = metrics.GetOrRegisterMeter("p2p/InboundTraffic", metrics.DefaultRegistry) - egressConnectMeter = metrics.GetOrRegisterMeter("p2p/OutboundConnects", metrics.DefaultRegistry) - egressTrafficMeter = metrics.GetOrRegisterMeter("p2p/OutboundTraffic", metrics.DefaultRegistry) + ingressConnectMeter = metrics.NewMeter("p2p/InboundConnects") + ingressTrafficMeter = metrics.NewMeter("p2p/InboundTraffic") + egressConnectMeter = metrics.NewMeter("p2p/OutboundConnects") + egressTrafficMeter = metrics.NewMeter("p2p/OutboundTraffic") ) // meteredConn is a wrapper around a network TCP connection that meters both the