目录

一,logging概述 

二,直接将日志打印在控制台

1,使用logging模块自带的日志打印方法

 2,使用logging模块创建对象

1)StreamHandler()

三,将日志输入到文件中

1,FileHandler()

2,TimedRotatingFileHandler() 


一,logging概述 

python中的logging模块和Java中的log4j一样,都是用来打印日志的。相信学习大数据的人在搭建集群的时候,有过配置好相关的文件,但是在启动集群时却启动失败,这个时候无疑是很令人头痛的,因为单单需要修改的文件就有四到五个,这个时候我们就需要去查看我们的日志文件以此来检查具体是哪里出现了问题,不然只能再去一个一个地查看那些文件内容才能够找到问题,有些时候有些问题还不是那种显而易见的,想想没有日志的话得有多恐怖,找错误能够找一天。

如果没有接触过大数据,但是接触了Android,亦或者是在使用pycharm等类型的开发环境进行编写代码后,出现的问题一般都会在控制台有报错显示,并且或多或少的带上了报错的级别,信息或时间等。日志的时候无处不在,可见掌握日志相关的操作是很有必要的,接下来我们去了解在python中的日志模块logging是怎么打印日志信息并将日志写入文件中。

二,直接将日志打印在控制台

日志按照级别可以从高到低分为:critical(批评)>error(错误)>warning(警告)>info(信息)>debug(调试)>notset (未设置)

在python中有两种方式用于将日志直接打印在控制台,一种是直接使用logging模块自带的方法来进行打印,另外一种就是去创建对象进行打印。接下来我们来看一下它们的具体使用。 

1,使用logging模块自带的日志打印方法

python的logging模块可以让我们直接使用它自带的方法来打印日志,但是这种方法并不推荐,因为它每打印一次日志,就是创建了一个对象,如果要打印不同级别的日志就需要调用不同的方法去生成一个对象,这样无疑是不大好的,但是它既然存在了,我们就需要知道有这么个东西,并且能够在必要的时候去使用它来打印日志。

之前我们也知道,日志都是有级别(等级)的,如果我们不去设置或者是修改输出日志的最低级别的话,它就会默认只输出warning及比它级别高的日志信息,即:warning,error,critical。

logging模块并不能够直接通过setLevel()去设置它的日志级别,但是我们可以通过basicConfig()去进行相应的设置。如下,当我们不设置日志的级别,但是使用logging来打印info,debug等的信息就不会显示出来:

# -*- encoding: utf-8 -*-
"""
@author:Low-level programmer
"""
import  logging
# 直接打印日志到控制台
if __name__ == '__main__':
    logging.debug("debug")          # 打印debug级别的信息
    logging.info("info")            # 打印info级别的信息
    logging.warning("warning")      # 打印warning级别的信息
    logging.error("error")          # 打印error级别的信息
    logging.critical("critical")    # 打印critical级别的信息

python 动态调整日志级别 python日志模块_python

 如上,我们还可以看到,使用logging模块创建的日志默认的日志名称为root,这个我们是无法去进行修改的,大家如果想要进行设置的话就需要去创建一个logger对象,但是就像之前提到的那样,我们是可以通过basicConfig方法去设置它输出日志的最低级别的,使其能够输出debug或者是info级别的日志信息:

# -*- encoding: utf-8 -*-
"""
@author:Low-level programmer
"""
import  logging
# 直接打印日志到控制台
if __name__ == '__main__':
    logging.basicConfig(level="DEBUG")   # 设置日志级别
    logging.debug("debug")          # 打印debug级别的信息
    logging.info("info")            # 打印info级别的信息
    logging.warning("warning")      # 打印warning级别的信息
    logging.error("error")          # 打印error级别的信息
    logging.critical("critical")    # 打印critical级别的信息

python 动态调整日志级别 python日志模块_python 动态调整日志级别_02

 2,使用logging模块创建对象

logging模块并不能直接使用它自己的模块名再加一个小括号的形式去创建对象即logger=logging(),但是我们可以通过logging模块下的getLogger()方法去创建一个logger对象,并且可以在创建对象的时候指定该日志的日志名称,也可以使用setLevel()方法去设置日志的输出级别,但是在python中的logger对象并不能够单独使用,它需要和一些处理器进行绑定才能够使一些设置生效,例如我们的logger对象是可以使用setLever方法来设置输出日志的最低级别,以及设置的日志名称,它们都不会生效:

