I'm having a slight logging problem with Python 3.6 (Flask==0.11.1
) and gunicorn==19.9.0
. I'm using the structlog==18.1.0
(for JSON logging) and python-json-logger==0.1.9
inside the Flask app to log out various stuff which works fine on its own, i.e. when running the Flask app without gunicorn. But when running the Flask app inside gunicorn some logging problems randomly start to appear, i.e. both access logs from gunicorn and from inside the Flask app go missing.
An example of a logging event would be
import structlog
def some_flask_endpoint():
logger = structlog.getLogger(__name__)
logger.info('This is an info event', additional_data='some additional data')
Which should output a JSON message to the logs similar to this
{"message": "This is an info event", "additional_data": "some additional data"}
Currently this is all done via a logging FileConfig (which both gunicorn and the flask app is using) as shown below:
[loggers]
keys = root,gunicorn.error,gunicorn.access
[handlers]
keys=console,logfile
[formatters]
keys=json
[logger_root]
level=INFO
handlers=console,logfile
[logger_gunicorn.error]
level = INFO
handlers = logfile
propagate = 1
qualname = gunicorn.error
[logger_gunicorn.access]
level = INFO
handlers = logfile
propagate = 0
qualname = gunicorn.access
[handler_console]
class=logging.StreamHandler
formatter=json
args=(sys.stdout, )
[handler_logfile]
class=logging.handlers.TimedRotatingFileHandler
formatter=json
args=('logs.log', 'midnight', )
[formatter_json]
format=%(message)s
class=pythonjsonlogger.jsonlogger.JsonFormatter
I.e. gunicorn is using this file with the parameter --logconfig logconfig.ini
and flask is using it with logging.config.fileConfig('logconfig.ini')
from the logging
package.
I realize that making the root logger output to the logfile might cause some events from other loggers being double logged but my main concern is that since gunicorn spins up several workers (4 in this case) there might be a collision within each worker where structlog
is used (i.e. multiple processes trying to access a single file) which might be the reason why some logs go missing.
So another option I thought of was to simply change the root logger to only use the console
handler or simply just create a new logger which structlog
uses, i.e.
import structlog
logger = structlog.getLogger('my_app')
logger.info('some info')
[logger_my_app]
level=INFO
handlers=console
And then make the gunicorn master take all logs from stdout and handle the writing of that to a log file and solving the multiprocess-single file problem. However when providing gunicorn with this logging config file (so that it outputs its logs in json and also so I dont have to provide endless amount of parameters to config gunicorn) it seems to completely ignore the parameter --capture-output
and therefore my structlog
logs only appear in the console but aren't written out to any config file.
So after this rather long but hopefully explanatory post, does anybody have information on the proper way to store logs from logging
/structlog
to file inside of gunicorn because I can't find any concrete information online and the gunicorn docs are quite wage on this topic?
Tl;dr: How can I send stdout to a log file in gunicorn while also providing a log config file to gunicorn.