Python日志模块学习,从这里开始...
一脸懵逼
文章图片
一脸懵逼 一直比较喜欢在上写博文,主要是因为它的页面看这清爽,没有csdn那么多的广告。可周五写文章的时候就看到禁止发文章的提示,当时以为是系统维护没有注意,没想到今天看到置顶文章才知道,要整改一个月。
之前文章就吐槽过,不知道从何时开始,首页上每天充斥这大量的擦边小黄文,反而技术类的文章没几篇能上榜的。对于这种问题,很多人都在吐槽、投诉文章,但没什么卵用。这下好了封停一个月,好好整改下吧。期待一个月后能看到一个不一样的平台,那么最近,只能在csdn上发文章了。之前的csdn账号id有些晦涩,虽然用了几年了,但决定还是重开了一个博客,期待大家的关注,博客地址:
csdn博客地址: https://blog.csdn.net/BreezePython
由于新开的博客,历史的文章还没有迁移,抽空慢慢迁移过来吧...
消息与记录
刚才谈到了关于历史账号的文章与消息记录,所以今天想跟大家聊聊Python关于消息记录的模块:日志管理模块 logging
。
学习python的第一课,肯定都是 print('Hello Wrold...')
。但print仅仅使用与我们日常学习,当我们的程序需要部署上线时,程序必须要具备记录日志与程序输出的功能。此时print就不能满足我们的需求,而logging应运而生。
logging是python的内置模块,无需安装即可直接使用。logging模块借鉴了Apache的Log4j中很多的功能与特性,使用起来较为方便,不论你是最简单无脑输出还是定义自己的过滤器与格式,最终都能满足大家的需求,所以logging模块是你的必修课!
Logging入门
日志级别
不论是python、java还是C,日志的级别都是统一规定的:
日志级别 | 使用范围 |
---|---|
FATAL | 致命错误 |
CRITICAL | 严重的错误,如内存耗尽、磁盘空间不足等. |
ERROR | 错误,如IO异常,文件读写异常等 |
WARNING | 警告类错误,如用户输入密码即将过期提醒等 |
INFO | 处理请求或者用户操作的状态及日常事务日志 |
DEBUG | 调试过程中使用的日志等级,可用于后台问题定位 |
简单日志打印 说了半天的日志级别,那么这东西对日志记录有什么用?此时我们需要了解LogLevel。logging模块默认记录日志的级别是大于等于WARNING。那么让我们来看第一个例子:
import logging
logging.debug('This is debug message')
logging.info('This is info message')
logging.warning('This is warning message')
logging.error('This is error message')
logging.critical('This is critical message')
>>> WARNING:root:This is warning message
>>> ERROR:root:This is error message
>>> CRITICAL:root:This is critical message
理想中我们期望的打印结果是从debug到critical,但现实是日志从warning级别开始打印。而且这种日志的打印和print又有什么区别,我们需要丰满日志的内容,提升逼格。
配置日志输出 logging提供了basicConfig函数,用于对日志输入进行相关配置。
让我们来看看basicConfig有哪些可配置参数吧:
filename: 指定日志文件名
filemode: 和file函数意义相同,指定日志文件的打开模式,'w'或'a'
format: 指定输出的格式和内容,format可以输出很多有用信息,如上例所示:
%(levelno)s: 打印日志级别的数值
%(levelname)s: 打印日志级别名称
%(pathname)s: 打印当前执行程序的路径,其实就是sys.argv[0]
%(filename)s: 打印当前执行程序名
%(funcName)s: 打印日志的当前函数
%(lineno)d: 打印日志的当前行号
%(asctime)s: 打印日志的时间
%(thread)d: 打印线程ID
%(threadName)s: 打印线程名称
%(process)d: 打印进程ID
%(message)s: 打印日志信息
datefmt: 指定时间格式,同time.strftime()
level: 设置日志级别,默认为logging.WARNING
stream: 指定将日志的输出流,可以指定输出到sys.stderr,sys.stdout或者文件,
????默认输出到sys.stderr,当stream和filename同时指定时,stream被忽略
import logginglogging.basicConfig(level=logging.DEBUG,
format='%(asctime)s %(filename)s[line:%(lineno)d] %(message)s', datefmt='%Y-%m-%d')
logging.debug('This is debug message')
logging.info('This is info message')
logging.warning('This is warning message')
logging.error('This is error message')
logging.critical('This is critical message')>>> 2019-09-01 23:56:33 LearnLogging.py[line:38] This is debug message
>>> 2019-09-01 23:56:33 LearnLogging.py[line:39] This is info message
>>> 2019-09-01 23:56:33 LearnLogging.py[line:40] This is warning message
>>> 2019-09-01 23:56:33 LearnLogging.py[line:41] This is error message
>>> 2019-09-01 23:56:33 LearnLogging.py[line:42] This is critical message
通过配置basicConfig,日志输出看起来就工整多了...当看到第一个filename的时候就想到了,现在的日志都是在控制台输出的,我们添加该参数后,就可以将日志输出到文本了,对吧?答案是肯定的,如下图:
文章图片
日志保存文本
但此时出现一个问题,我们的日志都保存到了文本中,前台的控制栏不再具备日志输出功能了!这该如何是好?
Logging进阶 刚才提到的入门使用,只是针对logging的一个简单操作,如果我们想深入的去使用logging模块,就必须了解Logger,Handler,Formatter,Filter的概念:
- Logger提供了应用程序可以直接使用的接口;
- Handler将(logger创建的)日志记录发送到合适的目的输出;
- Filters提供了细度设备来决定输出哪条日志记录;
- Formatter决定日志记录的最终输出格式。
常用的记录器对象的方法分为两类:配置和发送消息。
这些是最常用的配置方法:
Logger.setLevel()指定logger将会处理的最低的安全等级日志信息, debug是最低的内置安全等级,critical是最高的内建安全等级。例如,如果严重程度为INFO,记录器将只处理INFO,WARNING,ERROR和CRITICAL消息,DEBUG消息被忽略。
Logger.addHandler()和Logger.removeHandler()从记录器对象中添加和删除处理程序对象。处理器详见Handlers。
Logger.addFilter()和Logger.removeFilter()从记录器对象添加和删除过滤器对象。
Handlers 处理程序对象负责将适当的日志消息(基于日志消息的严重性)分派到处理程序的指定目标。Logger 对象可以通过addHandler()方法增加零个或多个handler对象。举个例子,一个应用可以将所有的日志消息发送至日志文件,所有的错误级别(error)及以上的日志消息发送至标准输出,所有的严重级别(critical)日志消息发送至某个电子邮箱。在这个例子中需要三个独立的处理器,每一个负责将特定级别的消息发送至特定的位置。
其中常用的有4种:
- logging.StreamHandler -> 控制台输出
- logging.FileHandler -> 文件输出
- logging.handlers.RotatingFileHandler
- logging.handlers.TimedRotatingFileHandler
参数 | 说明 |
---|---|
%(name)s | Logger的名字 |
%(levelno)s | 数字形式的日志级别 |
%(levelname)s | 文本形式的日志级别 |
%(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 | 用户输出的消息 |
import logging
logger = logging.getLogger(__name__)
logger.setLevel(level=logging.INFO)
formatter = logging.Formatter('%(asctime)s %(filename)s[line:%(lineno)d] %(message)s',
datefmt='%Y-%m-%d %H:%M:%S')
handler = logging.FileHandler("log.txt")
handler.setLevel(logging.INFO)
handler.setFormatter(formatter)console = logging.StreamHandler()
console.setLevel(logging.INFO)
console.setFormatter(formatter)logger.addHandler(handler)
logger.addHandler(console)logger.debug('This is debug message')
logger.info('This is info message')
logger.warning('This is warning message')
logger.error('This is error message')
logger.critical('This is critical message')>>> 2019-09-02 00:49:58 LearnLogging.py[line:62] This is info message
>>> 2019-09-02 00:49:58 LearnLogging.py[line:63] This is warning message
>>> 2019-09-02 00:49:58 LearnLogging.py[line:64] This is error message
>>> 2019-09-02 00:49:58 LearnLogging.py[line:65] This is critical message
【Python日志模块学习,从这里开始...】此时,前后台均输出了相关的日志信息。
Logging特别操作 日志切片 有时候,系统后台的日志会输出的比较频繁,那么我们如何将日志按照大小或者时间进行切片呢?这里就要用到刚才介绍的:
- logging.handlers.RotatingFileHandler
- logging.handlers.TimedRotatingFileHandler
file_handler = logging.handlers.RotatingFileHandler("test.log", mode="w", maxBytes=1000, backupCount=3, encoding="utf-8")
每隔 1小时 划分一个日志文件,interval 是时间间隔,备份文件为 10 个
handler2 = logging.handlers.TimedRotatingFileHandler("test.log", when="H", interval=1, backupCount=10)
我们以RotatingFileHandler为例,为了演示方便,我设置文件大小为3kb:
import logging
from logging.handlers import RotatingFileHandlerlogger = logging.getLogger(__name__)
logger.setLevel(level=logging.INFO)
formatter = logging.Formatter('%(asctime)s %(filename)s[line:%(lineno)d] %(message)s',
datefmt='%Y-%m-%d %H:%M:%S')
handler = RotatingFileHandler("log.txt", maxBytes=1024*3, backupCount=3)
handler.setLevel(logging.INFO)
handler.setFormatter(formatter)console = logging.StreamHandler()
console.setLevel(logging.INFO)
console.setFormatter(formatter)logger.addHandler(handler)
logger.addHandler(console)for i in range(10):
logger.info(i)
logger.debug('This is debug message')
logger.info('This is info message')
logger.warning('This is warning message')
logger.error('This is error message')
logger.critical('This is critical message')
最终实现:
文章图片
日志记录 关于异常日志 logging模块在对异常获取时,进行了相关的优化操作,来看下这个例子:
import logginglogger = logging.getLogger(__name__)
logger.setLevel(level=logging.INFO)
formatter = logging.Formatter('%(asctime)s %(filename)s[line:%(lineno)d] %(message)s',
datefmt='%Y-%m-%d %H:%M:%S')console = logging.StreamHandler()
console.setLevel(logging.INFO)
console.setFormatter(formatter)
logger.addHandler(console)try:
1/0
except Exception as error:
logger.error(error)logger.error(error, exc_info=True)logger.exception(error)>>> 2019-09-02 01:06:15 LearnLogging.py[line:87] division by zero>>> 2019-09-02 01:06:15 LearnLogging.py[line:89] division by zero
Traceback (most recent call last):
File "D:/Codes_Repository/Python/PythonTests/37.Python日志模块/LearnLogging.py", line 85, in
1/0
ZeroDivisionError: division by zero>>> 2019-09-02 01:06:15 LearnLogging.py[line:91] division by zero
Traceback (most recent call last):
File "D:/Codes_Repository/Python/PythonTests/37.Python日志模块/LearnLogging.py", line 85, in
1/0
ZeroDivisionError: division by zero
由此可见,当我们在对异常结果进行日志输出时,最好使用logger.exception。
其实logging模块的内容还有很多,比如封装与继承,今天就先介绍到这里,有空了继续为大家补充。
The End OK,今天的内容就到这里,如果觉得内容对你有所帮助,欢迎点击文章右下角的“
在看
”。期待你关注我的公众号
清风Python
,如果觉得不错,希望能动动手指转发给你身边的朋友们。希望每周一至五清晨的7点10分,都能让清风Python的知识文章叫醒大家!谢谢……
文章图片
清风Python
推荐阅读
- python学习之|python学习之 实现QQ自动发送消息
- 逻辑回归的理解与python示例
- 日志打卡
- SpringBoot调用公共模块的自定义注解失效的解决
- Node.js中readline模块实现终端输入
- python自定义封装带颜色的logging模块
- 解决SpringBoot引用别的模块无法注入的问题
- 【Leetcode/Python】001-Two|【Leetcode/Python】001-Two Sum
- Python基础|Python基础 - 练习1
- Python爬虫|Python爬虫 --- 1.4 正则表达式(re库)