Skip to content

Commit

Permalink
New version
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisronline committed Apr 25, 2022
1 parent fe84c57 commit 7274ca5
Show file tree
Hide file tree
Showing 24 changed files with 393 additions and 208 deletions.
33 changes: 33 additions & 0 deletions x-pack/plugins/actions/common/monitoring/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { ValidMetricSet } from '@kbn/monitoring-collection-plugin/common/types';

export interface RuleMonitoringMetrics {
[key: string]: {
data: Array<{ timestamp: number; value: number }>;
};
}

export interface NodeLevelMetricsType {
kibana_alerting_node_action_executions: number;
kibana_alerting_node_action_execution_time: number;
kibana_alerting_node_action_failures: number;
kibana_alerting_node_action_timeouts: number;
}

export enum NodeLevelMetricsEnum {
kibana_alerting_node_action_executions = 'kibana_alerting_node_action_executions',
kibana_alerting_node_action_execution_time = 'kibana_alerting_node_action_execution_time',
kibana_alerting_node_action_failures = 'kibana_alerting_node_action_failures',
kibana_alerting_node_action_timeouts = 'kibana_alerting_node_action_timeouts',
}

export interface ClusterLevelMetricsType extends ValidMetricSet {
kibana_alerting_cluster_actions_overdue_count: number;
kibana_alerting_cluster_actions_overdue_delay_p50: number;
kibana_alerting_cluster_actions_overdue_delay_p99: number;
}
36 changes: 36 additions & 0 deletions x-pack/plugins/actions/server/lib/action_executor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { eventLoggerMock } from '@kbn/event-log-plugin/server/mocks';
import { spacesServiceMock } from '@kbn/spaces-plugin/server/spaces_service/spaces_service.mock';
import { ActionType } from '../types';
import { actionsMock, actionsClientMock } from '../mocks';
import { nodeLevelMetricsMock } from '../monitoring/node_level_metrics.mock';
import { pick } from 'lodash';

const actionExecutor = new ActionExecutor({ isESOCanEncrypt: true });
Expand All @@ -34,6 +35,7 @@ const executeParams = {
request: {} as KibanaRequest,
};

const nodeLevelMetrics = nodeLevelMetricsMock.create();
const spacesMock = spacesServiceMock.createStartContract();
const loggerMock = loggingSystemMock.create().get();
const getActionsClientWithRequest = jest.fn();
Expand All @@ -46,6 +48,7 @@ actionExecutor.initialize({
encryptedSavedObjectsClient,
eventLogger,
preconfiguredActions: [],
nodeLevelMetrics,
});

beforeEach(() => {
Expand Down Expand Up @@ -726,6 +729,39 @@ test('writes to event log for execute and execute start when consumer and relate
});
});

test('increments monitoring metrics after execution', async () => {
const executorMock = setupActionExecutorMock();
executorMock.mockResolvedValue({
actionId: '1',
status: 'ok',
});
await actionExecutor.execute(executeParams);

expect(nodeLevelMetrics.execution).toHaveBeenCalledTimes(1);
});

test('increments monitoring metrics after a failed execution', async () => {
const executorMock = setupActionExecutorMock();
executorMock.mockRejectedValue(new Error('this action execution is intended to fail'));
await actionExecutor.execute(executeParams);
expect(nodeLevelMetrics.execution).toHaveBeenCalledTimes(1);
expect(nodeLevelMetrics.failure).toHaveBeenCalledTimes(1);
});

test('increments monitoring metrics after a timeout', async () => {
setupActionExecutorMock();

await actionExecutor.logCancellation({
actionId: 'action1',
executionId: '123abc',
consumer: 'test-consumer',
relatedSavedObjects: [],
request: {} as KibanaRequest,
});

expect(nodeLevelMetrics.timeout).toHaveBeenCalledTimes(1);
});

function setupActionExecutorMock() {
const actionType: jest.Mocked<ActionType> = {
id: 'test',
Expand Down
86 changes: 0 additions & 86 deletions x-pack/plugins/actions/server/lib/task_runner_factory.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -844,89 +844,3 @@ test('treats errors as errors if the error is thrown instead of returned', async
`Action '2' failed and will retry: undefined`
);
});

test('increments monitoring metrics after execution', async () => {
const taskRunner = taskRunnerFactory.create({
taskInstance: mockedTaskInstance,
});

mockedActionExecutor.execute.mockResolvedValueOnce({ status: 'ok', actionId: '2' });
spaceIdToNamespace.mockReturnValueOnce('namespace-test');
mockedEncryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce({
id: '3',
type: 'action_task_params',
attributes: {
actionId: '2',
params: { baz: true },
executionId: '123abc',
apiKey: Buffer.from('123:abc').toString('base64'),
},
references: [],
});

await taskRunner.run();

expect(taskRunnerFactoryInitializerParams.nodeLevelMetrics.execution).toHaveBeenCalledTimes(1);
});

