When I wrap my Flask application in gunicorn writing to stdout no longer seems to go anywhere (simple print statements don\'t appear). Is there someway to either ca
Two solutions to this problem. They are probably longer than others, but ultimately they tap into how logging is done under the hood in Python.
The official Flask documentation on logging works for gunicorn. https://flask.palletsprojects.com/en/1.1.x/logging/#basic-configuration
from logging.config import dictConfig
from flask import Flask
dictConfig(
{
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"default": {
"format": "[%(asctime)s] [%(process)d] [%(levelname)s] in %(module)s: %(message)s",
"datefmt": "%Y-%m-%d %H:%M:%S %z"
}
},
"handlers": {
"wsgi": {
"class": "logging.StreamHandler",
"stream": "ext://flask.logging.wsgi_errors_stream",
"formatter": "default",
}
},
"root": {"level": "DEBUG", "handlers": ["wsgi"]},
}
)
app = Flask(__name__)
@app.route("/")
def hello():
app.logger.debug("this is a DEBUG message")
app.logger.info("this is an INFO message")
app.logger.warning("this is a WARNING message")
app.logger.error("this is an ERROR message")
app.logger.critical("this is a CRITICAL message")
return "hello world"
gunicorngunicorn -w 2 -b 127.0.0.1:5000 --access-logfile - app:app
curl http://127.0.0.1:5000
[2020-09-04 11:24:43 +0200] [2724300] [INFO] Starting gunicorn 20.0.4
[2020-09-04 11:24:43 +0200] [2724300] [INFO] Listening at: http://127.0.0.1:5000 (2724300)
[2020-09-04 11:24:43 +0200] [2724300] [INFO] Using worker: sync
[2020-09-04 11:24:43 +0200] [2724311] [INFO] Booting worker with pid: 2724311
[2020-09-04 11:24:43 +0200] [2724322] [INFO] Booting worker with pid: 2724322
[2020-09-04 11:24:45 +0200] [2724322] [DEBUG] in flog: this is a DEBUG message
[2020-09-04 11:24:45 +0200] [2724322] [INFO] in flog: this is an INFO message
[2020-09-04 11:24:45 +0200] [2724322] [WARNING] in flog: this is a WARNING message
[2020-09-04 11:24:45 +0200] [2724322] [ERROR] in flog: this is an ERROR message
[2020-09-04 11:24:45 +0200] [2724322] [CRITICAL] in flog: this is a CRITICAL message
127.0.0.1 - - [04/Sep/2020:11:24:45 +0200] "GET / HTTP/1.1" 200 11 "-" "curl/7.68.0"
same application code as above but without the dictConfig({...}) section
create a logging.ini file
[loggers]
keys=root
[handlers]
keys=consoleHandler
[formatters]
keys=simpleFormatter
[logger_root]
level=DEBUG
handlers=consoleHandler
[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=simpleFormatter
args=(sys.stdout,)
[formatter_simpleFormatter]
format=[%(asctime)s] [%(process)d] [%(levelname)s] - %(module)s - %(message)s
datefmt=%Y-%m-%d %H:%M:%S %z
--log-config logging.ini option, i.e gunicorn -w 2 -b 127.0.0.1:5000 --access-logfile - --log-config logging.ini app:appYou can redirect standard output to a errorlog file, which is enough for me.
Note that:
capture_output
--capture-output
False
Redirect stdout/stderr to specified file in errorlog
My config file gunicorn.config.py setting
accesslog = 'gunicorn.log'
errorlog = 'gunicorn.error.log'
capture_output = True
Then run with gunicorn app_py:myapp -c gunicorn.config.py
The equivaluent command line would be
gunicorn app_py:myapp --error-logfile gunicorn.error.log --access-logfile gunicorn.log --capture-output
Use the logging: set the stream to stdout
import logging
app.logger.addHandler(logging.StreamHandler(sys.stdout))
app.logger.setLevel(logging.DEBUG)
app.logger.debug("Hello World")
The solution from John mee works, but it duplicates log entries in the stdout from gunicorn.
I used this:
import logging
from flask import Flask
app = Flask(__name__)
if __name__ != '__main__':
gunicorn_logger = logging.getLogger('gunicorn.error')
app.logger.handlers = gunicorn_logger.handlers
app.logger.setLevel(gunicorn_logger.level)
and got I this from: https://medium.com/@trstringer/logging-flask-and-gunicorn-the-manageable-way-2e6f0b8beb2f