1. 为什么要使用日志(作用)

在学习过程中,写一个小程序或小demo时,遇到程序出错时,我们一般会将一些信息打印到控制台进行查看,方便排查错误。这种方法在较小的程序中很实用,但是当你的程序变大,或是说在实际的工程项目中,代码量都是很大的,代码量一大,不可控因素就多,再将信息打印到控制台进行查看是非常不方便的,此时就需要使用日志来记录程序运行过程中的相关信息,监控程序的运行情况。

2. 基础概念

我们在程序中会使用print打印一些信息以供我们判断程序的运行情况,什么时候需要使用print打印一些信息以及在什么位置使用print,这些都是根据程序自身以及个人的经验。使用日志和使用print是相似的,不同的时,日志具有多种形式来记录一些信息,例如 logging.FileHandler ****将日志信息文件写入文件,logging.handlers.SMTPHandler 将日志信息通过SMTP发送到一个电子邮件地址。

记录和处理日志信息的方式有很多种,logging库中提供了许多方法:https://docs.python.org/zh-cn/3/library/logging.handlers.html# 本文只记录 StreamHandler和 FileHandler 的使用方法。

logging库虽然提供了多种方法来记录和处理日志信息,但并不是什么信息都需要记录的,我们往往会根据程序中各个模块的重要程度来决定是否需要记录信息以及记录哪些信息。logging库根据事件的重要性提供了以下几个级别:

级别 使用时机
DEBUG 细节信息,仅当诊断问题时适用。
INFO 确认程序按预期运行,和print使用类似。
WARNING 表明有已经或即将发生的意外(例如:磁盘空间不足,数值运算产生精度丢失等)。程序仍按预期进行。
ERROR 由于严重的问题,程序的某些功能已经不能正常执行。
CRITICAL 严重的错误,表明程序已不能继续执行。

级别大小:DEBUG < INFO < WARNING <ERROR < CRITICAL

划分处理等级的目的是为了针对不同的情况来记录有用的信息,方便有效地监控程序的运行状况,当程序出错时也能方便的定位到。因此在使用logging库记录和处理日志信息前,需要先设定处理等级,默认的等级为 WARNING,当记录和处理日志信息时,只处理大于等于该等级的日志信息。

3. logging库的一些简单使用案例

3.1 像print一样打印日志信息

使用debug()、info()、warning()、error()、critical() 方法分别打印对应的级别及以上的信息,因为默认的级别为 WARNING,所以只会对warning()、error()、critical() 中的信息进行打印。

import logging

if __name__ == "__main__":
logging.debug("the message of debug")
logging.info("the message of debug")
logging.warning("the message of warning")
logging.error("the message of error")
logging.critical("the message of critical") 输出结果:
WARNING:root:the message of warning
ERROR:root:the message of error
CRITICAL:root:the message of critical

3.2 设置级别

使用 basicConfig() 方法设置级别,传入关键字参数 level ,参数值为对应级别的字符串形式。

import logging

if __name__ =="__main__":
logging.basicConfig(level='DEBUG')
logging.debug("the message of debug")
logging.info("the message of debug")
logging.warning("the message of warning")
logging.error("the message of error")
logging.critical("the message of critical") 输出结果:
DEBUG:root:the message of debug
INFO:root:the message of debug
WARNING:root:the message of warning
ERROR:root:the message of error
CRITICAL:root:the message of critical

3.3 在日志中打印变量信息

默认使用 printf 风格的方式进行字符串格式化。

import logging

if __name__ == "__main__":
name = "张三"
age = 24
logging.warning("%s的年龄为%s岁", name, age)
# 也可以使用format的方式进行字符串格式化
logging.warning("{}的年龄为{}岁".format(name, age)) 输出结果:
WARNING:root:张三的年龄为24岁

3.4 更改日志信息显示的格式

对于可以出现在格式字符串中的全部内容,可以参考官方文档 LogRecord 属性

我们可以将日志信息的显示格式使用关键字 format 设置为:

format='%(asctime)s: %(name)s: %(levelname)s: %(filename)s: %(funcName)s: %(message)s'

记录时间 - 记录器的名称 - 事件等级 - 产生日志信息的源文件名 - 所在函数名 - 提示信息

import logging

def main():
logging.basicConfig(format='%(asctime)s: %(name)s: %(levelname)s: %(filename)s: %(funcName)s: %(message)s',
level=logging.DEBUG)
logging.debug('This message should appear on the console')
logging.info('So should this')
logging.warning('And this, too') if __name__ == "__main__":
main() 输出结果:
2022-04-19 15:30:02,404: root: DEBUG: logging_demo.py: main: This message should appear on the console
2022-04-19 15:30:02,404: root: INFO: logging_demo.py: main: So should this
2022-04-19 15:30:02,404: root: WARNING: logging_demo.py: main: And this, too

3.5 将日志信息写入文件

指定文件名 filename,文件写入方式 filenmode,默认写入方式为 a

import logging

