Monday, January 16

Push data to Google Analytics with Python

I'll share with you how to push data to Google Analytics with a simple Python example. You can collect/plot/analyze some interesting data:

  • If you have a programmable door lock in the office, you can track employees' office hours.
  • Track the commits of your team. Tag with branch/hash etc.
  • Track your own computer usage

Google Analytics is mostly used with a JavaScript snippet on the client side but if you browse the documentation, you'll see that they also provide mobile tracking features which help you to collect data without a web browser or even if the client doesn't support JavaScript.

Basically, mobile client displays an image which is served by a server-side script hosted by you and the script pushes the visit data to Google via GET request. The parameters of this method is listed on the Troubleshooting the Tracking Code section of the documentation.

After looking at this list, PHP/Perl codes provided by Google with some trial and error I've found the minimum parameters to push data.
  • utmwv, tracking code version.
    • The latest version at the time of this writing is 5.2.2d.
  • utmn, unique ID generated for each GIF request to prevent caching of the GIF image.
    • Example value in the documentation is 10 digits so stick to maximum of 10 digits.
  • utmp, requested path of the current page.
  • utmac, account string (property id).
  • utmcc,  cookie values.
    • __utma is required. These 2 posts discusses this cookie in detail.
    • "1" can be used for each part except unique visitor id.
    • For the visitor id, you can generate something unique for each visitor which doesn't change between visits. The safe assumption for the length of the id 10 because google Analytics itself uses around 10 digits.
After this data is generated, simply request http://www.google-analytics.com/__utm.gif with these parameters in the query string.

Here is the proof of concept Python code:

If you read this post from any non-js environment, you can visit the gist for this code.

I've provided you the bare minimum. Now you can add more variables and track whatever you need. Don't forget to share your hack in the comments.

Wednesday, January 11

How to serve static files with Pyramid

If you want to host your Pyramid static files in s3 or compile everything to a local folder, just like Django's collectstatic, van.static is to the rescue.

Before going further, ensure that all of your statics are resolved from the request object and any references from CSSs use relative paths. A Mako example would be: ${request.static_url("app:static/image.png")}.

Install van.static to your virtual environment with pip install van.static.

Setup van.static in your app's entry point:

from van.static import cdn
static_resources = (('static', 'app:static'),)
cdn.config_static(config,
                  static_resources,
                  static_cdn=settings.get("static_cdn"))

If you want to collect all static files together:

python -m van.static.cdn --target=file:///srv/static/myapp/ --resource="app:static"

van.static has 2 modes:

Development mode
If you do not provide it a static_cdn parameter, it serves everything via Pyramid's static view.
Production mode
If you provide the parameter, it simply generates unique urls for each version of your application, prefixing the given URL.

The software is not even a month old but already can compress files with YUI compressor and seems to be pretty usable.

Wednesday, January 6

Automatically decorating all views of a django project

Now the real thing, a middleware for Django.

This middleware auto-decorates each view function in a view module (views.py, or views/) with the decorators defined in settings.py.

An example setting is:

Think this middleware as a firewall.  Whether you decorated your view functions or not, this ensures that your content is protected by using the decorators.

Note that this middleware needs to be at the end of the middlewares list because it always return an HttpResponse by calling the view function; which means no other middleware after this is executed.

Here is the function: