Commit 3a77828c authored by Martin Wortschack's avatar Martin Wortschack

Merge branch 'jivanvl-add-snowplow-logs' into 'master'

Added snowplow for the logs page

See merge request gitlab-org/gitlab!32704
parents 7834eb60 61bcc936
export const dateFormatMask = 'mmm dd HH:MM:ss.l';
export const TOKEN_TYPE_POD_NAME = 'TOKEN_TYPE_POD_NAME';
export const tracking = {
USED_SEARCH_BAR: 'used_search_bar',
POD_LOG_CHANGED: 'pod_log_changed',
TIME_RANGE_SET: 'time_range_set',
ENVIRONMENT_SELECTED: 'environment_selected',
};
import Tracking from '~/tracking';
/**
* The value of 1 in count, means there was one action performed
* related to the tracked action, in either of the following categories
* 1. Refreshing the logs
* 2. Select an environment
* 3. Change the time range
* 4. Use the search bar
*/
const trackLogs = label =>
Tracking.event(document.body.dataset.page, 'logs_view', {
label,
property: 'count',
value: 1,
});
export default trackLogs;
......@@ -2,7 +2,8 @@ import { backOff } from '~/lib/utils/common_utils';
import httpStatusCodes from '~/lib/utils/http_status';
import axios from '~/lib/utils/axios_utils';
import { convertToFixedRange } from '~/lib/utils/datetime_range';
import { TOKEN_TYPE_POD_NAME } from '../constants';
import { TOKEN_TYPE_POD_NAME, tracking } from '../constants';
import trackLogs from '../logs_tracking_helper';
import * as types from './mutation_types';
......@@ -81,22 +82,22 @@ export const showFilteredLogs = ({ dispatch, commit }, filters = []) => {
commit(types.SET_CURRENT_POD_NAME, podName);
commit(types.SET_SEARCH, search);
dispatch('fetchLogs');
dispatch('fetchLogs', tracking.USED_SEARCH_BAR);
};
export const showPodLogs = ({ dispatch, commit }, podName) => {
commit(types.SET_CURRENT_POD_NAME, podName);
dispatch('fetchLogs');
dispatch('fetchLogs', tracking.POD_LOG_CHANGED);
};
export const setTimeRange = ({ dispatch, commit }, timeRange) => {
commit(types.SET_TIME_RANGE, timeRange);
dispatch('fetchLogs');
dispatch('fetchLogs', tracking.TIME_RANGE_SET);
};
export const showEnvironment = ({ dispatch, commit }, environmentName) => {
commit(types.SET_PROJECT_ENVIRONMENT, environmentName);
dispatch('fetchLogs');
dispatch('fetchLogs', tracking.ENVIRONMENT_SELECTED);
};
/**
......@@ -111,19 +112,22 @@ export const fetchEnvironments = ({ commit, dispatch }, environmentsPath) => {
.get(environmentsPath)
.then(({ data }) => {
commit(types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS, data.environments);
dispatch('fetchLogs');
dispatch('fetchLogs', tracking.ENVIRONMENT_SELECTED);
})
.catch(() => {
commit(types.RECEIVE_ENVIRONMENTS_DATA_ERROR);
});
};
export const fetchLogs = ({ commit, state }) => {
export const fetchLogs = ({ commit, state }, trackingLabel) => {
commit(types.REQUEST_LOGS_DATA);
return requestLogsUntilData({ commit, state })
.then(({ data }) => {
const { pod_name, pods, logs, cursor } = data;
if (logs && logs.length > 0) {
trackLogs(trackingLabel);
}
commit(types.RECEIVE_LOGS_DATA_SUCCESS, { logs, cursor });
commit(types.SET_CURRENT_POD_NAME, pod_name);
commit(types.RECEIVE_PODS_DATA_SUCCESS, pods);
......
---
title: Add snowplow tracking for logs page
merge_request: 32704
author:
type: other
import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
import Tracking from '~/tracking';
import * as types from '~/logs/stores/mutation_types';
import { convertToFixedRange } from '~/lib/utils/datetime_range';
import logsPageState from '~/logs/stores/state';
......@@ -104,7 +104,7 @@ describe('Logs Store actions', () => {
{ type: types.SET_CURRENT_POD_NAME, payload: null },
{ type: types.SET_SEARCH, payload: '' },
],
[{ type: 'fetchLogs' }],
[{ type: 'fetchLogs', payload: 'used_search_bar' }],
));
it('text search should filter with a search term', () =>
......@@ -116,7 +116,7 @@ describe('Logs Store actions', () => {
{ type: types.SET_CURRENT_POD_NAME, payload: null },
{ type: types.SET_SEARCH, payload: mockSearch },
],
[{ type: 'fetchLogs' }],
[{ type: 'fetchLogs', payload: 'used_search_bar' }],
));
it('pod search should filter with a search term', () =>
......@@ -128,7 +128,7 @@ describe('Logs Store actions', () => {
{ type: types.SET_CURRENT_POD_NAME, payload: mockPodName },
{ type: types.SET_SEARCH, payload: '' },
],
[{ type: 'fetchLogs' }],
[{ type: 'fetchLogs', payload: 'used_search_bar' }],
));
it('pod search should filter with a pod selection and a search term', () =>
......@@ -140,7 +140,7 @@ describe('Logs Store actions', () => {
{ type: types.SET_CURRENT_POD_NAME, payload: mockPodName },
{ type: types.SET_SEARCH, payload: mockSearch },
],
[{ type: 'fetchLogs' }],
[{ type: 'fetchLogs', payload: 'used_search_bar' }],
));
it('pod search should filter with a pod selection and two search terms', () =>
......@@ -152,7 +152,7 @@ describe('Logs Store actions', () => {
{ type: types.SET_CURRENT_POD_NAME, payload: null },
{ type: types.SET_SEARCH, payload: `term1 term2` },
],
[{ type: 'fetchLogs' }],
[{ type: 'fetchLogs', payload: 'used_search_bar' }],
));
it('pod search should filter with a pod selection and a search terms before and after', () =>
......@@ -168,7 +168,7 @@ describe('Logs Store actions', () => {
{ type: types.SET_CURRENT_POD_NAME, payload: mockPodName },
{ type: types.SET_SEARCH, payload: `term1 term2` },
],
[{ type: 'fetchLogs' }],
[{ type: 'fetchLogs', payload: 'used_search_bar' }],
));
});
......@@ -179,7 +179,7 @@ describe('Logs Store actions', () => {
mockPodName,
state,
[{ type: types.SET_CURRENT_POD_NAME, payload: mockPodName }],
[{ type: 'fetchLogs' }],
[{ type: 'fetchLogs', payload: 'pod_log_changed' }],
));
});
......@@ -198,7 +198,7 @@ describe('Logs Store actions', () => {
{ type: types.REQUEST_ENVIRONMENTS_DATA },
{ type: types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS, payload: mockEnvironments },
],
[{ type: 'fetchLogs' }],
[{ type: 'fetchLogs', payload: 'environment_selected' }],
);
});
......@@ -471,3 +471,58 @@ describe('Logs Store actions', () => {
});
});
});
describe('Tracking user interaction', () => {
let commit;
let dispatch;
let state;
let mock;
beforeEach(() => {
jest.spyOn(Tracking, 'event');
commit = jest.fn();
dispatch = jest.fn();
state = logsPageState();
state.environments.options = mockEnvironments;
state.environments.current = mockEnvName;
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.reset();
});
describe('Logs with data', () => {
beforeEach(() => {
mock.onGet(mockLogsEndpoint).reply(200, mockResponse);
mock.onGet(mockLogsEndpoint).replyOnce(202); // mock reactive cache
});
it('tracks fetched logs with data', () => {
return fetchLogs({ state, commit, dispatch }, 'environment_selected').then(() => {
expect(Tracking.event).toHaveBeenCalledWith(document.body.dataset.page, 'logs_view', {
label: 'environment_selected',
property: 'count',
value: 1,
});
});
});
});
describe('Logs without data', () => {
beforeEach(() => {
mock.onGet(mockLogsEndpoint).reply(200, {
...mockResponse,
logs: [],
});
mock.onGet(mockLogsEndpoint).replyOnce(202); // mock reactive cache
});
it('does not track empty log responses', () => {
return fetchLogs({ state, commit, dispatch }).then(() => {
expect(Tracking.event).not.toHaveBeenCalled();
});
});
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment