我将日志记录模块MemoryHandler设置为为SMTPHandler目标排队调试和错误消息。我想要的是当包含所有调试语句的进程错误(每行一个)时发送一封电子邮件。我得到的是每个调试消息的单独电子邮件。
这看起来应该是微不足道的,也是日志记录包的一部分,但我找不到任何关于它的内容,没有例子,谷歌上没有任何内容。
log = logging.getLogger()
log.setLevel(logging.DEBUG)
debug_format = logging.Formatter("%(levelname)s at %(asctime)s in %(filename)s (line %(lineno)d):: %(message)s")
# write errors to email
error_mail_subject = "ERROR: Script error in %s on %s" % (sys.argv[0], os.uname()[1])
error_mail_handler = logging.handlers.SMTPHandler(SMTP_HOST, 'errors@'+os.uname()[1], [LOG_EMAIL], error_mail_subject)
error_mail_handler.setLevel(logging.ERROR)
#error_mail_handler.setLevel(logging.DEBUG)
error_mail_handler.setFormatter(debug_format)
# buffer debug messages so they can be sent with error emails
memory_handler = logging.handlers.MemoryHandler(1024*10, logging.ERROR, error_mail_handler)
memory_handler.setLevel(logging.DEBUG)
# attach handlers
log.addHandler(memory_handler)
log.addHandler(error_mail_handler)
与此相关:
如果error_mail_handler
目标是memory_handler
,是否需要将error_mail_handler
明确添加到记录器中?
memory_handler
应该设置为DEBUG还是ERROR目标?当它从{{1}}喂养时是否还需要一个目标?
很想看到解决此问题的任何人的一些工作代码。
答案 0 :(得分:25)
您可能希望使用或修改this test script中的BufferingSMTPHandler
。
通常,如果记录器的目标是已添加到记录器的MemoryHandler处理程序,则无需向记录器添加处理程序。如果设置处理程序的级别,这将影响处理程序实际处理的内容 - 它将不处理任何比其级别设置更不严重的程序。
答案 1 :(得分:5)
我编写了自己的BufferingSMTPHandler
的beastly线程安全实现,它从一个单独的线程发送电子邮件。主要目标是不阻止主线程。
如上所述,它使用两个队列 - 这似乎是必要的,以便实现一些在代码的“可配置参数”部分中定义的有用的类级参数。虽然您可以按原样使用代码,但如果您学习并使用它来编写自己的类,可能会更好。
的问题:
threading.Timer
或signal
模块来避免永远运行的循环。答案 2 :(得分:2)
如果您使用的是django - 这里是简单的缓冲处理程序,它将使用标准的django电子邮件方法:
import logging
from django.conf import settings
from django.core.mail import EmailMessage
class DjangoBufferingSMTPHandler(logging.handlers.BufferingHandler):
def __init__(self, capacity, toaddrs=None, subject=None):
logging.handlers.BufferingHandler.__init__(self, capacity)
if toaddrs:
self.toaddrs = toaddrs
else:
# Send messages to site administrators by default
self.toaddrs = zip(*settings.ADMINS)[-1]
if subject:
self.subject = subject
else:
self.subject = 'logging'
def flush(self):
if len(self.buffer) == 0:
return
try:
msg = "\r\n".join(map(self.format, self.buffer))
emsg = EmailMessage(self.subject, msg, to=self.toaddrs)
emsg.send()
except Exception:
# handleError() will print exception info to stderr if logging.raiseExceptions is True
self.handleError(record=None)
self.buffer = []
在django settings.py中,您需要配置电子邮件和日志记录,如下所示:
EMAIL_USE_TLS = True
EMAIL_PORT = 25
EMAIL_HOST = '' # example: 'smtp.yandex.ru'
EMAIL_HOST_USER = '' # example: 'user@yandex.ru'
EMAIL_HOST_PASSWORD = ''
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
SERVER_EMAIL = EMAIL_HOST_USER
LOGGING = {
'handlers': {
...
'mail_buffer': {
'level': 'WARN',
'capacity': 9999,
'class': 'utils.logging.DjangoBufferingSMTPHandler',
# optional:
# 'toaddrs': 'admin@host.com'
# 'subject': 'log messages'
}
},
...
}
答案 3 :(得分:2)
更新了 Vinay Sajip 对 python3 的回答。
import logging
from logging.handlers import BufferingHandler
class BufferingSMTPHandler(BufferingHandler):
def __init__(self, mailhost, fromaddr, toaddrs, subject, capacity):
logging.handlers.BufferingHandler.__init__(self, capacity)
self.mailhost = mailhost
self.mailport = None
self.fromaddr = fromaddr
self.toaddrs = toaddrs
self.subject = subject
self.setFormatter(logging.Formatter("%(asctime)s %(levelname)-5s %(message)s"))
def flush(self):
if len(self.buffer) > 0:
try:
import smtplib
port = self.mailport
if not port:
port = smtplib.SMTP_PORT
smtp = smtplib.SMTP(self.mailhost, port)
msg = '''From: {}\r\nTo: {}\r\nSubject: {}\r\n\r\n'''.format(
self.fromaddr,
",".join(self.toaddrs),
self.subject
)
for record in self.buffer:
s = self.format(record)
print (s)
msg = msg + s + "\r\n"
smtp.sendmail(self.fromaddr, self.toaddrs, msg)
smtp.quit()
except:
self.handleError(None) # no particular record
self.buffer = []
#update for @Anant
if __name__ == '__main__'
buff_smtp_handler=BufferingSMTPHandler(...your args)
buff_smtp_handler.setLevel(logging.ERROR)
handlers=[buff_smtp_handler]
logging.basicConfig(handlers=handlers)
答案 4 :(得分:0)
为此,我使用Vinay Sajip建议的 BufferingSMTPHandler 进行一次小调整:我将缓冲区长度设置为非常大的(比如5000个日志记录)并且manualy调用处理程序的flush方法检查互联网连接后每隔几秒钟。
# init
log_handler1 = BufferingSMTPHandler(
'smtp.host.lala', "from@test.com", ['to@test.com'], 'Log event(s)',5000)
...
logger.addHandler(log_handler1)
...
# main code
...
if internet_connection_ok and seconds_since_last_flush>60:
log_handler1.flush() # send buffered log records (if any)
答案 5 :(得分:0)
我认为有关SMTP记录器的要点是,它旨在发送重要的日志消息,如果将其发送给人工收件人或由自动收件人进行进一步处理,则将起到某种警报的作用。
如果要通过电子邮件发送日志消息的集合,则构成在任务执行结束时发送的报告,并将该日志写入文件,然后通过电子邮件发送该文件似乎是一个合理的解决方案。
我研究了基本的FileHandler日志处理程序,以及如何建立一种机制来写入临时文件,然后在脚本退出时附加该临时文件。
我找到了“ atexit”模块,该模块允许注册一种方法,该方法将在脚本退出时针对对象执行。
import logging
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
import os
from email import encoders
import uuid
# atexit allows for a method to be set to handle an object when the script exits
import atexit
filename = uuid.uuid4().hex
class MailLogger:
def __init__(self, filePath, smtpDict):
self.filePath = filePath
self.smtpDict = smtpDict
# Generate random file name
filename = '%s.txt' % ( uuid.uuid4().hex )
# Create full filename
filename = '%s/%s' % (filePath,filename)
self.filename = filename
self.fileLogger = logging.getLogger('mailedLog')
self.fileLogger.setLevel(logging.INFO)
self.fileHandler = logging.FileHandler(filename)
self.fileHandler.setLevel(logging.INFO)
formatter = logging.Formatter('%(name)s - %(levelname)s - %(message)s')
self.fileHandler.setFormatter(formatter)
self.fileLogger.addHandler(self.fileHandler)
atexit.register(self.mailOut)
def mailOut(self):
'''
Script is exiting so time to mail out the log file
"emailSettings": {
"smtpServer" : "smtp.dom.com",
"smtpPort" : 25,
"sender" : "sender@dom.com>",
"recipients" : [
"recipient@dom.com"
],
"subject" : "Email Subject"
},
'''
# Close the file handler
smtpDict = self.smtpDict
self.fileHandler.close()
msg = MIMEMultipart('alternative')
s = smtplib.SMTP(smtpDict["smtpServer"], smtpDict["smtpPort"] )
msg['Subject'] = smtpDict["subject"]
msg['From'] = smtpDict["sender"]
msg['To'] = ','.join(smtpDict["recipients"])
body = 'See attached report file'
content = MIMEText(body, 'plain')
msg.attach(content)
attachment = MIMEBase('application', 'octet-stream')
attachment.set_payload(open(self.filename, 'rb').read())
encoders.encode_base64(attachment)
attachment.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(self.filename))
msg.attach(attachment)
s.send_message(msg)
s.quit()
我的基本测试脚本是:
from EmailLogRpt import MailLogger
import time
smtpDict = {
"smtpServer" : "smtp.dom.com",
"smtpPort" : 25,
"sender" : "sender@dom.com",
"recipients" : [
"recpient@dom.com>"
],
"subject" : "Email Subject"
}
myMailLogger = MailLogger("/home/ed/tmp",smtpDict).fileLogger
myMailLogger.info("test msg 1")
time.sleep(5)
myMailLogger.info("test msg 2")
希望这对某人有帮助。