13 ALERT_INTERVAL = 86400
18 with open(filename, "r") as f:
19 logging.info("Re-attached to log file.")
24 if not os.path.exists(filename):
30 yield line.rstrip("\n")
31 except FileNotFoundError:
35 def feed_handler(data):
37 handler = subprocess.Popen(shlex.split(args.handler),
38 stdin=subprocess.PIPE,
39 stdout=subprocess.PIPE,
40 stderr=subprocess.PIPE,
42 out_data, err_data = handler.communicate("%s\n" % data)
43 if handler.returncode != 0:
44 logging.warning("Handler exited with non-zero return code %d! (%s)" %
45 (handler.returncode, err_data))
46 except Exception as e:
47 logging.error("Error feeding handler: %s" % str(e))
49 def create_msg(title, icon, logfile, text, lines):
50 msg = "<b>%s</b> <i>%s</i> %s" % (title, logfile, icon)
51 msg += "<br>%s" % text
53 for line in lines: msg += line + "\n"
57 logging.basicConfig(format='[%(asctime)s] %(levelname)s: %(message)s',
59 datefmt='%m/%d/%Y %H:%M:%S')
61 parser = argparse.ArgumentParser(description='Alert on excessive number of error log lines.')
62 parser.add_argument('logfile', type=str, help='logfile to be watched')
63 parser.add_argument('handler', type=str,
64 help='alert will be delivered to standard input of handler')
65 parser.add_argument('-s', '--interval-size', type=int, default=600, dest='interval_size',
66 help='sample interval size in seconds (default: 600)')
67 parser.add_argument('-n', '--num-intervals', type=int, default=6, dest='num_intervals',
68 help='number of intervals to keep in history (default: 6)')
70 args = parser.parse_args()
78 for line in follow(args.logfile):
79 time_now = time.time()
80 slot_now = int(time_now) // args.interval_size
83 if not last_slot_time or slot_now > last_slot_time:
84 kept_times.append(slot_now)
85 last_slot_time = slot_now
87 if len(lines) > MAX_LINES:
90 while len(kept_times) > 0 and \
91 kept_times[0] <= slot_now - (args.num_intervals + 1):
94 intervals = [False] * (args.num_intervals + 1)
95 for kept_time in kept_times:
96 intervals[slot_now - kept_time] = True
98 logging.debug(intervals)
100 if not False in intervals[1:]:
101 if not error_state or time_now - last_alert_time > ALERT_INTERVAL:
102 last_alert_time = time_now
103 feed_handler( create_msg("Log Alert",
106 "Number of errors exceeded!",
109 logging.warning("Entering error state!")
114 logging.info("Leaving error state.")
116 feed_handler( create_msg("Log Un-Alert",
119 "Log is back to normal.",