ConsolePlugin.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. import re
  2. import logging
  3. from Plugin import PluginManager
  4. from Config import config
  5. from Debug import Debug
  6. from util import SafeRe
  7. from util.Flag import flag
  8. class WsLogStreamer(logging.StreamHandler):
  9. def __init__(self, stream_id, ui_websocket, filter):
  10. self.stream_id = stream_id
  11. self.ui_websocket = ui_websocket
  12. if filter:
  13. SafeRe.guard(filter)
  14. self.filter_re = re.compile(".*" + filter)
  15. else:
  16. self.filter_re = None
  17. return super(WsLogStreamer, self).__init__()
  18. def emit(self, record):
  19. if self.ui_websocket.ws.closed:
  20. self.stop()
  21. return
  22. line = self.format(record)
  23. if self.filter_re and not self.filter_re.match(line):
  24. return False
  25. self.ui_websocket.cmd("logLineAdd", {"stream_id": self.stream_id, "lines": [line]})
  26. def stop(self):
  27. logging.getLogger('').removeHandler(self)
  28. @PluginManager.registerTo("UiWebsocket")
  29. class UiWebsocketPlugin(object):
  30. def __init__(self, *args, **kwargs):
  31. self.log_streamers = {}
  32. return super(UiWebsocketPlugin, self).__init__(*args, **kwargs)
  33. @flag.no_multiuser
  34. @flag.admin
  35. def actionConsoleLogRead(self, to, filter=None, read_size=32 * 1024, limit=500):
  36. log_file_path = "%s/debug.log" % config.log_dir
  37. log_file = open(log_file_path, encoding="utf-8")
  38. log_file.seek(0, 2)
  39. end_pos = log_file.tell()
  40. log_file.seek(max(0, end_pos - read_size))
  41. if log_file.tell() != 0:
  42. log_file.readline() # Partial line junk
  43. pos_start = log_file.tell()
  44. lines = []
  45. if filter:
  46. SafeRe.guard(filter)
  47. filter_re = re.compile(".*" + filter)
  48. last_match = False
  49. for line in log_file:
  50. if not line.startswith("[") and last_match: # Multi-line log entry
  51. lines.append(line.replace(" ", " "))
  52. continue
  53. if filter and not filter_re.match(line):
  54. last_match = False
  55. continue
  56. last_match = True
  57. lines.append(line)
  58. num_found = len(lines)
  59. lines = lines[-limit:]
  60. return {"lines": lines, "pos_end": log_file.tell(), "pos_start": pos_start, "num_found": num_found}
  61. def addLogStreamer(self, stream_id, filter=None):
  62. logger = WsLogStreamer(stream_id, self, filter)
  63. logger.setFormatter(logging.Formatter('[%(asctime)s] %(levelname)-8s %(name)s %(message)s'))
  64. logger.setLevel(logging.getLevelName("DEBUG"))
  65. logging.getLogger('').addHandler(logger)
  66. return logger
  67. @flag.no_multiuser
  68. @flag.admin
  69. def actionConsoleLogStream(self, to, filter=None):
  70. stream_id = to
  71. self.log_streamers[stream_id] = self.addLogStreamer(stream_id, filter)
  72. self.response(to, {"stream_id": stream_id})
  73. @flag.no_multiuser
  74. @flag.admin
  75. def actionConsoleLogStreamRemove(self, to, stream_id):
  76. try:
  77. self.log_streamers[stream_id].stop()
  78. del self.log_streamers[stream_id]
  79. return "ok"
  80. except Exception as err:
  81. return {"error": Debug.formatException(err)}