Refactor Chartbeat module into its own app

This commit has not been tested.
This commit is contained in:
Joost Cassee 2011-01-26 23:53:33 +01:00
parent d715c16244
commit 05c82b833a
7 changed files with 282 additions and 128 deletions

View file

@ -0,0 +1,145 @@
"""
=============================
Chartbeat -- traffic analysis
=============================
Chartbeat_ provides real-time analytics to websites and blogs. It shows
visitors, load times, and referring sites on a minute-by-minute basis.
The service also provides alerts the second your website crashes or
slows to a crawl.
.. _Chartbeat: http://www.chartbeat.com/
.. chartbeat-installation:
Installation
============
You only need to do perform these steps if you are not using the
generic :ttag:`analytical.*` tags. If you are, skip to
:ref:`chartbeat-configuration`.
In order to use the template tags, you need to add
:mod:`analytical.chartbeat` to the installed applications list in the
project :file:`settings.py` file::
INSTALLED_APPS = [
...
'analytical.chartbeat',
...
]
The Chartbeat tracking code is inserted into templates using template
tags. At the top of the template, load the :mod:`chartbeat` template
tag library. Then insert the :ttag:`chartbeat_top` tag at the top of
the head section, and the :ttag:`chartbeat_bottom` tag at the bottom of
the body section::
{% load chartbeat %}
<html>
<head>
{% chartbeat_top %}
...
{% chartbeat_bottom %}
</body>
</html>
Because these tags are used to measure page loading time, it is
important to place them as close as possible to the start and end of the
document.
.. _chartbeat-configuration:
Configuration
=============
Before you can use the Chartbeat integration, you must first set your
User ID.
.. _chartbeat-user-id:
Setting the User ID
-------------------
Your Chartbeat account has a unique User ID. You can find your User ID
by visiting the Chartbeat `Add New Site`_ page. The second code snippet
contains a line that looks like this::
var _sf_async_config={uid:XXXXX,domain:"YYYYYYYYYY"};
Here, ``XXXXX`` is your User ID. Set :const:`CHARTBEAT_USER_ID` in the
project :file:`settings.py` file::
CHARTBEAT_SITE_ID = 'XXXXX'
If you do not set a User ID, the tracking code will not be rendered.
.. _`Add New Site`: http://chartbeat.com/code/
.. _chartbeat-internal-ips:
Internal IP addresses
---------------------
Usually you do not want to track clicks from your development or
internal IP addresses. By default, if the tags detect that the client
comes from any address in the :const:`INTERNAL_IPS` setting, the
tracking code is commented out. See :const:`ANALYTICAL_INTERNAL_IPS`
for important information about detecting the visitor IP address.
.. _chartbeat-domain:
Setting the domain
------------------
The Javascript tracking code can send the website domain to Chartbeat.
If you use multiple subdomains this enables you to treat them as one
website in Chartbeat. If your project uses the sites framework, the
domain name of the current :class:`~django.contrib.sites.models.Site`
will be passed to Chartbeat automatically. You can modify this behavior
using the :const:`CHARTBEAT_AUTO_DOMAIN` setting::
CHARTBEAT_AUTO_DOMAIN = False
Alternatively, you set the domain through the ``chartbeat_domain``
context variable when you render the template::
context = RequestContext({'chartbeat_domain': 'example.com'})
return some_template.render(context)
It is annoying to do this for every view, so you may want to set it in
a context processor that you add to the
:data:`TEMPLATE_CONTEXT_PROCESSORS` list in :file:`settings.py`::
def chartbeat(request):
return {'chartbeat_domain': 'example.com'}
The context domain overrides the domain from the current site. If no
domain is set, either explicitly or implicitly through the sites
framework, then no domain is sent, and Chartbeat will detect the domain
name from the URL. If your website uses just one domain, this will work
just fine.
----
Thanks go to Chartbeat for their support with the development of this
application.
"""
chartbeat_service = {
'head_top': (
'analytical.chartbeat.templatetags.chartbeat.ChartbeatTopNode',
'top',
),
'body_bottom': (
'analytical.chartbeat.templatetags.chartbeat.ChartbeatBottomNode',
'bottom',
),
}

View file

