Revert "Merge pull request #6 from datagovau/api-analytics-event-tracking"

This reverts commit 0febe11dc5, reversing
changes made to e45d73d7a3.

This has been reverted for caushing Apache to max out threads when running
under mod_wsgi.
This commit is contained in:
nigelb 2015-02-13 14:22:53 +05:30
parent 0febe11dc5
commit f4fce47601
5 changed files with 11 additions and 205 deletions

View File

@ -18,9 +18,6 @@ Features
resource downloads will be displayed as Events in the Google Analytics resource downloads will be displayed as Events in the Google Analytics
reporting interface. reporting interface.
* Adds Google Analytics Event Tracking to some API calls so that usage of the
API can be reported on via Google Analytics.
* Adds Google Analytics Event Tracking to group links on the home page, * Adds Google Analytics Event Tracking to group links on the home page,
user profile links, editing and saving user profiles, etc. user profile links, editing and saving user profiles, etc.

View File

@ -1,151 +1,12 @@
import logging import logging
from ckan.lib.base import BaseController, c, render, request from ckan.lib.base import BaseController, c, render
import dbutil import dbutil
import urllib
import urllib2
import logging
import ckan.logic as logic
import hashlib
import Queue
import threading
from pylons import config
from webob.multidict import UnicodeMultiDict
from paste.util.multidict import MultiDict
from ckan.controllers.api import ApiController
log = logging.getLogger('ckanext.googleanalytics') log = logging.getLogger('ckanext.googleanalytics')
class GAController(BaseController): class GAController(BaseController):
def view(self): def view(self):
# get package objects corresponding to popular GA content # get package objects corresponding to popular GA content
c.top_packages = dbutil.get_top_packages(limit=10) c.top_packages = dbutil.get_top_packages(limit=10)
c.top_resources = dbutil.get_top_resources(limit=10) c.top_resources = dbutil.get_top_resources(limit=10)
return render('summary.html') return render('summary.html')
class AnalyticsPostThread(threading.Thread):
"""Threaded Url POST"""
def __init__(self, queue):
threading.Thread.__init__(self)
self.queue = queue
def run(self):
while True:
# grabs host from queue
data_dict = self.queue.get()
data = urllib.urlencode(data_dict)
log.debug("Sending API event to Google Analytics: " + data)
# send analytics
urllib2.urlopen(
"http://www.google-analytics.com/collect",
data,
# timeout in seconds
# https://docs.python.org/2/library/urllib2.html#urllib2.urlopen
10)
# signals to queue job is done
self.queue.task_done()
class GAApiController(ApiController):
# intercept API calls to record via google analytics
analytics_queue = Queue.Queue()
def __init__(self):
# spawn a pool of 5 threads, and pass them queue instance
for i in range(5):
t = AnalyticsPostThread(self.analytics_queue)
t.setDaemon(True)
t.start()
def _post_analytics(
self, user, request_obj_type, request_function, request_id):
if config.get('googleanalytics.id'):
data_dict = {
"v": 1,
"tid": config.get('googleanalytics.id'),
"cid": hashlib.md5(user).hexdigest(),
# customer id should be obfuscated
"t": "event",
"dh": c.environ['HTTP_HOST'],
"dp": c.environ['PATH_INFO'],
"dr": c.environ.get('HTTP_REFERER', ''),
"ec": "CKAN API Request",
"ea": request_obj_type+request_function,
"el": request_id,
}
self.analytics_queue.put(data_dict)
def action(self, logic_function, ver=None):
try:
function = logic.get_action(logic_function)
side_effect_free = getattr(function, 'side_effect_free', False)
request_data = self._get_request_data(
try_url_params=side_effect_free)
if isinstance(request_data, dict):
id = request_data.get('id', '')
if 'q' in request_data:
id = request_data['q']
if 'query' in request_data:
id = request_data['query']
self._post_analytics(c.user, logic_function, '', id)
except Exception, e:
log.debug(e)
pass
return ApiController.action(self, logic_function, ver)
def list(self, ver=None, register=None,
subregister=None, id=None):
self._post_analytics(c.user,
register +
("_"+str(subregister) if subregister else ""),
"list",
id)
return ApiController.list(self, ver, register, subregister, id)
def show(self, ver=None, register=None,
subregister=None, id=None, id2=None):
self._post_analytics(c.user,
register +
("_"+str(subregister) if subregister else ""),
"show",
id)
return ApiController.show(self, ver, register, subregister, id, id2)
def update(self, ver=None, register=None,
subregister=None, id=None, id2=None):
self._post_analytics(c.user,
register +
("_"+str(subregister) if subregister else ""),
"update",
id)
return ApiController.update(self, ver, register, subregister, id, id2)
def delete(self, ver=None, register=None,
subregister=None, id=None, id2=None):
self._post_analytics(c.user,
register +
("_"+str(subregister) if subregister else ""),
"delete",
id)
return ApiController.delete(self, ver, register, subregister, id, id2)
def search(self, ver=None, register=None):
id = None
try:
params = MultiDict(self._get_search_params(request.params))
if 'q' in params.keys():
id = params['q']
if 'query' in params.keys():
id = params['query']
except ValueError, e:
log.debug(str(e))
pass
self._post_analytics(c.user, register, "search", id)

