Gerando Logs com python
Tags: python, logging, linux, programming
Published: 2021-01-11 21:53:33

Nesse artigo, iremos trabalhar com a geração de logs em python, utilizando o módulo *logging*.

**Retirado da documentação oficial do python**: "*Este módulo define funções e classes que implementam um sistema de registro de eventos flexível para aplicativos e bibliotecas.*"

O que a descrição acima quer dizer?
- Bem, imagine o seguinte cenário: Temos uma função que realiza retorna o nome completo de uma pessoa, os parâmetros dessa função são *primeiro_nome* e *ultimo_nome*, ambos aceitam strings como entrada, mas imagine que, por um motivo de força maior (pense nessa situação como algo para mérito de compreensão) a entrada seja do tipo booleano (True/False), nesse caso teríamos um erro e gostaríamos que o sistema reportasse essa mensagem de erro para nós. E é para isso, que temos esse módulo no python.

**Vamos abordar o exemplo acima de forma pratica**

1. Crie uma pasta para armazenar nosso codigo;
2. Crie um arquivo chamado *app.py*.

Dentro do nosso arquivo *app.py* iremos importar o módulo *logging*:

```python
import logging
```

Feito isso, iremos definir a formatação do nosso log:

```python
'''
   A formatação abaixo permite personalizarmos
   a forma como o log será mostrado para nós.
'''
# DateTime:Level:Arquivo:Mensagem
log_format = '%(asctime)s:%(levelname)s:%(filename)s:%(message)s'
```

Em seguida, definiremos as configurações do log e sua instancia:

```python
'''
   Aqui definimos as configurações do modulo.
   
   filename = 'nome do arquivo em que vamos salvar a mensagem do log.'
   filemode = 'É a forma em que o arquivo será gravado.'
   level = 'Level em que o log atuará'
   format = 'Formatação da mensagem do log'
'''
logging.basicConfig(filename='exemplo.log',
                    # w -> sobrescreve o arquivo a cada log
                    # a -> não sobrescreve o arquivo
                    filemode='w',
                    level=logging.DEBUG,
                    format=log_format)

'''
   O objeto getLogger() permite que retornemos
   varias instancias de logs.
'''
# Instancia do objeto getLogger()
logger = logging.getLogger('root')
```

- O módulo contém varios tipos de niveis de mensagens:

<table class="docutils align-default">
<colgroup>
<col style="width: 48%">
<col style="width: 52%">
</colgroup>
<thead>
<tr class="row-odd"><th class="head"><p>Level</p></th>
<th class="head"><p>Numeric value</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">CRITICAL</span></code></p></td>
<td><p>50</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">ERROR</span></code></p></td>
<td><p>40</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">WARNING</span></code></p></td>
<td><p>30</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">INFO</span></code></p></td>
<td><p>20</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">DEBUG</span></code></p></td>
<td><p>10</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">NOTSET</span></code></p></td>
<td><p>0</p></td>
</tr>
</tbody>
</table>

Até aqui definimos as configurações do nosso log, agora vamos colocar isso tudo em pratica, de fato.

Vamos fazer uma função que receba o *primeiro_nome* e o *segundo_nome* de uma pessoa e retorne o log dessa função no nosso arquivo *exemplo.log* (definido logo acima):

```python
def add(primeiro_nome: str, segundo_nome: str) -> str:
    """
        Essa função recebe o primeiro nome e o segundo nome de uma pessoa e retorna o nome completo dela.
    """

    # Aqui, verificamos se os parametros passados são do tipo string (str)
    if isinstance(primeiro_nome, str) and isinstance(segundo_nome, str):
        logger.info(f'{primeiro_nome} {segundo_nome}')
        return primeiro_nome + segundo_nome
    else:
        logger.error(
            f'{primeiro_nome} type: {type(primeiro_nome)} - {segundo_nome} type: {type(segundo_nome)}'
        )
```

Segue nosso codigo completo:
```python
import logging


'''
   A formatação abaixo permite personalizarmos
   a forma como o log será mostrado para nós.
'''
# DateTime:Level:Arquivo:Mensagem
log_format = '%(asctime)s:%(levelname)s:%(filename)s:%(message)s'
'''
   Aqui definimos as configurações do modulo.
   
   filename = 'nome do arquivo em que vamos salvar a mensagem do log.'
   filemode = 'É a forma em que o arquivo será gravado.'
   level = 'Level em que o log atuará'
   format = 'Formatação da mensagem do log'
'''
logging.basicConfig(filename='exemplo.log',
                    # w -> sobrescreve o arquivo a cada log
                    # a -> não sobrescreve o arquivo
                    filemode='w',
                    level=logging.DEBUG,
                    format=log_format)

'''
   O objeto getLogger() permite que retornemos
   varias instancias de logs.
'''
# Instancia do objeto getLogger()
logger = logging.getLogger('root')

def fullname(primeiro_nome: str, segundo_nome: str) -> str:
    """
        Essa função recebe o primeiro nome e o segundo nome de uma pessoa e retorna o nome completo dela.
    """

    # Aqui, verificamos se os parametros passados são do tipo string (str)
    if isinstance(primeiro_nome, str) and isinstance(segundo_nome, str):
        logger.info(f'{primeiro_nome} {segundo_nome}')
        return primeiro_nome + segundo_nome
    else:
        logger.error(
            f'{primeiro_nome} type: {type(primeiro_nome)} - {segundo_nome} type: {type(segundo_nome)}'
        )

fullname('Wendrew', 'Oliveira')
fullname('Wendrew', True)
```

O retorno desse codigo ficará dentro do arquivo *exemplo.log* no mesmo caminho do arquivo *app.py* e terá a seguinte forma:

![log](https://dev-to-uploads.s3.amazonaws.com/i/s6jnwumln9pjoq2yupoy.png)
 
Esse é o modo mais convencional de retorno de mensagens aos desenvolvedores, quando o sistema ja esta em produção