快速入门

快速入门
日志指南
日志进阶

getLogger

1、通过执行 logger = getLogger(“名称”) 创建一个该名称的日志记录器然后调用日志记录器的 debug(), info(), warning(), error() 和 critical() 方法来使用日志记录功能。
2、 logger = getLogger(“”) 或 logger = getLogger() 创建的是root日志记录器。
root logger 默认:level = WARNING,handlers = []
但 logging 模块有个 lastResort 兜底 handler,所以没配置控制台也能在控制台看到 WARNING 及以上的输出。
3、

import logging
logging.info()
logging.debug()
# 等价于
logging.getLogger().info("hello")   # 注意:这里用的是“root logger”
# 或
logging.getLogger("").info("hello")
也就是说:

logging.info() / logging.debug() / logging.error() 这些函数
本质上就是 调用 root logger 的对应方法。

logging.basicConfig

# 只配置了控制台(准确说是标准错误流 stderr),默认写到了stderr通道
logging.basicConfig(level=logging.INFO)
# 只配置了文件
logging.basicConfig(
    level=logging.DEBUG,
    format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
    datefmt="%Y-%m-%d %H:%M:%S"
)

basicConfig 是在给 整个 logging 系统的“老大”——root 日志记录器 做初始化配置的,同时顺带创建一个默认的 Handler。

你这段代码等价于在说:

“把 root logger 的等级设成 DEBUG,并且给它加一个写文件的 handler,日志都按这个格式写到 app.log 里。”
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

stderr stdout stdin

不管是 shell 还是 Python,stdin / stdout / stderr 都是 3 条“管道”(标准流)。
具体往哪条管道走,不是看内容是对还是错,而是看程序怎么写的。
谁写到 stdout / stderr,不是看“内容像不像错误”,而是看它到底往哪个文件描述符写:1(stdout)还是 2(stderr)。
在 shell / Linux 里,每个进程有三个默认“文件描述符”:

0 👉 stdin(标准输入)

1 👉 stdout(标准输出)

2 👉 stderr(标准错误)
重定向的时候:

或 1> 是 重定向 stdout

2> 是 重定向 stderr
stdin/stdout/stderr 是 3 条独立的通道;
✅ 到底走哪条,是程序写输出时选了哪个流;
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

不管是 Python 还是 shell,本质都是“进程有 0/1/2 三个流”,默认情况下:stdin 从终端读,stdout、stderr 都指向终端 → 你都能在屏幕上看到

在这里插入图片描述
✅ 默认情况下:控制台“接”着 stdout 和 stderr,所以你都能看到
❌ 但 stdout/stderr 仍然是两个不同的通道,只是默认连到了同一个“屏幕设备”上而已。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
不管是 Python 还是 shell,本质都是“进程有 0/1/2 三个流”

默认情况下:

stdin 从终端读

stdout、stderr 都指向终端 → 你都能在屏幕上看到
在这里插入图片描述

怎么从流里读出来

程序自己怎么从流里读?(读 stdin)

别的东西怎么拿到这个程序写到 stdout / stderr 里的内容?(重定向、管道、捕获)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
写到流里 = 写到一条“水管”里;
谁能拿出来,看谁在 另一头接这条管子:

程序自己:从 stdin 读

Shell:用 >、2>、| 把 stdout / stderr 接走

其他程序:用诸如 subprocess 之类的 API 捕获输出

配置文件和控制台

在这里插入图片描述
在这里插入图片描述

日志冒泡 propagation

日志从子 logger 一路往父 logger 传,最后传到 root 的过程,就像气泡往上浮一样。Python logging 里官方叫 propagation。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在同一个 Python 进程里,logging.getLogger(“名称”) 是“按名字全局唯一的单例”。进程间不共享

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

防止 handler 重复添加

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

函数属于它定义的模块,不属于调用它的文件

函数回家找“自己文件里的全局变量”,不会跨文件去你调用它的地方要东西。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

不只是 log,函数体里用到的所有“全局变量”都是先回自己定义所在的模块去找的,而不是去调用它的那个文件里找。

在这里插入图片描述

只打印自己python文件的日志,可以多个进程

# logger_utils.py
import logging
from logging.handlers import TimedRotatingFileHandler
from pathlib import Path
from typing import Optional

APP_LOGGER_NAME = "ai_build"  # 你项目的总 logger 名字,随便起一个


def setup_app_logger(log_file: Optional[str] = None, level: int = logging.INFO):
    """
    配置业务日志记录器,只打印自己项目相关的日志。
    """
    logger = logging.getLogger(APP_LOGGER_NAME)
    logger.setLevel(level)
    logger.propagate = False  # 关键:不要往 root 传了

    # 避免重复添加处理器
    if logger.handlers:
        return

    formatter = logging.Formatter(
        "%(asctime)s - %(name)s - [%(levelname)s] "
        "[%(threadName)s] %(filename)s:%(lineno)d — %(message)s"
    )

    # 控制台处理器
    console_handler = logging.StreamHandler()
    console_handler.setFormatter(formatter)
    logger.addHandler(console_handler)

    # 文件处理器(如果指定了文件)
    if log_file:
        Path(log_file).parent.mkdir(parents=True, exist_ok=True)
        file_handler = TimedRotatingFileHandler(
            log_file,
            when="midnight",
            interval=1,
            backupCount=7,
            encoding="utf-8",
        )
        file_handler.setFormatter(formatter)
        logger.addHandler(file_handler)


def get_logger(name: str) -> logging.Logger:
    """
    业务代码里用这个拿 logger,
    日志名会是: ai_build.xxx
    """
    return logging.getLogger(f"{APP_LOGGER_NAME}.{name}")

"""
然后入口脚本设置自己的日志文件。这样从入口调到的所有python文件都写到了该日志文件中,因为非如入口文件是get_logger(__name__),返回logging.getLogger(f"{APP_LOGGER_NAME}.{name}"),然后也没配置自己的handle,所有冒泡到父亲APP_LOGGER_NAME
"""
from logger_utils import setup_app_logger, get_logger

setup_app_logger("logs/ci.log")
log = get_logger(__name__)

log.info("只会打印自己项目的日志")

另一个进程的脚本里就换下日志文件就好
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