2025年4月15日 星期二 乙巳(蛇)年 正月十六 设为首页 加入收藏
rss
您当前的位置:首页 > 计算机 > 编程开发 > Python

python logging模块打印log日志到文件和屏幕

时间:12-09来源:作者:点击数:21

一、logging的框架

1、 Loggers: 可供程序直接调用的接口,app通过调用提供的api来记录日志

2、 Handlers: 决定将日志记录分配至正确的目的地

3、 Filters:对日志信息进行过滤,提供更细粒度的日志是否输出的判断

4、 Formatters: 制定最终记录打印的格式布局

二、Log级别

系统默认有6个级别,优先级:

CRITICAL    50

ERROR      40

WARNING   30

INFO        20

DEBUG      10

NOTSET     0

logging.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.WARNNING;

stream:指定将日志的输出流,可以指定输出到sys.stderr,sys.stdout或者文件,默认输出到sys.stderr,当stream和filename同时指定时,stream被忽略;

二、打印log日志到文件和屏幕的例子或者可以直接当成模块调用,文件名:debug_info.py

  • #!/usr/bin/env python
  • # coding=utf-8
  • # logging模块打印log日志到文件和屏幕
  • # Log级别:CRITICAL(50)、ERROR(40)、WARNING(30)、INFO(20)、DEBUG(10)、NOTSET(0)
  • # https://www.cnblogs.com/liujiacai/p/7804848.html
  • import logging,os,sys,time
  • class Log_info(object):
  • def __init__(self):
  • # 指定日志文件名,获取当前执行的py文件名
  • # 获取当天日期
  • file_name_date = time.strftime("%Y-%m-%d", time.localtime())
  • self.filename = str(os.path.basename(sys.argv[0]).split(".")[0]) + file_name_date + '.log'
  • # 指定输出的格式和内容
  • self.format = '%(asctime)s [%(filename)s] %(levelname)s:%(message)s'
  • # 设置日志级别,默认为logging.WARNNING
  • # self.level = logging.INFO
  • # 和file函数意义相同,指定日志文件的打开模式,'w'或者'a'
  • # self.filemode = 'a'
  • # 指定时间格式
  • self.datefmt = '%Y-%m-%d %H:%M:%S'
  • self.logger = logging.getLogger(__name__) # 创建日志记录器
  • def main(self):
  • # 这个方法只能保存到文件,不能同时输出到屏幕
  • # logging.basicConfig(filename=self.filename,format=self.format,level=self.level
  • # ,filemode=self.filemode,datefmt=self.datefmt)
  • self.logger.setLevel(logging.INFO) # 日志记录器的等级
  • format = logging.Formatter(self.format,datefmt=self.datefmt)
  • # 如果当前日志器里handler已存在就不重复添加,为空再添加,避免日志重复输出
  • if not self.logger.handlers:
  • # 日志输出到文件
  • file_handler = logging.FileHandler(self.filename)
  • file_handler.setLevel(logging.INFO)
  • file_handler.setFormatter(format)
  • # 使用StreamHandler输出到屏幕
  • console = logging.StreamHandler()
  • console.setLevel(logging.INFO)
  • console.setFormatter(format)
  • # 添加两个Handler
  • self.logger.addHandler(file_handler)
  • self.logger.addHandler(console)
  • # 执行输出信息: 2019-01-02 15:51:13 [print_debug.py] INFO:输出信息内容
  • # self.logger.info("输出信息内容")
  • # 注意不能这么写,类型不一致
  • # self.logger.info("经营许可证字段值个数:", 2)
  • # 这么写就可以
  • # self.logger.info("经营许可证字段值个数:%s"%2)
  • # self.logger.info("经营许可证字段值个数:%s",3)
  • # try:
  • # (a== 2)
  • # except Exception as e:
  • # self.logger.info(e)
  • # 如果这样返回,那样调取的时候就不用每次写logger.info,直接写logger就可以了
  • return self.logger.info
  • if __name__ =="__main__":
  • log_info = Log_info()
  • logger = log_info.main()

二、如何调用:

  • from debug_info import Log_info
  • logger = Log_info().main()
  • logger("输出的例子")
  • # 2、3是int类型
  • logger("输出的例子:%s"%2)
  • logger("输出的例子:%s",3)
  • logger("输出的例子:%d",3)

