I have come up with some code to send a file's exceptions as an email, and update a .txt log file. This method works for the following example:
from send_mail import send_error_email
from datetime import datetime
import logging
logging.basicConfig(filename='log.txt', level=logging.DEBUG, format='%(asctime)s %(levelname)s %(name)s %(message)s')
logger=logging.getLogger(__name__)
now = datetime.now()
date = now.strftime("%m/%d/%Y")
time = now.strftime("%H:%M:%S")
try:
a = 2 'seven'
except Exception as e:
print(e)
send_error_email(exception=e, message="Can't add string and int")
logging.exception('Oh no! Error on {} at {} Here is the traceback info:'.format(date, time))
However, the functions I want to apply it to have a lot of if/else
syntax where exceptions are raised in the if
or else
block. Here are two examples:
def is_empty(test_df):
if(test_df.empty):
raise Exception("The sheet: {} is empty".format(sheet_name))
else:
pass
for col in test_df.columns:
miss = test_df[col].isnull().sum()
if miss>0:
raise Exception("{} has {} missing value(s)".format(col,miss))
return None
or
def column_validation(sheet_name, input_file, expected_columns, input_columns, months):
if len(expected_columns) == len(input_columns):
for i in range(len(input_columns)):
if input_columns[i] != expected_columns[i]:
if sheet_name == "G2 30yr":
if input_columns[i][:3] in months:
continue
elif sheet_name != "G2 30yr":
if input_columns[i] in months:
continue
else:
raise Exception("The {} sheet of file: {}'s columns are not in expected format.".format(sheet_name, input_file))
else:
raise Exception("Number of columns in file: {}, {} sheet are not as expected".format(input_file, sheet_name))
return None
I'm not sure how to employ the emailing and log function with exceptions that are raised outside of try/except
blocks where I can access the Exception attributes using except Exception as e:
. The below else
will send the email notification but will not correctly update the log file.
else:
send_error_email(exception=e, message="Can't add string and int")
logging.error('Oh no! Error on {} at {} Here is the traceback info:'.format(date, time), stack_info = True)
CodePudding user response:
def catch_exception_and_send_email(func):
def exception_catcher(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception e:
print(e)
now = datetime.now()
date = now.strftime("%m/%d/%Y")
time = now.strftime("%H:%M:%S")
send_error_email(exception=e, message="Can't add string and int")
logging.exception('Oh no! Error on {} at {} Here is the traceback info:'.format(date, time))
return exception_catcher
Now, use this to decorate the functions you anticipate possibly raising exceptions:
@exception_catcher
def is_empty(test_df):
# function body
@exception_catcher
def column_validation(sheet_name, input_file, expected_columns, input_columns, months):
# function body
Now, whenever any of your decorated functions are called, the decorator's code will run, first try
ing your function's code, and if your function raise
s an exception, the decorator catches it, logs it, and sends the email.
I'd also suggest implementing custom exceptions, but that's beside the point here.