Skip to content

Commit

Permalink
feat(track): Introducing easier event tracking (#155)
Browse files Browse the repository at this point in the history
  • Loading branch information
aliabbasrizvi committed Jan 15, 2019
1 parent e03b60b commit a6709f2
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 232 deletions.
24 changes: 6 additions & 18 deletions optimizely/event_builder.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2016-2018, Optimizely
# Copyright 2016-2019, Optimizely
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
Expand Down Expand Up @@ -130,6 +130,7 @@ def _get_common_params(self, user_id, attributes):
commonParams[self.EventParams.USERS][0][self.EventParams.ATTRIBUTES] = self._get_attributes(attributes)

commonParams[self.EventParams.SOURCE_SDK_TYPE] = 'python-sdk'
commonParams[self.EventParams.ENRICH_DECISIONS] = True
commonParams[self.EventParams.SOURCE_SDK_VERSION] = version.__version__
commonParams[self.EventParams.ANONYMIZE_IP] = self._get_anonymize_ip()
commonParams[self.EventParams.REVISION] = self._get_revision()
Expand All @@ -152,6 +153,7 @@ class EventParams(object):
CAMPAIGN_ID = 'campaign_id'
VARIATION_ID = 'variation_id'
END_USER_ID = 'visitor_id'
ENRICH_DECISIONS = 'enrich_decisions'
EVENTS = 'events'
EVENT_ID = 'entity_id'
ATTRIBUTES = 'attributes'
Expand Down Expand Up @@ -233,30 +235,17 @@ def _get_required_params_for_impression(self, experiment, variation_id):

return snapshot

def _get_required_params_for_conversion(self, event_key, event_tags, decisions):
def _get_required_params_for_conversion(self, event_key, event_tags):
""" Get parameters that are required for the conversion event to register.
Args:
event_key: Key representing the event which needs to be recorded.
event_tags: Dict representing metadata associated with the event.
decisions: List of tuples representing valid experiments IDs and variation IDs.
Returns:
Dict consisting of the decisions and events info for conversion event.
"""
snapshot = {}
snapshot[self.EventParams.DECISIONS] = []

for experiment_id, variation_id in decisions:

experiment = self.config.get_experiment_from_id(experiment_id)

if variation_id:
snapshot[self.EventParams.DECISIONS].append({
self.EventParams.EXPERIMENT_ID: experiment_id,
self.EventParams.VARIATION_ID: variation_id,
self.EventParams.CAMPAIGN_ID: experiment.layerId
})

event_dict = {
self.EventParams.EVENT_ID: self.config.get_event(event_key).id,
Expand Down Expand Up @@ -303,22 +292,21 @@ def create_impression_event(self, experiment, variation_id, user_id, attributes)
http_verb=self.HTTP_VERB,
headers=self.HTTP_HEADERS)

def create_conversion_event(self, event_key, user_id, attributes, event_tags, decisions):
def create_conversion_event(self, event_key, user_id, attributes, event_tags):
""" Create conversion Event to be sent to the logging endpoint.
Args:
event_key: Key representing the event which needs to be recorded.
user_id: ID for user.
attributes: Dict representing user attributes and values.
event_tags: Dict representing metadata associated with the event.
decisions: List of tuples representing experiments IDs and variation IDs.
Returns:
Event object encapsulating the conversion event.
"""

params = self._get_common_params(user_id, attributes)
conversion_params = self._get_required_params_for_conversion(event_key, event_tags, decisions)
conversion_params = self._get_required_params_for_conversion(event_key, event_tags)

params[self.EventParams.USERS][0][self.EventParams.SNAPSHOTS].append(conversion_params)
return Event(self.EVENTS_URL,
Expand Down
61 changes: 13 additions & 48 deletions optimizely/optimizely.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2016-2018, Optimizely
# Copyright 2016-2019, Optimizely
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
Expand Down Expand Up @@ -133,31 +133,6 @@ def _validate_user_inputs(self, attributes=None, event_tags=None):

return True

def _get_decisions(self, event, user_id, attributes):
""" Helper method to retrieve decisions for the user for experiment(s) using the provided event.
Args:
event: The event which needs to be recorded.
user_id: ID for user.
attributes: Dict representing user attributes.
Returns:
List of tuples representing valid experiment IDs and variation IDs into which the user is bucketed.
"""
decisions = []
for experiment_id in event.experimentIds:
experiment = self.config.get_experiment_from_id(experiment_id)
variation_key = self.get_variation(experiment.key, user_id, attributes)

if not variation_key:
self.logger.info('Not tracking user "%s" for experiment "%s".' % (user_id, experiment.key))
continue

variation = self.config.get_variation_from_key(experiment.key, variation_key)
decisions.append((experiment_id, variation.id))

return decisions

def _send_impression_event(self, experiment, variation, user_id, attributes):
""" Helper method to send impression event.
Expand Down Expand Up @@ -322,28 +297,18 @@ def track(self, event_key, user_id, attributes=None, event_tags=None):
self.logger.info('Not tracking user "%s" for event "%s".' % (user_id, event_key))
return

# Filter out experiments that are not running or that do not include the user in audience
# conditions and then determine the decision i.e. the corresponding variation
decisions = self._get_decisions(event, user_id, attributes)

# Create and dispatch conversion event if there are any decisions
if decisions:
conversion_event = self.event_builder.create_conversion_event(
event_key, user_id, attributes, event_tags, decisions
)
self.logger.info('Tracking event "%s" for user "%s".' % (event_key, user_id))
self.logger.debug('Dispatching conversion event to URL %s with params %s.' % (
conversion_event.url,
conversion_event.params
))
try:
self.event_dispatcher.dispatch_event(conversion_event)
except:
self.logger.exception('Unable to dispatch conversion event!')
self.notification_center.send_notifications(enums.NotificationTypes.TRACK, event_key, user_id,
attributes, event_tags, conversion_event)
else:
self.logger.info('There are no valid experiments for event "%s" to track.' % event_key)
conversion_event = self.event_builder.create_conversion_event(event_key, user_id, attributes, event_tags)
self.logger.info('Tracking event "%s" for user "%s".' % (event_key, user_id))
self.logger.debug('Dispatching conversion event to URL %s with params %s.' % (
conversion_event.url,
conversion_event.params
))
try:
self.event_dispatcher.dispatch_event(conversion_event)
except:
self.logger.exception('Unable to dispatch conversion event!')
self.notification_center.send_notifications(enums.NotificationTypes.TRACK, event_key, user_id,
attributes, event_tags, conversion_event)

def get_variation(self, experiment_key, user_id, attributes=None):
""" Gets variation where user will be bucketed.
Expand Down
Loading

0 comments on commit a6709f2

Please sign in to comment.