Cómo recopilar, personalizar y centralizar los registros de Python

tip / logs /python
  • El módulo de registro integrado de Python está diseñado para ofrecerte una visibilidad crítica de tus aplicaciones con una configuración mínima. Tanto si estás empezando como si ya utilizas el módulo de registro de Python, esta guía te mostrará cómo configurar este módulo para registrar todos los datos que necesites, dirigirlos a los destinos que desees y centralizar tus registros para obtener una visión más profunda de tus aplicaciones Python. En este post, te mostraremos cómo:

    • Personalizar el nivel de prioridad y el destino de tus logs
    • Configurar una configuración personalizada que implique múltiples loggers y destinos
    • Incorporar el manejo de excepciones y los tracebacks en tus logs
    • .
    • Formatear tus logs en JSON y centralizarlos para una resolución de problemas más efectiva
      • Básicos del módulo de logging de Python

        El módulo logging está incluido en la librería estándar de Python, lo que significa que puedes empezar a utilizarlo sin necesidad de instalar nada. El método basicConfig() del módulo de registro es la forma más rápida de configurar el comportamiento deseado de tu registrador. Sin embargo, la documentación de Python recomienda crear un registrador para cada módulo de tu aplicación, y puede ser difícil configurar un registrador por módulo usando sólo basicConfig(). Por lo tanto, la mayoría de las aplicaciones (incluyendo los frameworks web como Django) utilizan automáticamente la configuración de registro basada en archivos o diccionarios en su lugar. Si quieres empezar con uno de esos métodos, te recomendamos que saltes directamente a esa sección.

        Tres de los parámetros principales de basicConfig() son:

        • nivel: el nivel de prioridad mínimo de los mensajes a registrar. En orden de gravedad creciente, los niveles de registro disponibles son: DEBUG, INFO, WARNING, ERROR y CRITICAL. Por defecto, el nivel se establece en ADVERTENCIA, lo que significa que el módulo de registro de Python filtrará cualquier mensaje de DEBUG o INFO.
        • Manager: determina a dónde dirigir tus registros. A menos que se especifique lo contrario, la biblioteca de registro utilizará un StreamHandler para dirigir los mensajes de registro a sys.stderr (normalmente la consola).
        • Formato: por defecto, la biblioteca de registro registrará los mensajes en el siguiente formato: <LEVEL>:<LOGGER_NAME>:<MESSAGE>. En la siguiente sección, le mostraremos cómo personalizar esto para incluir marcas de tiempo y otra información que es útil para la solución de problemas.
          • Dado que el módulo de registro sólo captura ADVERTENCIA y registros de nivel superior de forma predeterminada, es posible que le falte visibilidad en los registros de menor prioridad que pueden ser útiles para llevar a cabo un análisis de la causa raíz. El módulo de registro también transmite los registros a la consola en lugar de añadirlos a un archivo. En lugar de utilizar un StreamHandler o un SocketHandler para transmitir los registros directamente a la consola o a un servicio externo a través de la red, debe utilizar un FileHandler para registrar uno o más archivos en el disco.

            Una de las principales ventajas de registrar en un archivo es que su aplicación no necesita tener en cuenta la posibilidad de encontrar errores relacionados con la red mientras transmite los registros a un destino externo. Si se encuentra con algún problema al transmitir los registros a través de la red, no perderá el acceso a esos registros, ya que se almacenarán localmente en cada servidor. El registro en un archivo también le permite crear una configuración de registro más personalizada, en la que puede enrutar diferentes tipos de registros a archivos separados, y cola y centralizar esos archivos con un servicio de monitoreo de registros.

            En la siguiente sección, le mostraremos lo fácil que es personalizar basicConfig() para registrar mensajes de menor prioridad y dirigirlos a un archivo en el disco.

            Un ejemplo de basicConfig()

            El siguiente ejemplo utiliza basicConfig() para configurar una aplicación para que registre los mensajes de DEBUG y de mayor prioridad en un archivo en el disco (myapp.log). También indica que los registros deben seguir un formato que incluya la marca de tiempo y el nivel de gravedad del registro:

            import loggingdef word_count(myfile): logging.basicConfig(level=logging.DEBUG, filename='myapp.log', format='%(asctime)s %(levelname)s:%(message)s') try: # count the number of words in a file and log the result with open(myfile, 'r') as f: file_data = f.read() words = file_data.split(" ") num_words = len(words) logging.debug("this file has %d words", num_words) return num_words except OSError as e: logging.error("error reading the file")

            Si ejecuta el código en un archivo accesible (por ejemplo, miarchivo.txt) seguido de un archivo inaccesible (por ejemplo, nonexistentfile.txt), añadirá los siguientes registros al archivo myapp.

            2019-03-27 10:49:00,979 DEBUG:this file has 44 words2019-03-27 10:49:00,979 ERROR:error reading the file

            Gracias a la nueva configuración basicConfig(), los registros de nivel DEBUG ya no se filtran, y los registros siguen un formato personalizado que incluye los siguientes atributos:

            • %(asctime)s: muestra la fecha y la hora del registro, en hora local
            • %(levelname)s: el nivel de registro del mensaje
            • %(message)s: el mensaje
            • Consulte la documentación para obtener información sobre los atributos que puede incluir en el formato de cada registro. En el ejemplo anterior, se registró un mensaje de error, pero no incluyó ninguna información de rastreo de la excepción, lo que dificulta la determinación del origen del problema. En una sección posterior de este post, le mostraremos cómo registrar el rastreo completo cuando se produce una excepción.

              Cavando más en la biblioteca de registro de Python

              Hemos cubierto los fundamentos de basicConfig(), pero como se mencionó anteriormente, la mayoría de las aplicaciones se beneficiarán de la implementación de una configuración de registro por módulo. A medida que tu aplicación escale, necesitarás una forma más robusta y escalable de configurar cada registrador específico de módulo, y asegurarte de que estás capturando el nombre del registrador como parte de cada registro. En esta sección, exploraremos cómo:

              • configurar múltiples registradores y capturar automáticamente el nombre del registrador
              • utilizar fileConfig() para implementar opciones de formato y enrutamiento personalizadas
              • capturar tracebacks y excepciones no capturadas

              Configurar múltiples loggers y capturar el nombre del logger

              Para seguir la mejor práctica de crear un nuevo logger para cada módulo de su aplicación, utiliza el método incorporado de la biblioteca de registro getLogger() para establecer dinámicamente el nombre del registrador para que coincida con el nombre de tu módulo:

              logger = logging.getLogger(__name__)

              Este método getLogger() establece el nombre del registrador a __name__, que corresponde al nombre completo del módulo desde el que se llama a este método. Esto le permite ver exactamente qué módulo de su aplicación generó cada mensaje de registro, para que pueda interpretar sus registros con mayor claridad.

              Por ejemplo, si su aplicación incluye un módulo lowermodule.py que es llamado desde otro módulo, uppermodule.py, el método getLogger() establecerá el nombre del registrador para que coincida con el módulo asociado. Una vez que modifiques tu formato de registro para incluir el nombre del logger (%(name)s), verás esta información en cada mensaje de registro. Puedes definir el logger dentro de cada módulo así:

              # lowermodule.pyimport logginglogging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(name)s %(levelname)s:%(message)s')logger = logging.getLogger(__name__)def word_count(myfile): try: with open(myfile, 'r') as f: file_data = f.read() words = file_data.split(" ") final_word_count = len(words) logger.info("this file has %d words", final_word_count) return final_word_count except OSError as e: logger.error("error reading the file")# uppermodule.pyimport loggingimport lowermodule logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(name)s %(levelname)s:%(message)s')logger = logging.getLogger(__name__)def record_word_count(myfile): logger.info("starting the function") try: word_count = lowermodule.word_count(myfile) with open('wordcountarchive.csv', 'a') as file: row = str(myfile) + ',' + str(word_count) file.write(row + '\n') except: logger.warning("could not write file %s to destination", myfile) finally: logger.debug("the function is done for the file %s", myfile)

              Si ejecutamos uppermodule.py en un archivo accesible (miarchivo.txt) seguido de un archivo inaccesible (archivoinexistente.txt), el módulo de registro generará la siguiente salida:

              2019-03-27 21:16:41,200 __main__ INFO:starting the function2019-03-27 21:16:41,200 lowermodule INFO:this file has 44 words2019-03-27 21:16:41,201 __main__ DEBUG:the function is done for the file myfile.txt2019-03-27 21:16:41,201 __main__ INFO:starting the function2019-03-27 21:16:41,202 lowermodule ERROR: No such file or directory: 'nonexistentfile.txt'2019-03-27 21:16:41,202 __main__ DEBUG:the function is done for the file nonexistentfile.txt

              El nombre del logger se incluye justo después de la marca de tiempo, para que puedas ver exactamente qué módulo generó cada mensaje. Si no defines el logger con getLogger(), cada nombre de logger se mostrará como root, lo que hace difícil discernir qué mensajes fueron registrados por el uppermodule en contraposición al lowermodule. Los mensajes que se registraron desde uppermodule.py listan el módulo __main__ como el nombre del logger, porque uppermodule.py se ejecutó como el script de nivel superior.

              Aunque ahora estamos capturando automáticamente el nombre del logger como parte del formato de registro, ambos loggers están configurados con la misma línea basicConfig(). En la siguiente sección, le mostraremos cómo agilizar su configuración de registro utilizando fileConfig() para aplicar la configuración de registro a través de múltiples registradores.

              Utilizar fileConfig() para dar salida a los registros en múltiples destinos

              Aunque basicConfig() hace que sea rápido y fácil empezar con el registro, el uso de la configuración basada en archivos (fileConfig()) o en diccionarios (dictConfig()) te permite implementar más opciones de formato y enrutamiento personalizados para cada registrador de tu aplicación, y dirigir los registros a múltiples destinos. Este es también el modelo que utilizan frameworks populares como Django y Flask para configurar el registro de la aplicación. En esta sección, vamos a echar un vistazo más de cerca a la configuración del registro basado en archivos. Un archivo de configuración de logging debe contener tres secciones:

              • : los nombres de los loggers que vas a configurar.
              • : el/los manejador/es que estos loggers deben utilizar (por ejemplo, consoleHandlerfileHandler).
              • : el/los formato/s que quieres que siga cada logger al generar un registro.
                • Cada sección debe incluir una lista separada por comas de una o más claves: keys=handler1,handler2,. Las claves determinan los nombres de las otras secciones que tendrás que configurar, con el formato , donde el nombre de la sección es logger, handler o formatter. A continuación se muestra un archivo de configuración de registro de ejemplo (logging.ini).

                  keys=rootkeys=fileHandlerkeys=simpleFormatterlevel=DEBUGhandlers=fileHandlerclass=FileHandlerlevel=DEBUGformatter=simpleFormatterargs=("/path/to/log/file.log",)format=%(asctime)s %(name)s - %(levelname)s:%(message)s

                  La documentación de registro de Python recomienda que sólo se adjunte cada manejador a un registrador y se confíe en la propagación para aplicar los manejadores a los registradores hijos apropiados. Esto significa que si tiene una configuración de registro por defecto que quiere que todos sus registradores recojan, debería añadirla a un registrador padre (como el registrador raíz), en lugar de aplicarla a cada registrador de nivel inferior. Consulte la documentación para obtener más detalles sobre la propagación. En este ejemplo, configuramos un registrador raíz y dejamos que se propague a los dos módulos de nuestra aplicación (lowermodule y uppermodule). Ambos registradores darán salida a los registros DEBUG y de mayor prioridad, en el formato especificado (formatter_simpleFormatter), y los anexarán a un archivo de registro (file.log). Esto elimina la necesidad de incluir logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(name)s %(levelname)s:%(message)s') en ambos módulos.

                  En su lugar, una vez que hayas creado este archivo de configuración de registro, puedes añadir logging.config.fileConfig() a tu código de la siguiente manera:

                  import logging.configlogging.config.fileConfig('/path/to/logging.ini', disable_existing_loggers=False)logger = logging.getLogger(__name__)

                  Asegúrate de import logging.config para que tengas acceso a la función fileConfig(). En este ejemplo, disable_existing_loggers se establece en False, lo que indica que el módulo de registro no debe desactivar los registradores preexistentes que no sean root. Esta configuración está predeterminada a True, que deshabilitará cualquier registrador no root que existiera antes de fileConfig() a menos que los configure después.

                  Su aplicación debería ahora comenzar a registrar basándose en la configuración que estableció en su archivo logging.ini. También tienes la opción de configurar el registro en forma de diccionario de Python (a través de dictConfig()), en lugar de en un archivo. Consulta la documentación para obtener más detalles sobre el uso de fileConfig() y dictConfig().

                  Manejo de excepciones en Python y rastreos

                  Registrar el rastro en tus registros de excepciones puede ser muy útil para solucionar problemas. Como vimos anteriormente, logging.error() no incluye ninguna información de rastreo por defecto – simplemente registrará la excepción como un error, sin proporcionar ningún contexto adicional. Para asegurarse de que logging.error() capture el rastreo, establezca el parámetro sys.exc_info como True. Para ilustrar, probemos a registrar una excepción con y sin exc_info:

                  # lowermodule.pylogging.config.fileConfig('/path/to/logging.ini', disable_existing_loggers=False)logger = logging.getLogger(__name__)def word_count(myfile): try: # count the number of words in a file, myfile, and log the result except OSError as e: logger.error(e) logger.error(e, exc_info=True)

                  Si ejecutas el código con un archivo inaccesible (por ejemplo, nonexistentfile.txt) como entrada, generará la siguiente salida:

                  2019-03-27 21:01:58,191 lowermodule - ERROR: No such file or directory: 'nonexistentfile.txt'2019-03-27 21:01:58,191 lowermodule - ERROR: No such file or directory: 'nonexistentfile.txt'Traceback (most recent call last): File "/home/emily/logstest/lowermodule.py", line 14, in word_count with open(myfile, 'r') as f:FileNotFoundError: No such file or directory: 'nonexistentfile.txt'

                  La primera línea, registrada por logger.error(), no proporciona mucho contexto más allá del mensaje de error («No such file or directory»). La segunda línea muestra cómo añadir exc_info=True a logger.error() permite capturar el tipo de excepción (FileNotFoundError) y el rastreo, que incluye información sobre la función y el número de línea donde se ha producido esta excepción.

                  Alternativamente, también puedes usar logger.exception() para registrar la excepción desde un manejador de excepciones (como en una cláusula except). Esto captura automáticamente la misma información de rastreo mostrada anteriormente y establece ERROR como el nivel de prioridad del registro, sin necesidad de establecer explícitamente exc_info a True. Independientemente del método que utilices para capturar el traceback, disponer de la información completa de las excepciones en tus registros es fundamental para monitorizar y solucionar el rendimiento de tus aplicaciones.

                  Capturar las excepciones no manejadas

                  Nunca podrás anticipar y manejar todas las excepciones posibles, pero puedes asegurarte de registrar las excepciones no capturadas para poder investigarlas más adelante. Una excepción no controlada ocurre fuera de un bloque try...except, o cuando no incluyes el tipo de excepción correcto en tu declaración except. Por ejemplo, si tu aplicación encuentra una excepción TypeError, y tu cláusula except sólo maneja un NameError, se pasará a cualquier cláusula try restante hasta que encuentre el tipo de excepción correcto.

                  Si no lo hace, se convierte en una excepción no manejada, en cuyo caso, el intérprete invocará sys.excepthook(), con tres argumentos: la clase de la excepción, la instancia de la excepción y el rastreo. Esta información suele aparecer en sys.stderr, pero si has configurado tu logger para que salga a un archivo, la información del traceback no se registrará allí.

                  Puedes utilizar la librería estándar de Python traceback para formatear el traceback e incluirlo en el mensaje de log. Revisemos nuestra función word_count() para que intente escribir el número de palabras en el archivo. Como hemos proporcionado un número incorrecto de argumentos en la función write(), ésta lanzará una excepción:

                  # lowermodule.pyimport logging.configimport tracebacklogging.config.fileConfig('logging.ini', disable_existing_loggers=False)logger = logging.getLogger(__name__)def word_count(myfile): try: # count the number of words in a file, myfile, and log the result with open(myfile, 'r+') as f: file_data = f.read() words = file_data.split(" ") final_word_count = len(words) logger.info("this file has %d words", final_word_count) f.write("this file has %d words", final_word_count) return final_word_count except OSError as e: logger.error(e, exc_info=True) except: logger.error("uncaught exception: %s", traceback.format_exc()) return Falseif __name__ == '__main__': word_count('myfile.txt')

                  Al ejecutar este código nos encontraremos con una excepción TypeError que no se maneja en la lógica try-except. Sin embargo, como hemos añadido el código traceback, se registrará, gracias al código de seguimiento incluido en la segunda cláusula except:

                  # exception doesn't get handled but still gets logged, thanks to our traceback code2019-03-28 15:22:31,121 lowermodule - ERROR:uncaught exception: Traceback (most recent call last): File "/home/emily/logstest/lowermodule.py", line 23, in word_count f.write("this file has %d words", final_word_count)TypeError: write() takes exactly one argument (2 given)

                  El registro de la traza completa dentro de cada excepción manejada y no manejada proporciona una visibilidad crítica de los errores a medida que se producen en tiempo real, para que puedas investigar cuándo y por qué se produjeron. Aunque las excepciones de varias líneas son fáciles de leer, si está agregando sus registros con un servicio de registro externo, querrá convertir sus registros en JSON para asegurarse de que sus registros de varias líneas se analizan correctamente. A continuación, te mostraremos cómo usar una librería como python-json-logger para registrar en formato JSON.

                  Unifica todos tus registros de Python

                  Hasta ahora, te hemos mostrado cómo configurar la librería de registro incorporada en Python, personalizar el formato y el nivel de gravedad de tus registros, y capturar información útil como el nombre del registrador y las trazas de excepción. También hemos utilizado la configuración basada en archivos para implementar un formato de registro más dinámico y opciones de enrutamiento. Ahora podemos centrar nuestra atención en la interpretación y el análisis de todos los datos que estamos recopilando. En esta sección, le mostraremos cómo formatear los registros en JSON, añadir atributos personalizados y centralizar y analizar esos datos con una solución de gestión de registros para obtener una visibilidad más profunda del rendimiento de la aplicación, los errores y mucho más.

                  Agilice su recopilación y análisis de registros de Python con Datadog.

                  Registro en formato JSON

                  A medida que sus sistemas generan más registros con el tiempo, puede convertirse rápidamente en un desafío para localizar los registros que pueden ayudarle a solucionar problemas específicos, especialmente cuando esos registros se distribuyen a través de múltiples servidores, servicios y archivos. Si centraliza sus registros con una solución de gestión de registros, siempre sabrá dónde buscar cada vez que necesite buscar y analizar sus registros, en lugar de entrar manualmente en cada servidor de aplicaciones.

                  El registro en JSON es una práctica recomendada al centralizar sus registros con un servicio de gestión de registros, porque las máquinas pueden analizar fácilmente este formato estándar y estructurado. El formato JSON también es fácilmente personalizable para incluir cualquier atributo que decida añadir a cada formato de registro, por lo que no tendrá que actualizar sus conductos de procesamiento de registros cada vez que añada o elimine un atributo de su formato de registro.

                  La comunidad de Python ha desarrollado varias bibliotecas que pueden ayudarle a convertir sus registros en formato JSON. Para este ejemplo, utilizaremos python-json-logger para convertir los registros en JSON.

                  Primero, instálalo en tu entorno:

                  pip install python-json-logger

                  Ahora actualiza el archivo de configuración de logs (por ejemplo, logging.ini) para personalizar un formateador existente o añadir uno nuevo que formatee los registros en JSON ( en el ejemplo siguiente). El formateador JSON debe utilizar la clase pythonjsonlogger.jsonlogger.JsonFormatter. En la clave format del formateador, puedes especificar los atributos que te gustaría incluir en el objeto JSON de cada registro:

                  keys=root,lowermodulekeys=consoleHandler,fileHandlerkeys=simpleFormatter,jsonlevel=DEBUGhandlers=consoleHandlerlevel=DEBUGhandlers=fileHandlerqualname=lowermoduleclass=StreamHandlerlevel=DEBUGformatter=simpleFormatterargs=(sys.stdout,)class=FileHandlerlevel=DEBUGformatter=jsonargs=("/home/emily/myapp.log",)class=pythonjsonlogger.jsonlogger.JsonFormatterformat=%(asctime)s %(name)s %(levelname)s %(message)sformat=%(asctime)s %(name)s - %(levelname)s:%(message)s

                  Los registros que se envíen a la consola (con el consoleHandler) seguirán siguiendo el formato simpleFormatter para facilitar su lectura, pero los registros producidos por el lowermodule logger se escribirán en el archivo myapp.log en formato JSON.

                  Una vez que hayas incluido la clase pythonjsonlogger.jsonlogger.JsonFormatter en tu archivo de configuración de registro, la función fileConfig() debería ser capaz de crear el JsonFormatter siempre que ejecutes el código desde un entorno en el que se pueda importar pythonjsonlogger.

                  Si no estás utilizando la configuración basada en archivos, tendrás que importar la biblioteca python-json-logger en el código de tu aplicación, y definir un manejador y un formateador, como se describe en la documentación:

                  from pythonjsonlogger import jsonloggerlogger = logging.getLogger()logHandler = logging.StreamHandler()formatter = jsonlogger.JsonFormatter()logHandler.setFormatter(formatter)logger.addHandler(logHandler)

                  Para ver por qué es preferible el formato JSON, sobre todo cuando se trata de registros más complejos o detallados, volvamos al ejemplo del rastreo de la excepción de varias líneas que registramos antes. Se veía algo así:

                  2019-03-27 21:01:58,191 lowermodule - ERROR: No such file or directory: 'nonexistentfile.txt'Traceback (most recent call last): File "/home/emily/logstest/lowermodule.py", line 14, in word_count with open(myfile, 'r') as f:FileNotFoundError: No such file or directory: 'nonexistentfile.txt'

                  Aunque este registro de rastreo de excepciones es fácil de leer en un archivo o en la consola, si es procesado por una plataforma de gestión de registros, cada línea puede aparecer como un registro separado (a menos que configure reglas de agregación multilínea), lo que puede dificultar la reconstrucción de lo que sucedió exactamente.

                  Ahora que estamos registrando este rastreo de excepciones en JSON, la aplicación generará un único registro con el siguiente aspecto:

                  {"asctime": "2019-03-28 17:44:40,202", "name": "lowermodule", "levelname": "ERROR", "message": " No such file or directory: 'nonexistentfile.txt'", "exc_info": "Traceback (most recent call last):\n File \"/home/emily/logstest/lowermodule.py\", line 19, in word_count\n with open(myfile, 'r') as f:\nFileNotFoundError: No such file or directory: 'nonexistentfile.txt'"}

                  Un servicio de registro puede interpretar fácilmente este registro JSON y mostrar la información completa del rastreo (incluyendo el atributo exc_info) en un formato fácil de leer:

                  Registro de rastreo de excepciones de Python

                  Añadir atributos personalizados a tus registros JSON

                  Otra de las ventajas de registrar en JSON es que puedes añadir atributos que un servicio externo de gestión de registros puede analizar automáticamente. Antes hemos configurado el format para incluir atributos estándar como %(asctime)s%(name)s%(levelname)s, y %(message)s. También puedes registrar atributos personalizados utilizando el campo python-json-logs «extra». A continuación, creamos un nuevo atributo que registra la duración de esta operación:

                  # lowermodule.pyimport logging.configimport tracebackimport timedef word_count(myfile): logger = logging.getLogger(__name__) logging.fileConfig('logging.ini', disable_existing_loggers=False) try: starttime = time.time() with open(myfile, 'r') as f: file_data = f.read() words = file_data.split(" ") final_word_count = len(words) endtime = time.time() duration = endtime - starttime logger.info("this file has %d words", final_word_count, extra={"run_duration":duration}) return final_word_count except OSError as e: 

                  Este atributo personalizado, run_duration, mide la duración de la operación en segundos:

                  {"asctime": "2019-03-28 18:13:05,061", "name": "lowermodule", "levelname": "INFO", "message": "this file has 44 words", "run_duration": 6.389617919921875e-05}

                  En una solución de gestión de registros, los atributos de este registro JSON se analizarían en algo parecido a lo siguiente:

                  Python registra los atributos personalizados en JSON

                  Si estás usando una plataforma de monitorización de registros, puedes graficar y alertar sobre el run_duration de tu aplicación en el tiempo. También puedes exportar este gráfico a un panel de control si quieres visualizarlo junto a las métricas de rendimiento de la aplicación o de la infraestructura.

                  Datadog log analytics for Python logs custom JSON attribute for run duration

                  Ya sea que estés usando python-json-logger u otra biblioteca para formatear tus registros de Python en JSON, es fácil personalizar tus logs para incluir información que puedas analizar con una plataforma externa de gestión de logs.

                  Correlaciona los logs con otras fuentes de datos de monitorización

                  Una vez que centralices tus logs de Python con un servicio de monitorización, puedes empezar a explorarlos junto con las trazas de peticiones distribuidas y las métricas de la infraestructura para obtener una visibilidad más profunda de tus aplicaciones. Un servicio como Datadog puede conectar los registros con las métricas y los datos de monitorización del rendimiento de las aplicaciones para ayudarle a ver la imagen completa.

                  Por ejemplo, si actualiza su formato de registro para incluir los atributos dd.trace_id y dd.span_id, Datadog correlacionará automáticamente los registros y las trazas de cada solicitud individual. Esto significa que mientras está viendo una traza, puede simplemente hacer clic en la pestaña «Logs» de la vista de trazas para ver cualquier registro generado durante esa solicitud específica, como se muestra a continuación.

                  Los registros de Python de Datadog están correlacionados con las trazas de las solicitudes

                  También puede navegar en la otra dirección -desde un registro hasta la traza de la solicitud que generó el registro- si necesita investigar un problema específico. Consulte nuestra documentación para obtener más detalles sobre la correlación automática de los registros y las trazas de Python para una solución de problemas más rápida.

                  Centralice y analice sus registros de Python

                  En este post hemos recorrido algunas de las mejores prácticas para configurar la biblioteca de registro estándar de Python para generar registros ricos en contexto, capturar trazas de excepción y enrutar los registros a los destinos apropiados. También hemos visto cómo puedes centralizar, analizar y analizar tus registros con formato JSON con una plataforma de gestión de registros cuando necesites solucionar o depurar problemas. Si desea supervisar los registros de su aplicación Python con Datadog, regístrese para obtener una prueba gratuita.

    Deja una respuesta

    Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *