Skip to content

Commit

Permalink
Merge pull request #7 from rticommunity/formatters
Browse files Browse the repository at this point in the history
Implement Format Devices
  • Loading branch information
iblancasa authored Dec 13, 2016
2 parents a7cef52 + f83d6e1 commit 5e6b602
Show file tree
Hide file tree
Showing 5 changed files with 497 additions and 299 deletions.
20 changes: 20 additions & 0 deletions src/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Log Parser for RTI Connext.
#
# Copyright 2016 Real-Time Innovations, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Package LogParser."""

__version__ = "1.2a2"
__license__ = "Apache"
__copyright__ = "Copyright 2016 Real-Time Innovations, Inc."
65 changes: 65 additions & 0 deletions src/devices/formatdevice.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Log Parser for RTI Connext.
#
# Copyright 2016 Real-Time Innovations, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Device for the output format.
The module contains the abstract class representation for a formatter of the
parsed logs.
Classes:
+ FormatDevice: Abstract base class for format device implementations.
"""


class FormatDevice(object):
"""Abstract base class for format device implementations.
You will need to implement the following methods:
+ write_header: write the header if any.
+ write_configurations: write the configuration messages.
+ write_warnings: write the warning messages.
+ write_errors: write the error messages.
"""

def write_header(self, state):
"""Write the header if any."""
raise NotImplementedError("write_header not implemented")

def write_message(self, content, state):
"""Write the message.
The content argument is a dictionary with at least 'description' item.
The optional items are:
+ kind: the kind or remark for the message.
+ timestamp: the timestamp of the message.
+ input_line: the current input line.
+ output_line: the current output line.
+ inout: [packets-only] 'in' if it's input packet, 'out' otherwise.
+ remote: [packets-only] the remote address of the sender/receiver.
+ entity: [packets-only] the local entity sending/receiving.
"""
raise NotImplementedError("write_message not implemented")

def write_configurations(self, state):
"""Write the configuration messages."""
raise NotImplementedError("write_configurations not implemented")

def write_warnings(self, state):
"""Write the warning messages."""
raise NotImplementedError("write_warnings not implemented")

def write_errors(self, state):
"""Write the error messages."""
raise NotImplementedError("write_errors not implemented")
130 changes: 79 additions & 51 deletions src/devices/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,82 +16,104 @@
"""Logger functions.
The module contains functions to log the new messages.
The 'content' dictionary is defined in the FormatDevice class.
Functions:
+ log: Log the given message.
+ log_recv: Log a received packet.
+ log_send: Log a sent packet.
+ log_process: Log a processed packet.
+ log_cfg: Log a configuration message.
+ log_warning: Log a warning message.
+ log_error: Log an error.
+ countset_add_element: Add an element to the countset.
+ log: log the given message.
+ log_recv: log a received packet.
+ log_send: log a sent packet.
+ log_process: log a processed packet.
+ log_cfg: log a configuration message.
+ log_warning: log a warning message.
+ log_error: log an error.
+ countset_add_element: add an element to the countset.
+ dict_regex_search: apply the regex over all the fields of the dictionary.
Constants:
+ COLORS: Colors to use in log messages.
+ COLORS: ANSI colors to use in log messages.
+ KIND_TO_COLOR: conversion between log kind and ANSI color
"""


COLORS = {'HEADER': '\033[95m', 'BLUE': '\033[94m', 'OK': '\033[92m',
'WARNING': '\033[93m', 'FAIL': '\033[91m', 'ENDC': '\033[0m',
'BOLD': '\033[1m', 'UNDERLINE': '\033[4m'}
COLORS = {
'RED': '\033[91m',
'GREEN': '\033[92m',
'YELLOW': '\033[93m',
'BLUE': '\033[94m',
'MAGENTA': '\033[95m',
'BOLD': '\033[1m',
'FAINT': '\033[2m',
'ITALIC': '\033[3m',
'UNDERLINE': '\033[4m',
'END': '\033[0m',
}

KIND_TO_COLOR = {
'WARNING': 'YELLOW|ITALIC',
'ERROR': 'RED|BOLD',
'IMPORTANT': 'BOLD'
}

def log(msg, level, state, color=None):

def log(content, level, state):
"""Log the given message."""
if state['verbosity'] < level:
return

# Add the clock if so
if not state['no_timestamp']:
if 'clocks' in state:
clock = " %s " % state['clocks'][1].isoformat()
else:
clock = "".ljust(28)
msg = clock + "|" + msg
# Add the clock if available
if 'clocks' in state and state['clocks'][1]:
content['timestamp'] = " %s " % state['clocks'][1].isoformat()

# Add the current line if so
if state['show_lines']:
msg = " %05d/%04d |%s" % (
state['input_line'], state['output_line'] + 1, msg)
# Add the current line
content['input_line'] = state['input_line']
content['output_line'] = state['output_line'] + 1 # This message count

if 'onlyIf' in state and not state['onlyIf'].search(msg):
# Apply the filter
if 'onlyIf' in state and not dict_regex_search(content, state['onlyIf']):
return

# Highlight the message if so
if 'highlight' in state and state['highlight'].search(msg):
color = (color or "") + COLORS['BOLD']
# Highlight the message if match
if 'highlight' in state and dict_regex_search(content, state['highlight']):
content['kind'] = content.get('kind', "") + "|IMPORTANT"

# Apply color if specified
if color and not state['no_colors']:
msg = color + msg + COLORS['ENDC']
if not state['no_colors']:
color = ""
for kind in filter(None, content.get('kind', '').split("|")):
for subkind in KIND_TO_COLOR[kind].split("|"):
color += COLORS[subkind]
if len(color) > 0:
content['description'] = color + content['description'] + \
COLORS['END']

# Write the message
state['output_device'].write(msg)
state['format_device'].write_message(content, state)


def log_recv(addr, entity, text, state, level=0):
"""Log a received packet."""
if not state['ignore_packets']:
log("%s|%s|%s| %s" %
("---> ".rjust(9), addr.center(24), entity.center(16), text),
level, state)
if state['ignore_packets']:
return
content = {'description': text, 'remote': addr, 'entity': entity,
'inout': 'in'}
log(content, level, state)


def log_send(addr, entity, text, state, level=0):
"""Log a sent packet."""
if not state['ignore_packets']:
log("%s|%s|%s| %s" %
(" <---".ljust(9), addr.center(24), entity.center(16), text),
level, state)
if state['ignore_packets']:
return
content = {'description': text, 'remote': addr, 'entity': entity,
'inout': 'out'}
log(content, level, state)


def log_process(addr, entity, text, state, level=0):
"""Log a processed packet."""
if not state['ignore_packets']:
log("%s|%s|%s| %s" %
("".ljust(9), addr.center(24), entity.center(16), text),
level, state)
if state['ignore_packets']:
return
content = {'description': text, 'remote': addr, 'entity': entity}
log(content, level, state)


def log_cfg(text, state, level=0):
Expand All @@ -103,8 +125,8 @@ def log_cfg(text, state, level=0):

def log_event(text, state, level=0):
"""Log an application event."""
log("%s|%s|%s| %s" % ("".ljust(9), "".ljust(24), "".ljust(16), text),
level, state)
content = {'description': text}
log(content, level, state)


def log_warning(text, state, level=0):
Expand All @@ -114,9 +136,8 @@ def log_warning(text, state, level=0):

countset_add_element(state['warnings'], text)
if state['inline']:
text = "%s|%s|%s| *Warning: %s*" % (
"".ljust(9), "".ljust(24), "".ljust(16), text)
log(text, level, state, COLORS['WARNING'])
content = {'description': "Warning: " + text, 'kind': 'WARNING'}
log(content, level, state)


def log_error(text, state, level=0):
Expand All @@ -126,13 +147,20 @@ def log_error(text, state, level=0):

countset_add_element(state['errors'], text)
if state['inline']:
text = "%s|%s|%s| **Error: %s**" % (
"".ljust(9), "".ljust(24), "".ljust(16), text)
log(text, level, state, COLORS['FAIL'])
content = {'description': "Error: " + text, 'kind': 'ERROR'}
log(content, level, state)


def countset_add_element(countset, el):
"""Add an element to the countset."""
if el not in countset:
countset[el] = [len(countset), 0]
countset[el][1] += 1


def dict_regex_search(content, regex):
"""Apply the regex over all the fields of the dictionary."""
match = False
for field in content:
match = match if match else regex.search(field)
return match
Loading

0 comments on commit 5e6b602

Please sign in to comment.