#!/usr/bin/env python3
# Copyright 2026 SigmaSRC, Inc. All Rights Reserved.

"""Print statistics about the log file.

Usage: %prog [logfile] ...

Note: logging uses local time.  The first line of the log file should
show the UTC time it was started.

"""

import os
import re
import sys
import time
import optparse

from sigma.util import config
from sigma.util.errors import usage, error

parser = optparse.OptionParser(usage=__doc__.strip())
options = config.Options()
logdir = options.agentlogs
pattern = options.log_prefix + ".%04d-%02d-%02d.txt"

def main(args=None):
    ops, args = parser.parse_args(args)
    if not args:
        ymd = time.localtime()[:3]
        logfile = os.path.join(logdir, pattern % ymd)
        args = [logfile]
    ls = LogStats()
    sts = 0
    for arg in args:
        if not ls.process(arg):
            sts = 1
    ls.report()
    return sts

logre = r"""(?x)

        (?P<year> \d+) - (?P<month> \d+) - (?P<day> \d+)
        \s+
        (?P<hour> \d+) : (?P<minute> \d+) : (?P<second> \d+)
        (?: , (?P<msec> \d+))?
        :
        (?P<module> [^\s:]+)
        :
        (?P<level> \w+)
        :
        (?P<message> .*)
        """

logprog = re.compile(logre)

class LogStats(object):

    def __init__(self):
        self.bymod = {}
        self.bymsg = {}

    def process(self, filename):
        try:
            f = open(filename)
        except IOError as err:
            error("Can't open %s: %s", filename, err)
            return False
        print("Processing", filename, "...")
        count = errors = 0
        try:
            for line in f:
                if self.analyze(line):
                    count += 1
                else:
                    errors += 1
                    #sys.stderr.write("Ignored: %r\n" % line)
        finally:
            f.close()
        print("... %d lines, %d errors" % (count, errors))
        return True

    def analyze(self, line):
        m = logprog.match(line)
        if m is None:
            return False # Skip unrecognized lines
        module = m.group("module")
        if module.startswith("sigma.gathering.Table."):
            module = "sigma.gathering.Table"
        level = m.group("level")
        key = module + ":" + level
        self.bymod[key] = self.bymod.get(key, 0) + 1
        msg = m.group("message")
        msg = re.sub(r"\d+", "0", msg)
        msg = re.sub(r"'[^'\s]+'", "'X'", msg)
        msg = re.sub(r"\([\w.]+\)", "(X)", msg)
        msg = re.sub(r"/spool/spool\S+", "/spool/spool...", msg)
        msg = re.sub(r"^Rule 0: .*", "Rule 0: ...", msg)
        msg = re.sub(r"^Task [\w.-]+", "Task X", msg)
        msg = re.sub(r"^removed .*", "removed X", msg)
        msg = re.sub(r"^can't write state file .*",
                     "can't write state file X", msg)
        msg = re.sub(r"^Line 0 (offset 0): .*", "Line 0 (offset 0): X", msg)
        if key == "sigma.fuelc.compile:ERROR":
            msg = "X"
        key = key + ":" + msg
        self.bymsg[key] = self.bymsg.get(key, 0) + 1
        return True

    def report(self):
        L = [(count, key) for key, count in self.bymod.items()]
        L.sort()
        L.reverse()
        for count, key in L:
            print("%6d %s" % (count, key))
        print('-'*20)
        L = [(count, key) for key, count in self.bymsg.items()]
        L.sort()
        L.reverse()
        for count, key in L:
            print("%6d %s" % (count, key))

if __name__ == "__main__":
    sys.exit(main())
