Package: django-zipkin
django-zipkinis a middleware and api for recording and sending
messages toZipkin. Why use it?
From thehttp://twitter.github.io/zipkin/:“Collecting traces helps developers gain deeper knowledge about how
certain requests perform in a distributed system. Let’s say we’re having
problems with user requests timing out. We can look up traced requests
that timed out and display it in the web UI. We’ll be able to quickly
find the service responsible for adding the unexpected response time. If
the service has been annotated adequately we can also find out where in
that service the issue is happening.”Supported versionsPython:2.6,2.7(the current Python Thrift release doesn’t
support Python 3)Django:1.3-1.7Getting startedInstall the library:pip install django-zipkinAdd the middleware to the list of installed middlewares:MIDDLEWARE_CLASSES=('...','django_zipkin.middleware.ZipkinMiddleware','...')Set the name your service will use to identify itself. This will appear
as the service name in Zipkin.ZIPKIN_SERVICE_NAME='awesome-service'django-zipkinis now logging data compatible with the Zipkin
collector to the logger calledzipkin.Getting the data to ZipkinFrom here you it’s up to you to get the messages to Zipkin. Here’s how
we do it atPrezi:We configure logging in each service usingdjango-zipkinto send
log messages from thezipkinlogger to the locally running Scribe
instance, into the categoryzipkin.The Scribe instances are configured to forward thezipkincategory directly to the Zipkin collector. This is useful because
Scribe buffers messages in case the collector (or the network to it)
is down.Another alternative may be logging to syslog, and usingscribe_apacheshipped with Scribe to send data to Zipkin (possibly
via a local Scribe server).Recording annotationsdjango-zipkincreates a single span per served requests. It
automatically adds a number of annotations (see below). You can also add
your own annotations from anywhere in your code:fromdjango_zipkin.apiimportapiaszipkin_apizipkin_api.record_event('MySQL: "SELECT * FROM auth_users"',duration=15000)# Note duration is in microseconds, as defined by Zipkinzipkin_api.record_key_value('Cache misses',15)# You can use string, int, long and bool valuesPropagating tracing informationTo identify which spans belong to the same trace, some information must
be passed on with inter-service calls.django-zipkinprovides
facilities for this on both the client and the server side. The
middleware automatically reads the trace propagation HTTP headers
describedin the Zipkin
documentation.
For propagating data to outgoing requests, a function returning a dict
of the correct HTTP headers is provided:fromdjango_zipkin.apiimportapiaszipkin_apiheaders=zipkin_api.get_headers_for_downstream_request()# During a request returns something like this:{'X-B3-Sampled':'false','X-B3-TraceId':'b059fb34103a46f7','X-B3-Flags':'0','X-B3-SpanId':'a42f4f3a045c54a5'}Automatically generated annotationssrandssannotations are automatically added by the middleware.
The following binary (key-value) annotations are also added:AnnotationExample valueAdded ifhttp.uri/api/v1/loginAlwayshttp.statuscode200Alwaysdjango.view.func_nameloginAlwaysdjango.view.classAuthViewIf the view function is the method of a view-based classdjango.view.args('oauth')Alwaysdjango.view.kwargs{"next": "/index"}Alwaysdjango.url_namemyapp.views.loginAlwaysdjango.tastypie.resource_nameuserIf the request is served by Tastypie (specifically, when the view gets a kwargresource_name)It’s up to you to addcsandcr(client send and client receive)
annotations in whatever client you use.Things to keep in mindMiddleware orderIf a middleware abovedjango-zipkinreturns a response, then the
request processing part ofdjango-zipkinwill never be called,
resulting in an inconsistent internal state. In this case your custom
annotations and most of the automatically added annotations will be
lost, and timing information will be incorrect. An extra annotation will
be added with the following
value:No ZipkinData in thread local store. This can happen if process_request didn't run due to a previous middleware returning a response. Timing information is invalid.View wrappersIf your view is wrapped (for example with a decorator) without using thefunctools.wrapsdecorator, thendjango-zipkinhas no way of
retrieving the name of the view. In this casedjango.view.func_namewill be the function name of the wrapper function. This is something
you’ll want to avoid in your own code.One offender is Tastypie:django.view.func_namewill always bewrapper. On requests served by Tastypie the annotationdjango.tastypie.resource_namewill be added with the name of the
Tastypie resource, anddjango.url_namewill be something useful likeapi_dispatch_list.Zipkin UI vs. JSON annotation valuesThedjango.view.kwargsannotation has a JSON string as its value for
easier automated processing. Unfortunately this make the UI display the
value as[object Object]. SeeZipkin issue
#410for any progress
on this. If you want to find the value on the web UI, you can open the
page source and search fordjango.view.kwargs.CustomizingYou can customize the waydjango-zipkinworks with the following
settings values. They are defined indjango_zipkin/defaults.py.Settings variablesZIPKIN_SERVICE_NAME: DefaultNone. The service name that will
appear on Zipkin (theservice_namevalue in the sent Thrift
objects).ZIPKIN_LOGGER_NAME: Default'zipkin'. The name of the logger
to use when sending Zipkin messages through the Python logging system.ZIPKIN_DATA_STORE_CLASS: Default'django_zipkin.data_store.ThreadLocalDataStore'.django-zipkinneeds to pass some data from the request processor to the response
processor. This same data needs to be accessible from anywhere in the
users code. The default implementation for this is to use thread-local
storage.geventandgreenletmonkey-patch it, so this
implementation works fine even undergunicornand friends. You can
provide your own implementation - it needs to implement the methods ofdjango_zipkin.data_store.BaseDataStore.ZIPKIN_ID_GENERATOR_CLASS: Default'django_zipkin.id_generator.SimpleIdGenerator'. The class used to
generate span and trace ids if we don’t get one from the incoming
request.Configglueconfiggluesupport is provided viadjango_zipkin.schema; you can
include it into your own schema like this:fromdjango_zipkin.schemaimportDjangoZipkinSectionclassMySchema(...):...classzipkin(DjangoZipkinSection):passHackingSeeCONTRIBUTING.mdfor guidelines.You can start hacking ondjango-zipkinwith:gitclonehttps://github.com/prezi/django-zipkin.gitcddjango-zipkingitremoterenameoriginupstreamvirtualenvvirtualenv.virtualenv/bin/activatepipinstalldjangopythonsetup.pytest