2011-03-28 14 views
34

Así que he configurado mi aplicación de Python para iniciar sesión en syslog con Python's SysLogHandler, y todo funciona bien. Excepto por el manejo de múltiples líneas. No es que necesite emitir registros de registro de líneas múltiples tan mal (hago un poco), pero necesito poder leer las excepciones de Python. Estoy usando Ubuntu con rsyslog 4.2.0. Esto es lo que estoy haciendo: CódigoRegistros de registro de varias líneas en syslog

Mar 28 20:11:59 telemachos root: ERROR 'EXCEPTION'#012Traceback (most recent call last):#012 File "./test.py", line 22, in <module>#012 foo()#012 File "./test.py", line 13, in foo#012 bar()#012 File "./test.py", line 16, in bar#012 bla()#012 File "./test.py", line 19, in bla#012 raise Exception("EXCEPTION!")#012Exception: EXCEPTION! 

de prueba en caso de que lo necesite:

import logging 
from logging.handlers import SysLogHandler 

logger = logging.getLogger() 
logger.setLevel(logging.INFO) 
syslog = SysLogHandler(address='/dev/log', facility='local0') 
formatter = logging.Formatter('%(name)s: %(levelname)s %(message)r') 
syslog.setFormatter(formatter) 
logger.addHandler(syslog) 

def foo(): 
    bar() 

def bar(): 
    bla() 

def bla(): 
    raise Exception("EXCEPTION!") 

try: 
    foo() 
except: 
    logger.exception("EXCEPTION") 

Respuesta

30

OK, lo imaginó finalmente ...

rsyslog escapa por defecto todos los caracteres extraños (ASCII < 32), y esto incluye nuevas líneas (así como pestañas y otras). Basta con añadir esto a su configuración rsyslog para desactivar esta opción:

$EscapeControlCharactersOnReceive off 
+8

Esto probablemente va a trabajar para su caso, pero si usted está escribiendo una aplicación simultánea de grandes volúmenes, @ respuesta de Nick hará que sea mucho más fácil encontrar todas las líneas que van con su StackTrace. Su solución perderá el nombre de la aplicación y el nombre de nivel para todas las líneas después de la primera, dificultando la búsqueda. – mattbornski

+0

@mattbornski No perderá ninguna información, simplemente no estará en la misma línea. –

+13

Por "perdido" quise decir, en este caso, "no se puede reconstruir". En una aplicación de gran volumen, dividir el significado de su registro en varias líneas a menudo hace que sea imposible volver a montar ya que las líneas de múltiples solicitudes se entrelazan. – mattbornski

34

Alternativamente, si desea mantener intacta en una línea para el análisis de su syslog, puede simplemente reemplazar los caracteres cuando se visualiza el registro.

tail -f /var/log/syslog | sed 's/#012/\n\t/g' 
+1

sed no funciona, consigue "blah blah line1 ** nt ** blah blah line2". Sin embargo, perl funciona: 'tail -f/var/log/syslog | perl -pe 's/# 012/\ n \ t/g;' ' – user9645

+3

sed trabajado bien para mí – spikyjt

3

Otra opción sería la subclase el SysLogHandler y anular emit() - usted podría entonces llamar a la superclase emit() para cada línea en el texto le envían. Algo así como:

from logging import LogRecord 
from logging.handlers import SysLogHandler 

class MultilineSysLogHandler(SysLogHandler): 
    def emit(self, record): 
     if '\n' in record.msg: 
      record_args = [record.args] if isinstance(record.args, dict) else record.args 
      for single_line in record.msg.split('\n'): 
       single_line_record = LogRecord(
        name=record.name, 
        level=record.levelno, 
        pathname=record.pathname, 
        msg=single_line, 
        args=record_args, 
        exc_info=record.exc_info, 
        func=record.funcName 
       ) 
       super(MultilineSysLogHandler, self).emit(single_line_record) 
     else: 
      super(MultilineSysLogHandler, self).emit(record) 
+0

nivel = debe ser levelno = y lineno = falta registro.lineno. Sin embargo, si el mensaje contiene% s, etc. después de \ n, la sustitución de parámetros no funcionará correctamente. Este código necesitaría parametrizar completamente el mensaje antes de la división, pero solo si el record.levelno pasa el filtro. – Terris

Cuestiones relacionadas