diff --git a/cmd/bootnode/main.go b/cmd/bootnode/main.go index 9e60429ce..467e7851b 100644 --- a/cmd/bootnode/main.go +++ b/cmd/bootnode/main.go @@ -32,17 +32,14 @@ func printVersion(me string) { os.Exit(0) } -func loggingInit(logFolder, ip, port string, verbosity log.Lvl) { +func initLogFile(logFolder, ip, port string) { // Setup a logger to stdout and log file. if err := os.MkdirAll(logFolder, 0755); err != nil { panic(err) } logFileName := fmt.Sprintf("./%v/bootnode-%v-%v.log", logFolder, ip, port) - h := log.LvlFilterHandler(verbosity, log.MultiHandler( - log.StreamHandler(os.Stdout, log.TerminalFormat(false)), - log.Must.FileHandler(logFileName, log.JSONFormat()), // Log to file - )) - log.Root().SetHandler(h) + fileHandler := log.Must.FileHandler(logFileName, log.JSONFormat()) // Log to file + utils.AddLogHandler(fileHandler) } func main() { @@ -60,11 +57,9 @@ func main() { } // Logging setup - utils.SetPortAndIP(*port, *ip) - utils.SetVerbosity(log.Lvl(*verbosity)) - - // Init logging. - loggingInit(*logFolder, *ip, *port, log.Lvl(*verbosity)) + utils.SetLogContext(*port, *ip) + utils.SetLogVerbosity(log.Lvl(*verbosity)) + initLogFile(*logFolder, *ip, *port) privKey, _, err := utils.LoadKeyFromFile(*keyFile) if err != nil { diff --git a/cmd/client/txgen/main.go b/cmd/client/txgen/main.go index e08f89521..cd616f000 100644 --- a/cmd/client/txgen/main.go +++ b/cmd/client/txgen/main.go @@ -128,8 +128,8 @@ func main() { // Add GOMAXPROCS to achieve max performance. runtime.GOMAXPROCS(1024) // Logging setup - utils.SetPortAndIP(*port, *ip) - utils.SetVerbosity(log.Lvl(*verbosity)) + utils.SetLogContext(*port, *ip) + utils.SetLogVerbosity(log.Lvl(*verbosity)) if len(utils.BootNodes) == 0 { bootNodeAddrs, err := utils.StringsToAddrs(utils.DefaultBootNodeAddrStrings) if err != nil { diff --git a/cmd/harmony/main.go b/cmd/harmony/main.go index 92e2d9bc3..5739688f7 100644 --- a/cmd/harmony/main.go +++ b/cmd/harmony/main.go @@ -58,21 +58,23 @@ func printVersion(me string) { os.Exit(0) } -func loggingInit(logFolder, role, ip, port string, onlyLogTps bool, verbosity log.Lvl) { +func initLogFile(logFolder, role, ip, port string, onlyLogTps bool) { // Setup a logger to stdout and log file. + if err := os.MkdirAll(logFolder, 0755); err != nil { + panic(err) + } logFileName := fmt.Sprintf("./%v/%s-%v-%v.log", logFolder, role, ip, port) - h := log.LvlFilterHandler(verbosity, log.MultiHandler( - log.StreamHandler(os.Stdout, log.TerminalFormat(false)), - log.Must.FileHandler(logFileName, log.JSONFormat()), // Log to file - )) + fileHandler := log.Must.FileHandler(logFileName, log.JSONFormat()) + utils.AddLogHandler(fileHandler) + if onlyLogTps { - h = log.MatchFilterHandler("msg", "TPS Report", h) + matchFilterHandler := log.MatchFilterHandler("msg", "TPS Report", utils.GetLogInstance().GetHandler()) + utils.GetLogInstance().SetHandler(matchFilterHandler) } - log.Root().SetHandler(h) } var ( - ip = flag.String("ip", "127.0.0.1", "IP of the node") + ip = flag.String("ip", "127.0.0.1", "ip of the node") port = flag.String("port", "9000", "port of the node.") logFolder = flag.String("log_folder", "latest", "the folder collecting the logs of this execution") freshDB = flag.Bool("fresh_db", false, "true means the existing disk based db will be removed") @@ -372,13 +374,15 @@ func main() { flag.Var(&utils.BootNodes, "bootnodes", "a list of bootnode multiaddress (delimited by ,)") flag.Parse() + // Configure log parameters + utils.SetLogContext(*port, *ip) + utils.SetLogVerbosity(log.Lvl(*verbosity)) + initSetup() var currentNode *node.Node var consensus *consensus.Consensus nodeConfig := createGlobalConfig() - - // Init logging. - loggingInit(*logFolder, nodeConfig.StringRole, *ip, *port, *onlyLogTps, log.Lvl(*verbosity)) + initLogFile(*logFolder, nodeConfig.StringRole, *ip, *port, *onlyLogTps) // Start Profiler for leader if profile argument is on if nodeConfig.StringRole == "leader" && (*profile || *metricsReportURL != "") { diff --git a/internal/utils/singleton.go b/internal/utils/singleton.go index 512b17ab6..34d27b87a 100644 --- a/internal/utils/singleton.go +++ b/internal/utils/singleton.go @@ -3,6 +3,7 @@ package utils import ( + "io" "os" "sync" "sync/atomic" @@ -10,23 +11,43 @@ import ( "github.com/ethereum/go-ethereum/log" ) -// Global Port and IP for logging. var ( - Port string - IP string - Verbosity = log.LvlInfo + // Validator ID + validatorIDInstance *UniqueValidatorID + onceForUniqueValidatorID sync.Once + // Global port and ip for logging. + port string + ip string + // Logging + logInstance log.Logger + glogger *log.GlogHandler // top-level handler + logHandlers []log.Handler // sub handlers of glogger + logVerbosity log.Lvl + onceForLog sync.Once ) -// SetPortAndIP used to print out loggings of node with Port and IP. +// SetLogContext used to print out loggings of node with port and ip. // Every instance (node, txgen, etc..) needs to set this for logging. -func SetPortAndIP(port, ip string) { - Port = port - IP = ip +func SetLogContext(_port, _ip string) { + port = _port + ip = _ip } -// SetVerbosity specifies the verbosity of global logger -func SetVerbosity(verbosity log.Lvl) { - Verbosity = verbosity +// SetLogVerbosity specifies the verbosity of global logger +func SetLogVerbosity(verbosity log.Lvl) { + logVerbosity = verbosity + if glogger != nil { + glogger.Verbosity(logVerbosity) + } +} + +// AddLogHandler add a log handler +func AddLogHandler(handler log.Handler) { + logHandlers = append(logHandlers, handler) + if glogger != nil { + multiHandler := log.MultiHandler(logHandlers...) + glogger.SetHandler(multiHandler) + } } // UniqueValidatorID defines the structure of unique validator ID @@ -34,11 +55,6 @@ type UniqueValidatorID struct { uniqueID uint32 } -var validatorIDInstance *UniqueValidatorID -var logInstance log.Logger -var onceForUniqueValidatorID sync.Once -var onceForLog sync.Once - // GetUniqueValidatorIDInstance returns a singleton instance func GetUniqueValidatorIDInstance() *UniqueValidatorID { onceForUniqueValidatorID.Do(func() { @@ -57,8 +73,14 @@ func (s *UniqueValidatorID) GetUniqueID() uint32 { // GetLogInstance returns logging singleton. func GetLogInstance() log.Logger { onceForLog.Do(func() { - logInstance = log.New("port", Port, "ip", IP) - logInstance.SetHandler(log.LvlFilterHandler(Verbosity, log.StreamHandler(os.Stdout, log.TerminalFormat(false)))) + ostream := log.StreamHandler(io.Writer(os.Stdout), log.TerminalFormat(false)) + logHandlers = append(logHandlers, ostream) + multiHandler := log.MultiHandler(logHandlers...) + glogger = log.NewGlogHandler(multiHandler) + glogger.Verbosity(logVerbosity) + logInstance = log.New("port", port, "ip", ip) + logInstance.SetHandler(glogger) + log.Root().SetHandler(glogger) }) return logInstance }