在 Flask 应用程序中,我们经常需要查看日志,轻松地跟踪应用程序的运行状况、调试应用程序,诊断问题。
一、使用 Flask 的内置日志记录器
使用 Flask 的内置日志记录器来启用日志记录。示例如下:
from flask import Flask
import logging
app = Flask(__name__)
app.logger.setLevel(logging.INFO)
@app.route('/')
def index():
app.logger.info('index route was called')
return 'Hello, World!'
核心代码就一句,非常方便。
app.logger.info('This is an info message')
二、使用 Python 的 logging 模块
在 Flask 应用程序中使用 Python 的 logging 模块,示例如下。
import logging
from flask import Flask
app = Flask(__name__)
# 配置日志记录器,日志级别为DEBUG
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# 配置日志处理器
handler = logging.FileHandler('app.log')
handler.setLevel(logging.DEBUG)
# 配置日志格式化器
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
# 添加日志处理器到日志记录器
logger.addHandler(handler)
# 定义路由
@app.route('/')
def index():
# 记录日志
logger.debug('index page accessed')
# 返回响应
return 'Hello, World!'
if __name__ == '__main__':
app.run()
在路由函数中,可以使用logger.debug()等方法来记录日志。日志记录器会将日志信息输出到指定的日志文件中。可以根据需要修改日志级别、日志处理器和日志格式化器等参数,以实现不同的日志记录需求。
以上是2种在 Flask 应用程序中记录日志的方法。可以根据自己的需要选择其中的一种。
Flask使用标准的Python日志模块来记录信息这个日志器可以被扩展并用于记录自定义的消息。为Flask应用程序实现一个灵活的事件日志系统,可以让你在应用程序执行时或遇到错误时知道出了什么问题。下图显示了Flask日志模块的不同部分,以及它们对处理应用日志的贡献。
Python日志模块使用了四个子模块。
- 日志器是记录来自你的应用程序的事件的主要接口。这些事件被记录下来后,被称为日志记录。
- 处理程序将日志事件/记录导向各自的目的地。
- 格式化器指定你的消息在被记录器写入时的布局。
- 过滤器帮助开发者使用参数管理日志记录。这些参数可以是日志级别之外的。
实现Flask日志记录器
日志允许开发人员用所采取的行动来监控程序的流程。你可以使用日志记录器来跟踪应用程序的流程,如跟踪电子商务应用程序中的交易数据或记录API调用与服务交互时的事件。
要在Flask中开始使用日志,首先从Python中导入日志模块。这个日志模块是Python安装时开箱即用的,不需要配置。Python日志模块会根据预先定义的级别记录事件。记录的日志事件被称为日志记录。每个记录级别都有不同的严重性级别。
- Debug : 10
- 信息:20
- 警告:30
- 错误。40
- 危急:50
只有当严重程度大于其日志级别时,日志记录器才会记录日志。然后,日志器将它们传递给处理程序。
这个片段显示了不同类型的日志器以及它们在Flask路由中的用法/
。
@app.route('/')
def main():
app.logger.debug("Debug log level")
app.logger.info("Program running correctly")
app.logger.warning("Warning; low disk space!")
app.logger.error("Error!")
app.logger.critical("Program halt!")
return "logger levels!"
你可以在app.py
文件中找到这个片段。当Flask应用程序运行时,在浏览器中导航到/
home路由,以查看日志。
下面是如何使用日志的方法。
Debug
为开发者提供详细的信息,以诊断程序的错误。Info
显示一个确认信息,说明程序的流程行为正在按照预期执行。Warning
显示发生了一些意想不到的事情,或在不久的将来可能会发生问题(例如,磁盘空间不足)。Error
显示一个严重的问题,如程序未能执行某些功能。Critical
显示应用程序中发生了严重的错误,如程序失败。
配置一个基本的记录仪
一个只提供基本功能的日志记录器对许多应用程序来说已经足够了。要在你的app.py
文件中配置这种类型的日志,请添加这个。
from flask import Flask
import logging
logging.basicConfig(filename='record.log', level=logging.DEBUG)
app = Flask(__name__)
@app.route('/')
def main():
# showing different logging levels
app.logger.debug("debug log info")
app.logger.info("Info log information")
app.logger.warning("Warning log info")
app.logger.error("Error log info")
app.logger.critical("Critical log info")
return "testing logging levels."
if __name__ == '__main__':
app.run(debug=True)
这段话根据DEBUG
中的级别指定Flask将在哪里记录你的应用程序。它还设置了当你使用Postman等客户端调用你的/
主路径时将会记录的消息。
注意:日志配置应该在你创建Flask应用对象之前完成。如果在配置之前访问app.logger
,它将使用默认的Python处理程序。
这种使用logging.basicConfig
的基本配置会记录消息,并将日志信息存储在一个.log
文件中。对于我们的示例项目,它是record.log
文件。
现在,使用这个命令执行你的Flask应用程序。
FLASK_APP=app.py flask run
打开你的客户端应用程序,并为正在运行的应用程序向你的路由发出一个GET
请求。在这种情况下,它是http://127.0.0.1:5000/
。当你程序中的main
函数被调用时,它会创建record.log
文件,然后将日志级别设为DEBUG。日志活动应该出现在文件record.log
,输出应该是这样的。
## record.log file output
DEBUG:app:debug log info
INFO:app:Info log information
WARNING:app:Warning log info
ERROR:app:Error log info
CRITICAL:app:Critical log info
INFO:werkzeug:127.0.0.1 - - [01/Mar/2022 12:35:19] "GET / HTTP/1.1" 200 -
你能够根据不同的记录仪级别操纵记录仪对象,使其记录所有配置的记录仪。当你为记录不同级别的信息设置了不同的记录器时,你可以禁止一些日志在控制台显示,而启用其他日志。对于这种配置在终端上打印出日志,你可以在记录日志的logging.basicConfig()
对象中删除文件配置filename='record.log'
。
虽然这些日志输出是可读的,但它们可能不是很有用,特别是你不知道事件发生的时间。为了解决这个问题,你可以给你的日志添加一个格式,如下一节所述。
格式化日志输出
Python格式化器将记录的结构格式化为特定的结构,使之易于阅读日志并将其与特定的事件联系起来。它可以在basicConfig
配置里面应用。
日志格式化器由以下配置组成。
%(asctime)s
将时间戳配置为一个字符串%(levelname)s
将日志级别配置为一个字符串。%(name)s
将记录器名称配置为字符串。%(threadName)s
是线程名称。%(message)s
将日志信息配置为字符串。
你可以将这些格式化选项应用于你的配置,以获得更准确的对象输出。
.........
logging.basicConfig(filename='record.log',
level=logging.DEBUG, format='%(asctime)s %(levelname)s %(name)s %(threadName)s : %(message)s')
app = Flask(__name__)
.........
使用前面片段中指定的format
配置,你的日志输出可以与特定的时间戳、特定的线程,甚至是特定的线程名相联系。当你运行应用程序并观察你的output.log
文件时,所产生的输出日志更有意义,看起来更干净。
日志级别有消息,但也有时间戳、日志的级别、应用程序的名称、进程的线程,最后是你定义的日志的消息。如果你遇到了一个错误,这使得你很容易通过时间戳来确定具体的进程、时间戳甚至是消息。这个过程在调试时比仅仅阅读普通的错误日志要有用得多。
现在,你已经用PythonbasicConfig
创建了日志,你可以为你的日志模块编写测试。
测试日志器
from flask import Flask
from app import app
import logging
import unittest
class TestLogConfiguration(unittest.TestCase):
"""[config set up]
"""
def test_INFO__level_log(self):
"""
Verify log for INFO level
"""
self.app = app
self.client = self.app.test_client
with self.assertLogs() as log:
user_logs = self.client().get('/')
self.assertEqual(len(log.output), 4)
self.assertEqual(len(log.records), 4)
self.assertIn('Info log information', log.output[0])
测试Python记录器与编写普通Python函数的测试几乎是一样的。要写第一个测试,创建一个名为test_app.py
的文件。打开它并添加你的第一个测试片段。
2022-03-01 13:09:11,787 DEBUG app Thread-3 : debug log info
2022-03-01 13:09:11,788 INFO app Thread-3 : Info log information
2022-03-01 13:09:11,788 WARNING app Thread-3 : Warning log info
2022-03-01 13:09:11,788 ERROR app Thread-3 : Error log info
2022-03-01 13:09:11,788 CRITICAL app Thread-3 : Critical log info
2022-03-01 13:09:11,788 INFO werkzeug Thread-3 : 127.0.0.1 - - [01/Mar/2022 13:09:11] "GET / HTTP/1.1" 200 -
在上面的测试片段中,我们使用test_client
,首先向/
路由发出请求,就像我们在运行我们的应用程序时做的那样,在做完这些之后,我们可以验证日志输出记录了INFO
水平的日志信息。正如智者所说,知道我们的测试是否运行的唯一方法是执行它们,我们可以在你选择的终端上用下面的命令来做。
pytest -s
审查你的运行结果。
恭喜你!你已经成功地执行了第一个测试。你已经成功地执行了你的第一个测试。现在你可以将你的测试扩展到应用程序中定义的其他日志级别。这里有一个例子。
def test_WARNING__level_log(self):
"""
Verify log for WARNING level
"""
self.app = app
self.client = self.app.test_client
with self.assertLogs() as log:
user_logs = self.client().get('/')
self.assertEqual(len(log.output), 4)
self.assertIn('Warning log info', log.output[1])
def test_ERROR__level_log(self):
"""
Verify log for ERROR level
"""
self.app = app
self.client = self.app.test_client
with self.assertLogs() as log:
user_logs = self.client().get('/')
self.assertEqual(len(log.output), 4)
self.assertIn('Error log info', log.output[2])
这些测试的是片段中每个不同阶段的日志级别。
注意: 日志对象包含更多的信息,然后可以根据应用程序的需要进行测试和断言。