Skip to content
This repository has been archived by the owner on Oct 4, 2019. It is now read-only.

cmd/geth: implement interval-based status logging #324

Merged
merged 21 commits into from
Aug 16, 2017
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
8effd93
sketches for using API for logging... may be overkill
whilei Jun 14, 2017
7abe6ca
:floppy_disk:
whilei Jul 27, 2017
a360b1c
WIP: problem: should implement interval-based status logging
whilei Jul 27, 2017
8323600
problem: no reason to force RPC
whilei Jul 27, 2017
0fd6e5f
problem: no reason to return eth from StartNode
whilei Jul 27, 2017
80f7222
problem: warning log should use logger.Warn
whilei Jul 28, 2017
6f530fe
problem: log-pace flag usage antiquated
whilei Jul 28, 2017
0361214
problem: should polish log-pace function
whilei Jul 28, 2017
cdafd37
problem: minor variable renaming and comments
whilei Jul 29, 2017
5e5f52c
problem: logging genesis account balances on Core log-level is too high
whilei Jul 30, 2017
2990308
problem: can share interrupt chan
whilei Jul 30, 2017
861d49b
problem: logging to dir should also output to stderr
whilei Jul 30, 2017
05dca17
problem: log io flush never called after interrupt
whilei Jul 30, 2017
027a8d0
problem: rename '--log-pace' to '--log-status'
whilei Jul 30, 2017
a06f511
problem: want --log-status to be extensible for other interfaces
whilei Jul 30, 2017
492c7ca
problem: (nonfunctional,refactor) should move cmd-oriented functions …
whilei Jul 30, 2017
a117f2f
solution: run gofmt
whilei Jul 30, 2017
af4d7e4
problem: rollback command logging confirmation should check fastblock
whilei Jul 31, 2017
5be13af
problem: interrupt shutdown processes not consistent
whilei Jul 31, 2017
82ea60b
problem: (log syntax) log-status interval initial log still shows 'lo…
whilei Jul 31, 2017
4aed4f2
Merge branch 'master' into logging
whilei Aug 16, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
466 changes: 462 additions & 4 deletions cmd/geth/cmd.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion cmd/geth/flag.go
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ func MakeAddress(accman *accounts.Manager, account string) (accounts.Account, er
func MakeEtherbase(accman *accounts.Manager, ctx *cli.Context) common.Address {
accounts := accman.Accounts()
if !ctx.GlobalIsSet(aliasableName(EtherbaseFlag.Name, ctx)) && len(accounts) == 0 {
glog.V(logger.Error).Infoln("WARNING: No etherbase set and no accounts found as default")
glog.V(logger.Warn).Infoln("WARNING: No etherbase set and no accounts found as default")
return common.Address{}
}
etherbase := ctx.GlobalString(aliasableName(EtherbaseFlag.Name, ctx))
Expand Down
5 changes: 5 additions & 0 deletions cmd/geth/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,11 @@ var (
Usage: "Directory in which to write log files, redirecting terminal out (stderr)",
Value: DirectoryString{filepath.Join(common.DefaultDataDir(), "logs")},
}
LogStatusFlag = cli.StringFlag{
Name: "log-status",
Usage: `Toggle interval-based STATUS logs: comma-separated list of <pattern>=<interval>`,
Value: "sync=60",
}
BacktraceAtFlag = cli.GenericFlag{
Name: "backtrace",
Usage: "Request a stack trace at a specific logging statement (e.g. \"block.go:271\")",
Expand Down
277 changes: 10 additions & 267 deletions cmd/geth/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,19 @@
package main

import (
"errors"
"fmt"
"io/ioutil"
"gopkg.in/urfave/cli.v1"
"log"
"os"
"path/filepath"
"runtime"
"strconv"
"strings"

"gopkg.in/urfave/cli.v1"

"github.com/ethereumproject/ethash"
"github.com/ethereumproject/go-ethereum/console"
"github.com/ethereumproject/go-ethereum/core"
"github.com/ethereumproject/go-ethereum/core/state"
"github.com/ethereumproject/go-ethereum/eth"
"github.com/ethereumproject/go-ethereum/logger"
"github.com/ethereumproject/go-ethereum/logger/glog"
"github.com/ethereumproject/go-ethereum/metrics"
"github.com/ethereumproject/go-ethereum/node"
)

// Version is the application revision identifier. It can be set with the linker
Expand Down Expand Up @@ -160,6 +152,7 @@ The output of this command is supposed to be machine-readable.
VerbosityFlag,
VModuleFlag,
LogDirFlag,
LogStatusFlag,
BacktraceAtFlag,
MetricsFlag,
FakePoWFlag,
Expand Down Expand Up @@ -202,9 +195,10 @@ The output of this command is supposed to be machine-readable.
return e
}
glog.SetLogDir(p)
glog.SetAlsoToStderr(true)
}
} else {
glog.SetToStderr(true) // I don't know why...
glog.SetToStderr(true)
}

