So you want to find out why your Pylons app is running slowly? Well most likely it has to do with your SQL queries, and the best way to see what’s going on and how long each request is taking is to install Dozer (by benbangert of Pylons), and load it up with a TimerProxy (by zzzeek of SQLAlchemy).
Sound like fun? Well, here’s how to do it.
Install Dozer:
sudo easy_install -U http://www.bitbucket.org/bbangert/dozer/get/b748d3e1cc87.gz
Add this to your middleware:
# Add this to your middleware.py, right before return app
if asbool(config['debug']):
from dozer import Logview
app = Logview(app, config)
Add this to your development.ini
# Add to development.ini logview.sqlalchemy = #faa logview.pylons.templating = #bfb
(you can customize the colors here)
Next, modify your configuration ini as well as you like to configure what shows up in the log. Note that I have root set to INFO which will squelch a lot of messages. Change this to DEBUG to see more of what’s going on in each request.
# Logging configuration [loggers] keys = root, YOURPROJ [handlers] keys = console [formatters] keys = generic [logger_root] level = INFO handlers = console [logger_YOURPROJ] level = DEBUG handlers = qualname = YOURPROJ.lib [logger_sqlalchemy] level = INFO handlers = qualname = sqlalchemy.engine [handler_console] class = StreamHandler args = (sys.stderr,) level = NOTSET formatter = generic [formatter_generic] format = %(asctime)s,%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s datefmt = %H:%M:%S
Add this file to /lib/
querytimer.py
from sqlalchemy.interfaces import ConnectionProxy
import time
import logging
log = logging.getLogger(__name__)
class TimerProxy(ConnectionProxy):
def cursor_execute(self, execute, cursor, statement, parameters, context, executemany):
now = time.time()
try:
return execute(cursor, statement, parameters, context)
finally:
total = time.time() - now
log.debug("Query: %s" % statement)
log.debug("Total Time: %f" % total)
Okay, one last thing, modify your SQLAlchemy engine in environment.py to this:
engine = engine_from_config(config, 'sqlalchemy.', proxy=TimerProxy())
and add an import at the top:
from YOURPROJ.lib.querytimer import TimerProxy
So that’s it! Restart paster, and load up a request in your web browser. There will now be a bar at the top that you can click on and see all the requests.
If you want to run TimerProxy on it’s own (that is without Pylons and Dozer, see zzzeek’s post on “Timing All Queries“.
February 16th, 2010 at 4:04 am
Really cool ! thank’s for posting that
December 18th, 2010 at 6:08 pm
Your screenshot looks much prettier than what I get from upstream Dozer. Would you mind sharing the CSS with us?
December 21st, 2010 at 3:04 pm
I had an issue importing PIL. so I had to do this:
http://groups.google.com/group/pylons-discuss/msg/0b085996384d4fe3
I experienced an issue with installing PIL v.1.1.7 for py2.6 on mac osx
10.6. The egg on pypi was mis-organized. It installed fine but I would
receive errors when I tried to import PIL. It was easily rectified by
adding a PIL directory below the installed egg directory. Maybe you are
experiencing the same problem?
Here is what PIL looked like straight from pypi:
Under the following directory was only one directory, EGG-INFO, and then all
of the *.py files that make up the PIL library.
site-packages/PIL-1.1.7-py2.6-macosx-10.6-universal.egg/
But for the importer to properly recognize the package it should look like
the following with all the *.py files in the PIL directory:
site-packages/PIL-1.1.7-py2.6-macosx-10.6-universal.egg/
/EGG-INFO
/PIL
Therefore, just create a PIL directory and move all the .py files there.