Python命令如何使用logging模块记录执行日志 Python命令日志记录的操作方法

使用logging模块记录执行日志需先导入模块并调用logging.basicconfig()进行基础配置,包括设置日志级别、格式、输出文件和写入模式;2. 配置后通过logging.debug()、logging.info()、logging.error()等方法在代码中记录不同级别的日志信息;3. 可创建logger、handler和formatter对象实现更高级配置,如将日志同时输出到文件和控制台,并为不同模块使用logging.getlogger(__name__)创建独立logger;4. 在多进程环境中,应使用logging.handlers.queuehandler与logging.handlers.queuelistener结合队列机制,确保日志写入的线程安全与一致性,避免多进程同时写入导致的日志混乱。

Python命令如何使用logging模块记录执行日志?简单来说,就是利用logging模块,在你的Python脚本里插入一些记录信息的代码,这样程序运行的时候,就能把关键信息保存下来,方便你排查问题或者分析程序运行情况。

logging模块提供了灵活的配置,可以控制日志级别、输出格式和存储位置。下面详细说明操作方法。

解决方案

配置logging模块

首先,你需要导入logging模块,并进行基本配置。配置内容包括日志级别、日志格式、输出位置等。

import logging

# 配置日志级别,低于DEBUG级别的日志不会被记录
logging.basicConfig(level=logging.DEBUG,
                    # 日志格式,包括时间、级别、文件名、行号、消息
                    format='%(asctime)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s',
                    # 日志输出到文件,可以指定文件名
                    filename='my_program.log',
                    # 文件写入模式,'w'表示覆盖,'a'表示追加
                    filemode='a')

这段代码做了几件事:

  • logging.basicConfig()

    : 这是最基本的配置方法。

  • level=logging.DEBUG

    : 设置日志级别为DEBUG,意味着DEBUG、INFO、WARNING、ERROR、CRITICAL级别的日志都会被记录。你可以根据需要调整这个级别。

  • format='%(asctime)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s'

    : 定义日志信息的格式。

    %(asctime)s

    是时间,

    %(levelname)s

    是日志级别,

    %(filename)s

    是文件名,

    %(lineno)d

    是行号,

    %(message)s

    是日志消息。

  • filename='my_program.log'

    : 指定日志输出到文件

    my_program.log

    。如果不指定,默认输出到控制台。

  • filemode='a'

    : 设置文件写入模式为追加。每次运行程序,新的日志信息都会追加到文件末尾。如果设置为

    'w'

    ,每次运行都会覆盖之前的内容。

记录日志信息

配置好logging模块后,就可以在代码中插入日志记录语句了。

import logging

logging.basicConfig(level=logging.DEBUG,
                    format='%(asctime)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s',
                    filename='my_program.log',
                    filemode='a')

def my_function(x, y):
    logging.debug(f"Function my_function called with x={x}, y={y}")
    try:
        result = x / y
        logging.info(f"Result of x / y is {result}")
        return result
    except ZeroDivisionError:
        logging.error("Division by zero!")
        return None

if __name__ == '__main__':
    my_function(10, 2)
    my_function(5, 0)

这段代码演示了如何使用不同级别的日志记录:

  • logging.debug()

    : 记录调试信息,通常用于开发阶段。

  • logging.info()

    : 记录一般信息,用于程序正常运行时的信息。

  • logging.error()

    : 记录错误信息,用于程序出现错误时的信息。

当程序运行时,日志信息会被写入到

my_program.log

文件中。

更高级的配置:Logger、Handler和Formatter

logging.basicConfig()

提供了一些基本的配置,但logging模块的功能远不止于此。你可以使用Logger、Handler和Formatter进行更高级的配置。

  • Logger: 负责接收日志信息,并传递给Handler。
  • Handler: 负责将日志信息输出到不同的目标,比如文件、控制台、网络等。
  • Formatter: 负责格式化日志信息。

下面是一个更复杂的例子:

import logging

# 创建一个logger
logger = logging.getLogger('my_logger')
logger.setLevel(logging.DEBUG)

# 创建一个handler,用于输出到文件
file_handler = logging.FileHandler('my_program.log', mode='a')
file_handler.setLevel(logging.INFO)

# 创建一个handler,用于输出到控制台
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.DEBUG)

# 创建一个formatter
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

# 将formatter添加到handler
file_handler.setFormatter(formatter)
console_handler.setFormatter(formatter)

# 将handler添加到logger
logger.addHandler(file_handler)
logger.addHandler(console_handler)

def my_function(x, y):
    logger.debug(f"Function my_function called with x={x}, y={y}")
    try:
        result = x / y
        logger.info(f"Result of x / y is {result}")
        return result
    except ZeroDivisionError:
        logger.error("Division by zero!")
        return None

if __name__ == '__main__':
    my_function(10, 2)
    my_function(5, 0)

这个例子中,我们创建了一个名为

my_logger

的logger,并添加了两个handler:一个用于输出到文件,一个用于输出到控制台。 文件handler只记录INFO级别及以上的日志,而控制台handler记录DEBUG级别及以上的日志。 这样,你就可以根据需要,将不同级别的日志输出到不同的地方。

