---
title: "Thiết lập logging Python với đúng mức log và bắt ngoại lệ kèm traceback"
description: "Python logging chỉ in WARNING trở lên cho đến khi bạn cấu hình nó. Đây là cách thiết lập 3 dòng, 5 mức log và cách ghi log một ngoại lệ kèm traceback, từ các lượt chạy trên Python 3.13."
canonical: "https://logbrew.co/vi/guides/python-logging"
last_updated: "2026-11-10"
---

# Thiết lập logging Python với đúng mức log và bắt ngoại lệ kèm traceback

Python `logging` chỉ in WARNING trở lên cho đến khi bạn cấu hình nó. Đây là cách thiết lập 3 dòng, 5 mức log và cách ghi log một ngoại lệ kèm traceback, từ các lượt chạy trên Python 3.13.

Đã thử nghiệm ngày 10 tháng 11, 2026 với Python 3.13.5 và logbrew-sdk 0.1.29

Tác giả [Furkan Erday](https://github.com/furkanerday). Furkan Erday là nhà sáng lập LogBrew. Anh xây dựng LogBrew bằng Claude Code và Codex mỗi ngày.

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

## Mỗi mức log của Python làm gì khi chưa cấu hình, và trong LogBrew

| Lời gọi log | In ra khi chưa cấu hình | Mức riêng trong LogBrew |
| --- | --- | --- |
| `log.debug()` | Bị bỏ | Gộp vào `info` |
| `log.info()` | Bị bỏ | `info` |
| `log.warning()` | `WARNING:root:` | `warning` |
| `log.error()` | `ERROR:root:` | `error` |
| `log.critical()` | `CRITICAL:root:` | `critical` |

5 lời gọi trên root logger khi chưa cấu hình, rồi cùng 5 lời gọi đó qua handler của LogBrew. Cốc đầy nghĩa là được in ra, hoặc được giữ đúng mức của nó.

## Thiết lập logging trong 3 dòng

### Gọi basicConfig() 1 lần, trước lời gọi log đầu tiên

`basicConfig()` đặt mức log và định dạng dòng cho root logger. Khi chưa cấu hình, Python chỉ in WARNING trở lên, dạng `WARNING:root:keg below 10%`, và bỏ qua DEBUG và 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")
```

Kết quả

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

### Đặt tên logger theo từng module

`logging.getLogger(__name__)` cho mỗi module một logger riêng, nên mỗi dòng đều nêu tên module tạo ra nó. Chỉ dùng root logger cho `basicConfig()`.

### Đọc mức log từ biến môi trường

`basicConfig()` nhận tên mức log dưới dạng chuỗi. Chạy đoạn này với `LOG_LEVEL=DEBUG` và dòng debug xuất hiện mà không cần sửa code.

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

Kết quả

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

### Truyền force=True để cấu hình lại

Python bỏ qua lời gọi `basicConfig()` thứ 2 khi root logger đã có handler. Truyền `force=True` để thay thế các handler, chẳng hạn trong 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")
```

Kết quả

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

## Ghi log mọi ngoại lệ kèm traceback

### Gọi log.exception() bên trong except

`log.exception()` ghi log ở mức ERROR và đính kèm traceback. Truyền `exc_info=True` vào lời gọi ở bất kỳ mức nào khác để làm điều tương tự ở đó.

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

Kết quả

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

### Gửi từng dòng tới LogBrew bằng logging handler

Thêm `LogBrewLoggingHandler` vào logger của bạn. Mỗi bản ghi trở thành một log LogBrew với mức log, tên logger, file và dòng. Tên và thông điệp của ngoại lệ đi kèm, các giá trị trong `extra={}` cũng vậy.

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

Kết quả

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

### Đọc lại log cùng các trường ngoại lệ

`logbrew read logs --severity error --json` trả về dòng log với `exceptionName`, `exceptionMessage`, file, hàm, số dòng và `order_id` của bạn.

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

Kết quả

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

### Bắt crash làm tiến trình dừng

`install_process_error_capture()` gắn vào `sys.excepthook`. Một ngoại lệ không ai bắt trở thành một vấn đề ở mức `critical` với `handled: false`, được ghi lại trước khi tiến trình thoát với mã 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
```

Kết quả

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

## Kết quả khi chúng tôi thử nghiệm

Khi chưa cấu hình, 5 lời gọi trên root logger in 3 dòng ra stderr và bỏ qua các lời gọi DEBUG và INFO. Dòng mặc định gồm mức log, tên logger và thông điệp, dạng `WARNING:root:keg below 10%`.

Lời gọi `basicConfig()` thứ 2 không thay đổi gì cho đến khi chúng tôi truyền `force=True`. Qua handler của LogBrew, các bản ghi DEBUG và INFO đến dưới dạng `info`, WARNING thành `warning`, ERROR thành `error` và CRITICAL thành `critical`.

`log.exception()` thêm `exceptionName` và `exceptionMessage` vào log LogBrew. Với `include_exception_text=True` trên handler, toàn bộ traceback đến dưới dạng `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")
```

Kết quả

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

## 5 mức log và khi nào dùng mỗi mức

DEBUG dành cho các giá trị bạn cần khi sửa bug, như áp suất thùng keg, câu SQL hay số lần thử lại. Tắt nó trên production.

INFO ghi lại việc chương trình đã làm, như mở một vòi hay một đơn hàng đã thanh toán. WARNING ghi lại việc trục trặc nhưng đã được xử lý, như thùng keg dưới 10%. ERROR ghi lại một request hay một job thất bại, như thùng keg cạn. CRITICAL ghi lại việc làm chương trình dừng, như tủ lạnh mất kết nối.

Ghi log mỗi ngoại lệ 1 lần, tại nơi bạn xử lý nó. Một dòng ở mọi tầng của call stack sẽ gửi 3 cảnh báo cho 1 lỗi.

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

Kết quả

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

## LogBrew ghi nhận những gì

Mỗi bản ghi trở thành 1 log với mức log, tên logger, tên file, hàm, số dòng và module. Giá trị nguyên thủy trong `extra={}` trở thành các trường bạn lọc được, và `metadata={}` trên handler thêm một trường vào mọi dòng, như `service` ở trên.

Khi có ngoại lệ, log nhận thêm `exceptionName` và `exceptionMessage`. Truyền `include_exception_text=True` cho handler để lưu cả văn bản traceback.

`install_process_error_capture()` biến một ngoại lệ không được bắt thành một vấn đề ở mức `critical`, kèm loại ngoại lệ, các stack frame và cơ chế `python.excepthook`.

## Câu hỏi thường gặp

### Mức logging mặc định trong Python là gì?

WARNING. Khi không gọi `basicConfig()`, root logger in WARNING, ERROR và CRITICAL ra stderr dạng `WARNING:root:message`, và bỏ qua DEBUG và INFO.

### Vì sao logging.basicConfig không có tác dụng?

Root logger đã có handler, từ một lời gọi `basicConfig()` trước đó hoặc từ một thư viện, nên Python bỏ qua lời gọi này. Truyền `force=True` để thay thế các handler.

### logging.error và logging.exception khác nhau thế nào?

`log.exception()` là `log.error()` với `exc_info=True`. Nó ghi log ở mức ERROR và đính kèm traceback. Chỉ gọi nó bên trong khối `except`.

### Các mức logging của Python theo thứ tự là gì?

DEBUG 10, INFO 20, WARNING 30, ERROR 40, CRITICAL 50. Logger cho một bản ghi đi qua khi số của nó bằng hoặc cao hơn mức bạn đặt.

### Nên dùng print() hay logging trong Python?

Dùng `logging`. `print()` không có mức log, không có dấu thời gian, không có tên logger và không có handler. Với `logging`, bạn bật dòng log theo từng module và gửi chúng tới file hoặc tới LogBrew.

## Xem mọi ngoại lệ Python kèm traceback

LogBrew Python SDK gửi mỗi dòng log với mức log, logger, file và dòng, và biến một ngoại lệ không được bắt thành một vấn đề kèm stack trace. Bắt đầu với gói miễn phí rộng rãi, không cần thẻ.

[Bắt đầu miễn phí](https://logbrew.co/vi)

## Nguồn

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

## Thêm hướng dẫn cho agent và Python

- [Thêm máy chủ MCP vào Claude Code và Codex](https://logbrew.co/vi/guides/mcp-server-claude-code-codex)
- [Dùng AGENTS.md trong Claude Code và Codex](https://logbrew.co/vi/guides/agents-md)
- [Khắc phục lỗi Claude overloaded 529 và lỗi rate limit 429](https://logbrew.co/vi/guides/claude-overloaded-rate-limit-error)
- [Structured logging với định dạng log và mức log bạn tìm được theo trường](https://logbrew.co/vi/guides/structured-logging)
- [Cách sửa lỗi trong Claude Code, Codex, JavaScript và Python](https://logbrew.co/vi/guides)
