本文仅为作者自学之用,系统为macOS,不保证信息准确。
Flask/Gunicorn Logger
最近部署flask的服务器,发现需要合并各种middleware的logger的需求。由于一开始连logger本身是什么都不清楚,谈何合并不同的logger请求。这里且是查找网站加上实践出来的结果,未必有强劲的理论基础,可能有错误,希望能通过学习逐渐纠正。
首先,flask具有自己自带的logger。在程序中止需要使用app.logger
调用即可。flask的app.logger
的预设设置会讲log信息发布在stdout上。想要更改可以自己重新添加handler或者直接用logging.config中的dict来完全初始化成自己想要的logger模式。
接下来,假如需要Flask的logger与Gunicorn的合并,那么则需要在Flask中加入这样一段代码
代码的意义为,当Flask不是自启动的时候(言下之意就是被Gunicorn启动),那么则获取到
gunicorn.error
的logger,将app.logger
的handler
赋值成gunicorn.error.handler
。最后一句话则是将app.logger
的logger.level
设置成和Gunicorn配置的相同的level。
在Gunicorn的命令中,带有启动Flask程序的一些配置信息。Gunicorn可以运用logging.config
来进行完整的配置,但是我还没有学习过这一点,所以就先不多谈,目前只谈在命令行中的配置。
一个较为完整的命令如下图:
这个命令中,定义了access.file
和error.file
的输出文件地址。同时还定义了 log.level
(记住这里这个level也会向下赋值到Flask中)。
假如还需要用supervisor来监控gunicorn的话,也是可以将gunicorn的语句移植到supervisor的config文件中。在这里顺便记录一下supervisor的常用命令,以便日后查阅:
在supervisor.conf文件中,带上;
的行是文件说明格式以及功能的行,并没有执行能力,属于comment。若你需要执行某一行,就将;
删除。新的Gunicorn的监控program应当写在program模块的位置,且如果你的flask程序会执行API的呼叫等命令,则这几行代码的;
需要删掉
且这里需要换成第二行
最后关于logger的结果还是有一点需要说明。正常情况下,无论是Gunicorn的启动信息,还是Flask内部的logging信息,均会写入同一个文件中(也就是stderr.log)。这里就有人会好奇了,例如我,为什么会写入stderr而不是stdout呢?只怪自己学艺不精,经过多番查询之后只能得出这样一个结论:
- Gunicorn并没有自带的stdout这种输出方式,Gunicorn的配置文件中只有
access.file
stderr.file
以及sysout.file
三种输出文件地址的配置。其中access.file
会显示调用API的程序的网络地址,sysout.file
具体功能不详,但是貌似是非常底层的东西,其余的log信息都会进入stderr.file
。 - 正常情况下,
stdout
会收集的是print到console的信息,也就是python中的print('Hello World!')
或者java中的System.out.println("Hello World!")
类型的信息。我在尝试在Flask中加入print
功能之后再次测试,结果发现print
的结果果然被写入了stdout.file
中。唯一值得好奇的地方就是stderr.file
的信息会实时写入文件中,但是stdout.file
的文件却似乎是在我在让supervisor停止Gunicorn运行的时候才会一口气写入?着实奇怪,但是却又找不到原因。
最最后,supervisor停止了gunicorn的flask程序之后,如果flask程序中开启了新的后台进程,则进程还会占用该端口,导致supervisor无法使用restart命令,日志中一直显示端口占用,杀死该进程的方法有:
- 查看端口占用情况
lsof -i tcp:8080
该命令会显示占用8080端口的进程 - 杀死进程
kill -9 pid