2022-10-20 18:25:06 +00:00
|
|
|
package logging
|
|
|
|
|
|
|
|
import (
|
|
|
|
"flag"
|
|
|
|
"os"
|
2023-04-07 21:08:44 +00:00
|
|
|
"path/filepath"
|
2022-10-20 18:25:06 +00:00
|
|
|
"strconv"
|
|
|
|
|
|
|
|
"github.com/ledgerwatch/log/v3"
|
|
|
|
"github.com/spf13/cobra"
|
2022-11-14 16:33:57 +00:00
|
|
|
"github.com/urfave/cli/v2"
|
2023-04-07 21:08:44 +00:00
|
|
|
"gopkg.in/natefinch/lumberjack.v2"
|
2022-10-20 18:25:06 +00:00
|
|
|
)
|
|
|
|
|
2023-05-07 06:28:15 +00:00
|
|
|
// 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
|
2023-12-27 22:05:09 +00:00
|
|
|
func SetupLoggerCtx(filePrefix string, ctx *cli.Context,
|
|
|
|
consoleDefaultLevel log.Lvl, dirDefaultLevel log.Lvl, rootHandler bool) log.Logger {
|
2022-10-20 18:25:06 +00:00
|
|
|
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 {
|
2023-12-27 22:05:09 +00:00
|
|
|
consoleLevel = consoleDefaultLevel
|
2022-10-20 18:25:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
dirLevel, dErr := tryGetLogLevel(ctx.String(LogDirVerbosityFlag.Name))
|
|
|
|
if dErr != nil {
|
2023-12-27 22:05:09 +00:00
|
|
|
dirLevel = dirDefaultLevel
|
2022-10-20 18:25:06 +00:00
|
|
|
}
|
|
|
|
|
2023-12-04 04:11:11 +00:00
|
|
|
dirPath := ""
|
|
|
|
if !ctx.Bool(LogDirDisableFlag.Name) && dirPath != "/dev/null" {
|
|
|
|
dirPath = ctx.String(LogDirPathFlag.Name)
|
|
|
|
if dirPath == "" {
|
|
|
|
datadir := ctx.String("datadir")
|
|
|
|
if datadir != "" {
|
|
|
|
dirPath = filepath.Join(datadir, "logs")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if logDirPrefix := ctx.String(LogDirPrefixFlag.Name); len(logDirPrefix) > 0 {
|
|
|
|
filePrefix = logDirPrefix
|
2023-04-07 21:08:44 +00:00
|
|
|
}
|
|
|
|
}
|
2023-12-04 04:11:11 +00:00
|
|
|
|
2023-05-07 06:28:15 +00:00
|
|
|
var logger log.Logger
|
|
|
|
if rootHandler {
|
|
|
|
logger = log.Root()
|
|
|
|
} else {
|
|
|
|
logger = log.New()
|
|
|
|
}
|
2023-06-12 14:30:05 +00:00
|
|
|
|
2023-05-07 06:28:15 +00:00
|
|
|
initSeparatedLogging(logger, filePrefix, dirPath, consoleLevel, dirLevel, consoleJson, dirJson)
|
|
|
|
return logger
|
2022-10-20 18:25:06 +00:00
|
|
|
}
|
|
|
|
|
2023-05-07 06:28:15 +00:00
|
|
|
// 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 {
|
2022-10-20 18:25:06 +00:00
|
|
|
|
|
|
|
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 {
|
2023-04-07 21:08:44 +00:00
|
|
|
dirLevel = log.LvlInfo
|
2022-10-20 18:25:06 +00:00
|
|
|
}
|
|
|
|
|
2023-12-04 04:11:11 +00:00
|
|
|
dirPath := ""
|
|
|
|
disableFileLogging, err := cmd.Flags().GetBool(LogDirDisableFlag.Name)
|
|
|
|
if err != nil {
|
|
|
|
disableFileLogging = false
|
|
|
|
}
|
|
|
|
if !disableFileLogging && dirPath != "/dev/null" {
|
|
|
|
dirPath = cmd.Flags().Lookup(LogDirPathFlag.Name).Value.String()
|
|
|
|
if dirPath == "" {
|
|
|
|
datadirFlag := cmd.Flags().Lookup("datadir")
|
|
|
|
if datadirFlag != nil {
|
|
|
|
datadir := datadirFlag.Value.String()
|
|
|
|
if datadir != "" {
|
|
|
|
dirPath = filepath.Join(datadir, "logs")
|
|
|
|
}
|
2023-11-27 01:49:19 +00:00
|
|
|
}
|
2023-04-07 21:08:44 +00:00
|
|
|
}
|
2023-12-04 04:11:11 +00:00
|
|
|
if logDirPrefix := cmd.Flags().Lookup(LogDirPrefixFlag.Name).Value.String(); len(logDirPrefix) > 0 {
|
|
|
|
filePrefix = logDirPrefix
|
|
|
|
}
|
2023-06-12 14:30:05 +00:00
|
|
|
}
|
|
|
|
|
2023-05-07 06:28:15 +00:00
|
|
|
initSeparatedLogging(log.Root(), filePrefix, dirPath, consoleLevel, dirLevel, consoleJson, dirJson)
|
|
|
|
return log.Root()
|
2022-10-20 18:25:06 +00:00
|
|
|
}
|
|
|
|
|
2023-05-07 06:28:15 +00:00
|
|
|
// 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
|
2023-05-19 17:41:53 +00:00
|
|
|
func SetupLogger(filePrefix string) log.Logger {
|
2022-10-20 18:25:06 +00:00
|
|
|
var logConsoleVerbosity = flag.String(LogConsoleVerbosityFlag.Name, "", LogConsoleVerbosityFlag.Usage)
|
|
|
|
var logDirVerbosity = flag.String(LogDirVerbosityFlag.Name, "", LogDirVerbosityFlag.Usage)
|
|
|
|
var logDirPath = flag.String(LogDirPathFlag.Name, "", LogDirPathFlag.Usage)
|
2023-06-12 14:30:05 +00:00
|
|
|
var logDirPrefix = flag.String(LogDirPrefixFlag.Name, "", LogDirPrefixFlag.Usage)
|
2022-10-20 18:25:06 +00:00
|
|
|
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 {
|
2023-04-07 21:08:44 +00:00
|
|
|
dirLevel = log.LvlInfo
|
2022-10-20 18:25:06 +00:00
|
|
|
}
|
|
|
|
|
2023-06-12 14:30:05 +00:00
|
|
|
if logDirPrefix != nil && len(*logDirPrefix) > 0 {
|
|
|
|
filePrefix = *logDirPrefix
|
|
|
|
}
|
|
|
|
|
2023-05-07 06:28:15 +00:00
|
|
|
initSeparatedLogging(log.Root(), filePrefix, *logDirPath, consoleLevel, dirLevel, consoleJson, *dirJson)
|
2023-05-19 17:41:53 +00:00
|
|
|
return log.Root()
|
2022-10-20 18:25:06 +00:00
|
|
|
}
|
|
|
|
|
2023-05-07 06:28:15 +00:00
|
|
|
// 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
|
2022-10-20 18:25:06 +00:00
|
|
|
func initSeparatedLogging(
|
2023-05-07 06:28:15 +00:00
|
|
|
logger log.Logger,
|
2022-10-20 18:25:06 +00:00
|
|
|
filePrefix string,
|
|
|
|
dirPath string,
|
|
|
|
consoleLevel log.Lvl,
|
|
|
|
dirLevel log.Lvl,
|
|
|
|
consoleJson bool,
|
2023-04-07 21:08:44 +00:00
|
|
|
dirJson bool) {
|
2022-10-20 18:25:06 +00:00
|
|
|
|
2023-05-07 06:28:15 +00:00
|
|
|
var consoleHandler log.Handler
|
2022-10-20 18:25:06 +00:00
|
|
|
|
|
|
|
if consoleJson {
|
2023-05-07 06:28:15 +00:00
|
|
|
consoleHandler = log.LvlFilterHandler(consoleLevel, log.StreamHandler(os.Stderr, log.JsonFormat()))
|
2022-10-20 18:25:06 +00:00
|
|
|
} else {
|
2023-05-07 06:28:15 +00:00
|
|
|
consoleHandler = log.LvlFilterHandler(consoleLevel, log.StderrHandler)
|
2022-10-20 18:25:06 +00:00
|
|
|
}
|
2023-05-07 06:28:15 +00:00
|
|
|
logger.SetHandler(consoleHandler)
|
2022-10-20 18:25:06 +00:00
|
|
|
|
|
|
|
if len(dirPath) == 0 {
|
2023-12-04 04:11:11 +00:00
|
|
|
logger.Info("console logging only")
|
2023-04-07 21:08:44 +00:00
|
|
|
return
|
2022-10-20 18:25:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
err := os.MkdirAll(dirPath, 0764)
|
|
|
|
if err != nil {
|
|
|
|
logger.Warn("failed to create log dir, console logging only")
|
2023-04-07 21:08:44 +00:00
|
|
|
return
|
2022-10-20 18:25:06 +00:00
|
|
|
}
|
|
|
|
|
2023-04-07 21:08:44 +00:00
|
|
|
dirFormat := log.TerminalFormatNoColor()
|
2022-10-20 18:25:06 +00:00
|
|
|
if dirJson {
|
|
|
|
dirFormat = log.JsonFormat()
|
|
|
|
}
|
|
|
|
|
2023-04-07 21:08:44 +00:00
|
|
|
lumberjack := &lumberjack.Logger{
|
2023-12-27 22:05:09 +00:00
|
|
|
Filename: filepath.Join(dirPath, filePrefix+".log"),
|
2023-04-07 21:08:44 +00:00
|
|
|
MaxSize: 100, // megabytes
|
|
|
|
MaxBackups: 3,
|
|
|
|
MaxAge: 28, //days
|
2022-10-20 18:25:06 +00:00
|
|
|
}
|
2023-04-07 21:08:44 +00:00
|
|
|
userLog := log.StreamHandler(lumberjack, dirFormat)
|
2022-10-20 18:25:06 +00:00
|
|
|
|
2023-05-07 06:28:15 +00:00
|
|
|
mux := log.MultiHandler(consoleHandler, log.LvlFilterHandler(dirLevel, userLog))
|
|
|
|
logger.SetHandler(mux)
|
2022-10-20 18:25:06 +00:00
|
|
|
logger.Info("logging to file system", "log dir", dirPath, "file prefix", filePrefix, "log level", dirLevel, "json", dirJson)
|
2023-05-07 06:28:15 +00:00
|
|
|
return
|
2022-10-20 18:25:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|