Nunca mais prints! Digam “hello” ao logging em Python

Henrique Junqueira Branco
Data Hackers
Published in
6 min readFeb 8, 2021

--

Chega de encher seu código de print que não acrescentam utilidade alguma!

Photo by Chris Ried on Unsplash

Você está cansado de encher seu código de print e ficar horas esperando seu código rodar para ver uma mensagem na tela? Olhar fixo para não perder a mensagem… se espirrar, já era, horas desperdiçadas e vamos rodar o código novamente!

Print vs logging

Porque estudar mais uma biblioteca se já existe função print, que imprime o que eu quero ver na tela enquanto estou debugando?

Bom, de fato print e log têm funções similares, mas os arquivos de log são muito mais amplos, versáteis e úteis, principalmente para desenvolvedores. Com eles conseguimos registrar uma gama de informações muito maiores, de forma mais rápida e intuitiva, melhor do que encher seu código de print que não acrescentam funcionalidade alguma. Sem contar que ao fim de uma execução os arquivos ficam salvos, podendo ser consultados posteriormente, se necessário.

Mas afinal, o que é um arquivo de log?

Arquivos de log são gerados para armazenar/registrar eventos que acontecem. Simples assim! Existe uma biblioteca nativa da linguagem Python chamada logging que facilita esse caminho, ao invés de ter todo o trabalho de criar um arquivo e ir acrescentando informações nele. É um atalho para facilitar nossa vida… pois eu poderia muito bem manipular um arquivo para gravar todas essas informações

Amo tudo que facilita minha vida!

Amo tudo que facilita minha vida!
Photo by Ignacio Amenábar on Unsplash

O que armazenar em um arquivo de log?

O que quisermos! É um arquivo de texto comum, como qualquer outro! Simples e direto. Óbvio que para tudo na vida existem as famosas boas práticas. Aqui vão algumas sugestões do que é possível armazenar em um arquivo de log (tudo vai depender da sua necessidade). Vamos à elas:

  • Data/hora (timestamp): armazenamos a data e hora específica em que uma informação foi gravada no arquivo de log. Podemos controlar quando ocorreram as execuções de um sistema, por exemplo.
  • Nome do arquivo que gerou o log
  • Nome da função
  • Caminho de um arquivo
  • Linha do código que gerou o log
  • Mensagens padronizadas (sucesso/falha de execução)
  • Informações úteis para usuários/desenvolvedores
  • E muitas outras…

Níveis (level) de log

É uma boa prática seguir as orientações da própria documentação oficial da da biblioteca logging. Nela são definidos os seguintes níveis para se armazenar um log, onde cada level possui um número correspondente associado*:

DEBUG (10): informações detalhadas, normalmente de interesse apenas ao diagnosticar problemas.

INFO (20): Confirmação de que tudo está funcionando conforme o esperado.

WARNING (30): Uma indicação de que algo inesperado aconteceu, ou indicativo de algum problema em um futuro próximo (por exemplo, ‘espaço em disco insuficiente’). O software ainda está funcionando conforme o esperado.

CRITICAL (40): Devido a um problema mais sério, o software não conseguiu executar algumas funções.

ERROR (50): Um erro grave, indicando que o próprio programa pode não conseguir continuar em execução.

*Tradução literal da documentação oficial

Típico warning da biblioteca Pandas. Alguma coisa vai acontecer em um futuro não muito distante!

E como eu faço? Quero criar logo meus arquivos de log (perdão pelo trocadilho…)

Primeiro passo é importar a biblioteca. Não é necessário instalá-la, visto que é nativa da linguagem Python.

import logging

Antes de avançarmos com logs, quero trazer um exemplo onde usamos o print para avaliarmos as saídas de um código simples:

Debugando um código à moda antiga com print. Aprendam para nunca mais fazer!

Quando executamos esse trecho de código, veremos na tela (na tela/terminal! Já já veremos como armazenar em um arquivo de log):

Soma: 10 + 50 = 60
Sub: 10 - 50 = -40
Mult: 10 * 50 = -40
Div: 10 / 50 = -40

Pois bem. E onde entra o tal do log?

