Unable to write unicode log messages
I have a Flask app running with Apache and modwsgi with uses the Python
logging module to write log messages to stderr. These messages sometimes
contain non-ascii text (Japanese specifically). When run with the Flask
development server (no Apache, no modwsgi) the log messages are fine, eg:
ERROR:root:test message: 日本語
When run under Apache/modwsgi, the message appearing in the Apache log
file is escaped bytes string:
ERROR:root:test message: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e
I am using Ubuntu-18.04, apache2-2.4.29, libapache2-mod-wsgi-py3-4.5.17,
python3-3.6.7, flask-0.12.2, all installed from the usual Ubuntu
repositories.
What I have done:
- Lots of googling. Similar problems seem to be old (eg python-2),
involve unicode encode or decode exceptions (not a problem in my
case) and the suggested solutions I tried don't fix my problem.
- Added following settings to the WSGIDaemonProcess line in the
mod_wsgi config file:
locale=en_US.UTF-8 lang=en_US.UTF-8
- In /etc/apache2/envvars, uncommented line as directed:
## Uncomment the following line to use the system default locale instead:
. /etc/default/locale
- In /etc/apache2/envvars, added below the two lines above the lines:
export LANG='en_US.UTF-8'
export LC_ALL='en_US.UTF-8'
export PYTHONIOENCODING=UTF-8
- Printed out following values in the python app code just before
the problem logging line:
sys.filesystemencoding = utf-8
sys.defaultencoding = utf-8
type(sys.stderr) = <class '_io.TextIOWrapper'>, encoding = utf-8
locale = ('en_US', 'UTF-8')
- In the app, wrote the log message line directly to sys.stderr
without going through the logging module. The results were
still escaped bytes rather then the correct encoded unicode text.
None of the above made any difference. What now???
Thanks for any advice!
Addendum: here is a minimal test program.
======== test.py ========
import sys, logging
from flask import Flask
App = Flask(__name__)
L = logging.getLogger
logging.basicConfig()
@App.route('/')
def hello_world():
L().error("test message: 日本語")
return 'Hello, World!'
if __name__ == '__main__':
App.run (debug=True)
======== test.wsgi ========
import sys, os
appdir, _ = os.path.split (os.path.abspath(__file__))
sys.path.insert (0, appdir)
from test import App as application
======== test.conf ========
WSGIDaemonProcess jmtest processes=2 threads=4 \
display-name=apache2-jmtest \
locale=en_US.UTF-8 lang=en_US.UTF-8
WSGIProcessGroup jmtest
WSGIScriptAlias /jmtest /home/.../jmtest/test.wsgi
<Directory /home/.../jmtest>
Require all granted
</Directory>