from string import Template
from math import floor, ceil
from tabulate import tabulate
+import textwrap
import logparse
from logparse import interface, util, mail, config
JXNCHARS_SINGLE = ['├', '┤', '┬', '┴', '┼']
BULLET = "• "
INDENT = " "
+SPLIT_CHARS = ['.', '(', ')', '[', ']', '&', r"/", "\\", ',', '-', '_']
global VARSUBST
"hostname": util.hostname(config.prefs.get(
"logparse", "hostname-path")),
"version": logparse.__version__,
- "css": css_path
+ "css": css_path,
+ "period": util.LogPeriod("logparse").startdate.strftime(
+ TIMEFMT + " " + DATEFMT)
}
Print details with some primitive formatting
"""
box = PlaintextBox(content=
- Template("$title $version on $hostname\n\n$time $date")
+ Template("$title $version on $hostname\n\n$time $date"
+ "\nParsing logs since $period")
.safe_substitute(VARSUBST),
vpadding=2, hpadding="\t\t", linewidth=self.linewidth)
- line = PlaintextLine(self.linewidth)
- self.append(box.draw() + line.draw())
+ self.append(box.draw() + "\n"*2)
def append_footer(self):
"""
Append a horizontal line and some details
"""
- self.append(PlaintextLine(self.linewidth, vpadding=1).draw())
+ self.append(PlaintextLine(self.linewidth).draw())
self.append(Template("$hostname $time $date").safe_substitute(VARSUBST))
def append_section(self, section):
logger.warning("No subtitle provided.. skipping section")
return
+ logger.debug("Processing data {}".format(subtitle))
+
if (data == None or len(data) == 0):
- logger.debug("No data provided.. just printing subtitle")
- return subtitle + '\n'
+ # If no list items are provided, just print the subtitle
+ return subtitle + "\n"
+ elif (len(data) == 1):
+ # If only one item is provided, print it inline with subtitle
+ return self._wrap_datum("{}: {}".format(subtitle, data[0]),
+ bullet=False, indent=False) + "\n"
else:
- logger.debug("Received data " + str(data))
- subtitle += ':'
- if (len(data) == 1):
- return subtitle + ' ' + data[0] + '\n'
- else:
- itemoutput = subtitle + '\n'
- for datum in data:
- datum = BULLET + datum
- if len(datum) > self.linewidth - 3:
- words = datum.split()
- if max(map(len, words)) > self.linewidth - len(INDENT):
- continue
- res, part, others = [], words[0], words[1:]
- for word in others:
- if 1 + len(word) > self.linewidth - len(part):
- res.append(part)
- part = word
- else:
- part += ' ' + word
- if part:
- res.append(part)
- datum = ('\n ').join(res)
- datum = INDENT + datum
- itemoutput += datum + '\n'
- return itemoutput
+ # If many items are provided, print them all as a bulleted list
+ itemoutput = subtitle + ":\n"
+ for datum in data:
+ itemoutput += self._wrap_datum(datum) + "\n"
+ return itemoutput
+
+ def _wrap_datum(self, text, bullet=True, indent=True):
+ """
+ Use cpython's textwrap module to limit line width to the value
+ specified in self.linewidth. This is much easier than doing it all
+ from scratch (which I tried to do originally). Note that line
+ continuations are automatically indented even if they don't have a
+ bullet. This is to make it clear which lines are continuations.
+ """
+
+ wrapper = textwrap.TextWrapper(
+ initial_indent=(INDENT if indent else "") \
+ + (BULLET if bullet else ""),
+ subsequent_indent=INDENT + (' '*len(BULLET) if bullet else ""),
+ width=self.linewidth,
+ replace_whitespace=True)
+
+ return wrapper.fill(text)
+
class HtmlOutput(Output):
"""
logger.debug("No data provided.. just printing subtitle")
return tag('p', False, subtitle, cl="severity-" + str(severity))
else:
- logger.debug("Received data " + str(data))
+ logger.debug("Received data {}: {}".format(subtitle, data))
subtitle += ':'
if (len(data) == 1):
return tag('p', False, subtitle + ' ' + data[0],
def truncl(self, limit): # truncate list
"""
Truncate self.items to a specified value and state how many items are
- hidden.
+ hidden. Set limit to -1 to avoid truncating any items.
"""
+ if limit == -1:
+ return self
if (len(self.items) > limit):
more = len(self.items) - limit
if more == 1:
class Column(object):
"""
- Object representing a single table cell. This is somewhat of a misnomer -
- one column object exists for each cell in the table. Columns are children
+ Object representing a single table cell. "Column" is somewhat of a misnomer
+ - one column object exists for each cell in the table. Columns are children
of rows.
"""
Draw a horizontal line for plain text format, with optional padding/styling.
"""
- def __init__(self, linewidth=80, double=True, vpadding=1, hpadding=""):
+ def __init__(self, linewidth=80, double=True, vpadding=0, hpadding=""):
"""
Initialise variables
"""
line = (LINECHARS_DOUBLE[1] if self.double else LINECHARS_SINGLE[1])
return "\n" * self.vpadding + self.hpadding \
+ line * (self.linewidth - 2 * len(self.hpadding)) \
- + self.hpadding + "\n" * self.vpadding
+ + self.hpadding + "\n" * (self.vpadding + 1)
class PlaintextBox:
contentwidth = int((self.linewidth if self.linewidth > 0 else 80)
if self.content.splitlines()
else len(max(contentlines, key=len)))
- logger.debug("Contentwidth is {0}".format(str(contentwidth)))
+ logger.debug("Content width is {0}".format(str(contentwidth)))
logger.debug("Longest line is {0}".format(
len(max(contentlines, key=len))))
contentwidth += -2*(len(self.hpadding)+1)