如何自定义日志格式?

你可以通过

logging.Formatter

来自定义日志格式。

Formatter

接受一个格式字符串作为参数,格式字符串中可以使用各种占位符来表示不同的日志信息。

常用的占位符包括:

  • %(asctime)s

    : 日志产生的时间

  • %(name)s

    : logger的名字

  • %(levelname)s

    : 日志级别

  • %(message)s

    : 日志消息

  • %(filename)s

    : 文件名

  • %(lineno)d

    : 行号

  • %(module)s

    : 模块名

  • %(funcName)s

    : 函数名

  • %(process)d

    : 进程ID

  • %(thread)d

    : 线程ID

例如,你可以使用以下格式字符串:

formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s')

这将生成包含时间、logger名字、日志级别、文件名、行号和消息的日志信息。

如何根据不同的模块使用不同的Logger?

在大型项目中,通常会将代码分成多个模块。 为了方便管理日志,可以为每个模块创建一个Logger。

# module1.py
import logging

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

# 创建一个handler,用于输出到文件
file_handler = logging.FileHandler('my_program.log', mode='a')
file_handler.setLevel(logging.INFO)

# 创建一个formatter
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

# 将formatter添加到handler
file_handler.setFormatter(formatter)

# 将handler添加到logger
logger.addHandler(file_handler)

def my_function():
    logger.debug("my_function in module1 called")

# module2.py
import logging
from module1 import my_function

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

# 创建一个handler,用于输出到文件
file_handler = logging.FileHandler('my_program.log', mode='a')
file_handler.setLevel(logging.INFO)

# 创建一个formatter
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

# 将formatter添加到handler
file_handler.setFormatter(formatter)

# 将handler添加到logger
logger.addHandler(file_handler)

def another_function():
    logger.debug("another_function in module2 called")
    my_function()

if __name__ == '__main__':
    another_function()

在这个例子中,

module1.py

module2.py

都创建了自己的Logger,logger的名字分别是

module1

module2

。 这样,在日志信息中就可以区分来自不同模块的日志。 使用

__name__

作为Logger的名字是一个常用的技巧,因为

__name__

会自动设置为模块的名字。

如何在多线程或多进程中使用logging模块?

在多线程或多进程环境中,需要注意logging模块的线程安全问题。 logging模块本身是线程安全的,但如果多个线程或进程同时写入同一个文件,可能会导致日志信息混乱。

为了避免这个问题,可以使用以下方法:

  • 使用

    logging.handlers.RotatingFileHandler

    logging.handlers.TimedRotatingFileHandler

    : 这两种Handler可以自动分割日志文件,避免单个文件过大,也可以避免多个线程或进程同时写入同一个文件。

  • 使用

    logging.handlers.QueueHandler

    logging.handlers.QueueListener

    : 这种方法将日志信息发送到一个队列中,然后由一个单独的线程或进程从队列中读取日志信息并写入文件。 这样可以避免多个线程或进程同时写入同一个文件。

这里给出一个使用

logging.handlers.QueueHandler

logging.handlers.QueueListener

的例子:

import logging
import logging.handlers
import multiprocessing
import queue
import time

def worker_process(queue):
    # 配置worker进程的logger
    logger = logging.getLogger(__name__)
    logger.setLevel(logging.DEBUG)
    handler = logging.handlers.QueueHandler(queue)  # Use QueueHandler
    logger.addHandler(handler)

    # 记录一些日志
    logger.info('Worker process started')
    logger.debug('Debugging message from worker')
    logger.warning('Warning message from worker')
    logger.error('Error message from worker')
    logger.info('Worker process finished')

def listener_process(queue):
    # 配置listener进程的logger
    logger = logging.getLogger(__name__)
    logger.setLevel(logging.DEBUG)

    # 创建一个FileHandler来写入日志文件
    file_handler = logging.FileHandler('multiprocessing_example.log', mode='a')
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    file_handler.setFormatter(formatter)

    # 使用QueueListener来监听队列并将日志记录到handler
    listener = logging.handlers.QueueListener(queue, file_handler)
    listener.start()
    listener.join()

if __name__ == '__main__':
    # 创建一个队列
    log_queue = queue.Queue(-1)

    # 创建并启动listener进程
    listener = multiprocessing.Process(target=listener_process, args=(log_queue,))
    listener.start()

    # 创建并启动多个worker进程
    processes = []
    for i in range(3):
        process = multiprocessing.Process(target=worker_process, args=(log_queue,))
        processes.append(process)
        process.start()

    # 等待所有worker进程完成
    for process in processes:
        process.join()

    # 发送一个None到队列中,表示listener可以停止
    log_queue.put(None)
    listener.join()

    print("Finished!")

这个例子中,我们创建了一个listener进程和一个或多个worker进程。 worker进程将日志信息发送到一个队列中,listener进程从队列中读取日志信息并写入文件。 这样可以避免多个进程同时写入同一个文件,保证日志信息的完整性和一致性。 注意,需要在listener进程中调用

