feat: experimental measurement protol reporting
This commit is contained in:
parent
0257299b5a
commit
0748249e1f
|
@ -1,18 +1,15 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
|
||||||
from six.moves.urllib.parse import urlencode
|
|
||||||
import logging
|
import logging
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
import requests
|
|
||||||
|
|
||||||
import ckan.plugins as p
|
import ckan.plugins as p
|
||||||
import ckan.plugins.toolkit as tk
|
import ckan.plugins.toolkit as tk
|
||||||
|
|
||||||
from ckan.exceptions import CkanConfigurationException, CkanVersionException
|
from ckan.exceptions import CkanConfigurationException, CkanVersionException
|
||||||
|
|
||||||
from .. import helpers
|
from .. import helpers, utils
|
||||||
from ..logic import action, auth
|
from ..logic import action, auth
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
@ -39,16 +36,8 @@ class AnalyticsPostThread(threading.Thread):
|
||||||
def run(self):
|
def run(self):
|
||||||
while True:
|
while True:
|
||||||
# grabs host from queue
|
# grabs host from queue
|
||||||
data_dict = self.queue.get()
|
data = self.queue.get()
|
||||||
|
utils.send_event(data)
|
||||||
data = urlencode(data_dict)
|
|
||||||
log.debug("Sending API event to Google Analytics: " + data)
|
|
||||||
# send analytics
|
|
||||||
requests.post(
|
|
||||||
"http://www.google-analytics.com/collect",
|
|
||||||
data,
|
|
||||||
timeout=10,
|
|
||||||
)
|
|
||||||
# signals to queue job is done
|
# signals to queue job is done
|
||||||
self.queue.task_done()
|
self.queue.task_done()
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,16 @@
|
||||||
import ast
|
import ast
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from six.moves.urllib.parse import urlencode
|
||||||
import ckantoolkit as tk
|
import ckantoolkit as tk
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
DEFAULT_RESOURCE_URL_TAG = "/downloads/"
|
DEFAULT_RESOURCE_URL_TAG = "/downloads/"
|
||||||
DEFAULT_RECENT_VIEW_DAYS = 14
|
DEFAULT_RECENT_VIEW_DAYS = 14
|
||||||
|
EVENT_API = "CKAN API Request"
|
||||||
|
|
||||||
|
|
||||||
def config_id():
|
def config_id():
|
||||||
|
@ -26,6 +33,20 @@ def config_tracking_mode():
|
||||||
return "ga"
|
return "ga"
|
||||||
|
|
||||||
|
|
||||||
|
def config_measurement_protocol_client_id():
|
||||||
|
return tk.config.get("googleanalytics.measurement_protocol.client_id")
|
||||||
|
|
||||||
|
|
||||||
|
def config_measurement_protocol_client_secret():
|
||||||
|
return tk.config.get("googleanalytics.measurement_protocol.client_secret")
|
||||||
|
|
||||||
|
|
||||||
|
def config_measurement_protocol_api_whitelist():
|
||||||
|
return tk.aslist(
|
||||||
|
tk.config.get("googleanalytics.measurement_protocol.api_tracking_whitelist")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def config_account():
|
def config_account():
|
||||||
return tk.config.get("googleanalytics.account")
|
return tk.config.get("googleanalytics.account")
|
||||||
|
|
||||||
|
@ -74,3 +95,75 @@ def config_recent_view_days():
|
||||||
"googleanalytics.recent_view_days", DEFAULT_RECENT_VIEW_DAYS
|
"googleanalytics.recent_view_days", DEFAULT_RECENT_VIEW_DAYS
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def send_event(data):
|
||||||
|
if isinstance(data, MeasurementProtocolData):
|
||||||
|
if data["event"] != EVENT_API:
|
||||||
|
log.warning("Only API event supported by Measurement Protocol at the moment")
|
||||||
|
return
|
||||||
|
|
||||||
|
return _mp_api_handler({
|
||||||
|
"action": data["object"],
|
||||||
|
"payload": data["payload"],
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
return _ga_handler(data)
|
||||||
|
|
||||||
|
|
||||||
|
class SafeJSONEncoder(json.JSONEncoder):
|
||||||
|
def default(self, _):
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _mp_api_handler(data_dict):
|
||||||
|
whitelist = set(config_measurement_protocol_api_whitelist())
|
||||||
|
if whitelist and data_dict["action"] not in whitelist:
|
||||||
|
log.debug(
|
||||||
|
"Skip sending %s API action to Google Analytics because it is not whitelisted",
|
||||||
|
data_dict["action"]
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
log.debug(
|
||||||
|
"Sending API event to Google Analytics using the Measurement Protocol: %s",
|
||||||
|
data_dict
|
||||||
|
)
|
||||||
|
resp = requests.post(
|
||||||
|
"https://www.google-analytics.com/mp/collect",
|
||||||
|
params={
|
||||||
|
"api_secret": config_measurement_protocol_client_secret(),
|
||||||
|
"measurement_id": config_id()
|
||||||
|
},
|
||||||
|
data=json.dumps({
|
||||||
|
"client_id": config_measurement_protocol_client_id(),
|
||||||
|
"non_personalized_ads": False,
|
||||||
|
"events":[{
|
||||||
|
"name": data_dict["action"],
|
||||||
|
"params": data_dict["payload"]
|
||||||
|
}]
|
||||||
|
}, cls=SafeJSONEncoder)
|
||||||
|
)
|
||||||
|
# breakpoint()
|
||||||
|
if resp.status_code >= 300:
|
||||||
|
log.error("Cannot post event: %s", resp)
|
||||||
|
|
||||||
|
|
||||||
|
def _ga_handler(data_dict):
|
||||||
|
data = urlencode(data_dict)
|
||||||
|
log.debug("Sending API event to Google Analytics: %s", data)
|
||||||
|
|
||||||
|
requests.post(
|
||||||
|
"http://www.google-analytics.com/collect",
|
||||||
|
data,
|
||||||
|
timeout=10,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class UniversalAnalyticsData(dict):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class MeasurementProtocolData(dict):
|
||||||
|
pass
|
||||||
|
|
|
@ -12,6 +12,7 @@ import ckan.views.api as api
|
||||||
import ckan.views.resource as resource
|
import ckan.views.resource as resource
|
||||||
|
|
||||||
from ckan.common import g
|
from ckan.common import g
|
||||||
|
from . import utils
|
||||||
|
|
||||||
CONFIG_HANDLER_PATH = "googleanalytics.download_handler"
|
CONFIG_HANDLER_PATH = "googleanalytics.download_handler"
|
||||||
|
|
||||||
|
@ -30,7 +31,7 @@ def action(logic_function, ver=api.API_MAX_VERSION):
|
||||||
id = request_data["q"]
|
id = request_data["q"]
|
||||||
if "query" in request_data:
|
if "query" in request_data:
|
||||||
id = request_data[u"query"]
|
id = request_data[u"query"]
|
||||||
_post_analytics(g.user, "CKAN API Request", logic_function, "", id)
|
_post_analytics(g.user, utils.EVENT_API, logic_function, "", id, request_data)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.debug(e)
|
log.debug(e)
|
||||||
pass
|
pass
|
||||||
|
@ -87,23 +88,34 @@ ga.add_url_rule(
|
||||||
|
|
||||||
|
|
||||||
def _post_analytics(
|
def _post_analytics(
|
||||||
user, event_type, request_obj_type, request_function, request_id
|
user, event_type,
|
||||||
|
request_obj_type, request_function,
|
||||||
|
request_id, request_payload=None
|
||||||
):
|
):
|
||||||
|
|
||||||
from ckanext.googleanalytics.plugin import GoogleAnalyticsPlugin
|
from ckanext.googleanalytics.plugin import GoogleAnalyticsPlugin
|
||||||
|
|
||||||
if tk.config.get("googleanalytics.id"):
|
if tk.config.get("googleanalytics.id"):
|
||||||
data_dict = {
|
if utils.config_measurement_protocol_client_id() and event_type == utils.EVENT_API:
|
||||||
"v": 1,
|
data_dict = utils.MeasurementProtocolData({
|
||||||
"tid": tk.config.get("googleanalytics.id"),
|
"event": event_type,
|
||||||
"cid": hashlib.md5(six.ensure_binary(tk.c.user)).hexdigest(),
|
"object": event_type,
|
||||||
# customer id should be obfuscated
|
"function": event_type,
|
||||||
"t": "event",
|
"id": request_id,
|
||||||
"dh": tk.request.environ["HTTP_HOST"],
|
"payload": request_payload,
|
||||||
"dp": tk.request.environ["PATH_INFO"],
|
})
|
||||||
"dr": tk.request.environ.get("HTTP_REFERER", ""),
|
else:
|
||||||
"ec": event_type,
|
data_dict = utils.UniversalAnalyticsData({
|
||||||
"ea": request_obj_type + request_function,
|
"v": 1,
|
||||||
"el": request_id,
|
"tid": tk.config.get("googleanalytics.id"),
|
||||||
}
|
"cid": hashlib.md5(six.ensure_binary(tk.c.user)).hexdigest(),
|
||||||
|
# customer id should be obfuscated
|
||||||
|
"t": "event",
|
||||||
|
"dh": tk.request.environ["HTTP_HOST"],
|
||||||
|
"dp": tk.request.environ["PATH_INFO"],
|
||||||
|
"dr": tk.request.environ.get("HTTP_REFERER", ""),
|
||||||
|
"ec": event_type,
|
||||||
|
"ea": request_obj_type + request_function,
|
||||||
|
"el": request_id,
|
||||||
|
})
|
||||||
GoogleAnalyticsPlugin.analytics_queue.put(data_dict)
|
GoogleAnalyticsPlugin.analytics_queue.put(data_dict)
|
||||||
|
|
Loading…
Reference in New Issue