Commit 7c483a04 authored by Trevor Cappallo's avatar Trevor Cappallo
Browse files

more cleanup

parent 7a1ecb30
......@@ -15,40 +15,43 @@ import StringIO
import OperationalMail
def __exitHandler(logger, addresses, critical_addresses):
def __exit_handler(logger, addresses, critical_addresses):
"""Email given addresses if there are any buffered errors."""
if logger.hasCritical():
if logger.has_critical():
addresses = list(set([a for a in itertools.chain(addresses, critical_addresses)]))
if not logger.hasErrors():
if not logger.has_errors():
logging.info('No errors found. Email not sent')
else:
if not addresses:
logging.warning('No recipients found. Email not sent')
else:
logger.emailLog(addresses)
logger.email_log(addresses)
class OperationalLogger:
"""Main class for Operational Logging."""
def __init__(self, log_file='log.txt', log_level=logging.DEBUG):
def __init__(self, log_file='log.txt', log_level=logging.DEBUG,
log_format=None, date_format=None, from_address=None):
"""Initialize logging handlers, formats, etc."""
self.__file_name = log_file
self.__server_name = socket.gethostbyaddr(socket.gethostname())[0]
self.__server_name = socket.getfqdn()
self.__full_buffer = StringIO.StringIO()
self.__error_buffer = StringIO.StringIO()
self.__critical_buffer = StringIO.StringIO()
logging.basicConfig(filename=log_file,
format='[%(asctime)s][%(levelname)s][p%(process)d][%(filename)s:%(lineno)d]:%(message)s',
datefmt='%Y/%m/%d %H:%M:%S',
level=log_level)
formatter = logging.Formatter(
fmt='[%(asctime)s][%(levelname)s][p%(process)d][%(filename)s:%(lineno)d]:%(message)s',
datefmt='%m/%d %H:%M:%S'
)
if log_format is None:
log_format = '[%(asctime)s][%(levelname)8s][p%(process)d][%(filename)s:%(lineno)d]:%(message)s'
self.__log_format = log_format
if date_format is None:
date_format = '%Y/%m/%d %H:%M:%S'
self.__date_format = date_format
if from_address is None:
from_address = 'no-reply@aer.com'
self.__from_address = from_address
logging.basicConfig(filename=log_file, format=self.__log_format, datefmt=self.__date_format, level=log_level)
formatter = logging.Formatter(fmt=self.__log_format, datefmt='%m/%d %H:%M:%S')
full_trigger = logging.StreamHandler(self.__full_buffer)
full_trigger.setLevel(logging.DEBUG)
......@@ -60,10 +63,11 @@ class OperationalLogger:
critical_trigger.setLevel(logging.CRITICAL)
critical_trigger.setFormatter(formatter)
logging.getLogger('').addHandler(error_trigger)
logging.getLogger('').addHandler(critical_trigger)
logging.getLogger('').addHandler(full_trigger)
logging.getLogger().addHandler(error_trigger)
logging.getLogger().addHandler(critical_trigger)
logging.getLogger().addHandler(full_trigger)
# provide a more concise format for terminal output
if sys.stdout.isatty():
console = logging.StreamHandler(sys.stdout)
console.setLevel(logging.DEBUG)
......@@ -71,21 +75,23 @@ class OperationalLogger:
fmt='[%(asctime)s][%(levelname)s][%(filename)s:%(lineno)d]:%(message)s',
datefmt='%m/%d %H:%M:%S'
))
logging.getLogger('').addHandler(console)
logging.getLogger().addHandler(console)
def hasErrors(self):
"""Return number of ERROR-level log statements in buffer."""
def has_errors(self):
"""Return whether any ERROR-level log statements in buffer."""
return len(self.__error_buffer.getvalue()) > 0
def hasCritical(self):
"""Return number of CRITICAL-level log statements in buffer."""
def has_critical(self):
"""Return whether any CRITICAL-level log statements in buffer."""
return len(self.__critical_buffer.getvalue()) > 0
def emailLog(self, addresses):
def email_log(self, addresses):
"""Send email to addresses with current buffered errors."""
message = "<br />\n".join([OperationalLogger.__colorize(l) for l in self.__error_buffer.getvalue().split('\n')])
OperationalMail.sendStatus('Errors detected {}:{}'.format(self.__server_name, os.path.basename(sys.argv[0])),
addresses, message, text_attachment=self.__full_buffer.getvalue())
OperationalMail.send_status(subject='Errors detected {}:{}'.format(self.__server_name,
os.path.basename(sys.argv[0])),
message=message, to_list=addresses, from_address=self.__from_address,
text_attachment=self.__full_buffer.getvalue())
@staticmethod
def __colorize(line):
......@@ -106,13 +112,17 @@ class OperationalLogger:
##########################################################################################
def defaultLogging(log_root_dir, log_file_name, addresses, critical_addresses):
"""Set an intelligent,context-dependent default logging scheme for the current script."""
def default_logging(log_root_dir=None, log_file_name=None, addresses=[], critical_addresses=[], from_address=None):
"""Set an intelligent,context-dependent default logging scheme for the current script.
log_root_dir, log_file_name: log will be created as log_root_dir/log/YYYY-MM-DD/LOG_FILE_NAME.log
log_file_name defaults to script name
addresses, critical_address: email addresses to be notified on respective level errors
"""
if not log_file_name:
log_file_name = os.path.basename(sys.argv[0])
# log_directory = os.path.join(ProjectConfiguration.ProjectConfiguration.projectRoot(),
# 'log', datetime.datetime.utcnow().strftime('%Y-%m-%d'))
if not log_root_dir:
log_root_dir = os.getcwd()
log_directory = os.path.join(log_root_dir, 'log', datetime.datetime.utcnow().strftime('%Y-%m-%d'))
if not os.path.exists(log_directory):
......@@ -122,18 +132,19 @@ def defaultLogging(log_root_dir, log_file_name, addresses, critical_addresses):
# Potential race condition. Warn, but do not error
logging.warning('Unable to create log directory {}:{}'.format(log_directory, str(err)))
logger = OperationalLogger(os.path.join(log_directory, '{}.log'.format(log_file_name)), logging.DEBUG)
logger = OperationalLogger(os.path.join(log_directory, '{}.log'.format(log_file_name)),
logging.DEBUG, from_address=from_address)
logging.info('Logging output from: {}'.format(' '.join(sys.argv)))
logging.info('Process id {}, parent process id {}'.format(os.getpid(), os.getppid()))
logging.info('-' * 60)
if addresses and not sys.stdout.isatty():
atexit.register(__exitHandler, logger, addresses, critical_addresses)
if addresses: # and not sys.stdout.isatty():
atexit.register(__exit_handler, logger, addresses, critical_addresses)
return
def longLog(logging_level=logging.INFO, message=''):
def long_log(logging_level=logging.INFO, message=''):
"""For program output, multi-line messages, etc.
When message has linebreaks, will break it into individual log calls for consistent formatting.
......@@ -141,35 +152,34 @@ def longLog(logging_level=logging.INFO, message=''):
message_list = message.split("\n")
for msg in message_list:
logging.log(logging_level, msg)
return
def longCritical(message):
def long_critical(message):
"""Log a multi-line CRITICAL message."""
longLog(logging.CRITICAL, message)
long_log(logging.CRITICAL, message)
def longError(message):
def long_error(message):
"""Log a multi-line ERROR message."""
longLog(logging.ERROR, message)
long_log(logging.ERROR, message)
def longWarning(message):
def long_warning(message):
"""Log a multi-line WARNING message."""
longLog(logging.WARNING, message)
long_log(logging.WARNING, message)
def longInfo(message):
def long_info(message):
"""Log a multi-line INFO message."""
longLog(logging.INFO, message)
long_log(logging.INFO, message)
def longDebug(message):
def long_debug(message):
"""Log a multi-line DEBUG message."""
longLog(logging.DEBUG, message)
long_log(logging.DEBUG, message)
def loggedSubprocess(arg_list):
def logged_subprocess(arg_list):
"""Pass arg_list to a subprocess call and log all output."""
logging.info('Child process of [p{}]'.format(os.getppid()))
logging.info('Attempting {}'.format(' '.join(arg_list)))
......@@ -177,27 +187,26 @@ def loggedSubprocess(arg_list):
results = subprocess.check_output(arg_list, stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as cpe:
logging.error('Call {} failed with exit code {}'.format(' '.join(arg_list), str(cpe.returncode)))
longError(cpe.output)
long_error(cpe.output)
except Exception as err:
logging.error('Unknown exception resulting from {}:{}'.format(' '.join(arg_list), str(err)))
else:
logging.info('Successfully completed {}'.format(' '.join(arg_list)))
longInfo(results)
long_info(results)
return 0
logging.warning('Failure on {}'.format(' '.join(arg_list)))
return -1
def stackTrace(logging_level=logging.ERROR):
def stack_trace(logging_level=logging.ERROR):
"""Log a stack trace at the given level."""
import traceback
tb = traceback.format_exc()
longLog(logging_level, tb)
return
long_log(logging_level, tb)
if __name__ == '__main__':
defaultLogging('basic_unit_test.foo.bar', addresses=['tcappallo@veriskclimate.com'])
default_logging(addresses=['tcappallo@veriskclimate.com'], from_address='tcappallo@veriskclimate.com')
test = """Blah
foo
bar
......@@ -208,10 +217,10 @@ if __name__ == '__main__':
logging.debug('Fin')
logging.error('An error in testing, oh, no!!')
logging.critical('Put up the Jimsignal!')
longError(test)
long_error(test)
try:
raise Exception("I AM ERROR.")
except Exception as e:
logging.debug(str(e))
stackTrace(logging.ERROR)
except Exception as err:
logging.debug(str(err))
stack_trace(logging.ERROR)
......@@ -9,9 +9,9 @@ from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
def sendStatus(subject, to_list, message, from_address,
password=None, text_attachment=None, reply_to='no-reply@aer.com',
**kwargs):
def send_status(subject, message, to_list, from_address,
password=None, text_attachment=None, reply_to='no-reply@aer.com', smtp_server='smtp.aer.com',
**kwargs):
"""Send an email message to a given recipient list."""
mail = MIMEMultipart('mixed')
mail['From'] = from_address
......@@ -45,7 +45,7 @@ def sendStatus(subject, to_list, message, from_address,
attachment.add_header('Content-Disposition', 'attachment', filename='full_log.txt')
mail.attach(attachment)
server = smtplib.SMTP('smtp.aer.com')
server = smtplib.SMTP(smtp_server)
if password:
user_name = from_address.partition('@')[0]
try:
......@@ -74,4 +74,4 @@ if __name__ == '__main__':
"""
default_addresses = ['acappallo@aer.com']
sendStatus('Non-pyProcess Email Module', default_addresses, msg)
send_status('Non-pyProcess Email Module', default_addresses, msg)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment