2009-10-23 18 views
12

Tengo el módulo de registro MemoryHandler configurado para poner en cola los errores y mensajes de error para el objetivo SMTPHandler. Lo que quiero es que se envíe un correo electrónico cuando los errores de proceso contengan todas las declaraciones de depuración hasta ese momento (uno por línea). Lo que recibo en su lugar es un correo electrónico por separado para cada mensaje de depuración.Clasificar salida en el registro de Python MemoryHandler con SMTPHandler

Esta parece que debería ser trivial, y parte del paquete de registro, pero no puedo encontrar nada al respecto, no hay ejemplos, nada en Google.

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, '[email protected]'+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) 

relación a esto:

¿Es necesario añadir el error_mail_handler al registrador de forma explícita si se trata de un objetivo de memory_handler de todos modos? ¿Debe error_mail_handler establecerse en el objetivo DEBUG o ERROR? ¿Necesita siquiera un objetivo cuando se lo alimenta desde el memory_handler?

Me encantaría ver algún código de trabajo de cualquiera que haya resuelto este problema.

Respuesta

17

Es posible que desee utilizar o adaptar el BufferingSMTPHandler que está en this test script.

En general, no es necesario agregar un controlador a un registrador si es el blanco de un manejador de MemoryHandler que se ha añadido a un registrador. Si establece el nivel de un controlador, eso afectará lo que el controlador realmente procesa, no procesará nada que sea menos grave que su configuración de nivel.

+0

Great stuff. ¡No es todos los días que el autor del módulo responde tu pregunta! – SpliFF

+0

@VinaySajip: ¿qué opina sobre el uso del módulo smtplib para enviar correos electrónicos? – codingknob

+0

@ algotr8der - Puede ver en el enlace (ahora actualizado) que el script realmente usa 'smtplib' para enviar los correos electrónicos. –

0

Para ello uso el BufferingSMTPHandler sugerido por Vinay Sajip con un pequeño ajuste: He definido la longitud del búfer a algo realmente grande (digamos 5000 entradas de registro) y manualy llamar al método flush del manejador de cada algunos segundos y después de verificar la conectividad de Internet.

# init 
log_handler1 = BufferingSMTPHandler(
    'smtp.host.lala', "[email protected]", ['[email protected]'], '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) 
+2

Esto solo funcionaría si el controlador todavía está en el alcance cuando se vacía. De lo contrario, tendrías que recuperar el controlador del objeto de registro para llamar a flush. – DeaconDesperado

5

escribir mi propia aplicación segura para los subprocesos bestial de BufferingSMTPHandler que envía mensajes de correo electrónico desde un hilo separado. El objetivo principal es no bloquear el hilo principal.

Como está escrito, que utiliza dos colas - esto parecía necesaria con el fin de poner en práctica algunos de los parámetros de nivel de clase de utilidad que se definen en la sección "Parámetros configurables" del código. Aunque puede usar el código tal como está, probablemente sea mejor si lo estudia y lo usa para escribir su propia clase.

Problemas:

  • Algunos parámetros de nivel de clase pueden quizá ser ejemplo a nivel de su lugar.
  • De cualquier threading.Timer o el módulo de signal quizá podría utilizarse para evitar bucles que se ejecutan siempre.
2

Si está utilizando Django - aquí es sencilla manejador de amortiguación, que utilizará métodos de correo electrónico estándar 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 = [] 

En Django settings.py tendrá que configurar el correo electrónico y el registro de la siguiente manera:

EMAIL_USE_TLS = True 
EMAIL_PORT = 25 
EMAIL_HOST = '' # example: 'smtp.yandex.ru' 
EMAIL_HOST_USER = '' # example: '[email protected]' 
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': '[email protected]' 
      # 'subject': 'log messages' 
     } 
    }, 
    ... 
} 
Cuestiones relacionadas