Merge pull request #9875 from edx/bderusha/segment-cleanup

Segment Clean Up
This commit is contained in:
Bill DeRusha
2015-09-29 10:33:03 -04:00
28 changed files with 73 additions and 97 deletions

View File

@@ -1052,7 +1052,7 @@ class CourseEnrollment(models.Model):
with tracker.get_tracker().context(event_name, context):
tracker.emit(event_name, data)
if settings.FEATURES.get('SEGMENT_IO_LMS') and settings.SEGMENT_IO_LMS_KEY:
if settings.SEGMENT_KEY:
tracking_context = tracker.get_tracker().resolve_context()
analytics.track(self.user_id, event_name, {
'category': 'conversion',

View File

@@ -1163,11 +1163,11 @@ def login_user(request, error=""): # pylint: disable=too-many-statements,unused
LoginFailures.clear_lockout_counter(user)
# Track the user's sign in
if settings.FEATURES.get('SEGMENT_IO_LMS') and hasattr(settings, 'SEGMENT_IO_LMS_KEY'):
if settings.SEGMENT_KEY:
tracking_context = tracker.get_tracker().resolve_context()
analytics.identify(user.id, {
'email': email,
'username': username,
'username': username
})
analytics.track(
@@ -1601,7 +1601,7 @@ def create_account_with_params(request, params):
third_party_provider = provider.Registry.get_from_pipeline(running_pipeline)
# Track the user's registration
if settings.FEATURES.get('SEGMENT_IO_LMS') and hasattr(settings, 'SEGMENT_IO_LMS_KEY'):
if settings.SEGMENT_KEY:
tracking_context = tracker.get_tracker().resolve_context()
identity_args = [
user.id, # pylint: disable=no-member

View File

@@ -585,7 +585,7 @@ def set_logged_in_cookies(backend=None, user=None, strategy=None, auth_entry=Non
@partial.partial
def login_analytics(strategy, auth_entry, *args, **kwargs):
""" Sends login info to Segment.io """
""" Sends login info to Segment """
event_name = None
if auth_entry == AUTH_ENTRY_LOGIN:
@@ -593,7 +593,7 @@ def login_analytics(strategy, auth_entry, *args, **kwargs):
elif auth_entry in [AUTH_ENTRY_ACCOUNT_SETTINGS]:
event_name = 'edx.bi.user.account.linked'
if event_name is not None and hasattr(settings, 'SEGMENT_IO_LMS_KEY') and settings.SEGMENT_IO_LMS_KEY:
if event_name is not None and settings.SEGMENT_KEY:
tracking_context = tracker.get_tracker().resolve_context()
analytics.track(
kwargs['user'].id,

View File

@@ -67,7 +67,7 @@ def remove_shim_context(event):
context = event['context']
# These fields are present elsewhere in the event at this point
context_fields_to_remove = set(CONTEXT_FIELDS_TO_INCLUDE)
# This field is only used for Segment.io web analytics and does not concern researchers
# This field is only used for Segment web analytics and does not concern researchers
context_fields_to_remove.add('client_id')
for field in context_fields_to_remove:
if field in context:

View File

@@ -1,4 +1,4 @@
"""Handle events that were forwarded from the segment.io webhook integration"""
"""Handle events that were forwarded from the Segment webhook integration"""
import datetime
import json
@@ -35,28 +35,28 @@ ERROR_MISSING_RECEIVED_AT = 'Required receivedAt field not found'
@csrf_exempt
def segmentio_event(request):
"""
An endpoint for logging events using segment.io's webhook integration.
An endpoint for logging events using Segment's webhook integration.
segment.io provides a custom integration mechanism that initiates a request to a configurable URL every time an
Segment provides a custom integration mechanism that initiates a request to a configurable URL every time an
event is received by their system. This endpoint is designed to receive those requests and convert the events into
standard tracking log entries.
For now we limit the scope of handled events to track and screen events from mobile devices. In the future we could
enable logging of other types of events, however, there is significant overlap with our non-segment.io based event
tracking. Given that segment.io is closed third party solution we are limiting its required usage to just
enable logging of other types of events, however, there is significant overlap with our non-Segment based event
tracking. Given that Segment is closed third party solution we are limiting its required usage to just
collecting events from mobile devices for the time being.
Many of the root fields of a standard edX tracking event are read out of the "properties" dictionary provided by the
segment.io event, which is, in turn, provided by the client that emitted the event.
Segment event, which is, in turn, provided by the client that emitted the event.
In order for an event to be accepted and logged the "key" query string parameter must exactly match the django
setting TRACKING_SEGMENTIO_WEBHOOK_SECRET. While the endpoint is public, we want to limit access to it to the
segment.io servers only.
Segment servers only.
"""
# Validate the security token. We must use a query string parameter for this since we cannot customize the POST body
# in the segment.io webhook configuration, we can only change the URL that they call, so we force this token to be
# in the Segment webhook configuration, we can only change the URL that they call, so we force this token to be
# included in the URL and reject any requests that do not include it. This also assumes HTTPS is used to make the
# connection between their server and ours.
expected_secret = getattr(settings, 'TRACKING_SEGMENTIO_WEBHOOK_SECRET', None)
@@ -68,7 +68,7 @@ def segmentio_event(request):
track_segmentio_event(request)
except EventValidationError as err:
log.warning(
'Unable to process event received from segment.io: message="%s" event="%s"',
'Unable to process event received from Segment: message="%s" event="%s"',
str(err),
request.body
)
@@ -85,24 +85,24 @@ class EventValidationError(Exception):
def track_segmentio_event(request): # pylint: disable=too-many-statements
"""
Record an event received from segment.io to the tracking logs.
Record an event received from Segment to the tracking logs.
This method assumes that the event has come from a trusted source.
The received event must meet the following conditions in order to be logged:
* The value of the "type" field of the event must be included in the list specified by the django setting
TRACKING_SEGMENTIO_ALLOWED_TYPES. In order to make use of *all* of the features segment.io offers we would have
TRACKING_SEGMENTIO_ALLOWED_TYPES. In order to make use of *all* of the features Segment offers we would have
to implement some sort of persistent storage of information contained in some actions (like identify). For now,
we defer support of those actions and just support a limited set that can be handled without storing information
in external state.
* The value of the standard "userId" field of the event must be an integer that can be used to look up the user
using the primary key of the User model.
* Include a "name" field in the properties dictionary that indicates the edX event name. Note this can differ
from the "event" field found in the root of a segment.io event. The "event" field at the root of the structure is
from the "event" field found in the root of a Segment event. The "event" field at the root of the structure is
intended to be human readable, the "name" field is expected to conform to the standard for naming events
found in the edX data documentation.
* Have originated from a known and trusted segment.io client library. The django setting
* Have originated from a known and trusted Segment client library. The django setting
TRACKING_SEGMENTIO_SOURCE_MAP maps the known library names to internal "event_source" strings. In order to be
logged the event must have a library name that is a valid key in that map.
@@ -122,11 +122,11 @@ def track_segmentio_event(request): # pylint: disable=too-many-statements
# We mostly care about the properties
segment_properties = full_segment_event.get('properties', {})
# Start with the context provided by segment.io in the "client" field if it exists
# Start with the context provided by Segment in the "client" field if it exists
# We should tightly control which fields actually get included in the event emitted.
segment_context = full_segment_event.get('context')
# Build up the event context by parsing fields out of the event received from segment.io
# Build up the event context by parsing fields out of the event received from Segment
context = {}
library_name = segment_context.get('library', {}).get('name')

View File

@@ -1,4 +1,4 @@
"""Ensure we can parse events sent to us from the segment.io webhook integration"""
"""Ensure we can parse events sent to us from the Segment webhook integration"""
from datetime import datetime
import json
@@ -50,7 +50,7 @@ def expect_failure_with_message(message):
EVENT_TRACKING_PROCESSORS=MOBILE_SHIM_PROCESSOR,
)
class SegmentIOTrackingTestCase(EventTrackingTestCase):
"""Test processing of segment.io events"""
"""Test processing of Segment events"""
def setUp(self):
super(SegmentIOTrackingTestCase, self).setUp()
@@ -85,7 +85,7 @@ class SegmentIOTrackingTestCase(EventTrackingTestCase):
self.assert_no_events_emitted()
def create_request(self, key=None, **kwargs):
"""Create a fake request that emulates a request from the segment.io servers to ours"""
"""Create a fake request that emulates a request from the Segment servers to ours"""
if key is None:
key = SECRET
@@ -106,7 +106,7 @@ class SegmentIOTrackingTestCase(EventTrackingTestCase):
self.post_segmentio_event(name=name)
def post_segmentio_event(self, **kwargs):
"""Post a fake segment.io event to the view that processes it"""
"""Post a fake Segment event to the view that processes it"""
request = self.create_request(
data=self.create_segmentio_event_json(**kwargs),
content_type='application/json'
@@ -114,7 +114,7 @@ class SegmentIOTrackingTestCase(EventTrackingTestCase):
segmentio.track_segmentio_event(request)
def create_segmentio_event(self, **kwargs):
"""Populate a fake segment.io event with data of interest"""
"""Populate a fake Segment event with data of interest"""
action = kwargs.get('action', 'Track')
sample_event = {
"userId": kwargs.get('user_id', USER_ID),
@@ -158,7 +158,7 @@ class SegmentIOTrackingTestCase(EventTrackingTestCase):
return sample_event
def create_segmentio_event_json(self, **kwargs):
"""Return a json string containing a fake segment.io event"""
"""Return a json string containing a fake Segment event"""
return json.dumps(self.create_segmentio_event(**kwargs))
@expect_failure_with_message(segmentio.WARNING_IGNORED_SOURCE)