粉粉蕉的笔记本粉粉蕉的笔记本
  • JAVA

    • 代码笔记
    • Java8实战
    • 分布式事务实战(Seata)
    • 模板引擎(FreeMarker)
    • SpringSecurity
    • Maven
  • PYTHON

    • 概述
    • Python3 基础
    • Pandas
    • Numpy
    • Matplotlib
  • 中间件

    • Kafka
    • RocketMQ
    • Redis
    • MongoDB
    • Elastic Search
  • 数据库

    • Mysql
  • 前端

    • HTML
    • CSS
    • Javascript
    • Vue2学习笔记
    • Vue3学习笔记
    • React学习笔记
  • 设计模式
  • 大数据

    • 概览
    • Hadoop
    • Hive
  • 机器学习

    • 机器学习概览
  • openclaw实战
  • claudecode实战
  • RAG
  • 拟人类Agent
  • linux命令速查
  • windows命令速查
  • Docker笔记
  • kubernetes学习笔记
  • kubernetes实操笔记
  • 运维工具大全
  • git操作宝典
  • 概率论
  • 线性代数
  • 统计学
  • 金融知识学习
  • 聚宽
  • 因子分析
  • 后端

    • JAVA基础
    • JAVA多线程
    • JVM
    • 分布式相关
    • 数据库
  • 前端

    • HTML
    • CSS
    • JAVASCRIPT
    • VUE3
    • 网络
    • 前端工程化
    • nodejs
  • AI

    • RAG
  • 健身

    • 笔记
    • 训练计划
  • 读书笔记

    • 《深度学习》
  • 其他

    • RSS
    • 资源导航
    • 医保
    • 装修攻略
我也想搭建这样的博客!
🚋开往
  • JAVA

    • 代码笔记
    • Java8实战
    • 分布式事务实战(Seata)
    • 模板引擎(FreeMarker)
    • SpringSecurity
    • Maven
  • PYTHON

    • 概述
    • Python3 基础
    • Pandas
    • Numpy
    • Matplotlib
  • 中间件

    • Kafka
    • RocketMQ
    • Redis
    • MongoDB
    • Elastic Search
  • 数据库

    • Mysql
  • 前端

    • HTML
    • CSS
    • Javascript
    • Vue2学习笔记
    • Vue3学习笔记
    • React学习笔记
  • 设计模式
  • 大数据

    • 概览
    • Hadoop
    • Hive
  • 机器学习

    • 机器学习概览
  • openclaw实战
  • claudecode实战
  • RAG
  • 拟人类Agent
  • linux命令速查
  • windows命令速查
  • Docker笔记
  • kubernetes学习笔记
  • kubernetes实操笔记
  • 运维工具大全
  • git操作宝典
  • 概率论
  • 线性代数
  • 统计学
  • 金融知识学习
  • 聚宽
  • 因子分析
  • 后端

    • JAVA基础
    • JAVA多线程
    • JVM
    • 分布式相关
    • 数据库
  • 前端

    • HTML
    • CSS
    • JAVASCRIPT
    • VUE3
    • 网络
    • 前端工程化
    • nodejs
  • AI

    • RAG
  • 健身

    • 笔记
    • 训练计划
  • 读书笔记

    • 《深度学习》
  • 其他

    • RSS
    • 资源导航
    • 医保
    • 装修攻略
我也想搭建这样的博客!
🚋开往
  • Python

    • 概述
    • Python3 基础
    • logging 日志
    • FastAPI

logging 日志

Python 内置的 logging 模块是生产级日志的标准方案,相比 print 的优势:

  • 可设置日志级别,按环境过滤
  • 支持输出到文件、控制台、远程服务等多个目标
  • 自动记录时间、文件名、行号等上下文信息
  • 异步安全,多线程环境下不会产生日志混乱

日志级别

从低到高:

级别数值使用场景
DEBUG10开发调试,记录详细的执行流程
INFO20正常运行信息(服务启动、关键操作完成)
WARNING30警告,程序仍可运行但需要关注
ERROR40错误,某个功能失败
CRITICAL50严重错误,程序可能无法继续运行

设置某个级别后,只有 ≥ 该级别 的日志才会输出。例如设为 WARNING,则 DEBUG 和 INFO 的日志会被忽略。


快速开始

import logging