@ -0,0 +1,96 @@
"""
Chartbeat template tags.
"""
import re
from django.conf import settings
from django.contrib.sites.models import Site
from django.core.exceptions import ImproperlyConfigured
from django.template import Library, Node, TemplateSyntaxError
from django.utils import simplejson
from analytical.utils import is_internal_ip, disable_html
USER_ID_RE = re.compile(r'^\d{5}$')
INIT_CODE = """<script type="text/javascript">var _sf_startpt=(new Date()).getTime()</script>"""
SETUP_CODE = """
<script type="text/javascript">
var _sf_async_config=%(config)s;
(function(){
function loadChartbeat() {
window._sf_endpt=(new Date()).getTime();
var e = document.createElement('script');
e.setAttribute('language', 'javascript');
e.setAttribute('type', 'text/javascript');
e.setAttribute('src',
(("https:" == document.location.protocol) ? "https://a248.e.akamai.net/chartbeat.download.akamai.com/102508/" : "http://static.chartbeat.com/") +
"js/chartbeat.js");
document.body.appendChild(e);
}
var oldonload = window.onload;
window.onload = (typeof window.onload != 'function') ?
loadChartbeat : function() { oldonload(); loadChartbeat(); };
})();
</script>
"""
DOMAIN_CONTEXT_KEY = 'chartbeat_domain'
register = Library()
@register.tag
def chartbeat_top(parser, token):
"""
Top Chartbeat template tag.
Render the top Javascript code for Chartbeat.
"""
bits = token.split_contents()
if len(bits) > 1:
raise TemplateSyntaxError("'%s' takes no arguments" % bits[0])
return ChartbeatTopNode()
class ChartbeatTopNode(Node):
def render(self, context):
if is_internal_ip(context):
return disable_html(INIT_CODE, 'Chartbeat')
return INIT_CODE
@register.tag
def chartbeat_bottom(parser, token):
"""
Bottom Chartbeat template tag.
Render the bottom Javascript code for Chartbeat. You must supply
your Chartbeat User ID (as a string) in the ``CHARTBEAT_USER_ID``
setting.
"""
bits = token.split_contents()
if len(bits) > 1:
raise TemplateSyntaxError("'%s' takes no arguments" % bits[0])
return ChartbeatBottomNode()
class ChartbeatBottomNode(Node):
def __init__(self):
self.user_id = self.get_required_setting(
'CHARTBEAT_USER_ID', USER_ID_RE,
"must be a string containing an five-digit number")
def render(self, context):
config = {'uid': self.user_id}
domain = context.get(DOMAIN_CONTEXT_KEY)
if domain is None and getattr(settings, 'CHARTBEAT_AUTO_DOMAIN', True):
try:
domain = Site.objects.get_current().domain
except (ImproperlyConfigured, Site.DoesNotExist):
pass
if domain is not None:
config['domain'] = domain
html = SETUP_CODE % {'config': simplejson.dumps(config)}
if is_internal_ip(context):
html = disable_html(html, 'Chartbeat')
return html

View file

@ -11,7 +11,7 @@ designed to be very easy to use.
.. _Clicky: http://getclicky.com/
.. clicky-template-tag:
.. clicky-installation:
Installation
============
@ -37,6 +37,7 @@ have the tag, it is useful to add it to your base template. Insert
the tag at the bottom of the HTML body::
{% load clicky %}
...
{% clicky %}
@ -55,8 +56,8 @@ website Site ID. You can also customize the data that Clicky tracks.
.. _clicky-site-id:
The Site ID
-----------
Setting the Site ID
-------------------
Every website you track with Clicky gets its own Site ID, and the
:ttag:`clicky` tag will include it in the rendered Javascript code.
@ -64,15 +65,21 @@ You can find the Site ID in the *Info* tab of the website *Preferences*
page, in your Clicky account. Set :const:`CLICKY_SITE_ID` in the
project :file:`settings.py` file::
CLICKY_SITE_ID = '12345678'
CLICKY_SITE_ID = 'XXXXXXXX'
If you do not set a Site ID, the tracking code will not be rendered.
Often you do not want to track clicks from your development or internal
IP addresses. By default, if the tag detects that the client comes from
any address in the :const:`INTERNAL_IPS` setting, the tracking code is
commented out. See :const:`ANALYTICAL_INTERNAL_IPS` for important
information about detecting the visitor IP address.
.. _clicky-internal-ips:
Internal IP addresses
---------------------
Usually you do not want to track clicks from your development or
internal IP addresses. By default, if the tags detect that the client
comes from any address in the :const:`INTERNAL_IPS` setting, the
tracking code is commented out. See :const:`ANALYTICAL_INTERNAL_IPS`
for important information about detecting the visitor IP address.
.. _clicky-custom-data:
@ -106,34 +113,34 @@ Here is a table with the most important variables. All variable listed
on the `customized tracking`_ documentation page can be set by replacing
``clicky_custom.`` with ``clicky_``.
================ =============== =====================================
Context variable Clicky property Description
================ =============== =====================================
clicky_session session_ Session data. A dictionary
containing ``username`` and/or
``group`` keys.
---------------- --------------- -------------------------------------
clicky_goal goal_ A succeeded goal. A dictionary
containing ``id`` and ``revenue``
keys.
---------------- --------------- -------------------------------------
clicky_href href_ The URL as tracked by Clicky. Default
is the page URL.
---------------- --------------- -------------------------------------
clicky_title title_ The page title as tracked by Clicky.
Default is the HTML title.
================ =============== =====================================
================== =============== ===================================
Context variable Clicky property Description
================== =============== ===================================
``clicky_session`` session_ Session data. A dictionary
containing ``username`` and/or
``group`` keys.
------------------ --------------- -----------------------------------
``clicky_goal`` goal_ A succeeded goal. A dictionary
containing ``id`` and ``revenue``
keys.
------------------ --------------- -----------------------------------
``clicky_href`` href_ The URL as tracked by Clicky.
Default is the page URL.
------------------ --------------- -----------------------------------
``clicky_title`` title_ The page title as tracked by
Clicky. Default is the HTML title.
================== =============== ===================================
By default, the username of an authenticated user is passed to Clicky
automatically in the session_ property, unless that property was set
explicitly. See :data:`ANALYTICAL_AUTO_IDENTIFY`.
.. _`customized tracking`: http://getclicky.com/help/customization
.. _session: http://getclicky.com/help/customization#goal
.. _session: http://getclicky.com/help/customization#session
.. _goal: http://getclicky.com/help/customization#goal
.. _href: http://getclicky.com/help/customization#href
.. _title: http://getclicky.com/help/customization#title
By default, the username of an authenticated user is passed to Clicky
automatically in the ``session.username`` property, unless that property
was set explicitly. See :data:`ANALYTICAL_AUTO_IDENTIFY`.
----

