X-Git-Url: http://git.treefish.org/~alex/logalert.git/blobdiff_plain/6b726fdf122e07843cbaafd2f2ea76338a5878da..082f53238d44c1b52dc6a8110ec7dc4c56aa41df:/src/logalert.py?ds=inline diff --git a/src/logalert.py b/src/logalert.py index d240f44..c8eed19 100755 --- a/src/logalert.py +++ b/src/logalert.py @@ -2,60 +2,12 @@ import argparse import logging -import os -import shlex -import subprocess import time -from line import Line +import misc MAX_LINES = 10 - -def follow(filename): - while True: - try: - with open(filename, "r") as f: - logging.info("Re-attached to log file.") - for line in f: pass - while True: - line = f.readline() - if not line: - if not os.path.exists(filename): - break - else: - time.sleep(1.0) - yield None - else: - yield line.rstrip("\n") - except FileNotFoundError: - time.sleep(1.0) - yield None - -def feed_handler(data): - try: - handler = subprocess.Popen(shlex.split(args.handler), - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - encoding='UTF-8') - out_data, err_data = handler.communicate("%s\n" % data) - if handler.returncode != 0: - logging.warning("Handler exited with non-zero return code %d! (%s)" % - (handler.returncode, err_data)) - except Exception as e: - logging.error("Error feeding handler: %s" % str(e)) - -def create_msg(title, icon, logfile, text, lines): - msg = "%s %s %s" % (title, logfile, icon) - msg += "
%s" % text - msg += "
"
-    for line in lines: msg += line + "\n"
-    msg += "
" - return msg - -logging.basicConfig(format='[%(asctime)s] %(levelname)s: %(message)s', - level=logging.INFO, - datefmt='%m/%d/%Y %H:%M:%S') +ALERT_INTERVAL = 86400 parser = argparse.ArgumentParser(description='Alert on excessive number of error log lines.') parser.add_argument('logfile', type=str, help='logfile to be watched') @@ -65,50 +17,57 @@ parser.add_argument('-s', '--interval-size', type=int, default=600, dest='interv 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') + kept_times = [] lines = [] -last_time = None +last_slot_time = None error_state = False +last_alert_time = 0 -for line in follow(args.logfile): - now = int(time.time()) // args.interval_size +for line in misc.follow_file(args.logfile): + time_now = time.time() + slot_now = int(time_now) // args.interval_size if line != None: - if not last_time or now > last_time: - kept_times.append(now) - last_time = now + if not last_slot_time or slot_now > last_slot_time: + kept_times.append(slot_now) + last_slot_time = slot_now lines.append(line) if len(lines) > MAX_LINES: lines.pop(0) while len(kept_times) > 0 and \ - kept_times[0] <= now - args.num_intervals: + kept_times[0] <= slot_now - (args.num_intervals + 1): kept_times.pop(0) - intervals = [False] * args.num_intervals + intervals = [False] * (args.num_intervals + 1) for kept_time in kept_times: - intervals[now - kept_time] = True + intervals[slot_now - kept_time] = True logging.debug(intervals) - if not False in intervals: + if not False in intervals[1:]: + 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", + "☠", + args.logfile, + "Number of errors exceeded!", + lines) ) if not error_state: logging.warning("Entering error state!") error_state = True - feed_handler( create_msg("Log Alert", - "☠", - args.logfile, - "Number of errors exceeded!", - lines) ) + else: if error_state: logging.info("Leaving error state.") error_state = False - feed_handler( create_msg("Log Un-Alert", - "🌞", - args.logfile, - "Log is back to normal.", - lines) )