test('increments monitoring metrics after a failed execution', async () => {
const taskRunner = taskRunnerFactory.create({
taskInstance: mockedTaskInstance,
});

mockedActionExecutor.execute.mockResolvedValueOnce({
status: 'error',
actionId: '2',
message: 'Error message',
data: { foo: true },
retry: false,
});

spaceIdToNamespace.mockReturnValueOnce('namespace-test');
mockedEncryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce({
id: '3',
type: 'action_task_params',
attributes: {
actionId: '2',
params: { baz: true },
executionId: '123abc',
apiKey: Buffer.from('123:abc').toString('base64'),
},
references: [],
});

let err;
try {
await taskRunner.run();
} catch (e) {
err = e;
}

expect(err).toBeDefined();
expect(taskRunnerFactoryInitializerParams.nodeLevelMetrics.execution).toHaveBeenCalledTimes(1);
expect(taskRunnerFactoryInitializerParams.nodeLevelMetrics.failure).toHaveBeenCalledTimes(1);
});

test('increments monitoring metrics after a timeout', async () => {
const taskRunner = taskRunnerFactory.create({
taskInstance: mockedTaskInstance,
});

mockedActionExecutor.execute.mockResolvedValueOnce({ status: 'ok', actionId: '2' });
spaceIdToNamespace.mockReturnValueOnce('namespace-test');
mockedEncryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce({
id: '3',
type: 'action_task_params',
attributes: {
actionId: '2',
params: { baz: true },
executionId: '123abc',
apiKey: Buffer.from('123:abc').toString('base64'),
},
references: [],
});

await taskRunner.cancel();

expect(taskRunnerFactoryInitializerParams.nodeLevelMetrics.timeout).toHaveBeenCalledTimes(1);
});
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
import { coreMock } from '@kbn/core/public/mocks';
import { CoreSetup } from '@kbn/core/server';
import { monitoringCollectionMock } from '@kbn/monitoring-collection-plugin/server/mocks';
import { MetricSet, ValidMetricResult } from '@kbn/monitoring-collection-plugin/server';
import { MetricSet } from '@kbn/monitoring-collection-plugin/server';
import { registerClusterLevelMetrics } from './cluster_level_metrics';
import { ActionsPluginsStart } from '../plugin';
import { ValidMetricSet } from '@kbn/monitoring-collection-plugin/common/types';
import { ClusterLevelMetricsType } from '../../common/monitoring/types';

jest.useFakeTimers('modern');
jest.setSystemTime(new Date('2020-03-09').getTime());
Expand All @@ -33,7 +35,7 @@ describe('registerClusterLevelMetrics()', () => {
});

