基础用法

import logging

# 设置日志等级和输出格式
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s [%(levelname)s] %(message)s'
)

logging.debug("调试信息")
logging.info("普通信息")
logging.warning("警告")
logging.error("错误")
logging.critical("严重错误")

核心组成(五大组件)

Logger(日志记录器)     ← 你在代码中调用的接口
Handler(日志处理器)    ← 决定日志输出到哪里(终端、文件等)
Formatter(格式器)      ← 决定日志内容怎么显示
Filter(过滤器)         ← 控制哪些日志可以通过

再配上一个统一配置模块(Config),构成完整的日志系统

日志等级

级别 方法 说明
DEBUG logger.debug() 调试信息,最详细
INFO logger.info() 一般信息,如启动日志、请求成功等
WARNING logger.warning() 警告,但不影响程序执行
ERROR logger.error() 错误,程序功能部分失效
CRITICAL logger.critical() 严重错误,系统可能无法继续运行

Handler 处理者

Handler 是 Python logging 模块的核心组成部分之一,用来决定日志记录的输出位置和输出方式

一个 Logger 可以绑定多个 Handler。每个 Handler 可单独设置输出等级、格式器、过滤器

内置 Handler

类名 输出位置 特点
StreamHandler 控制台(stdout/stderr) 最常用,调试阶段
FileHandler 文件 简单直接,但不自动轮转
RotatingFileHandler 文件 按文件大小轮转(老文件保留)
TimedRotatingFileHandler 文件 按时间(天/小时)轮转
NullHandler 不输出任何东西 避免“无 handler 警告”
SocketHandler TCP socket 发给远程日志服务器
DatagramHandler UDP socket 轻量网络日志
HTTPHandler POST 到 HTTP 可配合日志收集服务
QueueHandler 多进程安全 推送到日志队列(用于 async/log listener)
SMTPHandler 发送邮件 通常用于严重错误报警
MemoryHandler 内存缓冲 达到阈值后 flush 到目标 Handler
WatchedFileHandler 文件 支持 logrotate 自动重载(Linux)

写入文件(简单)

file = logging.FileHandler("app.log", encoding="utf-8")
file.setLevel(logging.INFO)

文件轮转(按大小)

from logging.handlers import RotatingFileHandler

rotating = RotatingFileHandler(
    filename="app.log",
    maxBytes=5*1024*1024,  # 每个文件最大5MB
    backupCount=3,         # 最多保留3个旧日志
    encoding="utf-8"
)
rotating.setLevel(logging.INFO)

文件轮转(按时间)

from logging.handlers import TimedRotatingFileHandler

timed = TimedRotatingFileHandler(
    filename="app.log",
    when="midnight",       # 每天0点切分
    backupCount=7,         # 保留7天日志
    encoding="utf-8"
)
timed.setLevel(logging.INFO)

多进程日志:推荐使用 QueueHandler

from logging.handlers import QueueHandler, QueueListener
from multiprocessing import Queue

log_queue = Queue()
queue_handler = QueueHandler(log_queue)

listener = QueueListener(log_queue, timed)
listener.start()

logger.addHandler(queue_handler)

Handler 关键属性

属性 说明
.setLevel() 设置最低处理日志等级(如 INFO
.setFormatter() 绑定一个格式器(Formatter)
.addFilter() 可绑定一个或多个 Filter
.flush() / .close() 写入并关闭流(必要时)

使用多个 Handler 的例子(日志分级)

logger = logging.getLogger("myapp")

# 控制台显示所有日志
console = logging.StreamHandler()
console.setLevel(logging.DEBUG)

# 文件仅记录错误
file = logging.FileHandler("error.log")
file.setLevel(logging.ERROR)

logger.addHandler(console)
logger.addHandler(file)
logger.setLevel(logging.DEBUG)

Formatter 格式化器

Formatter 是 Python logging 模块中负责把日志记录格式化为字符串的组件

创建 Formatter 的方式

from logging import Formatter

formatter = Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

然后把它绑定到 Handler 上:

handler.setFormatter(formatter)

常用格式化占位符一览

占位符 含义 示例
%(asctime)s 日志时间戳 2025-07-14 10:30:10
%(levelname)s 日志等级 INFO、DEBUG
%(levelno)s 日志等级数字 20、40
%(name)s logger 名称 app.main
%(filename)s 当前文件名 main.py
%(module)s 模块名(无扩展) main
%(funcName)s 函数名 login_user
%(lineno)d 行号 42
%(message)s 用户日志内容 登录成功
%(process)d 进程 ID 13324
%(thread)d 线程 ID 140737
%(threadName)s 线程名 Thread-1
%(pathname)s 全路径 /project/app.py

时间格式自定义:datefmt

Formatter('%(asctime)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S')

默认格式:2025-07-14 10:30:10,423

你可以自定义为:

Formatter('%(asctime)s', datefmt='%Y/%m/%d %H:%M:%S')
# 输出: 2025/07/14 10:30:10

完整 Formatter 示例

formatter = logging.Formatter(
    fmt="%(asctime)s [%(levelname)s] %(name)s.%(funcName)s:%(lineno)d - %(message)s",
    datefmt="%Y-%m-%d %H:%M:%S"
)

输出示例:

2025-07-14 10:30:10 [INFO] app.user.login_user:42 - 用户登录成功

高级 Formatter:添加自定义字段

如果你希望在日志中输出 trace_id,你可以通过 Filter 注入:

# 自定义 filter 注入字段
class TraceIdFilter(logging.Filter):
    def filter(self, record):
        record.trace_id = "abc123xyz"
        return True

Formatter 可以直接用:

'%(asctime)s [%(trace_id)s] %(message)s'

自定义Formatter子类

你也可以继承 logging.Formatter,覆盖 format(self, record) 方法,做完全自定义格式控制:

class MyFormatter(logging.Formatter):
    def format(self, record):
        record.msg = f"[MyPrefix] {record.msg}"
        return super().format(record)

或:

import json

class JsonFormatter(logging.Formatter):
    def format(self, record):
        log = {
            "time": self.formatTime(record),
            "level": record.levelname,
            "msg": record.getMessage(),
            "trace_id": getattr(record, "trace_id", "-")
        }
        return json.dumps(log, ensure_ascii=False)

多个 Handler 用不同 Formatter

console_handler.setFormatter(color_formatter)
file_handler.setFormatter(json_formatter)

使用配置文件

可以使用 logging.config 加载 .ini.json.dict 格式的配置

dictConfig 示例:

import logging.config

LOGGING_CONFIG = {
    "version": 1,
    "formatters": {
        "default": {
            "format": "%(asctime)s [%(levelname)s] %(name)s: %(message)s"
        }
    },
    "handlers": {
        "console": {
            "class": "logging.StreamHandler",
            "formatter": "default",
            "level": "DEBUG"
        },
        "file": {
            "class": "logging.FileHandler",
            "formatter": "default",
            "filename": "logfile.log",
            "level": "INFO"
        }
    },
    "root": {
        "handlers": ["console", "file"],
        "level": "DEBUG"
    }
}

logging.config.dictConfig(LOGGING_CONFIG)
logger = logging.getLogger(__name__)

日志模块最佳实践

场景/项目需求 推荐配置
小项目调试 basicConfig() 即可
中大型项目 自定义 Logger + Handler + Formatter
多模块项目 每个模块单独用 __name__ 创建 logger
日志持久化 FileHandlerRotatingFileHandler
日志等级分级存储 多个 Handler 分别设置不同级别
日志格式统一 使用配置文件统一控制格式
想导入外部日志配置文件(YAML) yaml + dictConfig