Para trocarmos de print para log, primeiro importamos a biblioteca com import logging e trocar print por logging.warning . Já me explico sobre o warning

Aqui apenas alteramos algumas linhas do código acima

Na tela/terminal, veremos o seguinte resultado:

WARNING:root:Soma: 10 + 50 = 60
WARNING:root:Sub: 10 - 50 = -40
WARNING:root:Mult: 10 * 50 = -40
WARNING:root:Div: 10 / 50 = -40

Bom, já ouve alguma alteração. Concordam? Mas qual a diferença, além do WARNING:root: ? Até aqui nenhuma, por enquanto. Mas porque usamos o logging.warning ?

Por padrão, o Python define que ele só irá armazenar/imprimir/gravar os arquivos com level maior que 30, lembrando da seguinte ordem:

debug (10) < info (20) < warning (30) < critical (40) < error (50)

Ou seja, nenhum log do level info ou debug será armazenado/impresso por padrão! E como alteramos essa configuração?

Basta adicionarmos a seguinte linha de código logo (explico em seguida) abaixo do import da biblioteca:

import logging
logging.basicConfig(filename = "teste.log", level = logging.DEBUG)
  • filename: Esse parâmetro define o nome de um arquivo que será gerado durante a execução, ao invés de imprimir na tela. Basta ver que ao executar novamente, nada será impresso, e o arquivo teste.log será criado.
  • level: já este parâmetro define qual o nível de log mínimo para ser armazenado. Nesse caso, como definimos DEBUG , todos os outros logs serão armazenados. Caso tenhamos definido CRITICAL , somente logs do level CRITICAL e ERROR serão gravados no arquivo.

Existem outros parâmetros de configuração que você pode explorá-los aqui, nesta documentação oficial.

Você pode definir, por exemplo, o modo de escrita no arquivo com o parâmetro filemode(cheque as possíveis opções aqui, mas se você já manipulou arquivos em Python, então conhece w , r, a , x , etc.). Por padrão o valor é a de append, ou seja, se não definirmos tal parâmetro, ele vai adicionar os logs ao arquivo já existente. Experimente rodar o código acima mais de uma vez e abrir o arquivo de logs… =)

Também é possível armazenar mensagens personalizadas com o parâmetro format , que exploraremos em seguida.

Personalizando seus logs

Se quisermos personalizar os logs, podemos acrescentar alguns padrões no parâmetro format das configurações nologging.basicConfig() .
Para definirmos um padrão, podemos escolher uma das opções encontradas neste link. Aqui basta copiar a coluna Format dentro do parâmetro format conforme exemplo abaixo:

logging.basicConfig(
filename = "teste.log"
level = logging.DEBUG,
format = "%(asctime)s :: %(levelno)s :: %(lineno)d")

Quando acrescentamos esse parâmetro, observem o que acontece com o arquivo de log. Aqui ele me gerou o seguinte resultado:

2021-02-08 18:59:14,784 :: 10 :: 262021-02-08 18:59:14,785 :: 10 :: 292021-02-08 18:59:14,785 :: 10 :: 322021-02-08 18:59:14,785 :: 10 :: 35

Eu acrescentei a data e hora da execução do script, o número relacionado ao level (degug = 10, info = 20, etc.) e adicionou a linha do código em que ele executou o log.

Quando você executar, provavelmente verá resultados diferentes, mas de acordo com as configurações que você escolheu. Percebam que as 3 opções %(asctime)s , %(levelno)s e %(lineno)d foram escolhidas e definidas por mim, usando como separador o símbolo :: .

Esse tipo de configuração facilita muito quando você precisa armazenar qual usuário executou, quando, como, qual linha, qual arquivo, se deu erro ou sucesso. E sem precisar ficar horas na tela esperando seu print. Pode colocar o código pra rodar, tomar um café e ver seu arquivo de log posteriormente!

Photo by John Schnobrich on Unsplash

Em resumo, logs são ótimas alternativas (diria até que infalíveis) para substituir os prints da vida!

--

--

Henrique Junqueira Branco
Data Hackers

Life-time learner data scientist with great passion for new insights and technologies