2011-12-23 10 views
6

he instalado un local de SMTP server y se utiliza para iniciar la sesión logging.handlers.SMTPHandler una excepción utilizando este código:¿Cómo hacer SMTPHandler no bloquea

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 

Se tardó más de 1 segundo para completar, el bloqueo de la secuencia de comandos de Python para todo este tiempo. ¿Cómo? ¿Cómo puedo hacer que no bloquee el script?

Respuesta

13

Aquí está la implementación que estoy usando, que basé en this Gmail adapted SMTPHandler.
Tomé la parte que envía a SMTP y la coloqué en un hilo diferente.

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) 

Ejemplo de uso:

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

Lo más probable es que necesite escribir su propio controlador de registro que enviaría el correo electrónico en segundo plano.

+0

p. Llamando al programa local 'sendmail' que probablemente vino con su MTA y se envía a su servidor SMTP local sin usar SMTP. – MattH

5

Puede usar QueueHandler y QueueListener. Tomado de la documentación:

Junto con la clase QueueListener, QueueHandler se puede utilizar para dejar manipuladores hacen su trabajo en un hilo separado de la que hace la tala. Esto es importante en aplicaciones web y también en otras aplicaciones de servicio donde los clientes de servicio de subprocesos deben responder lo más rápido posible, mientras que cualquier operación potencialmente lenta (como enviando un correo electrónico a través de SMTPHandler) se realiza en una secuencia separada.

Alas, solo están disponibles desde Python 3.2 en adelante.

+2

+1, y * están * disponibles para las versiones anteriores de Python a través del proyecto logutils: http://plumberjack.blogspot.com/2010/10/logutils-using-recent-logging-features.html –

0

Una cosa a tener en cuenta cuando se codifica en Python es el GIL (Global Interpreter Lock). Este bloqueo evita que ocurra más de un proceso al mismo tiempo. hay muchas cosas que son actividades de 'Bloqueo' en Python. Ellos detendrán todo hasta que se completen.

Actualmente, la única forma de evitar el GIL es impulsar la acción que está intentando aplicar a una fuente externa como aix y MattH, o implementar su código utilizando el módulo de multiprocesamiento (http: //docs.python. org/library/multiprocessing.html) de modo que un proceso esté gestionando el envío de mensajes y el resto esté siendo manejado por el otro proceso.

2

La forma más simple de controlador smtp asíncrono para mí es sólo para anular emit método y utilizar el método original en un nuevo hilo. GIL no es un problema en este caso porque hay una llamada de E/S al servidor SMTP que libera GIL. El código es el siguiente

class ThreadedSMTPHandler(SMTPHandler): 
    def emit(self, record): 
     thread = Thread(target=SMTPHandler.emit, args=(self, record)) 
     thread.start() 
Cuestiones relacionadas