1
0

Merge pull request #10159 from SomberNight/202508_max_logfile_size

logging: add config.LOGS_MAX_TOTAL_SIZE_BYTES: to limit size on disk
This commit is contained in:
ghost43
2025-08-21 21:10:42 +00:00
committed by GitHub
2 changed files with 57 additions and 11 deletions

View File

@@ -116,24 +116,52 @@ class TruncatingMemoryHandler(logging.handlers.MemoryHandler):
super().close()
def _delete_old_logs(path, *, num_files_keep: int):
files = sorted(list(pathlib.Path(path).glob("electrum_log_*.log")), reverse=True)
for f in files[num_files_keep:]:
def _delete_old_logs(path, *, num_files_keep: int, max_total_size: int):
"""Delete old logfiles, only keeping the latest few."""
def sortkey_oldest_first(p: pathlib.PurePath):
fname = p.name
basename, ext, counter = str(fname).partition(".log")
# - each time electrum is launched, there will be a new basename, ordered by date
# - for any given basename, there might be multiple log files, differing by counter
# - empty counter is newest, then .1 is older, .2 is even older, etc
try:
os.remove(str(f))
counter = int(counter[1:]) if counter else 0 # convert ".2" -> 2
except ValueError:
_logger.warning(f"failed to parse log file name: {fname}")
counter = 0
return basename, -counter
files = sorted(
list(pathlib.Path(path).glob("electrum_log_*.log*")),
key=sortkey_oldest_first,
)
total_size = sum(os.stat(f).st_size for f in files) # in bytes
num_files_remaining = len(files)
for f in files:
fsize = os.stat(f).st_size
if total_size < max_total_size and num_files_remaining <= num_files_keep:
break
total_size -= fsize
num_files_remaining -= 1
try:
os.remove(f)
except OSError as e:
_logger.warning(f"cannot delete old logfile: {e}")
_logfile_path = None
def _configure_file_logging(log_directory: pathlib.Path, *, num_files_keep: int):
def _configure_file_logging(
log_directory: pathlib.Path,
*,
num_files_keep: int,
max_total_size: int,
):
from .util import os_chmod
global _logfile_path
assert _logfile_path is None, 'file logging already initialized'
log_directory.mkdir(exist_ok=True, mode=0o700)
_delete_old_logs(log_directory, num_files_keep=num_files_keep)
_delete_old_logs(log_directory, num_files_keep=num_files_keep, max_total_size=max_total_size)
timestamp = datetime.datetime.now(datetime.timezone.utc).strftime("%Y%m%dT%H%M%SZ")
PID = os.getpid()
@@ -142,7 +170,12 @@ def _configure_file_logging(log_directory: pathlib.Path, *, num_files_keep: int)
with open(_logfile_path, "w+") as f:
os_chmod(_logfile_path, 0o600)
file_handler = logging.FileHandler(_logfile_path, encoding='utf-8')
logfile_backupcount = 4
file_handler = logging.handlers.RotatingFileHandler(
_logfile_path,
maxBytes=max_total_size // (logfile_backupcount+1),
backupCount=logfile_backupcount,
encoding='utf-8')
file_handler.setFormatter(file_formatter)
file_handler.setLevel(logging.DEBUG)
root_logger.addHandler(file_handler)
@@ -236,8 +269,9 @@ electrum_logger.setLevel(logging.DEBUG)
# --- External API
def get_logger(name: str) -> _CustomLogger:
if name.startswith("electrum."):
name = name[9:]
prefix = "electrum."
if name.startswith(prefix):
name = name[len(prefix):]
return electrum_logger.getChild(name)
@@ -283,7 +317,8 @@ def configure_logging(config: 'SimpleConfig', *, log_to_file: Optional[bool] = N
if log_to_file:
log_directory = pathlib.Path(config.path) / "logs"
num_files_keep = config.LOGS_NUM_FILES_KEEP
_configure_file_logging(log_directory, num_files_keep=num_files_keep)
max_total_size = config.LOGS_MAX_TOTAL_SIZE_BYTES
_configure_file_logging(log_directory, num_files_keep=num_files_keep, max_total_size=max_total_size)
# clean up and delete in-memory logs
global _inmemory_startup_logs

View File

@@ -892,7 +892,18 @@ Warning: setting this to too low will result in lots of payment failures."""),
short_desc=lambda: _("Write logs to file"),
long_desc=lambda: _('Debug logs can be persisted to disk. These are useful for troubleshooting.'),
)
LOGS_NUM_FILES_KEEP = ConfigVar('logs_num_files_keep', default=30, type_=int)
LOGS_NUM_FILES_KEEP = ConfigVar(
'logs_num_files_keep', default=30, type_=int,
long_desc=lambda: _("Old log files get deleted on startup, with only the newest few being kept."),
)
LOGS_MAX_TOTAL_SIZE_BYTES = ConfigVar(
'logs_max_total_size', default=200_000_000, type_=int,
long_desc=lambda: _(
"Old log files get deleted on startup. "
"This value limits the max total size of the old log files kept, "
"and also separately the max size of the current log file. "
"Hence, the max disk usage will be twice this value."),
)
GUI_ENABLE_DEBUG_LOGS = ConfigVar('gui_enable_debug_logs', default=False, type_=bool)
LOCALIZATION_LANGUAGE = ConfigVar(
'language', default="", type_=str,