Skip to content

Commit

Permalink
[Actions] Telemetry for calling legacy routes (#111901)
Browse files Browse the repository at this point in the history
* Telemetry for legacy http api routes

* PR feedback
  • Loading branch information
chrisronline authored Sep 13, 2021
1 parent f8449a2 commit 74d87db
Show file tree
Hide file tree
Showing 20 changed files with 266 additions and 19 deletions.
1 change: 1 addition & 0 deletions x-pack/plugins/actions/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ export * from './rewrite_request_case';

export const BASE_ACTION_API_PATH = '/api/actions';
export const INTERNAL_BASE_ACTION_API_PATH = '/internal/actions';
export const ACTIONS_FEATURE_ID = 'actions';
32 changes: 32 additions & 0 deletions x-pack/plugins/actions/server/lib/track_legacy_route_usage.test.ts
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/actions/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,
});
}
}
11 changes: 9 additions & 2 deletions x-pack/plugins/actions/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ import { ensureSufficientLicense } from './lib/ensure_sufficient_license';
import { renderMustacheObject } from './lib/mustache_renderer';
import { getAlertHistoryEsIndex } from './preconfigured_connectors/alert_history_es_index/alert_history_es_index';
import { createAlertHistoryIndexTemplate } from './preconfigured_connectors/alert_history_es_index/create_alert_history_index_template';
import { AlertHistoryEsIndexConnectorId } from '../common';
import { ACTIONS_FEATURE_ID, AlertHistoryEsIndexConnectorId } from '../common';
import { EVENT_LOG_ACTIONS, EVENT_LOG_PROVIDER } from './constants/event_log';

export interface PluginSetupContract {
Expand Down Expand Up @@ -263,8 +263,15 @@ export class ActionsPlugin implements Plugin<PluginSetupContract, PluginStartCon
);
}

// Usage counter for telemetry
const usageCounter = plugins.usageCollection?.createUsageCounter(ACTIONS_FEATURE_ID);

// Routes
defineRoutes(core.http.createRouter<ActionsRequestHandlerContext>(), this.licenseState);
defineRoutes(
core.http.createRouter<ActionsRequestHandlerContext>(),
this.licenseState,
usageCounter
);

// Cleanup failed execution task definition
if (this.actionsConfig.cleanupFailedExecutionsTask.enabled) {
Expand Down
6 changes: 4 additions & 2 deletions x-pack/plugins/actions/server/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

import { IRouter } from 'kibana/server';
import { UsageCounter } from 'src/plugins/usage_collection/server';
import { ILicenseState } from '../lib';
import { ActionsRequestHandlerContext } from '../types';
import { createActionRoute } from './create';
Expand All @@ -20,9 +21,10 @@ import { defineLegacyRoutes } from './legacy';

export function defineRoutes(
router: IRouter<ActionsRequestHandlerContext>,
licenseState: ILicenseState
licenseState: ILicenseState,
usageCounter?: UsageCounter
) {
defineLegacyRoutes(router, licenseState);
defineLegacyRoutes(router, licenseState, usageCounter);

createActionRoute(router, licenseState);
deleteActionRoute(router, licenseState);
Expand Down
21 changes: 21 additions & 0 deletions x-pack/plugins/actions/server/routes/legacy/create.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,20 @@ import { licenseStateMock } from '../../lib/license_state.mock';
import { mockHandlerArguments } from './_mock_handler_arguments';
import { actionsClientMock } from '../../actions_client.mock';
import { verifyAccessAndContext } from '../verify_access_and_context';
import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage';
import { usageCountersServiceMock } from 'src/plugins/usage_collection/server/usage_counters/usage_counters_service.mock';

jest.mock('../verify_access_and_context.ts', () => ({
verifyAccessAndContext: jest.fn(),
}));

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

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

beforeEach(() => {
jest.resetAllMocks();
(verifyAccessAndContext as jest.Mock).mockImplementation((license, handler) => handler);
Expand Down Expand Up @@ -128,4 +137,16 @@ describe('createActionRoute', () => {

expect(handler(context, req, res)).rejects.toMatchInlineSnapshot(`[Error: OMG]`);
});

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

createActionRoute(router, licenseState, mockUsageCounter);
const [, handler] = router.post.mock.calls[0];
const [context, req, res] = mockHandlerArguments({ actionsClient }, {});
await handler(context, req, res);
expect(trackLegacyRouteUsage).toHaveBeenCalledWith('create', mockUsageCounter);
});
});
6 changes: 5 additions & 1 deletion x-pack/plugins/actions/server/routes/legacy/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
*/

