feat: decouple ldk log (#1879)

* feat: decouple ldk log

* fix: condition mapping correct levels

* fix: move LDK_LOG_LEVEL into LDK section

* fix: move ldk logger to be init in ldk service

* fix: higher is more verbose

* fix: missing 6 (trace)

* chore: address decouple ldk log feedback (#1924)

* fix: remove unneeded global variable

---------

Co-authored-by: Fmar <frnandu@gmail.com>
Co-authored-by: Roland <33993199+rolznz@users.noreply.github.com>
Co-authored-by: Roland Bewick <roland.bewick@gmail.com>
This commit is contained in:
frnandu 2025-11-20 05:54:36 +01:00 committed by GitHub
parent ea98bf1356
commit d01ced8b92
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 62 additions and 18 deletions

View file

@ -5,7 +5,7 @@ SEND_EVENTS_TO_ALBY=false
AUTO_LINK_ALBY_ACCOUNT=false
# Optionally set LDK debug log level to get more info
#LDK_LOG_LEVEL=2
#LDK_LOG_LEVEL=5
# Optionally set Main application debug log level to get more info
#LOG_LEVEL=5

View file

@ -158,7 +158,7 @@ The following configuration options can be set as environment variables or in a
- `DATABASE_URI`: A sqlite filename or postgres URL. Default is SQLite DB `nwc.db` without a path, which will be put in the user home directory: $XDG_DATA_HOME/albyhub/nwc.db
- `PORT`: The port on which the app should listen on (default: 8080)
- `WORK_DIR`: Directory to store NWC data files. Default: $XDG_DATA_HOME/albyhub
- `LOG_LEVEL`: Log level for the application. Higher is more verbose. Default: 4 (info)
- `LOG_LEVEL`: Log level for the main application. Higher is more verbose. Default: 4 (info)
- `AUTO_UNLOCK_PASSWORD`: Provide unlock password to auto-unlock Alby Hub on startup (e.g. after a machine restart). Unlock password still be required to access the interface.
- `BOLTZ_API`: The api which provides auto swaps functionality. Default: "https://api.boltz.exchange"
- `NETWORK`: On-chain network used for the node. Default: "bitcoin"
@ -226,6 +226,8 @@ _To configure via env, the following parameters must be provided:_
- `LDK_ANNOUNCEMENT_ADDRESSES`: configure announcement addresses (only required if you use a VPN)
- `LDK_MAX_CHANNEL_SATURATION`: Sets the maximum portion of a channel's total capacity that may be used for sending a payment, expressed as a power of 1/2. See `max_channel_saturation_power_of_half` in [LDK docs](https://docs.rs/lightning/latest/lightning/routing/router/struct.PaymentParameters.html#structfield.max_channel_saturation_power_of_half).
- `LDK_MAX_PATH_COUNT`: Maximum number of paths that may be used by MPP payments.
- `LDK_LOG_LEVEL`: Log level for the LDK node. Higher is more verbose. Default: 3. This is separate from the main application log level, allowing you to enable more verbose LDK logging (e.g., level 4, 5 or 6) without enabling verbose logging for the entire application.
#### LDK Network Configuration

View file

@ -120,11 +120,14 @@ func NewLDKService(ctx context.Context, cfg config.Config, eventPublisher events
logLevel, err := strconv.Atoi(cfg.GetEnv().LDKLogLevel)
if err != nil {
// If parsing log level fails we default to 3, which is then bumped below
logLevel = int(ldk_node.LogLevelDebug)
// If parsing log level fails we default to info log level
logLevel = int(logrus.InfoLevel)
}
ldkLogger, err := NewLDKLogger(logrus.Level(logLevel), cfg.GetEnv().LogToFile, workDir)
if err != nil {
return nil, err
}
// LogLevelGossip is added due to bug in go bindings which uses an enum that starts at 1 instead of 0
ldkLogger := NewLDKLogger(ldk_node.LogLevel(logLevel) + ldk_node.LogLevelGossip)
ldkConfig.TransientNetworkGraph = cfg.GetEnv().LDKTransientNetworkGraph
alias, _ := cfg.Get("NodeAlias", "")

View file

@ -1,31 +1,40 @@
package ldk
import (
// "github.com/getAlby/hub/ldk_node"
"github.com/getAlby/hub/logger"
"os"
"path/filepath"
"github.com/getAlby/hub/logger"
"github.com/getAlby/ldk-node-go/ldk_node"
"github.com/orandin/lumberjackrus"
"github.com/sirupsen/logrus"
)
const ldkLogFilename = "ldk.log"
const logDir = "log"
type ldkLogger struct {
logLevel ldk_node.LogLevel
logLevel logrus.Level
logger *logrus.Logger
}
func NewLDKLogger(logLevel ldk_node.LogLevel) ldk_node.LogWriter {
func NewLDKLogger(logLevel logrus.Level, logToFile bool, workDir string) (ldk_node.LogWriter, error) {
logger, err := createLogger(logLevel, logToFile, workDir)
if err != nil {
return nil, err
}
return &ldkLogger{
logLevel: logLevel,
}
logger: logger,
}, nil
}
func (ldkLogger *ldkLogger) Log(record ldk_node.LogRecord) {
if record.Level >= ldkLogger.logLevel {
logger.Logger.WithFields(logrus.Fields{
"log_type": "LDK-node",
"line": record.Line,
"module_path": record.ModulePath,
}).Log(mapLogLevel(record.Level), record.Args)
}
ldkLogger.logger.WithFields(logrus.Fields{
"log_type": "LDK-node",
"line": record.Line,
"module_path": record.ModulePath,
}).Log(mapLogLevel(record.Level), record.Args)
}
func mapLogLevel(logLevel ldk_node.LogLevel) logrus.Level {
@ -46,3 +55,33 @@ func mapLogLevel(logLevel ldk_node.LogLevel) logrus.Level {
logger.Logger.WithField("log_level", logLevel).Error("Unknown LDK log level")
return logrus.ErrorLevel
}
func createLogger(logLevel logrus.Level, logToFile bool, workDir string) (*logrus.Logger, error) {
ldkLogger := logrus.New()
ldkLogger.SetFormatter(&logrus.JSONFormatter{})
ldkLogger.SetOutput(os.Stdout)
ldkLogger.SetLevel(logLevel)
if logToFile {
parentDir := filepath.Dir(workDir)
ldkLogFilePath := filepath.Join(parentDir, logDir, ldkLogFilename)
ldkFileLoggerHook, err := lumberjackrus.NewHook(
&lumberjackrus.LogFile{
Filename: ldkLogFilePath,
MaxAge: 3,
MaxBackups: 3,
},
logLevel,
&logrus.JSONFormatter{},
nil,
)
if err != nil {
logger.Logger.WithError(err).Error("Failed to add LDK file logger")
return nil, err
}
ldkLogger.AddHook(ldkFileLoggerHook)
}
return ldkLogger, nil
}