47
Andy McKay andym on #django clearwind consulting andy @clearwind.ca @clearwind What the heck went wrong?

What the heck went wrong?

Embed Size (px)

Citation preview

Page 1: What the heck went wrong?

Andy McKayandym on #django

clearwind [email protected]

@clearwind

What the heck went wrong?

Page 2: What the heck went wrong?

debugging django

Page 3: What the heck went wrong?

reporting errors

Page 4: What the heck went wrong?

not a question of if...

Page 5: What the heck went wrong?

development → production

Page 6: What the heck went wrong?

use the dev. serverpython manage.py runserver

development

Page 7: What the heck went wrong?

turn on debugDEBUG = True

development

Page 8: What the heck went wrong?

assert False

development

Page 9: What the heck went wrong?

a printprint "some debugging statement"

development

Page 10: What the heck went wrong?

a printprint "some debugging statement"

print some_variableprint type(some_variable)

development

Page 11: What the heck went wrong?

there's a problem

Page 12: What the heck went wrong?

mod_wsgiIOError: sys.stdout access restricted by mod_wsgi

WSGIRestrictStdout Offhttp://code.google.com/p/modwsgi/wiki/ApplicationIssues

development

Page 13: What the heck went wrong?

logging

http://www.flickr.com/photos/astro-dudes/1492818224/

Page 14: What the heck went wrong?

development

import logginglogging.basicConfig( level = logging.DEBUG, format = '%(asctime)s %(levelname)s %(message)s',)

http://docs.python.org/library/logging.html

Page 15: What the heck went wrong?

development

import logging

log.debug("My brilliant debug message")

Page 16: What the heck went wrong?

developmentimport logging

import logging.handlers

if getattr(settings, "LOG_FILENAME", None):

logger = logging.getLogger("django")

handler = logging.handlers.RotatingFileHandler(settings.LOG_FILENAME)

formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")

handler.setFormatter(formatter)

logger.addHandler(handler)

else:

# so that if you don't have LOG_FILENAME defined, don't blow up

class NullHandler(logging.Handler):

def emit(self, record):

pass

logging.getLogger("django").addHandler(NullHandler())

Page 17: What the heck went wrong?

pdb

development

http://docs.python.org/library/pdb.html

Page 18: What the heck went wrong?

import pdb; pdb.set_trace()

Django version 1.2 pre-alpha, using settings 'test_profiler.settings'

Development server is running at http://0.0.0.0:8000/

Quit the server with CONTROL-C.

> /mnt/hgfs/sandboxes/test_profiler/profiler/middleware.py(12)process_response()

-> url = request.get_full_path()

(Pdb)

development

Page 19: What the heck went wrong?

l: shows lines of code at your current point

n: execute the next line

s: step into

c: continue

q: quit

locals(): see what's in your current scope

development

Page 20: What the heck went wrong?

pdb is essential

development

Page 21: What the heck went wrong?

there's a problem

Page 22: What the heck went wrong?

leave pdb in and your site...

development

Page 23: What the heck went wrong?
Page 24: What the heck went wrong?

werkzeug debugger

development

easy_install Werkzeughttp://dev.pocoo.org/projects/werkzeug/wiki/UsingDebuggerWithDjango

Page 25: What the heck went wrong?

development

#!/usr/bin/env python

from werkzeug import run_simple, DebuggedApplicationfrom django.core.handlers.wsgi import WSGIHandler

# This is only needed for Django versions < [7537]:def null_technical_500_response(request, exc_type, exc_value, tb): raise exc_type, exc_value, tb

from django.views import debugdebug.technical_500_response = null_technical_500_response

if __name__ == '__main__': run_simple('localhost', 8080, DebuggedApplication(WSGIHandler(), True))

Page 26: What the heck went wrong?

development

Page 27: What the heck went wrong?

unit tests

development

Page 28: What the heck went wrong?

django-debug-toolbar

development