if s := ctx.String("metrics"); s != "" {
Expand All @@ -228,7 +222,7 @@ The output of this command is supposed to be machine-readable.
if ctx.GlobalBool(aliasableName(DevModeFlag.Name, ctx)) {
if !ctx.GlobalIsSet(aliasableName(ChainIdentityFlag.Name, ctx)) {
if e := ctx.Set(aliasableName(ChainIdentityFlag.Name, ctx), "morden"); e != nil {
log.Fatalf("failed to set chain value: %v", e)
log.Fatalf("failed to set chain value: %v", e)
}
}
}
Expand Down Expand Up @@ -262,264 +256,13 @@ func main() {
// It creates a default node based on the command line arguments and runs it in
// blocking mode, waiting for it to be shut down.
func geth(ctx *cli.Context) error {
node := MakeSystemNode(Version, ctx)
startNode(ctx, node)
node.Wait()

return nil
}

func status(ctx *cli.Context) error {

shouldUseExisting := false
datadir := MustMakeChainDataDir(ctx)
chaindatadir := filepath.Join(datadir, "chaindata")
if di, e := os.Stat(chaindatadir); e == nil && di.IsDir() {
shouldUseExisting = true
}
// Makes sufficient configuration from JSON file or DB pending flags.
// Delegates flag usage.
config := mustMakeSufficientChainConfig(ctx)

// Configure the Ethereum service
ethConf := mustMakeEthConf(ctx, config)

// Configure node's service container.
name := makeNodeName(Version, ctx)
stackConf, _ := mustMakeStackConf(ctx, name, config)
n := MakeSystemNode(Version, ctx)
ethe := startNode(ctx, n)

sep := glog.Separator("-")
printme := []struct {
title string
keyVals []string
}{
{"Chain configuration", formatSufficientChainConfigPretty(config)},
{"Ethereum configuration", formatEthConfigPretty(ethConf)},
{"Node configuration", formatStackConfigPretty(stackConf)},
if ctx.GlobalIsSet(LogStatusFlag.Name) {
dispatchStatusLogs(ctx, ethe)
}

s := "\n"

for _, p := range printme {
s += withLineBreak(sep)
// right align category title
s += withLineBreak(strings.Repeat(" ", len(sep)-len(p.title)) + colorBlue(p.title))
for _, v := range p.keyVals {
s += v
}
}
glog.V(logger.Info).Info(s)

// Return here if database has not been initialized.
if !shouldUseExisting {
glog.V(logger.Info).Info("Geth has not been initialized; no database information available yet.")
return nil
}

chaindata, cdb := MakeChain(ctx)
defer cdb.Close()
s = "\n"
s += withLineBreak(sep)
title := "Chain database status"
s += withLineBreak(strings.Repeat(" ", len(sep)-len(title)) + colorBlue(title))
for _, v := range formatChainDataPretty(datadir, chaindata) {
s += v
}
glog.V(logger.Info).Info(s)

return nil
}

func rollback(ctx *cli.Context) error {
index := ctx.Args().First()
if len(index) == 0 {
log.Fatal("missing argument: use `rollback 12345` to specify required block number to roll back to")
return errors.New("invalid flag usage")
}

blockIndex, err := strconv.ParseUint(index, 10, 64)
if err != nil {
glog.Fatalf("invalid argument: use `rollback 12345`, were '12345' is a required number specifying which block number to roll back to")
return errors.New("invalid flag usage")
}

bc, chainDB := MakeChain(ctx)
defer chainDB.Close()

glog.Warning("Rolling back blockchain...")

bc.SetHead(blockIndex)

nowCurrentState := bc.CurrentBlock().Number().Uint64()
if nowCurrentState != blockIndex {
glog.Fatalf("ERROR: Wanted rollback to set head to: %v, instead current head is: %v", blockIndex, nowCurrentState)
} else {
glog.Infof("SUCCESS: Head block set to: %v", nowCurrentState)
}

return nil
}

// dumpChainConfig exports chain configuration based on context to JSON file.
// It is not compatible with --chain-config flag; it is intended to move from flags -> file,
// and not the other way around.
func dumpChainConfig(ctx *cli.Context) error {

chainIdentity := mustMakeChainIdentity(ctx)
if !(chainIdentitiesMain[chainIdentity] || chainIdentitiesMorden[chainIdentity]) {
glog.Fatal("Dump config should only be used with default chain configurations (mainnet or morden).")
}

glog.V(logger.Info).Infof("Dumping configuration for: %v", chainIdentity)

chainConfigFilePath := ctx.Args().First()
chainConfigFilePath = filepath.Clean(chainConfigFilePath)

if chainConfigFilePath == "" || chainConfigFilePath == "/" || chainConfigFilePath == "." {
glog.Fatalf("Given filepath to export chain configuration was blank or invalid; it was: '%v'. It cannot be blank. You typed: %v ", chainConfigFilePath, ctx.Args().First())
return errors.New("invalid required filepath argument")
}

fb := filepath.Dir(chainConfigFilePath)
di, de := os.Stat(fb)
if de != nil {
if os.IsNotExist(de) {
glog.V(logger.Warn).Infof("Directory path '%v' does not yet exist. Will create.", fb)
if e := os.MkdirAll(fb, os.ModePerm); e != nil {
glog.Fatalf("Could not create necessary directories: %v", e)
}
di, _ = os.Stat(fb) // update var with new dir info
} else {
glog.V(logger.Error).Infof("err: %v (at '%v')", de, fb)
}
}
if !di.IsDir() {
glog.Fatalf("'%v' must be a directory", fb)
}

// Implicitly favor Morden because it is a smaller, simpler configuration,
// so I expect it to be used more frequently than mainnet.
genesisDump := core.TestNetGenesis
netId := 2
stateConf := &core.StateConfig{StartingNonce: state.DefaultTestnetStartingNonce}
if !chainIsMorden(ctx) {
genesisDump = core.DefaultGenesis
netId = eth.NetworkId
stateConf = nil
}

// Note that we use default configs (not externalizable).
chainConfig := MustMakeChainConfigFromDefaults(ctx)
var nodes []string
for _, node := range MakeBootstrapNodesFromContext(ctx) {
nodes = append(nodes, node.String())
}

var currentConfig = &core.SufficientChainConfig{
Identity: chainIdentity,
Name: mustMakeChainConfigNameDefaulty(ctx),
Network: netId,
State: stateConf,
Consensus: "ethash",
Genesis: genesisDump,
ChainConfig: chainConfig.SortForks(), // get current/contextualized chain config
Bootstrap: nodes,
}

if writeError := currentConfig.WriteToJSONFile(chainConfigFilePath); writeError != nil {
glog.Fatalf("An error occurred while writing chain configuration: %v", writeError)
return writeError
}

glog.V(logger.Info).Info(fmt.Sprintf("Wrote chain config file to \x1b[32m%s\x1b[39m.", chainConfigFilePath))
return nil
}

// startNode boots up the system node and all registered protocols, after which
// it unlocks any requested accounts, and starts the RPC/IPC interfaces and the
// miner.
func startNode(ctx *cli.Context, stack *node.Node) {
// Start up the node itself
StartNode(stack)

// Unlock any account specifically requested
var ethereum *eth.Ethereum
if err := stack.Service(&ethereum); err != nil {
log.Fatal("ethereum service not running: ", err)
}

// Start auxiliary services if enabled
if ctx.GlobalBool(aliasableName(MiningEnabledFlag.Name, ctx)) {
if err := ethereum.StartMining(ctx.GlobalInt(aliasableName(MinerThreadsFlag.Name, ctx)), ctx.GlobalString(aliasableName(MiningGPUFlag.Name, ctx))); err != nil {
log.Fatalf("Failed to start mining: %v", err)
}
}
}

func makedag(ctx *cli.Context) error {
args := ctx.Args()
wrongArgs := func() {
log.Fatal(`Usage: geth makedag <block number> <outputdir>`)
}
switch {
case len(args) == 2:
blockNum, err := strconv.ParseUint(args[0], 0, 64)
dir := args[1]
if err != nil {
wrongArgs()
} else {
dir = filepath.Clean(dir)
// seems to require a trailing slash
if !strings.HasSuffix(dir, "/") {
dir = dir + "/"
}
_, err = ioutil.ReadDir(dir)
if err != nil {
log.Fatal("Can't find dir")
}
fmt.Println("making DAG, this could take awhile...")
ethash.MakeDAG(blockNum, dir)
}
default:
wrongArgs()
}
return nil
}

func gpuinfo(ctx *cli.Context) error {
eth.PrintOpenCLDevices()
return nil
}

func gpubench(ctx *cli.Context) error {
args := ctx.Args()
wrongArgs := func() {
log.Fatal(`Usage: geth gpubench <gpu number>`)
}
switch {
case len(args) == 1:
n, err := strconv.ParseUint(args[0], 0, 64)
if err != nil {
wrongArgs()
}
eth.GPUBench(n)
case len(args) == 0:
eth.GPUBench(0)
default:
wrongArgs()
}
return nil
}

func version(ctx *cli.Context) error {
fmt.Println("Geth")
fmt.Println("Version:", Version)
fmt.Println("Protocol Versions:", eth.ProtocolVersions)
fmt.Println("Network Id:", ctx.GlobalInt(aliasableName(NetworkIdFlag.Name, ctx)))
fmt.Println("Go Version:", runtime.Version())
fmt.Println("OS:", runtime.GOOS)
fmt.Printf("GOPATH=%s\n", os.Getenv("GOPATH"))
fmt.Printf("GOROOT=%s\n", runtime.GOROOT())
n.Wait()

return nil
}
1 change: 1 addition & 0 deletions cmd/geth/usage.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ var AppHelpFlagGroups = []flagGroup{
VerbosityFlag,
LogDirFlag,
VModuleFlag,
LogStatusFlag,
BacktraceAtFlag,
MetricsFlag,
FakePoWFlag,
Expand Down
2 changes: 1 addition & 1 deletion core/state/state_object.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ func (c *StateObject) AddBalance(amount *big.Int) {
}
c.SetBalance(new(big.Int).Add(c.Balance(), amount))

if glog.V(logger.Core) {
if glog.V(logger.Debug) {
glog.Infof("%x: #%d %v (+ %v)\n", c.Address(), c.Nonce(), c.Balance(), amount)
}
}
Expand Down
2 changes: 1 addition & 1 deletion core/state/statedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ func (self *StateDB) createObject(addr common.Address) (newobj, prev *StateObjec
newobj = newObject(self, addr, Account{}, self.MarkStateObjectDirty)
newobj.setNonce(StartingNonce) // sets the object to dirty
if prev == nil {
if glog.V(logger.Core) {
if glog.V(logger.Debug) {
glog.Infof("(+) %x\n", addr)
}
self.journal = append(self.journal, createObjectChange{account: &addr})
Expand Down
9 changes: 9 additions & 0 deletions eth/downloader/downloader.go
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,15 @@ func (d *Downloader) Synchronising() bool {
return atomic.LoadInt32(&d.synchronising) > 0
}

// Experimental getter functions for new logging.
func (d *Downloader) GetMode() SyncMode {
return d.mode
}

func (d *Downloader) GetPeers() *peerSet {
return d.peers
}

// RegisterPeer injects a new download peer into the set of block source to be
// used for fetching hashes and blocks from.
func (d *Downloader) RegisterPeer(id string, version int, currentHead currentHeadRetrievalFn,
Expand Down