Skip to content

Commit

Permalink
[Alerting] Telemetry for calling legacy routes (elastic#111885)
Browse files Browse the repository at this point in the history
* Telemetry for calling legacy routes

* Fix types

* Use different counter type

* PR feedback

* Fix this test too
# Conflicts:
#	x-pack/plugins/alerting/server/routes/legacy/create.ts
  • Loading branch information
chrisronline committed Sep 13, 2021
1 parent 2796926 commit a0060b1
Show file tree
Hide file tree
Showing 37 changed files with 569 additions and 41 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* 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 { usageCountersServiceMock } from 'src/plugins/usage_collection/server/usage_counters/usage_counters_service.mock';
import { trackLegacyRouteUsage } from './track_legacy_route_usage';

describe('trackLegacyRouteUsage', () => {
it('should call `usageCounter.incrementCounter`', () => {
const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract();
const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test');

trackLegacyRouteUsage('test', mockUsageCounter);
expect(mockUsageCounter.incrementCounter).toHaveBeenCalledWith({
counterName: `legacyRoute_test`,
counterType: 'legacyApiUsage',
incrementBy: 1,
});
});

it('should do nothing if no usage counter is provided', () => {
let err;
try {
trackLegacyRouteUsage('test', undefined);
} catch (e) {
err = e;
}
expect(err).toBeUndefined();
});
});
18 changes: 18 additions & 0 deletions x-pack/plugins/alerting/server/lib/track_legacy_route_usage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* 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 { UsageCounter } from 'src/plugins/usage_collection/server';

export function trackLegacyRouteUsage(route: string, usageCounter?: UsageCounter) {
if (usageCounter) {
usageCounter.incrementCounter({
counterName: `legacyRoute_${route}`,
counterType: 'legacyApiUsage',
incrementBy: 1,
});
}
}
27 changes: 27 additions & 0 deletions x-pack/plugins/alerting/server/routes/legacy/aggregate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,16 @@ import { licenseStateMock } from '../../lib/license_state.mock';
import { verifyApiAccess } from '../../lib/license_api_access';
import { mockHandlerArguments } from './../_mock_handler_arguments';
import { rulesClientMock } from '../../rules_client.mock';
import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage';
import { usageCountersServiceMock } from 'src/plugins/usage_collection/server/usage_counters/usage_counters_service.mock';

const rulesClient = rulesClientMock.create();
const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract();
const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test');

jest.mock('../../lib/track_legacy_route_usage', () => ({
trackLegacyRouteUsage: jest.fn(),
}));

jest.mock('../../lib/license_api_access.ts', () => ({
verifyApiAccess: jest.fn(),
Expand Down Expand Up @@ -139,4 +147,23 @@ describe('aggregateAlertRoute', () => {

expect(verifyApiAccess).toHaveBeenCalledWith(licenseState);
});

it('should track every call', async () => {
const licenseState = licenseStateMock.create();
const router = httpServiceMock.createRouter();

aggregateAlertRoute(router, licenseState, mockUsageCounter);
const [, handler] = router.get.mock.calls[0];
const [context, req, res] = mockHandlerArguments(
{ rulesClient },
{
query: {
default_search_operator: 'AND',
},
},
['ok']
);
await handler(context, req, res);
expect(trackLegacyRouteUsage).toHaveBeenCalledWith('aggregate', mockUsageCounter);
});
});
10 changes: 9 additions & 1 deletion x-pack/plugins/alerting/server/routes/legacy/aggregate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@
*/

import { schema } from '@kbn/config-schema';
import { UsageCounter } from 'src/plugins/usage_collection/server';
import type { AlertingRouter } from '../../types';
import { ILicenseState } from '../../lib/license_state';
import { verifyApiAccess } from '../../lib/license_api_access';
import { LEGACY_BASE_ALERT_API_PATH } from '../../../common';
import { renameKeys } from './../lib/rename_keys';
import { FindOptions } from '../../rules_client';
import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage';

// config definition
const querySchema = schema.object({
Expand All @@ -33,7 +35,11 @@ const querySchema = schema.object({
filter: schema.maybe(schema.string()),
});

export const aggregateAlertRoute = (router: AlertingRouter, licenseState: ILicenseState) => {
export const aggregateAlertRoute = (
router: AlertingRouter,
licenseState: ILicenseState,
usageCounter?: UsageCounter
) => {
router.get(
{
path: `${LEGACY_BASE_ALERT_API_PATH}/_aggregate`,
Expand All @@ -48,6 +54,8 @@ export const aggregateAlertRoute = (router: AlertingRouter, licenseState: ILicen
}
const rulesClient = context.alerting.getRulesClient();

trackLegacyRouteUsage('aggregate', usageCounter);

const query = req.query;
const renameMap = {
default_search_operator: 'defaultSearchOperator',
Expand Down
26 changes: 25 additions & 1 deletion x-pack/plugins/alerting/server/routes/legacy/create.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@
import { MockedLogger, loggerMock } from '@kbn/logging/mocks';
import { createAlertRoute } from './create';
import { httpServiceMock } from 'src/core/server/mocks';
import { usageCountersServiceMock } from 'src/plugins/usage_collection/server/usage_counters/usage_counters_service.mock';
import { licenseStateMock } from '../../lib/license_state.mock';
import { verifyApiAccess } from '../../lib/license_api_access';
import { mockHandlerArguments } from './../_mock_handler_arguments';
import { rulesClientMock } from '../../rules_client.mock';
import { Alert } from '../../../common/alert';
import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled';
import { encryptedSavedObjectsMock } from '../../../../encrypted_saved_objects/server/mocks';
import { usageCountersServiceMock } from 'src/plugins/usage_collection/server/usage_counters/usage_counters_service.mock';
import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage';

const rulesClient = rulesClientMock.create();
let logger: MockedLogger;
Expand All @@ -24,6 +25,10 @@ jest.mock('../../lib/license_api_access.ts', () => ({
verifyApiAccess: jest.fn(),
}));

jest.mock('../../lib/track_legacy_route_usage', () => ({
trackLegacyRouteUsage: jest.fn(),
}));

beforeEach(() => {
jest.resetAllMocks();
logger = loggerMock.create();
Expand Down Expand Up @@ -461,4 +466,23 @@ describe('createAlertRoute', () => {

expect(res.forbidden).toHaveBeenCalledWith({ body: { message: 'Fail' } });
});

it('should track every call', async () => {
const licenseState = licenseStateMock.create();
const router = httpServiceMock.createRouter();
const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true });
const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract();
const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test');

createAlertRoute({
router,
licenseState,
encryptedSavedObjects,
usageCounter: mockUsageCounter,
});
const [, handler] = router.post.mock.calls[0];
const [context, req, res] = mockHandlerArguments({ rulesClient }, {}, ['ok']);
await handler(context, req, res);
expect(trackLegacyRouteUsage).toHaveBeenCalledWith('create', mockUsageCounter);
});
});
2 changes: 2 additions & 0 deletions x-pack/plugins/alerting/server/routes/legacy/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled';
import { RouteOptions } from '..';
import { countUsageOfPredefinedIds } from '../lib';
import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage';

export const bodySchema = schema.object({
name: schema.string(),
Expand Down Expand Up @@ -67,6 +68,7 @@ export const createAlertRoute = ({ router, licenseState, logger, usageCounter }:
const alert = req.body;
const params = req.params;
const notifyWhen = alert?.notifyWhen ? (alert.notifyWhen as AlertNotifyWhenType) : null;
trackLegacyRouteUsage('create', usageCounter);

const spaceId = rulesClient.getSpaceId();
const shouldWarnId = params?.id && spaceId !== undefined && spaceId !== 'default';
Expand Down
21 changes: 21 additions & 0 deletions x-pack/plugins/alerting/server/routes/legacy/delete.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,25 @@
* 2.0.
*/

import { usageCountersServiceMock } from 'src/plugins/usage_collection/server/usage_counters/usage_counters_service.mock';
import { deleteAlertRoute } from './delete';
import { httpServiceMock } from 'src/core/server/mocks';
import { licenseStateMock } from '../../lib/license_state.mock';
import { verifyApiAccess } from '../../lib/license_api_access';
import { mockHandlerArguments } from './../_mock_handler_arguments';
import { rulesClientMock } from '../../rules_client.mock';
import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage';

const rulesClient = rulesClientMock.create();

jest.mock('../../lib/license_api_access.ts', () => ({
verifyApiAccess: jest.fn(),
}));

jest.mock('../../lib/track_legacy_route_usage', () => ({
trackLegacyRouteUsage: jest.fn(),
}));

beforeEach(() => {
jest.resetAllMocks();
});
Expand Down Expand Up @@ -106,4 +112,19 @@ describe('deleteAlertRoute', () => {

expect(verifyApiAccess).toHaveBeenCalledWith(licenseState);
});

it('should track every call', async () => {
const licenseState = licenseStateMock.create();
const router = httpServiceMock.createRouter();
const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract();
const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test');

deleteAlertRoute(router, licenseState, mockUsageCounter);
const [, handler] = router.delete.mock.calls[0];
const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: { id: '1' } }, [
'ok',
]);
await handler(context, req, res);
expect(trackLegacyRouteUsage).toHaveBeenCalledWith('delete', mockUsageCounter);
});
});
9 changes: 8 additions & 1 deletion x-pack/plugins/alerting/server/routes/legacy/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,22 @@
*/

import { schema } from '@kbn/config-schema';
import { UsageCounter } from 'src/plugins/usage_collection/server';
import type { AlertingRouter } from '../../types';
import { ILicenseState } from '../../lib/license_state';
import { verifyApiAccess } from '../../lib/license_api_access';
import { LEGACY_BASE_ALERT_API_PATH } from '../../../common';
import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage';

const paramSchema = schema.object({
id: schema.string(),
});

export const deleteAlertRoute = (router: AlertingRouter, licenseState: ILicenseState) => {
export const deleteAlertRoute = (
router: AlertingRouter,
licenseState: ILicenseState,
usageCounter?: UsageCounter
) => {
router.delete(
{
path: `${LEGACY_BASE_ALERT_API_PATH}/alert/{id}`,
Expand All @@ -28,6 +34,7 @@ export const deleteAlertRoute = (router: AlertingRouter, licenseState: ILicenseS
if (!context.alerting) {
return res.badRequest({ body: 'RouteHandlerContext is not registered for alerting' });
}
trackLegacyRouteUsage('delete', usageCounter);
const rulesClient = context.alerting.getRulesClient();
const { id } = req.params;
await rulesClient.delete({ id });
Expand Down
22 changes: 21 additions & 1 deletion x-pack/plugins/alerting/server/routes/legacy/disable.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,25 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { usageCountersServiceMock } from 'src/plugins/usage_collection/server/usage_counters/usage_counters_service.mock';
import { disableAlertRoute } from './disable';
import { httpServiceMock } from 'src/core/server/mocks';
import { licenseStateMock } from '../../lib/license_state.mock';
import { mockHandlerArguments } from './../_mock_handler_arguments';
import { rulesClientMock } from '../../rules_client.mock';
import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled';
import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage';

const rulesClient = rulesClientMock.create();

jest.mock('../../lib/license_api_access.ts', () => ({
verifyApiAccess: jest.fn(),
}));

jest.mock('../../lib/track_legacy_route_usage', () => ({
trackLegacyRouteUsage: jest.fn(),
}));

beforeEach(() => {
jest.resetAllMocks();
});
Expand Down Expand Up @@ -78,4 +83,19 @@ describe('disableAlertRoute', () => {

expect(res.forbidden).toHaveBeenCalledWith({ body: { message: 'Fail' } });
});

it('should track every call', async () => {
const licenseState = licenseStateMock.create();
const router = httpServiceMock.createRouter();
const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract();
const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test');

disableAlertRoute(router, licenseState, mockUsageCounter);
const [, handler] = router.post.mock.calls[0];
const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: { id: '1' } }, [
'ok',
]);
await handler(context, req, res);
expect(trackLegacyRouteUsage).toHaveBeenCalledWith('disable', mockUsageCounter);
});
});
9 changes: 8 additions & 1 deletion x-pack/plugins/alerting/server/routes/legacy/disable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,23 @@
*/

import { schema } from '@kbn/config-schema';
import { UsageCounter } from 'src/plugins/usage_collection/server';
import type { AlertingRouter } from '../../types';
import { ILicenseState } from '../../lib/license_state';
import { verifyApiAccess } from '../../lib/license_api_access';
import { LEGACY_BASE_ALERT_API_PATH } from '../../../common';
import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled';
import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage';

const paramSchema = schema.object({
id: schema.string(),
});

export const disableAlertRoute = (router: AlertingRouter, licenseState: ILicenseState) => {
export const disableAlertRoute = (
router: AlertingRouter,
licenseState: ILicenseState,
usageCounter?: UsageCounter
) => {
router.post(
{
path: `${LEGACY_BASE_ALERT_API_PATH}/alert/{id}/_disable`,
Expand All @@ -29,6 +35,7 @@ export const disableAlertRoute = (router: AlertingRouter, licenseState: ILicense
if (!context.alerting) {
return res.badRequest({ body: 'RouteHandlerContext is not registered for alerting' });
}
trackLegacyRouteUsage('disable', usageCounter);
const rulesClient = context.alerting.getRulesClient();
const { id } = req.params;
try {
Expand Down
Loading

0 comments on commit a0060b1

Please sign in to comment.