# 最简单用法(不推荐生产使用)
logging.basicConfig(level=logging.DEBUG)
logging.debug('调试信息')
logging.info('正常信息')
logging.warning('警告')
logging.error('错误')
logging.critical('严重错误')

推荐配置方式

方式一:代码配置(适合脚本、小项目)

import logging

def setup_logger(name: str = __name__, level: int = logging.INFO) -> logging.Logger:
    logger = logging.getLogger(name)
    logger.setLevel(level)

    # 避免重复添加 handler(多次调用时)
    if logger.handlers:
        return logger

    formatter = logging.Formatter(
        fmt='%(asctime)s | %(levelname)-8s | %(name)s:%(lineno)d | %(message)s',
        datefmt='%Y-%m-%d %H:%M:%S'
    )

    # 控制台输出
    console_handler = logging.StreamHandler()
    console_handler.setLevel(logging.DEBUG)
    console_handler.setFormatter(formatter)
    logger.addHandler(console_handler)

    # 文件输出(自动按大小滚动)
    from logging.handlers import RotatingFileHandler
    file_handler = RotatingFileHandler(
        filename='app.log',
        maxBytes=10 * 1024 * 1024,      # 10MB 后滚动
        backupCount=5,                  # 保留 5 个历史文件
        encoding='utf-8'
    )
    file_handler.setLevel(logging.INFO)
    file_handler.setFormatter(formatter)
    logger.addHandler(file_handler)

    return logger


# 使用
logger = setup_logger('myapp')
logger.info('服务启动')
logger.debug('调试:变量 x = %s', 42)

方式二:字典配置(推荐生产使用)

import logging
import logging.config

LOGGING_CONFIG = {
    'version': 1,
    'disable_existing_loggers': False,  # 不禁用第三方库的 logger
    'formatters': {
        'standard': {
            'format': '%(asctime)s | %(levelname)-8s | %(name)s:%(lineno)d | %(message)s',
            'datefmt': '%Y-%m-%d %H:%M:%S',
        },
        'simple': {
            'format': '[%(levelname)s] %(message)s'
        },
    },
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
            'level': 'DEBUG',
            'formatter': 'standard',
            'stream': 'ext://sys.stdout',
        },
        'file': {
            'class': 'logging.handlers.RotatingFileHandler',
            'level': 'INFO',
            'formatter': 'standard',
            'filename': 'logs/app.log',
            'maxBytes': 10485760,       # 10MB
            'backupCount': 5,
            'encoding': 'utf-8',
        },
        'error_file': {
            'class': 'logging.handlers.RotatingFileHandler',
            'level': 'ERROR',
            'formatter': 'standard',
            'filename': 'logs/error.log',
            'maxBytes': 10485760,
            'backupCount': 3,
            'encoding': 'utf-8',
        },
    },
    'loggers': {
        '': {                           # root logger
            'handlers': ['console', 'file', 'error_file'],
            'level': 'DEBUG',
            'propagate': False,
        },
        'uvicorn': {                    # 单独控制 uvicorn 日志级别
            'handlers': ['console'],
            'level': 'INFO',
            'propagate': False,
        },
    },
}

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

方式三:YAML 配置文件(适合大型项目)

# logging.yaml
version: 1
disable_existing_loggers: false

formatters:
  standard:
    format: "%(asctime)s | %(levelname)-8s | %(name)s:%(lineno)d | %(message)s"
    datefmt: "%Y-%m-%d %H:%M:%S"

handlers:
  console:
    class: logging.StreamHandler
    level: DEBUG
    formatter: standard
    stream: ext://sys.stdout
  file:
    class: logging.handlers.RotatingFileHandler
    level: INFO
    formatter: standard
    filename: logs/app.log
    maxBytes: 10485760
    backupCount: 5
    encoding: utf-8

root:
  level: DEBUG
  handlers: [console, file]
import logging
import logging.config
import yaml

with open('logging.yaml', 'r') as f:
    config = yaml.safe_load(f)
logging.config.dictConfig(config)

logger = logging.getLogger(__name__)

核心概念

Logger(记录器)
    ↓ 创建 LogRecord
Handler(处理器)      ← 决定"输出到哪里"
    ↓ 格式化
Formatter(格式化器)  ← 决定"输出什么格式"
    ↓
