Hi django-developers,

Hope things are going well! I work on an open-source group chat product
called zulip [1], written in python and javascript and based on Django, and
we have two small enhancements that we were thinking of contributing
upstream. Before making pull requests, we wanted to get a feel for what the
community thinks in terms of whether/how useful the features might be, and
any suggestions on how we should go about integrating them into the Django
codebase.

I realize many of you may be busy with DjangoCon US; I'll be at the sprints
on Thursday and Friday, and would be happy to talk to people then! We would
also love to get one or both of these into a merge-able state during that
time, or have a clear path forward.

(1) Middleware error framework.

Zulip has some exception middleware to allow 40x errors to be returned
to the user from anywhere within the view code via raising a special
exception, which we’ve found to be a really nice, convenient
programming style.  With this model, validation code called anywhere
from within a view can pass nice, clear user-facing errors up to the
frontend.  You can do this by writing something like:

def my_function(duration):
    if duration < 0:
        raise JsonableError(‘Negative durations are not valid’, status_code=400)

and the error message is passed back to the user via an HttpResponse
containing the error message in our own JSON format.

To implement this, our middleware code looks like the following (with
some logging and error checking):

class JsonErrorHandler(object):
    def process_exception(self, request, exception):
        if hasattr(exception, 'to_json_error_msg') and
callable(exception.to_json_error_msg):
            # json_error just dumps the arguments as JSON and puts it
into an HttpResponse
            return json_error(exception.to_json_error_msg(),
status=exception.status_code)
        if request.error_format == "JSON":
            logging.error(traceback.format_exc())
            return json_error("Internal server error", status=500)
        return None

class JsonableError(Exception):
    def __init__(self, error, status_code=400):
        self.error = error
        self.status_code = status_code
    def to_json_error_msg(self):
        return self.error

For merging into Django, we'd want to generalize this a bit to not
hardcode the way to
marshall the data, but hopefully the snippets above give a sense of
how this works and might be useful.

(2) High level logging for database queries.

We've currently monkey-patched a system to add the following
information to our log lines:

...  52ms (db: 4ms/8q) /url ...

Where 52ms is the total time spent in views code, during which 8
database queries were made, which took a total of 4ms.

Our developers use this as a light-weight performance debugging tool;
it helps in a few ways:
a) It highlights when one is accidentally making database calls in a
loop (common Django newbie mistake!).
b) It makes it possible to rule out possibilities for why performance
was poor for a specific request in production.  E.g. one can know if
it was slow due to too many database queries, a really slow database
query, or some other potentially expensive code in the application.

Currently there isn't a great way to do this "natively"; Django’s
database cursors either logs the whole query (in DEBUG mode) or
nothing at all.

We do it by wrapping the psycopg2 connection and cursor classes with
something that keeps track of these basic stats, along with middleware
that then logs the summary for the entire request.

(We’ve implemented similar logging for memcached as well; I think it’d
eventually make sense to do this sort of tracking for all of the major
network services that Django has hooks to RPC to).

Thanks!
Rishi

[1] https://github.com/zulip/zulip and https://zulip.org

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers  (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-developers+unsubscr...@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/CAM7ph2_-StD-AS2J-iWOcoBqyaxdRqgZy0vpSZ_W-cpnNGbrdg%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to