Instrument Rollups CRUD app with user action telemetry (#32534)

* Track start, stop, and delete rollup job requests.
* Track show details and show summary/histogram/terms/metrics/json tab actions.
* Track app load action.
This commit is contained in:
CJ Cenizal 2019-03-12 11:33:20 -07:00 committed by GitHub
parent 1c2481080e
commit 2eb70952c2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 123 additions and 14 deletions

View file

@ -8,11 +8,23 @@ export const PLUGIN = {
ID: 'rollup'
};
export const UA_APP_NAME = 'rollup-job-wizard';
export const UA_ROLLUP_JOB_CREATE = 'create';
export const USER_ACTIONS = [
UA_ROLLUP_JOB_CREATE,
];
export const CONFIG_ROLLUPS = 'rollups:enableIndexPatterns';
export {
UA_APP_NAME,
USER_ACTIONS,
UA_APP_LOAD,
UA_JOB_CREATE,
UA_JOB_DELETE,
UA_JOB_DELETE_MANY,
UA_JOB_START,
UA_JOB_START_MANY,
UA_JOB_STOP,
UA_JOB_STOP_MANY,
UA_SHOW_DETAILS_CLICK,
UA_DETAIL_PANEL_SUMMARY_TAB_CLICK,
UA_DETAIL_PANEL_TERMS_TAB_CLICK,
UA_DETAIL_PANEL_HISTOGRAM_TAB_CLICK,
UA_DETAIL_PANEL_METRICS_TAB_CLICK,
UA_DETAIL_PANEL_JSON_TAB_CLICK,
} from './user_action';

View file

@ -0,0 +1,39 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
export const UA_APP_NAME = 'rollup-job-wizard';
export const UA_APP_LOAD = 'app_load';
export const UA_JOB_CREATE = 'job_create';
export const UA_JOB_DELETE = 'job_delete';
export const UA_JOB_DELETE_MANY = 'job_delete_many';
export const UA_JOB_START = 'job_start';
export const UA_JOB_START_MANY = 'job_start_many';
export const UA_JOB_STOP = 'job_stop';
export const UA_JOB_STOP_MANY = 'job_stop_many';
export const UA_SHOW_DETAILS_CLICK = 'show_details_click';
export const UA_DETAIL_PANEL_SUMMARY_TAB_CLICK = 'detail_panel_summary_tab_click';
export const UA_DETAIL_PANEL_TERMS_TAB_CLICK = 'detail_panel_terms_tab_click';
export const UA_DETAIL_PANEL_HISTOGRAM_TAB_CLICK = 'detail_panel_histogram_tab_click';
export const UA_DETAIL_PANEL_METRICS_TAB_CLICK = 'detail_panel_metrics_tab_click';
export const UA_DETAIL_PANEL_JSON_TAB_CLICK = 'detail_panel_json_tab_click';
export const USER_ACTIONS = [
UA_APP_LOAD,
UA_JOB_CREATE,
UA_JOB_DELETE,
UA_JOB_DELETE_MANY,
UA_JOB_START,
UA_JOB_START_MANY,
UA_JOB_STOP,
UA_JOB_STOP_MANY,
UA_SHOW_DETAILS_CLICK,
UA_DETAIL_PANEL_SUMMARY_TAB_CLICK,
UA_DETAIL_PANEL_TERMS_TAB_CLICK,
UA_DETAIL_PANEL_HISTOGRAM_TAB_CLICK,
UA_DETAIL_PANEL_METRICS_TAB_CLICK,
UA_DETAIL_PANEL_JSON_TAB_CLICK,
];

View file

@ -8,8 +8,9 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Switch, Route, Redirect } from 'react-router-dom';
import { UA_APP_LOAD } from '../../common';
import { CRUD_APP_BASE_PATH } from './constants';
import { registerRouter, setUserHasLeftApp } from './services';
import { registerRouter, setUserHasLeftApp, trackUserAction } from './services';
import { JobList, JobCreate } from './sections';
export class App extends Component {
@ -33,6 +34,10 @@ export class App extends Component {
registerRouter(router);
}
componentWillMount() {
trackUserAction(UA_APP_LOAD);
}
componentWillUnmount() {
// Set internal flag so we can prevent reacting to route changes internally.
setUserHasLeftApp(true);

View file

@ -26,6 +26,15 @@ import {
EuiTitle,
} from '@elastic/eui';
import {
UA_DETAIL_PANEL_SUMMARY_TAB_CLICK,
UA_DETAIL_PANEL_TERMS_TAB_CLICK,
UA_DETAIL_PANEL_HISTOGRAM_TAB_CLICK,
UA_DETAIL_PANEL_METRICS_TAB_CLICK,
UA_DETAIL_PANEL_JSON_TAB_CLICK,
} from '../../../../../common';
import { trackUserAction } from '../../../services';
import {
JobActionMenu,
JobDetails,
@ -45,6 +54,14 @@ export const JOB_DETAILS_TABS = [
JOB_DETAILS_TAB_JSON,
];
const tabToUserActionMap = {
[JOB_DETAILS_TAB_SUMMARY]: UA_DETAIL_PANEL_SUMMARY_TAB_CLICK,
[JOB_DETAILS_TAB_TERMS]: UA_DETAIL_PANEL_TERMS_TAB_CLICK,
[JOB_DETAILS_TAB_HISTOGRAM]: UA_DETAIL_PANEL_HISTOGRAM_TAB_CLICK,
[JOB_DETAILS_TAB_METRICS]: UA_DETAIL_PANEL_METRICS_TAB_CLICK,
[JOB_DETAILS_TAB_JSON]: UA_DETAIL_PANEL_JSON_TAB_CLICK,
};
export class DetailPanelUi extends Component {
static propTypes = {
isOpen: PropTypes.bool.isRequired,
@ -96,7 +113,10 @@ export class DetailPanelUi extends Component {
const isSelected = tab === panelType;
renderedTabs.push(
<EuiTab
onClick={() => openDetailPanel({ panelType: tab, jobId: id })}
onClick={() => {
trackUserAction(tabToUserActionMap[tab]);
openDetailPanel({ panelType: tab, jobId: id });
}}
isSelected={isSelected}
data-test-subj={`detailPanelTab${isSelected ? 'Selected' : ''}`}
key={index}

View file

@ -17,6 +17,14 @@ import {
tabToHumanizedMap,
} from '../../components';
jest.mock('../../../services', () => {
const services = require.requireActual('../../../services');
return {
...services,
trackUserAction: jest.fn(),
};
});
const defaultJob = getJob();
const defaultProps = {

View file

@ -29,6 +29,8 @@ import {
EuiToolTip,
} from '@elastic/eui';
import { UA_SHOW_DETAILS_CLICK } from '../../../../../common';
import { trackUserAction } from '../../../services';
import { JobActionMenu, JobStatus } from '../../components';
const COLUMNS = [{
@ -257,6 +259,7 @@ export class JobTableUi extends Component {
content = (
<EuiLink
onClick={() => {
trackUserAction(UA_SHOW_DETAILS_CLICK);
openDetailPanel(job.id);
}}
>

View file

@ -11,6 +11,14 @@ import { getJobs } from '../../../../../fixtures';
import { rollupJobsStore } from '../../../store';
import { JobTable } from './job_table';
jest.mock('../../../services', () => {
const services = require.requireActual('../../../services');
return {
...services,
trackUserAction: jest.fn(),
};
});
const defaultProps = {
jobs: [],
pager: new Pager(20, 10, 1),

View file

@ -5,7 +5,15 @@
*/
import chrome from 'ui/chrome';
import { UA_ROLLUP_JOB_CREATE } from '../../../common';
import {
UA_JOB_CREATE,
UA_JOB_DELETE,
UA_JOB_DELETE_MANY,
UA_JOB_START,
UA_JOB_START_MANY,
UA_JOB_STOP,
UA_JOB_STOP_MANY,
} from '../../../common';
import { getHttp } from './http_provider';
import { trackUserRequest } from './track_user_action';
@ -18,23 +26,29 @@ export async function loadJobs() {
export async function startJobs(jobIds) {
const body = { jobIds };
return await getHttp().post(`${apiPrefix}/start`, body);
const request = getHttp().post(`${apiPrefix}/start`, body);
const actionType = jobIds.length > 1 ? UA_JOB_START_MANY : UA_JOB_START;
return await trackUserRequest(request, actionType);
}
export async function stopJobs(jobIds) {
const body = { jobIds };
return await getHttp().post(`${apiPrefix}/stop`, body);
const request = getHttp().post(`${apiPrefix}/stop`, body);
const actionType = jobIds.length > 1 ? UA_JOB_STOP_MANY : UA_JOB_STOP;
return await trackUserRequest(request, actionType);
}
export async function deleteJobs(jobIds) {
const body = { jobIds };
return await getHttp().post(`${apiPrefix}/delete`, body);
const request = getHttp().post(`${apiPrefix}/delete`, body);
const actionType = jobIds.length > 1 ? UA_JOB_DELETE_MANY : UA_JOB_DELETE;
return await trackUserRequest(request, actionType);
}
export async function createJob(job) {
const body = { job };
const request = getHttp().put(`${apiPrefix}/create`, body);
return await trackUserRequest(request, UA_ROLLUP_JOB_CREATE);
return await trackUserRequest(request, UA_JOB_CREATE);
}
export async function validateIndexPattern(indexPattern) {