Skip to content

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)slogger 名称
%(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 pyyaml
python
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: 3306

safe_loadload 安全——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 安全;敏感信息放环境变量。