Skip to content

Commit

Permalink
[Alerts][Actions][Telemetry] Fix mappings for Kibana actions and aler…
Browse files Browse the repository at this point in the history
…t types telemetry. (#88532)

* [Alerts][Actions][Telemetry] Fix mappings for Kibana actions and alert types telemetry.

* fixed count_active_by_type for actions

* fixed tests

* Fixed due to comments.

* Fixed due to comments.

Co-authored-by: Kibana Machine <[email protected]>
  • Loading branch information
YulNaumenko and kibanamachine authored Jan 27, 2021
1 parent d931ed6 commit 4663345
Show file tree
Hide file tree
Showing 5 changed files with 169 additions and 16 deletions.
90 changes: 87 additions & 3 deletions x-pack/plugins/actions/server/usage/actions_telemetry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { getTotalCount } from './actions_telemetry';
import { getInUseTotalCount, getTotalCount } from './actions_telemetry';

describe('actions telemetry', () => {
test('getTotalCount should replace action types names with . to __', async () => {
test('getTotalCount should replace first symbol . to __ for action types names', async () => {
const mockEsClient = jest.fn();
mockEsClient.mockReturnValue({
aggregations: {
byActionTypeId: {
value: {
types: { '.index': 1, '.server-log': 1 },
types: { '.index': 1, '.server-log': 1, 'some.type': 1, 'another.type.': 1 },
},
},
},
Expand Down Expand Up @@ -56,6 +56,38 @@ describe('actions telemetry', () => {
updated_at: '2020-03-26T18:46:44.449Z',
},
},
{
_id: 'action:00000000-1',
_index: '.kibana_1',
_score: 0,
_source: {
action: {
actionTypeId: 'some.type',
config: {},
name: 'test type',
secrets: {},
},
references: [],
type: 'action',
updated_at: '2020-03-26T18:46:44.449Z',
},
},
{
_id: 'action:00000000-2',
_index: '.kibana_1',
_score: 0,
_source: {
action: {
actionTypeId: 'another.type.',
config: {},
name: 'test another type',
secrets: {},
},
references: [],
type: 'action',
updated_at: '2020-03-26T18:46:44.449Z',
},
},
],
},
});
Expand All @@ -69,6 +101,58 @@ Object {
"countByType": Object {
"__index": 1,
"__server-log": 1,
"another.type__": 1,
"some.type": 1,
},
"countTotal": 4,
}
`);
});

test('getInUseTotalCount', async () => {
const mockEsClient = jest.fn();
mockEsClient.mockReturnValue({
aggregations: {
refs: {
actionRefIds: {
value: {
connectorIds: { '1': 'action-0', '123': 'action-0' },
total: 2,
},
},
},
hits: {
hits: [],
},
},
});
const actionsBulkGet = jest.fn();
actionsBulkGet.mockReturnValue({
saved_objects: [
{
id: '1',
attributes: {
actionTypeId: '.server-log',
},
},
{
id: '123',
attributes: {
actionTypeId: '.slack',
},
},
],
});
const telemetry = await getInUseTotalCount(mockEsClient, actionsBulkGet, 'test');

expect(mockEsClient).toHaveBeenCalledTimes(1);
expect(actionsBulkGet).toHaveBeenCalledTimes(1);

expect(telemetry).toMatchInlineSnapshot(`
Object {
"countByType": Object {
"__server-log": 1,
"__slack": 1,
},
"countTotal": 2,
}
Expand Down
48 changes: 44 additions & 4 deletions x-pack/plugins/actions/server/usage/actions_telemetry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { LegacyAPICaller } from 'kibana/server';
import {
LegacyAPICaller,
SavedObjectsBaseOptions,
SavedObjectsBulkGetObject,
SavedObjectsBulkResponse,
} from 'kibana/server';
import { ActionResult } from '../types';

export async function getTotalCount(callCluster: LegacyAPICaller, kibanaIndex: string) {
const scriptedMetric = {
Expand Down Expand Up @@ -58,14 +64,23 @@ export async function getTotalCount(callCluster: LegacyAPICaller, kibanaIndex: s
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(obj: any, key: string) => ({
...obj,
[key.replace('.', '__')]: searchResult.aggregations.byActionTypeId.value.types[key],
[replaceFirstAndLastDotSymbols(key)]: searchResult.aggregations.byActionTypeId.value.types[
key
],
}),
{}
),
};
}

export async function getInUseTotalCount(callCluster: LegacyAPICaller, kibanaIndex: string) {
export async function getInUseTotalCount(
callCluster: LegacyAPICaller,
actionsBulkGet: (
objects?: SavedObjectsBulkGetObject[] | undefined,
options?: SavedObjectsBaseOptions | undefined
) => Promise<SavedObjectsBulkResponse<ActionResult<Record<string, unknown>>>>,
kibanaIndex: string
): Promise<{ countTotal: number; countByType: Record<string, number> }> {
const scriptedMetric = {
scripted_metric: {
init_script: 'state.connectorIds = new HashMap(); state.total = 0;',
Expand Down Expand Up @@ -145,7 +160,32 @@ export async function getInUseTotalCount(callCluster: LegacyAPICaller, kibanaInd
},
});

return actionResults.aggregations.refs.actionRefIds.value.total;
const bulkFilter = Object.entries(
actionResults.aggregations.refs.actionRefIds.value.connectorIds
).map(([key]) => ({
id: key,
type: 'action',
fields: ['id', 'actionTypeId'],
}));
const actions = await actionsBulkGet(bulkFilter);
const countByType = actions.saved_objects.reduce(
(actionTypeCount: Record<string, number>, action) => {
const alertTypeId = replaceFirstAndLastDotSymbols(action.attributes.actionTypeId);
const currentCount =
actionTypeCount[alertTypeId] !== undefined ? actionTypeCount[alertTypeId] : 0;
actionTypeCount[alertTypeId] = currentCount + 1;
return actionTypeCount;
},
{}
);
return { countTotal: actionResults.aggregations.refs.actionRefIds.value.total, countByType };
}

function replaceFirstAndLastDotSymbols(strToReplace: string) {
const hasFirstSymbolDot = strToReplace.startsWith('.');
const appliedString = hasFirstSymbolDot ? strToReplace.replace('.', '__') : strToReplace;
const hasLastSymbolDot = strToReplace.endsWith('.');
return hasLastSymbolDot ? `${appliedString.slice(0, -1)}__` : appliedString;
}

// TODO: Implement executions count telemetry with eventLog, when it will write to index
26 changes: 22 additions & 4 deletions x-pack/plugins/actions/server/usage/task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,20 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { Logger, CoreSetup, LegacyAPICaller } from 'kibana/server';
import {
Logger,
CoreSetup,
LegacyAPICaller,
SavedObjectsBulkGetObject,
SavedObjectsBaseOptions,
} from 'kibana/server';
import moment from 'moment';
import {
RunContext,
TaskManagerSetupContract,
TaskManagerStartContract,
} from '../../../task_manager/server';
import { ActionResult } from '../types';
import { getTotalCount, getInUseTotalCount } from './actions_telemetry';

export const TELEMETRY_TASK_TYPE = 'actions_telemetry';
Expand Down Expand Up @@ -66,19 +73,30 @@ export function telemetryTaskRunner(logger: Logger, core: CoreSetup, kibanaIndex
client.callAsInternalUser(...args)
);
};
const actionsBulkGet = (
objects?: SavedObjectsBulkGetObject[],
options?: SavedObjectsBaseOptions
) => {
return core
.getStartServices()
.then(([{ savedObjects }]) =>
savedObjects.createInternalRepository(['action']).bulkGet<ActionResult>(objects, options)
);
};
return {
async run() {
return Promise.all([
getTotalCount(callCluster, kibanaIndex),
getInUseTotalCount(callCluster, kibanaIndex),
getInUseTotalCount(callCluster, actionsBulkGet, kibanaIndex),
])
.then(([totalAggegations, countActiveTotal]) => {
.then(([totalAggegations, totalInUse]) => {
return {
state: {
runs: (state.runs || 0) + 1,
count_total: totalAggegations.countTotal,
count_by_type: totalAggegations.countByType,
count_active_total: countActiveTotal,
count_active_total: totalInUse.countTotal,
count_active_by_type: totalInUse.countByType,
},
runAt: getNextMidnight(),
};
Expand Down
8 changes: 5 additions & 3 deletions x-pack/plugins/alerts/server/usage/alerts_telemetry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
import { getTotalCountInUse } from './alerts_telemetry';

describe('alerts telemetry', () => {
test('getTotalCountInUse should replace action types names with . to __', async () => {
test('getTotalCountInUse should replace first "." symbol to "__" in alert types names', async () => {
const mockEsClient = jest.fn();
mockEsClient.mockReturnValue({
aggregations: {
byAlertTypeId: {
value: {
types: { '.index-threshold': 2 },
types: { '.index-threshold': 2, 'logs.alert.document.count': 1, 'document.test.': 1 },
},
},
},
Expand All @@ -30,8 +30,10 @@ describe('alerts telemetry', () => {
Object {
"countByType": Object {
"__index-threshold": 2,
"document.test__": 1,
"logs.alert.document.count": 1,
},
"countTotal": 2,
"countTotal": 4,
}
`);
});
Expand Down
13 changes: 11 additions & 2 deletions x-pack/plugins/alerts/server/usage/alerts_telemetry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ export async function getTotalCountAggregations(callCluster: LegacyAPICaller, ki
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(obj: any, key: string) => ({
...obj,
[key.replace('.', '__')]: results.aggregations.byAlertTypeId.value.types[key],
[replaceFirstAndLastDotSymbols(key)]: results.aggregations.byAlertTypeId.value.types[key],
}),
{}
),
Expand Down Expand Up @@ -310,11 +310,20 @@ export async function getTotalCountInUse(callCluster: LegacyAPICaller, kibanaIne
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(obj: any, key: string) => ({
...obj,
[key.replace('.', '__')]: searchResult.aggregations.byAlertTypeId.value.types[key],
[replaceFirstAndLastDotSymbols(key)]: searchResult.aggregations.byAlertTypeId.value.types[
key
],
}),
{}
),
};
}

function replaceFirstAndLastDotSymbols(strToReplace: string) {
const hasFirstSymbolDot = strToReplace.startsWith('.');
const appliedString = hasFirstSymbolDot ? strToReplace.replace('.', '__') : strToReplace;
const hasLastSymbolDot = strToReplace.endsWith('.');
return hasLastSymbolDot ? `${appliedString.slice(0, -1)}__` : appliedString;
}

// TODO: Implement executions count telemetry with eventLog, when it will write to index

0 comments on commit 4663345

Please sign in to comment.