mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2024-12-22 19:50:36 +00:00
e99269ebce
This request adds an additional logging flag to change the name of the logfiles produced by erigon to be prefixed by a name other than 'erigon'. This allows multiple nodes to log to the same directory without overwriting each others files. It is requires so that the devnet when running can maintain all of its log files in a single consolidated directory which survives devnet restarts. --------- Co-authored-by: Mark Holt <mark@distributed.vision>
217 lines
6.6 KiB
Go
217 lines
6.6 KiB
Go
package logging
|
|
|
|
import (
|
|
"flag"
|
|
"os"
|
|
"path"
|
|
"path/filepath"
|
|
"strconv"
|
|
|
|
"github.com/ledgerwatch/log/v3"
|
|
"github.com/spf13/cobra"
|
|
"github.com/urfave/cli/v2"
|
|
"gopkg.in/natefinch/lumberjack.v2"
|
|
)
|
|
|
|
// SetupLoggerCtx performs the logging setup according to the parameters
|
|
// containted in the given urfave context. It returns either root logger,
|
|
// if rootHandler argument is set to true, or a newly created logger.
|
|
// This is to ensure gradual transition to the use of non-root logger thoughout
|
|
// the erigon code without a huge change at once.
|
|
// This function which is used in Erigon itself.
|
|
// Note: urfave and cobra are two CLI frameworks/libraries for the same functionalities
|
|
// and it would make sense to choose one over another
|
|
func SetupLoggerCtx(filePrefix string, ctx *cli.Context, rootHandler bool) log.Logger {
|
|
var consoleJson = ctx.Bool(LogJsonFlag.Name) || ctx.Bool(LogConsoleJsonFlag.Name)
|
|
var dirJson = ctx.Bool(LogDirJsonFlag.Name)
|
|
|
|
consoleLevel, lErr := tryGetLogLevel(ctx.String(LogConsoleVerbosityFlag.Name))
|
|
if lErr != nil {
|
|
// try verbosity flag
|
|
consoleLevel, lErr = tryGetLogLevel(ctx.String(LogVerbosityFlag.Name))
|
|
if lErr != nil {
|
|
consoleLevel = log.LvlInfo
|
|
}
|
|
}
|
|
|
|
dirLevel, dErr := tryGetLogLevel(ctx.String(LogDirVerbosityFlag.Name))
|
|
if dErr != nil {
|
|
dirLevel = log.LvlInfo
|
|
}
|
|
|
|
dirPath := ctx.String(LogDirPathFlag.Name)
|
|
if dirPath == "" {
|
|
datadir := ctx.String("datadir")
|
|
if datadir != "" {
|
|
dirPath = filepath.Join(datadir, "logs")
|
|
}
|
|
}
|
|
var logger log.Logger
|
|
if rootHandler {
|
|
logger = log.Root()
|
|
} else {
|
|
logger = log.New()
|
|
}
|
|
|
|
if logDirPrefix := ctx.String(LogDirPrefixFlag.Name); len(logDirPrefix) > 0 {
|
|
filePrefix = logDirPrefix
|
|
}
|
|
|
|
initSeparatedLogging(logger, filePrefix, dirPath, consoleLevel, dirLevel, consoleJson, dirJson)
|
|
return logger
|
|
}
|
|
|
|
// SetupLoggerCmd perform the logging for a cobra command, and sets it to the root logger
|
|
// This is the function which is NOT used by Erigon itself, but instead by some cobra-based commands,
|
|
// for example, rpcdaemon or integration.
|
|
// Note: urfave and cobra are two CLI frameworks/libraries for the same functionalities
|
|
// and it would make sense to choose one over another
|
|
func SetupLoggerCmd(filePrefix string, cmd *cobra.Command) log.Logger {
|
|
|
|
logJsonVal, ljerr := cmd.Flags().GetBool(LogJsonFlag.Name)
|
|
if ljerr != nil {
|
|
logJsonVal = false
|
|
}
|
|
|
|
logConsoleJsonVal, lcjerr := cmd.Flags().GetBool(LogConsoleJsonFlag.Name)
|
|
if lcjerr != nil {
|
|
logConsoleJsonVal = false
|
|
}
|
|
|
|
var consoleJson = logJsonVal || logConsoleJsonVal
|
|
dirJson, djerr := cmd.Flags().GetBool(LogDirJsonFlag.Name)
|
|
if djerr != nil {
|
|
dirJson = false
|
|
}
|
|
|
|
consoleLevel, lErr := tryGetLogLevel(cmd.Flags().Lookup(LogConsoleVerbosityFlag.Name).Value.String())
|
|
if lErr != nil {
|
|
// try verbosity flag
|
|
consoleLevel, lErr = tryGetLogLevel(cmd.Flags().Lookup(LogVerbosityFlag.Name).Value.String())
|
|
if lErr != nil {
|
|
consoleLevel = log.LvlInfo
|
|
}
|
|
}
|
|
|
|
dirLevel, dErr := tryGetLogLevel(cmd.Flags().Lookup(LogDirVerbosityFlag.Name).Value.String())
|
|
if dErr != nil {
|
|
dirLevel = log.LvlInfo
|
|
}
|
|
|
|
dirPath := cmd.Flags().Lookup(LogDirPathFlag.Name).Value.String()
|
|
if dirPath == "" {
|
|
datadir := cmd.Flags().Lookup("datadir").Value.String()
|
|
if datadir != "" {
|
|
dirPath = filepath.Join(datadir, "logs")
|
|
}
|
|
}
|
|
|
|
if logDirPrefix := cmd.Flags().Lookup(LogDirPrefixFlag.Name).Value.String(); len(logDirPrefix) > 0 {
|
|
filePrefix = logDirPrefix
|
|
}
|
|
|
|
initSeparatedLogging(log.Root(), filePrefix, dirPath, consoleLevel, dirLevel, consoleJson, dirJson)
|
|
return log.Root()
|
|
}
|
|
|
|
// SetupLoggerCmd perform the logging using parametrs specifying by `flag` package, and sets it to the root logger
|
|
// This is the function which is NOT used by Erigon itself, but instead by utility commans
|
|
func SetupLogger(filePrefix string) log.Logger {
|
|
var logConsoleVerbosity = flag.String(LogConsoleVerbosityFlag.Name, "", LogConsoleVerbosityFlag.Usage)
|
|
var logDirVerbosity = flag.String(LogDirVerbosityFlag.Name, "", LogDirVerbosityFlag.Usage)
|
|
var logDirPath = flag.String(LogDirPathFlag.Name, "", LogDirPathFlag.Usage)
|
|
var logDirPrefix = flag.String(LogDirPrefixFlag.Name, "", LogDirPrefixFlag.Usage)
|
|
var logVerbosity = flag.String(LogVerbosityFlag.Name, "", LogVerbosityFlag.Usage)
|
|
var logConsoleJson = flag.Bool(LogConsoleJsonFlag.Name, false, LogConsoleJsonFlag.Usage)
|
|
var logJson = flag.Bool(LogJsonFlag.Name, false, LogJsonFlag.Usage)
|
|
var logDirJson = flag.Bool(LogDirJsonFlag.Name, false, LogDirJsonFlag.Usage)
|
|
flag.Parse()
|
|
|
|
var consoleJson = *logJson || *logConsoleJson
|
|
var dirJson = logDirJson
|
|
|
|
consoleLevel, lErr := tryGetLogLevel(*logConsoleVerbosity)
|
|
if lErr != nil {
|
|
// try verbosity flag
|
|
consoleLevel, lErr = tryGetLogLevel(*logVerbosity)
|
|
if lErr != nil {
|
|
consoleLevel = log.LvlInfo
|
|
}
|
|
}
|
|
|
|
dirLevel, dErr := tryGetLogLevel(*logDirVerbosity)
|
|
if dErr != nil {
|
|
dirLevel = log.LvlInfo
|
|
}
|
|
|
|
if logDirPrefix != nil && len(*logDirPrefix) > 0 {
|
|
filePrefix = *logDirPrefix
|
|
}
|
|
|
|
initSeparatedLogging(log.Root(), filePrefix, *logDirPath, consoleLevel, dirLevel, consoleJson, *dirJson)
|
|
return log.Root()
|
|
}
|
|
|
|
// initSeparatedLogging construct a log handler accrosing to the configuration parameters passed to it
|
|
// and sets the constructed handler to be the handler of the given logger. It then uses that logger
|
|
// to report the status of this initialisation
|
|
func initSeparatedLogging(
|
|
logger log.Logger,
|
|
filePrefix string,
|
|
dirPath string,
|
|
consoleLevel log.Lvl,
|
|
dirLevel log.Lvl,
|
|
consoleJson bool,
|
|
dirJson bool) {
|
|
|
|
var consoleHandler log.Handler
|
|
|
|
if consoleJson {
|
|
consoleHandler = log.LvlFilterHandler(consoleLevel, log.StreamHandler(os.Stderr, log.JsonFormat()))
|
|
} else {
|
|
consoleHandler = log.LvlFilterHandler(consoleLevel, log.StderrHandler)
|
|
}
|
|
logger.SetHandler(consoleHandler)
|
|
|
|
if len(dirPath) == 0 {
|
|
logger.Warn("no log dir set, console logging only")
|
|
return
|
|
}
|
|
|
|
err := os.MkdirAll(dirPath, 0764)
|
|
if err != nil {
|
|
logger.Warn("failed to create log dir, console logging only")
|
|
return
|
|
}
|
|
|
|
dirFormat := log.TerminalFormatNoColor()
|
|
if dirJson {
|
|
dirFormat = log.JsonFormat()
|
|
}
|
|
|
|
lumberjack := &lumberjack.Logger{
|
|
Filename: path.Join(dirPath, filePrefix+".log"),
|
|
MaxSize: 100, // megabytes
|
|
MaxBackups: 3,
|
|
MaxAge: 28, //days
|
|
}
|
|
userLog := log.StreamHandler(lumberjack, dirFormat)
|
|
|
|
mux := log.MultiHandler(consoleHandler, log.LvlFilterHandler(dirLevel, userLog))
|
|
logger.SetHandler(mux)
|
|
logger.Info("logging to file system", "log dir", dirPath, "file prefix", filePrefix, "log level", dirLevel, "json", dirJson)
|
|
return
|
|
}
|
|
|
|
func tryGetLogLevel(s string) (log.Lvl, error) {
|
|
lvl, err := log.LvlFromString(s)
|
|
if err != nil {
|
|
l, err := strconv.Atoi(s)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return log.Lvl(l), nil
|
|
}
|
|
return lvl, nil
|
|
}
|