O módulo de registo incorporado em Python foi concebido para lhe dar uma visibilidade crítica das suas aplicações com uma configuração mínima. Quer esteja apenas a começar ou já a utilizar o módulo de registo Python, este guia mostrar-lhe-á como configurar este módulo para registar todos os dados de que necessita, encaminhá-los para os destinos desejados, e centralizar os seus registos para obter conhecimentos mais profundos sobre as suas aplicações Python. Neste post, mostrar-lhe-emos como o fazer:
- Personalize o nível de prioridade e destino dos seus logs
- Configure uma configuração personalizada que envolve múltiplos loggers e destinos
- Configuração de tratamento de excepções e tracebacks nos seus logs
- Forme os seus registos no JSON e centralize-os para uma resolução de problemas mais eficaz
Bases do módulo de registo de Python
O módulo logging
está incluído na biblioteca padrão do Python, o que significa que se pode começar a utilizá-lo sem instalar nada. O método basicConfig()
do módulo de registo é a forma mais rápida de configurar o comportamento desejado do seu registador. Contudo, a documentação Python recomenda a criação de um logger para cada módulo na sua aplicação – e pode ser difícil configurar um logger por módulo usando basicConfig()
sozinho. Portanto, a maioria das aplicações (incluindo estruturas web como Django) utilizam automaticamente uma configuração de registo baseada em ficheiros ou em dicionários. Se quiser começar com um desses métodos, recomendamos que salte directamente para essa secção.
Três dos parâmetros principais de basicConfig()
são:
- nível: o nível mínimo de prioridade de mensagens a registar. Por ordem de severidade crescente, os níveis de registo disponíveis são: DEBUG, INFO, ADVERTÊNCIA, ERRO, e CRÍTICO. Por defeito, o nível é definido para AVISO, o que significa que o módulo de registo Python filtrará qualquer mensagem DEBUG ou INFO.
- handler: determina onde encaminhar os seus registos. A menos que especifique o contrário, a biblioteca de registo usará um formato
StreamHandler
para dirigir as mensagens de registo parasys.stderr
(normalmente a consola). - : por defeito, a biblioteca de registo registará as mensagens no seguinte formato:
<LEVEL>:<LOGGER_NAME>:<MESSAGE>
. Na secção seguinte, mostrar-lhe-emos como personalizar isto para incluir carimbos temporais e outras informações úteis para a resolução de problemas.
Desde que o módulo de registo apenas captura registos de ADVERTÊNCIA e registos de nível superior por defeito, pode faltar-lhe visibilidade em registos de menor prioridade que podem ser úteis para conduzir uma análise da causa raiz. O módulo de registo também transmite os registos para a consola em vez de os anexar a um ficheiro. Em vez de usar um StreamHandler
ou um SocketHandler
para transmitir os registos directamente para a consola ou para um serviço externo através da rede, deverá usar um FileHandler
para registar um ou mais ficheiros no disco.
Uma das principais vantagens de iniciar sessão num ficheiro é que a sua aplicação não precisa de ter em conta a possibilidade de encontrar erros relacionados com a rede enquanto efectua registos de streaming para um destino externo. Se se deparar com quaisquer problemas com registos de streaming através da rede, não perderá o acesso a esses registos, uma vez que serão armazenados localmente em cada servidor. A ligação a um ficheiro permite-lhe também criar uma configuração de registo mais personalizada, onde pode encaminhar diferentes tipos de registos para ficheiros separados, e seguir e centralizar esses ficheiros com um serviço de monitorização de registos.
Na secção seguinte, mostraremos como é fácil personalizar basicConfig()
para registar mensagens de menor prioridade e direccioná-las para um ficheiro em disco.
Um exemplo de basicConfig()
O exemplo seguinte utiliza basicConfig()
para configurar uma aplicação para registar mensagens DEBUG e de nível superior num ficheiro em disco (myapp.log). Também indica que os registos devem seguir um formato que inclua o carimbo da hora e o nível de gravidade do registo:
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")
Se executar o código num ficheiro acessível (por exemplo, myfile.txt) seguido de um ficheiro inacessível (por exemplo, myapp.log) inexistente ficheiro.txt), anexará os seguintes registos ao myapp.ficheiro de registo:
2019-03-27 10:49:00,979 DEBUG:this file has 44 words2019-03-27 10:49:00,979 ERROR:error reading the file
Obrigado ao novo basicConfig()
configuração, os registos de nível DEBUG já não estão a ser filtrados, e os registos seguem um formato personalizado que inclui os seguintes atributos:
-
%(asctime)s
: exibe a data e hora do registo, na hora local -
%(levelname)s
: o nível de registo da mensagem -
%(message)s
: a mensagem
Ver a documentação para informação sobre os atributos que pode incluir no formato de cada registo de registo. No exemplo acima, foi registada uma mensagem de erro, mas que não incluía qualquer informação de rastreio de excepção, tornando difícil determinar a origem do problema. Numa secção posterior deste post, mostraremos como registar o traceback completo quando ocorre uma excepção.
Vasculhar mais fundo na biblioteca de registo Python
Cobrimos o básico de basicConfig()
, mas como mencionado anteriormente, a maioria das aplicações beneficiarão da implementação de uma configuração de registo por módulo. À medida que a sua aplicação for escalando, precisará de uma forma mais robusta e escalável para configurar cada logger específico de módulo – e para se certificar de que está a capturar o nome do logger como parte de cada log. Nesta secção, vamos explorar como fazê-lo:
- configurar vários registadores e capturar automaticamente o nome do registador
- utilizar
fileConfig()
para implementar formatação personalizada e opções de encaminhamento - captura tracebacks e excepções sem controlo
Configurar vários registadores e capturar o nome do registador
Para seguir a melhor prática de criar um novo registador para cada módulo na sua aplicação, utilize o método de registo incorporado na biblioteca de registo getLogger()
para definir dinamicamente o nome do registador de forma a corresponder ao nome do seu módulo:
logger = logging.getLogger(__name__)
Este getLogger()
método define o nome do logger para __name__
, que corresponde ao nome totalmente qualificado do módulo a partir do qual este método é chamado. Isto permite-lhe ver exactamente qual o módulo na sua aplicação gerou cada mensagem de log, para que possa interpretar os seus logs mais claramente.
Por exemplo, se a sua aplicação inclui um módulo lowermodule.py que é chamado de outro módulo, uppermodule.py, o método getLogger()
definirá o nome do logger para corresponder ao módulo associado. Uma vez modificado o seu formato de registo para incluir o nome do registador (%(name)s
), verá esta informação em cada mensagem de registo. Pode definir o logger dentro de cada módulo desta forma:
# 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)
Se executarmos uppermodule.py num ficheiro acessível (myfile.txt) seguido de um ficheiro inacessível (ficheiro inexistente.txt), o módulo de registo irá gerar a seguinte saída:
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
O nome do registador é incluído logo após o carimbo da hora, para que se possa ver exactamente qual o módulo que gerou cada mensagem. Se não definir o logger com getLogger()
, cada nome de logger aparecerá como root
, tornando difícil discernir que mensagens foram registadas pelo uppermodule
em oposição ao lowermodule
. As mensagens que foram registadas de uppermodule.py listam o módulo __main__
como o nome do logger, porque uppermodule.py foi executado como o script de nível superior.
Embora estejamos agora automaticamente a capturar o nome do logger como parte do formato log, ambos os loggers são configurados com a mesma linha basicConfig()
. Na secção seguinte, mostraremos como racionalizar a sua configuração de registo usando fileConfig()
para aplicar a configuração de registo em vários registadores.
Utilizar fileConfig() para emitir registos para múltiplos destinos
embora basicConfig()
torne rápido e fácil começar com o registo, usando configuração baseada em ficheiro (fileConfig()
) ou dicionário (dictConfig()
) permite-lhe implementar mais opções de formatação e encaminhamento personalizadas para cada logger na sua aplicação, e registos de rotas para múltiplos destinos. Este é também o modelo que estruturas populares como Django e Flask utilizam para configurar o registo da aplicação. Nesta secção, vamos analisar mais de perto a configuração de registo baseada em ficheiros. Um ficheiro de configuração de registo precisa de conter três secções:
- : os nomes dos registadores que irá configurar.
- : o(s) manipulador(es) estes
loggers
devem usar (por exemploconsoleHandler
fileHandler
). - : o(s) formato(s) que pretende que cada logger siga ao gerar um log.
Cada secção deve incluir uma lista separada por vírgulas de uma ou mais chaves: keys=handler1,handler2,
. As chaves determinam os nomes das outras secções que terá de configurar, formatadas como , onde o nome da secção é logger, handler, ou formatter. Um exemplo de ficheiro de configuração de registo (logging.ini) é mostrado abaixo.
keys=rootkeys=fileHandlerkeys=simpleFormatterlevel=DEBUGhandlers=fileHandlerclass=FileHandlerlevel=DEBUGformatter=simpleFormatterargs=("/path/to/log/file.log",)format=%(asctime)s %(name)s - %(levelname)s:%(message)s
documentação de registo de Python recomenda que só deve anexar cada manipulador a um registador e confiar na propagação para aplicar manipuladores aos registadores de crianças apropriados. Isto significa que se tiver uma configuração padrão de registo que deseja que todos os seus registadores apanhem, deve adicioná-la a um registador pai (tal como o registador raiz), em vez de a aplicar a cada registador de nível inferior. Consulte a documentação para mais detalhes sobre a propagação. Neste exemplo, configurámos um root logger e deixamo-lo propagar para ambos os módulos da nossa aplicação (lowermodule
e uppermodule
). Ambos os loggers irão emitir DEBUG e logs de maior prioridade, no formato especificado (formatter_simpleFormatter
), e anexá-los a um ficheiro de log (file.log). Isto elimina a necessidade de incluir logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(name)s %(levelname)s:%(message)s')
em ambos os módulos.
Em vez disso, uma vez criado este ficheiro de configuração de registo, pode adicionar logging.config.fileConfig()
ao seu código dessa forma:
import logging.configlogging.config.fileConfig('/path/to/logging.ini', disable_existing_loggers=False)logger = logging.getLogger(__name__)
Confirme-se a import logging.config
para que tenha acesso à função fileConfig()
. Neste exemplo, disable_existing_loggers
está definido para False
, indicando que o módulo de registo não deve desactivar os registadores não-root existentes previamente. Esta configuração padrão é True
, o que irá desactivar quaisquer registadores não-root existentes antes de fileConfig()
, a menos que os configure depois.
A sua aplicação deve agora iniciar o registo com base na configuração que configurou no seu ficheiro log.ini. Também tem a opção de configurar o registo sob a forma de um dicionário Python (via dictConfig()
), em vez de num ficheiro. Consulte a documentação para mais detalhes sobre a utilização de fileConfig()
e dictConfig()
.
Python exception handling and tracebacks
Logging the traceback in your exception logs can be very helpful for troubleshooting issues. Como vimos anteriormente, logging.error()
não inclui qualquer informação de traceback por defeito – simplesmente registará a excepção como um erro, sem fornecer qualquer contexto adicional. Para garantir que logging.error()
captura o traceback, definir o parâmetro sys.exc_info
para True
. Para ilustrar, vamos tentar registar uma excepção com e sem 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)
Se executar o código com um ficheiro inacessível (por exemplo inexistente ficheiro.txt) como entrada, gerará a seguinte saída:
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'
A primeira linha, registada por logger.error()
, não fornece muito contexto para além da mensagem de erro (“Nenhum ficheiro ou directório deste tipo”). A segunda linha mostra como adicionar exc_info=True
a logger.error()
permite capturar o tipo de excepção (FileNotFoundError
) e o traceback, que inclui informação sobre a função e número de linha onde esta excepção foi levantada.
Alternativamente, também pode usar logger.exception()
para registar a excepção de um manipulador de excepções (tal como numa cláusula except
). Isto capta automaticamente a mesma informação de rastreio mostrada acima e define ERROR como o nível de prioridade do registo, sem exigir que se defina explicitamente exc_info
a True
. Independentemente do método que utilize para capturar o rastreio, ter toda a informação de excepção disponível nos seus registos é fundamental para monitorizar e solucionar problemas de desempenho das suas aplicações.
Capturar excepções sem controlo
Nunca será capaz de antecipar e lidar com todas as excepções possíveis, mas pode certificar-se de que regista excepções sem controlo para as poder investigar mais tarde. Uma excepção não aplicada ocorre fora de um bloco try...except
, ou quando não inclui o tipo de excepção correcto na sua declaração except
. Por exemplo, se a sua candidatura encontrar uma TypeError
excepção, e a sua except
cláusula só lida com uma NameError
cláusula, será passada para qualquer try
cláusula até encontrar o tipo de excepção correcto.
Se não encontrar, torna-se uma excepção não aplicada, caso em que o intérprete invocará sys.excepthook()
, com três argumentos: a classe de excepção, a instância de excepção, e o traceback. Esta informação aparece geralmente em sys.stderr
, mas se tiver configurado o seu logger para sair para um ficheiro, a informação de traceback não será registada lá.
Pode usar o padrão Python traceback
biblioteca para formatar o traceback e incluí-lo na mensagem de log. Vamos rever a nossa função word_count()
para que tente escrever a contagem de palavras para o ficheiro. Uma vez que fornecemos o número errado de argumentos na função write()
, irá levantar uma excepção:
# 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')
A execução deste código irá encontrar uma TypeError
excepção que não é tratada na lógica try-except. Contudo, uma vez que adicionámos o código traceback
, ele será registado, graças ao código de traceback incluído no segundo except
cláusula:
# 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)
Logging the full traceback within each handled and unhandled exception provides critical visibility into errors as they occur in real time, so that you can investigate when and why they occurred. Embora as excepções de múltiplas linhas sejam fáceis de ler, se estiver a agregar os seus registos com um serviço de registo externo, vai querer converter os seus registos em JSON para assegurar que os seus registos de múltiplas linhas sejam analisados correctamente. A seguir, mostrar-lhe-emos como utilizar uma biblioteca como python-json-logger
para iniciar sessão no formato JSON.
Unificar todos os seus registos Python
Até agora, mostrámos-lhe como configurar a biblioteca de registo integrada Python, personalizar o formato e o nível de gravidade dos seus registos, e capturar informação útil como o nome do registador e os vestígios de excepções. Também utilizámos a configuração baseada em ficheiros para implementar opções mais dinâmicas de formatação e encaminhamento de logs. Agora podemos voltar a nossa atenção para a interpretação e análise de todos os dados que estamos a recolher. Nesta secção, mostrar-lhe-emos como formatar logs em JSON, adicionar atributos personalizados, e centralizar e analisar esses dados com uma solução de gestão de logs para obter maior visibilidade do desempenho da aplicação, erros, e mais.
Agelar a sua colecção e análise de logs Python com Datadog.
Log em formato JSON
Como os seus sistemas geram mais logs ao longo do tempo, pode rapidamente tornar-se um desafio localizar os logs que podem ajudá-lo a resolver problemas específicos – especialmente quando esses logs são distribuídos por múltiplos servidores, serviços e ficheiros. Se centralizar os seus registos com uma solução de gestão de registos, saberá sempre onde procurar sempre que precisar de pesquisar e analisar os seus registos, em vez de iniciar manualmente a sessão em cada servidor de aplicação.
O registo em JSON é uma melhor prática ao centralizar os seus registos com um serviço de gestão de registos, porque as máquinas podem facilmente analisar e analisar este formato padrão e estruturado. O formato JSON também é facilmente personalizável para incluir quaisquer atributos que decida adicionar a cada formato de log, pelo que não necessitará de actualizar os seus pipelines de processamento de logs sempre que adicionar ou remover um atributo do seu formato de log.
A comunidade Python desenvolveu várias bibliotecas que podem ajudá-lo a converter os seus logs para o formato JSON. Para este exemplo, vamos utilizar python-json-logger
para converter os registos de registo em JSON.
P>Primeiro, instale-o no seu ambiente:
pip install python-json-logger
Agora actualize o ficheiro de configuração de registo (por exemplo logging.ini) para personalizar um formatador existente ou adicionar um novo formatador que irá formatar os registos no JSON ( no exemplo abaixo). O formatador JSON precisa de utilizar o
pythonjsonlogger.jsonlogger.JsonFormatter
class. No formatador format
key, pode especificar os atributos que gostaria de incluir no objecto JSON de cada registo de registo:
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
Logs que são enviados para a consola (com a tecla consoleHandler
) continuarão a seguir o formato simpleFormatter
para legibilidade, mas os logs produzidos pelo lowermodule
logger serão escritos para o myapp.ficheiro de registo em formato JSON.
Após ter incluído o pythonjsonlogger.jsonlogger.JsonFormatter
classe no seu ficheiro de configuração de registo, a função fileConfig()
deverá ser capaz de criar o JsonFormatter
desde que execute o código a partir de um ambiente onde possa importar pythonjsonlogger
.
Se não estiver a utilizar configuração baseada em ficheiros, terá de importar a biblioteca python-json-logger
no seu código de aplicação, e definir um manipulador e formatador, como descrito na documentação:
from pythonjsonlogger import jsonloggerlogger = logging.getLogger()logHandler = logging.StreamHandler()formatter = jsonlogger.JsonFormatter()logHandler.setFormatter(formatter)logger.addHandler(logHandler)
Para ver porque é que o formato JSON é preferível, particularmente quando se trata de registos de registo mais complexos ou detalhados, voltemos ao exemplo do traceback de excepção multi-linhas que registámos anteriormente. Parecia algo como isto:
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'
Apesar deste registo de traceback de excepção ser fácil de ler num ficheiro ou na consola, se for processado por uma plataforma de gestão de registos, cada linha pode aparecer como um registo separado (a menos que se configurem regras de agregação multi-linhas), o que pode tornar difícil reconstruir exactamente o que aconteceu.
Agora que estamos a registar este registo de excepção no JSON, a aplicação irá gerar um único registo que se parece com isto:
{"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'"}
Um serviço de registo pode facilmente interpretar este registo JSON e exibir a informação completa de registo (incluindo o atributo exc_info
) num formato de fácil leitura:
Adicionar atributos personalizados aos seus registos JSON
Outro benefício de registo no JSON é que pode adicionar atributos que um serviço de gestão de registo externo pode analisar e analisar automaticamente. Anteriormente, configurámos o format
para incluir atributos padrão como %(asctime)s
%(name)s
%(levelname)s
, e %(message)s
. Também pode registar atributos personalizados usando o campo python-json-logs
“extra”. Abaixo, criámos um novo atributo que rastreia a duração desta operação:
# 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
, mede a duração da operação em segundos:
{"asctime": "2019-03-28 18:13:05,061", "name": "lowermodule", "levelname": "INFO", "message": "this file has 44 words", "run_duration": 6.389617919921875e-05}
Numa solução de gestão de log, os atributos deste log JSON seriam analisados em algo que se parece com o seguinte:
Se estiver a utilizar uma plataforma de monitorização de logs, pode fazer gráficos e alertas no run_duration
da sua aplicação ao longo do tempo. Também pode exportar este gráfico para um painel de controlo se quiser visualizá-lo lado a lado com o desempenho da aplicação ou métricas de infra-estrutura.
Se estiver a usar python-json-logger
ou outra biblioteca para formatar os seus registos Python no JSON, é fácil personalizar os seus registos para incluir informação que pode analisar com uma plataforma externa de gestão de registos.
Correlacionar os registos com outras fontes de dados de monitorização
Após estar a centralizar os seus registos Python com um serviço de monitorização, pode começar a explorá-los juntamente com os traços de pedido distribuídos e métricas de infra-estrutura para obter uma visibilidade mais profunda das suas aplicações. Um serviço como o Datadog pode ligar os registos com métricas e dados de monitorização do desempenho da aplicação para o ajudar a ver a imagem completa.
Por exemplo, se actualizar o seu formato de registo para incluir os atributos dd.trace_id
e dd.span_id
, o Datadog correlacionará automaticamente os registos e os vestígios de cada pedido individual. Isto significa que ao visualizar um traço, pode simplesmente clicar no separador “Logs” da vista de traços para ver quaisquer registos gerados durante esse pedido específico, como mostrado abaixo.
Também pode navegar na outra direcção – desde um log até ao traço do pedido que gerou o log – se precisar de investigar um problema específico. Consulte a nossa documentação para mais detalhes sobre a correlação automática de registos Python e vestígios para uma resolução mais rápida de problemas.
Centralize e analise os seus registos Python
Neste post, percorremos algumas das melhores práticas para configurar a biblioteca padrão de registo Python para gerar registos ricos em contexto, capturar vestígios de excepção, e encaminhar os registos para os destinos apropriados. Também vimos como pode centralizar, analisar e analisar os seus registos em formato JSON com uma plataforma de gestão de registos sempre que precisar de resolver problemas ou depurar problemas. Se quiser monitorizar os seus registos de aplicação Python com Datadog, inscreva-se para um teste gratuito.