De forma geral, logging é uma maneira de manter um registro gerado por um programa de computador. Um arquivo de log normalmente reúne eventos que ocorrem no seu código (por exemplo, um código Python) ou no sistema operacional. Esses eventos ou mensagens são escritos em um arquivo de log; uma mensagem ou evento também pode ser uma comunicação entre usuários diferentes.
Normalmente, cabe aos desenvolvedores decidir como querem gerar logs. Talvez queiram registrar cada operação de um aplicativo que desenvolveram, logar apenas quando ocorrer um erro ou monitorar operações essenciais feitas por um usuário e registrá-las. Um exemplo de operação essencial seria verificar qual usuário final ou endereço IP acessou o aplicativo ou o servidor e, caso tenha sido uma tentativa sem sucesso, o desenvolvedor pode consultar os logs e obter mais insights do que um simples stack trace.
Um bom exemplo é quando você tenta fazer uma instalação no Linux como usuário sudo quando não tem privilégios de sudo. Você vê a mensagem "Xyz is not in the sudoers file. This incident will be reported", que é escrita em um arquivo de log.
A boa notícia é que o Python já vem com um módulo de logging integrado, pronto para uso, sem precisar de instalação.
Como o logging é diferente da função print?
O logging é parecido, em essência, com a função print. Porém, a função print não traz várias informações que podem ser úteis para quem desenvolve. Já o logging pode registrar timestamps e o número da linha em que o erro ocorreu. Ele pode enviar erros ou qualquer informação para arquivos, sockets etc., e oferece cinco níveis de severidade para você diferenciar seus logs.
Os cinco níveis de logging, como mostrado aqui, são:
Debug (10): útil para diagnosticar problemas no código.
Info (20): pode atuar como confirmação de que não há bugs no código. Um bom caso de uso do nível Info é acompanhar o progresso do treinamento de um modelo de machine learning.
Warning (30): indicativo de um problema que pode ocorrer no futuro. Por exemplo, um aviso de que um módulo será descontinuado ou um alerta de pouca memória RAM.
Error (40): um bug sério no código, como erro de sintaxe, falta de memória ou exceções.
Critical (50): um erro devido ao qual o programa pode parar de funcionar ou encerrar abruptamente.
Chega de teoria, certo?
Agora vamos entender como implementar logging em um código Python.
Mas antes, veja a tabela de atributos de logging; você vai usar alguns dos atributos abaixo neste tutorial.
Como dá para ver pelos outputs acima, apenas mensagens com nível de severidade maior que 20 foram registradas, pois essa é a configuração padrão do logging em Python.
No entanto, como comentado, você pode alterar os níveis de severidade usando o método basicConfig(). Aqui, vamos mudar o nível de severidade para 20, o que significa que níveis com severidade maior que 10 serão registrados.
Observação: reinicie o kernel antes de executar as células abaixo para ver o output correto.
Como você pode ver, agora os logs estão sendo gerados no arquivo datacamp.log. Ao executar as células acima várias vezes, você notará que os logs serão adicionados ao arquivo todas essas vezes. Por padrão, o arquivo é aberto em modo de append.
Você pode usar a palavra-chave filemode para evitar que o arquivo de log receba várias cópias dos mesmos registros (modo append). O filemode pode ser alterado para o modo write, que sobrescreve os logs anteriores e salva apenas os atuais. Como o filemode está definido como w, isso significa que o arquivo de log será aberto em modo de escrita toda vez que basicConfig() for executado, o que acabará sobrescrevendo o arquivo.
A funcionalidade de modo de arquivo no logging é semelhante ao tratamento de arquivos padrão oferecido pelo Python.
Vamos executar as linhas acima várias vezes. Você vai notar que, desta vez, apenas as entradas de log atuais serão salvas e as anteriores serão sobrescritas, como mostrado abaixo.
Vamos ver mais alguns atributos de logging, como data, hora e número da linha em que o aviso ou erro foi gerado. Como você já deve concordar, tudo isso é vantagem em relação a um simples print e é muito mais poderoso do que uma saída com print.
Para fazer isso, você vai passar os atributos de logging asctime e lineno. Também vai passar o atributo message, que será um placeholder para a mensagem que você quer exibir nos logs. Todos esses atributos serão passados para o parâmetro format.
Date-Time :2020-03-1823:58:12,429: Line No.:1-A Debug Logging Message
Date-Time :2020-03-1823:58:12,436: Line No.:2-A Info Logging Message
Date-Time :2020-03-1823:58:12,437: Line No.:3-A Warning Logging Message
Date-Time :2020-03-1823:58:12,440: Line No.:4- An Error Logging Message
Date-Time :2020-03-1823:58:12,441: Line No.:5-A Critical Logging Message
Tecnologia
Vamos às definições de cada atributo diretamente desta tabela.
asctime: horário legível por humanos quando o LogRecord foi gerado. Por padrão, tem o formato 2020-03-18 22:24:42,670 (os números após a vírgula são os milissegundos). Como esse atributo é uma string, você usa o especificador s depois dele.
lineno: número da linha de origem onde a chamada de logging ocorreu. Como esse atributo é um inteiro, você usa o especificador d depois dele.
message: a mensagem registrada, computada como msg % args. Isso é definido quando Formatter.format() é chamada. Se você não especificar esse atributo ao usar o parâmetro format(), as mensagens que deseja registrar não serão geradas. Da mesma forma, para o atributo message, você usa s por ser uma string.
funcName: exibe o nome do módulo ou da função em que o log foi gerado. É útil quando você tem muitas funções no código e quer separar os logs com base na função ou no método a que pertencem.
Vamos a um exemplo simples para ver como substituir o print por logging no nível debug.
import logging
logging.basicConfig(format='%(asctime)s ::%(levelname)s ::%(funcName)s ::%(lineno)d \
::%(message)s', level = logging.INFO)defaddition(x, y):
add = x + y
return add
defsubtract(x, y):
sub = x - y
return sub
defmultiply(x, y):
mul = x * y
return mul
defdivide(x, y):
div = x / y
return div
defexponent(x, y):
exp = x ** y
return exp
num1 =20
num2 =2defmain():
add_result = addition(num1, num2)
logging.info('Add: {} + {} = {}'.format(num1, num2, add_result))
sub_result = subtract(num1, num2)
logging.info('Sub: {} - {} = {}'.format(num1, num2, sub_result))
mul_result = multiply(num1, num2)
logging.info('Mul: {} * {} = {}'.format(num1, num2, mul_result))
div_result = divide(num1, num2)
logging.info('Div: {} / {} = {}'.format(num1, num2, div_result))
exp_result = exponent(num1, num2)
logging.info('Exp: {} ** {} = {}'.format(num1, num2, exp_result))
main()Tecnologia
2020-03-1900:01:27,372::INFO:: main ::35:: Add:20+2=222020-03-1900:01:27,376::INFO:: main ::38:: Sub:20-2=182020-03-1900:01:27,377::INFO:: main ::41:: Mul:20*2=402020-03-1900:01:27,378::INFO:: main ::44:: Div:20/2=10.02020-03-1900:01:27,379::INFO:: main ::47:: Exp:20**2=400Tecnologia
Conclusão
Parabéns por concluir o tutorial.
Vale a pena testar outros atributos de logging e entender como aproveitá-los no seu código.
Fique à vontade para deixar suas dúvidas sobre este tutorial nos comentários abaixo.
Descubra como escrever funções em Python reutilizáveis e eficientes. Domine parâmetros, instruções de retorno e temas avançados como funções lambda. Organize melhor seu código com main() e outras boas práticas.
Este guia completo ensina os fundamentos do desenvolvimento backend com Python. Aprenda conceitos básicos, frameworks e boas práticas para começar a criar aplicações web.
Mergulhe na ciência de dados com Python para analisar e visualizar seus dados de forma eficaz. Não precisa ter experiência ou conhecimento em programação.
Se você está começando em Python e quer aprender mais, faça o curso Introduction to Data Science in Python da DataCamp.
De forma geral, logging é uma maneira de manter um registro gerado por um programa de computador. Um arquivo de log normalmente reúne eventos que ocorrem no seu código (por exemplo, um código Python) ou no sistema operacional. Esses eventos ou mensagens são escritos em um arquivo de log; uma mensagem ou evento também pode ser uma comunicação entre usuários diferentes.
Normalmente, cabe aos desenvolvedores decidir como querem gerar logs. Talvez queiram registrar cada operação de um aplicativo que desenvolveram, logar apenas quando ocorrer um erro ou monitorar operações essenciais feitas por um usuário e registrá-las. Um exemplo de operação essencial seria verificar qual usuário final ou endereço IP acessou o aplicativo ou o servidor e, caso tenha sido uma tentativa sem sucesso, o desenvolvedor pode consultar os logs e obter mais insights do que um simples stack trace.
Um bom exemplo é quando você tenta fazer uma instalação no Linux como usuário sudo quando não tem privilégios de sudo. Você vê a mensagem "Xyz is not in the sudoers file. This incident will be reported", que é escrita em um arquivo de log.
A boa notícia é que o Python já vem com um módulo de logging integrado, pronto para uso, sem precisar de instalação.
Como o logging é diferente da função print?
O logging é parecido, em essência, com a
função print. Porém, a função print não traz várias informações que podem ser úteis para quem desenvolve. Já o logging pode registrar timestamps e o número da linha em que o erro ocorreu. Ele pode enviar erros ou qualquer informação para arquivos, sockets etc., e oferece cinco níveis de severidade para você diferenciar seus logs.Os cinco níveis de logging, como mostrado aqui, são:
Debug (10): útil para diagnosticar problemas no código.
Info (20): pode atuar como confirmação de que não há bugs no código. Um bom caso de uso do nível Info é acompanhar o progresso do treinamento de um modelo de machine learning.
Warning (30): indicativo de um problema que pode ocorrer no futuro. Por exemplo, um aviso de que um módulo será descontinuado ou um alerta de pouca memória RAM.
Error (40): um bug sério no código, como erro de sintaxe, falta de memória ou exceções.
Critical (50): um erro devido ao qual o programa pode parar de funcionar ou encerrar abruptamente.
Chega de teoria, certo?
Agora vamos entender como implementar logging em um código Python.
Mas antes, veja a tabela de atributos de logging; você vai usar alguns dos atributos abaixo neste tutorial.
Agora, chame o método
basicConfig(), que ajuda a criar uma configuração básica para o sistema de logging funcionar sem problemas.Ele permite definir os seguintes parâmetros:
Lembre-se: o método
basicConfig()é opcional e você pode optar por não usá-lo.Vamos agora acionar os cinco níveis de severidade.
Como dá para ver pelos outputs acima, apenas mensagens com nível de severidade maior que 20 foram registradas, pois essa é a configuração padrão do logging em Python.
No entanto, como comentado, você pode alterar os níveis de severidade usando o método
basicConfig(). Aqui, vamos mudar o nível de severidade para 20, o que significa que níveis com severidade maior que 10 serão registrados.Observação: reinicie o kernel antes de executar as células abaixo para ver o output correto.
Agora vamos registrar os outputs acima em um arquivo de log. Para isso, você vai usar o método
basicConfig().Como você pode ver, agora os logs estão sendo gerados no arquivo
datacamp.log. Ao executar as células acima várias vezes, você notará que os logs serão adicionados ao arquivo todas essas vezes. Por padrão, o arquivo é aberto em modo deappend.Você pode usar a palavra-chave
filemodepara evitar que o arquivo de log receba várias cópias dos mesmos registros (modo append). O filemode pode ser alterado para o modowrite, que sobrescreve os logs anteriores e salva apenas os atuais. Como o filemode está definido comow, isso significa que o arquivo de log será aberto emmodo de escritatoda vez quebasicConfig()for executado, o que acabará sobrescrevendo o arquivo.A funcionalidade de modo de arquivo no logging é semelhante ao tratamento de arquivos padrão oferecido pelo Python.
Vamos executar as linhas acima várias vezes. Você vai notar que, desta vez, apenas as entradas de log atuais serão salvas e as anteriores serão sobrescritas, como mostrado abaixo.
Vamos ver mais alguns atributos de logging, como data, hora e número da linha em que o aviso ou erro foi gerado. Como você já deve concordar, tudo isso é vantagem em relação a um simples print e é muito mais poderoso do que uma saída com print.
Para fazer isso, você vai passar os atributos de logging
asctimeelineno. Também vai passar o atributomessage, que será um placeholder para a mensagem que você quer exibir nos logs. Todos esses atributos serão passados para o parâmetroformat.Vamos às definições de cada atributo diretamente desta tabela.
asctime: horário legível por humanos quando o LogRecord foi gerado. Por padrão, tem o formato2020-03-18 22:24:42,670(os números após a vírgula são os milissegundos). Como esse atributo é uma string, você usa o especificadorsdepois dele.lineno: número da linha de origem onde a chamada de logging ocorreu. Como esse atributo é um inteiro, você usa o especificadorddepois dele.message: a mensagem registrada, computada como msg % args. Isso é definido quandoFormatter.format()é chamada. Se você não especificar esse atributo ao usar o parâmetroformat(), as mensagens que deseja registrar não serão geradas. Da mesma forma, para o atributo message, você usaspor ser uma string.funcName: exibe o nome do módulo ou da função em que o log foi gerado. É útil quando você tem muitas funções no código e quer separar os logs com base na função ou no método a que pertencem.Vamos a um exemplo simples para ver como substituir o print por logging no nível debug.
Conclusão
Parabéns por concluir o tutorial.
Vale a pena testar outros atributos de logging e entender como aproveitá-los no seu código.
Fique à vontade para deixar suas dúvidas sobre este tutorial nos comentários abaixo.
Se você está começando em Python e quer aprender mais, faça o curso Introduction to Data Science in Python da DataCamp.