log_formatter.py
author Tero Marttila <terom@fixme.fi>
Mon, 09 Feb 2009 23:49:57 +0200
changeset 73 5a7188bf2894
parent 72 5ade0288f2ec
child 79 43ac75054d5c
permissions -rw-r--r--
split defined configuration constants into config, and implement search result pagination
"""
    Format LogLines into some other representation
"""

import re, xml.sax.saxutils

from log_line import LogTypes

class LogFormatter (object) :
    """
        Provides a method to format series of LogLines into various output formats, with varying themes.
    """

    # machine-readable name
    name = None

    # human-readable name
    title = None

    ## parameters
    # use a fixed-width font for HTML output
    html_fixedwidth = True

    def __init__ (self, tz, timestamp_fmt="%H:%M:%S") :
        """
            Initialize to format timestamps with the given timezone and timestamp
        """

        self.tz = tz
        self.timestamp_fmt = timestamp_fmt
    
    def _format_line_text (self, line, template_dict, full_timestamp=False) :
        """
            Format the given line as text, using the given { type: string template } dict
        """
            
        # look up the template
        template = template_dict[line.type]
        
        # convert timestamp into display timezone
        dtz = line.timestamp.astimezone(self.tz)
        
        # full timestamps?
        if full_timestamp :
            # XXX: ugly hack
            timestamp_fmt = '%Y-%m-%d ' + self.timestamp_fmt

        else :
            timestamp_fmt = self.timestamp_fmt

        # build timestamp
        timestamp = dtz.strftime(timestamp_fmt)
        
        # format with dict
        return template % dict(
            timestamp       = timestamp,
            source          = line.source,
            data            = line.data,
        )
    
    def format_txt (self, lines, full_timestamps=False) :
        """
            Format given lines as plaintext.

            If full_timestamps is given, the output will contain full timestamps with both date and time.

            No trailing newlines.
        """

        abstract

    def format_html (self, lines, full_timestamps=False) :
        """
            Format as HTML.
            
            See format_txt for information about arguments
        """

        abstract

class BaseHTMLFormatter (object) :
    """
        Implements some HTML-formatting utils
    """

    URL_REGEXP = re.compile(r"http://\S+")

    def _process_links (self, line) :
        """
            Processed the rendered line, adding in <a href>'s for things that look like URLs, returning the new line.

            The line should already be escaped
        """

        def _encode_url (match) :
            # encode URL
            url_html = match.group(0)
            url_link = xml.sax.saxutils.unescape(url_html)

            return '<a href="%(url_link)s">%(url_html)s</a>' % dict(url_link=url_link, url_html=url_html)

        return self.URL_REGEXP.sub(_encode_url, line)

class IrssiTextFormatter (LogFormatter) :
    """
        Implements format_txt for irssi-style output
    """

    # format definitions by type
    __FMT = {
        LogTypes.RAW        : "%(timestamp)s %(data)s",
    }

    def format_txt (self, lines, full_timestamps=False) :
        # ...handle each line
        for line in lines :
            # using __TYPES
            yield line, self._format_line_text(line, self.__FMT, full_timestamps)

class IrssiFormatter (IrssiTextFormatter, BaseHTMLFormatter) :
    """
        Implements plain black-and-white irssi-style formatting
    """
    
    # name
    name = 'irssi'
    title = "Irssi (plain)"

    # parameters
    html_fixedwidth = True

    def format_html (self, lines, full_timestamps=False) :
        """
            Just uses format_txt, but processes links, etc
        """
        
        # format using IrssiTextFormatter
        for line, txt in self.format_txt(lines, full_timestamps) :
            # escape HTML
            html = xml.sax.saxutils.escape(txt)

            # process links
            html = self._process_links(html)

            # yield
            yield line, html

# define formatters by name
FORMATTERS = {
    'irssi':        IrssiFormatter,
}

def by_name (name) :
    """
        Lookup and return a class LogFormatter by name
    """

    return FORMATTERS[name]