lbry-sdk/lbrynet/analytics/api.py

89 lines
2.7 KiB
Python
Raw Normal View History

import functools
import json
import logging
from requests import auth
from requests_futures import sessions
from lbrynet import conf
from lbrynet.analytics import utils
log = logging.getLogger(__name__)
def log_response(fn):
def _log(future):
if future.cancelled():
log.warning('Request was unexpectedly cancelled')
2016-11-17 01:10:49 +01:00
elif future.exception():
2016-11-22 21:18:01 +01:00
exc, traceback = future.exception_info()
log.warning('Failed to send an analytics event', exc_info=(type(exc), exc, traceback))
else:
response = future.result()
log.debug('Response (%s): %s', response.status_code, response.content)
@functools.wraps(fn)
def wrapper(*args, **kwargs):
future = fn(*args, **kwargs)
future.add_done_callback(_log)
return future
return wrapper
2016-10-01 17:47:37 +02:00
class Api(object):
def __init__(self, session, url, write_key):
self.session = session
self.url = url
self.write_key = write_key
def post(self, endpoint, data):
# there is an issue with a timing condition with keep-alive
# that is best explained here: https://github.com/mikem23/keepalive-race
#
# If you make a request, wait just the right amount of time,
# then make another request, the requests module may opt to
# reuse the connection, but by the time the server gets it the
# timeout will have expired.
#
# by forcing the connection to close, we will disable the keep-alive.
assert endpoint[0] == '/'
headers = {"Connection": "close"}
return self.session.post(
self.url + endpoint, json=data, auth=self.auth, headers=headers)
@property
def auth(self):
return auth.HTTPBasicAuth(self.write_key, '')
@log_response
def batch(self, events):
"""Send multiple events in one request.
Each event needs to have its type specified.
"""
data = json.dumps({
'batch': events,
'sentAt': utils.now(),
})
log.debug('sending %s events', len(events))
log.debug('Data: %s', data)
return self.post('/batch', data)
@log_response
def track(self, event):
"""Send a single tracking event"""
log.debug('Sending track event: %s', event)
return self.post('/track', event)
@classmethod
def new_instance(cls, session=None):
"""Initialize an instance using values from the configuration"""
if not session:
session = sessions.FuturesSession()
return cls(
session,
conf.settings.ANALYTICS_ENDPOINT,
utils.deobfuscate(conf.settings.ANALYTICS_TOKEN)
)