2011-12-23 25 views
6

Tôi đã cài đặt một địa phương SMTP server và sử dụng logging.handlers.SMTPHandler để đăng nhập một ngoại lệ sử dụng mã này:Làm thế nào để làm cho SMTPHandler không chặn

import logging 
import logging.handlers 
import time 
gm = logging.handlers.SMTPHandler(("localhost", 25), '[email protected]', ['[email protected]'], 'Hello Exception!',) 
gm.setLevel(logging.ERROR) 
logger.addHandler(gm) 
t0 = time.clock() 
try: 
    1/0 
except: 
    logger.exception('testest') 
print time.clock()-t0 

Phải mất hơn 1 giây để hoàn thành, chặn kịch bản python cho toàn bộ thời gian này. Làm thế nào mà? Làm thế nào tôi có thể làm cho nó không chặn kịch bản?

Trả lời

13

Đây là triển khai tôi đang sử dụng, dựa trên số this Gmail adapted SMTPHandler.
Tôi lấy phần gửi đến SMTP và đặt nó vào một chủ đề khác.

import logging.handlers 
import smtplib 
from threading import Thread 

def smtp_at_your_own_leasure(mailhost, port, username, password, fromaddr, toaddrs, msg): 
    smtp = smtplib.SMTP(mailhost, port) 
    if username: 
     smtp.ehlo() # for tls add this line 
     smtp.starttls() # for tls add this line 
     smtp.ehlo() # for tls add this line 
     smtp.login(username, password) 
    smtp.sendmail(fromaddr, toaddrs, msg) 
    smtp.quit() 

class ThreadedTlsSMTPHandler(logging.handlers.SMTPHandler): 
    def emit(self, record): 
     try: 
      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 
      msg = self.format(record) 
      msg = "From: %s\r\nTo: %s\r\nSubject: %s\r\nDate: %s\r\n\r\n%s" % (
          self.fromaddr, 
          string.join(self.toaddrs, ","), 
          self.getSubject(record), 
          formatdate(), msg) 
      thread = Thread(target=smtp_at_your_own_leasure, args=(self.mailhost, port, self.username, self.password, self.fromaddr, self.toaddrs, msg)) 
      thread.start() 
     except (KeyboardInterrupt, SystemExit): 
      raise 
     except: 
      self.handleError(record) 

dụ Cách sử dụng:

logger = logging.getLogger() 

gm = ThreadedTlsSMTPHandler(("smtp.gmail.com", 587), '[email protected]_company.com', ['[email protected]_company.com'], 'Error found!', ('[email protected]', 'top_secret_gmail_password')) 
gm.setLevel(logging.ERROR) 

logger.addHandler(gm) 

try: 
    1/0 
except: 
    logger.exception('FFFFFFFFFFFFFFFFFFFFFFFUUUUUUUUUUUUUUUUUUUUUU-') 
0

Có thể bạn cần phải viết trình xử lý ghi nhật ký của riêng mình để thực hiện việc gửi email trong nền.

+0

ví dụ: Gọi chương trình 'sendmail' cục bộ có thể đi kèm với MTA của bạn và gửi đến máy chủ SMTP cục bộ của bạn mà không cần sử dụng SMTP. – MattH

5

Bạn có thể sử dụng QueueHandlerQueueListener. Lấy từ các tài liệu:

Cùng với lớp QueueListener, QueueHandler thể được sử dụng để cho xử lý làm việc của họ trên một sợi riêng biệt từ một trong đó không logging. Điều này quan trọng trong các ứng dụng Web và cũng như các ứng dụng dịch vụ khác trong đó các chủ đề phục vụ khách hàng cần trả lời càng nhanh càng tốt, trong khi bất kỳ hoạt động nào có khả năng chậm (chẳng hạn như gửi email qua SMTPHandler) được thực hiện trên một chuỗi riêng biệt.

Chúng chỉ có sẵn từ Python 3.2 trở đi.

+2

+1 và chúng * có * cho các phiên bản Python cũ hơn thông qua dự án logutils: http://plumberjack.blogspot.com/2010/10/logutils-using-recent-logging-features.html –

0

Một điều cần lưu ý khi mã hóa bằng Python là GIL (Khóa thông dịch toàn cầu). Khóa này ngăn cản nhiều quá trình xảy ra cùng một lúc. có rất nhiều thứ đang hoạt động 'Chặn' trong Python. Họ sẽ dừng mọi thứ cho đến khi họ hoàn thành.

Hiện tại, cách duy nhất xung quanh GIL là đẩy hành động bạn đang cố gắng đến nguồn bên ngoài như aix và MattH đang đề xuất hoặc triển khai mã của bạn bằng mô-đun đa xử lý (http: //docs.python. org/library/multiprocessing.html) để một quy trình xử lý việc gửi thư và phần còn lại đang được xử lý bởi quy trình khác.

2

Các hình thức đơn giản nhất của handler smtp không đồng bộ đối với tôi là chỉ để ghi đè emit phương pháp và sử dụng phương pháp ban đầu trong một chủ đề mới. GIL không phải là một vấn đề trong trường hợp này bởi vì có một cuộc gọi I/O đến máy chủ SMTP phát hành GIL. Mã như sau

class ThreadedSMTPHandler(SMTPHandler): 
    def emit(self, record): 
     thread = Thread(target=SMTPHandler.emit, args=(self, record)) 
     thread.start() 
Các vấn đề liên quan