一. logging模块_打印以及保存日志
1、Logging :用来做简单的日志。等级分为 debug()、 info()、 warning()、 error() 和 critical()
| 等级 使用场景 |
| DEBUG 调试 ,打印详细信息 |
| INFO 一般信息,打印关键信息,证明程序按预定轨迹执行。 |
| WARNING 警告信息,未预料到的 及可能出现问题和错误的提示信息,但是软件还是会照常运行 例如:磁盘空间不足。 |
| ERROR 程序出现错误,可能会波及一些功能的使用 |
| CRITICAL 严重错误,软件不能正常执行 |
2. logging组件
| |
| |
| |
| Logger.setLevel() |
| 指定logger将会处理的日志等级信息。 |
| Logger.addHandler()和Logger.removeHandler() |
| 从记录器对象中添加和删除处理程序对象。 |
| Logger.addFilter()和Logger.removeFilter() |
| 从记录器对象添加和删除过滤器对象。 |
| |
| |
| |
| logging.StreamHandler |
| 控制台输出 |
| logging.FileHandler |
| 文件输出 |
| logging.handlers.RotatingFileHandler |
| 按照大小自动分割日志文件,一旦达到指定的大小重新生成文件 |
| logging.handlers.TimedRotatingFileHandler |
| 按照时间自动分割日志文件 |
| |
| |
| |
| setLevel()方法 |
| 指明了将会分发日志的最低级别。为什么会有两个setLevel()方法?记录器的级别决定了消息是否要传递给处理器。 |
| 每个处理器的级别决定了消息是否要分发。 |
| setFormatter() |
| 为该处理器选择一个格式化器。 |
| addFilter()和removeFilter() |
| 分别配置和取消配置处理程序上的过滤器对象。 |
| |
| |
| |
| |
| addFilter(filter),removeFilter(filter)和filter(record)方法 |
| |
| name 就是初始化logger对象时传入的名字 |
| |
| level 是级别 |
| |
| pathname 是哪个文件输出的这行日志 |
| |
| lineno 是行号 |
| |
| msg 是日志本身 |
| |
| |
| |
| |
| |
| |
| |
| %(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) |
三.打印方法
| |
| |
| import logging |
| |
| |
| |
| logging.debug("打印到控制台") |
| logging.info("打印到控制台") |
| logging.warning("打印到控制台") |
| logging.error("打印到控制台") |
| logging.critical("打印到控制台") |
| |
| |
| |
| logging.basicConfig(format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s', |
| datefmt='%F %T ', |
| level=logging.INFO, |
| filename="info.log", |
| filemode="a") |
四. 输出控制台并写入日志文件
| |
| |
| import os, datetime, 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} |
| |
| |
| 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' |
| |
| |
| def __init__(self, filename=filepath, level='info', when='D', backCount=3, fmt='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s'): |
| |
| 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) |
| self.logger.addHandler(th) |
| |
| def getLog(self): |
| return self.logger |
| |
| |
| |
| |
| |
| logs = Logger(level="debug").getLog() |
| |
| |
| |
| 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) |
| 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) |
| 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") |
| |
| |
| |
| |
| 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()) |
| |
| |
| |
| |
| |
| |
| |
| |
| from loguru import logger as logg |
| logg.add("logs.log") |
| |
| def case(): |
| logg.debug("debug") |
| logg.warning("warning") |
| |
| |
| case() |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| logs.remove(handler_id=None) |
| |
| |
| |
| |
| |
| |
| 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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?