import { schema } from '@kbn/config-schema';
import { UsageCounter } from 'src/plugins/usage_collection/server';
import { IRouter } from 'kibana/server';
import { ActionsRequestHandlerContext } from '../../types';
import { ILicenseState } from '../../lib';
import { BASE_ACTION_API_PATH } from '../../../common';
import { verifyAccessAndContext } from '../verify_access_and_context';
import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage';

export const bodySchema = schema.object({
name: schema.string(),
Expand All @@ -21,7 +23,8 @@ export const bodySchema = schema.object({

export const createActionRoute = (
router: IRouter<ActionsRequestHandlerContext>,
licenseState: ILicenseState
licenseState: ILicenseState,
usageCounter?: UsageCounter
) => {
router.post(
{
Expand All @@ -34,6 +37,7 @@ export const createActionRoute = (
verifyAccessAndContext(licenseState, async function (context, req, res) {
const actionsClient = context.actions.getActionsClient();
const action = req.body;
trackLegacyRouteUsage('create', usageCounter);
return res.ok({
body: await actionsClient.create({ action }),
});
Expand Down
28 changes: 28 additions & 0 deletions x-pack/plugins/actions/server/routes/legacy/delete.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,20 @@ import { licenseStateMock } from '../../lib/license_state.mock';
import { verifyApiAccess } from '../../lib';
import { mockHandlerArguments } from './_mock_handler_arguments';
import { actionsClientMock } from '../../mocks';
import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage';
import { usageCountersServiceMock } from 'src/plugins/usage_collection/server/usage_counters/usage_counters_service.mock';

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

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

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

beforeEach(() => {
jest.resetAllMocks();
});
Expand Down Expand Up @@ -107,4 +116,23 @@ describe('deleteActionRoute', () => {

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

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

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

import { schema } from '@kbn/config-schema';
import { UsageCounter } from 'src/plugins/usage_collection/server';
import { IRouter } from 'kibana/server';
import { ILicenseState, verifyApiAccess, isErrorThatHandlesItsOwnResponse } from '../../lib';
import { BASE_ACTION_API_PATH } from '../../../common';
import { ActionsRequestHandlerContext } from '../../types';
import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage';

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

export const deleteActionRoute = (
router: IRouter<ActionsRequestHandlerContext>,
licenseState: ILicenseState
licenseState: ILicenseState,
usageCounter?: UsageCounter
) => {
router.delete(
{
Expand All @@ -33,6 +36,7 @@ export const deleteActionRoute = (
}
const actionsClient = context.actions.getActionsClient();
const { id } = req.params;
trackLegacyRouteUsage('delete', usageCounter);
try {
await actionsClient.delete({ id });
return res.noContent();
Expand Down
21 changes: 21 additions & 0 deletions x-pack/plugins/actions/server/routes/legacy/execute.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,20 @@ import { mockHandlerArguments } from './_mock_handler_arguments';
import { verifyApiAccess, ActionTypeDisabledError, asHttpRequestExecutionSource } from '../../lib';
import { actionsClientMock } from '../../actions_client.mock';
import { ActionTypeExecutorResult } from '../../types';
import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage';
import { usageCountersServiceMock } from 'src/plugins/usage_collection/server/usage_counters/usage_counters_service.mock';

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

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

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

beforeEach(() => {
jest.resetAllMocks();
});
Expand Down Expand Up @@ -192,4 +201,16 @@ describe('executeActionRoute', () => {

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

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

executeActionRoute(router, licenseState, mockUsageCounter);
const [, handler] = router.post.mock.calls[0];
const [context, req, res] = mockHandlerArguments({ actionsClient }, { body: {}, params: {} });
await handler(context, req, res);
expect(trackLegacyRouteUsage).toHaveBeenCalledWith('execute', mockUsageCounter);
});
});
6 changes: 5 additions & 1 deletion x-pack/plugins/actions/server/routes/legacy/execute.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 { IRouter } from 'kibana/server';
import { ILicenseState, verifyApiAccess, isErrorThatHandlesItsOwnResponse } from '../../lib';

import { ActionTypeExecutorResult, ActionsRequestHandlerContext } from '../../types';
import { BASE_ACTION_API_PATH } from '../../../common';
import { asHttpRequestExecutionSource } from '../../lib/action_execution_source';
import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage';

const paramSchema = schema.object({
id: schema.string(),
Expand All @@ -23,7 +25,8 @@ const bodySchema = schema.object({

export const executeActionRoute = (
router: IRouter<ActionsRequestHandlerContext>,
licenseState: ILicenseState
licenseState: ILicenseState,
usageCounter?: UsageCounter
) => {
router.post(
{
Expand All @@ -43,6 +46,7 @@ export const executeActionRoute = (
const actionsClient = context.actions.getActionsClient();
const { params } = req.body;
const { id } = req.params;
trackLegacyRouteUsage('execute', usageCounter);
try {
const body: ActionTypeExecutorResult<unknown> = await actionsClient.execute({
params,
Expand Down
21 changes: 21 additions & 0 deletions x-pack/plugins/actions/server/routes/legacy/get.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,20 @@ import { licenseStateMock } from '../../lib/license_state.mock';
import { verifyApiAccess } from '../../lib';
import { mockHandlerArguments } from './_mock_handler_arguments';
import { actionsClientMock } from '../../actions_client.mock';
import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage';
import { usageCountersServiceMock } from 'src/plugins/usage_collection/server/usage_counters/usage_counters_service.mock';

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

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

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

beforeEach(() => {
jest.resetAllMocks();
});
Expand Down Expand Up @@ -133,4 +142,16 @@ describe('getActionRoute', () => {

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

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

getActionRoute(router, licenseState, mockUsageCounter);
const [, handler] = router.get.mock.calls[0];
const [context, req, res] = mockHandlerArguments({ actionsClient }, { params: { id: '1' } });
await handler(context, req, res);
expect(trackLegacyRouteUsage).toHaveBeenCalledWith('get', mockUsageCounter);
});
});
6 changes: 5 additions & 1 deletion x-pack/plugins/actions/server/routes/legacy/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,21 @@
*/

import { schema } from '@kbn/config-schema';
import { UsageCounter } from 'src/plugins/usage_collection/server';
import { IRouter } from 'kibana/server';
import { ILicenseState, verifyApiAccess } from '../../lib';
import { BASE_ACTION_API_PATH } from '../../../common';
import { ActionsRequestHandlerContext } from '../../types';
import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage';

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

export const getActionRoute = (
router: IRouter<ActionsRequestHandlerContext>,
licenseState: ILicenseState
licenseState: ILicenseState,
usageCounter?: UsageCounter
) => {
router.get(
{
Expand All @@ -33,6 +36,7 @@ export const getActionRoute = (
}
const actionsClient = context.actions.getActionsClient();
const { id } = req.params;
trackLegacyRouteUsage('get', usageCounter);
return res.ok({
body: await actionsClient.get({ id }),
});
Expand Down
Loading

0 comments on commit 74d87db

Please sign in to comment.