日志
日志是一个商业网站必备的功能,用日志可以记录网站运行中产生的信息,这些信息包括网站运行时产生的异常或用户行为等,具体情况如下。
-
用户相关的行为:如登录、退出登录、注册、找回密码、不正确的密码尝试等。通过日志记录和分析用户的行为,可以提高网站用户体验以及发现非法登录等。
-
补充数据库记录:如后台用户谁禁用了帖子、谁添加了新员工。这些在数据库中没有记录的,可以用日志补充记录。
-
错误:如程序出现异常、数据库操作异常、响应了错误状态码等,都可以通过日志记录下来,方便后期优化程序。
Flask 使用了 Python 中内置的 logging 模块。logging 模块有 4 个子模块,分别为 loggers、handlers、filters 和 formatters,下面分别进行讲解。
loggers模块
loggers 模块是用来创建日志的,在 Flask 中通过 app.logger 可以获取当前的 logger 对象,然后使用 logger.info、logger.debug 等级别函数创建日志。在 Python 内置的 logging 模块中,日志分为 6 个级别,如表 9-5 所示。

在记录日志时,只会记录比当前设置级别高的日志。如设置日志级别为 INFO,那么 logger.debug
将不会产生日志记录。Flask 中的默认级别为 DEBUG,如果要修改默认级别,可以通过 app.logger.setLevel
来修改。如修改为 INFO 级别,代码如下。
app.logger.setLevel(logging.INFO)
我们在 blueprints/front.py
的 index
视图函数中,添加一条测试日志,代码如下。
current_app.logger.info("index页面被请求了")
在浏览器中访问首页后,在 PyCharm 的 Run 界面会显示如图 9-51 所示的日志。

handlers模块
handlers 模块用来指定日志被定向到何处。在 Flask 中默认是定向到控制台打印。如果要定向到文件,那么就用 FileHandler 或 RotatingFileHandler;如果要使用邮箱发送日志,那么就用 SMTPHandler。
关于 logging 模块支持的所有 handler,读者如果感兴趣可以参阅 Python 官方文档 https://docs.python.org/3/library/logging.handlers.html 中的 logging 模块。 |
如果要将日志定向到文件中,则可以给 app.logger
再添加一个 handler,代码如下。
file_handler = logging.FileHandler("pythonbbs.log", encoding="utf-8")
app.logger.addHandler(file_handler)
我们在请求项目的首页可以看到,除了控制台显示日志信息,还会在 pythonbbs
项目的根路径下产生一个 pythonbbs.log
的文件,里面也有日志信息。如果不想要打印 Flask 默认在控制台的日志信息,可以通过以下代码移除。
from flask.logging import default_handler
app.logger.removeHandler(default_handler)
FileHandler 会把所有日志打印在一个文件中,在网站运行中这个文件大小将不断变大。在商业项目中可以使用 RotatingFileHandler
或 TimeRotatingFileHandler
。
-
RotatingFileHandler 可以指定文件大小,当超过最大文件限制时将自动开启一个新的日志文件。
-
TimeRotatingFileHandler 则是根据时间来判断是否要开启一个新的日志文件,下面分别进行讲解。
(1)RotatingFileHandler(filename, maxBytes=0, backupCount=0)
: 当 maxBytes ≥ 0
时,如果文件大小超过 maxBytes
,则会创建一个新的文件,新的文件以 filename
为基本名称,并且在名称后面加上 .1
.2
等。如 filename
的值是 app.log
,那么产生的新文件为 app.log.1
、app.log.2
等。backupCount
指定最多创建多少个文件,只有 backupCount ≥ 1
时,才会产生新的文件。RotatingFileHandler
写入日志的逻辑是这样的,先写入 filename
指定的文件中,如 app.log
,如果 app.log
的大小接近 maxBytes
,则将 app.log
重命名为 app.log.1
,然后创建新的 app.log
用于写入日志。
(2)TimeRotatingFileHandler(filename, when, interval=1, backupCount=0)
: when
参数用于指定按什么时间单位创建新的日志文件,when
可以取以下值:
-
S:按照秒为单位。
-
M:按照分钟为单位。
-
H:按照小时为单位。
-
D:按照天为单位。
-
midnight:按照半夜 12 点为单位。
-
W{0-6}
:按照星期为单位,W0
为星期一。
interval
表示等待多少个单位 when
的时间后创建新的日志文件。创建文件的规则与 RotatingFileHandler
类似,如果 backupCount
不为 0,则最多保留 backupCount
个文件,如果创建超过 backupCount
个的文件,则最旧的文件会被删除。
filters模块
filters
模块是用来给 Logger
和 Handler
提供过滤器的,只有过滤器返回 True
的日志才会被记录,先执行 Logger
的过滤器,再执行 Handler
的过滤器。这里以给 Logger
添加过滤器为例,代码如下。
class stringFilter(logging.Filter):
def filter(self, record):
if record.msg.startswith("abc"):
return False
return True
app.logger.addFilter(stringFilter())
app.logger.info("abc-test")
app.logger.info("123-test")
上述代码中,因为在 app.logger
中添加了 stringFilter
过滤器,会过滤掉以 "abc" 开头的日志,因此只会记录 123-test
,而不会记录 abc-test
。其中 filter
方法中的 record
参数为 logging.LogRecord
对象。
formatters模块
formatters
模块用来指定日志记录的格式。logging
模块内置了一些变量,我们在定义格式时可以直接使用。变量的说明如下:
-
%(asctime)s
:日志被创建的时间。 -
%(filename)s
:被创建的日志所在的文件。 -
%(funcName)s
:被创建的日志所在的函数。 -
%(levelname)s
:被创建的日志的级别。 -
%(lineno)d
:被创建的日志所在文件的代码行号。 -
%(message)s
:日志文本的内容。 -
%(module)s
:被创建的日志所在的模块。
我们可以使用以上变量,灵活地组合自己想要的日志格式。完整的使用示例代码如下:
import logging
from flask.logging import default_handler
from logging.handlers import RotatingFileHandler
# 移除Flask自带的handler
app.logger.removeHandler(default_handler)
# 创建一个RotatingFileHandler对象
file_handler = RotatingFileHandler('pythonbbs.log', maxBytes=16384, backupCount=20)
# 设置handler级别为INFO
file_handler.setLevel(logging.INFO)
# 创建日志记录的格式
file_formatter = logging.Formatter('%(asctime)s %(levelname)s: %(message)s [in %(filename)s: %(lineno)d]')
# 将日志格式对象添加到handler中
file_handler.setFormatter(file_formatter)
# 将handler添加到app.logger中
app.logger.addHandler(file_handler)