def main():
fmt = '%(asctime)s: %(name)s: %(levelname)s: %(filename)s: %(funcName)s: %(message)s'
logging.basicConfig(filename="example.log", filemode='w', format=fmt, level="DEBUG")
logging.debug('This message should appear on the console')
logging.info('So should this')
logging.warning('And this, too') if __name__ == "__main__":
main()

3.6 basicConfig

前面几个案例都使用到了 basicConfig 方法对打印和记录日志信息的行为进行设置,可以设置是将信息显示在控制台还是记录到文件中,可以设置显示或记录的内容格式,设置事件等级等,更详细的设置官方文档已经给出了很细致的解释。

4. 进一步使用

当程序规模变大,使用上面方式介绍的记录日志的方式就会显得捉襟见肘。下面介绍 logging库的进阶使用方式。

logging 库采用模块化的方式来记录日志信息,由以下四个核心组件组成:

Logger(记录器):根据记录器设置的等级捕获日志信息,并传递给对应的处理器;

Handler(处理器):将记录器传递过来的日志信息交给不同的处理器处理;

Filter(过滤器):更细粒度地控制要输出哪些日志记录;

Formatter(格式器):设置日志记录的输出格式;

下面说明这几个组件之间的联系及处理顺序:

  1. 首先通过 getLogger() 方法一个指定名称的 Logger实例的引用,如果没提供名称,则返回 rootlogger = getLogger(name)
  2. 为 Logger 实例设置捕获信息的等级,默认等级为 WARNING,logger.setLevel('INFO')
  3. logger 通过调用 debug()、info()、warning()、error()、critical() 这些方法来捕获日志信息;Logger 只暴露接口供程序员调用,用来捕获日志信息,而不处理信息;只捕获大于等于其自身等级的信息;
  4. 如果 logger 捕获了日志信息,则将日志信息传递给 Handler 进行处理;
  5. 每个 logger 可以有多个 Handler 处理捕获的日志信息,常用的 StreamHandler 和 FileHandler ,StreamHandler 将日志信息打印到终端显示,FileHandler 将日志信息记录写入到文件中;不同的Handler 也都具有等级属性,每个Handler 只会处理大于等于自身等级的日志信息;

其中 Filter 可以作用 Logger 和 Handler,用于更细粒度地控制捕获或输出哪些日志信息,本文不讨论 Filter 使用。

日志事件信息流程如下图所示:

整体代码框架如下:

# 实例化一个 Logger 对象,并记录一个名字
# 在命名记录器时使用的一个好习惯,是在每个使用日志记录的模块中使用模块级记录器
logger = logging.getLogger(__name__)
# 设置记录器捕获日志信息的等级
logger.setLevel("INFO") # 实例化处理器对象
ch = logging.StreamHandler()
fh = logging.FileHandler("example.log") # 设置处理器处理信息的等级
ch.setLevel("INFO")
fh.setLevel("WARNING") # 设置处理器输出日志信息的格式
fmt = logging.Formatter('%(asctime)s: %(levelname)s: %(name)s: %(filename)s: %(message)s')
ch.setFormatter(fmt)
fh.setFormatter(fmt) # 给记录器添加处理器
logger.addHandler(ch)
logger.addHandler(fh) # 捕获日志信息
logger.info("the message info")
logger.error("the message of error")

将上面代码封装成一个类,方便使用

import logging

class Logger:
"""
将日志信息打印到控制台和记录到文件的操作封装成一个类
"""
def __init__(self, name: str, console_handler_level: str = logging.DEBUG,
fmt: str = '%(asctime)s: %(levelname)s: %(name)s: %(filename)s: %(message)s'):
"""
默认会添加一个等级为 'DEBUG' 的 Handler 对象到 Logger 对象
:param name: handler 的名称
:param console_handler_level: 设置 StreamHandler 的等级
:param fmt: 日志消息的显示格式
"""
self.logger = logging.getLogger(name)
self.logger.setLevel(logging.DEBUG)
self.fmt = logging.Formatter(fmt)
self.set_console_handler(console_handler_level) def set_console_handler(self, console_handler_level: str = logging.DEBUG) -> None:
ch = logging.StreamHandler()
ch.setLevel(console_handler_level)
ch.setFormatter(self.fmt)
self.logger.addHandler(ch) def set_file_handler(self, filename: str, mode: str = 'a', file_handler_level: str = logging.INFO) -> None:
fh = logging.FileHandler(filename, mode=mode, encoding='utf-8')
fh.setLevel(file_handler_level)
fh.setFormatter(self.fmt)
self.logger.addHandler(fh) def debug(self, msg):
self.logger.debug(msg) def info(self, msg):
self.logger.info(msg) def warning(self, msg):
self.logger.warning(msg) def error(self, msg):
self.logger.error(msg) def critical(self, msg):
self.logger.critical(msg)

