Skip to content

Commit

Permalink
Rename track to trackUiMetric, and simplify logic to not involve inte…
Browse files Browse the repository at this point in the history
…rceptors.

- Add support for an array of metric types.
- Update README.
  • Loading branch information
cjcenizal committed Apr 18, 2019
1 parent 8bdf554 commit d084eaa
Show file tree
Hide file tree
Showing 17 changed files with 45 additions and 57 deletions.
22 changes: 15 additions & 7 deletions src/legacy/core_plugins/ui_metric/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,23 @@ the name of a dashboard they've viewed, or the timestamp of the interaction.

## How to use it

To track a user interaction, simply send a `POST` request to `/api/ui_metric/{APP_NAME}/{METRIC_TYPE}`,
where `APP_NAME` and `METRIC_TYPE` are underscore-delimited strings. For example, to track the app
`my_app` and the metric `my_metric`, send a request to `/api/ui_metric/my_app/my_metric`.
To track a user interaction, import the `trackUiMetric` helper function from UI Metric app:

```js
import { trackUiMetric } from 'relative/path/to/src/legacy/core_plugins/ui_metric/public';
```

Call this function whenever you would like to track a user interaction within your app. The function
accepts two arguments, `appName` and `metricType`. These should be underscore-delimited strings.
For example, to track the `my_metric` metric in the app `my_app` call `trackUiMetric('my_app', 'my_metric)`.

That's all you need to do!

To track multiple metrics within a single request, provide multiple metric types separated by
commas, e.g. `/api/ui_metric/my_app/my_metric1,my_metric2,my_metric3`.
To track multiple metrics within a single request, provide an array of metric types, e.g. `trackUiMetric('my_app', ['my_metric1', 'my_metric2', 'my_metric3'])`.

**NOTE:** When called, this function sends a `POST` request to `/api/ui_metric/{appName}/{metricType}`.
It's important that this request is sent via the `trackUiMetric` function, because it contains special
logic for blocking the request if the user hasn't opted in to telemetry.

### Tracking timed interactions

Expand All @@ -32,8 +41,7 @@ logic yourself. You'll also need to predefine some buckets into which the UI met
For example, if you're timing how long it takes to create a visualization, you may decide to
measure interactions that take less than 1 minute, 1-5 minutes, 5-20 minutes, and longer than 20 minutes.
To track these interactions, you'd use the timed length of the interaction to determine whether to
hit `/api/ui_metric/visualize/create_vis_1m`, `/api/ui_metric/visualize/create_vis_5m`,
`/api/ui_metric/visualize/create_vis_20m`, etc.
use a `metricType` of `create_vis_1m`, `create_vis_5m`, `create_vis_20m`, or `create_vis_infinity`.

## How it works

Expand Down
36 changes: 8 additions & 28 deletions src/legacy/core_plugins/ui_metric/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,40 +19,20 @@

import chrome from 'ui/chrome';
import { uiModules } from 'ui/modules';
import { getCanGatherUiMetrics } from 'ui/ui_metric';
import { getCanTrackUiMetrics } from 'ui/ui_metric';
import { API_BASE_PATH } from '../common';

const module = uiModules.get('kibana');

let _http;

