一. logging模块_打印以及保存日志
1、Logging :用来做简单的日志。等级分为 debug()、 info()、 warning()、 error() 和 critical()
等级 使用场景
DEBUG 调试 ,打印详细信息
INFO 一般信息,打印关键信息,证明程序按预定轨迹执行。
WARNING 警告信息,未预料到的 及可能出现问题和错误的提示信息,但是软件还是会照常运行 例如:磁盘空间不足。
ERROR 程序出现错误,可能会波及一些功能的使用
CRITICAL 严重错误,软件不能正常执行
2. logging组件
# 1. Logger 记录器: 记录运行日志,并按配置日志等级过滤日志信息。
#常用的方法分为两类:配置和发送消息。
Logger.setLevel()
指定logger将会处理的日志等级信息。
Logger.addHandler()和Logger.removeHandler()
从记录器对象中添加和删除处理程序对象。
Logger.addFilter()和Logger.removeFilter()
从记录器对象添加和删除过滤器对象。
# 2. Handler 处理器: 将日志存放到控制台或写入文件。
logging.StreamHandler
控制台输出
logging.FileHandler
文件输出
logging.handlers.RotatingFileHandler
按照大小自动分割日志文件,一旦达到指定的大小重新生成文件
logging.handlers.TimedRotatingFileHandler
按照时间自动分割日志文件
# 配置方法:
setLevel()方法
指明了将会分发日志的最低级别。为什么会有两个setLevel()方法?记录器的级别决定了消息是否要传递给处理器。
每个处理器的级别决定了消息是否要分发。
setFormatter()
为该处理器选择一个格式化器。
addFilter()和removeFilter()
分别配置和取消配置处理程序上的过滤器对象。
# 3. Filter 过滤器: 过滤输出的日志信息。
addFilter(filter),removeFilter(filter)和filter(record)方法
# 常用的属性
name 就是初始化logger对象时传入的名字
level 是级别
pathname 是哪个文件输出的这行日志
lineno 是行号
msg 是日志本身
# 4. Formatter 格式化器: 格式化日志输出格式。
# 默认的时间格式为%Y-%m-%d %H:%M:%S
# 常用信息
%(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 用户输出的消息
二. 方法
1. 引入方法
import logging
from logging import handles
2. 配置日志输出格式
logging.basicConfig函数各参数
filename: 指定日志文件名,将文件写入
filemode: 和file函数意义相同,指定日志文件的打开模式,'w' 覆盖写入 或'a' 追加写入 ,默认写入模式为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()
英文: %A 周, %B 月
英文缩写: %a 周, %b 月, %c 日期+时间缩写 (输出格式:Wed Jan 12 10:00:06 2022)
时间: %d 日, %w 周, %m 月, %Y 年, %H:%M:%S 时分秒, %T 时间 (10:09:32), %D 日期 (12/01/22), %F 日期(2022-01-12)
level: 设置日志级别,默认为logging.WARNING
stream: 指定将日志的输出流,可以指定输出到sys.stderr,sys.stdout或者文件,默认输出到sys.stderr,当stream和filename同时指定时,stream被忽略
3. 设置日志格式
# 设置日志格式
# 设置打印格式
logging.basicConfig(format='%(asctime)s - %(name)s[line:%(lineno)d] - %(levelname)s: %(message)s', # 日志格式
datefmt='%F %T ', # 日期格式
level=logging.INFO) # 日志等级info
三.打印方法
# 1、仅打印到控制台,logging 默认设置的等级为warning,只打印warning和以上等级
# coding:utf-8
import logging
# 打印到控制台
logging.debug("打印到控制台")
logging.info("打印到控制台")
logging.warning("打印到控制台")
logging.error("打印到控制台")
logging.critical("打印到控制台")
# 2. 仅将日志写入文件
# 设置打印格式
logging.basicConfig(format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s', # 日志格式
datefmt='%F %T ', # 日期格式
level=logging.INFO,# 日志等级
filename="info.log", # 日志写入文件info.log
filemode="a") #a 追加写入, w 覆盖写入
四. 输出控制台并写入日志文件
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import os, datetime, logging
from logging import handlers
# >>> 定义Logger类
class Logger(object):
# 定义类属性
level_relations = {'debug': logging.DEBUG, 'info': logging.INFO, 'warning': logging.WARNING, 'error': logging.ERROR, 'crit': logging.CRITICAL}#日志级别关系映射
# 使用函数exists()对文件存在与否进行判断,存在为True,不存在为False.
if os.path.exists('logs') == True: # 文件存在
filepath = os.getcwd() + '\logs\log_' + datetime.datetime.now().strftime('%Y%m%d') + '.log'
else:
os.makedirs(".\logs") # 创建文件夹
filepath = os.getcwd() + '\logs\log_' + datetime.datetime.now().strftime('%Y%m%d') + '.log'
# 定义构造函数 when=D 天数,新生成的文件名上会带上时间 backCount 保留文件生成个数
def __init__(self, filename=filepath, level='info', when='D', backCount=3, fmt='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s'):
#when:描述滚动周期的基本单位;“S”: Seconds ,“M”: Minutes ,“H”: Hours ,“D”: Days ,“W”: Week day (0=Monday) ,“midnight”: Roll over at midnight
self.logger = logging.getLogger(filename) # 指定日志文件名
format_str = logging.Formatter(fmt) # 设置日志格式
self.logger.setLevel(self.level_relations.get(level)) # 设置日志级别
sh = logging.StreamHandler() # 往屏幕上输出
sh.setFormatter(format_str) # 设置屏幕上显示的格式
th = handlers.TimedRotatingFileHandler(filename=filename, when=when, backupCount=backCount, encoding='utf-8') # 写入文件
th.setFormatter(format_str) # 设置文件里写入的格式
self.logger.addHandler(sh) # 把对象加到logger里 屏幕输出
self.logger.addHandler(th) # 把对象加到logger里 文件写入
def getLog(self):
return self.logger
#创建log对象,隐式调用了我们手动创建的 __init__() 构造方法,并设置日志等级
# logs = Logger().logger # 方法一
# logs = Logger().getLog() # 方法二
# 方法三:重置日志等级
logs = Logger(level="debug").getLog()
# 该部分只有文件作为脚本时才会被执行,而 import 到其他脚本中是不会被执行的
if __name__ == '__main__':
logs.debug('debug 信息')
logs.info('info 信息')
logs.warning('警告 信息')
logs.error('报错 信息')
logs.critical('严重 信息')
自动分割日志:将不同级别的日志分别保存在不同的文件中
import logging
from logging import handlers
class Logger(object):
level_relations = {'debug': logging.DEBUG, 'info': logging.INFO, 'warning': logging.WARNING, 'error': logging.ERROR, 'crit': logging.CRITICAL}#日志级别关系映射
def __init__(self, filename, level='info', when='D', backCount=3, fmt='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s'):
self.logger = logging.getLogger(filename) # 创建一个logger
format_str = logging.Formatter(fmt)#设置日志格式
self.logger.setLevel(self.level_relations.get(level))#设置日志级别
sh = logging.StreamHandler()#往屏幕上输出
sh.setFormatter(format_str) #设置屏幕上显示的格式
th = handlers.TimedRotatingFileHandler(filename=filename, when=when, backupCount=backCount, encoding='utf-8') #往文件里写入#指定间隔时间自动生成文件的处理器
th.setFormatter(format_str)#设置文件里写入的格式
self.logger.addHandler(sh) #把对象加到logger里
self.logger.addHandler(th)#
if __name__ == '__main__':
log = Logger('./logs/debug.log', level='debug')
log.logger.debug('debug')
log.logger.info('info')
log.logger.warning('警告')
log.logger.error('报错')
log.logger.critical('严重')
Logger('./logs/error.log', level='error').logger.error('error')
五. loguru
# 安装
pip install loguru
# 引用
from loguru import logger as logg
# 打印日志
logg.info("debug")
# 写入文件
# logg.add("logs_20220414.log")
# 将日志保存在当前路径上一级目录的logs目录下,命名为 log_name
log_name = "log_{}.log".format(datetime.datetime.now().strftime('%Y%m%d'))
logs.add(sink=os.path.abspath("..") + "\\logs\\{}".format(log_name), level=log_level.upper())
# 设置生成日志文件,utf-8编码,每天0点切割,zip压缩,保留3天,异步写入
# logs.add(sink='test.log', level="INFO", rotation="00:00", retention="3 days", compression="zip", encoding="utf-8", enqueue=True)
from loguru import logger as logg
logg.add("logs.log")
def case():
logg.debug("debug")
logg.warning("warning")
case()
# 仅输出到文件 不打印到控制台
# 删除以前添加的处理程序并停止向其接收器发送日志。
logs.remove(handler_id=None) # 移除控制台输出
# 集成loguru到控制台(即html报告)
class PropogateHandler(logging.Handler):
def emit(self, record):
logging.getLogger(record.name).handle(record)
logs.add(PropogateHandler(), format="{time:YYYY-MM-DD at HH:mm:ss} | {message}")
原文链接:https://www.cnblogs.com/phoenixy/p/15791454.html
标签:logging,log,python,打印,详解,日志,logger,logs From: https://www.cnblogs.com/kh-1314/p/16902510.html