"""Parse the BLATHER logging generated by ZEO.

An example of the log format is:
2002-04-15T13:05:29 BLATHER(-100) ZEO Server storea(3235680, [714], 235339406490168806) ('10.0.26.30', 45514)
"""

import operator
import re
import time

rx_time = re.compile('(\d\d\d\d-\d\d-\d\d)T(\d\d:\d\d:\d\d)')

def parse_time(line):
    """Return the time portion of a zLOG line in seconds or None."""
    mo = rx_time.match(line)
    if mo is None:
        return None
    date, time_ = mo.group(1, 2)
    date_l = [int(elt) for elt in date.split('-')]
    time_l = [int(elt) for elt in time_.split(':')]
    return int(time.mktime(date_l + time_l + [0, 0, 0]))

rx_meth = re.compile("ZEO Server (\w+)\((.*)\) \('(.*)', (\d+)")

def parse_method(line):
    pass

def parse_line(line):
    """Parse a log entry and return time, method info, and client."""
    t = parse_time(line)
    if t is None:
        return None, None, None
    mo = rx_meth.search(line)
    if mo is None:
        return None, None, None
    meth_name = mo.group(1)
    meth_args = mo.group(2)
    meth_args = [s.strip() for s in meth_args.split(",")]
    m = meth_name, tuple(meth_args)
    c = mo.group(3), mo.group(4)
    return t, m, c

class TStats:
    pass

class TransactionParser:

    def __init__(self):
        self.transactions = []
        self.cur_t = {}
        self.skipped = 0

    def parse(self, line):
        t, m, c = parse_line(line)
        if t is None:
            return
        name = m[0]
        meth = getattr(self, name, None)
        if meth is not None:
            meth(t, m[1], c)

    def tpc_begin(self, time, args, client):
        t = TStats()
        t.begin = time
        t.url = args[2]
        t.objects = []
        self.cur_t[client] = t

    def tpc_finish(self, time, args, client):
        t = self.cur_t.get(client, None)
        if t is None:
            self.skipped += 1
            return
        t.finish = time
##        self.transactions.append(t)
        self.report(t)
        self.cur_t[client] = None

    def storea(self, time, args, client):
        t = self.cur_t.get(client, None)
        if t is None:
            self.skipped += 1
            return
        # append the oid and the length of the object
        # parse the length as [NNN]
        info = int(args[0]), int(args[1][1:-1])
        t.objects.append(info)

    def report(self, t):
        """Print a report about the transaction"""
        if t.objects:
            bytes = reduce(operator.add, [size for oid, size in t.objects])
        else:
            bytes = 0
        print "%s %2d %4d %10d %s" % (t.begin, t.finish - t.begin,
                                      len(t.objects), bytes,
                                      time.ctime(t.begin)), t.url

if __name__ == "__main__":
    import fileinput

    p = TransactionParser()
    i = 0
    for line in fileinput.input():
        i += 1
        try:
            p.parse(line)
        except:
            print "line", i
            raise
    print len(p.transactions)