module.run($http => {
uiModules.get('kibana').run($http => {
_http = $http;
});

module.config($httpProvider => {
$httpProvider.interceptors.push($q => {
return {
request: config => {
const { url } = config;
const isUiMetricRequest = url.indexOf(`${chrome.getBasePath()}${API_BASE_PATH}`) === 0;
const canGatherUiMetrics = getCanGatherUiMetrics();

if (isUiMetricRequest && !canGatherUiMetrics) {
// Block request from going out if the user has disabled telemetry.
return $q.reject('uiMetricsDisallowed');
} else {
return $q.resolve(config);
}
},
};
});
});
export function trackUiMetric(appName: string, metricType: string | string[]) {
const metricTypes = Array.isArray(metricType) ? metricType.join(',') : metricType;
const uri = chrome.addBasePath(`${API_BASE_PATH}/${appName}/${metricTypes}`);

export function track(appName: string, actionType: string) {
const uri = chrome.addBasePath(`${API_BASE_PATH}/${appName}/${actionType}`);
// Silently swallow request failures. Without this empty error handler, Angular will complain
// in the console that the rejected promise isn't being handled.
const emptyHandler = () => {};
_http.post(uri).then(emptyHandler, emptyHandler);
if (getCanTrackUiMetrics()) {
_http.post(uri);
}
}
10 changes: 5 additions & 5 deletions src/legacy/ui/public/ui_metric/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@
* under the License.
*/

let _canGatherUiMetrics = false;
let _canTrackUiMetrics = false;

export function setCanGatherUiMetrics(flag: boolean) {
_canGatherUiMetrics = flag;
export function setCanTrackUiMetrics(flag: boolean) {
_canTrackUiMetrics = flag;
}

export function getCanGatherUiMetrics(): boolean {
return _canGatherUiMetrics;
export function getCanTrackUiMetrics(): boolean {
return _canTrackUiMetrics;
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jest.mock('ui/index_patterns', () => {
});

jest.mock('../../../../../src/legacy/core_plugins/ui_metric/public', () => ({
track: jest.fn(),
trackUiMetric: jest.fn(),
}));

describe('<AutoFollowPatternList />', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jest.mock('ui/index_patterns', () => {
});

jest.mock('../../../../../src/legacy/core_plugins/ui_metric/public', () => ({
track: jest.fn(),
trackUiMetric: jest.fn(),
}));

describe('<FollowerIndicesList />', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jest.mock('ui/index_patterns', () => {
});

jest.mock('../../../../../src/legacy/core_plugins/ui_metric/public', () => ({
track: jest.fn(),
trackUiMetric: jest.fn(),
}));

const testBedOptions = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export const createFollowerIndex = (followerIndex) => {
uiMetrics.push(UIM_FOLLOWER_INDEX_USE_ADVANCED_OPTIONS);
}
const request = httpClient.post(`${apiPrefix}/follower_indices`, followerIndex);
return trackUserRequest(request, uiMetrics.join(',')).then(extractData);
return trackUserRequest(request, uiMetrics).then(extractData);
};

export const pauseFollowerIndex = (id) => {
Expand Down Expand Up @@ -138,7 +138,7 @@ export const updateFollowerIndex = (id, followerIndex) => {
uiMetrics.push(UIM_FOLLOWER_INDEX_USE_ADVANCED_OPTIONS);
}
const request = httpClient.put(`${apiPrefix}/follower_indices/${encodeURIComponent(id)}`, followerIndex);
return trackUserRequest(request, uiMetrics.join(',')).then(extractData);
return trackUserRequest(request, uiMetrics).then(extractData);
};

/* Stats */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { track } from '../../../../../../src/legacy/core_plugins/ui_metric/public';
import { trackUiMetric as track } from '../../../../../../src/legacy/core_plugins/ui_metric/public';
import { UIM_APP_NAME } from '../constants';

export function trackUiMetric(actionType) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import { get } from 'lodash';

import { track } from '../../../../../src/legacy/core_plugins/ui_metric/public';
import { trackUiMetric as track } from '../../../../../src/legacy/core_plugins/ui_metric/public';

import {
UIM_APP_NAME,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export const saveLifecyclePolicy = (lifecycle, isNew) => async () => {

const uiMetrics = getUiMetricsForPhases(lifecycle.phases);
uiMetrics.push(isNew ? UIM_POLICY_CREATE : UIM_POLICY_UPDATE);
trackUiMetric(uiMetrics.join(','));
trackUiMetric(uiMetrics);

const message = i18n.translate('xpack.indexLifecycleMgmt.editPolicy.successfulSaveMessage',
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { track } from '../../../../../src/legacy/core_plugins/ui_metric/public';
import { trackUiMetric as track } from '../../../../../src/legacy/core_plugins/ui_metric/public';
import { UIM_APP_NAME } from '../../common/constants';

export function trackUiMetric(metricType) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jest.mock('ui/chrome', () => ({
}));

jest.mock('../../../../../src/legacy/core_plugins/ui_metric/public', () => ({
track: jest.fn(),
trackUiMetric: jest.fn(),
}));

const testBedOptions = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { track } from '../../../../../src/legacy/core_plugins/ui_metric/public';
import { trackUiMetric as track } from '../../../../../src/legacy/core_plugins/ui_metric/public';
import { UIM_APP_NAME } from '../constants';

export function trackUiMetric(actionType) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jest.mock('ui/chrome', () => ({
jest.mock('lodash/function/debounce', () => fn => fn);

jest.mock('../../../../../src/legacy/core_plugins/ui_metric/public', () => ({
track: jest.fn(),
trackUiMetric: jest.fn(),
}));

describe('Create Rollup Job, step 5: Metrics', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jest.mock('ui/chrome', () => ({
}));

jest.mock('../../../../../src/legacy/core_plugins/ui_metric/public', () => ({
track: jest.fn(),
trackUiMetric: jest.fn(),
}));

jest.mock('../../public/crud_app/services', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { track } from '../../../../../../src/legacy/core_plugins/ui_metric/public';
import { trackUiMetric as track } from '../../../../../../src/legacy/core_plugins/ui_metric/public';
import { UIM_APP_NAME } from '../../../common';

export function trackUiMetric(actionType) {
Expand Down
6 changes: 3 additions & 3 deletions x-pack/plugins/xpack_main/public/services/telemetry_opt_in.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@
*/

import moment from 'moment';
import { setCanGatherUiMetrics } from 'ui/ui_metric';
import { setCanTrackUiMetrics } from 'ui/ui_metric';

export function TelemetryOptInProvider($injector, chrome) {
const Notifier = $injector.get('Notifier');
const notify = new Notifier();
let currentOptInStatus = $injector.get('telemetryOptedIn');
setCanGatherUiMetrics(currentOptInStatus);
setCanTrackUiMetrics(currentOptInStatus);

return {
getOptIn: () => currentOptInStatus,
setOptIn: async (enabled) => {
setCanGatherUiMetrics(enabled);
setCanTrackUiMetrics(enabled);

const $http = $injector.get('$http');

Expand Down

0 comments on commit d084eaa

Please sign in to comment.