优化:

  • # 非单例模式
  • def get_logs(folderName):
  • """封装日志打印输出到文件和控制台,folderName为日志存放的文件夹名"""
  • logs_path = os.path.dirname(os.path.dirname(__file__)) + '/' + folderName + '/'
  • if not os.path.exists(logs_path):
  • print("未找到指定文件夹:%s,请核实!" % folderName)
  • sys.exit()
  • else:
  • # 创建日志器,记录器名称通过__name__获取
  • logger = logging.getLogger(__name__)
  • # 设置日志器级别
  • logger.setLevel(logging.INFO)
  • # 如果当前日志器里处理器Handler已存在就不重复添加,为空再添加,避免日志重复输出
  • if not logger.handlers:
  • # 指定日志文件名为当前执行的py文件名
  • filename = str(os.path.basename(sys.argv[0]).split(".")[0]) + '.log'
  • # 指定输出的格式和内容
  • fmt = '%(asctime)s [%(filename)s-(%(funcName)s:%(lineno)d)] %(levelname)s:%(message)s'
  • # 指定日期格式
  • datefmt = '%Y-%m-%d %H:%M:%S'
  • # 设置格式器
  • format = logging.Formatter(fmt, datefmt=datefmt)
  • # 日志输出到文件,只保存到单一文件,容量会无限大,一般不用,采用时间节点分割
  • file_handler = logging.FileHandler(logs_path + filename)
  • # 日志输出到文件,依据时间切割到不同文件中,when以什么时间单位进行分割(秒、分钟、小时、天、午夜等),
  • # interval间隔多久,backupCount保留文件数量,超过数量时间久远的自动被替换掉
  • # 例如:以每一晚进行切割日志,保留30个文件
  • # file_handler = logging.handlers.TimedRotatingFileHandler(logs_path + filename, when='midnight', interval=1, backupCount=30)
  • file_handler.setLevel(logging.INFO)
  • file_handler.setFormatter(format)
  • # 只输出error级别的日志到文件,可以快速定位代码问题
  • error_file_handler = logging.FileHandler(logs_path + 'error_' + filename)
  • error_file_handler.setLevel(logging.ERROR)
  • error_file_handler.setFormatter(format)
  • # 使用StreamHandler输出到屏幕
  • console = logging.StreamHandler()
  • console.setLevel(logging.INFO)
  • console.setFormatter(format)
  • # 添加处理器Handler
  • logger.addHandler(file_handler)
  • logger.addHandler(error_file_handler)
  • logger.addHandler(console)
  • return logger

优化为单例模式,get_log.py:

  • #!/usr/bin/env python
  • # coding=utf-8
  • # logging模块打印log日志到文件和控制台
  • # Log级别:CRITICAL(50)、ERROR(40)、WARNING(30)、INFO(20)、DEBUG(10)、NOTSET(0)
  • # 四大组件:日志器(Logger)、处理器(Handler)、格式器(Formatter)、过滤器(Filter)
  • # 以下这种方式导入也可以使用logging,因为logging是包名,导入时会自动执行__init__文件
  • import logging.handlers
  • import os
  • import sys
  • class GetLog(object):
  • """单例模式封装日志打印输出到文件和控制台"""
  • logger = None
  • @classmethod
  • def get_log(cls, folderName):
  • """folderName为日志存放的文件夹名"""
  • # logs_path = os.path.dirname(os.path.dirname(__file__)) + '/' + folderName + '/'
  • logs_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), folderName + '/')
  • if not os.path.exists(logs_path):
  • print("ERROR:未找到指定文件夹:%s,请核实!" % folderName)
  • sys.exit()
  • else:
  • if cls.logger is None:
  • # 创建日志器,记录器名称通过__name__获取
  • cls.logger = logging.getLogger(__name__)
  • # 设置日志器级别
  • cls.logger.setLevel(logging.INFO)
  • # 指定日志文件名为当前执行的py文件名
  • filename = str(os.path.basename(sys.argv[0]).split(".")[0]) + '.log'
  • # 指定输出的格式和内容
  • fmt = '%(asctime)s [%(filename)s-(%(funcName)s:%(lineno)d)] %(levelname)s:%(message)s'
  • # 指定日期格式
  • datefmt = '%Y-%m-%d %H:%M:%S'
  • # 设置格式器
  • format = logging.Formatter(fmt, datefmt=datefmt)
  • # 日志输出到文件,只保存到单一文件,容量会无限大,一般不用,采用时间节点分割(运行时,即使没有日志输出结果,也会创建一个空的日志文件)
  • file_handler = logging.FileHandler(logs_path + filename)
  • # 日志输出到文件,依据时间切割到不同文件中,when以什么时间单位进行分割(秒、分钟、小时、天、午夜等)
  • # interval间隔多久,backupCount保留文件数量,超过数量时间久远的自动被替换掉
  • # 例如:以每一晚进行切割日志,保留30个文件
  • # file_handler = logging.handlers.TimedRotatingFileHandler(logs_path + filename, when='midnight', interval=1, backupCount=30)
  • file_handler.setLevel(logging.INFO)
  • file_handler.setFormatter(format)
  • # 只输出error级别的日志到文件,可以快速定位代码问题(运行时,即使没有日志输出结果,也会创建一个空的日志文件)
  • # error_file_handler = logging.handlers.TimedRotatingFileHandler(logs_path + 'error_' + filename, when='midnight', interval=1, backupCount=30)
  • # error_file_handler = logging.FileHandler(logs_path + 'error_' + filename)
  • # error_file_handler.setLevel(logging.ERROR)
  • # error_file_handler.setFormatter(format)
  • # 使用StreamHandler输出到屏幕
  • console = logging.StreamHandler()
  • console.setLevel(logging.INFO)
  • console.setFormatter(format)
  • # 添加处理器Handler到日志器中
  • cls.logger.addHandler(file_handler)
  • # cls.logger.addHandler(error_file_handler)
  • cls.logger.addHandler(console)
  • return cls.logger
  • if __name__ == "__main__":
  • logger = GetLog().get_log('logs')
  • logger.info("经营许可证字段值个数:%s", 3)
  • logger.info("经营许可证字段值个数:{}".format(333))
  • logger.error("错误的日志。。。。")

 

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门
本栏推荐