2012-06-11 12 views
65

Estoy tratando de aprender cómo funciona una aplicación. Y para esto estoy insertando comandos de depuración como la primera línea del cuerpo de cada función con el objetivo de registrar el nombre de la función así como también el número de línea (dentro del código) donde envío un mensaje al resultado del registro. Finalmente, dado que esta aplicación se compone de muchos archivos, quiero crear un único archivo de registro para que pueda comprender mejor el flujo de control de la aplicación.Registro de Python (nombre de la función, nombre de archivo, número de línea) utilizando un único archivo

Esto es lo que sé:

  1. para obtener nombre de la función, puedo usar function_name.__name__ pero no desee utilizar el function_name (para que pudiera rápidamente copiar y pegar un genérico en el Log.info("Message") cuerpo de todas las funciones). Sé que esto podría hacerse en C usando macro __func__ pero no estoy seguro acerca de Python.

  2. para obtener el nombre de archivo y número de línea, he visto que (y creo que) mi aplicación está utilizando la función de Python locals() pero en una sintaxis que no soy completamente consciente de, por ejemplo: options = "LOG.debug('%(flag)s : %(flag_get)s' % locals()) y lo probé utilizando como LOG.info("My message %s" % locals()) que produce algo así como {'self': <__main__.Class_name object at 0x22f8cd0>}. Cualquier entrada en esto, por favor?

  3. Sé cómo usar el registro y agregar controlador para iniciar sesión en un archivo, pero no estoy seguro de si se puede usar un solo archivo para registrar todos los mensajes de registro en el orden correcto de las llamadas a funciones en el proyecto.

Agradeceria cualquier ayuda.

Gracias!

+0

Puede pasar al depurador de python utilizando 'import pdb; pdb.set_trace() ', y luego recorrer el código de forma interactiva. Eso puede ayudarlo a rastrear el flujo del programa. –

+0

¡Gran idea! Gracias Matt. Todavía sería útil obtener un registro como se menciona en la pregunta para no tener que depurar todo el tiempo. Además, ¿conoces un IDE para python que sea tan bueno como Eclipse para Java (ctrl + clic lo lleva a la definición de la función) que puedo utilizar para facilitar la depuración? – user1126425

Respuesta

17

Aquí tiene algunas preguntas marginalmente relacionadas.

Comenzaré por el más fácil: (3). Con logging puede agregar todas las llamadas a un único archivo de registro u otro destino de salida: estarán en el orden en que ocurrieron en el proceso.

Siguiente: (2). locals() proporciona un dict del alcance actual. Por lo tanto, en un método que no tiene otros argumentos, tiene self en alcance, que contiene una referencia a la instancia actual. El truco que se está utilizando que le está afectando es el formato de cadena que utiliza un dict como el RHS del operador %. "%(foo)s" % bar será reemplazado por cualquiera que sea el valor de bar["foo"].

Por último, puede utilizar algunos trucos introspección, similares a los utilizados por pdb que puede registrar más información:

def autolog(message): 
    "Automatically log the current function details." 
    import inspect, logging 
    # Get the previous frame in the stack, otherwise it would 
    # be this function!!! 
    func = inspect.currentframe().f_back.f_code 
    # Dump the message + the name of this function to the log. 
    logging.debug("%s: %s in %s:%i" % (
     message, 
     func.co_name, 
     func.co_filename, 
     func.co_firstlineno 
    )) 

Esto registrará el mensaje que se transmite en, más el nombre de la función (original), el nombre del archivo en el que aparece la definición, y la línea en ese archivo. Eche un vistazo a inspect - Inspect live objects para más detalles.

Como ya he mencionado en mi comentario anterior, también se puede colocar en un indicador de depuración interactiva pdb en cualquier momento mediante la inserción en la línea import pdb; pdb.set_trace(), y volviendo a ejecutar su programa. Esto le permite recorrer el código e inspeccionar los datos como lo desee.

+0

Gracias Matt! Voy a probar esta función de autolog. Tengo una pequeña confusión sobre el uso de dict como RHS del operador%: Would ''% (foo) s:% (bar) s'' también imprimiría el valor de' bar ["foo"] '? ¿O es algo diferente a tu ejemplo? – user1126425

+0

Básicamente, todo el formulario '% () s' se reemplaza por el valor del objeto al que se hace referencia en el diccionario por' '. Hay más ejemplos/detalles en http://docs.python.org/library/stdtypes.html#string-formatting –

+0

La respuesta de @synthesizerpatel es mucho más útil. – Jan

276

La respuesta correcta para esto es el uso de la ya proporcionada funcName variables

import logging 
logger = logging.getLogger('root') 
FORMAT = "[%(filename)s:%(lineno)s - %(funcName)20s() ] %(message)s" 
logging.basicConfig(format=FORMAT) 
logger.setLevel(logging.DEBUG) 

Entonces cualquier lugar que desee, sólo tiene que añadir:

logger.debug('your message') 

Ejemplo de salida de un guión que estoy trabajando en este ahora:

[invRegex.py:150 -   handleRange() ] ['[A-Z]'] 
[invRegex.py:155 -  handleRepetition() ] [[<__main__.CharacterRangeEmitter object at 0x10ba03050>, '{', '1', '}']] 
[invRegex.py:197 -   handleMacro() ] ['\\d'] 
[invRegex.py:155 -  handleRepetition() ] [[<__main__.CharacterRangeEmitter object at 0x10ba03950>, '{', '1', '}']] 
[invRegex.py:210 -  handleSequence() ] [[<__main__.GroupEmitter object at 0x10b9fedd0>, <__main__.GroupEmitter object at 0x10ba03ad0>]] 
+20

¡Esta debería haber sido la respuesta! – user3885927

+1

Excelente ... Una cosa para agregar, ¿podemos decir que el archivo de registro es el mismo que el archivo de código de forma dinámica? por ejemplo: Intenté logging.basicConfig (filename = "% (filename)", format = FORMAT) para tomar el nombre de archivo dinámicamente, pero tomó valor estático. ¿cualquier sugerencia? – Outlier

+2

@Outlier No, la forma recomendada de lograrlo es a través de 'getLogger (__ name __)' – farthVader

Cuestiones relacionadas