def __parse_hdr(self, line: str) -> None: "Parse line from header" for key, valtype, name in items_hdr: if line.startswith(key): # Check for GSTAT_VERSION if self.gstat_version is None: if key == 'System Change Number': self.gstat_version = GSTAT_30 elif key == 'Checksum': raise Error( "Output from gstat older than Firebird 3 is not supported" ) # value: str = line[len(key):].strip() if valtype == 'i': # integer value = int(value) elif valtype == 's': # string pass elif valtype == 'd': # date time value = datetime.datetime.strptime(value, '%b %d, %Y %H:%M:%S') elif valtype == 'l': # list if value == '': value = [] else: value = [x.strip() for x in value.split(',')] value = [DbAttribute(x) for x in value] else: raise Error(f"Unknown value type {valtype}") if name is None: name = key.lower().replace(' ', '_') setattr(self, name, value) return raise Error(f'Unknown information (line {self.__line_no})')
def __parse_fseq(self, line: str) -> None: "Parse line from file sequence" if not line.startswith('File '): raise Error(f"Bad file specification (line {self.__line_no})") if 'is the only file' in line: return if ' is the ' in line: self.continuation_files.append(line[5:line.index(' is the ')]) elif ' continues as' in line: self.continuation_files.append(line[5:line.index(' continues as')]) else: raise Error(f"Bad file specification (line {self.__line_no})")
def __parse_index(self, line: str) -> None: "Parse line from index data" if self.__index.name is None: # We should parse header iname, iid = line[6:].split(' (') self.__index.name = iname.strip(' "') self.__index.index_id = int(iid.strip('()')) else: if ',' in line: # Data values for item in line.split(','): item = item.strip() found = False items = items_idx3 for key, valtype, name in items: if item.startswith(key): value: str = item[len(key):].strip() if valtype == 'i': # integer value = int(value) elif valtype == 'f': # float value = float(value) elif valtype == 'p': # % value = int(value.strip('%')) else: raise Error(f"Unknown value type {valtype}") if name is None: name = key.lower().strip(':').replace(' ', '_') setattr(self.__index, name, value) found = True break if not found: raise Error( f'Unknown information (line {self.__line_no})') else: # Fill distribution if '=' in line: fill_range, fill_value = line.split('=') i = items_fill.index(fill_range.strip()) if self.__index.distribution is None: self.__index.distribution = [0, 0, 0, 0, 0] self.__index.distribution[i] = int(fill_value.strip()) elif line.startswith('Fill distribution:'): pass else: raise Error(f'Unknown information (line {self.__line_no})')
def __parse_var(self, line: str) -> None: "Parse line from variable header data" if line == '*END*': return for key, valtype, name in items_var: if line.startswith(key): value = line[len(key):].strip() if valtype == 'i': # integer value = int(value) elif valtype == 's': # string pass elif valtype == 'd': # date time value = datetime.datetime.strptime(value, '%b %d, %Y %H:%M:%S') else: raise Error(f"Unknown value type {valtype}") if name is None: name = key.lower().strip(':').replace(' ', '_') setattr(self, name, value) return raise Error(f'Unknown information (line {self.__line_no})')
def __parse_encryption(self, line: str) -> None: "Parse line from encryption data" try: total, encrypted, unencrypted = line.split(',') pad, total = total.rsplit(' ', 1) total = int(total) pad, encrypted = encrypted.rsplit(' ', 1) encrypted = int(encrypted) pad, unencrypted = unencrypted.rsplit(' ', 1) unencrypted = int(unencrypted) data = Encryption(total, encrypted, unencrypted) except: raise Error( f'Malformed encryption information (line {self.__line_no})') if 'Data pages:' in line: self.encrypted_data_pages = data elif 'Index pages:' in line: self.encrypted_index_pages = data elif 'Blob pages:' in line: self.encrypted_blob_pages = data else: raise Error( f'Unknown encryption information (line {self.__line_no})')
def parse_entry(self, log_entry: List[str]) -> LogMessage: """Parse single log entry. Arguments: log_entry: List with log entry lines. """ try: items = log_entry[0].split() timestamp = datetime.strptime(' '.join(items[len(items) - 5:]), '%a %b %d %H:%M:%S %Y') origin = ' '.join(items[:len(items) - 5]) except Exception as exc: raise Error("Malformed log entry") from exc msg = '\n'.join(log_entry[1:]).strip() # if (found := identify_msg(msg)) is not None: log_msg = found[0] return LogMessage(origin, timestamp, log_msg.severity, log_msg.msg_id, log_msg.facility, log_msg.get_pattern(found[2]), found[1])
def push(self, line: Union[str, Sentinel]) -> None: """Push parser. Arguments: line: Single gstat output line, or `~firebird.base.types.STOP` sentinel. """ if self.__step == -1: self.__clear() if line is STOP: if self.has_table_stats(): for table in self.tables: table.distribution = FillDistribution(*table.distribution) if self.has_index_stats(): for index in self.indices: index.distribution = FillDistribution(*index.distribution) self.tables.freeze() self.indices.freeze() self.__step = -1 else: line = line.strip() self.__line_no += 1 if line.startswith('Gstat completion time'): self.completed = datetime.datetime.strptime( line[22:], '%a %b %d %H:%M:%S %Y') elif self.__step == 0: # Looking for section or self name if line.startswith('Gstat execution time'): self.executed = datetime.datetime.strptime( line[21:], '%a %b %d %H:%M:%S %Y') elif line.startswith('Database header page information:'): self.__step = 1 elif line.startswith('Variable header data:'): self.__step = 2 elif line.startswith('Database file sequence:'): self.__step = 3 elif 'encrypted' in line and 'non-crypted' in line: self.__parse_encryption(line) elif line.startswith('Analyzing database pages ...'): self.__step = 4 elif empty_str(line): pass elif line.startswith('Database "'): x, s = line.split(' ') self.filename = s.strip('"') self.__step = 0 else: raise Error(f"Unrecognized data (line {self.__line_no})") elif self.__step == 1: # Header if empty_str(line): # section ends with empty line self.__step = 0 else: self.__parse_hdr(line) elif self.__step == 2: # Variable data if empty_str(line): # section ends with empty line self.__step = 0 else: self.__parse_var(line) elif self.__step == 3: # File sequence if empty_str(line): # section ends with empty line self.__step = 0 else: self.__parse_fseq(line) elif self.__step == 4: # Tables and indices if empty_str(line): # section ends with empty line self.__new_block = True else: if self.__new_block: self.__new_block = False if not line.startswith('Index '): # Should be table self.__table = StatTable() self.tables.append(self.__table) self.__in_table = True self.__parse_table(line) else: # It's index self.__index = StatIndex(self.__table) self.indices.append(self.__index) self.__in_table = False self.__parse_index(line) else: if self.__in_table: self.__parse_table(line) else: self.__parse_index(line)