---
title: "Configura il logging di Python con i livelli di log giusti e la cattura delle eccezioni"
description: "Python logging stampa solo WARNING e superiori finché non lo configuri. Ecco la configurazione in 3 righe, i 5 livelli di log e come registrare un’eccezione con il traceback, su Python 3.13."
canonical: "https://logbrew.co/it/guides/python-logging"
last_updated: "2026-11-10"
---

# Configura il logging di Python con i livelli di log giusti e la cattura delle eccezioni

Python `logging` stampa solo WARNING e superiori finché non lo configuri. Ecco la configurazione in 3 righe, i 5 livelli di log e come registrare un’eccezione con il traceback, su Python 3.13.

Testato il 10 novembre 2026 con Python 3.13.5 e logbrew-sdk 0.1.29

Di [Furkan Erday](https://github.com/furkanerday). Furkan Erday è il fondatore di LogBrew. Sviluppa LogBrew ogni giorno con Claude Code e Codex.

Canonical: https://logbrew.co/it/guides/python-logging

## Cosa fa ogni livello di log di Python senza configurazione, e in LogBrew

| Chiamata di logging | Stampato senza configurazione | Livello a sé in LogBrew |
| --- | --- | --- |
| `log.debug()` | Scartato | Unito a `info` |
| `log.info()` | Scartato | `info` |
| `log.warning()` | `WARNING:root:` | `warning` |
| `log.error()` | `ERROR:root:` | `error` |
| `log.critical()` | `CRITICAL:root:` | `critical` |

5 chiamate sul logger root senza configurazione, poi le stesse 5 attraverso l’handler di LogBrew. Una tazza piena significa stampato, o conservato come livello a sé.

## Configura il logging in 3 righe

### Chiama basicConfig() una volta, prima della prima chiamata di log

`basicConfig()` imposta il livello e il formato di riga del logger root. Senza configurazione, Python stampa solo WARNING e superiori, come `WARNING:root:keg below 10%`, e scarta 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")
```

Output

```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
```

### Dai a ogni modulo il suo logger

`logging.getLogger(__name__)` dà a ogni modulo il proprio logger, così ogni riga indica il modulo da cui arriva. Tieni il logger root solo per `basicConfig()`.

### Leggi il livello dall’ambiente

`basicConfig()` accetta il nome del livello come testo. Esegui questo con `LOG_LEVEL=DEBUG` e la riga di debug compare, senza cambiare il codice.

```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")
```

Output

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

### Passa force=True per configurare di nuovo

Python ignora una seconda chiamata a `basicConfig()` quando il logger root ha già un handler. Passa `force=True` per sostituire gli handler, per esempio nei test.

```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")
```

Output

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

## Registra ogni eccezione con il suo traceback

### Chiama log.exception() dentro except

`log.exception()` registra a livello ERROR e aggiunge il traceback. Passa `exc_info=True` a una chiamata di qualsiasi altro livello per fare lo stesso lì.

```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")
```

Output

```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'
```

### Invia ogni riga a LogBrew con l’handler di logging

Aggiungi `LogBrewLoggingHandler` al tuo logger. Ogni record diventa un log di LogBrew con livello, nome del logger, file e riga. Il nome e il messaggio dell’eccezione arrivano insieme, come i valori in `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")
```

Output

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

### Rileggi il log con i suoi campi di eccezione

`logbrew read logs --severity error --json` restituisce la riga con `exceptionName`, `exceptionMessage`, il file, la funzione, il numero di riga e il tuo `order_id`.

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

Output

```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"
  }
}
```

### Cattura il crash che termina il processo

`install_process_error_capture()` si aggancia a `sys.excepthook`. Un’eccezione che nessuno cattura diventa un problema di livello `critical` con `handled: false`, catturato prima che il processo esca con codice 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
```

Output

```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}}
```

## Cosa abbiamo visto nei test

Senza configurazione, 5 chiamate sul logger root hanno stampato 3 righe su stderr e scartato le chiamate DEBUG e INFO. La riga predefinita è il livello, il nome del logger e il messaggio, come `WARNING:root:keg below 10%`.

