#!/usr/bin/env python3

import argparse
import logging
import os
import signal
import time

import misc

LINES_TO_KEEP = 10
ALERT_INTERVAL = 86400

def handleInterrupt(sig, frame):
    global stop
    if os.getpid() == mainPid:
        logging.info( "Got stop signal." )
        stop = True

mainPid = os.getpid()
signal.signal(signal.SIGINT, handleInterrupt)

stop = False

parser = argparse.ArgumentParser(description='Alert on excessive number of error log lines.')
parser.add_argument('logfile', type=str, help='logfile to be watched')
parser.add_argument('handler', type=str,
                    help='alert will be delivered to standard input of handler')
parser.add_argument('-s', '--interval-size', type=int, default=600, dest='interval_size',
                    help='sample interval size in seconds (default: 600)')
parser.add_argument('-n', '--num-intervals', type=int, default=6, dest='num_intervals',
                    help='number of intervals to keep in history (default: 6)')
parser.add_argument('-l', '--log-level', type=str, default='INFO', dest='log_lvl',
                    choices=['DEBUG', 'INFO', 'WARNING'], help='select log level')

args = parser.parse_args()

logging.basicConfig(format='[%(asctime)s] %(levelname)s: %(message)s',
                    level=logging.getLevelName(args.log_lvl),
                    datefmt='%m/%d/%Y %H:%M:%S')

num_intervals = (args.num_intervals + 1)
intervals = [False] * num_intervals
lines = []
last_time_slot = 0
interval_ptr = 0
error_state = False
last_alert_time = 0

for line in misc.follow_file(args.logfile):
    time_now = time.time()
    time_slot = int(time_now) // args.interval_size
    time_slot_diff = time_slot - last_time_slot
    last_time_slot = time_slot

    interval_ptr = (interval_ptr + time_slot_diff) % num_intervals
    for i in range(0, min(num_intervals, time_slot_diff)):
        intervals[(interval_ptr + i ) % num_intervals] = False

    if line:
        intervals[interval_ptr] = True
        lines.append(line)
        if len(lines) > LINES_TO_KEEP:
            lines.pop(0)

    logging.debug( misc.print_list(intervals, interval_ptr) )

    intervals_error_state = True
    for i in range(1, num_intervals):
        if not intervals[(interval_ptr + i) % num_intervals]:
            intervals_error_state = False
            break

    if intervals_error_state:
        if not error_state or time_now - last_alert_time > ALERT_INTERVAL:
            last_alert_time = time_now
            misc.feed_handler( args.handler,
                               misc.create_msg("Log Alert",
                                               "&#9760;",
                                               args.logfile,
                                               lines) )
        if not error_state:
            logging.warning("Entering error state!")
            error_state = True

    else:
        if error_state:
            logging.info("Leaving error state.")
            error_state = False

    if stop:
        break
