使用logging模块打印日志

logging模块是python里面用来操作日志的模块

logging模块中主要有4个类:

  1. Logger 记录器,暴露了应用程序代码能直接使用的接口;
  2. Handler 处理器,将(记录器产生的)日志记录发送至合适的目的地

StreamHandler 控制台输出
FileHandler 文件输出
TimedRotatingFileHandler 按照时间自动分割日志文件
RotatingFileHandler 按照大小自动分割日志文件,一旦达到指定的大小重新生成文件

  1. Filter 过滤器,提供了更好的粒度控制,它可以决定输出哪些日志记
  2. Formatter 格式化器,指明了最终输出中日志记录的布局。指定输出日志的格式

日志级别

debug < info < warning < error < critical,设置了日志级别之后,会打印该级别以及比该级别高的所有日志,一般为方便测试都设置为debug

logging.debug(‘debug级别,最低级别,一般开发人员用来打印一些调试信息’)
logging.info(‘info级别,正常输出信息,一般用来打印一些正常的操作’)
logging.warning(‘waring级别,一般用来打印警信息’)
logging.error(‘error级别,一般用来打印一些错误信息’)
logging.critical(‘critical级别,一般用来打印一些致命的错误信息’)

日志输出格式

指定日志的输出格式,比较常用的格式的如下:
%(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: 打印日志信息

格式用法:

format='%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s'

这个格式可以输出日志的打印时间,是哪个文件第几行输出的,输出的日志级别是什么,以及输入的日志内容。

日志模块用法详解

import logging
from logging import handlers
logger = logging.getLogger('my_log')
#先创建一个logger对象,相当于这个办公室,也就是上面说的Logger
logger.setLevel(logging.INFO)#设置日志的总级别
fh = logging.FileHandler('test.log',mode='a',encoding='utf-8')#创建一个文件处理器,也就是把日志写到文件里头
fh.setLevel(logging.INFO)#设置文件输出的级别
sh = logging.StreamHandler()#创建一个控制台输出的处理器,这两个就是上面说的Handler
sh.setLevel(logging.INFO)
#设置控制台输出的日志级别,这两个级别都可以单独设置,他们俩和logger的级别区别是如果logger设置的级别比里面的handler级别设置的高,那么就以logger的级别为准
th = handlers.TimedRotatingFileHandler('time',when='S',interval=1,backupCount=2)
#指定间隔时间自动生成文件的处理器
#interval是时间间隔,backupCount是备份文件的个数,如果超过这个超过这个个数,就会自动删除,when是间隔的时间单位,单位有以下几种:
            # S 秒
            # M 分
            # H 小时、
            # D 天、
            # W 每星期(interval==0时代表星期一)
            # midnight 每天凌晨
th.setLevel(logging.INFO)
formater = logging.Formatter('%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s')
#指定日志格式,上面咱们写了常用的格式,直接指定了就行了,这也就是咱们上面说的Formatter
sh.setFormatter(formater)
fh.setFormatter(formater)
th.setFormatter(formater)
#设置两个处理器的日志格式
 
logger.addHandler(sh)
logger.addHandler(fh)
logger.addHandler(th)
#把两个handler加入容器里头,相当于把工作人员培训完了,你们可以上班了
logger.debug('debug级别,最低级别,一般开发人员用来打印一些调试信息')
logger.info('info级别,正常输出信息,一般用来打印一些正常的操作')
logger.warning('waring级别,一般用来打印警信息')
logger.error('error级别,一般用来打印一些错误信息')
logger.critical('critical级别,一般用来打印一些致命的错误信息')

封装一个类来使用logging模块1

import logging
from logging import handlers
class Logger(object):
    level_relations = {
        'debug':logging.DEBUG,
        'info':logging.INFO,
        'warning':logging.WARN,
        'error':logging.ERROR,
        'crit':logging.CRITICAL
    }#日志级别关系映射
    def __init__(self,fp,level='debug',when='midnight',interval=1,backCount=5,encoding='utf-8'):
        '''
 
        :param fp:日志文件路径
        :param level: 日志级别 默认是debug
        :param when: 分割日志的单位 S 秒、M 分、 H 小时、 D 天、 W 每星期(interval==0时代表星期一)、midnight 每天凌晨
        :param interval: 时间间隔 默认每天凌晨
        :param backCount: 备份文件个数 默认5个
        :param encoding: 日志文件编码
        '''
        self.level = self.level_relations.get(level)
        self.logger = logging.getLogger(fp)
        self.logger.setLevel(self.level)
        fmt = logging.Formatter('%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s')
        sh = logging.StreamHandler()
        sh.setFormatter(fmt)
        sh.setLevel(self.level)
        th = handlers.TimedRotatingFileHandler(fp,when=when,interval=interval,backupCount=backCount,encoding=encoding)
        th.setFormatter(fmt)
        th.setLevel(self.level)
        self.logger.addHandler(th)
        self.logger.addHandler(sh)
    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 crit(self,msg):
        self.logger.critical(msg)
if __name__ == '__main__':
    l = Logger('a.log')#实例化
    l.info('hehehe')#调用

封装一个类来使用logging模块2

# -*-coding:utf-8 -*-
import os
import logging
from logging.handlers import TimedRotatingFileHandler
from getbasepath import GetBasePath

# log_path是存放日志的路径
log_path = os.path.join(GetBasePath.get_base_path(), 'logs')
# 如果不存在这个logs文件夹,就自动创建一个
if not os.path.exists(log_path):
    os.mkdir(log_path)


class MyLog:
    def __init__(self):
        # 文件的命名
        self.log_name = os.path.join(log_path, 'log')
        self.logger = logging.getLogger()
        self.logger.setLevel(logging.DEBUG)
        # 最多存放日志的数量
        self.backup_count = 30
        # 日志输出格式
        self.formatter = logging.Formatter('[%(asctime)s] - %(filename)s - %(processName)s] - %(levelname)s: %(message)s')

    def __console(self, level, message):
        # 创建一个FileHandler,用于写到本地
        # fh = logging.FileHandler(self.log_name, 'a')  # 追加模式  这个是python2的
        # fh = logging.FileHandler(self.log_name, 'a', encoding='utf-8')  # 这个是python3的
        # 每天重新创建一个日志文件,最多保留backup_count份
        fh = TimedRotatingFileHandler(filename=self.log_name, when='D', interval=1,
                                      backupCount=self.backup_count, delay=True, encoding='utf-8')
        fh.setLevel(logging.DEBUG)
        fh.setFormatter(self.formatter)
        self.logger.addHandler(fh)

        # 创建一个StreamHandler,用于输出到控制台
        ch = logging.StreamHandler()
        ch.setLevel(logging.DEBUG)
        ch.setFormatter(self.formatter)
        self.logger.addHandler(ch)

        if level == 'info':
            self.logger.info(message)
        elif level == 'debug':
            self.logger.debug(message)
        elif level == 'warning':
            self.logger.warning(message)
        elif level == 'error':
            self.logger.error(message)

        # 这两行代码是为了避免日志输出重复问题
        self.logger.removeHandler(ch)
        self.logger.removeHandler(fh)
        # 关闭打开的文件
        fh.close()

    def debug(self, message):
        self.__console('debug', message)

    def info(self, message):
        self.__console('info', message)

    def warning(self, message):
        self.__console('warning', message)

    def error(self, message):
        self.__console('error', message)


if __name__ == "__main__":
    log = MyLog()
    log.info("---测试开始----")
    log.info("操作步骤1,2,3")
    log.warning("----测试结束----")
# 日志文件的配置 config.logging.yaml
version: 1
disable_existing_loggers: False
formatters:
        simple:
            format: "%(asctime)s - %(name)s - %(levelname)s - %(lineno)s-%(message)s"
handlers:
    console:
            class: logging.StreamHandler
            level: DEBUG
            formatter: simple
#            stream: ext://sys.stdout
    file:
            class: toolkit.custom_logging_handle.AUTOTimeRotatingFileHandler
            level: DEBUG
            formatter: simple
            when: midnight
            suffix: "%Y-%m-%d.log"
            filename: ./logs/info.log
#            maxBytes: 10485760
            backupCount: 30
            encoding: utf8
    error_file:
            class: logging.handlers.RotatingFileHandler
            level: ERROR
            formatter: simple
            filename: ./logs/errors.log
            maxBytes: 10485760
            backupCount: 20
            encoding: utf8
loggers:
    uiautotest:
            level: DEBUG
            handlers: [console,file,error_file]
            propagate: no
root:
    level: DEBUG
    handlers: [console,file,error_file]


# 在主程序中配置日志
BASE_PATH = basepath.get_base_path()   # 获取项目的基础路径
LOGGING_CONFIG = os.path.join(BASE_PATH, "config", "logging.yaml"

def setup_logging(default_path=LOGGING_CONFIG, default_level=logging.INFO, env_key="LOG_CFG"):
    path = default_path
    value = os.getenv(env_key, None)
    if value:
        path = value
    if os.path.exists(path):
        with open(path, "r", encoding='utf-8') as f:
            config = yaml.safe_load(f)
            print(config)
            dictConfig(config)
    else:
        logging.basicConfig(level=default_level)

参考文章:

  1. https://www.cnblogs.com/sriba/p/8043538.html
  2. https://blog.csdn.net/qq_44614026/article/details/119985629 --解决打印行号固定的问题
  3. https://www.cnblogs.com/ydf0509/p/10502683.html --后续优化方向
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值