awlane | 1cec233 | 2025-04-24 17:24:47 -0500 | [diff] [blame^] | 1 | import re |
| 2 | from time import sleep |
| 3 | from io import TextIOWrapper |
| 4 | from threading import Thread |
| 5 | |
| 6 | import msgpack |
| 7 | |
| 8 | from mininet.node import Node |
| 9 | from minindn.util import host_home |
| 10 | from minindn.minindn_play.socket import PlaySocket |
| 11 | from minindn.minindn_play.consts import WSKeys, WSFunctions |
| 12 | |
| 13 | |
| 14 | class LogMonitor: |
| 15 | nodes: list[Node] |
| 16 | log_file: str |
| 17 | interval: float |
| 18 | socket: PlaySocket |
| 19 | filter: re.Pattern |
| 20 | quit: bool = False |
| 21 | |
| 22 | def __init__(self, nodes: list, log_file: str, interval: float = 0.5, regex_filter: str = ''): |
| 23 | self.nodes = nodes |
| 24 | self.log_file = log_file |
| 25 | self.interval = interval |
| 26 | self.regex_filter = re.compile(regex_filter) |
| 27 | |
| 28 | def start(self, socket: PlaySocket): |
| 29 | self.socket = socket |
| 30 | Thread(target=self._start).start() |
| 31 | |
| 32 | def stop(self): |
| 33 | self.quit = True |
| 34 | |
| 35 | def _start(self): |
| 36 | files: list[TextIOWrapper] = [] |
| 37 | counts: dict[str, int] = {} |
| 38 | |
| 39 | for node in self.nodes: |
| 40 | path = f"{host_home(node)}/{self.log_file}" |
| 41 | files.append(open(path, 'r')) |
| 42 | counts[node.name] = 0 |
| 43 | |
| 44 | while not self.quit: |
| 45 | for i, file in enumerate(files): |
| 46 | node = self.nodes[i] |
| 47 | counts[node.name] = 0 |
| 48 | while line := file.readline(): |
| 49 | if self.regex_filter.match(line): |
| 50 | counts[node.name] += 1 |
| 51 | |
| 52 | self._send(counts) |
| 53 | sleep(self.interval) |
| 54 | |
| 55 | for file in files: |
| 56 | file.close() |
| 57 | |
| 58 | def _send(self, counts: dict[str, int]): |
| 59 | self.socket.send_all(msgpack.dumps({ |
| 60 | WSKeys.MSG_KEY_FUN: WSFunctions.MONITOR_COUNTS, |
| 61 | WSKeys.MSG_KEY_RESULT: counts, |
| 62 | })) |