---
title: "Configure o logging do Python com os níveis de log certos e captura de exceções"
description: "O logging do Python só imprime WARNING e acima até você configurá-lo. Veja a configuração em 3 linhas, os 5 níveis de log e como registrar uma exceção com o traceback, em execuções no Python 3.13."
canonical: "https://logbrew.co/pt-BR/guides/python-logging"
last_updated: "2026-11-10"
---

# Configure o logging do Python com os níveis de log certos e captura de exceções

O `logging` do Python só imprime WARNING e acima até você configurá-lo. Veja a configuração em 3 linhas, os 5 níveis de log e como registrar uma exceção com o traceback, em execuções no Python 3.13.

Testado em 10 de novembro de 2026 com Python 3.13.5 e logbrew-sdk 0.1.29

Por [Furkan Erday](https://github.com/furkanerday). Furkan Erday é o fundador do LogBrew. Ele desenvolve o LogBrew com Claude Code e Codex todos os dias.

Canonical: https://logbrew.co/pt-BR/guides/python-logging

## O que cada nível de log do Python faz sem configuração, e no LogBrew

| Chamada de log | Impresso sem configuração | Nível próprio no LogBrew |
| --- | --- | --- |
| `log.debug()` | Descartado | Mesclado em `info` |
| `log.info()` | Descartado | `info` |
| `log.warning()` | `WARNING:root:` | `warning` |
| `log.error()` | `ERROR:root:` | `error` |
| `log.critical()` | `CRITICAL:root:` | `critical` |

5 chamadas no logger raiz sem configuração, depois as mesmas 5 pelo handler do LogBrew. Uma caneca cheia significa impresso, ou mantido como nível próprio.

## Configure o logging em 3 linhas

### Chame basicConfig() 1 vez, antes da primeira chamada de log

`basicConfig()` define o nível e o formato da linha do logger raiz. Sem configuração, o Python imprime só WARNING e acima, como `WARNING:root:keg below 10%`, e descarta DEBUG e INFO.

```bash
import logging

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s %(levelname)s %(name)s %(message)s",
)
log = logging.getLogger("taproom")

log.debug("keg pressure read")
log.info("tap opened")
log.warning("keg below 10%")
log.error("keg empty")
log.critical("cooler offline")
```

Saída

```text
2026-11-10 08:34:04,828 INFO taproom tap opened
2026-11-10 08:34:04,828 WARNING taproom keg below 10%
2026-11-10 08:34:04,828 ERROR taproom keg empty
2026-11-10 08:34:04,828 CRITICAL taproom cooler offline
```

### Dê a cada módulo um logger com o nome dele

`logging.getLogger(__name__)` dá a cada módulo o próprio logger, então cada linha diz de qual módulo veio. Reserve o logger raiz só para `basicConfig()`.

### Leia o nível do ambiente

`basicConfig()` aceita o nome do nível como texto. Rode isto com `LOG_LEVEL=DEBUG` e a linha de debug aparece, sem mudar o código.

```bash
import logging
import os

logging.basicConfig(level=os.environ.get("LOG_LEVEL", "INFO"))
log = logging.getLogger("taproom")
log.debug("keg pressure read")
log.info("tap opened")
```

Saída

```text
DEBUG:taproom:keg pressure read
INFO:taproom:tap opened
```

### Passe force=True para configurar de novo

O Python ignora uma 2ª chamada de `basicConfig()` quando o logger raiz já tem um handler. Passe `force=True` para substituir os handlers, por exemplo em testes.

```bash
import logging

logging.basicConfig(level=logging.WARNING)
logging.basicConfig(level=logging.DEBUG)
logging.debug("second basicConfig: not printed")
logging.basicConfig(level=logging.DEBUG, force=True)
logging.debug("basicConfig with force=True: printed")
```

Saída

```text
DEBUG:root:basicConfig with force=True: printed
```

## Registre toda exceção com o traceback

### Chame log.exception() dentro do except

`log.exception()` registra em ERROR e anexa o traceback. Passe `exc_info=True` a uma chamada em qualquer outro nível para fazer o mesmo ali.

```bash
import logging

logging.basicConfig(level=logging.INFO, format="%(levelname)s %(name)s %(message)s")
log = logging.getLogger("taproom")
taps = {"ipa": 12}

def pour(beer):
    return taps[beer]

try:
    pour("stout")
except KeyError:
    log.exception("pour failed")
```

Saída

```text
ERROR taproom pour failed
Traceback (most recent call last):
  File "app.py", line 11, in <module>
    pour("stout")
    ~~~~^^^^^^^^^
  File "app.py", line 8, in pour
    return taps[beer]
           ~~~~^^^^^^
KeyError: 'stout'
```

### Envie cada linha ao LogBrew com o handler de logging

Adicione `LogBrewLoggingHandler` ao seu logger. Cada registro vira um log do LogBrew com nível, nome do logger, arquivo e linha. O nome e a mensagem da exceção vão junto, assim como os valores em `extra={}`.

```bash
import logging
import os

from logbrew_sdk import HttpTransport, LogBrewClient, LogBrewLoggingHandler

client = LogBrewClient.create(api_key=os.environ["LOGBREW_SERVER_API_KEY"])
transport = HttpTransport()
log = logging.getLogger("taproom")
log.addHandler(LogBrewLoggingHandler(client, transport, metadata={"service": "taproom"}))
log.setLevel(logging.INFO)

taps = {"ipa": 12}

def pour(beer):
    return taps[beer]

try:
    pour("stout")
except KeyError:
    log.exception("pour failed", extra={"order_id": "ord_42"})

response = client.flush(transport)
print("HTTP", response.status_code, "accepted", response.accepted_events, "logs")
```

Saída

```text
HTTP 200 accepted 1 logs
```

### Leia o log de volta com os campos da exceção

`logbrew read logs --severity error --json` devolve a linha com `exceptionName`, `exceptionMessage`, o arquivo, a função, o número da linha e o seu `order_id`.

```bash
logbrew read logs --project <project_id> --severity error --since 1h --json | jq '.[0] | {level, message, logger: .attributes.logger, metadata: .attributes.metadata}'
```

Saída

```text
{
  "level": "error",
  "message": "pour failed",
  "logger": "taproom",
  "metadata": {
    "exceptionMessage": "'stout'",
    "exceptionName": "KeyError",
    "fileName": "send.py",
    "functionName": "<module>",
    "levelName": "ERROR",
    "levelNumber": 40,
    "lineNumber": 20,
    "module": "send",
    "order_id": "ord_42",
    "processName": "MainProcess",
    "service": "taproom",
    "threadName": "MainThread"
  }
}
```

### Capture a falha que encerra o processo

`install_process_error_capture()` se encaixa em `sys.excepthook`. Uma exceção que ninguém captura vira um problema no nível `critical` com `handled: false`, capturado antes de o processo sair com código 1.

```bash
import atexit
import json
import os

from logbrew_sdk import LogBrewClient, RecordingTransport, install_process_error_capture

transport = RecordingTransport.always_accept()
client = LogBrewClient.create(api_key=os.environ["LOGBREW_SERVER_API_KEY"], transport=transport)
install_process_error_capture(client, on_capture_error=print)


@atexit.register
def show_captured_issue() -> None:
    issue = json.loads(transport.last_body())["events"][0]["attributes"]
    print(json.dumps({k: issue[k] for k in ("title", "level")}), json.dumps(issue["exception"]))


kegs = {"ipa": 3}
kegs["stout"] -= 1
```

Saída

```text
Traceback (most recent call last):
  File "<stdin>", line 19, in <module>
KeyError: 'stout'
{"title": "KeyError", "level": "critical"} {"type": "KeyError", "mechanism": {"type": "python.excepthook", "handled": false}}
```

## O que vimos no teste

Sem configuração, 5 chamadas no logger raiz imprimiram 3 linhas no stderr e descartaram as chamadas DEBUG e INFO. A linha padrão é o nível, o nome do logger e a mensagem, como `WARNING:root:keg below 10%`.

Uma 2ª chamada de `basicConfig()` não mudou nada até passarmos `force=True`. Pelo handler do LogBrew, os registros DEBUG e INFO chegaram como `info`, WARNING como `warning`, ERROR como `error` e CRITICAL como `critical`.

`log.exception()` adicionou `exceptionName` e `exceptionMessage` ao log do LogBrew. Com `include_exception_text=True` no handler, o traceback completo chegou como `exceptionText`.

```bash
import logging

logging.debug("keg pressure read")
logging.info("tap opened")
logging.warning("keg below 10%")
logging.error("keg empty")
logging.critical("cooler offline")
```

Saída

```text
WARNING:root:keg below 10%
ERROR:root:keg empty
CRITICAL:root:cooler offline
```

## Os 5 níveis de log e quando usar cada um

DEBUG é para os valores de que você precisa enquanto corrige um bug, como a pressão do barril, o texto SQL ou o número de tentativas. Deixe desligado em produção.

INFO registra o que o programa fez, como uma torneira aberta ou um pedido pago. WARNING registra o que deu errado mas foi tratado, como um barril abaixo de 10%. ERROR registra uma requisição ou um job que falhou, como um barril vazio. CRITICAL registra o que para o programa, como uma câmara fria offline.

Registre cada exceção 1 vez, onde você a trata. Uma linha em cada nível da pilha de chamadas manda 3 alertas para 1 falha.

```bash
import logging

for name in ("DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"):
    print(name, logging.getLevelName(name))
print("root logger level:", logging.getLevelName(logging.getLogger().level))
```

Saída

```text
DEBUG 10
INFO 20
WARNING 30
ERROR 40
CRITICAL 50
root logger level: WARNING
```

## O que o LogBrew registra

Cada registro vira 1 log com nível, nome do logger, nome do arquivo, função, número da linha e módulo. Valores primitivos de `extra={}` viram campos pelos quais você filtra, e `metadata={}` no handler adiciona um campo a toda linha, como `service` acima.

Em uma exceção, o log recebe `exceptionName` e `exceptionMessage`. Passe `include_exception_text=True` ao handler para guardar também o texto do traceback.

`install_process_error_capture()` transforma uma exceção não capturada em um problema no nível `critical`, com o tipo da exceção, os frames da pilha e o mecanismo `python.excepthook`.

## Perguntas frequentes

### Qual é o nível de logging padrão do Python?

WARNING. Sem uma chamada de `basicConfig()`, o logger raiz imprime WARNING, ERROR e CRITICAL no stderr como `WARNING:root:message`, e descarta DEBUG e INFO.

### Por que logging.basicConfig não faz nada?

O logger raiz já tem um handler, de uma chamada anterior de `basicConfig()` ou de uma biblioteca, então o Python ignora a chamada. Passe `force=True` para substituir os handlers.

### Qual é a diferença entre logging.error e logging.exception?

`log.exception()` é `log.error()` com `exc_info=True`. Registra em ERROR e anexa o traceback. Chame só dentro de um bloco `except`.

### Quais são os níveis de logging do Python em ordem?

DEBUG 10, INFO 20, WARNING 30, ERROR 40, CRITICAL 50. Um logger deixa passar um registro quando o número dele é igual ou maior que o nível que você definiu.

### Devo usar print() ou logging no Python?

Use `logging`. `print()` não tem nível, timestamp, nome de logger nem handler. Com `logging` você liga linhas por módulo e as envia para um arquivo ou para o LogBrew.

## Veja toda exceção do Python com o traceback

O SDK Python do LogBrew envia cada linha de log com nível, logger, arquivo e linha, e transforma uma exceção não capturada em um problema com o stack trace. Comece no plano gratuito generoso, sem cartão.

[Comece grátis](https://logbrew.co/pt-BR)

## Fontes

- [Python docs, Logging HOWTO](https://docs.python.org/3/howto/logging.html)
- [Python docs, logging module](https://docs.python.org/3/library/logging.html)
- [python/cpython#78078](https://github.com/python/cpython/issues/78078)

## Mais guias para agentes e Python

- [Adicione um servidor MCP ao Claude Code e ao Codex](https://logbrew.co/pt-BR/guides/mcp-server-claude-code-codex)
- [Use AGENTS.md no Claude Code e no Codex](https://logbrew.co/pt-BR/guides/agents-md)
- [Corrija o erro 529 overloaded e o erro 429 de rate limit do Claude](https://logbrew.co/pt-BR/guides/claude-overloaded-rate-limit-error)
- [Logs estruturados com formato de log e níveis que você busca por campo](https://logbrew.co/pt-BR/guides/structured-logging)
- [Como corrigir erros no Claude Code, Codex, JavaScript e Python](https://logbrew.co/pt-BR/guides)