it('should get overdue actions', async () => {
const metrics: Record<string, MetricSet> = {};
const metrics: Record<string, MetricSet<ValidMetricSet>> = {};
monitoringCollection.registerMetricSet.mockImplementation((set) => {
metrics[set.id] = set;
});
Expand All @@ -54,13 +56,11 @@ describe('registerClusterLevelMetrics()', () => {
];
taskManagerFetch.mockImplementation(async () => ({ docs }));

const result = (await metrics.kibana_alerting_cluster_actions.fetch()) as Record<
string,
ValidMetricResult
>;
expect(result.overdue_count).toBe(docs.length);
expect(result.overdue_delay_p50).toBe(1000);
expect(result.overdue_delay_p99).toBe(1000);
const result =
(await metrics.kibana_alerting_cluster_actions.fetch()) as ClusterLevelMetricsType;
expect(result.kibana_alerting_cluster_actions_overdue_count).toBe(docs.length);
expect(result.kibana_alerting_cluster_actions_overdue_delay_p50).toBe(1000);
expect(result.kibana_alerting_cluster_actions_overdue_delay_p99).toBe(1000);
expect(taskManagerFetch).toHaveBeenCalledWith({
query: {
bool: {
Expand Down Expand Up @@ -132,7 +132,7 @@ describe('registerClusterLevelMetrics()', () => {
});

it('should calculate accurate p50 and p99', async () => {
const metrics: Record<string, MetricSet> = {};
const metrics: Record<string, MetricSet<ValidMetricSet>> = {};
monitoringCollection.registerMetricSet.mockImplementation((set) => {
metrics[set.id] = set;
});
Expand All @@ -152,12 +152,10 @@ describe('registerClusterLevelMetrics()', () => {
];
taskManagerFetch.mockImplementation(async () => ({ docs }));

const result = (await metrics.kibana_alerting_cluster_actions.fetch()) as Record<
string,
ValidMetricResult
>;
expect(result.overdue_count).toBe(docs.length);
expect(result.overdue_delay_p50).toBe(3000);
expect(result.overdue_delay_p99).toBe(40000);
const result =
(await metrics.kibana_alerting_cluster_actions.fetch()) as ClusterLevelMetricsType;
expect(result.kibana_alerting_cluster_actions_overdue_count).toBe(docs.length);
expect(result.kibana_alerting_cluster_actions_overdue_delay_p50).toBe(3000);
expect(result.kibana_alerting_cluster_actions_overdue_delay_p99).toBe(40000);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
} from '@kbn/task-manager-plugin/server';
import { CoreSetup } from '@kbn/core/server';
import { ActionsPluginsStart } from '../plugin';
import { ClusterLevelMetricsType } from '../../common/monitoring/types';

export function registerClusterLevelMetrics({
monitoringCollection,
Expand All @@ -20,9 +21,8 @@ export function registerClusterLevelMetrics({
monitoringCollection: MonitoringCollectionSetup;
core: CoreSetup<ActionsPluginsStart, unknown>;
}) {
monitoringCollection.registerMetricSet({
monitoringCollection.registerMetricSet<ClusterLevelMetricsType>({
id: `kibana_alerting_cluster_actions`,
keys: ['overdue_count', 'overdue_delay_p50', 'overdue_delay_p99'],
fetch: async () => {
const [_, pluginStart] = await core.getStartServices();
const now = +new Date();
Expand Down Expand Up @@ -53,9 +53,9 @@ export function registerClusterLevelMetrics({
const p50 = stats.percentile(overdueTasksDelay, 0.5);
const p99 = stats.percentile(overdueTasksDelay, 0.99);
return {
overdue_count: overdueTasks.length,
overdue_delay_p50: isNaN(p50) ? 0 : p50,
overdue_delay_p99: isNaN(p99) ? 0 : p99,
kibana_alerting_cluster_actions_overdue_count: overdueTasks.length,
kibana_alerting_cluster_actions_overdue_delay_p50: isNaN(p50) ? 0 : p50,
kibana_alerting_cluster_actions_overdue_delay_p99: isNaN(p99) ? 0 : p99,
};
},
});
Expand Down
22 changes: 11 additions & 11 deletions x-pack/plugins/actions/server/monitoring/node_level_metrics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,27 @@ describe('NodeLevelMetrics', () => {
describe('execution', () => {
it('should register a counter when called', () => {
const metrics = new NodeLevelMetrics(monitoringCollection);
metrics.execution('actionA');
metrics.execution('actionA', 'actionTypeA');
expect(monitoringCollection.reportCounter).toHaveBeenCalledTimes(1);
expect(monitoringCollection.reportCounter).toHaveBeenCalledWith(
'kibana_alerting_node_action_executions',
{ action_id: 'actionA' }
{ action_id: 'actionA', action_type_id: 'actionTypeA' }
);
});

it('should report a gauge when provided with an execution time', () => {
const executionTime = 1000;
const metrics = new NodeLevelMetrics(monitoringCollection);
metrics.execution('actionA', 'actionType', executionTime);
metrics.execution('actionA', 'actionTypeA', executionTime);
expect(monitoringCollection.reportCounter).toHaveBeenCalledTimes(1);
expect(monitoringCollection.reportCounter).toHaveBeenCalledWith(
'kibana_alerting_node_action_executions',
{ action_id: 'actionA' }
{ action_id: 'actionA', action_type_id: 'actionTypeA' }
);
expect(monitoringCollection.reportGauge).toHaveBeenCalledTimes(1);
expect(monitoringCollection.reportGauge).toHaveBeenCalledWith(
'kibana_alerting_node_action_execution_time',
{ action_id: 'actionA' },
{ action_id: 'actionA', action_type_id: 'actionTypeA' },
executionTime
);
});
Expand All @@ -47,34 +47,34 @@ describe('NodeLevelMetrics', () => {
describe('failure', () => {
it('should register a counter when called', () => {
const metrics = new NodeLevelMetrics(monitoringCollection);
metrics.failure('actionA');
metrics.failure('actionA', 'actionTypeA');
expect(monitoringCollection.reportCounter).toHaveBeenCalledTimes(1);
expect(monitoringCollection.reportCounter).toHaveBeenCalledWith(
`kibana_alerting_node_action_failures`,
{ action_id: 'actionA' }
{ action_id: 'actionA', action_type_id: 'actionTypeA' }
);
});
});

describe('timeout', () => {
it('should register a counter when called', () => {
const metrics = new NodeLevelMetrics(monitoringCollection);
metrics.timeout('actionA');
metrics.timeout('actionA', 'actionTypeA');
expect(monitoringCollection.reportCounter).toHaveBeenCalledTimes(1);
expect(monitoringCollection.reportCounter).toHaveBeenCalledWith(
`kibana_alerting_node_action_timeouts`,
{ action_id: 'actionA' }
{ action_id: 'actionA', action_type_id: 'actionTypeA' }
);
});

it('should report the timeout if provided', () => {
const timeout = '1000';
const metrics = new NodeLevelMetrics(monitoringCollection);
metrics.timeout('actionA', timeout);
metrics.timeout('actionA', 'actionTypeA', timeout);
expect(monitoringCollection.reportCounter).toHaveBeenCalledTimes(1);
expect(monitoringCollection.reportCounter).toHaveBeenCalledWith(
`kibana_alerting_node_action_timeouts`,
{ action_id: 'actionA', timeout }
{ action_id: 'actionA', action_type_id: 'actionTypeA', timeout }
);
});
});
Expand Down
Loading

0 comments on commit 7274ca5

Please sign in to comment.