listener.start()

listener.join()

,以启动和等待listener线程。 还需要在所有worker进程完成后,向队列中发送一个

None

,以通知listener进程停止。

总而言之,Python的logging模块是一个非常强大和灵活的工具,可以帮助你记录程序的运行信息,方便你排查问题和分析程序运行情况。 你可以根据自己的需要,选择合适的配置方式和日志级别,以及使用不同的Handler和Formatter,来实现各种各样的日志记录需求。

以上就是Python命令如何使用logging模块记录执行日志 Python命令日志记录的操作方法的详细内容,更多请关注骃骐网【www.myinqi.com】。

相关推荐:

怎样用Python处理日志文件的滚动更新_使用logging.handlers

RotatingFileHandler 日志不按大小切分是因为仅在写入新日志且当前文件超 maxBytes 时触发滚动,非定时检查;需确保有日志输出、maxBytes 不宜过小(建议≥1024)、多进程须用 QueueHandler。 RotatingFileHandler 为什么日志不按大小切分 常见现象是配置了 maxBytes 和 backupCount,但日志始终只写入一个文件,从不生成 ...

如何清理Python项目中产生的__pycache__冗余文件_使用find命令批量删除

精准定位所有__pycache__目录应使用find . -type d -name '__pycache__',其中-type d限定为目录类型,-name精确匹配大小写敏感的固定名称,引号防止shell展开,避免误用-iname或通配符。 find 命令怎么精准定位所有 __pycache__ 目录 默认情况下,find 会递归遍历整个目录树,但容易误删或漏删——关键在指定类型和路径模式。__...

Python证书链验证失败的根源与正确OpenSSL命令解析

本文详解python cryptography.x509 构建多级证书链(根→中间→终端)时,openssl验证报错 unable to get issuer certificate 的真实原因——并非代码缺陷,而是证书链加载方式错误;重点阐明 -untrusted 参数的关键作用及完整验证流程。 本文详解python cryptography.x509 构建多级证书链(根→中间→终端)时,ope...

如何在Python中实现可撤销的数据操作队列_通过双栈模拟或命令模式

双栈结构更适合轻量级撤销队列,因其内存和逻辑更直接:仅存状态快照或增量变更,避免命令模式的类抽象与生命周期开销;对list/dict/数值等原子操作,浅拷贝+双栈即可覆盖90%场景,且undo/redo为O(1)。 为什么双栈结构比命令模式更适合轻量级撤销队列 双栈(undo_stack 和 redo_stack)在内存和逻辑上更直接:每次操作只存状态快照或简单变更描述,不需为每类操作定义新类。命...

如何在 Python Tkinter 循环中实现命令间的精确暂停

Tkinter 中不能直接用 time.sleep() 实现界面响应式延时,需改用 root.after() 方法在事件循环中调度任务,才能让窗口逐个延迟创建而不阻塞 GUI。 tkinter 中不能直接用 `time.sleep()` 实现界面响应式延时,需改用 `root.after()` 方法在事件循环中调度任务,才能让窗口逐个延迟创建而不阻塞 gui。 在 Tkinter 应用中,使用 t...

Python开发Flask应用如何记录日志_配置logging模块实现分级输出

Flask默认不记录日志到文件,需手动配置logging:添加FileHandler(推荐RotatingFileHandler)和StreamHandler,统一设level为INFO,并禁用gunicorn冲突输出;模块日志应按功能命名如'app.models'以精准定位。 Flask默认不记录日志到文件,必须手动配置logging模块 Flask开发时,app.logger默认只输出到std...

Windows 上 py 命令未指向最新 Python 版本的解决方法

Windows 的 py 启动器默认应调用系统中最新安装的 Python,但若 py --version 与 python3 --version 显示不同版本,说明启动器的默认配置未同步——可通过 py -0p 查看已注册版本,并用 py -3.12 --default 手动设为最新版。 windows 的 `py` 启动器默认应调用系统中最新安装的 python,但若 `py --version...

Windows 系统中 py 命令默认未指向最新 Python 版本的解决方案

Windows 的 py 启动器默认使用注册表中设定的“默认 Python 版本”,而非自动选择系统中最新安装的版本;可通过 py -0p 查看已注册版本,并用 py -3.12 --default 显式设置最新版为默认。 windows 的 `py` 启动器默认使用注册表中设定的“默认 python 版本”,而非自动选择系统中最新安装的版本;可通过 `py -0p` 查看已注册版本,并用 `py...

Windows 系统中 py 命令未指向最新 Python 版本的解决方法

Windows 的 py 启动器默认应调用系统最新 Python,但实际可能因注册表配置滞后而指向旧版本;可通过 py -0p 查看已注册版本,并用 py -3.12 --default 显式设置默认版本。 windows 系统中 `py` 启动器默认应调用系统最新 python,但实际可能因注册表配置滞后而指向旧版本;可通过 `py -0p` 查看已注册版本,并用 `py -3.12 --def...