日志(logging模块)的更多相关文章

  1. day18包的使用与日志(logging)模块

    包的使用与日志(logging)模块1. 什么是包    包就是一个包含有__init__.py文件的文件夹    包本质就是一种模块,即包是用包导入使用的,包内部包含的文件也都是用来被导入使用2 为 ...

  2. python中日志logging模块的性能及多进程详解

    python中日志logging模块的性能及多进程详解 使用Python来写后台任务时,时常需要使用输出日志来记录程序运行的状态,并在发生错误时将错误的详细信息保存下来,以别调试和分析.Python的 ...

  3. python 的日志logging模块学习

    1.简单的将日志打印到屏幕 import logging logging.debug('This is debug message') logging.info('This is info messa ...

  4. Python之日志 logging模块

    关于logging模块的日志功能 典型的日志记录的步骤是这样的: 创建logger 创建handler 定义formatter 给handler添加formatter 给logger添加handler ...

  5. python 的日志logging模块

    1.简单的将日志打印到屏幕 import logging logging.debug('This is debug message')logging.info('This is info messag ...

  6. Python日志(logging)模块,shelve,sys模块

    菜鸟学python第十七天 1.logging 模块 logging模块即日志记录模块 用途:用来记录日志 为什么要记录日志: 为了日后复查,提取有用信息 如何记录文件 直接打开文件,往里写东西 直接 ...

  7. python的日志logging模块性能以及多进程

    写在前面: 日志是记录操作的一种好方式.但是日志,基本都是基于文件的,也就是要写到磁盘上的.这时候,磁盘将会成为一个性能瓶颈.对于普通的服务器硬盘(机械磁盘,非固态硬盘),python日志的性能瓶颈是 ...

  8. python+Appium自动化:日志logging模块

    日志级别 debug.info.warn.error.critical五个级别 logging模块构成(四部分) logger(记录器,用于日志采集) Handler(处理器,将日志记录发送到合适的路 ...

  9. Python中日志logging模块

    # coding:utf-8 import logging import os import time class Logger(object): def __init__(self): # 创建一个 ...

  10. Python的日志记录-logging模块的使用

    一.日志 1.1什么是日志 日志是跟踪软件运行时所发生的事件的一种方法,软件开发者在代码中调用日志函数,表明发生了特定的事件,事件由描述性消息描述,同时还包含事件的重要性,重要性也称为级别或严重性. ...

随机推荐

  1. JavaMetaweblogClient,Metaweblog的java实现-从此上传博客实现全平台

    目录 1. 什么是Metaweblog? 2. Metaweblog的应用 3. 如何使用Metaweblog 4. 本项目介绍 4.1 metaweblog与java之间的关系映射 4.2 使用Ja ...

  2. e2fsck-磁盘分区修复

    检查 ext2/ext3/ext4 类型文件系统. 语法 e2fsck [-panyrcdfvtDFV] [-b superblock] [-B blocksize] [-I inode_buffer ...

  3. 一文学完Linux常用命令

    一.Linux 终端命令格式 1.终端命令格式 完整版参考链接:Linux常用命令完整版 command [-options] [parameter] 说明: command : 命令名,相应功能的英 ...

  4. Mac远程windows工具

    现在很多小伙伴都是使用MAC系统,但在工作中或多或少会遇到需要远程windows的情况,今天给大家安利一款软件,让你轻轻松松远程windows Microsoft Remote Desktop Mic ...

  5. 初识 Redis 以及其基本使用方法

     1.什么是Redis  redis 是一个高性能的key-value数据库,它支持的类型更多 包括 string(字符串).list(链表).set(集合).zset(sorted set --有序 ...

  6. 最强肉坦:RUST多线程

    Rust最近非常火,作为coder要早学早享受.本篇作为该博客第一篇学习Rust语言的文章,将通过一个在其他语言都比较常见的例子作为线索,引出Rust的一些重要理念或者说特性.这些特性都是令人心驰神往 ...

  7. Centos6添加防火墙端口 以及相关操作命令的使用

    用命令 vim /etc/sysconfig/iptables 增加防火墙端口号:(添加你需要的端口号) service iptables start  启动防火墙 service iptables ...

  8. 『忘了再学』Shell基础 — 30、sed命令的使用

    目录 1.sed命令说明 2.行数据操作 (1)查看文件中的数据 (2)删除文件中的数据 (3)向文件中追加数据 (4)向文件中插入数据 (5)修改文件中的多行数据(删除,追加,插入) (6)替换文件 ...

  9. TDSQL|三篇论文入选国际顶会SIGMOD,厉害了腾讯云数据库

    好消息!6月13日,腾讯云数据库三篇论文再次入选数据库行业顶会SIGMOD,被SIGMOD 2022 Research Full Paper(研究类长文)收录. 本次被收录的研究成果中,新型数据结构设 ...

  10. 表达式的动态解析和计算,Flee用起来真香

    前言 在很多项目中经常会出现需要动态解析表达式和计算的场景,比如一些自动审核规则,或者是一些变量的值通过维护的公式在运行过程中动态算出:由于场景需求,都需要比较灵活的配置对应的表达式,然后希望在需要的 ...