Merge pull request #143 from mesosphere/identity-analytics

Identity analytics -- DCOS-1258
This commit is contained in:
mgummelt
2015-04-30 13:37:40 -07:00
6 changed files with 121 additions and 26 deletions

View File

@@ -50,25 +50,63 @@ def wait_and_track(subproc):
return exit_code
def _send_segment_event(event, properties):
def _segment_track(event, conf, properties):
"""
Send a segment event
Send a segment.io 'track' event
:param event: name of event
:type event: string
:param conf: dcos config file
:type conf: Toml
:param properties: event properties
:type properties: dict
:rtype: None
"""
data = {'anonymousId': session_id,
'event': event,
data = {'event': event,
'properties': properties}
if 'core.email' in conf:
data['userId'] = conf['core.email']
else:
data['anonymousId'] = session_id
_segment_request('track', data)
def segment_identify(conf):
"""
Send a segment.io 'identify' event
:param conf: dcos config file
:type conf: Toml
:rtype: None
"""
if 'core.email' in conf:
data = {'userId': conf.get('core.email')}
else:
data = {'anonymousId': session_id}
_segment_request('identify', data)
def _segment_request(path, data):
"""
Send a segment.io HTTP request
:param path: URL path
:type path: str
:param data: json POST data
:type data: dict
:rtype: None
"""
key = SEGMENT_IO_WRITE_KEY_PROD if _is_prod() else \
SEGMENT_IO_WRITE_KEY_DEV
try:
requests.post(SEGMENT_URL,
requests.post('{}/{}'.format(SEGMENT_URL, path),
json=data,
auth=HTTPBasicAuth(key, ''),
timeout=1)
@@ -135,7 +173,7 @@ def _segment_track_cli(pool, conf):
"""
props = _base_properties(conf)
pool.submit(_send_segment_event, SEGMENT_IO_CLI_EVENT, props)
pool.submit(_segment_track, SEGMENT_IO_CLI_EVENT, conf, props)
def _segment_track_err(pool, conf, err, exit_code):
@@ -156,7 +194,7 @@ def _segment_track_err(pool, conf, err, exit_code):
props = _base_properties(conf)
props['err'] = err
props['exit_code'] = exit_code
pool.submit(_send_segment_event, SEGMENT_IO_CLI_ERROR_EVENT, props)
pool.submit(_segment_track, SEGMENT_IO_CLI_ERROR_EVENT, conf, props)
def _rollbar_track_err(conf, err, exit_code):

View File

@@ -30,8 +30,9 @@ import docopt
import pkg_resources
import six
import toml
from dcos.api import (cmds, config, constants, emitting, errors, jsonitem,
options, subcommand, util)
from dcos.api import (cmds, config, constants, emitting, errors, http,
jsonitem, options, subcommand, util)
from dcoscli.analytics import segment_identify
emitter = emitting.FlatEmitter()
@@ -46,6 +47,8 @@ def main():
__doc__,
version='dcos-config version {}'.format(dcoscli.version))
http.silence_requests_warnings()
returncode, err = cmds.execute(_cmds(), args)
if err is not None:
emitter.publish(err)
@@ -132,6 +135,11 @@ def _set(name, value):
return 1
toml_config[name] = python_value
if (name == 'core.reporting' and python_value is True) or \
(name == 'core.email'):
segment_identify(toml_config)
_save_config_file(config_path, toml_config)
return 0

View File

@@ -4,6 +4,6 @@ SEGMENT_IO_WRITE_KEY_PROD = '51ybGTeFEFU1xo6u10XMDrr6kATFyRyh'
SEGMENT_IO_WRITE_KEY_DEV = '39uhSEOoRHMw6cMR6st9tYXDbAL3JSaP'
SEGMENT_IO_CLI_EVENT = 'dcos-cli'
SEGMENT_IO_CLI_ERROR_EVENT = 'dcos-cli-error'
SEGMENT_URL = 'https://api.segment.io/v1/track'
SEGMENT_URL = 'https://api.segment.io/v1'
DCOS_PRODUCTION_ENV = 'DCOS_PRODUCTION'

View File

@@ -1,3 +1,3 @@
[core]
reporting = true
email = "test@mail.com"
reporting = true

View File

@@ -60,3 +60,30 @@ def assert_command(cmd,
assert returncode_ == returncode
assert stdout_ == stdout
assert stderr_ == stderr
def mock_called_some_args(mock, *args, **kwargs):
"""Convience method for some mock assertions. Returns True if the
arguments to one of the calls of `mock` contains `args` and
`kwargs`.
:param mock: the mock to check
:type mock: mock.Mock
:returns: True if the arguments to one of the calls for `mock`
contains `args` and `kwargs`.
:rtype: bool
"""
for call in mock.call_args_list:
call_args, call_kwargs = call
if any(arg not in call_args for arg in args):
continue
if any(k not in call_kwargs or call_kwargs[k] != v
for k, v in kwargs.items()):
continue
return True
return False

View File

@@ -6,15 +6,18 @@ import requests
import rollbar
from dcos.api import constants, util
from dcoscli.analytics import _base_properties
from dcoscli.config.main import main as config_main
from dcoscli.constants import (ROLLBAR_SERVER_POST_KEY,
SEGMENT_IO_CLI_ERROR_EVENT,
SEGMENT_IO_CLI_EVENT, SEGMENT_IO_WRITE_KEY_DEV,
SEGMENT_IO_WRITE_KEY_PROD, SEGMENT_URL)
from dcoscli.main import main
from common import mock_called_some_args
from mock import patch
ANON_ID = 0
USER_ID = 'test@mail.com'
def _mock(fn):
@@ -38,7 +41,6 @@ def test_no_exc():
'''
# args
args = [util.which('dcos')]
env = _env_reporting()
@@ -46,14 +48,13 @@ def test_no_exc():
assert main() == 0
# segment.io
args, kwargs = requests.post.call_args
assert args == (SEGMENT_URL,)
props = _base_properties()
assert kwargs['json'] == {'anonymousId': ANON_ID,
'event': SEGMENT_IO_CLI_EVENT,
'properties': props}
assert kwargs['timeout'] == 1
data = {'userId': USER_ID,
'event': SEGMENT_IO_CLI_EVENT,
'properties': _base_properties()}
assert mock_called_some_args(requests.post,
'{}/track'.format(SEGMENT_URL),
json=data,
timeout=1)
# rollbar
assert rollbar.report_message.call_count == 0
@@ -66,7 +67,6 @@ def test_exc():
'''
# args
args = [util.which('dcos')]
env = _env_reporting()
@@ -77,15 +77,19 @@ def test_exc():
assert main() == 1
# segment.io
_, kwargs = requests.post.call_args_list[1]
props = _base_properties()
props['err'] = 'Traceback'
props['exit_code'] = 1
assert kwargs['json'] == {'anonymousId': ANON_ID,
'event': SEGMENT_IO_CLI_ERROR_EVENT,
'properties': props}
data = {'userId': USER_ID,
'event': SEGMENT_IO_CLI_ERROR_EVENT,
'properties': props}
assert mock_called_some_args(requests.post,
'{}/track'.format(SEGMENT_URL),
json=data,
timeout=1)
# rollbar
props = _base_properties()
props['exit_code'] = 1
rollbar.report_message.assert_called_with('Traceback', 'error',
@@ -150,6 +154,24 @@ def test_production_setting_false():
rollbar.init.assert_called_with(ROLLBAR_SERVER_POST_KEY, 'dev')
@_mock
def test_config_set():
'''Tests that a `dcos config set core.email <email>` makes a
segment.io identify call'''
args = [util.which('dcos'), 'config', 'set', 'core.email', 'test@mail.com']
env = _env_reporting()
with patch('sys.argv', args), patch.dict(os.environ, env):
assert config_main() == 0
# segment.io
assert mock_called_some_args(requests.post,
'{}/identify'.format(SEGMENT_URL),
json={'userId': 'test@mail.com'},
timeout=1)
def _env_reporting():
path = os.path.join('tests', 'data', 'analytics', 'dcos_reporting.toml')
return {constants.DCOS_CONFIG_ENV: path}