# -*- encoding: utf-8 -*-
"""
@author:Low-level programmer
"""
import  logging
# 直接打印日志到控制台
if __name__ == '__main__':
    logger=logging.getLogger("mylogger")  # 创建一个日志对象并给一个日志名称
    logger.setLevel("DEBUG")  # 可以输出debug以上的日志级别信息
    logger.debug("debug")
    logger.info("info")
    logger.warning("warning")
    logger.error("error")
    logger.critical("critical")

python 动态调整日志级别 python日志模块_打印日志_03

使用一个对象的形式来输出打印日志信息需要结合其他处理器方能够展示它所有的功能。接下来我们去了解与之相关的几个处理器并让它们与logger对象一起绑定使用。

1)StreamHandler()

logging模块下的StreamHandler()方法可以创建一个控制台处理器,能够让我们之前的日志对象实现在控制台打印日志信息的功能,这个时候我们就需要使用到logger对象下的addHandler()方法来讲我们的logger对象和控制台处理器进行绑定:

# -*- encoding: utf-8 -*-
"""
@author:Low-level programmer
"""
import  logging
# 直接打印日志到控制台
if __name__ == '__main__':
    logger=logging.getLogger("mylogger")  # 创建一个日志对象并给一个日志名称
    logger.setLevel("DEBUG")  # 可以输出debug以上的日志级别信息
    ch=logging.StreamHandler()  # 创建控制台处理器
    logger.addHandler(ch)       # 将日志对象和控制台处理器进行绑定
    logger.debug("debug") 
    logger.info("info")
    logger.warning("warning")
    logger.error("error")
    logger.critical("critical")

python 动态调整日志级别 python日志模块_python 动态调整日志级别_04

看到这里相信大家也会有疑惑:为什么还是没有打印出来日志的名称?如果要解决这个问题,需要在创建好的的ch控制台处理器那里进行相应的设置才行,因为我们的logger对象就像个空壳的公司,只设置了名字,级别,但是具体的显示都没有,需要其他的处理器绑定在一起才行。

在设置之前,我们需要有的知识储备:

对于日志模块中的处理器来说,如果想要有自定义的日志输出格式的话,就需要使用logging模块下的Formatter方法来创建格式化对象,并将我们想要的格式传入进去,之后处理器只需要调用setFormater方法即可格式化成功:

# -*- encoding: utf-8 -*-
"""
@author:Low-level programmer
"""
import  logging
# 直接打印日志到控制台
if __name__ == '__main__':
    logger=logging.getLogger("mylogger")  # 创建一个日志对象并给一个日志名称
    logger.setLevel("DEBUG")  # 可以输出debug以上的日志级别信息
    ch=logging.StreamHandler()  # 创建控制台处理器
    format_str="日志名[%(name)s],日志级别[%(levelname)s]" \
               "日志信息[%(message)s],日志在代码中的行数[%(lineno)s]" \
               "日志打印的时间[%(asctime)s]"      # 需要格式化的字符串
    formatter=logging.Formatter(fmt=format_str)  # 创建格式对象
    ch.setFormatter(formatter)   # 将格式对象传入ch控制台处理器中
    logger.addHandler(ch)        # logger对象与ch控制台处理器进行绑定
    logger.debug("debug")
    logger.info("info")
    logger.warning("warning")
    logger.error("error")
    logger.critical("critical")

python 动态调整日志级别 python日志模块_日志打印_05

 如果对如上格式化中格式化串不大满意,还想要其他效果的可以参考如下内容,自己去打印自己想要的日志形式

