Registro de Python (nombre de la función, nombre del archivo, número de línea) usando un solo archivo


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 el número de línea (dentro del código) donde envío un mensaje a la salida de registro. Finalmente, dado que esta aplicación se compone de muchos archivos, quiero crear un solo archivo de registro para que pueda comprender mejor el flujo de control de la aplicación.

Esto es lo que sé:

  1. Para obteniendo el nombre de la función, puedo usar function_name.__name__ pero no quiero usar el nombre_función (para poder copiar y pegar rápidamente un Log.info("Message") genérico en el cuerpo de todas las funciones). Sé que esto podría hacerse en C usando la macro __func__ pero no estoy seguro sobre python.

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

  3. Sé cómo usar el registro y agregarle un controlador para registrar 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.

Agradecería mucho cualquier ayuda.

Gracias!

Author: AdrieanKhisbe, 2012-06-11

2 answers

Usted tiene algunas preguntas marginalmente relacionadas aquí.

Comenzaré con la más fácil: (3). Usando logging puede agregar todas las llamadas a un solo 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 ámbito actual. Por lo tanto, en un método que no tiene otros argumentos, tiene self en el ámbito, que contiene una referencia a la instancia actual. El truco que se está usando que te está golpeando es la cuerda formateo usando un dict como el RHS del operador %. "%(foo)s" % bar será reemplazado por cualquiera que sea el valor de bar["foo"].

Finalmente, puedes usar algunos trucos de introspección, similares a los utilizados por pdb que pueden 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 pasado, 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. Echa un vistazo a inspect - Inspect live objects para más detalles.

As I mencionado en mi comentario anterior, también puede colocar en un mensaje de depuración interactivo pdb en cualquier momento insertando la línea import pdb; pdb.set_trace() y volviendo a ejecutar su programa. Esto le permite pasar por el código, inspeccionando los datos como desee.

 19
Author: Matthew Schinckel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-18 02:56:48

La respuesta correcta para esto es utilizar el ya proporcionado funcName variable

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

Luego, en cualquier lugar que desee, solo agregue:

logger.debug('your message') 

Ejemplo de salida de un script en el que estoy trabajando ahora mismo:

[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>]]
 341
Author: synthesizerpatel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-17 13:02:41