View File

@ -8,7 +8,7 @@ this.ckan.module('google-analytics', function(jQuery, _) {
jQuery('a.resource-url-analytics').on('click', function() { jQuery('a.resource-url-analytics').on('click', function() {
var resource_url = encodeURIComponent(jQuery(this).prop('href')); var resource_url = encodeURIComponent(jQuery(this).prop('href'));
if (resource_url) { if (resource_url) {
ga('send', 'event', 'Resource', 'Download', resource_url); _gaq.push(['_trackEvent', 'Resource', 'Download', resource_url]);
} }
}); });
} }

View File

@ -8,7 +8,6 @@ import pylons
import ckan.lib.helpers as h import ckan.lib.helpers as h
import ckan.plugins as p import ckan.plugins as p
import gasnippet import gasnippet
from routes.mapper import SubMapper, Mapper as _Mapper
log = logging.getLogger('ckanext.googleanalytics') log = logging.getLogger('ckanext.googleanalytics')
@ -68,58 +67,6 @@ class GoogleAnalyticsPlugin(p.SingletonPlugin):
else: else:
p.toolkit.add_template_directory(config, 'templates') p.toolkit.add_template_directory(config, 'templates')
def before_map(self, map):
'''Add new routes that this extension's controllers handle.
See IRoutes.
'''
# Helpers to reduce code clutter
GET = dict(method=['GET'])
PUT = dict(method=['PUT'])
POST = dict(method=['POST'])
DELETE = dict(method=['DELETE'])
GET_POST = dict(method=['GET', 'POST'])
# intercept API calls that we want to capture analytics on
register_list = [
'package',
'dataset',
'resource',
'tag',
'group',
'related',
'revision',
'licenses',
'rating',
'user',
'activity'
]
register_list_str = '|'.join(register_list)
# /api ver 3 or none
with SubMapper(map, controller='ckanext.googleanalytics.controller:GAApiController', path_prefix='/api{ver:/3|}',
ver='/3') as m:
m.connect('/action/{logic_function}', action='action',
conditions=GET_POST)
# /api ver 1, 2, 3 or none
with SubMapper(map, controller='ckanext.googleanalytics.controller:GAApiController', path_prefix='/api{ver:/1|/2|/3|}',
ver='/1') as m:
m.connect('/search/{register}', action='search')
# /api/rest ver 1, 2 or none
with SubMapper(map, controller='ckanext.googleanalytics.controller:GAApiController', path_prefix='/api{ver:/1|/2|}',
ver='/1', requirements=dict(register=register_list_str)
) as m:
m.connect('/rest/{register}', action='list', conditions=GET)
m.connect('/rest/{register}', action='create', conditions=POST)
m.connect('/rest/{register}/{id}', action='show', conditions=GET)
m.connect('/rest/{register}/{id}', action='update', conditions=PUT)
m.connect('/rest/{register}/{id}', action='update', conditions=POST)
m.connect('/rest/{register}/{id}', action='delete', conditions=DELETE)
return map
def after_map(self, map): def after_map(self, map):
'''Add new routes that this extension's controllers handle. '''Add new routes that this extension's controllers handle.

View File

@ -1,10 +1,11 @@
<script type="text/javascript"> <script type="text/javascript">
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ var _gaq = _gaq || [];
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), _gaq.push(['_setAccount', '{{googleanalytics_id}}']);
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) _gaq.push(['_setDomainName', '{{googleanalytics_domain}}']);
})(window,document,'script','//www.google-analytics.com/analytics.js','ga'); _gaq.push(['_trackPageview']);
(function() {
ga('create', '{{googleanalytics_id}}', '{{googleanalytics_domain}}'); var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga('set', 'anonymizeIp', true); ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
ga('send', 'pageview'); var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script> </script>