当前位置:

首页 > 编程开发 > 使用Python内置logging来记录日志

使用Python内置logging来记录日志

logging的主要作用提供日志记录的接口和众多处理模块,供用户存储各种格式的日志,帮助调试程序或者记录程序运行过程中的输出信息。logging日志等级logging日志等级分为五个等级,优先级从高到低依次是:**CRITICAL;**程序严重错误**ERROR;**程序错误/部分功能错误**WARNING;**程序有发生错误的可能**INFO;**程序正常运行时的信息DEBUG程序调试信息默认的日志的记录等级为WARNING,即当日志的等级大于获等于WARNING时才会被记录。一般常用的记录等级为INF

本文目录

    logging 的主要作用

    提供日志记录的接口和众多处理模块,供用户存储各种格式的日志,帮助调试程序或者记录程序运行过程中的输出信息。

    logging 日志等级

    logging 日志等级分为五个等级,优先级从高到低依次是 :

    **CRITICAL; ** 程序严重错误

    **ERROR; **程序错误/部分功能错误

    **WARNING; **程序有发生错误的可能

    **INFO; **程序正常运行时的信息

    DEBUG程序调试信息

    默认的日志的记录等级为 WARNING, 即当日志的等级大于获等于 WARNING 时才会被记录。

    一般常用的记录等级为 INFO,其用于记录程序的正常运行的一些信息(类似于print)。

    当日志的等级达到 WARNING 以上时,表明此时程序不能正常运行;

    logging 的基础函数

    logging.basicConfig(**kwargs)

    在没有显式的进行创建记录器(logger)时,会默认创建一个root logger,而logging.basicConfig(**kwargs) 可以创建带有默认的Formatter的streamHandle并将其添加到根日志记录器中来初始化基本配置。

    比如

    import logging
    logging.debug('Debug code!')
    logging.info('Run code!')
    logging.warning('Watch out!')  
    logging.error('This is an error')
    logging.critical('This is a ciritical')

    上面代码中 logging 并没有显式的创建logger( logging.getLogger ), 其在直接使用debug(), info(), warning(), error(), critical() 时会使用默认的 root logger,并会自动调用 自定义的或者默认的logging.basicConfig(**kwargs) 初始化 root logger。

    自定义的 logging.basicConfig(**kwargs) 中的参数 有以下的主要的选项:

    参数功能
    filename指定保存日志的文件名,用指定文件名创建一个FileHandler,记录的日志会保存到该文件中
    format指定输出的格式和内容,默认是以冒号分割的levalname、name 和 message
    datefmt使用指定的日期/时间格式,与 time.strftime() 所接受的格式相同。
    level指定根日志记录器级别,默认为 logging.WARNING
    stream指定日志的输出流,可以指定输出到sys.stderr,std.stdout 或 文件,默认输出到sys.stderr。使用指定的流初始化StramHandler,注意:stream和filename参数不兼容,如果两者同时使用,则会引发ValueError 错误

    例如下面通过自定义 logging.basicConfig(**kwargs) 来初始化 root logger 来获得DEBUG级别及以上的日志记录并保存到 log.txt 文件中。

    import logging
    logging.basicConfig(filename='./log.txt',
                            format='%(asctime)s-%(name)s-%(levelname)s-%(message)s-%(funcName)s:%(lineno)d',
                            level=logging.DEBUG)
    logging.debug('Debug code!')
    logging.info('Run code!')
    logging.warning('Watch out!')  
    logging.error('This is an error')
    logging.critical('This is a ciritical')

    logging 的四大组件(类)

    Logger

    除了根记录器(root logger)外,最主要的是可以自己创建日志记录器。

    通过模块级别的函数 logging.getLogger(name) 实例化记录器

    默认情况下,记录器采用层级结构,通过 . 来区分不同的层级。比如 有个名叫 foo 的记录器 则 foo.a 和 foo.b 都是 foo 的子级记录器。当然,最开始的或者说最上层的记录器就是 root logger。如果 name=None,构建的是root logger。

    可以直接用当前模块的名称当作记录器的名字 logging.getLogger(__name__)

    子级记录器通常不需要单独设置日志级别以及 Handler,如果子级记录器没有单独设置,则它的行为会委托给父级。比如说,记录器foo的级别为INFO,而foo.a 和 foo.b 都不设置日志级别。此时foo.a 和 foo.b 会遵循foo 的级别设置,即只记录大于等于INFO级别的日志;而如果foo也没设置的话,就会找到根记录器root logger,root默认的级别为WARGING。

    logger类的一些常用的方法

    方法功能描述
    Logger.setLevel()设置日志器(Logger)将会处理的日志消息级别
    Logger.addHandler()添加一个handler对象
    Logger.removeHandler()移除一个handler对象
    Logger.addFilter()添加一个filter对象
    Logger.removeFilter()移除一个filter对象
    Logger.debug()设置DEBUG级别的日志记录
    Logger.info()设置INFO级别的日志记录
    Logger.warning()设置WARNING级别的日志记录
    Logger.error()设置ERROR级别的日志记录
    Logger.critical()设置CRITICAL级别的日志记录
    Logger.exception()输出堆栈追踪信息
    Logger.log()设置一个自定义的level参数来创建一个日志记录

    logger 结合 后面要介绍的其他的三个组件可以实现以下的功能:

    • Logger需要通过handler将日志信息输出到目标位置,目标位置可以是sys.stdout和文件等(这与logging.basicConfig(**kwargs) 设置中不太一致)。

    • 一个Logger可以设置不同的Handler,而不同的Handler可以将日志输出到不同的位置(不同的日志文件),并且每个Handler都可以设置自己的filter从而实现日志过滤,保留实际项目中需要的日志。同时每个Handler也可以设置不同的Formatter,在每个Formatter实现同一条日志以不同的格式输出到不同的地方。

    Handle

    处理器;其可以控制记录的日志输出到什么地方(标准输出/文件/...),同时处理器也可以添加 过滤器(filter)和格式控制器(formatter)来控制输出的内容和输出的格式。

    其具有几种常见的处理器:

    • logging.StreamHandler 标准流处理器,将消息发送到标准输出流、错误流 --> logging.StreamHandler(sys.stdout) # sys.stdout 表示的是指向控制台即标准输出;当我们在 Python 中打印对象调用 print obj 时候,事实上是调用了 sys.stdout.write(obj+'\n')。

    • print 将你需要的内容打印到了控制台,然后追加了一个换行符

    • logging.FileHandler 文件处理器,将消息发送到文件 --> logging.FileHandler(log_path)

    • logging.RotatingFileHandler 文件处理器,文件达到指定大小后,启用新文件存储日志

    • logging.TimedRotatingFileHandler 文件处理器,日志以特定的时间间隔轮换日志文件

    handle 类的一些常用的方法

    Handler.setLevel()设置处理器将会处理的日志消息的最低严重级别
    Handler.setFormatter()为处理器设置一个格式对象
    Handler.addFilter()为处理器添加一个过滤器对象
    Handler.removeFilter()为处理器删除一个过滤器对象
    logging.StramHandler()将日志消息发送到输出Stream,如std.out,std.err
    logging.FilterHandler()将日志消息发送到磁盘文件,默认情况文件大小会无线增长
    RotationFileHandler()将日志消息发送到磁盘文件,支持日志文件按大小切割
    TimeRotatingFileHandler()将日志消息发送到磁盘文件,并支持日志文件按时间切割
    logging.handers.HTTPHandler()将日志消息通过GET或POST的方式发送给一个HTTP服务器
    logging.handlers.SMTPHandler()将日志消息发送email地址

    Filter

    filter组件用来过滤 logger 对象,一个 filter 可以直接添加到 logger对象上,也可以添加到 handler 对象上,而如果在logger和handler中都设置了filter,则日志是先通过logger的filter,再通过handler的filter。由于所有的信息都可以经过filter,所以filter不仅可以过滤信息,还可以增加信息。

    Filter 类的实例化对象可以通过 logging.Filter(name) 来创建,其中name 为 记录器的名字,如果没有创建过该名字的记录器,就不会输出任何日志:

    filter = logging.Filter("foo.a")

    基本过滤器类只允许低于指定的日志记录器层级结构中低于特定层级的事件,例如 这个用 foo.a 初始化的过滤器,则foo.a.b;foo.a.c 等日志记录器记录的日志都可以通过过滤器,而foo.c; a.foo 等就不能通过。如果name为空字符串,则所有的日志都能通过。

    Filter 类 有 三个方法 :

    • addFilter(filter) : 为 logger(logger..addFilter(filter)) 或者 handler(handler..addFilter(filter)) 增加过滤器

    • removeFilter(filter) : 为 logger 或者 handler 删除一个过滤器

    • filter(record) : 表示是否要记录指定的记录?返回零表示否,非零表示是。一般自定义Filter需要继承Filter基类,并重写filter方法

    Formatter

    格式化日志的输出;实例化:formatter = logging.Formatter(fmt=None,datefmt=None); 如果不指明 fmt,将默认使用 ‘%(message)s’ ,如果不指明 datefmt,将默认使用 ISO8601 日期格式。

    其中 fmt 参数 有以下选项:

    %(name)sLogger的名字
    %(levelno)s数字形式的日志级别
    %(levelname)s文本形式的日志级别;如果是logger.debug则它是DEBUG,如果是logger.error则它是ERROR
    %(pathname)s调用日志输出函数的模块的完整路径名,可能没有
    %(filename)s调用日志输出函数的模块的文件名
    %(module)s调用日志输出函数的模块名
    %(funcName)s调用日志输出函数的函数名
    %(lineno)d调用日志输出函数的语句所在的代码行
    %(created)f当前时间,用UNIX标准的表示时间的浮 点数表示
    %(relativeCreated)d输出日志信息时的,自Logger创建以 来的毫秒数
    %(asctime)s字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
    %(thread)d线程ID。可能没有
    %(threadName)s线程名。可能没有
    %(process)d进程ID。可能没有
    %(message)s用户输出的消息; 假如有logger.warning("NO Good"),则在%(message)s位置上是字符串NO Good

    例如:

    formatter = logging.Formatter('%(asctime)s %(levelname)-8s: %(message)s')		# -表示右对齐 8表示取8位
    handler.formatter = formatter

    datefmt 参数 有以下选项:

    参数含义
    %y两位数的年份表示(00-99)
    %Y四位数的年份表示(000-9999)
    %m月份(01-12)
    %d月内中的一天(0-31)
    %H24小时制小时数(0-23)
    %I12小时制小时数(01-12)
    %M分钟数(00=59)
    %S 秒(00-59)

    例如:

    formatter = logging.Formatter('%(asctime)s %(levelname)-8s: %(message)s')		# -表示右对齐 8表示取8位
    handler.formatter = formatter

    datefmt 参数 有以下选项:

    参数含义
    %y两位数的年份表示(00-99)
    %Y四位数的年份表示(000-9999)
    %m月份(01-12)
    %d月内中的一天(0-31)
    %H24小时制小时数(0-23)
    %I12小时制小时数(01-12)
    %M分钟数(00=59)
    %S 秒(00-59)

    例子:

    formatter = logging.Formatter("%(asctime)s %(levelname)s %(message)s","%Y%m%d-%H:%M:%S")
    handler.formatter = formatter

    logging 的配置

    • conf 形式的配置

    在 loguser.conf 中 写入相关的信息

    [loggers]
    keys=root,fileLogger,rotatingFileLogger
    
    [handlers]
    keys=consoleHandler,fileHandler,rotatingFileHandler
    
    [formatters]
    keys=simpleFormatter
    
    [logger_root]
    level=INFO
    handlers=consoleHandler
    
    [logger_fileLogger]
    level=INFO
    handlers=fileHandler
    qualname=fileLogger
    propagate=0
    
    [logger_rotatingFileLogger]
    level=INFO
    handlers=consoleHandler,rotatingFileHandler
    qualname=rotatingFileLogger
    propagate=0
    
    [handler_consoleHandler]
    class=StreamHandler
    level=INFO
    formatter=simpleFormatter
    args=(sys.stdout,)
    
    [handler_fileHandler]
    class=FileHandler
    level=INFO
    formatter=simpleFormatter
    args=("logs/fileHandler_test.log", "a")
    
    [handler_rotatingFileHandler]
    class=handlers.RotatingFileHandler
    level=WARNING
    formatter=simpleFormatter
    args=("logs/rotatingFileHandler.log", "a", 10*1024*1024, 50)
    
    [formatter_simpleFormatter]
    format=%(asctime)s - %(module)s - %(levelname)s -%(thread)d : %(message)s
    datefmt=%Y-%m-%d %H:%M:%S
    • 在使用logger时,直接导入配置文件即可

    from logging import config
    
    with open('./loguser.conf', 'r', encoding='utf-8') as f:
    	## 加载配置
        config.fileConfig(f)
        ## 创建同名Logger,其按照配置文件的handle,formatter,filter方法初始化
        logger = logging.getLogger(name="fileLogger")
    • yaml 形式配置文件

    在 loguser.yaml文件 中 配置相关信息

    version: 1
    disable_existing_loggers: False
    # formatters配置了日志输出时的样式
    # formatters定义了一组formatID,有不同的格式;
    formatters:
      brief:
          format: "%(asctime)s - %(message)s"
      simple:
          format: "%(asctime)s - [%(name)s] - [%(levelname)s] :%(levelno)s: %(message)s"
          datefmt: '%F %T'
    # handlers配置了需要处理的日志信息,logging模块的handler只有streamhandler和filehandler
    handlers:
      console:
          class : logging.StreamHandler
          formatter: brief
          level   : DEBUG
          stream  : ext://sys.stdout
      info_file_handler:
          class : logging.FileHandler
          formatter: simple
          level: ERROR
          filename: ./logs/debug_test.log
      error_file_handler:
        class: logging.handlers.RotatingFileHandler
        level: ERROR
        formatter: simple
        filename: ./logs/errors.log
        maxBytes: 10485760 # 10MB #1024*1024*10
        backupCount: 50
        encoding: utf8
    
    loggers:
    #fileLogger, 就是在代码中通过logger = logging.getLogger("fileLogger")来获得该类型的logger
      my_testyaml:
          level: DEBUG
          handlers: [console, info_file_handler,error_file_handler]
    # root为默认情况下的输出配置, 当logging.getLogger("fileLoggername")里面的fileLoggername没有传值的时候,
    # 就是用的这个默认的root,如logging.getLogger(__name__)或logging.getLogger()
    root:
        level: DEBUG
        handlers: [console]

    同样的可以通过导入 yaml 文件加载配置

    with open('./loguser.yaml', 'r', encoding='utf-8') as f:
            yaml_config = yaml.load(stream=f, Loader=yaml.FullLoader)
            config.dictConfig(config=yaml_config)
    
        root = logging.getLogger()
        # 子记录器的名字与配置文件中loggers字段内的保持一致
        # loggers:
        #   my_testyaml:
        #       level: DEBUG
        #       handlers: [console, info_file_handler,error_file_handler]
        my_testyaml = logging.getLogger("my_testyaml")

    logging 和 print 的区别

    看起来logging要比print复杂多了,那么为什么推荐在项目中使用 logging 记录日志而不是使用print 输出程序信息呢。

    相比与print logging 具有以下优点:

    • 可以通过设置不同的日志等级,在 release 版本中只输出重要信息,而不必显示大量的调试信息;

    • print 将所有信息都输出到标准输出中,严重影响开发者从标准输出中查看其它数据;logging 则可以由开发者决定将信息输出到什么地方,以及怎么输出;

    • 和 print 相比,logging 是线程安全的。(python 3中 print 也是线程安全的了,而python 2中的print不是)(线程安全是指在多线程时程序不会运行混乱;而python 2 中的print 分两步打印信息,第一打印字符串,第二打印换行符,如果在这中间发生线程切换就会产生输出混乱。这就是为什么python2的print不是原子操作,也就是说其不是线程安全的)印信息,第一打印字符串,第二打印换行符,如果在这中间发生线程切换就会产生输出混乱。这就是为什么python2的print不是原子操作,也就是说其不是线程安全的)

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发 Python
    相关文章 更多
    python删除一个列表里的重复元素的方法与代码示例
    python删除一个列表里的重复元素的方法与代码示例

    学习如何使用Python高效删除列表中的重复元素。本文提供5种常见方法的代码示例,涵盖保持顺序与不保持顺序的场景,适合初学者和进阶开发者参考。

    Python写接口的步骤及完整代码示例
    Python写接口的步骤及完整代码示例

    详细讲解使用Python编写Web接口的核心步骤与完整代码示例,涵盖环境准备、路由定义、数据校验、服务启动及调试测试方法。

    codex怎么读取word文档及docx文件操作教程
    codex怎么读取word文档及docx文件操作教程

    介绍如何利用编程工具读取和解析Word文档(docx格式),涵盖基础文本提取代码示例、结构化数据处理逻辑,以及处理复杂排版时的技术局限与替代方案。

    怎么在Python中调用C语言代码提升性能
    怎么在Python中调用C语言代码提升性能

    详细讲解在Python中调用C语言代码提升性能的完整实践指南,包含原理分析、编译步骤、ctypes与CFFI具体实现、性能对比及常见陷阱。

    Python与C语言的性能差异及底层原理
    Python与C语言的性能差异及底层原理

    深入解析Python与C语言在执行效率上的数量级差异,从编译机制、变量内存布局、动态类型推断到GIL锁,系统阐明底层核心原理。

    Python和C语言哪个更适合编程入门
    Python和C语言哪个更适合编程入门

    客观对比Python与C语言在心智负担、底层机制与学习反馈上的核心差异,提供清晰有据的选择标准与切实的入门学习路径。

    selenium上传文件教程本地文件路径设置方法
    selenium上传文件教程本地文件路径设置方法

    深入解析Selenium处理文件上传的技术细节,涵盖标准HTML控件的路径直接注入法与非标准控件的系统级模拟方案,提供Windows与Linux环境下的路径设置最佳实践及常见异常排查。

    大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景
    大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景

    针对大数据工程场景,系统对比Java、Scala与Python在执行性能、生态结合、开发效率和维护成本上的核心差异,给出清晰的架构选型依据与落地方案。

    langgraph python guide中文入门教程详解
    langgraph python guide中文入门教程详解

    本篇LangGraph Python中文入门教程详解,系统梳理StateGraph状态机定义、节点编写、边与条件路由、检查点持久化(MemorySaver)等核心机制,提供从环境安装到完整循环智能体构建的代码示例与实操指导。

    Windows 安装 Python:从官方入口到虚拟环境的可复现实践
    Windows 安装 Python:从官方入口到虚拟环境的可复现实践

    面向后端开发者,基于 Python 官方文档说明如何在 Windows 上安装 Python、创建 venv 虚拟环境及使用 pip 管理依赖。包含可复制命令、验证方法及工具选择边界,避免常见配置误区。

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。