Conceptos básicos de registro de Python

El registro lo ayuda a realizar un seguimiento de los eventos que ocurren durante la ejecución de su código, que luego se pueden usar en el futuro para fines de depuración. Proporciona un...

Introducción

El registro lo ayuda a realizar un seguimiento de los eventos que ocurren durante la ejecución de su código, que luego se pueden usar en el futuro para fines de depuración. Proporciona una mejor imagen del flujo de la aplicación y ayuda a los desarrolladores a rastrear el origen de los errores que ocurren durante la ejecución de su código, mejorando así la capacidad de mantenimiento de la aplicación.

En Python, la biblioteca estándar de Python proporciona la mayoría de las funciones básicas de registro. Por lo tanto, puede agregar registros a su aplicación fácilmente sin ninguna configuración adicional. El módulo de registro estándar permite al desarrollador escribir mensajes de estado en un archivo o cualquier otro flujo de salida.

El módulo de registro

El módulo logging está disponible en entornos de Python de forma predeterminada y proporciona un registrador predeterminado llamado "root". Define las funciones y clases que implementan la funcionalidad de registro.

La API de registro proporcionada por la biblioteca estándar le permite incluir sus propios mensajes en el registro de la aplicación, así como la integración con mensajes de módulos de terceros. También proporciona un mecanismo para anotar los mensajes de registro con la fuente, la marca de tiempo, la gravedad y otros metadatos, lo que ayuda en el análisis de registros.

Tipos de registro (niveles de registro)

Cada mensaje de registro está asociado con un nivel de gravedad, que es un número entero que se utiliza para señalar la criticidad de los eventos registrados. El módulo de registro tiene una función auxiliar para cada nivel de registro; estos se nombran según el nivel de registro. A continuación, hay una lista de niveles de registro junto con su uso recomendado.

  • Depuración (logger.debug): proporciona una salida muy detallada. Se utiliza para diagnosticar problemas.

  • Info (logger.info): Proporciona información sobre la ejecución exitosa. Confirma si las cosas funcionan como se esperaba.

  • Advertencia (logger.warn o logger.warning): emite una advertencia sobre un problema que podría ocurrir en el futuro o una falla recuperable.

  • Error (logger.error): Indica un problema en el software ya que no se está ejecutando como se esperaba.

  • Critical (logger.critical): Indica un error grave que podría detener la ejecución del programa.

De forma predeterminada, el registrador raíz está configurado para informar todos los mensajes en el nivel de advertencia o por encima de él; se filtran todos los mensajes por debajo de este nivel. Sin embargo, es posible configurar el módulo explícitamente para que sea más o menos selectivo en el filtrado.

Para agregar el registro a una secuencia de comandos de Python, simplemente importe el módulo usando importar registro, y después de una importación exitosa, la secuencia de comandos puede registrar mensajes usando los métodos logging.*, como logging.debug().

Aquí puede ver un ejemplo simple del módulo de registro en acción:

1
2
import logging
logging.warning("Caution: This is the root logger!")

Producción:

1
WARNING:root:Caution: This is the root logger!

Objetos registradores

El módulo de registro permite al usuario crear múltiples objetos registradores. Se pueden usar diferentes tipos de objetos de registro para obtener un control detallado sobre cómo las diferentes partes de una aplicación de Python registran sus mensajes; por ejemplo, la aplicación principal de Python puede usar el registrador raíz mientras que las bibliotecas de terceros usan desde dentro de este. La aplicación puede usar sus propios objetos de registro con sus propias configuraciones.

Mientras usamos las funciones predeterminadas del registrador root, podemos llamar a las funciones directamente, por ejemplo, logging.debug(). Es posible configurar su propio registrador creando un objeto de la clase Logger, y esto puede ser útil si su aplicación tiene múltiples módulos.

Echemos un vistazo a algunas de las clases y funciones en el módulo de registro. Las clases básicas y sus funciones son las siguientes:

  • Registradores: expone la interfaz que utiliza la aplicación. Los objetos de esta clase se utilizan directamente para llamar a las funciones en la aplicación.

  • Controladores: envía mensajes de registro a la ubicación adecuada en el software, como una consola de salida estándar, un archivo, a través de HTTP o incluso correo electrónico (a través de SMTP).

  • Filtros: brinda un control detallado sobre la elección de registros para mostrar.

  • Formateadores: especifica el diseño final de los registros, especificando los atributos que debe contener la salida.

De estos, los objetos de la clase Logger se usan con mayor frecuencia.

Para crear un nuevo registrador, podemos usar el método logging.getLogger(). En el siguiente script, registramos errores utilizando el registrador root así como nuestro registrador personalizado my_logger.

1
2
3
4
5
import logging

my_logger = logging.getLogger("My Logger")
logging.error("Error: Root Log")
my_logger.error("Error: My Logger log")

Producción:

1
2
ERROR:root:Error: Root Log
ERROR:My Logger:Error: My Logger log

Cada mensaje de registro no solo indicará la fuente, el objeto registrador a través del cual se registró, sino que mostrará un mensaje basado en la configuración de ese objeto registrador.

En las siguientes secciones, veremos las diversas opciones de configuración de los objetos registradores.