http://github.com/robhudson/django-debug-toolbar/tree/master

Page 29: What the heck went wrong?

development

rocks!

Page 30: What the heck went wrong?

MIDDLEWARE_CLASSES = ([...snip] 'debug_toolbar.middleware.DebugToolbarMiddleware',)

INSTALLED_APPS = ([...snip] 'debug_toolbar')

INTERNAL_IPS = ('127.0.0.1',)

development

Page 31: What the heck went wrong?

development

Page 32: What the heck went wrong?

cheaper and easier

development

Page 33: What the heck went wrong?

continuous integration

staging

e.g: Teamcity, Integrity, buildbot, Tinderbox ... others are available

Page 34: What the heck went wrong?

custom test runnerTeamCity: http://bit.ly/geAA

[..snip]if hasTeamcity and underTeamcity(): result = TeamcityTestRunner().run(suite)else: result = unittest.TextTestRunner(verbosity=verbosity).run(suite)

staging

Page 35: What the heck went wrong?

staging

Page 36: What the heck went wrong?

varies upon server

production

mod_wsgi → http://code.google.com/p/modwsgi/wiki/DebuggingTechniques

mod_python → http://yenaer.com/blog/2008/jan/12/debugging-modpython-scripts-apache-and-pdb

Page 37: What the heck went wrong?

errors

production

http://docs.djangoproject.com/en/dev/howto/error-reporting/

Page 38: What the heck went wrong?

404 and 500

production

(has to be in root url.conf)

handler404 = 'mysite.views.custom_404'

handler500 = 'mysite.views.custom_500'

http://docs.djangoproject.com/en/dev/topics/http/views/

Page 39: What the heck went wrong?

emailed

production

DEBUG = False

ADMIN = ( ('Andy', '[email protected]'), )

Page 40: What the heck went wrong?

productionTraceback (most recent call last):

 File "/usr/lib/python2.5/site-packages/django/core/handlers/base.py", line 86, in get_response   response = callback(request, *callback_args, **callback_kwargs)

 File "/usr/lib/python2.5/site-packages/django/contrib/admin/sites.py", line 154, in root   return shortcut(request, *url.split('/')[1:])

 File "/usr/lib/python2.5/site-packages/django/contrib/contenttypes/views.py", line 57, in shortcut   object_domain = Site.objects.get_current().domain

 File "/usr/lib/python2.5/site-packages/django/contrib/sites/models.py", line 22, in get_current   current_site = self.get(pk=sid)

 File "/usr/lib/python2.5/site-packages/django/db/models/manager.py", line 93, in get   return self.get_query_set().get(*args, **kwargs)

 File "/usr/lib/python2.5/site-packages/django/db/models/query.py", line 298, in get   num = len(clone)

 File "/usr/lib/python2.5/site-packages/django/db/models/query.py", line 154, in __len__   self._result_cache = list(self.iterator())

 File "/usr/lib/python2.5/site-packages/django/db/models/query.py", line 269, in iterator   for row in self.query.results_iter():

 File "/usr/lib/python2.5/site-packages/django/db/models/sql/query.py", line 206, in results_iter   for rows in self.execute_sql(MULTI):

 File "/usr/lib/python2.5/site-packages/django/db/models/sql/query.py", line 1723, in execute_sql   cursor.execute(sql, params)

ProgrammingError: relation "django_site" does not exist

