Appearance
37|日志与配置
程序运行时需要记录发生了什么——成功、失败、异常、状态变化。日志是排查问题的第一手材料。配置则把会变动的值(文件路径、超时时间、目标地址)从代码中分离出来,让脚本在不同环境下复用。
一、logging 模块
print() 适合一次性脚本。稍正式的程序用 logging,能区分级别、带时间戳、还能写文件。
python
import logging
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s %(levelname)s %(message)s",
)
logging.debug("调试信息")
logging.info("程序启动")
logging.warning("磁盘空间不足")
logging.error("连接失败")
logging.critical("系统崩溃")日志级别(从低到高):
| 级别 | 用途 |
|---|---|
| DEBUG | 详细调试信息 |
| INFO | 正常流程信息 |
| WARNING | 需要注意但不致命的问题 |
| ERROR | 错误,功能受影响 |
| CRITICAL | 严重错误,程序可能终止 |
level=logging.INFO 表示只输出 INFO 及以上级别的日志。DEBUG 信息会被过滤掉。
二、写日志到文件
python
import logging
from pathlib import Path
logging.basicConfig(
filename=Path("/var/log/myapp.log"),
level=logging.INFO,
format="%(asctime)s %(levelname)s %(message)s",
)同时输出到控制台和文件:
python
import logging
logger = logging.getLogger("myapp")
logger.setLevel(logging.DEBUG)
# 文件处理器
file_handler = logging.FileHandler("app.log")
file_handler.setLevel(logging.INFO)
# 控制台处理器
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.DEBUG)
# 格式
formatter = logging.Formatter("%(asctime)s %(levelname)s %(message)s")
file_handler.setFormatter(formatter)
console_handler.setFormatter(formatter)
logger.addHandler(file_handler)
logger.addHandler(console_handler)
logger.info("这条信息同时输出到文件和控制台")三、日志格式
常用格式字段:
| 字段 | 含义 |
|---|---|
%(asctime)s | 时间戳 |
%(levelname)s | 日志级别 |
%(message)s | 日志内容 |
%(name)s | logger 名称 |
%(filename)s | 文件名 |
%(lineno)d | 行号 |
%(funcName)s | 函数名 |
四、日志内容规范
日志要写清楚对象和结果,不要只写"出错了":
python
# 含糊
logging.error("check failed")
# 清楚:谁、做了什么、结果
logging.info("check_service host=%s port=%d status=%s", "web01", 80, "ok")logging 用 %s 占位符而不是 f-string——当日志级别被过滤时(如设成 WARNING,INFO 不输出),占位符不会被格式化,省开销。
五、INI 配置
简单的键值配置用 configparser:
python
import configparser
from pathlib import Path
config = configparser.ConfigParser()
config.read(Path("config.ini"), encoding="utf-8")
api_url = config["api"]["url"]
timeout = config.getint("api", "timeout") # 自动转整数config.ini:
ini
[api]
url = https://example.com/api
timeout = 5
[database]
host = 127.0.0.1
port = 3306六、YAML 配置
YAML 支持嵌套和列表,比 INI 灵活:
bash
pip install pyyamlpython
from pathlib import Path
import yaml
config = yaml.safe_load(Path("config.yaml").read_text(encoding="utf-8"))
print(config["api"]["url"])config.yaml:
yaml
api:
url: https://example.com/api
timeout: 5
database:
host: 127.0.0.1
port: 3306safe_load 比 load 安全——load 能反序列化任意 Python 对象,读到恶意 YAML 会执行代码,safe_load 只解析基础数据类型。
七、JSON 配置
python
import json
from pathlib import Path
config = json.loads(Path("config.json").read_text(encoding="utf-8"))JSON 没有注释,不适合需要注释说明的配置文件。INI 和 YAML 支持注释。
八、配置选择
| 格式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| INI | 简单、有注释、标准库支持 | 不支持嵌套 | 简单键值配置 |
| YAML | 支持嵌套、有注释、可读性好 | 需要第三方库 | 复杂配置 |
| JSON | 标准格式、解析器 ubiquitous | 无注释、不支持多行字符串 | 程序间交换配置 |
| 环境变量 | 容器友好、不落地 | 只支持字符串 | 敏感信息、容器部署 |
记忆锚点:logging.basicConfig() 快速配置日志;日志级别 DEBUG < INFO < WARNING < ERROR < CRITICAL;用 %s 占位符而不是 f-string;文件+控制台同时输出用多个 Handler;INI 用 configparser,YAML 用 pyyaml,JSON 用标准库;yaml.safe_load() 比 load 安全;敏感信息放环境变量。