Registro en un archivo frente a la salida estándar {#registro en un archivo frente a la salida estándar}

Por defecto, los objetos del registrador generan los registros en la salida estándar. Puede usar el método basicConfig() para cambiar este y otros parámetros. A continuación se muestra una lista de parámetros para el método basicConfig:

  • nivel: establece el registrador en un nivel de gravedad. Cualquier mensaje por debajo de este nivel de gravedad no se registrará.
  • filename: El nombre del archivo donde se escriben los registros.
  • filemode: El modo en el que se va a abrir el archivo especificado, si lo hay.
  • formato: especifica el formato del mensaje de registro. Esta es una cadena con atributos LogRecord.

El objeto LogRecord contiene la información de los eventos que se registran, como el número de línea, la hora, el nombre del registrador, etc. Discutir el objeto LogRecord está fuera del alcance de este artículo, pero hay más información disponible [aquí](https: //docs.python.org/3/library/logging.html#logrecord-attributes).

A continuación se muestra un resumen de los pasos a seguir para registrar eventos de registro en un archivo:

  1. Importe el módulo de registro.
  2. Configure el registrador usando el método basicConfig
  3. Crear un objeto registrador.
  4. Configuración del valor umbral del registrador.
  5. Utilice los métodos de registro.

Esto se puede entender mejor con un ejemplo:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# Filename: test_logger.py

import logging

# Create a logger object
logger = logging.getLogger()

# Configure logger
logging.basicConfig(filename="test.log", format='%(filename)s: %(message)s', filemode='w')

# Setting threshold level
logger.setLevel(logging.DEBUG)

# Use the logging methods
logger.debug("This is a debug message")
logger.info("For your info")
logger.warning("This is a warning message")
logger.error("This is an error message")
logger.critical("This is a critical message")

El script anterior creará un archivo "test.log". El archivo contendrá la siguiente información de registro:

1
2
3
4
5
test_logger.py: This is a debug message
test_logger.py: For your info
test_logger.py: This is a warning message
test_logger.py: This is an error message
test_logger.py: This is a critical message

Fecha/hora en los mensajes de registro

Para mostrar la fecha y hora de la ocurrencia de un evento, puede usar %(asctime)s en su cadena de formato en la función basicConfig(). Por ejemplo:

1
2
3
4
import logging

logging.basicConfig(format='%(asctime)s %(message)s')
logging.warning('is the time the Admin logged out.')

Producción:

1
2018-12-17 10:52:15,463 is the time the Admin logged out.

Si desea cambiar la forma en que se muestra la fecha/hora, puede configurarlo usando el parámetro datefmt del método basicConfig.

Variables de registro {#variables de registro}

En las aplicaciones del mundo real, necesitamos generar registros de acuerdo con los cambios dinámicos que ocurren en nuestra aplicación. Como se ve en el ejemplo anterior, los métodos de registro toman una cadena como argumento. Además, podemos incluir variables y formatear la cadena con marcadores de posición y luego pasarla al método de registro. En tiempo de ejecución, el valor de las variables se mostrará en los mensajes de registro.

Aquí hay un ejemplo de eso usando formato de cadena:

1
2
3
4
import logging

status = "connection unavailable"
logging.error("System reported: %s", status)

Producción:

1
ERROR:root:System reported: connection unavailable

A partir de Python 3.6, f-Strings se puede usar como una alternativa a los especificadores de formato de cadena, manteniendo así el código fácilmente legible cuando hay varios parámetros. Usando f-strings, puede especificar cualquier expresión de Python como parte del mensaje y estos se evalúan durante el tiempo de ejecución y el resultado se incrustará en los mensajes de registro.

El ejemplo anterior se puede reescribir usando una cadena f como:

1
2
3
4
import logging

status = "connection unavailable"
logging.error(f'System reported: {status}')

Registro de seguimientos de pila

El módulo de registro también admite la captura de seguimientos de pila en su aplicación. Establecer el parámetro exc_info en True al llamar a las funciones de registro nos permite capturar la información de la excepción. Al usar esta función, podemos obtener información sobre la excepción que se está manejando actualmente. La información es específica para el subproceso actual y el marco de pila actual.

1
2
3
4
5
6
7
import logging

my_list = [1, 2]
try:
    print(my_list[3]) # Index out of range
except Exception as e:
    logging.error("Caught Exception!", exc_info=True)

Producción:

1
2
3
4
5
ERROR:root:Caught Exception!
Traceback (most recent call last):
  File "index.py", line 5, in <module>
    print(my_list[3]) # Index out of range
IndexError: list index out of range

En caso de que el marco de pila actual no maneje las excepciones, la información se obtiene de su llamador (es decir, el marco de pila que llama) y así sucesivamente hasta que encuentre un marco de pila para manejar la excepción. El marco de pila tiene la información de la excepción manejada más recientemente.

Si la pila no tiene excepciones que se manejen, se devuelve una tupla que tiene el valor Ninguno. De lo contrario, la función devuelve el valor de tipo (el tipo de excepción que se maneja), valor (parámetro de excepción) y rastreo (el objeto de rastreo que encapsula la pila de llamadas donde ocurrió originalmente la excepción).

Conclusión

El diseño del módulo de registro es muy práctico y proporciona funciones de registro listas para usar que pueden agregar un registro básico a un proyecto pequeño. Se puede ampliar fácilmente mediante el uso de objetos registradores y sus ricas opciones de configuración para satisfacer las necesidades incluso de las aplicaciones más exigentes. Además de los mensajes, el módulo de registro también se puede utilizar para registrar excepciones y apilar seguimientos. Esto concluye el tutorial básico sobre cómo implementar el registro en Python.

Licensed under CC BY-NC-SA 4.0