Merge pull request #9083 from ellemouton/slog

log: structured logging
This commit is contained in:
Elle 2024-10-22 20:00:56 +02:00 committed by GitHub
commit b4ef22bf47
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
111 changed files with 1035 additions and 373 deletions

View File

@ -1,7 +1,7 @@
package autopilot
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

65
build/config.go Normal file
View File

@ -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
}

162
build/config_dev.go Normal file
View File

@ -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
}
}

201
build/handler_sets.go Normal file
View File

@ -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)

23
build/handlers.go Normal file
View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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()
}

View File

@ -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
}

View File

@ -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"
)

View File

@ -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
r.pipe = pw
return nil
}
// 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)
}
return len(b), nil
}
// 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()
if r.rotator != nil {
return r.rotator.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)
}
// 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 *RotatingLogWriter) SetLogLevel(subsystemID string, logLevel string) {
// Ignore invalid subsystems.
logger, ok := r.subsystemLoggers[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 *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)
}
}

View File

@ -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)
}

263
build/sub_logger.go Normal file
View File

@ -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
}

View File

@ -1,7 +1,7 @@
package chainntnfs
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -1,7 +1,7 @@
package chainreg
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -1,7 +1,7 @@
package chanacceptor
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -1,7 +1,7 @@
package chanbackup
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -1,7 +1,7 @@
package chanfitness
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -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"

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,7 +1,7 @@
package channelnotifier
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -1,7 +1,7 @@
package cluster
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -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)}

View File

@ -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"

View File

@ -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"

View File

@ -1,7 +1,7 @@
package contractcourt
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -1,7 +1,7 @@
package discovery
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -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

View File

@ -1,7 +1,7 @@
package funding
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

3
go.mod
View File

@ -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

5
go.sum
View File

@ -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=

View File

@ -1,7 +1,7 @@
package graph
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -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

View File

@ -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"

View File

@ -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"
)

View File

@ -1,7 +1,7 @@
package invoices
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -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"

View File

@ -1,7 +1,7 @@
package lncfg
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

2
lnd.go
View File

@ -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)
}

View File

@ -1,7 +1,7 @@
package autopilotrpc
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -1,7 +1,7 @@
package chainrpc
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -1,7 +1,7 @@
package devrpc
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -1,7 +1,7 @@
package invoicesrpc
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -1,7 +1,7 @@
package neutrinorpc
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -1,7 +1,7 @@
package peersrpc
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -1,7 +1,7 @@
package routerrpc
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -1,7 +1,7 @@
package signrpc
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -1,7 +1,7 @@
package verrpc
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -1,7 +1,7 @@
package walletrpc
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -1,7 +1,7 @@
package watchtowerrpc
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -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"
)

View File

@ -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"
)

View File

@ -1,7 +1,7 @@
package btcwallet
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -1,7 +1,7 @@
package chainfee
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -1,7 +1,7 @@
package chancloser
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -1,7 +1,7 @@
package chanfunding
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -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"

View File

@ -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"

View File

@ -1,7 +1,7 @@
package rpcwallet
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

57
log.go
View File

@ -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)
}
}

View File

@ -1,7 +1,7 @@
package monitoring
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -1,7 +1,7 @@
package msgmux
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -1,7 +1,7 @@
package netann
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -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"

View File

@ -1,7 +1,7 @@
package peer
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -1,7 +1,7 @@
package peernotifier
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -1,7 +1,7 @@
package blindedpath
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -1,7 +1,7 @@
package chainview
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -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"
)

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -1,7 +1,7 @@
package rpcperms
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -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 {

View File

@ -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]

View File

@ -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

View File

@ -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"

View File

@ -1,7 +1,7 @@
package sweep
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -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"

View File

@ -1,7 +1,7 @@
package lookout
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -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"

View File

@ -1,7 +1,7 @@
package wtclient
import (
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/build"
)

View File

@ -7,7 +7,7 @@ import (
"sync/atomic"
"time"
"github.com/btcsuite/btclog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/watchtower/wtdb"
)

View File

@ -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"

View File

@ -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"

Some files were not shown because too many files have changed in this diff Show More