"""Parses logs and collects the interesting information."""
from .conflict import Conflict
from .event import Event
from .log_lines import InsertEventLogLine, DeleteEventLogLine, \
UpdateEventLogLine, UnknownLocationLogLine, EventLocationLogLine, \
SpecialLocationLogLine, RetireEventLogLine, SuppressEventLogLine
from parsley import makeGrammar, ParseError
from collections import namedtuple
Field = namedtuple("Field", "name value")
LogLineStart = namedtuple("LogLineStart", "timestamp log_level")
UpdateToLogLine = namedtuple("UpdateToLogLine", "timestamp event")
Summary = namedtuple(
"Summary",
"counter crud_lister conflict_reporter location_mapper "
"suppressed_event_tracker")
SpecialLocation = namedtuple(
"SpecialLocation",
"meetup_id location override comment places")
GRAMMER = r"""
log_lines :summary = log_line(summary)*
log_line :summary = (start_log_line(summary.counter)
| event_log_line(summary)
| conflict_analysis_log_line(summary.conflict_reporter)
| event_location_log_line:l
-> summary.location_mapper.add_event_location_log_line(l)
| suppressed_id_log_line(summary.suppressed_event_tracker)
| other_log_line) '\n'
start_log_line :counter = log_line_start('meetup2xibo'):s
'Start ' rest_of_line:p
-> counter.count(p)
event_log_line :summary = (insert_log_line
| delete_log_line
| retire_log_line
| suppress_log_line(summary.suppressed_event_tracker)
| update_log_line
| unknown_location_log_line
| special_location_log_line):log_line
-> summary.crud_lister.add_log_line(log_line)
insert_log_line = log_line_start('XiboEventCrud'):s 'Inserted ' event:e
-> InsertEventLogLine(s.timestamp, e)
delete_log_line = log_line_start('XiboEventCrud'):s 'Deleted Xibo' event:e
-> DeleteEventLogLine(s.timestamp, e)
retire_log_line = log_line_start('XiboEventCrud'):s 'Retired Xibo' event:e
-> RetireEventLogLine(s.timestamp, e)
suppress_log_line :tracker = log_line_start('XiboEventCrud'):s
'Suppressed Xibo'
(event:e -> tracker.suppressed_event(e)):event
-> SuppressEventLogLine(s.timestamp, event)
update_log_line = update_from_log_line:f '\n' update_to_log_line:t
-> UpdateEventLogLine(t.timestamp, f, t.event)
update_from_log_line = log_line_start('XiboEventCrud')
'Updated from Xibo' event:e
-> e
update_to_log_line = log_line_start('XiboEventCrud'):s
'Updated to ' event:e
-> UpdateToLogLine(s.timestamp, e)
unknown_location_log_line = log_line_start('LocationChooser'):s
'Unknown location for Partial' event:e
-> UnknownLocationLogLine(s.timestamp, e)
special_location_log_line = log_line_start('SpecialEventsMonitor'):s
'No longer needed ' special_location:l
-> SpecialLocationLogLine(s.timestamp, l)
special_location = 'SpecialLocation(' fields:f ')'
-> SpecialLocation(**dict(f))
event_location_log_line = log_line_start('EventConverter'):s
'Location=' quoted_value:l ' MeetupEvent=Partial' event:e
-> EventLocationLogLine(s.timestamp, l, e)
conflict_analysis_log_line :conflict_reporter =
start_conflict_analysis_log_line -> conflict_reporter.clear()
| checked_place_log_line:n -> conflict_reporter.add_checked_place(n)
| schedule_conflict_log_line:cp -> conflict_reporter.add_conflict(*cp)
start_conflict_analysis_log_line = log_line_start('ConflictAnalyzer')
'Start conflict analysis'
checked_place_log_line = log_line_start('CheckedPlace') 'Name=' quoted_value
schedule_conflict_log_line = log_line_start('CheckedPlace')
'Schedule conflict: place=' quoted_value:p ' ' conflict:c -> (p, c)
conflict = 'Conflict(' conflict_fields:f ')' -> Conflict.from_fields(f)
suppressed_id_log_line :tracker =
suppressed_meetup_id_log_line(tracker)
| suppressed_id_not_checked_log_line(tracker)
suppressed_meetup_id_log_line :tracker =
log_line_start('EventSuppressor')
'Suppressed meetup_id=' quoted_value:v
-> tracker.suppressed_id(v)
suppressed_id_not_checked_log_line :tracker =
log_line_start('EventSuppressor')
'Suppressed Meetup ID was not checked. meetup_id='
quoted_value:v
-> tracker.unchecked_id(v)
other_log_line = rest_of_line
log_line_start :logger = timestamp:t dash level:l dash exactly(logger) dash
-> LogLineStart(t, l)
timestamp = date:d ' ' time:t -> " ".join((d, t))
event_timestamp = date:d ' ' event_time:t -> " ".join((d, t))
date = <digit{4} '-' digit{2} '-' digit{2}>
time = <digit{2} ':' digit{2}>:t ':' digit{2} ',' digit{3} -> t
event_time = <digit{2} ':' digit{2}>:t ':' digit{2} -> t
level = 'INFO' | 'DEBUG' | 'WARNING' | 'ERROR' | 'CRITICAL'
name = <(letterOrDigit | '_')+>
event_list = '[' event:first (', ' event)+:rest ']' -> [first] + rest
event = 'Event(' fields:f ')' -> Event.from_fields(f)
fields = field:first (', ' field)*:rest -> [first] + rest
conflict_fields = conflict_field:first (', ' conflict_field)*:rest
-> [first] + rest
field = time_field | boolean_field | list_field | other_field
conflict_field = event_list_field | field
time_field = time_field_name:n '=\'' event_timestamp:v '\'' -> Field(n, v)
time_field_name = 'start_time' | 'end_time'
boolean_field = boolean_field_name:n '=' boolean_value:v -> Field(n, v)
boolean_value = 'True' -> True
| 'False' -> False
boolean_field_name = 'override'
event_list_field = name:n '=' event_list:l -> Field(n, l)
list_field = name:n '=' quoted_value_list:l -> Field(n, l)
other_field = name:n '=' quoted_value:v -> Field(n, v)
quoted_value_list = '[' quoted_values:qv ']' -> qv
quoted_values = quoted_value:first (', ' quoted_value)*:rest -> [first] + rest
| -> []
quoted_value = ( '\'' | '"' ):q
(escaped_char | ~exactly(q) anything)*:c
exactly(q)
-> ''.join(c)
escaped_char = '\\' ( '\\' | '\'' | '"' )
rest_of_line <(~'\n' anything)*>
end_of_line ('\n' | end)
dash = ' - '
"""
[docs]def make_log_parser_class():
"""Make a log line parser class."""
context = {
'Conflict': Conflict,
'Field': Field,
'Event': Event,
'InsertEventLogLine': InsertEventLogLine,
'DeleteEventLogLine': DeleteEventLogLine,
'RetireEventLogLine': RetireEventLogLine,
'SuppressEventLogLine': SuppressEventLogLine,
'UpdateEventLogLine': UpdateEventLogLine,
'UnknownLocationLogLine': UnknownLocationLogLine,
'SpecialLocation': SpecialLocation,
'SpecialLocationLogLine': SpecialLocationLogLine,
'EventLocationLogLine': EventLocationLogLine,
'LogLineStart': LogLineStart,
'UpdateToLogLine': UpdateToLogLine,
}
return makeGrammar(GRAMMER, context)
[docs]def parse_error_hash(self):
"""Define missing ParseError.__hash__()."""
return hash((self.position, self.formatReason()))
ParseError.__hash__ = parse_error_hash
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 autoindent