def __init__( self, xloghost=None, xlogport=None, xsrcid=None, xsubid=None, xlogel="2", xlogsl="_", sl=None, sw=None, txrate=0.02, nop=False, ): me = "XLog.__init__" self.nop = nop # Make a do-nothing logger. self.xlog = None # Default no logging until host & port connected. self.xloghost = xloghost # xlog server host IP. self.xlogport = xlogport # xlog server port. # srcid, subid, el & sl are defaults used by message builders if no # overrides are supplied in the log dict. self.xsrcid = xsrcid # Initial source ID. self.xsubid = xsubid # Initial sub ID. self.xlogel = xlogel # Default error-level (info). self.xlogsl = xlogsl # Default sub-level (base). # Optional simple logger and screenwriter objects. self.sl = sl # Optional simple logger to mimic what's being # sent to xlog. self.sw = sw # Optional screen writer object for # error messages (otherwise print). # Message queue. self.q = None # Queue of messages to send. # Processing thread. self.t = None # Thread to send messages. # Stop signal. self.stop = False # External signal to stop XLog instance. self.stopped = False # When stopped by self.stop. # Count messages. self.nmsgs = 0 # Number of messages sent. # if self.xloghost and self.xlogport: try: if not self.nop: self.xlog = XLogTxRx((self.xloghost, self.xlogport), txrate=txrate) self.q = queue.Queue(10000) # 10^4 self.t = threading.Thread(target=self._xlogthread) # ??? daemon? self.t.start() if FAIL_CONNECT: 1 / 0 except Exception as E: _m.beeps(10) errmsg = "{}: {}: {} @ {}".format(me, "setup failed", E, _m.tblineno()) self._p("** " + errmsg) raise Exception(errmsg)
class XLog: def __init__( self, xloghost=None, xlogport=None, xsrcid=None, xsubid=None, xlogel="2", xlogsl="_", sl=None, sw=None, txrate=0.02, nop=False, ): me = "XLog.__init__" self.nop = nop # Make a do-nothing logger. self.xlog = None # Default no logging until host & port connected. self.xloghost = xloghost # xlog server host IP. self.xlogport = xlogport # xlog server port. # srcid, subid, el & sl are defaults used by message builders if no # overrides are supplied in the log dict. self.xsrcid = xsrcid # Initial source ID. self.xsubid = xsubid # Initial sub ID. self.xlogel = xlogel # Default error-level (info). self.xlogsl = xlogsl # Default sub-level (base). # Optional simple logger and screenwriter objects. self.sl = sl # Optional simple logger to mimic what's being # sent to xlog. self.sw = sw # Optional screen writer object for # error messages (otherwise print). # Message queue. self.q = None # Queue of messages to send. # Processing thread. self.t = None # Thread to send messages. # Stop signal. self.stop = False # External signal to stop XLog instance. self.stopped = False # When stopped by self.stop. # Count messages. self.nmsgs = 0 # Number of messages sent. # if self.xloghost and self.xlogport: try: if not self.nop: self.xlog = XLogTxRx((self.xloghost, self.xlogport), txrate=txrate) self.q = queue.Queue(10000) # 10^4 self.t = threading.Thread(target=self._xlogthread) # ??? daemon? self.t.start() if FAIL_CONNECT: 1 / 0 except Exception as E: _m.beeps(10) errmsg = "{}: {}: {} @ {}".format(me, "setup failed", E, _m.tblineno()) self._p("** " + errmsg) raise Exception(errmsg) # Internal: _p, _xlogthread. def _p(self, s): """Print using either self.sw or system print function.""" s = s.rstrip() if self.sw: self.sw.nlln(s) else: print(s) def _xlogthread(self): """A thread to send a FIFO queue of objects to an xlog server.""" me = "_xlogthread" while not self.stop: try: o = self.q.get(timeout=1) # !MAGIC! 1 sec timeout. try: if FAIL_O: 1 / 0 otn = o[0] # object type number if otn == 0: # srcid, subid, el, sl, msg -> {_id, _si, _el, _sl, _msg} d = {"_id": str(o[1]), "_si": str(o[2]), "_el": str(o[3]), "_sl": str(o[4]), "_msg": str(o[5])} j = json.dumps(d, ensure_ascii=ENSURE_ASCII, sort_keys=SORT_KEYS) if DEBPRT: self._p("~~ 0: [%d] -> [%d]" % (len(d), len(j))) self.xlog.send(j) self.nmsgs += 1 continue elif otn == 1: # dict d = o[1] j = json.dumps(d, ensure_ascii=ENSURE_ASCII, sort_keys=SORT_KEYS) if DEBPRT: self._p("~~ 1: [%d] -> [%d]" % (len(d), len(j))) self.xlog.send(j) self.nmsgs += 1 continue elif otn == 2: # json j = o[1] if DEBPRT: self._p("~~ 2: [%d]" % (len(j))) self.xlog.send(j) self.nmsgs += 1 continue else: _m.beeps(3) # Switch to errmsg. errmsg = "{}: {}: {}".format(me, "unexpected object type number", repr(otn)) self._p("** " + errmsg) z = json.dumps( {"_id": self.xsrcid, "_si": self.xsubid, "_el": 5, "_sl": "!", "_msg": "[" + errmsg + "]"}, ensure_ascii=ENSURE_ASCII, sort_keys=SORT_KEYS, ) self.xlog.send(z) self.nmsgs += 1 continue pass except Exception as E: _m.beeps(3) errmsg = "{}: {} @ {}".format(me, E, _m.tblineno()) self._p("** " + errmsg) self._p("** " + repr(o)) # Switch to errmsg. z = json.dumps( {"_id": self.xsrcid, "_si": self.xsubid, "_el": 5, "_sl": "!", "_msg": "[" + errmsg + "]"}, ensure_ascii=ENSURE_ASCII, sort_keys=SORT_KEYS, ) self.xlog.send(z) self.nmsgs += 1 continue ###---self._xlogsend(z) except: # Queue get timeout. pass ##### not self.stop: ^^^ self.stopped = True ### _xlogthread(self): ^^^ # >>> msg2xlog, d2xlog & j2xlog. def msg2xlog(self, msg, srcid=None, subid=None, el=None, sl=None): """Tx msg (with optional srcid, subid, el, sl overridess) via xlog.""" if self.nop or not msg or not isinstance(msg, str): return # Sample self.* defaults when adding to queue. self.q.put( ( 0, # 0 -> srcid, subid, el, sl, msg self.xsrcid if srcid is None else srcid, self.xsubid if subid is None else subid, self.xlogel if el is None else el, self.xlogsl if sl is None else sl, msg, ), block=False, ) def logd2xlog(self, logd): """Tx ready-to-use dict via xlog.""" # srcid, subid, el and sl must already be in dict. if self.nop or not logd or not isinstance(logd, dict): return self.q.put((1, logd), block=False) # 1 -> dict def logdj2xlog(self, logdj): """Tx ready-to-use json'd dict via xlog.""" # Srcid and subid must already be in json. if self.nop or not logdj or not isinstance(logdj, str): return self.q.put((2, logdj), block=False) # 2 -> json # >>> close, busy & stop. def close(self): """Shut down xlog wrap.""" if self.nop: self.stopped = True return self.stop = True self.t.join(timeout=1) if self.t.is_alive(): _m.beeps(3) errmsg = "XLog._xlogthread did not self-stop" self._p("** " + errmsg) self.xlog.close() 1 / 1 def busy(self): """Check queue not empty.""" if self.nop: return False # !TODO! !!! Check for not connected! return not self.q.empty() def stop(self): """Signal stop to tx thread.""" if self.nop: return self.q.stop = True # # >>> Functions named by logging level. # msg must be a string. # srcid and subid can be supplied to override defaults. # el and sl are set by each logging level function. # def null(self, msg=None, srcid=None, subid=None): """Null level msg.""" self.msg2xlog(msg, srcid=srcid, subid=subid, el=0, sl="_") if self.sl: self.sl.null(msg) def debug(self, msg=None, srcid=None, subid=None): """Debug level msg.""" self.msg2xlog(msg, srcid=srcid, subid=subid, el=1, sl=".") if self.sl: self.sl.debug(msg) def info(self, msg=None, srcid=None, subid=None): """Info level msg.""" self.msg2xlog(msg, srcid=srcid, subid=subid, el=2, sl="-") if self.sl: self.sl.info(msg) def warning(self, msg=None, srcid=None, subid=None): """Warning level msg.""" self.msg2xlog(msg, srcid=srcid, subid=subid, el=3, sl=">") if self.sl: self.sl.warning(msg) def error(self, msg=None, srcid=None, subid=None): """Error level msg.""" self.msg2xlog(msg, srcid=srcid, subid=subid, el=4, sl="*") if self.sl: self.sl.error(msg) def critical(self, msg=None, srcid=None, subid=None): """Critical level msg.""" self.msg2xlog(msg, srcid=srcid, subid=subid, el=5, sl="!") if self.sl: self.sl.critical(msg) def extra(self, msg=None, srcid=None, subid=None): """Extra level msg.""" self.msg2xlog(msg, srcid=srcid, subid=subid, el=6, sl="+") if self.sl: self.sl.extra(msg)