Pregunta Registro de Python (nombre de la función, nombre de 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 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.

Esto es lo que sé:

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

  2. para obtener el nombre de archivo y el número de línea, lo he visto (y creo que) mi aplicación está usando Python locals() función pero en una sintaxis que no conozco completamente, p. ej .: options = "LOG.debug('%(flag)s : %(flag_get)s' % locals()) y lo intenté usando 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 agregarle controlador para que se registre 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.

Agradecería enormemente cualquier ayuda.

¡Gracias!


73
2018-06-11 00:07


origen


Respuestas:


Aquí tienes algunas preguntas marginalmente relacionadas.

Empezaré por el más fácil: (3). Utilizando logging puede agregar todas las llamadas a un solo archivo de registro u otro objetivo de salida: estarán en el orden en que ocurrieron en el proceso.

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

Finalmente, puede usar algunos trucos de 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 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. Mira esto inspeccionar - Inspeccionar objetos vivos para más detalles.

Como mencioné en mi comentario anterior, también puede caer en un pdb solicitud de depuración interactiva en cualquier momento insertando la línea import pdb; pdb.set_trace() en, y volver a ejecutar su programa. Esto le permite recorrer el código e inspeccionar los datos como lo desee.


18
2018-06-11 04:29



La respuesta correcta para esto es usar 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, simplemente agregue:

logger.debug('your message') 

Ejemplo de salida de un script en el que estoy trabajando en este momento:

[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>]]

326
2017-11-21 04:28