# LogStream """ A LogStream is supposed to: - parse data feeded into it. - yield new objects - remember errors LogStream.Initialize: - initialize the logstream in some way. LogStream.Next: - once initialized, read your stream until you can yield a new class the next function reads the read-stream ahead. empty lines are omitted it tries to match the data into a new class and yields it if it runs into trouble, it just outputs the line for now. InitializeString: - init with a data blob - nice for trying it on files @TODO: look at how file streams in python are implemented and find a good generic solution combine it with the lookup for "watching files being changed", to create a program which listens to the logs live @see: monitor.py @see: watchdog https://pypi.python.org/pypi/watchdog """ from .base import Log import re from logs.base import Stacktrace import logging RE_SCLOG = r'^(?P\d{2,2})\:(?P\d{2,2})\:(?P\d{2,2})\.(?P\d{3,3})\s(?P\s*[^\|\s]+\s*|\s+)\|\s(?P.*)' R_SCLOG = re.compile(RE_SCLOG) class LogStream(object): def __init__(self): self.lines = [] self._data = None self._last_object = None def add_to_queue(self, line): # adds a line to the queue pass def new_packets(self, finish=False): # yields new packets. # processes the queue a bit. # yields new packets, once they are done. # watch out not to process the last packet until it has a follow up! # finish: override and yield all packets to finish. pass def has_data(self): if self._data: return True def set_data(self, data): self._data = data def get_data(self): return self._data def clean(self, remove_log=True): # cleans the logs by removing all non parsed packets. # remove_log: should i remove the raw log entry? lines = [] for l in self.lines: if isinstance(l, Log): if l.unpack(): if not getattr(l, 'trash', False): if remove_log: l.clean() lines.append(l) else: print type(l) print l self.lines = lines self._unset_data() data = property(set_data, get_data) def _unset_data(self): self._data = None def pre_parse_line(self, line): if not isinstance(line, basestring): return line elif line.startswith('---'): return None elif line == '' or line == '\n': if line == '\n': logging.debug('Empty Newline detected.') return None else: # get the timecode & logtype m = R_SCLOG.match(line) if m: g = m.groupdict() if 'logtype' in g.keys(): g['logtype'] = g['logtype'].strip() return g else: return line return None def _parse_line(self, line): # add the line to my lines. if line is not None: o = line if isinstance(line, basestring): # Unknown Log? if not line: return # It might be a stacktrace. inject it./ if Stacktrace.is_handler(o): o = Stacktrace(o) self._last_object = o else: #if isinstance(self._last_object, Stacktrace) and line.startswith('\t'): # logging.debug('Workaround: %s, worked: %s' % (line, self._last_object.append(line))) # return if self._last_object is not None: self._last_object.unpack() if self._last_object.append(line): return logging.debug('>> %s' % line) o = None elif isinstance(line, dict): # Unresolved Log. o = self.resolve(line) self._last_object = o else: self._last_object = o if o is None: self._last_object = None return self.lines.append(o) def parse_line(self, line): return self._parse_line(self.pre_parse_line(line)) def resolve(self, gd): # gd is a dict. # try to find a class that is responsible for this log. return gd