在程序中,DEBUG是经常要进行的事情。需要把Debug信息打印到控制台中。比如,可以使用print()完成。

class Pizza():
    def __init__(self, name, price):
        self.name = name
        self.price = price
        print("Pizza created: {} (${})".format(self.name, self.price))

    def make(self, quantity=1):
        print("Made {} {} pizza(s)".format(quantity, self.name))

    def eat(self, quantity=1):
        print("Ate {} pizza(s)".format(quantity, self.name))

pizza_01 = Pizza("artichoke", 15)
pizza_01.make()
pizza_01.eat()

pizza_02 = Pizza("margherita", 12)
pizza_02.make(2)
pizza_02.eat()

#Output
Pizza created: artichoke ($15)
Made 1 artichoke pizza(s)
Ate 1 pizza(s)
Pizza created: margherita ($12)
Made 2 margherita pizza(s)
Ate 1 pizza(s)

这种方式虽然简单,但是收到很多限制,例如不能将所有信息按照等级进行分类。

而Python标准库中的logging模块为我们提供了新型的工具。

>>> import logging
>>> logging.debug('test debug')    #debug和info级默认不返回信息
>>> logging.info('test info') 
>>> logging.warning('test warning')    #默认返回信息的级别
WARNING:root:test warning
>>> logging.error('test error')
ERROR:root:test error
>>> logging.critical('test critical')
CRITICAL:root:test critical


logging模块中的日志级别等级和顺序分别是:critical > error > warning > info > debug

默认是warning级别。


如果不使用print函数,改用logging模块,可以这么做。将上面的类Pizza中所有的print函数删除,改用logging模块的函数。

import logging

logging.basicConfig(level=logging.DEBUG)

class Pizza:
...


这里使用的logging.basicConfig(),主要参数有三个:

filename:指定文件名,日志会被存储到此文件中,如果不指定,则默认输出到控制台

filemode:默认filemode的默认值"a",表示append,也可以指定为"w"

level,一共5个级别,critical(50)>error(40)>warning(30)>info(20)>debug(10),默认级别为Warning,这里可以用对应的数值表示level

如下写法效果相当,都是要将信息输出到指定文件

logging.basicConfig(filename="example.log", level=logging.DEBUG) 
# logging.basicConfig(filename="example.log", level=logging.DEBUG, filemode="w") 
# logging.basicConfig(filename="example.log", level=10, filemode="w") 
替代了所有print之后的程序,完整呈现如下:
#coding:utf-8
import logging
logging.basicConfig(level=logging.DEBUG)

class Pizza:
    def __init__(self, name, price):
        self.name = name
        self.price = price
        #print("Pizza created: {} (${})".format(self.name, self.price))
        logging.debug("Pizza created: {} (${})".format(self.name, self.price))
    def make(self, quantity=1):
        #print("Made {} {} pizza(s)".format(quantity, self.name))
        logging.debug("Made {} {} pizza(s)".format(quantity, self.name))

    def eat(self, quantity=1):
        #print("Ate {} pizza(s)".format(quantity, self.name))
        logging.debug("Ate {} pizza(s)".format(quantity, self.name))

pizza_01 = Pizza("artichoke", 15)
pizza_01.make()
pizza_01.eat()

pizza_02 = Pizza("margherita", 12)
pizza_02.make(2)
pizza_02.eat()

#output
$ python3.7 exalog2.py
DEBUG:root:Pizza created: artichoke ($15)
DEBUG:root:Made 1 artichoke pizza(s)
DEBUG:root:Ate 1 pizza(s)
DEBUG:root:Pizza created: margherita ($12)
DEBUG:root:Made 2 margherita pizza(s)
DEBUG:root:Ate 1 pizza(s)
DEBUG是日志信息的级别,结合root,指的是Python模块的级别。logging模块还能设置不同的日志记录器,程序中的不同部分使用不同的日志记录器。
>>> import logging
>>> logger1 = logging.getLogger("Module_1")    #创建一个日志记录器
>>> logger2 = logging.getLogger("Module_2")    #再创建一个
>>> logger1.debug("Module 1 debug")
>>> logger2.debug("Module 1 debug")
以上是将日志信息输出到控制台。如果输出到文件,则可用如下方式。
#coding:utf-8
import logging
logging.basicConfig(filename='test.log', level=logging.DEBUG)    #add filename='test.lgo'

class Pizza:
    def __init__(self, name, price):
        self.name = name
        self.price = price
        #print("Pizza created: {} (${})".format(self.name, self.price))
        logging.debug("Pizza created: {} (${})".format(self.name, self.price))
    def make(self, quantity=1):
        #print("Made {} {} pizza(s)".format(quantity, self.name))
        logging.debug("Made {} {} pizza(s)".format(quantity, self.name))

    def eat(self, quantity=1):
        #print("Ate {} pizza(s)".format(quantity, self.name))
        logging.debug("Ate {} pizza(s)".format(quantity, self.name))

pizza_01 = Pizza("artichoke", 15)
pizza_01.make()
pizza_01.eat()

pizza_02 = Pizza("margherita", 12)
pizza_02.make(2)
pizza_02.eat()


查看test.log文件,会看到日志信息。

还可以继续增加logging.basicConfig()的参数,比如增加格式,修改如下:

#coding:utf-8

import logging
logging.basicConfig(
    filename='test.log', 
    level=logging.DEBUG,
    format="%(asctime)s: %(levelname)s: %(message)s"
    )

class Pizza:
    def __init__(self, name, price):
        self.name = name
        self.price = price
        logging.debug("Pizza created: {} (${})".format(self.name, self.price))
    def make(self, quantity=1):
        logging.debug("Made {} {} pizza(s)".format(quantity, self.name))

    def eat(self, quantity=1):
        logging.debug("Ate {} pizza(s)".format(quantity, self.name))

pizza_01 = Pizza("Scilian", 18)
pizza_01.make()
pizza_01.eat()

pizza_02 = Pizza("quattro formaggi", 16)
pizza_02.make(2)
pizza_02.eat()
再次运行之后,查看test.log文件,发现每次运行之后的日志,都是追加方式的。
 
调试是项目中很重要的环节。logging模块提供了程序运行中事务追踪的功能,可以将相关信息输出到控制台和文件,从而了解程序运行过程中发生了什么事情。