Задача скрипта – выполнять постоянную проверку лога приложения и, в случае обнаружения сообщений об ошибке подключения к базе данных, останавливать Tomcat.
Т.к. после трёх неудачных попыток подключения аккаунт на Oracle-сервере блокируется – необходимо было жестко останавливать приложение до того, как аккаунт будет заблокирован.
Для PROD-сервера – конечно, “убивать” приложение нельзя, поэтому – там скрипт только отправляет письмо.
Для чтения лога – используется модуль python-tail.
#!/usr/bin/env python import subprocess import os import sys import tail import smtplib import signal import datetime import logging import socket try: env = os.environ['ENV'] except KeyError as e: print('ERROR - no such variable: %s' % e) sys.exit(6) host = os.environ['HOSTNAME'] if env == 'DEV': app_basedir = '/home/user1/APP' elif env == 'SIT': app_basedir = '/home/user2/APP' elif env == 'UAT': app_basedir = '/home/user3/APP' elif env == 'REG': app_basedir = '/home/user4/APP' elif env == 'UDEP': app_basedir = '/home/user5/APP' elif env == 'PROD': app_basedir = '/usr/local/app_install/APP' else: print('nERROR! Unknown ENV. Exit.') sys.exit(1) catalina_home = app_basedir + '/application-server' # APP lo-file applicationlog = app_basedir + '/logs/application-app.log' # Tomcat log catalog = app_basedir + '/logs/catalina.out' # APPmanager log manalog = app_basedir + '/logs/application-manager.log' # LogParcer lof parcerlog = app_basedir + '/logs/logparcer.log' # list to check logfile logs = (applicationlog, catalog, manalog) # list to print names of log-files names = ('APP', 'Tomcat', 'APPmanager') # LogParcer PID to kill it when APPmanager -stop ppid = os.getpid() # file to save LogParcer PID ppidf = (app_basedir + '/logparser.pid') # Tomcat's PID file tpidf = (catalina_home + '/conf/catalina.pid') # email sender function sender = '[email protected]' receivers = ['[email protected]', '[email protected]', '[email protected]'] # message to be mailed message = """From: Logparser <[email protected]> To: APP team <[email protected]> Subject: Logparser on %s ALERT ALARM on %s!n """ % (env, host) # list of errors to parce errors = ('ORA-01017', 'ORA-28000') # logging properties logging.basicConfig(format = '%(filename)s[LINE:%(lineno)d] - %(levelname)-3s [%(asctime)s] %(message)s ', filename=parcerlog, level=logging.DEBUG) logging.info('LogParcer started') logging.info('Working on %s and using %s as $APP_BASEDIR, and %s as APP logfile.' % (env, app_basedir, applicationlog)) # save own PID to file def savepid(ppidf, ppid): if os.path.isfile(ppidf): logging.info('Found my own old PID file...') os.remove(ppidf) logging.info('Removed.') pidfile = open(ppidf, 'w') pidfile.write(ppid) pidfile.close() logging.info('Saved my PID %s in file %s.' % (ppid, ppidf)) # get Tomcat PID to kill def catapid(tpidf): try: catalina = open(tpidf, 'r') pid = catalina.readline() return pid except IOError as e: logging.critical("ERROR! Can't find catalina.pid: %sn" % e) sys.exit(3) # check if catalina.pid exist - otherwise LogParcer will can't kill it def catacheck(tpidf): if not os.path.isfile(tpidf): logging.critical("ERROR! Can't find catalina.pid: %sn" % tpid) sys.exit(4) # check log-files is exists def checkfile(log, name): if os.path.isfile(log): logging.info('%s log is: %s' % (name, log)) else: logging.critical('nERROR! Can't find log file! Exit.n') sys.exit(2) # sending notifications def sendmail(event): try: # get time time = datetime.datetime.now() timemes = 'nnSysevent at %s' % time # connect to local SMTP smtpconnect = smtplib.SMTP('localhost:25') # debug to sys.stdout currently is $OUTPUT_DIR/logparcer_mail.log smtpconnect.set_debuglevel(1) # sending email smtpconnect.sendmail(sender, receivers, message + event + timemes) # close conenction smtpconnect.quit() logging.info('Email sent from %s to %s.' % (sender, receivers)) # if anything wrong on local SMTP except socket.gaierror as s: logging.exception('Local SMTP error: %s' % s) except smtplib.SMTPException as e: logging.exception('ERROR during email sent: %s' % e) # APPmanager stops LogParcer with SIGINT (Ctrl+C same) def signal_handler(signal, frame): logging.info('Exited by APPmanager SIGINT.') sys.exit(0) # main error parces function def err(data): # check both errors if any(ora in data for ora in errors): # on PROD we don't need kill Tomcat if not env == 'PROD': # get Tomcat's PID pid = catapid(tpidf) # kill Tomcat with kill -9 try: # killing Tomcat with kill -9 os.kill(int(pid), signal.SIGKILL) # save message for email and log event = "Tomcat killed with PID %s.nnError data: nn%s" % (pid, data) logging.error(event) # sending email sendmail(event) logging.info('Email sent from %s to %s.n' % (sender, receivers)) # as Tomcat killed - LogParcer doesn't need anymore # will be started again when APPmanager -start sys.exit(0) # if can't find catalina.pid except OSError as e: event = "Got ALARM, but can't kill Tomcat: %s with PID %s" % (e, pid) sendmail(event) logging.critical(event) # if PROD - just send email, no kill else: event = "Tomcat wasn't killed. Please - check logs manually.n" sendmail(event) logging.error(event) # capture exit to write log message signal.signal(signal.SIGINT, signal_handler) # check if Tomcat was started and catalina.pid created # and it's PID file present catacheck(tpidf) # need PID of logparceer own process to kill it # when APPmanger -stop executed savepid(ppidf, str(ppid)) logging.info('Check log-files:') # running log-files checks for file, name in zip(logs, names): checkfile(file, name) logging.info('Files checked, OK.') # running main tail tail = tail.Tail(applicationlog) # when new line appears - sent it to 'err' function tail.register_callback(err) tail.follow()
ToDo: Добавить парсинг одновременно лога Tomcat и приложения.