2 Parsers for P2P logging information.
4 Built on previous work by Adriana Draghici, Razvan Deaconescu
7 2011, Razvan Deaconescu, razvan.deaconescu@cs.pub.ro
17 import storage # Use *Message classes.
20 # Logging code heavily inspired by Logging HOWTO documentation:
21 # http://docs.python.org/dev/howto/logging.html#configuring-logging
24 # Create logger; default logging level is DEBUG.
25 logger = logging.getLogger(__name__)
26 logger.setLevel(logging.DEBUG)
28 # Create console handler and set level to ERROR.
29 ch = logging.StreamHandler()
30 ch.setLevel(logging.DEBUG)
33 formatter = logging.Formatter('%(filename)s:%(lineno)s - %(levelname)s: %(message)s')
35 # Add formatter to console handler.
36 ch.setFormatter(formatter)
38 # Add console handler to logger.
41 class SessionLogParser(object):
43 Top-level class for parsing log file(s) for a given BitTorrent session.
46 def __init__(self, path):
48 # parsing: file currently being parsed
51 def get_next_message(self):
53 Find next message in log file/folder. May be status, peer status
55 Return None when all logs have been parsed.
59 def get_current_parsing_filename(self):
60 """Return the name of the log file being currently parsed."""
64 class LibtorrentLogParser(SessionLogParser):
66 libtorrent-rasterbar log folder parser.
69 def __init__(self, path, priority=None):
71 If priority == "verbose" parse verbose log files first. Else, parse
74 super(LibtorrentLogParser, self).__init__(path)
76 # to_parse: list of files to be parsed
77 # have_parsed: list of files that have been parsed
81 self.f = None # handler to file being parsed
83 for entry in os.listdir(self.path):
84 entry_path = os.path.join(self.path, entry)
85 if os.path.isfile(entry_path):
86 # If entry is file and name is IP_PORT.log add it to list.
87 if self.is_verbose_log_filename(entry):
88 logger.debug("Add entry path %s." %(entry_path))
89 self.to_parse.append(entry_path)
91 status_file_path = os.path.join(self.path, "status.log")
92 # In case status file doesn't exist, skip it.
93 if os.access(status_file_path, os.F_OK) and \
94 os.access(status_file_path, os.R_OK):
95 logger.debug("Status file exists: %s." %(status_file_path))
96 # List functions as a stack. First files go to the end.
97 if priority == "verbose":
98 self.to_parse.insert(0, status_file_path)
100 self.to_parse.append(status_file_path)
102 self.open_next_file()
104 def get_to_parse_list(self):
107 def get_have_parsed_list(self):
108 return self.have_parsed
110 def is_verbose_log_filename(self, filename):
111 r = re.compile(r'^[0-9]+(?:\.[0-9]+){3}_[0-9]+\.log$')
112 if not r.match(filename):
115 # Check for valid IP address and port.
116 a = re.split('_', filename)
118 port = int(a[1].split('.')[0])
121 if port <= 0 or port > 65535:
124 # Check valid IP address.
127 except socket.error, e:
132 def open_next_file(self):
134 Open next log file from to_parse list.
135 Update have_parsed and parsing accordingly.
137 if self.parsing is None: # first call
141 self.have_parsed.append(parsing)
143 self.parsing = self.to_parse.pop()
144 self.f = open(self.parsing, 'r')
146 # TODO: Log this information somewhere for snapshotting purpose.
147 # In case an error occurs parsing would resume from that point.
149 def is_status_log_line(self):
152 def is_peer_status_log_line(self):
155 def is_verbose_log_line(self):
158 def parse_status_log_line(self):
161 def parse_peer_status_log_line(self):
164 def parse_verbose_log_line(self):
167 def parse_log_line(self, line):
168 """Parse a log line and establish its type.
170 Type may be status, verbose or peer status.
171 Return message in line, in case of message line, or None in case
172 of no message line."""
174 # Check log line type and call appropriate method.
175 if self.is_status_log_line(line):
176 return self.parse_status_log_line(line)
177 elif self.is_peer_status_log_line(line):
178 return self.parse_peer_status_log_line(line)
179 elif self.is_verbose_log_line(line):
180 return self.parse_verbose_log_line(line)
182 # Return None in case of unknown/non-existent message type line.
185 def get_next_message(self):
187 Go through all files in libtorrent log folder and parse them.
188 Return the next message available or None when all log files have
192 while True: # Find first message.
193 while True: # Find first available file.
194 line = self.f.readline()
198 # end of file reached
200 self.open_next_file()
201 except IndexError, e:
202 # In case of no more files, return None.
207 msg = self.parse_log_line(line)
209 # Go around in case line is bogus (msg is None).
213 # Caller has to distinguish between message types.
217 class TriblerLogParser(SessionLogParser):
219 Tribler log file parser.
222 def __init__(self, path):
223 super(TriblerLogParser, self).__init__(path)
225 def get_next_message(self):
227 Go through Tribler log file. All log messages (verbose, status)
228 are stored in the same file.
229 Return the next message available or None when all messages have