ppf/new: Fixes to LogParser classes.
[cs-p2p-next.git] / ppf / new / parsing.py
1 """
2 Parsers for P2P logging information.
3
4 Built on previous work by Adriana Draghici, Razvan Deaconescu
5 and Mariana Marasoiu.
6
7 2011, Razvan Deaconescu, razvan.deaconescu@cs.pub.ro
8 """
9
10 import os
11 import os.path
12 import re
13 import datetime
14 import logging
15
16 import storage      # Use *Message classes.
17
18 #
19 # Logging code heavily inspired by Logging HOWTO documentation:
20 #     http://docs.python.org/dev/howto/logging.html#configuring-logging
21 #
22
23 # Create logger; default logging level is DEBUG.
24 logger = logging.getLogger(__name__)
25 logger.setLevel(logging.DEBUG)
26
27 # Create console handler and set level to ERROR.
28 ch = logging.StreamHandler()
29 ch.setLevel(logging.DEBUG)
30
31 # Create formatter.
32 formatter = logging.Formatter('%(filename)s:%(lineno)s - %(levelname)s: %(message)s')
33
34 # Add formatter to console handler.
35 ch.setFormatter(formatter)
36
37 # Add console handler to logger.
38 logger.addHandler(ch)
39
40 class SessionLogParser(object):
41     """
42     Top-level class for parsing log file(s) for a given BitTorrent session.
43     """
44
45     def __init__(self, path):
46         self.path = path
47         # parsing: file currently being parsed
48         self.parsing = None
49
50     def get_next_message(self):
51         """
52         Find next message in log file/folder. May be status, peer status
53         or verbose message.
54         Return None when all logs have been parsed.
55         """
56         return None
57
58     def get_current_parsing_filename():
59         """Return the name of the log file being currently parsed."""
60         return self.parsing
61
62
63 class LibtorrentLogParser(SessionLogParser):
64     """
65     libtorrent-rasterbar log folder parser.
66     """
67
68     def __init__(self, path, priority=None):
69         """
70         If priority == "verbose" parse verbose log files first. Else, parse
71         status file first."
72         """
73         super(LibtorrentLogParser, self).__init__(path)
74
75         # to_parse: list of files to be parsed
76         # have_parsed: list of files that have been parsed
77         self.to_parse = []
78         self.have_parsed = []
79
80         self.f = None   # handler to file being parsed
81
82         for entry in os.listdir(self.path):
83             entry_path = os.path.join(self.path, entry)
84             if os.path.isfile(entry_path):
85                 # TODO: If entry is file and name is IP_PORT.log add it to list.
86                 if True:
87                     self.to_parse.append(entry_path)
88
89         status_file_path = os.path.join(self.path, "status.log")
90         # TODO: Check if status file exists and is a file.
91
92         # List functions as a stack. First files go to the end.
93         if priority == "verbose":
94             self.to_parse.insert(0, status_file_path)
95         else:
96             self.to_parse.append(status_file_path)
97
98         self.open_next_file()
99
100     def open_next_file(self):
101         """
102         Open next log file from to_parse list.
103         Update have_parsed and parsing accordingly.
104         """
105         if self.parsing is None:     # first call
106             pass
107         else:
108             self.f.close()
109             self.have_parsed.append(parsing)
110
111         parsing = self.to_parse.pop()
112         self.f = open(parsing, 'r')
113
114         # TODO: Log this information somewhere for snapshotting purpose.
115         # In case an error occurs parsing would resume from that point.
116
117     def is_status_log_line(self):
118         return False
119
120     def is_peer_status_log_line(self):
121         return False
122
123     def is_verbose_log_line(self):
124         return False
125
126     def parse_status_log_line(self):
127         return None
128
129     def parse_peer_status_log_line(self):
130         return None
131
132     def parse_verbose_log_line(self):
133         return None
134
135     def parse_log_line(self, line):
136         """Parse a log line and establish its type.
137
138         Type may be status, verbose or peer status.
139         Return message in line, in case of message line, or None in case
140         of no message line."""
141
142         # Check log line type and call appropriate method.
143         if self.is_status_log_line(line):
144             return self.parse_status_log_line(line)
145         elif self.is_peer_status_log_line(line):
146             return self.parse_peer_status_log_line(line)
147         elif self.is_verbose_log_line(line):
148             return self.parse_verbose_log_line(line)
149
150         # Return None in case of unknown/non-existent message type line.
151         return None
152
153     def get_next_message(self):
154         """
155         Go through all files in libtorrent log folder and parse them.
156         Return the next message available or None when all log files have
157         been parsed.
158         """
159
160         while True:             # Find first message.
161             while True:             # Find first available file.
162                 line = self.f.readline()
163                 if line is not None:
164                     break
165
166                 # end of file reached
167                 try:
168                     self.open_next_file()
169                 except IndexError, e:
170                     # In case of no more files, return None.
171                     return None
172                 else:
173                     continue
174
175             msg = self.parse_log_line(line)
176
177             # Go around in case line is bogus (msg is None).
178             if msg is not None:
179                 break
180
181         # Caller has to distinguish between message types.
182         return msg
183
184
185 class TriblerLogParser(SessionLogParser):
186     """
187     Tribler log file parser.
188     """
189
190     def __init__(self, path):
191         super(TriblerLogParser, self).__init__(path)
192
193     def get_next_message(self):
194         """
195         Go through Tribler log file. All log messages (verbose, status)
196         are stored in the same file.
197         Return the next message available or None when all messages have
198         been parsed.
199         """
200         return None