logging日志模块

7-06 456 views

一、日志输出合理的必要性
日式收集使我们日常工作中都会遇到的问题,而一个好的日志输出,则会给收集工作带来大大的效率提升。同时能够给程序员自己排错带来方便。那么python程序中logging模块是如何实现规范的日志信息输出呢,让我们深入了解下。

二、简单的将日志输出到控制台,了解日志的相关级别设定

DEBUG:程序调试bug时使用
INFO:程序正常运行时使用
WARNING:程序未按预期运行时使用,但并不是错误,如:用户登录密码错误
ERROR:程序出错误时使用,如:IO操作失败
CRITICAL:特别严重的问题,导致程序不能再继续运行时使用,如:磁盘空间为空,一般很少使用
默认的是WARNING等级,当在WARNING或WARNING之上等级的才记录日志信息。
日志等级从低到高的顺序是: DEBUG < INFO < WARNING < ERROR < CRITICAL 下面我这有个小例子。 import logging #日志时间,主题,级别及日志信息(设置level=logging.INFO 则大于等于info级别的信息才输出) logging.basicConfig(level=logging.INFO,format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') #日志主题定义 logger= logging.getLogger("日志主题") logger.info("Start print log") logger.debug("Do something") logger.warning("Something maybe fail.") logger.info("Finish") logger.error("oh this is fuck error")
可以看出只有debug信息没输出来。

logging.basicConfig函数各参数:
filename:指定日志文件名;
filemode:和file函数意义相同,指定日志文件的打开模式,’w’或者’a’; 写入和追加写入
format:指定输出的格式和内容,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被忽略;

三、将日志写入到文件里面,产生模拟的日志文件
创建一个FileHandler,并对输出消息的格式进行设置,将其添加到logger,然后将日志写入到指定的文件中


#!/usr/bin/env python3
# encoding: utf-8

"""
@version: Python 3.8.2
@author: ycy
@file: log-test.py
@time: 2020/6/20 16:16
"""
import logging

#日志主题定义
logger= logging.getLogger("__name__")

#设置日志级别
logger.setLevel(level = logging.DEBUG)

#日志写入路径
handler = logging.FileHandler("log.txt",'a',encoding='utf-8')

#设置日志级别
handler.setLevel(level=logging.DEBUG)

#日志时间,主题,级别及日志信息
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

handler.setFormatter(formatter)
logger.addHandler(handler)

logger.info("Start print log")
logger.debug("Do something")
logger.warning("Something maybe fail.")
logger.error("Something maybe Error")
logger.info("Finish")


可以看到文件里debug–>error的信息都有写入

四、在介绍下logging的鸡肋功能RotatingFileHandler日志回滚
为啥说它是鸡肋功能呢?它通过backupCount设定值备份日志的值,这种会丢失(N+1)个日志文件大小之前的日志信息。
比如backupCount设置为3,那它只会保留4份日志信息。超过你设定的日志大小阈值时,会清理掉最后一个日志文件

#!/usr/bin/env python3
# encoding: utf-8

"""
@version: Python 3.8.2
@author: ycy
@file: log-test.py
@time: 2020/6/20 16:16
"""
import logging
from logging.handlers import RotatingFileHandler

#日志主题定义
logger= logging.getLogger("__name__")

#设置日志级别
logger.setLevel(level = logging.DEBUG)

#定义一个RotatingFileHandler,最多备份3个日志文件,每个日志文件最大1k(方便测试将大小调整的比较小)
rHandler = RotatingFileHandler("log.txt",maxBytes = 1*1024,backupCount = 3)
rHandler.setLevel(logging.DEBUG)

#日志时间,主题,级别及日志信息
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
rHandler.setFormatter(formatter)

logger.addHandler(rHandler)

logger.info("Start print log")
logger.debug("Do something")
logger.warning("Something maybe fail.")
logger.error("Something maybe Error")
logger.info("Finish")

可以看到只保留了3个日志文件备份。之前的日志会被清理。若你要无限保留,可以将backupCount及maxBytes值调整的很大,但是意义不大,我的建议是不使用这种日志回滚方式,因为存在日志丢失的情况。建议将日志输出文件已日期时间变量命名,这种既能保留全部日志,又能做为日志的切割使用。若不需要旧的日志还可以写个脚本,批量删除掉几个月前的日志

五、将logging写成一个类文件,方便其他程序调用它输出日志。
这个类最好有写入,也有控制台输出,这样可以方便你后期调试程序代码。不然你看报错还得去日志文件里看,但是后期调试完毕,需要记得在程序文件将终端输出的命令注释掉。

import logging

class Loggerfile(object):
    def __init__(self,file_path,level,topic=None):
        file_handler = logging.FileHandler(file_path,'a',encoding='utf-8')
        fmt = logging.Formatter(fmt="%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s")
        file_handler.setFormatter(fmt)

        self.logger = logging.Logger(topic,level=level)
        self.logger.addHandler(file_handler)
    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)


class Loggerconsole(object):
    def __init__(self,level,topic=None):
        console_handler = logging.StreamHandler()
        fmt = logging.Formatter(fmt="%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s")
        console_handler.setFormatter(fmt)

        self.logger = logging.Logger(topic,level=level)
        self.logger.addHandler(console_handler)
    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)




if __name__ == '__main__':
    logger = Loggerfile('test.log',logging.DEBUG,'日志主题')
    logger.info('我是日志信息info')
    # logger.error('我是日志信息Error')
    # logger.debug('我是日志信息Debug')
    loggerconsole = Loggerconsole(logging.INFO,'终端日志输出主题')
    loggerconsole.info('我是终端输出日志info')

可以看到我定义了2个类,一个日志写入类,一个终端输出类。
下面我使用其他脚本,调用这个类文件

#!/usr/bin/env python3
# encoding: utf-8

"""
@version: Python 3.8.2
@author: ycy
@file: logimport.py.py
@time: 2020/7/2 11:02
"""
import logging
import time
#导入类文件(就是上面的py文件名称,在同一级目录下,不在同一级目录下需要使用from XXX目录名 import py脚本名)
import logtest
now_time = time.strftime("%Y%m%d", time.localtime(time.time()))


def running():
#调用写入类
    logger=logtest.Loggerfile('{}-test.log'.format(now_time),logging.DEBUG,'我是调用的日志主题')
    logger.debug("我是调用的一个debug信息")
    logger.info("我是调用的一个Info信息")
#调用终端输出类
    loggerconsole=logtest.Loggerconsole(logging.INFO,'我是调用的日志主题console终端输出')
    loggerconsole.info('我是调用的日志console终端info信息')


if __name__ == '__main__':
    running()

我这里通过的是now_time这个变量写入日志文件,保证日志文件完整,有能按日切割。
好的,logging模块的简单使用就到这里了,感谢大家阅读。

python的zipfie简单应用

一、场景案例 需求:当开发上传某一个zip包时,自动解压到当前目录。已经解压过得zip包不再解压! 此处用到的模块有Python3自有模块os,sys,time,json,re,zipf...

阅读全文

vip电影的解析

一、出现的原因 由于各大互联网视频app均推出了“轻奢主义”的营销模式,导致了很多优质视频需要我们办这个月卡、年卡才能观看,更离谱的是腾讯最近推出了会员...

阅读全文

python参数

一、位置参数 调用函数时根据函数定义的参数位置来传递参数。 #!/usr/bin/env python # coding=utf-8 def print_hello(name, sex): sex_dict = {1...

阅读全文

欢迎留言