输出目标(控制台 / 文件 / 网络...)

Logger 层级与传播

# Logger 按名称形成父子层级,用 . 分隔
root_logger = logging.getLogger()           # 根 logger(名称为 '')
app_logger = logging.getLogger('myapp')     # myapp
db_logger = logging.getLogger('myapp.db')  # myapp.db(myapp 的子级)

# 默认情况下,子 logger 的日志会向上传播(propagate=True)
# myapp.db 的日志会同时被 myapp 和 root 处理
# 如果不想传播,设置:
db_logger.propagate = False

推荐做法:每个模块用 __name__ 作为 logger 名称:

# utils/db.py
import logging
logger = logging.getLogger(__name__)        # 名称为 'utils.db'

Formatter 格式符

格式符说明示例输出
%(asctime)s时间2025-03-11 14:30:00
%(levelname)s级别名INFO
%(name)sLogger 名称myapp.db
%(filename)s文件名db.py
%(lineno)d行号42
%(funcName)s函数名connect
%(message)s日志内容连接数据库成功
%(process)d进程 ID12345
%(thread)d线程 ID140234

常用 Handler

Handler说明
StreamHandler输出到控制台(stdout/stderr)
FileHandler输出到文件
RotatingFileHandler按文件大小滚动
TimedRotatingFileHandler按时间滚动(每天/每小时)
SysLogHandler输出到系统 Syslog
HTTPHandler发送 HTTP 请求到日志服务器
QueueHandler异步日志(配合 QueueListener)
from logging.handlers import TimedRotatingFileHandler

# 每天生成一个日志文件,保留 30 天
handler = TimedRotatingFileHandler(
    filename='logs/app.log',
    when='midnight',                    # 每天凌晨切换
    interval=1,
    backupCount=30,
    encoding='utf-8'
)

实用技巧

记录异常信息(含堆栈)

try:
    result = 1 / 0
except ZeroDivisionError:
    logger.exception('计算出错')        # 自动附加完整堆栈信息
    # 等价于:
    logger.error('计算出错', exc_info=True)

结构化日志(便于日志平台检索)

import json

class JsonFormatter(logging.Formatter):
    def format(self, record):
        log_data = {
            'timestamp': self.formatTime(record),
            'level': record.levelname,
            'logger': record.name,
            'message': record.getMessage(),
            'file': f'{record.filename}:{record.lineno}',
        }
        if record.exc_info:
            log_data['exception'] = self.formatException(record.exc_info)
        return json.dumps(log_data, ensure_ascii=False)

添加上下文信息(LoggerAdapter)

# 给每条日志附加 request_id、user_id 等上下文
logger = logging.getLogger(__name__)

def get_logger_with_context(request_id: str, user_id: str = None):
    extra = {'request_id': request_id, 'user_id': user_id or 'anonymous'}
    return logging.LoggerAdapter(logger, extra)

# 在 Formatter 中使用 %(request_id)s 即可输出

与 FastAPI 集成

# main.py
import logging
import logging.config
from fastapi import FastAPI, Request
import time

logging.config.dictConfig(LOGGING_CONFIG)
logger = logging.getLogger('myapp')

app = FastAPI()

@app.middleware('http')
async def log_requests(request: Request, call_next):
    start = time.time()
    logger.info(f'→ {request.method} {request.url.path}')
    response = await call_next(request)
    duration = time.time() - start
    logger.info(
        f'← {request.method} {request.url.path} '
        f'[{response.status_code}] {duration*1000:.1f}ms'
    )
    return response

最佳实践

实践说明
每个模块独立 loggerlogger = logging.getLogger(__name__)
用参数占位符而非字符串拼接logger.info('用户 %s 登录', username) 而非 f'用户 {username} 登录'(性能更好,级别过滤时不必要的格式化被跳过)
异常用 exception()自动包含完整堆栈,而不只是错误消息
生产环境输出到文件使用 RotatingFileHandler 防止日志文件无限增长
错误日志单独文件设一个只接收 ERROR 及以上的 handler,便于监控告警
不要用 print在模块代码中用 logger,只在脚本入口用 print
日志级别区分环境开发:DEBUG;生产:INFO 或 WARNING
Last Updated: 6/29/26, 8:24 AM
Contributors: dongyz8
Prev
Python3 基础
Next
FastAPI