1010
1111# third-party
1212import aiofiles
13- from vcorelib .logging import LoggerMixin , LoggerType
13+ from vcorelib .logging import ListLogger , LoggerMixin , LoggerType
1414from vcorelib .paths import Pathlike , normalize
1515
1616# internal
@@ -66,6 +66,25 @@ def setup_level_channel(
6666
6767
6868LogPaths = Iterable [tuple [LogLevellike , Pathlike ]]
69+ EXT_LOG_EXTRA = {"external" : True }
70+
71+
72+ def handle_safe_log (
73+ logger : LoggerType , level : int , data : str , safe_to_log : bool
74+ ) -> None :
75+ """handle a log filtering scenario."""
76+
77+ if safe_to_log :
78+ logger .log (level , data , extra = EXT_LOG_EXTRA )
79+ else :
80+ record = logging .LogRecord (
81+ logger .name , level , __file__ , - 1 , data , (), None
82+ )
83+ record .external = True
84+
85+ for handler in logger .handlers : # type: ignore
86+ if isinstance (handler , ListLogger ):
87+ handler .emit (record )
6988
7089
7190class LogCaptureMixin :
@@ -76,7 +95,10 @@ class LogCaptureMixin:
7695 # Open aiofiles handles.
7796 streams : list [tuple [int , Any ]]
7897
79- ext_log_extra = {"external" : True }
98+ # Set false to only forward to ListLogger handlers. Required for when the
99+ # system log / process-management logs are being forwarded (otherwise also
100+ # logging would lead to infinite spam).
101+ safe_to_log = True
80102
81103 async def init_log_capture (
82104 self , stack : AsyncExitStack , log_paths : LogPaths
@@ -98,7 +120,8 @@ async def init_log_capture(
98120
99121 def log_line (self , level : int , data : str ) -> None :
100122 """Log a line for output."""
101- self .logger .log (level , data , extra = self .ext_log_extra )
123+
124+ handle_safe_log (self .logger , level , data , self .safe_to_log )
102125
103126 async def dispatch_log_capture (self ) -> None :
104127 """Get the next line from this log stream."""
0 commit comments