Una seconda chiamata a `basicConfig()` non ha cambiato nulla finché non abbiamo passato `force=True`. Attraverso l’handler di LogBrew, i record DEBUG e INFO sono arrivati come `info`, WARNING come `warning`, ERROR come `error` e CRITICAL come `critical`.

`log.exception()` ha aggiunto `exceptionName` ed `exceptionMessage` al log di LogBrew. Con `include_exception_text=True` sull’handler, il traceback completo è arrivato come `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")
```

Output

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

## I 5 livelli di log e quando usare ciascuno

DEBUG è per i valori che ti servono mentre correggi un bug, come la pressione del fusto, il testo SQL o il numero di tentativi. Lascialo spento in produzione.

INFO registra cosa ha fatto il programma, come una spina aperta o un ordine pagato. WARNING registra cosa è andato storto ma è stato gestito, come un fusto sotto il 10%. ERROR registra una richiesta o un job fallito, come un fusto vuoto. CRITICAL registra cosa ferma il programma, come una cella frigorifera spenta.

Registra ogni eccezione una volta, dove la gestisci. Una riga a ogni livello dello stack di chiamate invia 3 avvisi per 1 errore.

```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))
```

Output

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

## Cosa registra LogBrew

Ogni record diventa 1 log con livello, nome del logger, nome del file, funzione, numero di riga e modulo. I valori primitivi di `extra={}` diventano campi per cui puoi filtrare, e `metadata={}` sull’handler aggiunge un campo a ogni riga, come `service` qui sopra.

Su un’eccezione, il log riceve `exceptionName` ed `exceptionMessage`. Passa `include_exception_text=True` all’handler per salvare anche il testo del traceback.

`install_process_error_capture()` trasforma un’eccezione non catturata in un problema di livello `critical`, con il tipo dell’eccezione, i frame dello stack e il meccanismo `python.excepthook`.

## Domande frequenti

### Qual è il livello di logging predefinito in Python?

WARNING. Senza una chiamata a `basicConfig()`, il logger root stampa WARNING, ERROR e CRITICAL su stderr come `WARNING:root:message`, e scarta DEBUG e INFO.

### Perché logging.basicConfig non fa nulla?

Il logger root ha già un handler, da una chiamata precedente a `basicConfig()` o da una libreria, quindi Python ignora la chiamata. Passa `force=True` per sostituire gli handler.

### Che differenza c’è tra logging.error e logging.exception?

`log.exception()` è `log.error()` con `exc_info=True`. Registra a livello ERROR e aggiunge il traceback. Chiamalo solo dentro un blocco `except`.

### Quali sono i livelli di logging di Python in ordine?

DEBUG 10, INFO 20, WARNING 30, ERROR 40, CRITICAL 50. Un logger lascia passare un record quando il suo numero è pari o superiore al livello che hai impostato.

### Devo usare print() o logging in Python?

Usa `logging`. `print()` non ha livello, timestamp, nome del logger né handler. Con `logging` attivi le righe per modulo e le invii a un file o a LogBrew.

## Vedi ogni eccezione Python con il suo traceback

L’SDK Python di LogBrew invia ogni riga di log con livello, logger, file e riga, e trasforma un’eccezione non catturata in un problema con il suo stack trace. Inizia con il generoso piano gratuito, senza carta.

[Inizia gratis](https://logbrew.co/it)

## Fonti

- [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)

## Altre guide per gli agenti e Python

- [Aggiungi un server MCP a Claude Code e Codex](https://logbrew.co/it/guides/mcp-server-claude-code-codex)
- [Usa AGENTS.md in Claude Code e Codex](https://logbrew.co/it/guides/agents-md)
- [Risolvi l’errore overloaded 529 e l’errore di rate limit 429 di Claude](https://logbrew.co/it/guides/claude-overloaded-rate-limit-error)
- [Logging strutturato con un formato dei log e livelli che puoi cercare per campo](https://logbrew.co/it/guides/structured-logging)
- [Come risolvere gli errori in Claude Code, Codex, JavaScript e Python](https://logbrew.co/it/guides)
