Coverage for portality/lib/plausible.py: 77%
53 statements
« prev ^ index » next coverage.py v6.4.2, created at 2022-09-21 00:49 +0100
« prev ^ index » next coverage.py v6.4.2, created at 2022-09-21 00:49 +0100
1# ~~ PlausibleAnalytics:ExternalService~~
2import json
3import logging
4import os
5import requests
7from functools import wraps
8from threading import Thread
10from portality.core import app
11from flask import request
13logger = logging.getLogger(__name__)
15# Keep track of when this is misconfigured so we don't spam the logs with skip messages
16_failstate = False
19def create_logfile(log_dir=None):
20 filepath = __name__ + '.log'
21 if log_dir is not None:
22 if not os.path.exists(log_dir):
23 os.makedirs(log_dir)
24 filepath = os.path.join(log_dir, filepath)
25 fh = logging.FileHandler(filepath)
26 fh.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s'))
27 logger.addHandler(fh)
30def send_event(goal: str, on_completed=None, **props_kwargs):
31 """ Send event data to Plausible Analytics. (ref: https://plausible.io/docs/events-api )
32 """
34 plausible_api_url = app.config.get('PLAUSIBLE_API_URL', '')
35 if not app.config.get('PLAUSIBLE_URL', '') and not plausible_api_url:
36 global _failstate
37 if not _failstate:
38 logger.warning('skip send_event, PLAUSIBLE_URL undefined')
39 _failstate = True
40 return
42 # prepare request payload
43 payload = {'name': goal,
44 'url': app.config.get('BASE_URL', 'http://localhost'),
45 'domain': app.config.get('PLAUSIBLE_SITE_NAME', 'localhost'), }
46 if props_kwargs:
47 payload['props'] = json.dumps(props_kwargs)
49 headers = {}
50 if request:
51 headers = {"X-Forwarded-For": request.remote_addr} # this works because we have ProxyFix on the app
53 def _send():
54 resp = requests.post(plausible_api_url, json=payload, headers=headers)
55 if on_completed:
56 if resp.status_code >= 300:
57 logger.warning(f'send plausible event api fail. [{resp.status_code}][{resp.text}]')
59 on_completed(resp)
61 Thread(target=_send).start()
64def pa_event(goal, action, label='',
65 record_value_of_which_arg='', **prop_kwargs):
66 """
67 Decorator for Flask view functions, sending event data to Plausible
68 Analytics.
69 """
71 def decorator(fn):
72 @wraps(fn)
73 def decorated_view(*args, **kwargs):
74 # define event label
75 el = label
76 if record_value_of_which_arg in kwargs:
77 el = kwargs[record_value_of_which_arg]
79 # prepare event props payload
80 event_payload = {
81 'action': action,
82 'label': el,
83 }
84 if prop_kwargs:
85 event_payload.update(prop_kwargs)
87 # send event
88 send_event(goal, **event_payload)
90 return fn(*args, **kwargs)
92 return decorated_view
94 return decorator