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