Coverage for portality/lib/analytics.py: 0%
58 statements
« prev ^ index » next coverage.py v6.4.2, created at 2022-07-22 15:59 +0100
« prev ^ index » next coverage.py v6.4.2, created at 2022-07-22 15:59 +0100
1# ~~ GoogleAnalytics:ExternalService~~
2import logging
3import os
4from functools import wraps
6# Logger specific to analytics
7logger = logging.getLogger(__name__)
8logger.setLevel(logging.DEBUG)
10# The global tracker object
11tracker = None
14class GAException(Exception):
15 pass
18def create_tracker(ga_id, domain):
19 global tracker
20 if ga_id:
21 #tracker = UniversalAnalytics.Tracker.create(ga_id, client_id=domain)
22 raise GAException("GA is not running because universal-analytics is broken in Python 3")
23 else:
24 raise GAException("Invalid GA ID supplied, no tracker created.")
27def create_logfile(log_dir=None):
28 filepath = __name__ + '.log'
29 if log_dir is not None:
30 if not os.path.exists(log_dir):
31 os.makedirs(log_dir)
32 filepath = os.path.join(log_dir, filepath)
33 fh = logging.FileHandler(filepath)
34 fh.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s'))
35 logger.addHandler(fh)
38class GAEvent(object):
39 category = None
40 action = None
41 label = None
42 value = None
43 fieldsobject = None
45 def __init__(self, category, action, label='', value=None, fieldsobject=None):
46 self.category = category
47 self.action = action
48 self.label = label
49 self.value = value
50 self.fieldsobject=fieldsobject
52 def submit(self):
53 ga_send_event(self.category, self.action, self.label, self.value, self.fieldsobject)
56def ga_send_event(category, action, label='', value=None, fieldsobject=None):
57 """
58 Send event data to Google Analytics.
59 (supposedly supporting other analytics providers as well,
60 check https://github.com/analytics-pros/universal-analytics-python )
62 See https://support.google.com/analytics/answer/1033068?hl=en for
63 guidance on how to use the various event properties this decorator
64 takes.
66 One thing to note is that event_value must be an integer. We
67 don't really use that, it's for things like "total downloads" or
68 "number of times video played".
70 The others are strings and can be anything we like. They must
71 take into account what previous strings we've sent so that events
72 can be aggregated correctly. Changing the strings you use for
73 categories, actions and labels to describe the same event will
74 split your analytics reports into two: before and after the
75 change of the event strings you use.
77 :param category: Typically the object that was interacted with (e.g. 'Video')
78 :param action: The type of interaction (e.g. 'play')
79 :param label: Useful for categorizing events (e.g. 'Fall Campaign')
80 :param value: A non-negative numeric value associated with the event (e.g. 42)
81 :param fieldsobject: Key, value pairs which don't fit into the above categories
82 """
84 # Write event to file even if there's no tracker configured.
85 analytics_args = [category, action]
87 if label != '':
88 analytics_args.append(label)
89 if value is not None:
90 analytics_args.append(value)
91 if fieldsobject is not None:
92 analytics_args.append(fieldsobject)
94 logger.debug("Event Send %s", analytics_args)
96 # Send the event to GA via the tracker
97 if tracker is not None:
98 tracker.send('event', *analytics_args)
99 else:
100 # logger.error("Google Analytics tracker is not configured.")
101 pass # we now know it's broken, stop spamming this in our logs.
104def sends_ga_event(event_category, event_action, event_label='',
105 event_value=0, record_value_of_which_arg=''):
106 """
107 Decorator for Flask view functions, sending event data to Google
108 Analytics.
110 :param event_category:
111 :param event_action:
112 :param event_label:
113 :param event_value:
115 :param record_value_of_which_arg: The name of one argument that
116 the view function takes. During tracking, the value of that
117 argument will be extracted and sent as the Event Label to the
118 analytics servers. NOTE! If you pass both event_label and
119 record_value_of_which_arg to this decorator, event_label will be
120 ignored and overwritten by the action that
121 record_value_of_which_arg causes.
123 For example:
124 @sends_ga_event('API Hit', 'Search applications',
125 record_value_of_which_arg='search_query')
126 def search_applications(search_query):
127 # ...
129 Then we get a hit, with search_query being set to 'computer shadows'.
130 This will result in an event with category "API Hit", action "Search
131 applications" and label "computer shadows".
133 A different example:
134 @sends_ga_event('API Hit', 'Retrieve application',
135 record_value_of_which_arg='application_id')
136 def retrieve_application(application_id):
137 # ...
139 Then we get a hit asking for application with id '12345'.
140 This will result in an event with category "API Hit", action "Retrieve
141 application" and label "12345".
143 Clashing arguments:
144 @sends_ga_event('API Hit', 'Retrieve application',
145 event_label='Special interest action',
146 record_value_of_which_arg='application_id')
147 def retrieve_application(application_id):
148 # ...
150 Then we get a hit asking for application with id '12345' again.
151 This will result in an event with category "API Hit", action "Retrieve
152 application" and label "12345". I.e. the event_label passed in will
153 be ignored, because we also passed in record_value_of_which_arg which
154 overrides the event label sent to the analytics servers.
156 On testing: this has been tested manually on DOAJ with Google
157 Analytics by @emanuil-tolev & @Steven-Eardley.
158 """
160 def decorator(fn):
161 @wraps(fn)
162 def decorated_view(*args, **kwargs):
163 el = event_label
164 if record_value_of_which_arg in kwargs:
165 el = kwargs[record_value_of_which_arg]
167 ga_send_event(event_category, event_action, el, event_value)
169 return fn(*args, **kwargs)
171 return decorated_view
172 return decorator