99import pathlib
1010import os
1111import platform
12- from typing import Optional , TYPE_CHECKING
12+ from typing import Optional , TYPE_CHECKING , Set
1313import copy
1414import subprocess
15+ import hashlib
1516
1617if TYPE_CHECKING :
1718 from .simple_config import SimpleConfig
@@ -190,6 +191,24 @@ def _process_verbosity_log_levels(verbosity):
190191 raise Exception (f"invalid log filter: { filt } " )
191192
192193
194+ class _CustomLogger (logging .getLoggerClass ()):
195+ def __init__ (self , name , * args , ** kwargs ):
196+ super ().__init__ (name , * args , ** kwargs )
197+ self .msg_hashes_seen = set () # type: Set[bytes]
198+ # ^ note: size grows without bounds, but only for log lines using "only_once".
199+
200+ def _log (self , level , msg : str , * args , only_once : bool = False , ** kwargs ) -> None :
201+ """Overridden to add 'only_once' arg to logger.debug()/logger.info()/logger.warning()/etc."""
202+ if only_once : # if set, this logger will only log this msg a single time during its lifecycle
203+ msg_hash = hashlib .sha256 (msg .encode ("utf-8" )).digest ()
204+ if msg_hash in self .msg_hashes_seen :
205+ return
206+ self .msg_hashes_seen .add (msg_hash )
207+ super ()._log (level , msg , * args , ** kwargs )
208+
209+ logging .setLoggerClass (_CustomLogger )
210+
211+
193212# enable logs universally (including for other libraries)
194213root_logger = logging .getLogger ()
195214root_logger .setLevel (logging .WARNING )
@@ -216,7 +235,7 @@ def _process_verbosity_log_levels(verbosity):
216235
217236# --- External API
218237
219- def get_logger (name : str ) -> logging . Logger :
238+ def get_logger (name : str ) -> _CustomLogger :
220239 if name .startswith ("electrum." ):
221240 name = name [9 :]
222241 return electrum_logger .getChild (name )
0 commit comments