From 70772ab99b2cebc00004596b45934b67d2dca4d1 Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Mon, 25 May 2020 18:22:41 +0200 Subject: [PATCH 1/2] config+lnd+rpcserver: use log writer from cfg --- config.go | 17 ++++++++++++++--- lnd.go | 2 +- rpcserver.go | 4 ++-- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/config.go b/config.go index 37c0c63a..8cc0e014 100644 --- a/config.go +++ b/config.go @@ -250,6 +250,10 @@ type Config struct { DB *lncfg.DB `group:"db" namespace:"db"` + // LogWriter is the root logger that all of the daemon's subloggers are + // hooked up to. + LogWriter *build.RotatingLogWriter + // registeredChains keeps track of all chains that have been registered // with the daemon. registeredChains *chainRegistry @@ -360,6 +364,7 @@ func DefaultConfig() Config { }, MaxOutgoingCltvExpiry: htlcswitch.DefaultMaxOutgoingCltvExpiry, MaxChannelFeeAllocation: htlcswitch.DefaultMaxLinkFeeAllocation, + LogWriter: build.NewRotatingLogWriter(), DB: lncfg.DefaultDB(), registeredChains: newChainRegistry(), } @@ -928,15 +933,21 @@ func ValidateConfig(cfg Config, usageMessage string) (*Config, error) { cfg.registeredChains.PrimaryChain().String(), normalizeNetwork(activeNetParams.Name)) + // A log writer must be passed in, otherwise we can't function and would + // run into a panic later on. + if cfg.LogWriter == nil { + return nil, fmt.Errorf("log writer missing in config") + } + // Special show command to list supported subsystems and exit. if cfg.DebugLevel == "show" { fmt.Println("Supported subsystems", - RootLogWriter.SupportedSubsystems()) + cfg.LogWriter.SupportedSubsystems()) os.Exit(0) } // Initialize logging at the default logging level. - err = RootLogWriter.InitLogRotator( + err = cfg.LogWriter.InitLogRotator( filepath.Join(cfg.LogDir, defaultLogFilename), cfg.MaxLogFileSize, cfg.MaxLogFiles, ) @@ -948,7 +959,7 @@ func ValidateConfig(cfg Config, usageMessage string) (*Config, error) { } // Parse, validate, and set debug log level(s). - err = build.ParseAndSetDebugLevels(cfg.DebugLevel, RootLogWriter) + err = build.ParseAndSetDebugLevels(cfg.DebugLevel, cfg.LogWriter) if err != nil { err = fmt.Errorf("%s: %v", funcName, err.Error()) _, _ = fmt.Fprintln(os.Stderr, err) diff --git a/lnd.go b/lnd.go index 75b757b4..47cc4698 100644 --- a/lnd.go +++ b/lnd.go @@ -190,7 +190,7 @@ type rpcListeners func() ([]*ListenerWithSignal, func(), error) func Main(cfg *Config, lisCfg ListenerCfg, shutdownChan <-chan struct{}) error { defer func() { ltndLog.Info("Shutdown complete") - err := RootLogWriter.Close() + err := cfg.LogWriter.Close() if err != nil { ltndLog.Errorf("Could not close log rotator: %v", err) } diff --git a/rpcserver.go b/rpcserver.go index 9399d10f..8237d5da 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -5295,7 +5295,7 @@ func (r *rpcServer) DebugLevel(ctx context.Context, if req.Show { return &lnrpc.DebugLevelResponse{ SubSystems: strings.Join( - RootLogWriter.SupportedSubsystems(), " ", + r.cfg.LogWriter.SupportedSubsystems(), " ", ), }, nil } @@ -5304,7 +5304,7 @@ func (r *rpcServer) DebugLevel(ctx context.Context, // Otherwise, we'll attempt to set the logging level using the // specified level spec. - err := build.ParseAndSetDebugLevels(req.LevelSpec, RootLogWriter) + err := build.ParseAndSetDebugLevels(req.LevelSpec, r.cfg.LogWriter) if err != nil { return nil, err } From 75f916b026de48cb425d68b74ef62041a64425fa Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Mon, 25 May 2020 18:34:00 +0200 Subject: [PATCH 2/2] log+config: remove global RootLogWriter variable --- config.go | 1 + log.go | 161 +++++++++++++++++++++++++++++++----------------------- 2 files changed, 93 insertions(+), 69 deletions(-) diff --git a/config.go b/config.go index 8cc0e014..962db579 100644 --- a/config.go +++ b/config.go @@ -947,6 +947,7 @@ func ValidateConfig(cfg Config, usageMessage string) (*Config, error) { } // Initialize logging at the default logging level. + SetupLoggers(cfg.LogWriter) err = cfg.LogWriter.InitLogRotator( filepath.Join(cfg.LogDir, defaultLogFilename), cfg.MaxLogFileSize, cfg.MaxLogFiles, diff --git a/log.go b/log.go index 83fa239b..4e3eb831 100644 --- a/log.go +++ b/log.go @@ -39,89 +39,112 @@ import ( "google.golang.org/grpc" ) -// Loggers per subsystem. A single backend logger is created and all subsystem -// loggers created from it will write to the backend. When adding new -// subsystems, add the subsystem logger variable here and to the -// subsystemLoggers map. -// +// replaceableLogger is a thin wrapper around a logger that is used so the +// logger can be replaced easily without some black pointer magic. +type replaceableLogger struct { + btclog.Logger + subsystem string +} + // Loggers can not be used before the log rotator has been initialized with a -// log file. This must be performed early during application startup by -// calling RootLogWriter.InitLogRotator. +// log file. This must be performed early during application startup by +// calling InitLogRotator() on the main log writer instance in the config. var ( - // RootLogWriter is the main parent log writer all sub loggers should be - // appended to. - RootLogWriter = build.NewRotatingLogWriter() + // lndPkgLoggers is a list of all lnd package level loggers that are + // registered. They are tracked here so they can be replaced once the + // SetupLoggers function is called with the final root logger. + lndPkgLoggers []*replaceableLogger + + // addLndPkgLogger is a helper function that creates a new replaceable + // main lnd package level logger and adds it to the list of loggers that + // are replaced again later, once the final root logger is ready. + addLndPkgLogger = func(subsystem string) *replaceableLogger { + l := &replaceableLogger{ + Logger: build.NewSubLogger(subsystem, nil), + subsystem: subsystem, + } + lndPkgLoggers = append(lndPkgLoggers, l) + return l + } // Loggers that need to be accessible from the lnd package can be placed // here. Loggers that are only used in sub modules can be added directly - // by using the addSubLogger method. - ltndLog = build.NewSubLogger("LTND", RootLogWriter.GenSubLogger) - peerLog = build.NewSubLogger("PEER", RootLogWriter.GenSubLogger) - rpcsLog = build.NewSubLogger("RPCS", RootLogWriter.GenSubLogger) - srvrLog = build.NewSubLogger("SRVR", RootLogWriter.GenSubLogger) - fndgLog = build.NewSubLogger("FNDG", RootLogWriter.GenSubLogger) - utxnLog = build.NewSubLogger("UTXN", RootLogWriter.GenSubLogger) - brarLog = build.NewSubLogger("BRAR", RootLogWriter.GenSubLogger) - atplLog = build.NewSubLogger("ATPL", RootLogWriter.GenSubLogger) + // by using the addSubLogger method. We declare all loggers so we never + // run into a nil reference if they are used early. But the SetupLoggers + // function should always be called as soon as possible to finish + // setting them up properly with a root logger. + ltndLog = addLndPkgLogger("LTND") + peerLog = addLndPkgLogger("PEER") + rpcsLog = addLndPkgLogger("RPCS") + srvrLog = addLndPkgLogger("SRVR") + fndgLog = addLndPkgLogger("FNDG") + utxnLog = addLndPkgLogger("UTXN") + brarLog = addLndPkgLogger("BRAR") + atplLog = addLndPkgLogger("ATPL") ) -// Initialize package-global logger variables. -func init() { - setSubLogger("LTND", ltndLog, signal.UseLogger) - setSubLogger("ATPL", atplLog, autopilot.UseLogger) - setSubLogger("PEER", peerLog) - setSubLogger("RPCS", rpcsLog) - setSubLogger("SRVR", srvrLog) - setSubLogger("FNDG", fndgLog) - setSubLogger("UTXN", utxnLog) - setSubLogger("BRAR", brarLog) +// SetupLoggers initializes all package-global logger variables. +func SetupLoggers(root *build.RotatingLogWriter) { + // Now that we have the proper root logger, we can replace the + // placeholder lnd package loggers. + for _, l := range lndPkgLoggers { + l.Logger = build.NewSubLogger(l.subsystem, root.GenSubLogger) + SetSubLogger(root, l.subsystem, l.Logger) + } - addSubLogger("LNWL", lnwallet.UseLogger) - addSubLogger("DISC", discovery.UseLogger) - addSubLogger("NTFN", chainntnfs.UseLogger) - addSubLogger("CHDB", channeldb.UseLogger) - addSubLogger("HSWC", htlcswitch.UseLogger) - addSubLogger("CMGR", connmgr.UseLogger) - addSubLogger("BTCN", neutrino.UseLogger) - addSubLogger("CNCT", contractcourt.UseLogger) - addSubLogger("SPHX", sphinx.UseLogger) - addSubLogger("SWPR", sweep.UseLogger) - addSubLogger("SGNR", signrpc.UseLogger) - addSubLogger("WLKT", walletrpc.UseLogger) - addSubLogger("ARPC", autopilotrpc.UseLogger) - addSubLogger("INVC", invoices.UseLogger) - addSubLogger("NANN", netann.UseLogger) - addSubLogger("WTWR", watchtower.UseLogger) - addSubLogger("NTFR", chainrpc.UseLogger) - addSubLogger("IRPC", invoicesrpc.UseLogger) - addSubLogger("CHNF", channelnotifier.UseLogger) - addSubLogger("CHBU", chanbackup.UseLogger) - addSubLogger("PROM", monitoring.UseLogger) - addSubLogger("WTCL", wtclient.UseLogger) - addSubLogger("PRNF", peernotifier.UseLogger) - addSubLogger("CHFD", chanfunding.UseLogger) + // Some of the loggers declared in the main lnd package are also used + // in sub packages. + signal.UseLogger(ltndLog) + autopilot.UseLogger(atplLog) - addSubLogger(routing.Subsystem, routing.UseLogger, localchans.UseLogger) - addSubLogger(routerrpc.Subsystem, routerrpc.UseLogger) - addSubLogger(chanfitness.Subsystem, chanfitness.UseLogger) - addSubLogger(verrpc.Subsystem, verrpc.UseLogger) + AddSubLogger(root, "LNWL", lnwallet.UseLogger) + AddSubLogger(root, "DISC", discovery.UseLogger) + AddSubLogger(root, "NTFN", chainntnfs.UseLogger) + AddSubLogger(root, "CHDB", channeldb.UseLogger) + AddSubLogger(root, "HSWC", htlcswitch.UseLogger) + AddSubLogger(root, "CMGR", connmgr.UseLogger) + AddSubLogger(root, "BTCN", neutrino.UseLogger) + AddSubLogger(root, "CNCT", contractcourt.UseLogger) + AddSubLogger(root, "SPHX", sphinx.UseLogger) + AddSubLogger(root, "SWPR", sweep.UseLogger) + AddSubLogger(root, "SGNR", signrpc.UseLogger) + AddSubLogger(root, "WLKT", walletrpc.UseLogger) + AddSubLogger(root, "ARPC", autopilotrpc.UseLogger) + AddSubLogger(root, "INVC", invoices.UseLogger) + AddSubLogger(root, "NANN", netann.UseLogger) + AddSubLogger(root, "WTWR", watchtower.UseLogger) + AddSubLogger(root, "NTFR", chainrpc.UseLogger) + AddSubLogger(root, "IRPC", invoicesrpc.UseLogger) + AddSubLogger(root, "CHNF", channelnotifier.UseLogger) + AddSubLogger(root, "CHBU", chanbackup.UseLogger) + AddSubLogger(root, "PROM", monitoring.UseLogger) + AddSubLogger(root, "WTCL", wtclient.UseLogger) + AddSubLogger(root, "PRNF", peernotifier.UseLogger) + AddSubLogger(root, "CHFD", chanfunding.UseLogger) + + AddSubLogger(root, routing.Subsystem, routing.UseLogger, localchans.UseLogger) + AddSubLogger(root, routerrpc.Subsystem, routerrpc.UseLogger) + AddSubLogger(root, chanfitness.Subsystem, chanfitness.UseLogger) + AddSubLogger(root, verrpc.Subsystem, verrpc.UseLogger) } -// addSubLogger is a helper method to conveniently create and register the +// AddSubLogger is a helper method to conveniently create and register the // logger of one or more sub systems. -func addSubLogger(subsystem string, useLoggers ...func(btclog.Logger)) { - // Create and register just a single logger to prevent them from - // overwriting each other internally. - logger := build.NewSubLogger(subsystem, RootLogWriter.GenSubLogger) - setSubLogger(subsystem, logger, useLoggers...) -} - -// setSubLogger is a helper method to conveniently register the logger of a sub -// system. -func setSubLogger(subsystem string, logger btclog.Logger, +func AddSubLogger(root *build.RotatingLogWriter, subsystem string, useLoggers ...func(btclog.Logger)) { - RootLogWriter.RegisterSubLogger(subsystem, logger) + // Create and register just a single logger to prevent them from + // overwriting each other internally. + logger := build.NewSubLogger(subsystem, root.GenSubLogger) + SetSubLogger(root, subsystem, logger, useLoggers...) +} + +// SetSubLogger is a helper method to conveniently register the logger of a sub +// system. +func SetSubLogger(root *build.RotatingLogWriter, subsystem string, + logger btclog.Logger, useLoggers ...func(btclog.Logger)) { + + root.RegisterSubLogger(subsystem, logger) for _, useLogger := range useLoggers { useLogger(logger) }