diff --git a/autopilot/log.go b/autopilot/log.go index 34e53c8462..1d86eb5254 100644 --- a/autopilot/log.go +++ b/autopilot/log.go @@ -1,7 +1,7 @@ package autopilot import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/build/config.go b/build/config.go new file mode 100644 index 0000000000..66a0b31444 --- /dev/null +++ b/build/config.go @@ -0,0 +1,65 @@ +//go:build !dev +// +build !dev + +package build + +import "github.com/btcsuite/btclog/v2" + +const ( + callSiteOff = "off" + callSiteShort = "short" + callSiteLong = "long" +) + +// LogConfig holds logging configuration options. +// +//nolint:lll +type LogConfig struct { + Console *LoggerConfig `group:"console" namespace:"console" description:"The logger writing to stdout and stderr."` + File *LoggerConfig `group:"file" namespace:"file" description:"The logger writing to LND's standard log file."` +} + +// DefaultLogConfig returns the default logging config options. +func DefaultLogConfig() *LogConfig { + return &LogConfig{ + Console: &LoggerConfig{ + CallSite: callSiteOff, + }, + File: &LoggerConfig{ + CallSite: callSiteOff, + }, + } +} + +// LoggerConfig holds options for a particular logger. +// +//nolint:lll +type LoggerConfig struct { + Disable bool `long:"disable" description:"Disable this logger."` + NoTimestamps bool `long:"no-timestamps" description:"Omit timestamps from log lines."` + CallSite string `long:"call-site" description:"Include the call-site of each log line." choice:"off" choice:"short" choice:"long"` +} + +// HandlerOptions returns the set of btclog.HandlerOptions that the state of the +// config struct translates to. +func (cfg *LoggerConfig) HandlerOptions() []btclog.HandlerOption { + opts := []btclog.HandlerOption{ + // The default skip depth used by the logging library is 6 but + // since we wrap the logging handlers with another level of + // abstraction with the handlerSet, we increase the skip depth + // to 7 here. + btclog.WithCallSiteSkipDepth(7), + } + if cfg.NoTimestamps { + opts = append(opts, btclog.WithNoTimestamp()) + } + + switch cfg.CallSite { + case callSiteShort: + opts = append(opts, btclog.WithCallerFlags(btclog.Lshortfile)) + case callSiteLong: + opts = append(opts, btclog.WithCallerFlags(btclog.Llongfile)) + } + + return opts +} diff --git a/build/config_dev.go b/build/config_dev.go new file mode 100644 index 0000000000..daa5b1fde2 --- /dev/null +++ b/build/config_dev.go @@ -0,0 +1,162 @@ +//go:build dev +// +build dev + +package build + +import ( + "fmt" + "strings" + + btclogv1 "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" +) + +const ( + resetSeq = "0" + boldSeq = "1" + faintSeq = "2" + esc = '\x1b' + csi = string(esc) + "[" + + callSiteOff = "off" + callSiteShort = "short" + callSiteLong = "long" +) + +// LogConfig holds logging configuration options. +// +//nolint:lll +type LogConfig struct { + Console *consoleLoggerCfg `group:"console" namespace:"console" description:"The logger writing to stdout and stderr."` + File *LoggerConfig `group:"file" namespace:"file" description:"The logger writing to LND's standard log file."` +} + +// DefaultLogConfig returns the default logging config options. +func DefaultLogConfig() *LogConfig { + return &LogConfig{ + Console: &consoleLoggerCfg{ + LoggerConfig: LoggerConfig{ + CallSite: callSiteShort, + }, + }, + File: &LoggerConfig{ + CallSite: callSiteOff, + }, + } +} + +// LoggerConfig holds options for a particular logger. +// +//nolint:lll +type LoggerConfig struct { + Disable bool `long:"disable" description:"Disable this logger."` + NoTimestamps bool `long:"no-timestamps" description:"Omit timestamps from log lines."` + CallSite string `long:"call-site" description:"Include the call-site of each log line." choice:"off" choice:"short" choice:"long"` +} + +// HandlerOptions returns the set of btclog.HandlerOptions that the state of the +// config struct translates to. +func (cfg *LoggerConfig) HandlerOptions() []btclog.HandlerOption { + opts := []btclog.HandlerOption{ + // The default skip depth used by the logging library is 6 but + // since we wrap the logging handlers with another level of + // abstraction with the handlerSet, we increase the skip depth + // to 7 here. + btclog.WithCallSiteSkipDepth(7), + } + + if cfg.NoTimestamps { + opts = append(opts, btclog.WithNoTimestamp()) + } + + switch cfg.CallSite { + case callSiteShort: + opts = append(opts, btclog.WithCallerFlags(btclog.Lshortfile)) + case callSiteLong: + opts = append(opts, btclog.WithCallerFlags(btclog.Llongfile)) + } + + return opts +} + +// consoleLoggerCfg extends the LoggerConfig struct by adding a Color option +// which is only available for a console logger. +// +//nolint:lll +type consoleLoggerCfg struct { + LoggerConfig + Style bool `long:"style" description:"If set, the output will be styled with color and fonts"` +} + +// HandlerOptions returns the set of btclog.HandlerOptions that the state of the +// config struct translates to. +func (cfg *consoleLoggerCfg) HandlerOptions() []btclog.HandlerOption { + opts := cfg.LoggerConfig.HandlerOptions() + + if !cfg.Style { + return opts + } + + return append( + opts, btclog.WithStyledLevel( + func(l btclogv1.Level) string { + return styleString( + fmt.Sprintf("[%s]", l), + boldSeq, + string(ansiColoSeq(l)), + ) + }, + ), + btclog.WithStyledCallSite( + func(file string, line int) string { + str := fmt.Sprintf("%s:%d", file, line) + + return styleString(str, faintSeq) + }, + ), + btclog.WithStyledKeys(func(key string) string { + return styleString(key, faintSeq) + }), + ) +} + +func styleString(s string, styles ...string) string { + if len(styles) == 0 { + return s + } + + seq := strings.Join(styles, ";") + if seq == "" { + return s + } + + return fmt.Sprintf("%s%sm%s%sm", csi, seq, s, csi+resetSeq) +} + +type ansiColorSeq string + +const ( + ansiColorSeqDarkTeal ansiColorSeq = "38;5;30" + ansiColorSeqDarkBlue ansiColorSeq = "38;5;63" + ansiColorSeqLightBlue ansiColorSeq = "38;5;86" + ansiColorSeqYellow ansiColorSeq = "38;5;192" + ansiColorSeqRed ansiColorSeq = "38;5;204" + ansiColorSeqPink ansiColorSeq = "38;5;134" +) + +func ansiColoSeq(l btclogv1.Level) ansiColorSeq { + switch l { + case btclog.LevelTrace: + return ansiColorSeqDarkTeal + case btclog.LevelDebug: + return ansiColorSeqDarkBlue + case btclog.LevelWarn: + return ansiColorSeqYellow + case btclog.LevelError: + return ansiColorSeqRed + case btclog.LevelCritical: + return ansiColorSeqPink + default: + return ansiColorSeqLightBlue + } +} diff --git a/build/handler_sets.go b/build/handler_sets.go new file mode 100644 index 0000000000..d9786a8580 --- /dev/null +++ b/build/handler_sets.go @@ -0,0 +1,201 @@ +package build + +import ( + "context" + "log/slog" + + btclogv1 "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" +) + +// handlerSet is an implementation of Handler that abstracts away multiple +// Handlers. +type handlerSet struct { + level btclogv1.Level + set []btclog.Handler +} + +// newHandlerSet constructs a new HandlerSet. +func newHandlerSet(level btclogv1.Level, set ...btclog.Handler) *handlerSet { + h := &handlerSet{ + set: set, + level: level, + } + h.SetLevel(level) + + return h +} + +// Enabled reports whether the handler handles records at the given level. +// +// NOTE: this is part of the slog.Handler interface. +func (h *handlerSet) Enabled(ctx context.Context, level slog.Level) bool { + for _, handler := range h.set { + if !handler.Enabled(ctx, level) { + return false + } + } + + return true +} + +// Handle handles the Record. +// +// NOTE: this is part of the slog.Handler interface. +func (h *handlerSet) Handle(ctx context.Context, record slog.Record) error { + for _, handler := range h.set { + if err := handler.Handle(ctx, record); err != nil { + return err + } + } + + return nil +} + +// WithAttrs returns a new Handler whose attributes consist of both the +// receiver's attributes and the arguments. +// +// NOTE: this is part of the slog.Handler interface. +func (h *handlerSet) WithAttrs(attrs []slog.Attr) slog.Handler { + newSet := &reducedSet{set: make([]slog.Handler, len(h.set))} + for i, handler := range h.set { + newSet.set[i] = handler.WithAttrs(attrs) + } + + return newSet +} + +// WithGroup returns a new Handler with the given group appended to the +// receiver's existing groups. +// +// NOTE: this is part of the slog.Handler interface. +func (h *handlerSet) WithGroup(name string) slog.Handler { + newSet := &reducedSet{set: make([]slog.Handler, len(h.set))} + for i, handler := range h.set { + newSet.set[i] = handler.WithGroup(name) + } + + return newSet +} + +// SubSystem creates a new Handler with the given sub-system tag. +// +// NOTE: this is part of the Handler interface. +func (h *handlerSet) SubSystem(tag string) btclog.Handler { + newSet := &handlerSet{set: make([]btclog.Handler, len(h.set))} + for i, handler := range h.set { + newSet.set[i] = handler.SubSystem(tag) + } + + return newSet +} + +// SetLevel changes the logging level of the Handler to the passed +// level. +// +// NOTE: this is part of the btclog.Handler interface. +func (h *handlerSet) SetLevel(level btclogv1.Level) { + for _, handler := range h.set { + handler.SetLevel(level) + } + h.level = level +} + +// Level returns the current logging level of the Handler. +// +// NOTE: this is part of the btclog.Handler interface. +func (h *handlerSet) Level() btclogv1.Level { + return h.level +} + +// A compile-time check to ensure that handlerSet implements btclog.Handler. +var _ btclog.Handler = (*handlerSet)(nil) + +// reducedSet is an implementation of the slog.Handler interface which is +// itself backed by multiple slog.Handlers. This is used by the handlerSet +// WithGroup and WithAttrs methods so that we can apply the WithGroup and +// WithAttrs to the underlying handlers in the set. These calls, however, +// produce slog.Handlers and not btclog.Handlers. So the reducedSet represents +// the resulting set produced. +type reducedSet struct { + set []slog.Handler +} + +// Enabled reports whether the handler handles records at the given level. +// +// NOTE: this is part of the slog.Handler interface. +func (r *reducedSet) Enabled(ctx context.Context, level slog.Level) bool { + for _, handler := range r.set { + if !handler.Enabled(ctx, level) { + return false + } + } + + return true +} + +// Handle handles the Record. +// +// NOTE: this is part of the slog.Handler interface. +func (r *reducedSet) Handle(ctx context.Context, record slog.Record) error { + for _, handler := range r.set { + if err := handler.Handle(ctx, record); err != nil { + return err + } + } + + return nil +} + +// WithAttrs returns a new Handler whose attributes consist of both the +// receiver's attributes and the arguments. +// +// NOTE: this is part of the slog.Handler interface. +func (r *reducedSet) WithAttrs(attrs []slog.Attr) slog.Handler { + newSet := &reducedSet{set: make([]slog.Handler, len(r.set))} + for i, handler := range r.set { + newSet.set[i] = handler.WithAttrs(attrs) + } + + return newSet +} + +// WithGroup returns a new Handler with the given group appended to the +// receiver's existing groups. +// +// NOTE: this is part of the slog.Handler interface. +func (r *reducedSet) WithGroup(name string) slog.Handler { + newSet := &reducedSet{set: make([]slog.Handler, len(r.set))} + for i, handler := range r.set { + newSet.set[i] = handler.WithGroup(name) + } + + return newSet +} + +// A compile-time check to ensure that handlerSet implements slog.Handler. +var _ slog.Handler = (*reducedSet)(nil) + +// subLogGenerator implements the SubLogCreator backed by a Handler. +type subLogGenerator struct { + handler btclog.Handler +} + +// newSubLogGenerator constructs a new subLogGenerator from a Handler. +func newSubLogGenerator(handler btclog.Handler) *subLogGenerator { + return &subLogGenerator{ + handler: handler, + } +} + +// Logger returns a new logger for a particular sub-system. +// +// NOTE: this is part of the SubLogCreator interface. +func (b *subLogGenerator) Logger(subsystemTag string) btclog.Logger { + handler := b.handler.SubSystem(subsystemTag) + + return btclog.NewSLogger(handler) +} + +// A compile-time check to ensure that handlerSet implements slog.Handler. +var _ SubLogCreator = (*subLogGenerator)(nil) diff --git a/build/handlers.go b/build/handlers.go new file mode 100644 index 0000000000..9ffbdd70a6 --- /dev/null +++ b/build/handlers.go @@ -0,0 +1,23 @@ +package build + +import ( + "os" + + "github.com/btcsuite/btclog/v2" +) + +// NewDefaultLogHandlers returns the standard console logger and rotating log +// writer handlers that we generally want to use. It also applies the various +// config options to the loggers. +func NewDefaultLogHandlers(cfg *LogConfig, rotator *RotatingLogWriter) ( + btclog.Handler, btclog.Handler) { + + consoleLogHandler := btclog.NewDefaultHandler( + os.Stdout, cfg.Console.HandlerOptions()..., + ) + logFileHandler := btclog.NewDefaultHandler( + rotator, cfg.File.HandlerOptions()..., + ) + + return consoleLogHandler, logFileHandler +} diff --git a/build/log.go b/build/log.go index 484b48e422..568f9f618c 100644 --- a/build/log.go +++ b/build/log.go @@ -1,11 +1,9 @@ package build import ( - "fmt" - "io" - "strings" + "os" - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" ) // LogType is an indicating the type of logging specified by the build flag. @@ -62,17 +60,6 @@ func SuportedLogCompressor(logCompressor string) bool { return ok } -// LogWriter is a stub type whose behavior can be changed using the build flags -// "stdlog" and "nolog". The default behavior is to write to both stdout and the -// RotatorPipe. Passing "stdlog" will cause it only to write to stdout, and -// "nolog" implements Write as a no-op. -type LogWriter struct { - // RotatorPipe is the write-end pipe for writing to the log rotator. It - // is written to by the Write method of the LogWriter type. This only - // needs to be set if neither the stdlog or nolog builds are set. - RotatorPipe *io.PipeWriter -} - // NewSubLogger constructs a new subsystem log from the current LogWriter // implementation. This is primarily intended for use with stdlog, as the actual // writer is shared amongst all instantiations. @@ -106,8 +93,10 @@ func NewSubLogger(subsystem string, // that they share the same backend, since all output is written // to std out. case LogTypeStdOut: - backend := btclog.NewBackend(&LogWriter{}) - logger := backend.Logger(subsystem) + backend := btclog.NewDefaultHandler(os.Stdout) + logger := btclog.NewSLogger( + backend.SubSystem(subsystem), + ) // Set the logging level of the stdout logger to use the // configured logging level specified by build flags. @@ -121,114 +110,3 @@ func NewSubLogger(subsystem string, // For any other configurations, we'll disable logging. return btclog.Disabled } - -// SubLoggers is a type that holds a map of subsystem loggers keyed by their -// subsystem name. -type SubLoggers map[string]btclog.Logger - -// LeveledSubLogger provides the ability to retrieve the subsystem loggers of -// a logger and set their log levels individually or all at once. -type LeveledSubLogger interface { - // SubLoggers returns the map of all registered subsystem loggers. - SubLoggers() SubLoggers - - // SupportedSubsystems returns a slice of strings containing the names - // of the supported subsystems. Should ideally correspond to the keys - // of the subsystem logger map and be sorted. - SupportedSubsystems() []string - - // SetLogLevel assigns an individual subsystem logger a new log level. - SetLogLevel(subsystemID string, logLevel string) - - // SetLogLevels assigns all subsystem loggers the same new log level. - SetLogLevels(logLevel string) -} - -// ParseAndSetDebugLevels attempts to parse the specified debug level and set -// the levels accordingly on the given logger. An appropriate error is returned -// if anything is invalid. -func ParseAndSetDebugLevels(level string, logger LeveledSubLogger) error { - // Split at the delimiter. - levels := strings.Split(level, ",") - if len(levels) == 0 { - return fmt.Errorf("invalid log level: %v", level) - } - - // If the first entry has no =, treat is as the log level for all - // subsystems. - globalLevel := levels[0] - if !strings.Contains(globalLevel, "=") { - // Validate debug log level. - if !validLogLevel(globalLevel) { - str := "the specified debug level [%v] is invalid" - return fmt.Errorf(str, globalLevel) - } - - // Change the logging level for all subsystems. - logger.SetLogLevels(globalLevel) - - // The rest will target specific subsystems. - levels = levels[1:] - } - - // Go through the subsystem/level pairs while detecting issues and - // update the log levels accordingly. - for _, logLevelPair := range levels { - if !strings.Contains(logLevelPair, "=") { - str := "the specified debug level contains an " + - "invalid subsystem/level pair [%v]" - return fmt.Errorf(str, logLevelPair) - } - - // Extract the specified subsystem and log level. - fields := strings.Split(logLevelPair, "=") - if len(fields) != 2 { - str := "the specified debug level has an invalid " + - "format [%v] -- use format subsystem1=level1," + - "subsystem2=level2" - return fmt.Errorf(str, logLevelPair) - } - subsysID, logLevel := fields[0], fields[1] - subLoggers := logger.SubLoggers() - - // Validate subsystem. - if _, exists := subLoggers[subsysID]; !exists { - str := "the specified subsystem [%v] is invalid -- " + - "supported subsystems are %v" - return fmt.Errorf( - str, subsysID, logger.SupportedSubsystems(), - ) - } - - // Validate log level. - if !validLogLevel(logLevel) { - str := "the specified debug level [%v] is invalid" - return fmt.Errorf(str, logLevel) - } - - logger.SetLogLevel(subsysID, logLevel) - } - - return nil -} - -// validLogLevel returns whether or not logLevel is a valid debug log level. -func validLogLevel(logLevel string) bool { - switch logLevel { - case "trace": - fallthrough - case "debug": - fallthrough - case "info": - fallthrough - case "warn": - fallthrough - case "error": - fallthrough - case "critical": - fallthrough - case "off": - return true - } - return false -} diff --git a/build/log_default.go b/build/log_default.go index bbb6d4c390..6e027e0dd0 100644 --- a/build/log_default.go +++ b/build/log_default.go @@ -3,17 +3,6 @@ package build -import "os" - // LoggingType is a log type that writes to both stdout and the log rotator, if // present. const LoggingType = LogTypeDefault - -// Write writes the byte slice to both stdout and the log rotator, if present. -func (w *LogWriter) Write(b []byte) (int, error) { - os.Stdout.Write(b) - if w.RotatorPipe != nil { - w.RotatorPipe.Write(b) - } - return len(b), nil -} diff --git a/build/log_nolog.go b/build/log_nolog.go index 32199ada00..75f17bf66b 100644 --- a/build/log_nolog.go +++ b/build/log_nolog.go @@ -5,8 +5,3 @@ package build // LoggingType is a log type that writes no logs. const LoggingType = LogTypeNone - -// Write is a noop. -func (w *LogWriter) Write(b []byte) (int, error) { - return len(b), nil -} diff --git a/build/log_shutdown.go b/build/log_shutdown.go index e5a63410bc..dfabe1cb6f 100644 --- a/build/log_shutdown.go +++ b/build/log_shutdown.go @@ -1,7 +1,9 @@ package build import ( - "github.com/btcsuite/btclog" + "context" + + "github.com/btcsuite/btclog/v2" ) // ShutdownLogger wraps an existing logger with a shutdown function which will @@ -41,3 +43,16 @@ func (s *ShutdownLogger) Critical(v ...interface{}) { s.Logger.Info("Sending request for shutdown") s.shutdown() } + +// CriticalS writes a structured log with the given message and key-value pair +// attributes with LevelCritical to the log. It will then call the shutdown +// logger's shutdown function to prompt safe shutdown. +// +// Note: it is part of the btclog.Logger interface. +func (s *ShutdownLogger) CriticalS(ctx context.Context, msg string, err error, + attr ...interface{}) { + + s.Logger.CriticalS(ctx, msg, err, attr...) + s.Logger.Info("Sending request for shutdown") + s.shutdown() +} diff --git a/build/log_stdlog.go b/build/log_stdlog.go index 34a8c1bf02..461474376d 100644 --- a/build/log_stdlog.go +++ b/build/log_stdlog.go @@ -3,13 +3,5 @@ package build -import "os" - // LoggingType is a log type that only writes to stdout. const LoggingType = LogTypeStdOut - -// Write writes the provided byte slice to stdout. -func (w *LogWriter) Write(b []byte) (int, error) { - os.Stdout.Write(b) - return len(b), nil -} diff --git a/build/log_test.go b/build/log_test.go index 001b8e08b3..dbce428e40 100644 --- a/build/log_test.go +++ b/build/log_test.go @@ -3,7 +3,7 @@ package build_test import ( "testing" - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" "github.com/stretchr/testify/require" ) diff --git a/build/logrotator.go b/build/logrotator.go index aa4683bba2..2ae105fde0 100644 --- a/build/logrotator.go +++ b/build/logrotator.go @@ -6,9 +6,7 @@ import ( "io" "os" "path/filepath" - "sort" - "github.com/btcsuite/btclog" "github.com/jrick/logrotate/rotator" "github.com/klauspost/compress/zstd" ) @@ -16,45 +14,18 @@ import ( // RotatingLogWriter is a wrapper around the LogWriter that supports log file // rotation. type RotatingLogWriter struct { - logWriter *LogWriter + // pipe is the write-end pipe for writing to the log rotator. + pipe *io.PipeWriter - backendLog *btclog.Backend - - logRotator *rotator.Rotator - - subsystemLoggers SubLoggers + rotator *rotator.Rotator } -// A compile time check to ensure RotatingLogWriter implements the -// LeveledSubLogger interface. -var _ LeveledSubLogger = (*RotatingLogWriter)(nil) - // NewRotatingLogWriter creates a new file rotating log writer. // // NOTE: `InitLogRotator` must be called to set up log rotation after creating // the writer. func NewRotatingLogWriter() *RotatingLogWriter { - logWriter := &LogWriter{} - backendLog := btclog.NewBackend(logWriter) - return &RotatingLogWriter{ - logWriter: logWriter, - backendLog: backendLog, - subsystemLoggers: SubLoggers{}, - } -} - -// GenSubLogger creates a new sublogger. A shutdown callback function -// is provided to be able to shutdown in case of a critical error. -func (r *RotatingLogWriter) GenSubLogger(tag string, shutdown func()) btclog.Logger { - logger := r.backendLog.Logger(tag) - return NewShutdownLogger(logger, shutdown) -} - -// RegisterSubLogger registers a new subsystem logger. -func (r *RotatingLogWriter) RegisterSubLogger(subsystem string, - logger btclog.Logger) { - - r.subsystemLoggers[subsystem] = logger + return &RotatingLogWriter{} } // InitLogRotator initializes the log file rotator to write logs to logFile and @@ -68,7 +39,8 @@ func (r *RotatingLogWriter) InitLogRotator(logFile, logCompressor string, if err != nil { return fmt.Errorf("failed to create log directory: %w", err) } - r.logRotator, err = rotator.New( + + r.rotator, err = rotator.New( logFile, int64(maxLogFileSize*1024), false, maxLogFiles, ) if err != nil { @@ -94,7 +66,7 @@ func (r *RotatingLogWriter) InitLogRotator(logFile, logCompressor string, } // Apply the compressor and its file suffix to the log rotator. - r.logRotator.SetCompressor(c, logCompressors[logCompressor]) + r.rotator.SetCompressor(c, logCompressors[logCompressor]) // Run rotator as a goroutine now but make sure we catch any errors // that happen in case something with the rotation goes wrong during @@ -102,75 +74,32 @@ func (r *RotatingLogWriter) InitLogRotator(logFile, logCompressor string, // create a new logfile for whatever reason). pr, pw := io.Pipe() go func() { - err := r.logRotator.Run(pr) + err := r.rotator.Run(pr) if err != nil { _, _ = fmt.Fprintf(os.Stderr, "failed to run file rotator: %v\n", err) } }() - r.logWriter.RotatorPipe = pw - return nil -} + r.pipe = pw -// Close closes the underlying log rotator if it has already been created. -func (r *RotatingLogWriter) Close() error { - if r.logRotator != nil { - return r.logRotator.Close() - } return nil } -// SubLoggers returns all currently registered subsystem loggers for this log -// writer. -// -// NOTE: This is part of the LeveledSubLogger interface. -func (r *RotatingLogWriter) SubLoggers() SubLoggers { - return r.subsystemLoggers -} - -// SupportedSubsystems returns a sorted string slice of all keys in the -// subsystems map, corresponding to the names of the subsystems. -// -// NOTE: This is part of the LeveledSubLogger interface. -func (r *RotatingLogWriter) SupportedSubsystems() []string { - // Convert the subsystemLoggers map keys to a string slice. - subsystems := make([]string, 0, len(r.subsystemLoggers)) - for subsysID := range r.subsystemLoggers { - subsystems = append(subsystems, subsysID) +// Write writes the byte slice to the log rotator, if present. +func (r *RotatingLogWriter) Write(b []byte) (int, error) { + if r.rotator != nil { + return r.rotator.Write(b) } - // Sort the subsystems for stable display. - sort.Strings(subsystems) - return subsystems + return len(b), nil } -// SetLogLevel sets the logging level for provided subsystem. Invalid -// subsystems are ignored. Uninitialized subsystems are dynamically created as -// needed. -// -// NOTE: This is part of the LeveledSubLogger interface. -func (r *RotatingLogWriter) SetLogLevel(subsystemID string, logLevel string) { - // Ignore invalid subsystems. - logger, ok := r.subsystemLoggers[subsystemID] - if !ok { - return +// Close closes the underlying log rotator if it has already been created. +func (r *RotatingLogWriter) Close() error { + if r.rotator != nil { + return r.rotator.Close() } - // Defaults to info if the log level is invalid. - level, _ := btclog.LevelFromString(logLevel) - logger.SetLevel(level) -} - -// SetLogLevels sets the log level for all subsystem loggers to the passed -// level. It also dynamically creates the subsystem loggers as needed, so it -// can be used to initialize the logging system. -// -// NOTE: This is part of the LeveledSubLogger interface. -func (r *RotatingLogWriter) SetLogLevels(logLevel string) { - // Configure all sub-systems with the new logging level. Dynamically - // create loggers as needed. - for subsystemID := range r.subsystemLoggers { - r.SetLogLevel(subsystemID, logLevel) - } + return nil } diff --git a/build/prefix_log.go b/build/prefix_log.go index 926b3f58f3..3db114ffcf 100644 --- a/build/prefix_log.go +++ b/build/prefix_log.go @@ -1,18 +1,25 @@ package build -import "github.com/btcsuite/btclog" +import ( + "context" + + btclogv1 "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" +) // PrefixLog is a pass-through logger that adds a prefix to every logged line. type PrefixLog struct { log btclog.Logger prefix string + attr []any } // NewPrefixLog instantiates a new prefixed logger. -func NewPrefixLog(prefix string, log btclog.Logger) *PrefixLog { +func NewPrefixLog(prefix string, log btclog.Logger, attrs ...any) *PrefixLog { return &PrefixLog{ - prefix: prefix, log: log, + prefix: prefix, + attr: attrs, } } @@ -22,10 +29,16 @@ func (p *PrefixLog) addFormatPrefix(s string) string { } // addArgsPrefix prepends the prefix to a list of arguments. -func (p *PrefixLog) addArgsPrefix(args []interface{}) []interface{} { +func (p *PrefixLog) addArgsPrefix(args []any) []any { return append([]interface{}{p.prefix}, args...) } +// mergeAttr merges the given set of attributes with any attributes that the +// logger was initialised with. +func (p *PrefixLog) mergeAttr(attrs []any) []any { + return append(append([]any{}, attrs...), p.attr...) +} + // Tracef formats message according to format specifier and writes to to log // with LevelTrace. func (p *PrefixLog) Tracef(format string, params ...interface{}) { @@ -98,13 +111,55 @@ func (p *PrefixLog) Critical(v ...interface{}) { p.log.Critical(p.addArgsPrefix(v)...) } +// TraceS writes a structured log with the given message and key-value pair +// attributes with LevelTrace to the log. +func (p *PrefixLog) TraceS(ctx context.Context, msg string, attrs ...any) { + p.log.TraceS(ctx, p.addFormatPrefix(msg), p.mergeAttr(attrs)...) +} + +// DebugS writes a structured log with the given message and key-value pair +// attributes with LevelDebug to the log. +func (p *PrefixLog) DebugS(ctx context.Context, msg string, attrs ...any) { + p.log.DebugS(ctx, p.addFormatPrefix(msg), p.mergeAttr(attrs)...) +} + +// InfoS writes a structured log with the given message and key-value pair +// attributes with LevelInfo to the log. +func (p *PrefixLog) InfoS(ctx context.Context, msg string, attrs ...any) { + p.log.InfoS(ctx, p.addFormatPrefix(msg), p.mergeAttr(attrs)...) +} + +// WarnS writes a structured log with the given message and key-value pair +// attributes with LevelWarn to the log. +func (p *PrefixLog) WarnS(ctx context.Context, msg string, err error, + attrs ...any) { + + p.log.WarnS(ctx, p.addFormatPrefix(msg), err, p.mergeAttr(attrs)...) +} + +// ErrorS writes a structured log with the given message and key-value pair +// attributes with LevelError to the log. +func (p *PrefixLog) ErrorS(ctx context.Context, msg string, err error, + attrs ...any) { + + p.log.ErrorS(ctx, p.addFormatPrefix(msg), err, p.mergeAttr(attrs)...) +} + +// CriticalS writes a structured log with the given message and key-value pair +// attributes with LevelCritical to the log. +func (p *PrefixLog) CriticalS(ctx context.Context, msg string, err error, + attrs ...any) { + + p.log.CriticalS(ctx, p.addFormatPrefix(msg), err, p.mergeAttr(attrs)...) +} + // Level returns the current logging level. -func (p *PrefixLog) Level() btclog.Level { +func (p *PrefixLog) Level() btclogv1.Level { return p.log.Level() } // SetLevel changes the logging level to the passed level. -func (p *PrefixLog) SetLevel(level btclog.Level) { +func (p *PrefixLog) SetLevel(level btclogv1.Level) { p.log.SetLevel(level) } diff --git a/build/sub_logger.go b/build/sub_logger.go new file mode 100644 index 0000000000..2a68e6cd55 --- /dev/null +++ b/build/sub_logger.go @@ -0,0 +1,263 @@ +package build + +import ( + "fmt" + "sort" + "strings" + "sync" + + "github.com/btcsuite/btclog/v2" +) + +// SubLogCreator can be used to create a new logger for a particular subsystem. +type SubLogCreator interface { + // Logger returns a new logger for a particular subsytem. + Logger(subsystemTag string) btclog.Logger +} + +// SubLoggerManager manages a set of subsystem loggers. Level updates will be +// applied to all the loggers managed by the manager. +type SubLoggerManager struct { + genLogger SubLogCreator + + loggers SubLoggers + mu sync.Mutex +} + +// A compile time check to ensure SubLoggerManager implements the +// LeveledSubLogger interface. +var _ LeveledSubLogger = (*SubLoggerManager)(nil) + +// NewSubLoggerManager constructs a new SubLoggerManager. +func NewSubLoggerManager(handlers ...btclog.Handler) *SubLoggerManager { + return &SubLoggerManager{ + loggers: make(SubLoggers), + genLogger: newSubLogGenerator( + newHandlerSet(btclog.LevelInfo, handlers...), + ), + } +} + +// GenSubLogger creates a new sub-logger and adds it to the set managed by the +// SubLoggerManager. A shutdown callback function is provided to be able to shut +// down in case of a critical error. +func (r *SubLoggerManager) GenSubLogger(subsystem string, + shutdown func()) btclog.Logger { + + // Create a new logger with the given subsystem tag. + logger := r.genLogger.Logger(subsystem) + + // Wrap the new logger in a Shutdown logger so that the shutdown + // call back is called if a critical log is ever written via this new + // logger. + l := NewShutdownLogger(logger, shutdown) + + r.RegisterSubLogger(subsystem, l) + + return l +} + +// RegisterSubLogger registers the given logger under the given subsystem name. +func (r *SubLoggerManager) RegisterSubLogger(subsystem string, + logger btclog.Logger) { + + // Add the new logger to the set of loggers managed by the manager. + r.mu.Lock() + r.loggers[subsystem] = logger + r.mu.Unlock() +} + +// SubLoggers returns all currently registered subsystem loggers for this log +// writer. +// +// NOTE: This is part of the LeveledSubLogger interface. +func (r *SubLoggerManager) SubLoggers() SubLoggers { + r.mu.Lock() + defer r.mu.Unlock() + + return r.loggers +} + +// SupportedSubsystems returns a sorted string slice of all keys in the +// subsystems map, corresponding to the names of the subsystems. +// +// NOTE: This is part of the LeveledSubLogger interface. +func (r *SubLoggerManager) SupportedSubsystems() []string { + r.mu.Lock() + defer r.mu.Unlock() + + // Convert the subsystemLoggers map keys to a string slice. + subsystems := make([]string, 0, len(r.loggers)) + for subsysID := range r.loggers { + subsystems = append(subsystems, subsysID) + } + + // Sort the subsystems for stable display. + sort.Strings(subsystems) + + return subsystems +} + +// SetLogLevel sets the logging level for provided subsystem. Invalid +// subsystems are ignored. Uninitialized subsystems are dynamically created as +// needed. +// +// NOTE: This is part of the LeveledSubLogger interface. +func (r *SubLoggerManager) SetLogLevel(subsystemID string, logLevel string) { + r.mu.Lock() + defer r.mu.Unlock() + + r.setLogLevelUnsafe(subsystemID, logLevel) +} + +// setLogLevelUnsafe sets the logging level for provided subsystem. Invalid +// subsystems are ignored. Uninitialized subsystems are dynamically created as +// needed. +// +// NOTE: the SubLoggerManager mutex must be held before calling this method. +func (r *SubLoggerManager) setLogLevelUnsafe(subsystemID string, + logLevel string) { + + // Ignore invalid subsystems. + logger, ok := r.loggers[subsystemID] + if !ok { + return + } + + // Defaults to info if the log level is invalid. + level, _ := btclog.LevelFromString(logLevel) + + logger.SetLevel(level) +} + +// SetLogLevels sets the log level for all subsystem loggers to the passed +// level. It also dynamically creates the subsystem loggers as needed, so it +// can be used to initialize the logging system. +// +// NOTE: This is part of the LeveledSubLogger interface. +func (r *SubLoggerManager) SetLogLevels(logLevel string) { + r.mu.Lock() + defer r.mu.Unlock() + + // Configure all sub-systems with the new logging level. Dynamically + // create loggers as needed. + for subsystemID := range r.loggers { + r.setLogLevelUnsafe(subsystemID, logLevel) + } +} + +// SubLoggers is a type that holds a map of subsystem loggers keyed by their +// subsystem name. +type SubLoggers map[string]btclog.Logger + +// LeveledSubLogger provides the ability to retrieve the subsystem loggers of +// a logger and set their log levels individually or all at once. +type LeveledSubLogger interface { + // SubLoggers returns the map of all registered subsystem loggers. + SubLoggers() SubLoggers + + // SupportedSubsystems returns a slice of strings containing the names + // of the supported subsystems. Should ideally correspond to the keys + // of the subsystem logger map and be sorted. + SupportedSubsystems() []string + + // SetLogLevel assigns an individual subsystem logger a new log level. + SetLogLevel(subsystemID string, logLevel string) + + // SetLogLevels assigns all subsystem loggers the same new log level. + SetLogLevels(logLevel string) +} + +// ParseAndSetDebugLevels attempts to parse the specified debug level and set +// the levels accordingly on the given logger. An appropriate error is returned +// if anything is invalid. +func ParseAndSetDebugLevels(level string, logger LeveledSubLogger) error { + // Split at the delimiter. + levels := strings.Split(level, ",") + if len(levels) == 0 { + return fmt.Errorf("invalid log level: %v", level) + } + + // If the first entry has no =, treat is as the log level for all + // subsystems. + globalLevel := levels[0] + if !strings.Contains(globalLevel, "=") { + // Validate debug log level. + if !validLogLevel(globalLevel) { + str := "the specified debug level [%v] is invalid" + + return fmt.Errorf(str, globalLevel) + } + + // Change the logging level for all subsystems. + logger.SetLogLevels(globalLevel) + + // The rest will target specific subsystems. + levels = levels[1:] + } + + // Go through the subsystem/level pairs while detecting issues and + // update the log levels accordingly. + for _, logLevelPair := range levels { + if !strings.Contains(logLevelPair, "=") { + str := "the specified debug level contains an " + + "invalid subsystem/level pair [%v]" + + return fmt.Errorf(str, logLevelPair) + } + + // Extract the specified subsystem and log level. + fields := strings.Split(logLevelPair, "=") + if len(fields) != 2 { + str := "the specified debug level has an invalid " + + "format [%v] -- use format subsystem1=level1," + + "subsystem2=level2" + + return fmt.Errorf(str, logLevelPair) + } + subsysID, logLevel := fields[0], fields[1] + subLoggers := logger.SubLoggers() + + // Validate subsystem. + if _, exists := subLoggers[subsysID]; !exists { + str := "the specified subsystem [%v] is invalid -- " + + "supported subsystems are %v" + + return fmt.Errorf( + str, subsysID, logger.SupportedSubsystems(), + ) + } + + // Validate log level. + if !validLogLevel(logLevel) { + str := "the specified debug level [%v] is invalid" + return fmt.Errorf(str, logLevel) + } + + logger.SetLogLevel(subsysID, logLevel) + } + + return nil +} + +// validLogLevel returns whether or not logLevel is a valid debug log level. +func validLogLevel(logLevel string) bool { + switch logLevel { + case "trace": + fallthrough + case "debug": + fallthrough + case "info": + fallthrough + case "warn": + fallthrough + case "error": + fallthrough + case "critical": + fallthrough + case "off": + return true + } + + return false +} diff --git a/chainntnfs/log.go b/chainntnfs/log.go index f21246053e..cc06e3bc63 100644 --- a/chainntnfs/log.go +++ b/chainntnfs/log.go @@ -1,7 +1,7 @@ package chainntnfs import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/chainreg/log.go b/chainreg/log.go index 2670794786..1a8e1148f8 100644 --- a/chainreg/log.go +++ b/chainreg/log.go @@ -1,7 +1,7 @@ package chainreg import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/chanacceptor/log.go b/chanacceptor/log.go index 26e131c438..3f9c925d30 100644 --- a/chanacceptor/log.go +++ b/chanacceptor/log.go @@ -1,7 +1,7 @@ package chanacceptor import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/chanbackup/log.go b/chanbackup/log.go index 34eb9e93ff..6f7147caa4 100644 --- a/chanbackup/log.go +++ b/chanbackup/log.go @@ -1,7 +1,7 @@ package chanbackup import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/chanfitness/log.go b/chanfitness/log.go index 626f7538dc..b729c51f7b 100644 --- a/chanfitness/log.go +++ b/chanfitness/log.go @@ -1,7 +1,7 @@ package chanfitness import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/channeldb/log.go b/channeldb/log.go index 10b1b54d3c..b423154d3e 100644 --- a/channeldb/log.go +++ b/channeldb/log.go @@ -1,7 +1,7 @@ package channeldb import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" mig "github.com/lightningnetwork/lnd/channeldb/migration" "github.com/lightningnetwork/lnd/channeldb/migration12" diff --git a/channeldb/migration/log.go b/channeldb/migration/log.go index 5085596dac..b60e34978f 100644 --- a/channeldb/migration/log.go +++ b/channeldb/migration/log.go @@ -1,6 +1,6 @@ package migration -import "github.com/btcsuite/btclog" +import "github.com/btcsuite/btclog/v2" // log is a logger that is initialized as disabled. This means the package will // not perform any logging by default until a logger is set. diff --git a/channeldb/migration12/log.go b/channeldb/migration12/log.go index 1352e52aea..9581808421 100644 --- a/channeldb/migration12/log.go +++ b/channeldb/migration12/log.go @@ -1,7 +1,7 @@ package migration12 import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" ) // log is a logger that is initialized as disabled. This means the package will diff --git a/channeldb/migration13/log.go b/channeldb/migration13/log.go index 33ec1812af..ff8169f30e 100644 --- a/channeldb/migration13/log.go +++ b/channeldb/migration13/log.go @@ -1,7 +1,7 @@ package migration13 import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" ) // log is a logger that is initialized as disabled. This means the package will diff --git a/channeldb/migration16/log.go b/channeldb/migration16/log.go index cb946854cf..ec134bc186 100644 --- a/channeldb/migration16/log.go +++ b/channeldb/migration16/log.go @@ -1,7 +1,7 @@ package migration16 import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" ) // log is a logger that is initialized as disabled. This means the package will diff --git a/channeldb/migration20/log.go b/channeldb/migration20/log.go index da75760d08..23a97de7d0 100644 --- a/channeldb/migration20/log.go +++ b/channeldb/migration20/log.go @@ -1,7 +1,7 @@ package migration20 import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" ) // log is a logger that is initialized as disabled. This means the package diff --git a/channeldb/migration24/log.go b/channeldb/migration24/log.go index a74cb039d4..0424df79e4 100644 --- a/channeldb/migration24/log.go +++ b/channeldb/migration24/log.go @@ -1,7 +1,7 @@ package migration24 import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" ) // log is a logger that is initialized as disabled. This means the package will diff --git a/channeldb/migration25/log.go b/channeldb/migration25/log.go index e308d2755a..07b9f60ad7 100644 --- a/channeldb/migration25/log.go +++ b/channeldb/migration25/log.go @@ -1,7 +1,7 @@ package migration25 import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" ) // log is a logger that is initialized as disabled. This means the package will diff --git a/channeldb/migration26/log.go b/channeldb/migration26/log.go index b7326a3130..3bcd276ad3 100644 --- a/channeldb/migration26/log.go +++ b/channeldb/migration26/log.go @@ -1,7 +1,7 @@ package migration26 import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" ) // log is a logger that is initialized as disabled. This means the package will diff --git a/channeldb/migration27/log.go b/channeldb/migration27/log.go index 70cdb41ec8..c4dd1a1284 100644 --- a/channeldb/migration27/log.go +++ b/channeldb/migration27/log.go @@ -1,7 +1,7 @@ package migration27 import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" ) // log is a logger that is initialized as disabled. This means the package will diff --git a/channeldb/migration29/log.go b/channeldb/migration29/log.go index b9ae19a5f5..3563c074f3 100644 --- a/channeldb/migration29/log.go +++ b/channeldb/migration29/log.go @@ -1,6 +1,6 @@ package migration29 -import "github.com/btcsuite/btclog" +import "github.com/btcsuite/btclog/v2" // log is a logger that is initialized as disabled. This means the package will // not perform any logging by default until a logger is set. diff --git a/channeldb/migration30/log.go b/channeldb/migration30/log.go index 1a1672fe6f..8b58b99a62 100644 --- a/channeldb/migration30/log.go +++ b/channeldb/migration30/log.go @@ -1,7 +1,7 @@ package migration30 import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" ) // log is a logger that is initialized as disabled. This means the package will diff --git a/channeldb/migration31/log.go b/channeldb/migration31/log.go index 2a863b7c1c..42b6cadfb9 100644 --- a/channeldb/migration31/log.go +++ b/channeldb/migration31/log.go @@ -1,7 +1,7 @@ package migration31 import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" ) // log is a logger that is initialized as disabled. This means the package will diff --git a/channeldb/migration32/log.go b/channeldb/migration32/log.go index 98709c28ea..2a921a600d 100644 --- a/channeldb/migration32/log.go +++ b/channeldb/migration32/log.go @@ -1,7 +1,7 @@ package migration32 import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" ) // log is a logger that is initialized as disabled. This means the package will diff --git a/channeldb/migration33/log.go b/channeldb/migration33/log.go index e9b271f5df..62b286b28a 100644 --- a/channeldb/migration33/log.go +++ b/channeldb/migration33/log.go @@ -1,7 +1,7 @@ package migration33 import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" ) // log is a logger that is initialized as disabled. This means the package will diff --git a/channeldb/migration_01_to_11/log.go b/channeldb/migration_01_to_11/log.go index b169b5afb1..22c3932618 100644 --- a/channeldb/migration_01_to_11/log.go +++ b/channeldb/migration_01_to_11/log.go @@ -1,7 +1,7 @@ package migration_01_to_11 import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" ) // log is a logger that is initialized as disabled. This means the package will diff --git a/channelnotifier/log.go b/channelnotifier/log.go index 5756f69976..6044e84548 100644 --- a/channelnotifier/log.go +++ b/channelnotifier/log.go @@ -1,7 +1,7 @@ package channelnotifier import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/cluster/log.go b/cluster/log.go index 11ced0871c..5551809c12 100644 --- a/cluster/log.go +++ b/cluster/log.go @@ -1,7 +1,7 @@ package cluster import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/config.go b/config.go index 2ad83c1265..a427e4c7d4 100644 --- a/config.go +++ b/config.go @@ -21,6 +21,7 @@ import ( "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg" + "github.com/btcsuite/btclog/v2" flags "github.com/jessevdk/go-flags" "github.com/lightninglabs/neutrino" "github.com/lightningnetwork/lnd/autopilot" @@ -494,9 +495,11 @@ type Config struct { GRPC *GRPCConfig `group:"grpc" namespace:"grpc"` - // LogWriter is the root logger that all of the daemon's subloggers are + // SubLogMgr is the root logger that all the daemon's subloggers are // hooked up to. - LogWriter *build.RotatingLogWriter + SubLogMgr *build.SubLoggerManager + LogRotator *build.RotatingLogWriter + LogConfig *build.LogConfig `group:"logging" namespace:"logging"` // networkDir is the path to the directory of the currently active // network. This path will hold the files related to each different @@ -714,7 +717,7 @@ func DefaultConfig() Config { MaxChannelFeeAllocation: htlcswitch.DefaultMaxLinkFeeAllocation, MaxCommitFeeRateAnchors: lnwallet.DefaultAnchorsCommitMaxFeeRateSatPerVByte, MaxFeeExposure: uint64(htlcswitch.DefaultMaxFeeExposure.ToSatoshis()), - LogWriter: build.NewRotatingLogWriter(), + LogRotator: build.NewRotatingLogWriter(), DB: lncfg.DefaultDB(), Cluster: lncfg.DefaultCluster(), RPCMiddleware: lncfg.DefaultRPCMiddleware(), @@ -736,6 +739,7 @@ func DefaultConfig() Config { ServerPingTimeout: defaultGrpcServerPingTimeout, ClientPingMinWait: defaultGrpcClientPingMinWait, }, + LogConfig: build.DefaultLogConfig(), WtClient: lncfg.DefaultWtClientCfg(), HTTPHeaderTimeout: DefaultHTTPHeaderTimeout, } @@ -1400,10 +1404,24 @@ func ValidateConfig(cfg Config, interceptor signal.Interceptor, fileParser, lncfg.NormalizeNetwork(cfg.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, mkErr("log writer missing in config") + var ( + logCfg = cfg.LogConfig + logHandlers []btclog.Handler + consoleLogHandler, logFileHandler = build.NewDefaultLogHandlers( + logCfg, cfg.LogRotator, + ) + ) + maybeAddLogger := func(cmdOptionDisable bool, handler btclog.Handler) { + if !cmdOptionDisable { + logHandlers = append(logHandlers, handler) + } + } + switch build.LoggingType { + case build.LogTypeStdOut: + maybeAddLogger(logCfg.Console.Disable, consoleLogHandler) + case build.LogTypeDefault: + maybeAddLogger(logCfg.Console.Disable, consoleLogHandler) + maybeAddLogger(logCfg.File.Disable, logFileHandler) } if !build.SuportedLogCompressor(cfg.LogCompressor) { @@ -1411,16 +1429,18 @@ func ValidateConfig(cfg Config, interceptor signal.Interceptor, fileParser, cfg.LogCompressor) } + cfg.SubLogMgr = build.NewSubLoggerManager(logHandlers...) + // Initialize logging at the default logging level. - SetupLoggers(cfg.LogWriter, interceptor) + SetupLoggers(cfg.SubLogMgr, interceptor) // Special show command to list supported subsystems and exit. if cfg.DebugLevel == "show" { fmt.Println("Supported subsystems", - cfg.LogWriter.SupportedSubsystems()) + cfg.SubLogMgr.SupportedSubsystems()) os.Exit(0) } - err = cfg.LogWriter.InitLogRotator( + err = cfg.LogRotator.InitLogRotator( filepath.Join(cfg.LogDir, defaultLogFilename), cfg.LogCompressor, cfg.MaxLogFileSize, cfg.MaxLogFiles, ) @@ -1430,7 +1450,7 @@ func ValidateConfig(cfg Config, interceptor signal.Interceptor, fileParser, } // Parse, validate, and set debug log level(s). - err = build.ParseAndSetDebugLevels(cfg.DebugLevel, cfg.LogWriter) + err = build.ParseAndSetDebugLevels(cfg.DebugLevel, cfg.SubLogMgr) if err != nil { str := "error parsing debug level: %v" return nil, &lncfg.UsageError{Err: mkErr(str, err)} diff --git a/config_builder.go b/config_builder.go index 1c3a842ef1..7cc1a112d2 100644 --- a/config_builder.go +++ b/config_builder.go @@ -18,7 +18,7 @@ import ( "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/btcsuite/btcwallet/chain" "github.com/btcsuite/btcwallet/waddrmgr" "github.com/btcsuite/btcwallet/wallet" diff --git a/contractcourt/contract_resolver.go b/contractcourt/contract_resolver.go index 5acf800649..691822610a 100644 --- a/contractcourt/contract_resolver.go +++ b/contractcourt/contract_resolver.go @@ -7,7 +7,7 @@ import ( "io" "github.com/btcsuite/btcd/wire" - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/fn" diff --git a/contractcourt/log.go b/contractcourt/log.go index 2e52cc97dd..21844cc3d6 100644 --- a/contractcourt/log.go +++ b/contractcourt/log.go @@ -1,7 +1,7 @@ package contractcourt import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/discovery/log.go b/discovery/log.go index f09e7fb71b..0f885e9067 100644 --- a/discovery/log.go +++ b/discovery/log.go @@ -1,7 +1,7 @@ package discovery import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/docs/release-notes/release-notes-0.19.0.md b/docs/release-notes/release-notes-0.19.0.md index 9ff363c03c..3b20a054e6 100644 --- a/docs/release-notes/release-notes-0.19.0.md +++ b/docs/release-notes/release-notes-0.19.0.md @@ -75,6 +75,19 @@ config settings to its own dedicated group. The old ones still work but will be removed in a future release. +* [Update to use structured + logging](https://github.com/lightningnetwork/lnd/pull/9083). This also + introduces a new `--logging.console.disable` option to disable logs being + written to stdout and a new `--logging.file.disable` option to disable writing + logs to the standard log file. It also adds `--logging.console.no-timestamps` + and `--logging.file.no-timestamps` which can be used to omit timestamps in + log messages for the respective loggers. The new `--logging.console.call-site` + and `--logging.file.call-site` options can be used to include the call-site of + a log line. The options for this include "off" (default), "short" (source file + name and line number) and "long" (full path to source file and line number). + Finally, the new `--logging.console.style` option can be used under the `dev` + build tag to add styling to console logging. + ## Breaking Changes ## Performance Improvements diff --git a/funding/log.go b/funding/log.go index 887d4f7192..357483db40 100644 --- a/funding/log.go +++ b/funding/log.go @@ -1,7 +1,7 @@ package funding import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/go.mod b/go.mod index b1e63f8cff..692e5ad75f 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,8 @@ require ( github.com/btcsuite/btcd/btcutil v1.1.5 github.com/btcsuite/btcd/btcutil/psbt v1.1.8 github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 - github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f + github.com/btcsuite/btclog v0.0.0-20241003133417-09c4e92e319c + github.com/btcsuite/btclog/v2 v2.0.0-20241017175713-3428138b75c7 github.com/btcsuite/btcwallet v0.16.10-0.20240912233857-ffb143c77cc5 github.com/btcsuite/btcwallet/wallet/txauthor v1.3.5 github.com/btcsuite/btcwallet/wallet/txrules v1.2.2 diff --git a/go.sum b/go.sum index 5c3b97e88a..d0f1882f32 100644 --- a/go.sum +++ b/go.sum @@ -89,8 +89,11 @@ github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtyd github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6sjybR934QNHSJZPTQ= github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= -github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= +github.com/btcsuite/btclog v0.0.0-20241003133417-09c4e92e319c h1:4HxD1lBUGUddhzgaNgrCPsFWd7cGYNpeFUgd9ZIgyM0= +github.com/btcsuite/btclog v0.0.0-20241003133417-09c4e92e319c/go.mod h1:w7xnGOhwT3lmrS4H3b/D1XAXxvh+tbhUm8xeHN2y3TQ= +github.com/btcsuite/btclog/v2 v2.0.0-20241017175713-3428138b75c7 h1:3Ct3zN3VCEKVm5nceWBBEKczc+jvTfVyOEG71ob2Yuc= +github.com/btcsuite/btclog/v2 v2.0.0-20241017175713-3428138b75c7/go.mod h1:XItGUfVOxotJL8kkuk2Hj3EVow5KCugXl3wWfQ6K0AE= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcwallet v0.16.10-0.20240912233857-ffb143c77cc5 h1:zYy233eUBvkF3lq2MUkybEhxhDsrRDSgiToIKN57mtk= github.com/btcsuite/btcwallet v0.16.10-0.20240912233857-ffb143c77cc5/go.mod h1:1HJXYbjJzgumlnxOC2+ViR1U+gnHWoOn7WeK5OfY1eU= diff --git a/graph/log.go b/graph/log.go index 7d2f741c66..4e03156688 100644 --- a/graph/log.go +++ b/graph/log.go @@ -1,7 +1,7 @@ package graph import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/htlcswitch/hop/log.go b/htlcswitch/hop/log.go index 4134d1662f..7b412b95d2 100644 --- a/htlcswitch/hop/log.go +++ b/htlcswitch/hop/log.go @@ -1,7 +1,7 @@ package hop import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" ) // log is a logger that is initialized with no output filters. This diff --git a/htlcswitch/link.go b/htlcswitch/link.go index 7ce618574a..3532a23181 100644 --- a/htlcswitch/link.go +++ b/htlcswitch/link.go @@ -13,7 +13,7 @@ import ( "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/wire" - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb/models" diff --git a/htlcswitch/log.go b/htlcswitch/log.go index 79259be91c..f20310f8dd 100644 --- a/htlcswitch/log.go +++ b/htlcswitch/log.go @@ -1,7 +1,7 @@ package htlcswitch import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" "github.com/lightningnetwork/lnd/htlcswitch/hop" ) diff --git a/invoices/log.go b/invoices/log.go index 5e3a0b17be..291a6aa68e 100644 --- a/invoices/log.go +++ b/invoices/log.go @@ -1,7 +1,7 @@ package invoices import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/lncfg/db.go b/lncfg/db.go index 4072a51fea..1f7e0ae35d 100644 --- a/lncfg/db.go +++ b/lncfg/db.go @@ -7,7 +7,7 @@ import ( "path/filepath" "time" - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/kvdb" "github.com/lightningnetwork/lnd/kvdb/etcd" "github.com/lightningnetwork/lnd/kvdb/postgres" diff --git a/lncfg/log.go b/lncfg/log.go index a22a215daf..f48516eb1f 100644 --- a/lncfg/log.go +++ b/lncfg/log.go @@ -1,7 +1,7 @@ package lncfg import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/lnd.go b/lnd.go index 8fb38b8f38..f511811950 100644 --- a/lnd.go +++ b/lnd.go @@ -149,7 +149,7 @@ func Main(cfg *Config, lisCfg ListenerCfg, implCfg *ImplementationCfg, defer func() { ltndLog.Info("Shutdown complete\n") - err := cfg.LogWriter.Close() + err := cfg.LogRotator.Close() if err != nil { ltndLog.Errorf("Could not close log rotator: %v", err) } diff --git a/lnrpc/autopilotrpc/log.go b/lnrpc/autopilotrpc/log.go index 113486d0d9..6eace32443 100644 --- a/lnrpc/autopilotrpc/log.go +++ b/lnrpc/autopilotrpc/log.go @@ -1,7 +1,7 @@ package autopilotrpc import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/lnrpc/chainrpc/log.go b/lnrpc/chainrpc/log.go index 6b68e324aa..d592e55b06 100644 --- a/lnrpc/chainrpc/log.go +++ b/lnrpc/chainrpc/log.go @@ -1,7 +1,7 @@ package chainrpc import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/lnrpc/devrpc/log.go b/lnrpc/devrpc/log.go index 9cae145e52..8e13c1001f 100644 --- a/lnrpc/devrpc/log.go +++ b/lnrpc/devrpc/log.go @@ -1,7 +1,7 @@ package devrpc import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/lnrpc/invoicesrpc/log.go b/lnrpc/invoicesrpc/log.go index f3644fdb51..7f284ad2ea 100644 --- a/lnrpc/invoicesrpc/log.go +++ b/lnrpc/invoicesrpc/log.go @@ -1,7 +1,7 @@ package invoicesrpc import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/lnrpc/neutrinorpc/log.go b/lnrpc/neutrinorpc/log.go index fb2cd79ecf..be5c9ff1b1 100644 --- a/lnrpc/neutrinorpc/log.go +++ b/lnrpc/neutrinorpc/log.go @@ -1,7 +1,7 @@ package neutrinorpc import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/lnrpc/peersrpc/log.go b/lnrpc/peersrpc/log.go index 3fd59789cb..2196fdfc91 100644 --- a/lnrpc/peersrpc/log.go +++ b/lnrpc/peersrpc/log.go @@ -1,7 +1,7 @@ package peersrpc import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/lnrpc/routerrpc/log.go b/lnrpc/routerrpc/log.go index 5c4ad01d83..a705e2b615 100644 --- a/lnrpc/routerrpc/log.go +++ b/lnrpc/routerrpc/log.go @@ -1,7 +1,7 @@ package routerrpc import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/lnrpc/signrpc/log.go b/lnrpc/signrpc/log.go index 2dc6533435..cce9f7c436 100644 --- a/lnrpc/signrpc/log.go +++ b/lnrpc/signrpc/log.go @@ -1,7 +1,7 @@ package signrpc import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/lnrpc/verrpc/log.go b/lnrpc/verrpc/log.go index 3553b56806..a6f3546dd9 100644 --- a/lnrpc/verrpc/log.go +++ b/lnrpc/verrpc/log.go @@ -1,7 +1,7 @@ package verrpc import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/lnrpc/walletrpc/log.go b/lnrpc/walletrpc/log.go index 1916c549f2..eef49e7d0c 100644 --- a/lnrpc/walletrpc/log.go +++ b/lnrpc/walletrpc/log.go @@ -1,7 +1,7 @@ package walletrpc import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/lnrpc/watchtowerrpc/log.go b/lnrpc/watchtowerrpc/log.go index a71b7827fb..2563affe1c 100644 --- a/lnrpc/watchtowerrpc/log.go +++ b/lnrpc/watchtowerrpc/log.go @@ -1,7 +1,7 @@ package watchtowerrpc import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/lnrpc/websocket_proxy.go b/lnrpc/websocket_proxy.go index 4a46929657..b333ba1c8e 100644 --- a/lnrpc/websocket_proxy.go +++ b/lnrpc/websocket_proxy.go @@ -12,7 +12,7 @@ import ( "strings" "time" - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/gorilla/websocket" "golang.org/x/net/context" ) diff --git a/lnrpc/wtclientrpc/config.go b/lnrpc/wtclientrpc/config.go index b95fb1197c..81fb5f18f6 100644 --- a/lnrpc/wtclientrpc/config.go +++ b/lnrpc/wtclientrpc/config.go @@ -1,7 +1,7 @@ package wtclientrpc import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/lncfg" "github.com/lightningnetwork/lnd/watchtower/wtclient" ) diff --git a/lnwallet/btcwallet/log.go b/lnwallet/btcwallet/log.go index 878db08e64..d0a589fed2 100644 --- a/lnwallet/btcwallet/log.go +++ b/lnwallet/btcwallet/log.go @@ -1,7 +1,7 @@ package btcwallet import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/lnwallet/chainfee/log.go b/lnwallet/chainfee/log.go index d5d0405782..536f73eff6 100644 --- a/lnwallet/chainfee/log.go +++ b/lnwallet/chainfee/log.go @@ -1,7 +1,7 @@ package chainfee import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/lnwallet/chancloser/log.go b/lnwallet/chancloser/log.go index 7189ed2a35..46c777aae8 100644 --- a/lnwallet/chancloser/log.go +++ b/lnwallet/chancloser/log.go @@ -1,7 +1,7 @@ package chancloser import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/lnwallet/chanfunding/log.go b/lnwallet/chanfunding/log.go index 159a96ca1d..4ef34f9852 100644 --- a/lnwallet/chanfunding/log.go +++ b/lnwallet/chanfunding/log.go @@ -1,7 +1,7 @@ package chanfunding import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/lnwallet/channel.go b/lnwallet/channel.go index 3a980df1a3..33360228d5 100644 --- a/lnwallet/channel.go +++ b/lnwallet/channel.go @@ -21,7 +21,7 @@ import ( "github.com/btcsuite/btcd/mempool" "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/davecgh/go-spew/spew" "github.com/lightningnetwork/lnd/build" "github.com/lightningnetwork/lnd/chainntnfs" diff --git a/lnwallet/log.go b/lnwallet/log.go index 7c8ce51984..5fde019d76 100644 --- a/lnwallet/log.go +++ b/lnwallet/log.go @@ -1,7 +1,7 @@ package lnwallet import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/btcsuite/btcwallet/chain" btcwallet "github.com/btcsuite/btcwallet/wallet" "github.com/btcsuite/btcwallet/wtxmgr" diff --git a/lnwallet/rpcwallet/log.go b/lnwallet/rpcwallet/log.go index 190aa623ad..21b8a73d68 100644 --- a/lnwallet/rpcwallet/log.go +++ b/lnwallet/rpcwallet/log.go @@ -1,7 +1,7 @@ package rpcwallet import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/log.go b/log.go index a24c39fd40..faa4f15f4d 100644 --- a/log.go +++ b/log.go @@ -3,7 +3,8 @@ package lnd import ( "github.com/btcsuite/btcd/connmgr" "github.com/btcsuite/btcd/rpcclient" - "github.com/btcsuite/btclog" + btclogv1 "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightninglabs/neutrino" sphinx "github.com/lightningnetwork/lightning-onion" "github.com/lightningnetwork/lnd/autopilot" @@ -95,7 +96,7 @@ var ( // genSubLogger creates a logger for a subsystem. We provide an instance of // a signal.Interceptor to be able to shutdown in the case of a critical error. -func genSubLogger(root *build.RotatingLogWriter, +func genSubLogger(root *build.SubLoggerManager, interceptor signal.Interceptor) func(string) btclog.Logger { // Create a shutdown function which will request shutdown from our @@ -116,7 +117,9 @@ func genSubLogger(root *build.RotatingLogWriter, } // SetupLoggers initializes all package-global logger variables. -func SetupLoggers(root *build.RotatingLogWriter, interceptor signal.Interceptor) { +// +//nolint:lll +func SetupLoggers(root *build.SubLoggerManager, interceptor signal.Interceptor) { genLogger := genSubLogger(root, interceptor) // Now that we have the proper root logger, we can replace the @@ -132,9 +135,9 @@ func SetupLoggers(root *build.RotatingLogWriter, interceptor signal.Interceptor) // `btcwallet.chain`, which is overwritten by `lnwallet`. To ensure the // overwriting works, we need to initialize the loggers here so they // can be overwritten later. - AddSubLogger(root, "BTCN", interceptor, neutrino.UseLogger) - AddSubLogger(root, "CMGR", interceptor, connmgr.UseLogger) - AddSubLogger(root, "RPCC", interceptor, rpcclient.UseLogger) + AddV1SubLogger(root, "BTCN", interceptor, neutrino.UseLogger) + AddV1SubLogger(root, "CMGR", interceptor, connmgr.UseLogger) + AddV1SubLogger(root, "RPCC", interceptor, rpcclient.UseLogger) // Some of the loggers declared in the main lnd package are also used // in sub packages. @@ -149,7 +152,7 @@ func SetupLoggers(root *build.RotatingLogWriter, interceptor signal.Interceptor) AddSubLogger(root, "CNCT", interceptor, contractcourt.UseLogger) AddSubLogger(root, "UTXN", interceptor, contractcourt.UseNurseryLogger) AddSubLogger(root, "BRAR", interceptor, contractcourt.UseBreachLogger) - AddSubLogger(root, "SPHX", interceptor, sphinx.UseLogger) + AddV1SubLogger(root, "SPHX", interceptor, sphinx.UseLogger) AddSubLogger(root, "SWPR", interceptor, sweep.UseLogger) AddSubLogger(root, "SGNR", interceptor, signrpc.UseLogger) AddSubLogger(root, "WLKT", interceptor, walletrpc.UseLogger) @@ -174,13 +177,13 @@ func SetupLoggers(root *build.RotatingLogWriter, interceptor signal.Interceptor) AddSubLogger(root, routerrpc.Subsystem, interceptor, routerrpc.UseLogger) AddSubLogger(root, chanfitness.Subsystem, interceptor, chanfitness.UseLogger) AddSubLogger(root, verrpc.Subsystem, interceptor, verrpc.UseLogger) - AddSubLogger(root, healthcheck.Subsystem, interceptor, healthcheck.UseLogger) + AddV1SubLogger(root, healthcheck.Subsystem, interceptor, healthcheck.UseLogger) AddSubLogger(root, chainreg.Subsystem, interceptor, chainreg.UseLogger) AddSubLogger(root, chanacceptor.Subsystem, interceptor, chanacceptor.UseLogger) AddSubLogger(root, funding.Subsystem, interceptor, funding.UseLogger) AddSubLogger(root, cluster.Subsystem, interceptor, cluster.UseLogger) AddSubLogger(root, rpcperms.Subsystem, interceptor, rpcperms.UseLogger) - AddSubLogger(root, tor.Subsystem, interceptor, tor.UseLogger) + AddV1SubLogger(root, tor.Subsystem, interceptor, tor.UseLogger) AddSubLogger(root, btcwallet.Subsystem, interceptor, btcwallet.UseLogger) AddSubLogger(root, rpcwallet.Subsystem, interceptor, rpcwallet.UseLogger) AddSubLogger(root, peersrpc.Subsystem, interceptor, peersrpc.UseLogger) @@ -193,7 +196,7 @@ func SetupLoggers(root *build.RotatingLogWriter, interceptor signal.Interceptor) // AddSubLogger is a helper method to conveniently create and register the // logger of one or more sub systems. -func AddSubLogger(root *build.RotatingLogWriter, subsystem string, +func AddSubLogger(root *build.SubLoggerManager, subsystem string, interceptor signal.Interceptor, useLoggers ...func(btclog.Logger)) { // genSubLogger will return a callback for creating a logger instance, @@ -206,9 +209,9 @@ func AddSubLogger(root *build.RotatingLogWriter, subsystem string, 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, +// SetSubLogger is a helper method to conveniently register the logger of a +// sub system. +func SetSubLogger(root *build.SubLoggerManager, subsystem string, logger btclog.Logger, useLoggers ...func(btclog.Logger)) { root.RegisterSubLogger(subsystem, logger) @@ -216,3 +219,31 @@ func SetSubLogger(root *build.RotatingLogWriter, subsystem string, useLogger(logger) } } + +// AddV1SubLogger is a helper method to conveniently create and register the +// logger of one or more sub systems. +func AddV1SubLogger(root *build.SubLoggerManager, subsystem string, + interceptor signal.Interceptor, useLoggers ...func(btclogv1.Logger)) { + + // genSubLogger will return a callback for creating a logger instance, + // which we will give to the root logger. + genLogger := genSubLogger(root, interceptor) + + // Create and register just a single logger to prevent them from + // overwriting each other internally. + logger := build.NewSubLogger(subsystem, genLogger) + SetV1SubLogger(root, subsystem, logger, useLoggers...) +} + +// SetV1SubLogger is a helper method to conveniently register the logger of a +// sub system. Note that the btclog v2 logger implements the btclog v1 logger +// which is why we can pass the v2 logger to the UseLogger call-backs that +// expect the v1 logger. +func SetV1SubLogger(root *build.SubLoggerManager, subsystem string, + logger btclog.Logger, useLoggers ...func(btclogv1.Logger)) { + + root.RegisterSubLogger(subsystem, logger) + for _, useLogger := range useLoggers { + useLogger(logger) + } +} diff --git a/monitoring/log.go b/monitoring/log.go index a35af85230..95f0efb232 100644 --- a/monitoring/log.go +++ b/monitoring/log.go @@ -1,7 +1,7 @@ package monitoring import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/msgmux/log.go b/msgmux/log.go index 63da4791f9..27abbf271c 100644 --- a/msgmux/log.go +++ b/msgmux/log.go @@ -1,7 +1,7 @@ package msgmux import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/netann/log.go b/netann/log.go index 85d8d68c34..4aaa15bc7a 100644 --- a/netann/log.go +++ b/netann/log.go @@ -1,7 +1,7 @@ package netann import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/peer/brontide.go b/peer/brontide.go index a66618f11c..ae4d373cac 100644 --- a/peer/brontide.go +++ b/peer/brontide.go @@ -17,7 +17,7 @@ import ( "github.com/btcsuite/btcd/connmgr" "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/davecgh/go-spew/spew" "github.com/lightningnetwork/lnd/buffer" "github.com/lightningnetwork/lnd/build" diff --git a/peer/log.go b/peer/log.go index f0d1a6672f..e4b075d19d 100644 --- a/peer/log.go +++ b/peer/log.go @@ -1,7 +1,7 @@ package peer import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/peernotifier/log.go b/peernotifier/log.go index 1178c0f3df..a06051b263 100644 --- a/peernotifier/log.go +++ b/peernotifier/log.go @@ -1,7 +1,7 @@ package peernotifier import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/routing/blindedpath/log.go b/routing/blindedpath/log.go index 979884fbd4..d6b39d7ef4 100644 --- a/routing/blindedpath/log.go +++ b/routing/blindedpath/log.go @@ -1,7 +1,7 @@ package blindedpath import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/routing/chainview/log.go b/routing/chainview/log.go index b411819dd2..5a2bad27fe 100644 --- a/routing/chainview/log.go +++ b/routing/chainview/log.go @@ -1,7 +1,7 @@ package chainview import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/routing/log.go b/routing/log.go index 741ec084ef..ad248bba98 100644 --- a/routing/log.go +++ b/routing/log.go @@ -1,7 +1,7 @@ package routing import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" "github.com/lightningnetwork/lnd/routing/chainview" ) diff --git a/routing/missioncontrol.go b/routing/missioncontrol.go index d848235d88..be8ce7c9f6 100644 --- a/routing/missioncontrol.go +++ b/routing/missioncontrol.go @@ -7,7 +7,7 @@ import ( "time" "github.com/btcsuite/btcd/btcutil" - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/btcsuite/btcwallet/walletdb" "github.com/lightningnetwork/lnd/build" "github.com/lightningnetwork/lnd/channeldb" diff --git a/routing/payment_session.go b/routing/payment_session.go index 89fb2fd137..2ab9e4fd41 100644 --- a/routing/payment_session.go +++ b/routing/payment_session.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/btcsuite/btcd/btcec/v2" - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb/models" diff --git a/rpcperms/interceptor.go b/rpcperms/interceptor.go index cea9670c48..9bbef0414d 100644 --- a/rpcperms/interceptor.go +++ b/rpcperms/interceptor.go @@ -7,7 +7,7 @@ import ( "sync" "sync/atomic" - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware" "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/macaroons" diff --git a/rpcperms/log.go b/rpcperms/log.go index 209aacce58..76e4c8d409 100644 --- a/rpcperms/log.go +++ b/rpcperms/log.go @@ -1,7 +1,7 @@ package rpcperms import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/rpcserver.go b/rpcserver.go index 6f43adf7fb..76aa057bf1 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -7341,7 +7341,7 @@ func (r *rpcServer) DebugLevel(ctx context.Context, if req.Show { return &lnrpc.DebugLevelResponse{ SubSystems: strings.Join( - r.cfg.LogWriter.SupportedSubsystems(), " ", + r.cfg.SubLogMgr.SupportedSubsystems(), " ", ), }, nil } @@ -7350,12 +7350,12 @@ 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, r.cfg.LogWriter) + err := build.ParseAndSetDebugLevels(req.LevelSpec, r.cfg.SubLogMgr) if err != nil { return nil, err } - subLoggers := r.cfg.LogWriter.SubLoggers() + subLoggers := r.cfg.SubLogMgr.SubLoggers() // Sort alphabetically by subsystem name. var tags []string for t := range subLoggers { diff --git a/sample-lnd.conf b/sample-lnd.conf index b863e60bf6..eeb6a9d311 100644 --- a/sample-lnd.conf +++ b/sample-lnd.conf @@ -970,6 +970,33 @@ ; Instructs lnd to encrypt the private key using the wallet's seed. ; tor.encryptkey=false +[logging] + +; Disable logging to stdout and stderror. +; logging.console.disable=false + +; Don't add timestamps to logs written to stdout and stderr. +; logging.console.no-timestamps=false + +; Include the log call-site in the log line written to stdout +; and stderr. Options include 'off', 'short' and 'long'. +; Default: +; logging.console.call-site=off +; Example: +; logging.console.call-site=short + +; Disable logging to the standard LND log file. +; logging.file.disable=false + +; Don't add timestamps to logs written to the standard LND log file. +; logging.file.no-timestamps=false + +; Include the log call-site in the log line written the standard LND +; log file. Options include 'off', 'short' and 'long'. +; Default: +; logging.file.call-site=off +; Example: +; logging.file.call-site=short [watchtower] diff --git a/signal/log.go b/signal/log.go index 6bde284b76..4fcbd6d7aa 100644 --- a/signal/log.go +++ b/signal/log.go @@ -1,6 +1,6 @@ package signal -import "github.com/btcsuite/btclog" +import "github.com/btcsuite/btclog/v2" // log is a logger that is initialized with no output filters. This // means the package will not perform any logging by default until the caller diff --git a/subrpcserver_config.go b/subrpcserver_config.go index 8ea5b0ab39..a4ee6d1a16 100644 --- a/subrpcserver_config.go +++ b/subrpcserver_config.go @@ -6,7 +6,7 @@ import ( "reflect" "github.com/btcsuite/btcd/chaincfg" - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/aliasmgr" "github.com/lightningnetwork/lnd/autopilot" "github.com/lightningnetwork/lnd/chainreg" diff --git a/sweep/log.go b/sweep/log.go index 1725023758..864c9e37a2 100644 --- a/sweep/log.go +++ b/sweep/log.go @@ -1,7 +1,7 @@ package sweep import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/watchtower/log.go b/watchtower/log.go index 8e9062d958..bfdbe5fcab 100644 --- a/watchtower/log.go +++ b/watchtower/log.go @@ -1,7 +1,7 @@ package watchtower import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" "github.com/lightningnetwork/lnd/watchtower/lookout" "github.com/lightningnetwork/lnd/watchtower/wtclient" diff --git a/watchtower/lookout/log.go b/watchtower/lookout/log.go index b569b4ae0a..286478614e 100644 --- a/watchtower/lookout/log.go +++ b/watchtower/lookout/log.go @@ -1,7 +1,7 @@ package lookout import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/watchtower/wtclient/client.go b/watchtower/wtclient/client.go index aef0fe505e..6cf5d9114a 100644 --- a/watchtower/wtclient/client.go +++ b/watchtower/wtclient/client.go @@ -11,7 +11,7 @@ import ( "time" "github.com/btcsuite/btcd/btcec/v2" - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/keychain" diff --git a/watchtower/wtclient/log.go b/watchtower/wtclient/log.go index 8d2e37dda3..dbda57bada 100644 --- a/watchtower/wtclient/log.go +++ b/watchtower/wtclient/log.go @@ -1,7 +1,7 @@ package wtclient import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" ) diff --git a/watchtower/wtclient/queue.go b/watchtower/wtclient/queue.go index ee03d288ad..68e4b6c180 100644 --- a/watchtower/wtclient/queue.go +++ b/watchtower/wtclient/queue.go @@ -7,7 +7,7 @@ import ( "sync/atomic" "time" - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/watchtower/wtdb" ) diff --git a/watchtower/wtclient/queue_test.go b/watchtower/wtclient/queue_test.go index 529acb49a4..a8494c2166 100644 --- a/watchtower/wtclient/queue_test.go +++ b/watchtower/wtclient/queue_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/kvdb" "github.com/lightningnetwork/lnd/lntest/wait" "github.com/lightningnetwork/lnd/watchtower/wtdb" diff --git a/watchtower/wtclient/session_negotiator.go b/watchtower/wtclient/session_negotiator.go index ea17c5b47a..4cba7de62c 100644 --- a/watchtower/wtclient/session_negotiator.go +++ b/watchtower/wtclient/session_negotiator.go @@ -7,7 +7,7 @@ import ( "time" "github.com/btcsuite/btcd/chaincfg/chainhash" - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/watchtower/blob" diff --git a/watchtower/wtclient/session_queue.go b/watchtower/wtclient/session_queue.go index 41ae28f2fa..4ee1597637 100644 --- a/watchtower/wtclient/session_queue.go +++ b/watchtower/wtclient/session_queue.go @@ -7,7 +7,7 @@ import ( "time" "github.com/btcsuite/btcd/chaincfg/chainhash" - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/lnwire" diff --git a/watchtower/wtdb/log.go b/watchtower/wtdb/log.go index fa0a64f6ac..474ff08b9b 100644 --- a/watchtower/wtdb/log.go +++ b/watchtower/wtdb/log.go @@ -1,7 +1,7 @@ package wtdb import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" "github.com/lightningnetwork/lnd/watchtower/wtdb/migration1" "github.com/lightningnetwork/lnd/watchtower/wtdb/migration2" diff --git a/watchtower/wtdb/migration1/log.go b/watchtower/wtdb/migration1/log.go index 1dc1052809..f741ceaace 100644 --- a/watchtower/wtdb/migration1/log.go +++ b/watchtower/wtdb/migration1/log.go @@ -1,7 +1,7 @@ package migration1 import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" ) // log is a logger that is initialized as disabled. This means the package will diff --git a/watchtower/wtdb/migration2/log.go b/watchtower/wtdb/migration2/log.go index fd64d2fcbe..ae1ca59a18 100644 --- a/watchtower/wtdb/migration2/log.go +++ b/watchtower/wtdb/migration2/log.go @@ -1,7 +1,7 @@ package migration2 import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" ) // log is a logger that is initialized as disabled. This means the package will diff --git a/watchtower/wtdb/migration3/log.go b/watchtower/wtdb/migration3/log.go index 2f14ff5e75..07cc2730ea 100644 --- a/watchtower/wtdb/migration3/log.go +++ b/watchtower/wtdb/migration3/log.go @@ -1,7 +1,7 @@ package migration3 import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" ) // log is a logger that is initialized as disabled. This means the package will diff --git a/watchtower/wtdb/migration4/log.go b/watchtower/wtdb/migration4/log.go index 3a609d76d6..eb85aa5c3a 100644 --- a/watchtower/wtdb/migration4/log.go +++ b/watchtower/wtdb/migration4/log.go @@ -1,7 +1,7 @@ package migration4 import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" ) // log is a logger that is initialized as disabled. This means the package will diff --git a/watchtower/wtdb/migration5/log.go b/watchtower/wtdb/migration5/log.go index f0b725a2ef..d92b108ad6 100644 --- a/watchtower/wtdb/migration5/log.go +++ b/watchtower/wtdb/migration5/log.go @@ -1,7 +1,7 @@ package migration5 import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" ) // log is a logger that is initialized as disabled. This means the package will diff --git a/watchtower/wtdb/migration6/log.go b/watchtower/wtdb/migration6/log.go index e43e7d27ec..b15662bba6 100644 --- a/watchtower/wtdb/migration6/log.go +++ b/watchtower/wtdb/migration6/log.go @@ -1,7 +1,7 @@ package migration6 import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" ) // log is a logger that is initialized as disabled. This means the package will diff --git a/watchtower/wtdb/migration7/log.go b/watchtower/wtdb/migration7/log.go index 39f28b6c00..baf5a0990c 100644 --- a/watchtower/wtdb/migration7/log.go +++ b/watchtower/wtdb/migration7/log.go @@ -1,7 +1,7 @@ package migration7 import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" ) // log is a logger that is initialized as disabled. This means the package will diff --git a/watchtower/wtdb/migration8/log.go b/watchtower/wtdb/migration8/log.go index ab35682c5a..412b95f8b8 100644 --- a/watchtower/wtdb/migration8/log.go +++ b/watchtower/wtdb/migration8/log.go @@ -1,7 +1,7 @@ package migration8 import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" ) // log is a logger that is initialized as disabled. This means the package will diff --git a/watchtower/wtserver/log.go b/watchtower/wtserver/log.go index 7939bd97f8..3c901b4861 100644 --- a/watchtower/wtserver/log.go +++ b/watchtower/wtserver/log.go @@ -1,7 +1,7 @@ package wtserver import ( - "github.com/btcsuite/btclog" + "github.com/btcsuite/btclog/v2" "github.com/lightningnetwork/lnd/build" )