View file

@ -1,57 +0,0 @@
"""
Chartbeat service.
"""
import re
from django.contrib.sites.models import Site, RequestSite
from django.core.exceptions import ImproperlyConfigured
from django.utils import simplejson
from analytical.services.base import AnalyticalService
USER_ID_RE = re.compile(r'^\d{5}$')
INIT_CODE = """<script type="text/javascript">var _sf_startpt=(new Date()).getTime()</script>"""
SETUP_CODE = """
<script type="text/javascript">
var _sf_async_config=%(config)s;
(function(){
function loadChartbeat() {
window._sf_endpt=(new Date()).getTime();
var e = document.createElement('script');
e.setAttribute('language', 'javascript');
e.setAttribute('type', 'text/javascript');
e.setAttribute('src',
(("https:" == document.location.protocol) ? "https://a248.e.akamai.net/chartbeat.download.akamai.com/102508/" : "http://static.chartbeat.com/") +
"js/chartbeat.js");
document.body.appendChild(e);
}
var oldonload = window.onload;
window.onload = (typeof window.onload != 'function') ?
loadChartbeat : function() { oldonload(); loadChartbeat(); };
})();
</script>
"""
DOMAIN_CONTEXT_KEY = 'chartbeat_domain'
class ChartbeatService(AnalyticalService):
def __init__(self):
self.user_id = self.get_required_setting(
'CHARTBEAT_USER_ID', USER_ID_RE,
"must be a string containing an five-digit number")
def render_head_top(self, context):
return INIT_CODE
def render_body_bottom(self, context):
config = {'uid': self.user_id}
try:
config['domain'] = context[DOMAIN_CONTEXT_KEY]
except KeyError:
try:
config['domain'] = Site.objects.get_current().domain
except (ImproperlyConfigured, Site.DoesNotExist, AttributeError):
pass
return SETUP_CODE % {'config': simplejson.dumps(config)}

View file

@ -12,7 +12,7 @@ from django.utils.importlib import import_module
DEFAULT_SERVICES = [
'analytical.chartbeat.ChartbeatService',
'analytical.chartbeat.chartbeat_service',
'analytical.clicky.clicky_service',
'analytical.crazy_egg.CrazyEggService',
'analytical.google_analytics.GoogleAnalyticsService',

View file

@ -1,40 +1,3 @@
Chartbeat -- traffic analysis
=============================
.. currentmodule:: analytical.chartbeat
Chartbeat_ provides real-time analytics to websites and blogs. It shows
visitors, load times, and referring sites on a minute-by-minute basis.
The service also provides alerts the second your website crashes or
slows to a crawl.
.. _Chartbeat: http://www.chartbeat.com/
The Chartbeat service adds code both to the top of the head section and
the bottom of the body section. If the project uses the sites
framework, the domain name of the current website will be passed to
Chartbeat. Otherwise, Chartbeat will detect the domain name from the
URL.
Required settings
-----------------
.. data:: CHARTBEAT_USER_ID
The User ID::
CHARTBEAT_USER_ID = '12345'
You can find the User ID by visiting the Chartbeat `Add New Site`_
page. The second code snippet contains a line that looks like this::
var _sf_async_config={uid:XXXXX,domain:"YYYYYYYYYY"};
Here, ``XXXXX`` is your User ID.
.. _`Add New Site`: http://chartbeat.com/code/
----
Thanks go to Chartbeat for their support with the development of this
application.
.. automodule:: analytical.chartbeat