@@ -23,8 +23,7 @@ def handle_exceptions(logger):
2323 """Handle exceptions using the provided logger."""
2424
2525 def exception_handler (scope , etype , value , traceback ):
26- logger .exception ("Top-level exception occurred" ,
27- scope = scope , exc_info = (etype , value , traceback ))
26+ logger .exception ("Top-level exception occurred" , scope = scope , exc_info = (etype , value , traceback ))
2827
2928 def sys_exception_handler (etype , value , traceback ):
3029 exception_handler ("sys" , etype , value , traceback )
@@ -33,21 +32,19 @@ def threading_exception_handler(args):
3332 if args .exc_type == SystemExit and args .exc_value .code == 0 :
3433 # `sys.exit(0)` is considered "successful termination":
3534 # https://docs.python.org/3/library/sys.html#sys.exit
36- logger .debug ("normal thread exit" , thread = args .thread ,
37- stack = "" .join (
38- format_exception (
39- args .exc_type , args .exc_value , args .exc_traceback )))
35+ logger .debug (
36+ "normal thread exit" ,
37+ thread = args .thread ,
38+ stack = "" .join (format_exception (args .exc_type , args .exc_value , args .exc_traceback )),
39+ )
4040 else :
41- exception_handler (f"thread: { args .thread } " ,
42- args .exc_type , args .exc_value , args .exc_traceback )
41+ exception_handler (f"thread: { args .thread } " , args .exc_type , args .exc_value , args .exc_traceback )
4342
4443 sys .excepthook = sys_exception_handler
4544 threading .excepthook = threading_exception_handler
4645
4746
48- def get_structured_logger (name = __name__ ,
49- filename = None ,
50- log_exceptions = True ):
47+ def get_structured_logger (name = __name__ , filename = None , log_exceptions = True , is_real = True ):
5148 """Create a new structlog logger.
5249
5350 Use the logger returned from this in indicator code using the standard
@@ -66,17 +63,17 @@ def get_structured_logger(name=__name__,
6663 name: Name to use for logger (included in log lines), __name__ from caller
6764 is a good choice.
6865 filename: An (optional) file to write log output.
66+ log_exceptions: should we log exceptions?
67+ is_real: is this logger *not* in a testing environment? Used to avoid
68+ setting features that interfere with testing the logging output
6969 """
7070 # Set the underlying logging configuration
7171 if "LOG_DEBUG" in os .environ :
7272 log_level = logging .DEBUG
7373 else :
7474 log_level = logging .INFO
7575
76- logging .basicConfig (
77- format = "%(message)s" ,
78- level = log_level ,
79- handlers = [logging .StreamHandler ()])
76+ logging .basicConfig (format = "%(message)s" , level = log_level , handlers = [logging .StreamHandler ()])
8077
8178 def add_pid (_logger , _method_name , event_dict ):
8279 """Add current PID to the event dict."""
@@ -115,7 +112,7 @@ def add_pid(_logger, _method_name, event_dict):
115112 # Use a standard wrapper class for utilities like log.warning()
116113 wrapper_class = structlog .stdlib .BoundLogger ,
117114 # Cache the logger
118- cache_logger_on_first_use = True ,
115+ cache_logger_on_first_use = is_real ,
119116 )
120117
121118 # Create the underlying python logger and wrap it with structlog
@@ -131,7 +128,7 @@ def add_pid(_logger, _method_name, event_dict):
131128 return logger
132129
133130
134- class LoggerThread () :
131+ class LoggerThread :
135132 """
136133 A construct to use a logger from multiprocessing workers/jobs.
137134
@@ -149,15 +146,15 @@ class LoggerThread():
149146 docs.python.org/3/howto/logging-cookbook.html#logging-to-a-single-file-from-multiple-processes
150147 """
151148
152- class SubLogger () :
149+ class SubLogger :
153150 """MP-safe logger-like interface to convey log messages to a listening LoggerThread."""
154151
155152 def __init__ (self , queue ):
156153 """Create SubLogger with a bound queue."""
157154 self .queue = queue
158155
159156 def _log (self , level , * args , ** kwargs ):
160- kwargs_plus = {' sub_pid' : multiprocessing .current_process ().pid }
157+ kwargs_plus = {" sub_pid" : multiprocessing .current_process ().pid }
161158 kwargs_plus .update (kwargs )
162159 self .queue .put ([level , args , kwargs_plus ])
163160
@@ -181,7 +178,6 @@ def critical(self, *args, **kwargs):
181178 """Log a CRITICAL level message."""
182179 self ._log (logging .CRITICAL , * args , ** kwargs )
183180
184-
185181 def get_sublogger (self ):
186182 """Retrieve SubLogger for this LoggerThread."""
187183 return self .sublogger
@@ -195,25 +191,22 @@ def __init__(self, logger, q=None):
195191 self .msg_queue = multiprocessing .Queue ()
196192
197193 def logger_thread_worker ():
198- logger .info (' thread started' )
194+ logger .info (" thread started" )
199195 while True :
200196 msg = self .msg_queue .get ()
201- if msg == ' STOP' :
202- logger .debug (' received stop signal' )
197+ if msg == " STOP" :
198+ logger .debug (" received stop signal" )
203199 break
204200 level , args , kwargs = msg
205- if level in [logging .DEBUG , logging .INFO , logging .WARNING ,
206- logging .ERROR , logging .CRITICAL ]:
201+ if level in [logging .DEBUG , logging .INFO , logging .WARNING , logging .ERROR , logging .CRITICAL ]:
207202 logger .log (level , * args , ** kwargs )
208203 else :
209- logger .error ('received unknown logging level! exiting...' ,
210- level = level , args_kwargs = (args , kwargs ))
204+ logger .error ("received unknown logging level! exiting..." , level = level , args_kwargs = (args , kwargs ))
211205 break
212- logger .debug (' stopping thread' )
206+ logger .debug (" stopping thread" )
213207
214- self .thread = threading .Thread (target = logger_thread_worker ,
215- name = "LoggerThread__" + logger .name )
216- logger .debug ('starting thread' )
208+ self .thread = threading .Thread (target = logger_thread_worker , name = "LoggerThread__" + logger .name )
209+ logger .debug ("starting thread" )
217210 self .thread .start ()
218211
219212 self .sublogger = LoggerThread .SubLogger (self .msg_queue )
@@ -222,13 +215,13 @@ def logger_thread_worker():
222215 def stop (self ):
223216 """Terminate this LoggerThread."""
224217 if not self .running :
225- self .logger .warning (' thread already stopped' )
218+ self .logger .warning (" thread already stopped" )
226219 return
227- self .logger .debug (' sending stop signal' )
228- self .msg_queue .put (' STOP' )
220+ self .logger .debug (" sending stop signal" )
221+ self .msg_queue .put (" STOP" )
229222 self .thread .join ()
230223 self .running = False
231- self .logger .info (' thread stopped' )
224+ self .logger .info (" thread stopped" )
232225
233226
234227@contextlib .contextmanager
0 commit comments