<WSGIRequestGET:<QueryDict: {}>,POST:<QueryDict: {}>,COOKIES:{'__utma': '90285002.4337325975145378300.1232037035.1233126418.1233185854.12','__utmb': '90285002.2.10.1233185854','__utmc': '90285002','__utmz': '90285002.1232037035.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)','sessionid': 'b139e8d00ed433fb5e6dff50a3956036'},META:{'DOCUMENT_ROOT': '/htdocs','GATEWAY_INTERFACE': 'CGI/1.1','HTTP_ACCEPT': 'text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5','HTTP_ACCEPT_ENCODING': 'gzip, deflate','HTTP_ACCEPT_LANGUAGE': 'en-us','HTTP_CONNECTION': 'keep-alive','HTTP_COOKIE': '__utmz=90285002.1232037035.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utma=90285002.4337325975145378300.1232037035.1233126418.1233185854.12; __utmc=90285002; __utmb=90285002.2.10.1233185854; sessionid=b139e8d00ed433fb5e6dff50a3956036','HTTP_HOST': 'www.areciboapp.com','HTTP_REFERER': 'http://www.areciboapp.com/arecibo-admin/singleblog/post/7/','HTTP_USER_AGENT': 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-us) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/3.2.1 Safari/525.27.1','PATH': '/usr/local/bin:/usr/bin:/bin','PATH_INFO': u'/arecibo-admin/r/18/7/','PATH_TRANSLATED': '/var/www/arecibo/django.wsgi/arecibo-admin/r/18/7/','QUERY_STRING': '','REMOTE_ADDR': '70.79.161.59','REMOTE_PORT': '63593','REQUEST_METHOD': 'GET','REQUEST_URI': '/arecibo-admin/r/18/7/','SCRIPT_FILENAME': '/var/www/arecibo/django.wsgi','SCRIPT_NAME': u'','SERVER_ADDR': '216.139.224.26','SERVER_ADMIN': '[no address given]','SERVER_NAME': 'www.areciboapp.com','SERVER_PORT': '80','SERVER_PROTOCOL': 'HTTP/1.1','SERVER_SIGNATURE': '<address>Apache/2.2.8 (Ubuntu) DAV/2 SVN/1.4.6 mod_python/3.3.1 Python/2.5.2 mod_ssl/2.2.8 OpenSSL/0.9.8g mod_wsgi/1.3 Server at www.areciboapp.com Port 80</address>\n','SERVER_SOFTWARE': 'Apache/2.2.8 (Ubuntu) DAV/2 SVN/1.4.6 mod_python/3.3.1 Python/2.5.2 mod_ssl/2.2.8 OpenSSL/0.9.8g mod_wsgi/1.3','mod_wsgi.application_group': 'areciboapp.com|','mod_wsgi.callable_object': 'application','mod_wsgi.case_sensitivity': '1','mod_wsgi.listener_host': '','mod_wsgi.listener_port': '80','mod_wsgi.output_buffering': '0','mod_wsgi.process_group': 'www-data','mod_wsgi.reload_mechanism': '0','mod_wsgi.script_reloading': '1','wsgi.errors': <mod_wsgi.Log object at 0x8c0d620>,'wsgi.input': <mod_wsgi.Input object at 0xb469958>,'wsgi.multiprocess': True,'wsgi.multithread': False,'wsgi.run_once': False,'wsgi.url_scheme': 'http','wsgi.version': (1, 0)}>

Page 42: What the heck went wrong?

get accountInstall Arecibo library

ARECIBO_PUBLIC_ACCOUNT_NUMBER = "xxxx"

production

Page 43: What the heck went wrong?

add to errorfrom arecibo.wrapper import post

def application_error(request): t = loader.get_template('500.html') uid = post(request, 500) c = RequestContext(request, {"uid": uid}) return HttpResponse(t.render(c), status=500)

production

Page 44: What the heck went wrong?

production

Page 45: What the heck went wrong?

django-db-log

honourable mentions

http://code.google.com/p/django-db-log/

"Logs Django exceptions to your database handler."

Page 46: What the heck went wrong?

django-sql-profiler

honourable mentions

http://code.google.com/p/django-sql-profiler

"Records every SQL query in Django in the database so that you can find slow queries in your site."

Page 47: What the heck went wrong?

Andy McKayclearwind consulting

[email protected]@clearwind

slides will be going on http://djangozen.com

The error message is the Truth. The error message is God.

James Bennett, earlier today.