1""" 2Debugger component used to debug each event in a system by printing 3each event to sys.stderr or to a Logger Component instance. 4""" 5 6 7import os 8import sys 9from traceback import format_exc, format_exception_only 10from signal import SIGINT, SIGTERM 11 12 13from .components import BaseComponent 14from .handlers import handler, reprhandler 15 16 17class Debugger(BaseComponent): 18 19 """Create a new Debugger Component 20 21 Creates a new Debugger Component that listens to all events in the system 22 printing each event to sys.stderr or a Logger Component. 23 24 :var IgnoreEvents: list of events (str) to ignore 25 :var IgnoreChannels: list of channels (str) to ignore 26 :var enabled: Enabled/Disabled flag 27 28 :param log: Logger Component instance or None (*default*) 29 """ 30 31 IgnoreEvents = ["generate_events"] 32 IgnoreChannels = [] 33 34 def __init__(self, errors=True, events=True, file=None, logger=None, 35 prefix=None, trim=None, **kwargs): 36 "initializes x; see x.__class__.__doc__ for signature" 37 38 super(Debugger, self).__init__() 39 40 self._errors = errors 41 self._events = events 42 43 if isinstance(file, str): 44 self.file = open(os.path.abspath(os.path.expanduser(file)), "a") 45 elif hasattr(file, "write"): 46 self.file = file 47 else: 48 self.file = sys.stderr 49 50 self.logger = logger 51 self.prefix = prefix 52 self.trim = trim 53 54 self.IgnoreEvents.extend(kwargs.get("IgnoreEvents", [])) 55 self.IgnoreChannels.extend(kwargs.get("IgnoreChannels", [])) 56 57 @handler("signal", channel="*") 58 def _on_signal(self, signo, stack): 59 if signo in [SIGINT, SIGTERM]: 60 raise SystemExit(0) 61 62 @handler("exception", channel="*", priority=100.0) 63 def _on_exception(self, error_type, value, traceback, 64 handler=None, fevent=None): 65 66 if not self._errors: 67 return 68 69 s = [] 70 71 if handler is None: 72 handler = "" 73 else: 74 handler = reprhandler(handler) 75 76 msg = "ERROR {0:s} ({1:s}) ({2:s}): {3:s}\n".format( 77 handler, repr(fevent), repr(error_type), repr(value) 78 ) 79 80 s.append(msg) 81 s.append('Traceback (most recent call last):\n') 82 s.extend(traceback) 83 s.extend(format_exception_only(error_type, value)) 84 s.append("\n") 85 86 if self.logger is not None: 87 self.logger.error("".join(s)) 88 else: 89 try: 90 self.file.write("".join(s)) 91 self.file.flush() 92 except IOError: 93 pass 94 95 @handler(priority=101.0) 96 def _on_event(self, event, *args, **kwargs): 97 """Global Event Handler 98 99 Event handler to listen to all events printing 100 each event to self.file or a Logger Component instance 101 by calling self.logger.debug 102 """ 103 104 try: 105 if not self._events: 106 return 107 108 channels = event.channels 109 110 if event.name in self.IgnoreEvents: 111 return 112 113 if all(channel in self.IgnoreChannels for channel in channels): 114 return 115 116 s = repr(event) 117 118 if self.prefix: 119 s = "%s: %s" % (self.prefix, s) 120 121 if self.trim: 122 s = "%s ...>" % s[:self.trim] 123 124 if self.logger is not None: 125 self.logger.debug(s) 126 else: 127 self.file.write(s) 128 self.file.write("\n") 129 self.file.flush() 130 except Exception as e: 131 sys.stderr.write("ERROR (Debugger): {}".format(e)) 132 sys.stderr.write("{}".format(format_exc())) 133