%(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用户输出的消息

如上的日志打印都是在控制台上进行的,但是有些时候我们的日志信息需要写到文件中进行保存,而不是输出到控制台上(只要我们的pycharm软件一关闭该日志信息就会消失),接下来我们去接着了解日志模块中的日志写入文件中的相关操作。

三,将日志输入到文件中

如果我们想要将日志输入到文件中,就需要知道两个文件处理器,一个是logging模块下的FileHandler()只能够产生一个文件并且将所有的内容都写入到同一个文件中,另外一个是logging模块下的handlers中的TimedRotatingFileHandler()可以将我们的文件按照指定的时间来产生多个日期文件。接下来我们分别使用代码来了解它们。

1,FileHandler()

logging模块下的FileHandler()方法可以创建一个文件处理器对象,用于将我们之前输入到控制台的日志信息保存到相应的文件中。所以我们需要指定需要保存的文件路径及编码格式(防止出现乱码),创建好该处理器之后我们就可以将它与logger对象进行绑定:

# -*- encoding: utf-8 -*-
"""
@author:Low-level programmer
"""
import  logging
import os   # os模块与文件目录的操作有关
# 直接打印日志到控制台
if __name__ == '__main__':
    logger=logging.getLogger("mylogger")  # 创建一个日志对象并给一个日志名称
    logger.setLevel("DEBUG")  # 可以输出debug以上的日志级别信息
    ch=logging.StreamHandler()  # 创建控制台处理器
    format_str="日志名[%(name)s],日志级别[%(levelname)s]" \
               "日志信息[%(message)s],日志在代码中的行数[%(lineno)s]" \
               "日志打印的时间[%(asctime)s]"      # 需要格式化的字符串
    formatter=logging.Formatter(fmt=format_str)  # 创建格式对象
    path_name="./logs"  # 日志文件保存的目录
    if  not os.path.exists(path_name):
        os.mkdir(path_name)   # 如果该目录不存在则创建
    file_name="log.txt"          # 文件名
    fh=logging.FileHandler("logs/"+file_name,encoding="utf8")    # 创建文件处理器
    ch.setFormatter(formatter)   # 将格式对象传入ch控制台处理器中
    fh.setFormatter(formatter)   #  以指定的日志打印格式将日志输入到文件中
    logger.addHandler(ch)        # logger对象与ch控制台处理器进行绑定
    logger.addHandler(fh)        # logger对象与fh文件处理器进行绑定
    logger.debug("debug")
    logger.info("info")
    logger.warning("warning")
    logger.error("error")
    logger.critical("critical")

python 动态调整日志级别 python日志模块_python 动态调整日志级别_06

 现在我们在程序中使用while死循环来写入多条日志信息:

# -*- encoding: utf-8 -*-
"""
@author:Low-level programmer
"""
import  logging
import os   # os模块与文件目录的操作有关
# 直接打印日志到控制台
if __name__ == '__main__':
    logger=logging.getLogger("mylogger")  # 创建一个日志对象并给一个日志名称
    logger.setLevel("DEBUG")  # 可以输出debug以上的日志级别信息
    ch=logging.StreamHandler()  # 创建控制台处理器
    format_str="日志名[%(name)s],日志级别[%(levelname)s]" \
               "日志信息[%(message)s],日志在代码中的行数[%(lineno)s]" \
               "日志打印的时间[%(asctime)s]"      # 需要格式化的字符串
    formatter=logging.Formatter(fmt=format_str)  # 创建格式对象
    path_name="./logs"  # 日志文件保存的目录
    if  not os.path.exists(path_name):
        os.mkdir(path_name)   # 如果该目录不存在则创建
    file_name="log.txt"          # 文件名
    fh=logging.FileHandler("logs/"+file_name,encoding="utf8")    # 创建文件处理器
    ch.setFormatter(formatter)   # 将格式对象传入ch控制台处理器中
    fh.setFormatter(formatter)   #  以指定的日志打印格式将日志输入到文件中
    logger.addHandler(ch)        # logger对象与ch控制台处理器进行绑定
    logger.addHandler(fh)        # logger对象与fh文件处理器进行绑定
    while True:                  # 死循环,需要手动去暂停,不然就会一直运行到计算机的资源耗尽为止
        logger.debug("debug")
        logger.info("info")
        logger.warning("warning")
        logger.error("error")
        logger.critical("critical")

python 动态调整日志级别 python日志模块_pycharm_07

 如上,我们可以发现不管我们的程序运行了多久,产生的日志信息始终都是写入同一个文件中,不能说这样的方式不好,只是有些时候我们查看日志的时候并不需要查看之前或者是更久之前的日志信息,那么怎样才能够让日志信息能够按照时间的不同而进行区分开?虽然不能够直接使用python中的logging模块来创建时间文件,但是我们可以导入logging模块下的handler来得以使用TimedRotatingFileHandler()方法进行创建时间回滚日志文件来实现我们想要的功能。接下来我们来认识它。

2,TimedRotatingFileHandler() 

TimedRotatingFileHandler()方法其实和FileHandler()一样都是要创建文件来保存我们的日志信息,但是TimedRotatingFileHandler()不仅可以传入文件名,编码格式,还可以指定文件的前缀(file_name)和后缀(suffix),多长时间创建一个日志文件(when),间隔时间(interval,但是一般很少进行设置,直接默认使用默认值1即可),保留日志个数(backupcount)等。

对于如上提到的几个TimedRotatingFileHandler()中的成员变量对应的含义如下:

filename:是输出日志文件名的前缀

when:是一个字符串的定义:
            “S”: Seconds
            “M”: Minutes
            “H”: Hours
            “D”: Days
            “W”: Week day (0=Monday)
            midnight”: Roll over at midnight

        interval: 是指等待多少个单位when的时间后,Logger会自动重建文件,默认是1,当然,这个文件的创建取决于filename+suffix,若这个文件跟之前的文件有重名,则会自动覆盖掉以前的文件,所以有些情况suffix要定义的不能因为when而重复。

        backupCount: 是保留日志个数。默认的0是不会自动删除掉日志。若设10,则在文件的创建过程中,会判断是否有超过这个10,若超过,则会从最先创建的开始删除。

        除了上述参数之外,TimedRotatingFileHandler还有两个比较重要的成员变量,它们分别是 suffix 和 extMatch 。

        suffix 是指日志文件名的后缀,suffix中通常带有格式化的时间字符串,filename和suffix由“.”连接构成文件名(例如:filename=“runtime”, suffix=“%Y-%m-%d.log”,生成的文件名为runtime.2015-07-06.log)。

接下来我们就使用这些成员变量去创建定时旋转文件处理程序文件:

# -*- encoding: utf-8 -*-
"""
@author:Low-level programmer
"""
import  logging
# 直接打印日志到控制台
import  os
from logging.handlers import TimedRotatingFileHandler

if __name__ == '__main__':
    logger=logging.getLogger("mylogger")  # 创建一个日志对象并给一个日志名称
    logger.setLevel("DEBUG")  # 可以输出debug以上的日志级别信息
    ch=logging.StreamHandler()  # 创建控制台处理器
    format_str="日志名[%(name)s],日志级别[%(levelname)s]" \
               "日志信息[%(message)s],日志在代码中的行数[%(lineno)s]" \
               "日志打印的时间[%(asctime)s]"      # 需要格式化的字符串
    formatter=logging.Formatter(fmt=format_str)  # 创建格式对象
    path_name="./logs"
    if not os.path.exists(path_name):
        os.mkdir(path_name)  # 如果当前工作目录下该logs目录不存在则进行创建
    file_suffix_name="logs/log."  # 时间日志文件的文件名
    tfh=TimedRotatingFileHandler(file_suffix_name,when="S",encoding="utf8")   # 创建定时旋转文件处理程序文件对象
    ch.setFormatter(formatter)   # 将格式对象传入ch控制台处理器中
    tfh.setFormatter(formatter)   # 将格式对象传入tfh定时选择文件处理器中
    logger.addHandler(ch)        # logger对象与ch控制台处理器进行绑定
    logger.addHandler(tfh)       # logger对象与tfh定时旋转文件处理器进行绑定
    while True:   # 程序运行得很快,可能就一两秒就结束了,所以为了直观的看到定时旋转日志文件的创建,这里使用了死循环
        logger.debug("debug")
        logger.info("info")
        logger.warning("warning")
        logger.error("error")
        logger.critical("critical")

python 动态调整日志级别 python日志模块_pycharm_08

 到这里python中的日志模块logging的内容就先告一段落了。