This class takes a log file name(which must be of a specific format/order) and returns a list of serial numbers of those drives which contain particular type of error. It uses regular expressions to process the file line by line and all but one of the regular expressions searches using patterns shaped by previous matches.
I have little experience in object orientated programming and would like to better understand how I might structure code to achieve the below task. In particular, I'm unsure about my methods calling each other in sequence as they do.
import re
class SerialNumberFinder:
"""Finds serial numbers of drives with a corrupt filesytem (XFS ERROR)"""
def __init__(self, filename):
self.serial_numbers = []
self.result = None
self.match = None
try:
with open(filename) as f:
# reverse order of lines otherwise serial number information
# for a drive is processed before error type is identified
self.lines = reversed(f.readlines())
except FileNotFoundError:
print("Cannot find file {}".format(self.filename))
def get_next_line(self):
"""Return next line from self.lines if lines, otherwise return None"""
try:
line = next(self.lines)
except StopIteration:
return None
else:
return line
def get_serial_numbers(self):
"""Return a list of serial numbers"""
self.find_error()
return self.serial_numbers
def find_error(self):
"""Use a regex to find mention of a specific type of error in a line"""
while not self.match:
line = self.get_next_line()
if not line:
return
self.match = re.match("XFS ERROR (\[sd[a-z]\])", line)
self.result = self.match.groups()[0]
self.match = None
self.find_bus()
def find_bus(self):
"""Find mention of bus using identifier from find_error"""
while not self.match:
line = self.get_next_line()
if not line:
return
self.match = re.match("(sd \S+) {}.*".format(re.escape
(self.result)), line)
self.result = self.match.groups()[0]
self.match = None
self.find_serial()
def find_serial(self):
"""Find a serial number using identifier from find_bus"""
while not self.match:
line = self.get_next_line()
if not line:
return
self.match = re.match("{} \(SERIAL=([^)]*)\)".format(self.result),
line)
self.serial_numbers.append(self.match.groups()[0])
self.match = None
self.find_error()
if __name__ == "__main__":
s = SerialNumberFinder("EXAMPLE_LOG.log")
nums = s.get_serial_numbers()
print(nums)
Output:
['WW11111', 'ZZ12345']
Example log file:
unrelated log messages
sd 0:0:0:0 Attached Disk Drive
unrelated log messages
sd 0:0:0:0 (SERIAL=ZZ12345)
unrelated log messages
sd 0:0:0:0 [sda] Options
unrelated log messages
XFS ERROR [sda]
unrelated log messages
sd 2:0:0:1 Attached Disk Drive
unrelated log messages
sd 2:0:0:1 (SERIAL=ZZ67890)
unrelated log messages
sd 2:0:0:1 [sdb] Options
unrelated log messages
sd 3:0:1:8 Attached Disk Drive
unrelated log messages
sd 3:0:1:8 (SERIAL=WW11111)
unrelated log messages
sd 3:0:1:8 [sdc] Options
unrelated log messages
XFS ERROR [sdc]
unrelated log messages