|
import logging |
|
import logging.handlers |
|
import smtplib |
|
import sys |
|
import datetime |
|
|
|
|
|
logging.basicConfig(stream=sys.stderr,level=logging.DEBUG,format="%(asctime)s %(name)s %(levelname)s: %(filename)s %(lineno)s: %(message)s") |
|
|
|
# https://stackoverflow.com/a/36937462/2743441 |
|
# Provide a class to allow SSL (Not TLS) connection for mail handlers by overloading the emit() method |
|
class SSLSMTPHandler(logging.handlers.SMTPHandler): |
|
def emit(self, record): |
|
""" |
|
Emit a record. |
|
""" |
|
try: |
|
port = self.mailport |
|
if not port: |
|
port = smtplib.SMTP_PORT |
|
smtp = smtplib.SMTP_SSL(self.mailhost, port) |
|
msg = self.format(record) |
|
if self.username: |
|
smtp.login(self.username, self.password) |
|
smtp.sendmail(self.fromaddr, self.toaddrs, msg) |
|
smtp.quit() |
|
except (KeyboardInterrupt, SystemExit): |
|
raise |
|
except: |
|
self.handleError(record) |
|
|
|
|
|
|
|
# http://mynthon.net/howto/-/python/python%20-%20logging.SMTPHandler-how-to-use-gmail-smtp-server.txt |
|
|
|
# Consider using https://github.com/Simplistix/mailinglogger/blob/master/mailinglogger/MailingLogger.py for flood prevention |
|
|
|
flood_template=""" |
|
Too Many Log Entries |
|
|
|
More than %s entries have been logged that would have resulted in |
|
emails being sent. |
|
|
|
No further emails will be sent for log entries generated between |
|
%s and %i:00:00 |
|
|
|
Please consult any other configured logs, such as a File Logger, |
|
that may contain important entries that have not been emailed. |
|
""" |
|
|
|
|
|
|
|
class TlsSMTPHandler(logging.handlers.SMTPHandler): |
|
|
|
|
|
def __init__(self,*args,flood_level=10,**kwargs) : |
|
super(TlsSMTPHandler, self).__init__(*args,**kwargs) |
|
self.hour = self.now().hour |
|
self.sent = 0 |
|
self.flood_level = flood_level |
|
|
|
|
|
def now(self) : |
|
return datetime.datetime.now() |
|
|
|
# https://stackoverflow.com/a/20801330/2743441 |
|
def getSubject(self, record): |
|
formatter = logging.Formatter(fmt=self.subject) |
|
return formatter.format(record) |
|
|
|
|
|
|
|
def emit(self, record): |
|
""" |
|
Emit a record. |
|
|
|
Format the record and send it to the specified addressees. |
|
""" |
|
current_time = self.now() |
|
current_hour = current_time.hour |
|
if current_hour != self.hour: |
|
self.hour = current_hour |
|
self.sent = 0 |
|
if self.sent == self.flood_level: |
|
# send critical error |
|
record = logging.LogRecord( |
|
name='flood', |
|
level=logging.CRITICAL, |
|
pathname='', |
|
lineno=0, |
|
msg=flood_template % (self.sent, |
|
current_time.strftime('%H:%M:%S'), |
|
current_hour + 1), |
|
args=(), |
|
exc_info=None) |
|
elif self.flood_level and self.sent > self.flood_level: |
|
# do nothing, we've sent too many emails already |
|
return |
|
self.sent += 1 |
|
try: |
|
import smtplib |
|
import string # for tls add this line |
|
try: |
|
from email.utils import formatdate |
|
except ImportError: |
|
formatdate = self.date_time |
|
port = self.mailport |
|
if not port: |
|
port = smtplib.SMTP_PORT |
|
smtp = smtplib.SMTP(self.mailhost, port) |
|
msg = self.format(record) |
|
msg = "From: %s\r\nTo: %s\r\nSubject: %s\r\nDate: %s\r\n\r\n%s" % ( |
|
self.fromaddr, |
|
",".join(self.toaddrs), |
|
self.getSubject(record), |
|
formatdate(), msg) |
|
if self.username: |
|
smtp.ehlo() # for tls add this line |
|
smtp.starttls() # for tls add this line |
|
smtp.ehlo() # for tls add this line |
|
smtp.login(self.username, self.password) |
|
smtp.sendmail(self.fromaddr, self.toaddrs, msg) |
|
smtp.quit() |
|
except (KeyboardInterrupt, SystemExit): |
|
raise |
|
except: |
|
self.handleError(record) |
|
|
|
|
|
|
|
def send_email_on(logger,level=logging.ERROR,handler=TlsSMTPHandler,flood_level=10) : |
|
from credentials import MAILERRORS |
|
mail_handler = handler(**MAILERRORS,flood_level=flood_level) |
|
mail_handler.setLevel(level) |
|
logger.addHandler(mail_handler) |
|
mail_handler.setFormatter(logging.Formatter(''' |
|
Message type: %(levelname)s |
|
Location: %(pathname)s:%(lineno)d |
|
Module: %(module)s |
|
Function: %(funcName)s |
|
Time: %(asctime)s |
|
|
|
Message: |
|
|
|
%(message)s |
|
''')) |
|
|
|
|
|
|
|
|
|
def test() : |
|
logger=logging.getLogger() |
|
from credentials import MAILERRORS |
|
send_email_on(logger,level=logging.ERROR,flood_level=1) |
|
print("Look out. Error below should be arriving at {toaddrs} from {fromaddr}".format(**MAILERRORS)) |
|
try : |
|
1/0 |
|
except Exception as e: |
|
logger.exception(e) |
|
print("next one should result in a flood warning") |
|
try : |
|
1/0 |
|
except Exception as e: |
|
logger.exception(e) |
|
|
|
|
|
|
|
|
|
if __name__ == '__main__' : |
|
test() |
|
|
|
|
|
|
|
|