mirror of
https://github.com/jazzband/django-analytical.git
synced 2026-03-16 22:20:25 +00:00
Refactor Chartbeat module into its own app
This commit has not been tested.
This commit is contained in:
parent
d715c16244
commit
05c82b833a
7 changed files with 282 additions and 128 deletions
145
analytical/chartbeat/__init__.py
Normal file
145
analytical/chartbeat/__init__.py
Normal 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',
|
||||
),
|
||||
}
|
||||
0
analytical/chartbeat/templatetags/__init__.py
Normal file
0
analytical/chartbeat/templatetags/__init__.py
Normal file
96
analytical/chartbeat/templatetags/chartbeat.py
Normal file
96
analytical/chartbeat/templatetags/chartbeat.py
Normal 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
|
||||
|
|
@ -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`.
|
||||
|
||||
|
||||
----
|
||||
|
||||
|
|
|
|||
|
|
@ -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)}
|
||||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue