I am using uWSGI (2.0.11.2) with Python (3.4.3) to serve my Pyramid (1.5.7) app on Ubuntu 14.04. I have noticed that I am getting errors in my uWSGI log related to unicode decoding:
#
# one of the situations when exception is raised is
# when SQLAlchemy (which has set INFO logging level)
# tries to write an SQL statement containing unicode charater
# into log file
#
2016-02-26 16:01:38,734 INFO [sqlalchemy.engine.base.Engine][b'uWSGIWorker5Core0'] BEGIN (implicit)
2016-02-26 16:01:38,735 INFO [sqlalchemy.engine.base.Engine][b'uWSGIWorker5Core0'] SELECT * FROM staging WHERE company_name = %(company_name_1)s AND time = %(time_1)s AND ship_name = %(ship_name_1)s
# exact place (missing line) where SQLAlchemy is trying to print out
# query parameters, which in this case include unicode character
--- Logging error ---
Traceback (most recent call last):
File "/usr/lib/python3.4/logging/__init__.py", line 980, in emit
stream.write(msg)
UnicodeEncodeError: 'ascii' codec can't encode character '\xfa' in position 132: ordinal not in range(128)
Call stack:
File "/home/mk/.virtualenvs/api/lib/python3.4/site-packages/sqltap/wsgi.py", line 42, in __call__
return self.app(environ, start_response)
File "/home/mk/.virtualenvs/api/lib/python3.4/site-packages/pyramid/router.py", line 242, in __call__
response = self.invoke_subrequest(request, use_tweens=True)
#
# the stack continues...
# full stack here -> https://bpaste.net/show/8e12af790372
#
File "/home/mk/.virtualenvs/api/lib/python3.4/site-packages/sqlalchemy/engine/base.py", line 1010, in _execute_clauseelement
compiled_sql, distilled_params
File "/home/mk/.virtualenvs/api/lib/python3.4/site-packages/sqlalchemy/engine/base.py", line 1100, in _execute_context
sql_util._repr_params(parameters, batches=10)
Unable to print the message and arguments - possible formatting error.
Use the traceback above to help find the error.
I have also noticed that writing same lines into Pyramid-generated log file (no uWSGI involved) is working perfectly fine, no errors whatsoever, and unicode characters are properly inserted.
I am running uWSGI with this command:
/usr/local/bin/uwsgi --emperor /etc/uwsgi/vassals
In vassals
folder I have symlinked uWSGI config from my Pyramid app and it looks like this:
[uwsgi]
host = %h
username = mk
project_name = api
project_root = /shared/projects/python/%(project_name)
env = PYTHONIOENCODING=UTF-8
; this env var is generated based on host name
env = APP_INI_FILE=develop.ini
; folders config
home_folder = /home/%(username)
virtualenv_folder = %(home_folder)/.virtualenvs/%(project_name)
logs_folder = %(home_folder)/logs/%(project_name)
chdir = %(project_root)
socket = %(project_root)/%(project_name).sock
pidfile = %(project_root)/%(project_name).pid
virtualenv = %(virtualenv_folder)
daemonize = %(logs_folder)/uwsgi.log
; core stuff
master = true
vacuum = true
processes = 5
enable-threads = true
; socket conf
chmod-socket = 666 # invoking the One
chown-socket = %(username)
uid = %(username)
gid = %(username)
; log conf
log-reopen = true
logfile-chown = %(username)
logfile-chmod = 644
; app conf
module = wsgi:application
harakiri = 120
max-requests = 500
post-buffering = 1
paste = config:%p
paste-logger = $p
Pyramid's config file where all the logging is defined looks like this:
###
# app configuration
# http://docs.pylonsproject.org/projects/pyramid/en/1.5-branch/narr/environment.html
###
[DEFAULT]
home_dir = /home/mk
[app:main]
use = egg:api
pyramid.reload_templates = false
pyramid.debug_authorization = false
pyramid.debug_notfound = false
pyramid.debug_routematch = false
pyramid.default_locale_name = en
sqlalchemy.url = postgresql://XXX:[email protected]:5432/ze_database?client_encoding=utf8
[server:main]
use = egg:waitress#main
host = 0.0.0.0
port = 6543
###
# logging configuration
# http://docs.pylonsproject.org/projects/pyramid/en/1.5-branch/narr/logging.html
###
[loggers]
keys = root, sqlalchemy
[handlers]
keys = console, debuglog
[formatters]
keys = generic, short
[logger_root]
level = DEBUG
handlers = console, debuglog
[logger_sqlalchemy]
level = INFO
handlers =
qualname = sqlalchemy.engine
# "level = INFO" logs SQL queries.
# "level = DEBUG" logs SQL queries and results.
# "level = WARN" logs neither. (Recommended for production systems.)
[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = DEBUG
formatter = generic
[handler_debuglog]
class = handlers.RotatingFileHandler
args = ('%(home_dir)s/logs/api/pyramid_debug.log', 'a', 1024000000, 10)
level = DEBUG
formatter = generic
[formatter_generic]
format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
[formatter_short]
format = %(asctime)s %(message)s
And finally, my Pyramid's wsgi.py
file is very simple:
import os
from pyramid.paster import get_app, setup_logging
here = os.path.dirname(os.path.abspath(__file__))
conf = os.path.join(here, os.environ.get('APP_INI_FILE')) # APP_INI_FILE variable is set in uwsgi.ini
setup_logging(conf)
application = get_app(conf, 'main')
Essentially, I am redirecting my app's logs to stderr
(or stdout
, it's all the same as far as I have noticed) and I also write it in a separate file (pyramid_debug.log
) in the same time. stderr
in my case is uWSGI daemon's log file and that's where the error happens.
Although LC_ALL
and related variables are set on the system to en_EN.UTF-8
, I also tried to play around with various localization-related environmental variables and explicitly setting them in my Pyramid's wsgi app, but with little luck - for example, setting only PYTHONIOENCODING=UTF-8
variable in uWSGI config solved the problem on my local machine, but not on the server once I deployed.
My obvious question here is - how to handle uWSGI's writing of unicode characters in log file properly in this situation?
Edit File "/usr/lib/python3.4/logging/__init__.py", line 980
and change
stream.write(msg)
to
stream.write(msg.encode('utf-8'))
Most likely the stream type was changed in ways that shouldn't kill your UTF-8 encoding capabilities, but actually do because of Pythonics. (It seems that no matter how loud the world screams "UTF-8", Python ignores everyone on that matter.)
For example, all those environment variables you tried are ignored if you're dealing with a file:
# test.py
import sys
sys.stdout.write(u'\u00f6\n')
test:
max% python test.py
ö
max% python test.py > f
Traceback (most recent call last):
File "test.py", line 2, in <module>
sys.stdout.write(u'\u00f6\n')
UnicodeEncodeError: 'ascii' codec can't encode character u'\xf6' in position 0: ordinal not in range(128)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With