简单使用
import logging
logging.warning("test log")
这行代码会在 控制台 输出 “ WARNING:root:test log”。
但,众所周知,日志是有级别的。
logging的默认级别是 warning,所以如果直接输入 longging.info(“test info”),控制台是不会有输出的。
设置默认日志级别
import logging
logging.basicConfig(level=logging.DEBUG)
logging.debug("test debug log")
将日志级别设置为 debug,所以控制台会有输出
输出到文件
import logging
logging.basicConfig(filename="test.log")
logging.warning("test filelog")
此时,控制台不再有输出,而是输出到 test.log 文件。
import logging
logging.basicConfig(filename="test.log",level=logging.DEBUG)
logging.debug("test debug file log")
debug 日志写入 文件 test.log
日志格式化输出
默认格式是 “%(levelname)s:%(name)s:%(message)s”
import logging
logging.basicConfig(format="%(asctime)s - %(levelname)s - %(name)s : %(message)s")
logging.warning("test format message")
还可额外指定 时间格式:
logging.basicConfig(format=”%(asctime)s - %(levelname)s - %(name)s : %(message)s”, datefmt=”%x %x “)
以上足够满足简单的开发日志使用了。
logging 模块提供了四大组件:logger、handler、format、filter,用来满足一些高级需求。
logger 是日志接口、写日志时就用它。logging.info() 这个方法实际上用的是 默认的 logger, logging可以有多个 logger。
每个 logger 有对应的 handler 时,才会输出日志。logger 可以有多个 handler。
handler 可以设置输出格式 format、级别、和过滤器 filter。
logger 和 handler 是 多对多 关系。
只有 logger 是真正被调用的,其他三项都可以说是配置项,在初始化日志模块的时候配置好就可以了。
logger
testlogger = logging.getLogger(“testlogname”)
这是获取 logger 对象的方法,当 “testlogname” 不存在时,会创建一个新的 logger 并返回,否则返回已有的 logger。这跨模块的 logger 的基础。
logger 的名字可任意取,但最好用 . 分割层级,以便 logging 在层级间传递日志。
例如:myApp.myModule.myFile
myAppLog = logging.getLogger(“myApp”)
myModuleLog = logging.getLogger(“myApp.myModule”)
myFileLog = logging.getLogger(“myApp.myModule.myFile”)
#再写入日志
myAppLog.warning("my app log")
myModuleLog .warning("my modulelog")
myFileLog .warning("my file log")
此时,”my app log” 只会写入 myAppLog,”my modulelog” 写入 myModuleLog 和 myAppLog,”my file log” 写入 myFileLog 、myModuleLog 、和 myAppLog。
以上是伪码,后续有完整代码。
handler 、format
光生成了 logger 其实还无法输出日志的,logger 只有与 handler 绑定了,才会有输出,handler 定义了输出的 目的地(控制台、文件、网络、邮件等)、格式、级别、过滤器等
例如,创建一个输出到文件的 handler:
filehandler = logging.FileHandler("file.log")
# 设置 handler 的输出级别
filehandler.setLevel(logging.DEBUG)
# 设置 handler 的输出格式
fileformatter = logging.Formatter("%(asctime)s - %(levelname)s - %(name)s : %(message)s")
filehandler.setFormatter(fileformatter)
# 将 logger 关联 handler
logger.addHandler(filehandler)
# 然后 logger 输入的日志,就通过 filehandler 写入文件 file.log 了。
logger.info("a file log")
logger 和 handler
一个 logger、可以输出到 多个 handler。
一个 handler、可以接受多个 logger 的输出。
import logging
# 创建 有父子关系 的 logger,loggerFather -> loggerChild ,设置级别
loggerFather = logging.getLogger("fatherlog")
loggerChild = logging.getLogger("fatherlog.childlog")
loggerFather .setLevel(logging.DEBUG)
loggerChild .setLevel(logging.DEBUG)
#再创建两个 文件 handler,分别设置级别和 format
fatherhandler = logging.FileHandler("father.log")
childhandler = logging.FileHandler("child.log")
fatherhandler.setLevel(logging.DEBUG)
childhandler.setLevel(logging.DEBUG)
formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(name)s : %(message)s")
# 将父子 logger 分别提添加 对应的 handler
loggerFather.addHandler(fatherhandler)
loggerChild .addHandler(childhandler)
# 写入日志
loggerFather.debug("test father log")
loggerChild .debug("test child log")
# 打开 father.log ,既有 loggerFather 的日志,也有 loggerChild 的日志
# 打开 child.log,只有 loggerChild 的日志
# logger/handler 多对多关系测试。再创建另一个 logger,同时添加 fatherhandler 、childhandler
loggerother = logging.getLogger("otherlog")
loggerother.setLevel(logging.DEBUG)
loggerother.addHandler(fatherhandler)
loggerother.addHandler(childhandler )
loggerother.debug("test other log")
# father.log 和 child.log 都有 loggerother 的日志。
时间自动切片
import logging
import logging.handlers
logger = logging.getLogger('mylover')
logger .setLevel(logging.DEBUG)
format = logging.Formatter(fmt="%(asctime)s-%(levelname)s-%(name)s-%(message)s", datefmt="%x %X")
handler = logging.handlers.TimedRotatingFileHandler('test.log', when='D', interval=1,backupCount=30)
handler.setFormatter(format )
handler.setLevel(logging.DEBUG)
logger.addHandler(handler )
TimedRotatingFileHandler(‘test.log’, when=’D’, interval=1,backupCount=30)
when=’D’:表示按天计算时间间隔
interval=1:表示 1 个 when 之后就进行切片
backupCount=30:表示最多保留 30 个历史日志切片文件
至此,满足大多数 product 场景的日志功能。拿来主义,就此打住。
但是,logging 还有其他的功能,打住只不过是不继续深究而已,logging 还能做哪些事情仍然需要有所了解。
1、日志配置从文件读取
2、自定义日志级别
3、日志自动分片
4、build-in handler
● 控制台 handler
● 大小自动分片 handler
● 邮件 handler
● http handler
● syslog handler
……
附一个我在用的 flask log 配置:
import logging
applogger = logging.getLogger('myApp')
apploggerformat = logging.Formatter(fmt="%(asctime)s-%(levelname)s-%(name)s-%(message)s", datefmt="%x %X")
apploggerhandler = logging.handlers.TimedRotatingFileHandler('/var/log/myApp/myApp.log', when='D', interval=1,backupCount=30)
apploggerhandler.setFormatter(apploggerformat)
if app.debug:
apploggerhandler.setLevel(logging.DEBUG)
applogger.setLevel(logging.DEBUG)
else:
apploggerhandler.setLevel(logging.WARNING)
applogger.setLevel(logging.WARNING)
loggers = [applogger, app.logger, logging.getLogger('sqlalchemy')]
[logger.addHandler(apploggerhandler) for logger in loggers]