feat: experimental measurement protol reporting

This commit is contained in:
Sergey Motornyuk 2022-08-24 01:52:08 +03:00
parent 0257299b5a
commit 0748249e1f
3 changed files with 123 additions and 29 deletions

View File

@ -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()

View File

@ -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

View File

@ -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)