From 2234e3ad025109b315656a8fe13a4f8d213ff52a Mon Sep 17 00:00:00 2001 From: Ersin Erdal Date: Mon, 24 Jun 2024 12:41:37 +0200 Subject: [PATCH 01/25] Metering connector actions request body bytes --- .../create_unsecured_execute_function.ts | 5 +- .../actions/server/lib/action_executor.ts | 3 + .../plugins/actions/server/lib/axios_utils.ts | 44 ++++-- .../server/lib/connector_metrics_service.ts | 31 ++++ x-pack/plugins/actions/server/lib/index.ts | 1 + .../server/sub_action_framework/executor.ts | 12 +- .../sub_action_connector.ts | 26 ++-- x-pack/plugins/actions/server/types.ts | 7 +- .../unsecured_actions_client.ts | 9 +- .../common/slack_api/types.ts | 26 ++-- .../server/connector_types/bedrock/bedrock.ts | 128 ++++++++-------- .../connector_types/cases_webhook/api.ts | 40 +++-- .../connector_types/cases_webhook/index.ts | 13 +- .../connector_types/cases_webhook/service.ts | 38 +++-- .../connector_types/cases_webhook/types.ts | 26 +++- .../crowdstrike/crowdstrike.ts | 139 +++++++++++------- .../connector_types/d3security/d3security.ts | 35 +++-- .../server/connector_types/email/index.ts | 7 +- .../connector_types/email/send_email.ts | 26 +++- .../email/send_email_graph_api.ts | 15 +- .../server/connector_types/slack/index.ts | 4 +- .../server/connector_types/slack_api/api.ts | 13 +- .../server/connector_types/slack_api/index.ts | 4 + .../connector_types/slack_api/service.ts | 25 ++-- .../server/connector_types/webhook/index.ts | 4 +- 25 files changed, 437 insertions(+), 244 deletions(-) create mode 100644 x-pack/plugins/actions/server/lib/connector_metrics_service.ts diff --git a/x-pack/plugins/actions/server/create_unsecured_execute_function.ts b/x-pack/plugins/actions/server/create_unsecured_execute_function.ts index c37ca980867dd..71ec6d4e09d00 100644 --- a/x-pack/plugins/actions/server/create_unsecured_execute_function.ts +++ b/x-pack/plugins/actions/server/create_unsecured_execute_function.ts @@ -27,7 +27,10 @@ interface CreateBulkUnsecuredExecuteFunctionOptions { } export interface ExecuteOptions - extends Pick { + extends Pick< + ActionExecutorOptions, + 'params' | 'source' | 'relatedSavedObjects' | 'connectorMetricsService' + > { id: string; } diff --git a/x-pack/plugins/actions/server/lib/action_executor.ts b/x-pack/plugins/actions/server/lib/action_executor.ts index c06e33bf3df6a..838a076b1fc16 100644 --- a/x-pack/plugins/actions/server/lib/action_executor.ts +++ b/x-pack/plugins/actions/server/lib/action_executor.ts @@ -16,6 +16,7 @@ import { IEventLogger, SAVED_OBJECT_REL_PRIMARY } from '@kbn/event-log-plugin/se import { AuthenticatedUser, SecurityPluginStart } from '@kbn/security-plugin/server'; import { createTaskRunError, TaskErrorSource } from '@kbn/task-manager-plugin/server'; import { getErrorSource } from '@kbn/task-manager-plugin/server/task_running'; +import { ConnectorMetricsService } from './connector_metrics_service'; import { getGenAiTokenTracking, shouldTrackGenAiToken } from './gen_ai_token_tracking'; import { validateConfig, @@ -381,6 +382,7 @@ export class ActionExecutor { }, async (span) => { const { actionTypeRegistry, eventLogger } = this.actionExecutorContext!; + const connectorMetricsService = new ConnectorMetricsService(); const actionInfo = await this.getActionInfoInternal(actionId, namespace.namespace); @@ -502,6 +504,7 @@ export class ActionExecutor { logger, source, ...(actionType.isSystemActionType ? { request } : {}), + connectorMetricsService, }); if (rawResult && rawResult.status === 'error') { diff --git a/x-pack/plugins/actions/server/lib/axios_utils.ts b/x-pack/plugins/actions/server/lib/axios_utils.ts index 3852f2a33755b..4ec72e7f6c064 100644 --- a/x-pack/plugins/actions/server/lib/axios_utils.ts +++ b/x-pack/plugins/actions/server/lib/axios_utils.ts @@ -17,7 +17,7 @@ import { import { Logger } from '@kbn/core/server'; import { getCustomAgents } from './get_custom_agents'; import { ActionsConfigurationUtilities } from '../actions_config'; -import { SSLSettings } from '../types'; +import { ConnectorMetricsService, SSLSettings } from '../types'; import { combineHeadersWithBasicAuthHeader } from './get_basic_auth_header'; export const request = async ({ @@ -30,6 +30,7 @@ export const request = async ({ headers, sslOverrides, timeout, + connectorMetricsService, ...config }: { axios: AxiosInstance; @@ -41,6 +42,7 @@ export const request = async ({ headers?: Record; timeout?: number; sslOverrides?: SSLSettings; + connectorMetricsService?: ConnectorMetricsService; } & AxiosRequestConfig): Promise => { if (!isEmpty(axios?.defaults?.baseURL ?? '')) { throw new Error( @@ -64,18 +66,31 @@ export const request = async ({ headers, }); - return await axios(url, { - ...restConfig, - method, - headers: headersWithBasicAuth, - ...(data ? { data } : {}), - // use httpAgent and httpsAgent and set axios proxy: false, to be able to handle fail on invalid certs - httpAgent, - httpsAgent, - proxy: false, - maxContentLength, - timeout: Math.max(settingsTimeout, timeout ?? 0), - }); + try { + const result = await axios(url, { + ...restConfig, + method, + headers: headersWithBasicAuth, + ...(data ? { data } : {}), + // use httpAgent and httpsAgent and set axios proxy: false, to be able to handle fail on invalid certs + httpAgent, + httpsAgent, + proxy: false, + maxContentLength, + timeout: Math.max(settingsTimeout, timeout ?? 0), + }); + + if (connectorMetricsService) { + connectorMetricsService.addRequestBodyBytes(result, data); + } + + return result; + } catch (error) { + if (connectorMetricsService) { + connectorMetricsService.addRequestBodyBytes(error, data); + } + throw error; + } }; export const patch = async ({ @@ -84,12 +99,14 @@ export const patch = async ({ data, logger, configurationUtilities, + connectorMetricsService, }: { axios: AxiosInstance; url: string; data: T; logger: Logger; configurationUtilities: ActionsConfigurationUtilities; + connectorMetricsService: ConnectorMetricsService; }): Promise => { return request({ axios, @@ -98,6 +115,7 @@ export const patch = async ({ method: 'patch', data, configurationUtilities, + connectorMetricsService, }); }; diff --git a/x-pack/plugins/actions/server/lib/connector_metrics_service.ts b/x-pack/plugins/actions/server/lib/connector_metrics_service.ts new file mode 100644 index 0000000000000..678d72e6413b0 --- /dev/null +++ b/x-pack/plugins/actions/server/lib/connector_metrics_service.ts @@ -0,0 +1,31 @@ +/* + * 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 { AxiosError, AxiosResponse } from 'axios'; + +interface ConnectorMetrics { + requestBodyBytes: number; +} + +export class ConnectorMetricsService { + private metrics: ConnectorMetrics = { + requestBodyBytes: 0, + }; + + public addRequestBodyBytes(result?: AxiosError | AxiosResponse, body: string | object = '') { + this.metrics.requestBodyBytes = this.extractRequestBodyBytes(result, body); + } + + public getRequestBodyByte() { + return this.metrics.requestBodyBytes; + } + + private extractRequestBodyBytes(result?: AxiosError | AxiosResponse, body: string | object = '') { + const stringBody = typeof body === 'string' ? body : JSON.stringify(body); + return result?.request?.headers?.['Content-Length'] || Buffer.byteLength(stringBody, 'utf8'); + } +} diff --git a/x-pack/plugins/actions/server/lib/index.ts b/x-pack/plugins/actions/server/lib/index.ts index 2737d83abfff6..ada48f8beefd0 100644 --- a/x-pack/plugins/actions/server/lib/index.ts +++ b/x-pack/plugins/actions/server/lib/index.ts @@ -39,3 +39,4 @@ export { validateEmptyStrings } from './validate_empty_strings'; export { parseDate } from './parse_date'; export type { RelatedSavedObjects } from './related_saved_objects'; export { getBasicAuthHeader, combineHeadersWithBasicAuthHeader } from './get_basic_auth_header'; +export { ConnectorMetricsService } from './connector_metrics_service'; diff --git a/x-pack/plugins/actions/server/sub_action_framework/executor.ts b/x-pack/plugins/actions/server/sub_action_framework/executor.ts index d9f2f693c175d..5e8d79264b3e6 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/executor.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/executor.ts @@ -30,7 +30,15 @@ export const buildExecutor = < logger: Logger; configurationUtilities: ActionsConfigurationUtilities; }): ExecutorType => { - return async ({ actionId, params, config, secrets, services, request }) => { + return async ({ + actionId, + params, + config, + secrets, + services, + request, + connectorMetricsService, + }) => { const subAction = params.subAction; const subActionParams = params.subActionParams; @@ -88,7 +96,7 @@ export const buildExecutor = < } } - const data = await func.call(service, subActionParams); + const data = await func.call(service, subActionParams, connectorMetricsService); return { status: 'ok', data: data ?? {}, actionId }; }; }; diff --git a/x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.ts b/x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.ts index 19cc7e90d6254..92834c6cd8485 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.ts @@ -24,6 +24,7 @@ import { IncomingMessage } from 'http'; import { PassThrough } from 'stream'; import { KibanaRequest } from '@kbn/core-http-server'; import { inspect } from 'util'; +import { ConnectorMetricsService } from '../lib'; import { assertURL } from './helpers/validators'; import { ActionsConfigurationUtilities } from '../actions_config'; import { SubAction, SubActionRequestParams } from './types'; @@ -130,15 +131,18 @@ export abstract class SubActionConnector { protected abstract getResponseErrorMessage(error: AxiosError): string; - protected async request({ - url, - data, - method = 'get', - responseSchema, - headers, - timeout, - ...config - }: SubActionRequestParams): Promise> { + protected async request( + { + url, + data, + method = 'get', + responseSchema, + headers, + timeout, + ...config + }: SubActionRequestParams, + connectorMetricsService: ConnectorMetricsService + ): Promise> { try { this.assertURL(url); this.ensureUriAllowed(url); @@ -149,6 +153,7 @@ export abstract class SubActionConnector { ); const { auth, ...restConfig } = config; + const normalizedData = this.normalizeData(data); const res = await request({ ...restConfig, @@ -156,10 +161,11 @@ export abstract class SubActionConnector { url: normalizedURL, logger: this.logger, method, - data: this.normalizeData(data), + data: normalizedData, configurationUtilities: this.configurationUtilities, headers: this.getHeaders(auth, headers as AxiosHeaders), timeout, + connectorMetricsService, }); this.validateResponse(responseSchema, res.data); diff --git a/x-pack/plugins/actions/server/types.ts b/x-pack/plugins/actions/server/types.ts index aa6c7b26cf0ae..d4bb89618e0e5 100644 --- a/x-pack/plugins/actions/server/types.ts +++ b/x-pack/plugins/actions/server/types.ts @@ -39,11 +39,9 @@ export type ActionTypeSecrets = Record; export type ActionTypeParams = Record; export type ConnectorTokenClientContract = PublicMethodsOf; -import type { ActionExecutionSource } from './lib'; import { Connector, ConnectorWithExtraFindData } from './application/connector/types'; -export type { ActionExecutionSource } from './lib'; - -export { ActionExecutionSourceType } from './lib'; +import type { ActionExecutionSource, ConnectorMetricsService } from './lib'; +export { ActionExecutionSourceType, ConnectorMetricsService } from './lib'; export interface Services { savedObjectsClient: SavedObjectsClientContract; @@ -88,6 +86,7 @@ export interface ActionTypeExecutorOptions< configurationUtilities: ActionsConfigurationUtilities; source?: ActionExecutionSource; request?: KibanaRequest; + connectorMetricsService: ConnectorMetricsService; } export type ActionResult = Connector; diff --git a/x-pack/plugins/actions/server/unsecured_actions_client/unsecured_actions_client.ts b/x-pack/plugins/actions/server/unsecured_actions_client/unsecured_actions_client.ts index 8331f6890486c..8394d885158b8 100644 --- a/x-pack/plugins/actions/server/unsecured_actions_client/unsecured_actions_client.ts +++ b/x-pack/plugins/actions/server/unsecured_actions_client/unsecured_actions_client.ts @@ -12,11 +12,8 @@ import { ExecuteOptions, ExecutionResponse, } from '../create_unsecured_execute_function'; -import { - ActionExecutorContract, - asNotificationExecutionSource, - type RelatedSavedObjects, -} from '../lib'; +import { ActionExecutorContract, asNotificationExecutionSource } from '../lib'; +import type { RelatedSavedObjects } from '../lib'; import { ActionTypeExecutorResult, InMemoryConnector } from '../types'; import { asBackgroundTaskExecutionSource } from '../lib/action_execution_source'; import { ConnectorWithExtraFindData } from '../application/connector/types'; @@ -70,6 +67,7 @@ export class UnsecuredActionsClient { params, relatedSavedObjects, spaceId, + connectorMetricsService, }: UnsecuredExecuteOptions) { // Check that requesterId is allowed if (!ALLOWED_REQUESTER_IDS.includes(requesterId)) { @@ -93,6 +91,7 @@ export class UnsecuredActionsClient { relatedSavedObjects, spaceId, ...source, + connectorMetricsService, }); } diff --git a/x-pack/plugins/stack_connectors/common/slack_api/types.ts b/x-pack/plugins/stack_connectors/common/slack_api/types.ts index a19aa5c2159fa..16a240778307c 100644 --- a/x-pack/plugins/stack_connectors/common/slack_api/types.ts +++ b/x-pack/plugins/stack_connectors/common/slack_api/types.ts @@ -8,7 +8,10 @@ import type { ActionType as ConnectorType } from '@kbn/actions-plugin/server/types'; import { TypeOf } from '@kbn/config-schema'; import type { ActionTypeExecutorOptions as ConnectorTypeExecutorOptions } from '@kbn/actions-plugin/server/types'; -import type { ActionTypeExecutorResult as ConnectorTypeExecutorResult } from '@kbn/actions-plugin/server/types'; +import type { + ActionTypeExecutorResult as ConnectorTypeExecutorResult, + ConnectorMetricsService, +} from '@kbn/actions-plugin/server/types'; import { PostMessageParamsSchema, PostMessageSubActionParamsSchema, @@ -84,16 +87,15 @@ export interface ValidChannelRouteResponse { export interface SlackApiService { validChannelId: ( - channelId: string + channelId: string, + connectorMetricsService: ConnectorMetricsService ) => Promise>; - postMessage: ({ - channels, - channelIds, - text, - }: PostMessageSubActionParams) => Promise>; - postBlockkit: ({ - channels, - channelIds, - text, - }: PostBlockkitSubActionParams) => Promise>; + postMessage: ( + { channels, channelIds, text }: PostMessageSubActionParams, + connectorMetricsService: ConnectorMetricsService + ) => Promise>; + postBlockkit: ( + { channels, channelIds, text }: PostBlockkitSubActionParams, + connectorMetricsService: ConnectorMetricsService + ) => Promise>; } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.ts b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.ts index 8b05c30a5b0cb..c9c4a3404d6ae 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.ts @@ -11,6 +11,7 @@ import { AxiosError, Method } from 'axios'; import { IncomingMessage } from 'http'; import { PassThrough } from 'stream'; import { SubActionRequestParams } from '@kbn/actions-plugin/server/sub_action_framework/types'; +import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; import { initDashboard } from '../lib/gen_ai/create_gen_ai_dashboard'; import { RunActionParamsSchema, @@ -184,16 +185,18 @@ The Kibana Connector in use may need to be reconfigured with an updated Amazon B } private async runApiDeprecated( - params: SubActionRequestParams // : SubActionRequestParams + params: SubActionRequestParams, // : SubActionRequestParams + connectorMetricsService: ConnectorMetricsService ): Promise { - const response = await this.request(params); + const response = await this.request(params, connectorMetricsService); return response.data; } private async runApiLatest( - params: SubActionRequestParams // : SubActionRequestParams + params: SubActionRequestParams, // : SubActionRequestParams + connectorMetricsService: ConnectorMetricsService ): Promise { - const response = await this.request(params); + const response = await this.request(params, connectorMetricsService); // keeping the response the same as claude 2 for our APIs // adding the usage object for better token tracking return { @@ -208,12 +211,10 @@ The Kibana Connector in use may need to be reconfigured with an updated Amazon B * @param body The stringified request body to be sent in the POST request. * @param model Optional model to be used for the API request. If not provided, the default model from the connector will be used. */ - public async runApi({ - body, - model: reqModel, - signal, - timeout, - }: RunActionParams): Promise { + public async runApi( + { body, model: reqModel, signal, timeout }: RunActionParams, + connectorMetricsService: ConnectorMetricsService + ): Promise { // set model on per request basis const currentModel = reqModel ?? this.model; const path = `/model/${currentModel}/invoke`; @@ -229,9 +230,15 @@ The Kibana Connector in use may need to be reconfigured with an updated Amazon B }; // possible api received deprecated arguments, which will still work with the deprecated Claude 2 models if (usesDeprecatedArguments(body)) { - return this.runApiDeprecated({ ...requestArgs, responseSchema: RunActionResponseSchema }); + return this.runApiDeprecated( + { ...requestArgs, responseSchema: RunActionResponseSchema }, + connectorMetricsService + ); } - return this.runApiLatest({ ...requestArgs, responseSchema: RunApiLatestResponseSchema }); + return this.runApiLatest( + { ...requestArgs, responseSchema: RunApiLatestResponseSchema }, + connectorMetricsService + ); } /** @@ -242,26 +249,27 @@ The Kibana Connector in use may need to be reconfigured with an updated Amazon B * @param body The stringified request body to be sent in the POST request. * @param model Optional model to be used for the API request. If not provided, the default model from the connector will be used. */ - private async streamApi({ - body, - model: reqModel, - signal, - timeout, - }: RunActionParams): Promise { + private async streamApi( + { body, model: reqModel, signal, timeout }: RunActionParams, + connectorMetricsService: ConnectorMetricsService + ): Promise { // set model on per request basis const path = `/model/${reqModel ?? this.model}/invoke-with-response-stream`; const signed = this.signRequest(body, path, true); - const response = await this.request({ - ...signed, - url: `${this.url}${path}`, - method: 'post', - responseSchema: StreamingResponseSchema, - data: body, - responseType: 'stream', - signal, - timeout, - }); + const response = await this.request( + { + ...signed, + url: `${this.url}${path}`, + method: 'post', + responseSchema: StreamingResponseSchema, + data: body, + responseType: 'stream', + signal, + timeout, + }, + connectorMetricsService + ); return response.data.pipe(new PassThrough()); } @@ -274,21 +282,19 @@ The Kibana Connector in use may need to be reconfigured with an updated Amazon B * @param messages An array of messages to be sent to the API * @param model Optional model to be used for the API request. If not provided, the default model from the connector will be used. */ - public async invokeStream({ - messages, - model, - stopSequences, - system, - temperature, - signal, - timeout, - }: InvokeAIActionParams): Promise { - const res = (await this.streamApi({ - body: JSON.stringify(formatBedrockBody({ messages, stopSequences, system, temperature })), - model, - signal, - timeout, - })) as unknown as IncomingMessage; + public async invokeStream( + { messages, model, stopSequences, system, temperature, signal, timeout }: InvokeAIActionParams, + connectorMetricsService: ConnectorMetricsService + ): Promise { + const res = (await this.streamApi( + { + body: JSON.stringify(formatBedrockBody({ messages, stopSequences, system, temperature })), + model, + signal, + timeout, + }, + connectorMetricsService + )) as unknown as IncomingMessage; return res; } @@ -300,24 +306,30 @@ The Kibana Connector in use may need to be reconfigured with an updated Amazon B * @param model Optional model to be used for the API request. If not provided, the default model from the connector will be used. * @returns an object with the response string as a property called message */ - public async invokeAI({ - messages, - model, - stopSequences, - system, - temperature, - maxTokens, - signal, - timeout, - }: InvokeAIActionParams): Promise { - const res = await this.runApi({ - body: JSON.stringify( - formatBedrockBody({ messages, stopSequences, system, temperature, maxTokens }) - ), + public async invokeAI( + { + messages, model, + stopSequences, + system, + temperature, + maxTokens, signal, timeout, - }); + }: InvokeAIActionParams, + connectorMetricsService: ConnectorMetricsService + ): Promise { + const res = await this.runApi( + { + body: JSON.stringify( + formatBedrockBody({ messages, stopSequences, system, temperature, maxTokens }) + ), + model, + signal, + timeout, + }, + connectorMetricsService + ); return { message: res.completion.trim() }; } } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/api.ts b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/api.ts index 109c1afa920b6..f2aec6f05fc05 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/api.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/api.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; import { ExternalServiceApi, Incident, @@ -12,10 +13,10 @@ import { PushToServiceResponse, } from './types'; -const pushToServiceHandler = async ({ - externalService, - params, -}: PushToServiceApiHandlerArgs): Promise => { +const pushToServiceHandler = async ( + { externalService, params }: PushToServiceApiHandlerArgs, + connectorMetricsService: ConnectorMetricsService +): Promise => { const { incident: { externalId, ...rest }, comments, @@ -24,14 +25,20 @@ const pushToServiceHandler = async ({ let res: PushToServiceResponse; if (externalId != null) { - res = await externalService.updateIncident({ - incidentId: externalId, - incident, - }); + res = await externalService.updateIncident( + { + incidentId: externalId, + incident, + }, + connectorMetricsService + ); } else { - res = await externalService.createIncident({ - incident, - }); + res = await externalService.createIncident( + { + incident, + }, + connectorMetricsService + ); } if (comments && Array.isArray(comments) && comments.length > 0) { @@ -40,10 +47,13 @@ const pushToServiceHandler = async ({ if (!currentComment.comment) { continue; } - await externalService.createComment({ - incidentId: res.id, - comment: currentComment, - }); + await externalService.createComment( + { + incidentId: res.id, + comment: currentComment, + }, + connectorMetricsService + ); res.comments = [ ...(res.comments ?? []), { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/index.ts index 62dd881608605..eaf99852fd75a 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/index.ts @@ -98,11 +98,14 @@ export async function executor( if (subAction === 'pushToService') { const pushToServiceParams = subActionParams as ExecutorSubActionPushParams; - data = await api.pushToService({ - externalService, - params: pushToServiceParams, - logger, - }); + data = await api.pushToService( + { + externalService, + params: pushToServiceParams, + logger, + }, + execOptions.connectorMetricsService + ); logger.debug(`response push to service for case id: ${data.id}`); } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.ts b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.ts index 424fe9b394517..340bb5c51c3b2 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.ts @@ -11,7 +11,10 @@ import { Logger } from '@kbn/core/server'; import { renderMustacheStringNoEscape } from '@kbn/actions-plugin/server/lib/mustache_renderer'; import { request } from '@kbn/actions-plugin/server/lib/axios_utils'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; -import { combineHeadersWithBasicAuthHeader } from '@kbn/actions-plugin/server/lib'; +import { + combineHeadersWithBasicAuthHeader, + ConnectorMetricsService, +} from '@kbn/actions-plugin/server/lib'; import { buildConnectorAuth, validateConnectorAuthConfiguration } from '../../../common/auth/utils'; import { validateAndNormalizeUrl, validateJson } from './validators'; import { @@ -96,7 +99,10 @@ export const createExternalService = ( const createIncidentUrl = removeSlash(createIncidentUrlConfig); - const getIncident = async (id: string): Promise => { + const getIncident = async ( + id: string, + connectorMetricsService: ConnectorMetricsService + ): Promise => { try { const getUrl = renderMustacheStringNoEscape(getIncidentUrl, { external: { @@ -117,6 +123,7 @@ export const createExternalService = ( logger, configurationUtilities, sslOverrides, + connectorMetricsService, }); throwDescriptiveErrorIfResponseIsNotValid({ @@ -131,9 +138,10 @@ export const createExternalService = ( } }; - const createIncident = async ({ - incident, - }: CreateIncidentParams): Promise => { + const createIncident = async ( + { incident }: CreateIncidentParams, + connectorMetricsService: ConnectorMetricsService + ): Promise => { try { const { description, id, severity, status: incidentStatus, tags, title } = incident; const normalizedUrl = validateAndNormalizeUrl( @@ -162,6 +170,7 @@ export const createExternalService = ( data: json, configurationUtilities, sslOverrides, + connectorMetricsService, }); const { status, statusText, data } = res; @@ -171,7 +180,7 @@ export const createExternalService = ( requiredAttributesToBeInTheResponse: [createIncidentResponseKey], }); const externalId = getObjectValueByKeyAsString(data, createIncidentResponseKey)!; - const insertedIncident = await getIncident(externalId); + const insertedIncident = await getIncident(externalId, connectorMetricsService); logger.debug(`response from webhook action "${actionId}": [HTTP ${status}] ${statusText}`); @@ -199,10 +208,10 @@ export const createExternalService = ( } }; - const updateIncident = async ({ - incidentId, - incident, - }: UpdateIncidentParams): Promise => { + const updateIncident = async ( + { incidentId, incident }: UpdateIncidentParams, + connectorMetricsService: ConnectorMetricsService + ): Promise => { try { const updateUrl = renderMustacheStringNoEscape(updateIncidentUrl, { external: { @@ -246,13 +255,14 @@ export const createExternalService = ( data: json, configurationUtilities, sslOverrides, + connectorMetricsService, }); throwDescriptiveErrorIfResponseIsNotValid({ res, }); - const updatedIncident = await getIncident(incidentId as string); + const updatedIncident = await getIncident(incidentId as string, connectorMetricsService); const viewUrl = renderMustacheStringNoEscape(viewIncidentUrl, { external: { @@ -280,7 +290,10 @@ export const createExternalService = ( } }; - const createComment = async ({ incidentId, comment }: CreateCommentParams): Promise => { + const createComment = async ( + { incidentId, comment }: CreateCommentParams, + connectorMetricsService: ConnectorMetricsService + ): Promise => { try { if (!createCommentUrl || !createCommentJson || !createCommentMethod) { return; @@ -319,6 +332,7 @@ export const createExternalService = ( data: json, configurationUtilities, sslOverrides, + connectorMetricsService, }); throwDescriptiveErrorIfResponseIsNotValid({ diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/types.ts b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/types.ts index 95af6d5e306f2..8328e6a0694a2 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/types.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/types.ts @@ -7,6 +7,7 @@ import { TypeOf } from '@kbn/config-schema'; import { Logger } from '@kbn/core/server'; +import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; import { ExecutorParamsSchema, ExecutorSubActionPushParamsSchema, @@ -44,10 +45,22 @@ export type PushToServiceApiParams = ExecutorSubActionPushParams; // incident service export interface ExternalService { - createComment: (params: CreateCommentParams) => Promise; - createIncident: (params: CreateIncidentParams) => Promise; - getIncident: (id: string) => Promise; - updateIncident: (params: UpdateIncidentParams) => Promise; + createComment: ( + params: CreateCommentParams, + connectorMetricsService: ConnectorMetricsService + ) => Promise; + createIncident: ( + params: CreateIncidentParams, + connectorMetricsService: ConnectorMetricsService + ) => Promise; + getIncident: ( + id: string, + connectorMetricsService: ConnectorMetricsService + ) => Promise; + updateIncident: ( + params: UpdateIncidentParams, + connectorMetricsService: ConnectorMetricsService + ) => Promise; } export interface CreateIncidentParams { incident: Incident; @@ -91,7 +104,10 @@ export interface GetIncidentResponse { } export interface ExternalServiceApi { - pushToService: (args: PushToServiceApiHandlerArgs) => Promise; + pushToService: ( + args: PushToServiceApiHandlerArgs, + connectorMetricsService: ConnectorMetricsService + ) => Promise; } export type CasesWebhookExecutorResultData = ExternalServiceIncidentResponse; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.ts b/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.ts index 07967d5013fa2..0ffaf72d06db0 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.ts @@ -9,6 +9,7 @@ import { ServiceParams, SubActionConnector } from '@kbn/actions-plugin/server'; import type { AxiosError } from 'axios'; import { SubActionRequestParams } from '@kbn/actions-plugin/server/sub_action_framework/types'; +import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; import { isAggregateError, NodeSystemError } from './types'; import type { CrowdstrikeConfig, @@ -96,68 +97,87 @@ export class CrowdstrikeConnector extends SubActionConnector< }); } - public async executeHostActions({ alertIds, ...payload }: CrowdstrikeHostActionsParams) { - return this.crowdstrikeApiRequest({ - url: this.urls.hostAction, - method: 'post', - params: { - action_name: payload.command, - }, - data: { - ids: payload.ids, - ...(payload.actionParameters - ? { - action_parameters: Object.entries(payload.actionParameters).map(([name, value]) => ({ - name, - value, - })), - } - : {}), + public async executeHostActions( + { alertIds, ...payload }: CrowdstrikeHostActionsParams, + connectorMetricsService: ConnectorMetricsService + ) { + return this.crowdstrikeApiRequest( + { + url: this.urls.hostAction, + method: 'post', + params: { + action_name: payload.command, + }, + data: { + ids: payload.ids, + ...(payload.actionParameters + ? { + action_parameters: Object.entries(payload.actionParameters).map( + ([name, value]) => ({ + name, + value, + }) + ), + } + : {}), + }, + paramsSerializer, + responseSchema: CrowdstrikeHostActionsResponseSchema, }, - paramsSerializer, - responseSchema: CrowdstrikeHostActionsResponseSchema, - }); + connectorMetricsService + ); } public async getAgentDetails( - payload: CrowdstrikeGetAgentsParams + payload: CrowdstrikeGetAgentsParams, + connectorMetricsService: ConnectorMetricsService ): Promise { - return this.crowdstrikeApiRequest({ - url: this.urls.agents, - method: 'GET', - params: { - ids: payload.ids, + return this.crowdstrikeApiRequest( + { + url: this.urls.agents, + method: 'GET', + params: { + ids: payload.ids, + }, + paramsSerializer, + responseSchema: RelaxedCrowdstrikeBaseApiResponseSchema, }, - paramsSerializer, - responseSchema: RelaxedCrowdstrikeBaseApiResponseSchema, - }) as Promise; + connectorMetricsService + ) as Promise; } public async getAgentOnlineStatus( - payload: CrowdstrikeGetAgentsParams + payload: CrowdstrikeGetAgentsParams, + connectorMetricsService: ConnectorMetricsService ): Promise { - return this.crowdstrikeApiRequest({ - url: this.urls.agentStatus, - method: 'GET', - params: { - ids: payload.ids, + return this.crowdstrikeApiRequest( + { + url: this.urls.agentStatus, + method: 'GET', + params: { + ids: payload.ids, + }, + paramsSerializer, + responseSchema: RelaxedCrowdstrikeBaseApiResponseSchema, }, - paramsSerializer, - responseSchema: RelaxedCrowdstrikeBaseApiResponseSchema, - }) as Promise; + connectorMetricsService + ) as Promise; } - private async getTokenRequest() { - const response = await this.request({ - url: this.urls.getToken, - method: 'post', - headers: { - accept: 'application/json', - 'Content-Type': 'application/x-www-form-urlencoded', - authorization: 'Basic ' + this.base64encodedToken, + private async getTokenRequest(connectorMetricsService: ConnectorMetricsService) { + const response = await this.request( + { + url: this.urls.getToken, + method: 'post', + headers: { + accept: 'application/json', + 'Content-Type': 'application/x-www-form-urlencoded', + authorization: 'Basic ' + this.base64encodedToken, + }, + responseSchema: CrowdstrikeGetTokenResponseSchema, }, - responseSchema: CrowdstrikeGetTokenResponseSchema, - }); + connectorMetricsService + ); const token = response.data?.access_token; if (token) { // Clear any existing timeout @@ -173,28 +193,33 @@ export class CrowdstrikeConnector extends SubActionConnector< private async crowdstrikeApiRequest( req: SubActionRequestParams, + connectorMetricsService: ConnectorMetricsService, retried?: boolean ): Promise { try { if (!CrowdstrikeConnector.token) { - CrowdstrikeConnector.token = (await this.getTokenRequest()) as string; + CrowdstrikeConnector.token = (await this.getTokenRequest( + connectorMetricsService + )) as string; } - const response = await this.request({ - ...req, - headers: { - ...req.headers, - Authorization: `Bearer ${CrowdstrikeConnector.token}`, + const response = await this.request( + { + ...req, + headers: { + ...req.headers, + Authorization: `Bearer ${CrowdstrikeConnector.token}`, + }, }, - }); + connectorMetricsService + ); return response.data; } catch (error) { if (error.code === 401 && !retried) { CrowdstrikeConnector.token = null; - return this.crowdstrikeApiRequest(req, true); + return this.crowdstrikeApiRequest(req, connectorMetricsService, true); } - throw new CrowdstrikeError(error.message); } } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.ts b/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.ts index 804590c01b284..c2c08ccbe6830 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.ts @@ -7,6 +7,7 @@ import { ServiceParams, SubActionConnector } from '@kbn/actions-plugin/server'; import type { AxiosError } from 'axios'; +import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; import { addSeverityAndEventTypeInBody } from './helpers'; import { D3SecurityRunActionParamsSchema, @@ -57,22 +58,24 @@ export class D3SecurityConnector extends SubActionConnector { - const response = await this.request({ - url: this.url, - method: 'post', - responseSchema: D3SecurityRunActionResponseSchema, - data: addSeverityAndEventTypeInBody( - body ?? '', - severity ?? D3SecuritySeverity.EMPTY, - eventType ?? '' - ), - headers: { d3key: this.token || '' }, - }); + public async runApi( + { body, severity, eventType }: D3SecurityRunActionParams, + connectorMetricsService: ConnectorMetricsService + ): Promise { + const response = await this.request( + { + url: this.url, + method: 'post', + responseSchema: D3SecurityRunActionResponseSchema, + data: addSeverityAndEventTypeInBody( + body ?? '', + severity ?? D3SecuritySeverity.EMPTY, + eventType ?? '' + ), + headers: { d3key: this.token || '' }, + }, + connectorMetricsService + ); return response.data; } } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/email/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/email/index.ts index 1705342e73742..364f0528dd6de 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/email/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/email/index.ts @@ -365,7 +365,12 @@ async function executor( let result; try { - result = await sendEmail(logger, sendEmailOptions, connectorTokenClient); + result = await sendEmail( + logger, + sendEmailOptions, + connectorTokenClient, + execOptions.connectorMetricsService + ); } catch (err) { const message = i18n.translate('xpack.stackConnectors.email.errorSendingErrorMessage', { defaultMessage: 'error sending email', diff --git a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.ts b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.ts index f3ab3bfa22c55..63d79f0df77d3 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.ts @@ -17,7 +17,11 @@ import { getNodeSSLOptions, getSSLSettingsFromConfig, } from '@kbn/actions-plugin/server/lib/get_node_ssl_options'; -import { ConnectorTokenClientContract, ProxySettings } from '@kbn/actions-plugin/server/types'; +import { + ConnectorMetricsService, + ConnectorTokenClientContract, + ProxySettings, +} from '@kbn/actions-plugin/server/types'; import { getOAuthClientCredentialsAccessToken } from '@kbn/actions-plugin/server/lib/get_oauth_client_credentials_access_token'; import { AdditionalEmailServices } from '../../../common'; import { sendEmailGraphApi } from './send_email_graph_api'; @@ -66,7 +70,8 @@ export interface Content { export async function sendEmail( logger: Logger, options: SendEmailOptions, - connectorTokenClient: ConnectorTokenClientContract + connectorTokenClient: ConnectorTokenClientContract, + connectorMetricsService: ConnectorMetricsService ): Promise { const { transport, content } = options; const { message, messageHTML } = content; @@ -74,9 +79,15 @@ export async function sendEmail( const renderedMessage = messageHTML ?? htmlFromMarkdown(logger, message); if (transport.service === AdditionalEmailServices.EXCHANGE) { - return await sendEmailWithExchange(logger, options, renderedMessage, connectorTokenClient); + return await sendEmailWithExchange( + logger, + options, + renderedMessage, + connectorTokenClient, + connectorMetricsService + ); } else { - return await sendEmailWithNodemailer(logger, options, renderedMessage); + return await sendEmailWithNodemailer(logger, options, renderedMessage, connectorMetricsService); } } @@ -85,7 +96,8 @@ export async function sendEmailWithExchange( logger: Logger, options: SendEmailOptions, messageHTML: string, - connectorTokenClient: ConnectorTokenClientContract + connectorTokenClient: ConnectorTokenClientContract, + connectorMetricsService: ConnectorMetricsService ): Promise { const { transport, configurationUtilities, connectorId } = options; const { clientId, clientSecret, tenantId, oauthTokenUrl } = transport; @@ -155,6 +167,7 @@ export async function sendEmailWithExchange( }, logger, configurationUtilities, + connectorMetricsService, axiosInstance ); } @@ -163,7 +176,8 @@ export async function sendEmailWithExchange( async function sendEmailWithNodemailer( logger: Logger, options: SendEmailOptions, - messageHTML: string + messageHTML: string, + connectorMetricsService: ConnectorMetricsService ): Promise { const { transport, routing, content, configurationUtilities, hasAuth } = options; const { service } = transport; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.ts b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.ts index 79d7af05e041e..104fe34bfea57 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.ts @@ -11,18 +11,14 @@ import axios, { AxiosInstance, AxiosResponse } from 'axios'; import { Logger } from '@kbn/core/server'; import { request } from '@kbn/actions-plugin/server/lib/axios_utils'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; +import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; import { SendEmailOptions } from './send_email'; -interface SendEmailGraphApiOptions { - options: SendEmailOptions; - headers: Record; - messageHTML: string; -} - export async function sendEmailGraphApi( sendEmailOptions: SendEmailGraphApiOptions, logger: Logger, configurationUtilities: ActionsConfigurationUtilities, + connectorMetricsService: ConnectorMetricsService, axiosInstance?: AxiosInstance ): Promise { const { options, headers, messageHTML } = sendEmailOptions; @@ -42,6 +38,7 @@ export async function sendEmailGraphApi( headers, configurationUtilities, validateStatus: () => true, + connectorMetricsService, }); if (res.status === 202) { return res.data; @@ -53,6 +50,12 @@ export async function sendEmailGraphApi( throw new Error(errString); } +interface SendEmailGraphApiOptions { + options: SendEmailOptions; + headers: Record; + messageHTML: string; +} + function getMessage(emailOptions: SendEmailOptions, messageHTML: string) { const { routing, content } = emailOptions; const { to, cc, bcc } = routing; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack/index.ts index 98573f98f2aa8..fd76e736e4ef3 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack/index.ts @@ -139,7 +139,8 @@ function validateConnectorTypeConfig( async function slackExecutor( execOptions: SlackConnectorTypeExecutorOptions ): Promise> { - const { actionId, secrets, params, configurationUtilities, logger } = execOptions; + const { actionId, secrets, params, configurationUtilities, logger, connectorMetricsService } = + execOptions; let result: IncomingWebhookResult; const { webhookUrl } = secrets; @@ -163,6 +164,7 @@ async function slackExecutor( const webhook = new IncomingWebhook(webhookUrl, { agent, }); + connectorMetricsService.addRequestBodyBytes(undefined, { text: message }); result = await webhook.send(message); } catch (err) { if (err.original == null || err.original.response == null) { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/api.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/api.ts index 89205d1418209..1014c43605134 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/api.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/api.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; import type { PostMessageSubActionParams, PostBlockkitSubActionParams, @@ -15,26 +16,32 @@ import type { const validChannelIdHandler = async ({ externalService, params: { channelId }, + connectorMetricsService, }: { externalService: SlackApiService; params: ValidChannelIdSubActionParams; -}) => await externalService.validChannelId(channelId ?? ''); + connectorMetricsService: ConnectorMetricsService; +}) => await externalService.validChannelId(channelId ?? '', connectorMetricsService); const postMessageHandler = async ({ externalService, params: { channelIds, channels, text }, + connectorMetricsService, }: { externalService: SlackApiService; params: PostMessageSubActionParams; -}) => await externalService.postMessage({ channelIds, channels, text }); + connectorMetricsService: ConnectorMetricsService; +}) => await externalService.postMessage({ channelIds, channels, text }, connectorMetricsService); const postBlockkitHandler = async ({ externalService, params: { channelIds, channels, text }, + connectorMetricsService, }: { externalService: SlackApiService; params: PostBlockkitSubActionParams; -}) => await externalService.postBlockkit({ channelIds, channels, text }); + connectorMetricsService: ConnectorMetricsService; +}) => await externalService.postBlockkit({ channelIds, channels, text }, connectorMetricsService); export const api = { validChannelId: validChannelIdHandler, diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.ts index 62e377dd623e1..5584dc90469d4 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.ts @@ -102,6 +102,7 @@ const slackApiExecutor = async ({ secrets, configurationUtilities, logger, + connectorMetricsService, }: SlackApiExecutorOptions): Promise> => { const subAction = params.subAction; @@ -130,6 +131,7 @@ const slackApiExecutor = async ({ return await api.validChannelId({ externalService, params: params.subActionParams, + connectorMetricsService, }); } @@ -137,6 +139,7 @@ const slackApiExecutor = async ({ return await api.postMessage({ externalService, params: params.subActionParams, + connectorMetricsService, }); } @@ -144,6 +147,7 @@ const slackApiExecutor = async ({ return await api.postBlockkit({ externalService, params: params.subActionParams, + connectorMetricsService, }); } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.ts index 28e9ee8be4b5d..9a028f274a005 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.ts @@ -13,6 +13,7 @@ import { request } from '@kbn/actions-plugin/server/lib/axios_utils'; import { pipe } from 'fp-ts/lib/pipeable'; import { map, getOrElse } from 'fp-ts/lib/Option'; import type { ActionTypeExecutorResult as ConnectorTypeExecutorResult } from '@kbn/actions-plugin/server/types'; +import { ConnectorMetricsService } from '@kbn/actions-plugin/server/types'; import { SLACK_CONNECTOR_NAME } from './translations'; import type { PostMessageSubActionParams, @@ -128,7 +129,8 @@ export const createExternalService = ( }; const validChannelId = async ( - channelId: string + channelId: string, + connectorMetricsService: ConnectorMetricsService ): Promise> => { try { const validChannel = (): Promise> => { @@ -139,6 +141,7 @@ export const createExternalService = ( method: 'get', headers, url: `${SLACK_URL}conversations.info?channel=${channelId}`, + connectorMetricsService, }); }; if (channelId.length === 0) { @@ -191,11 +194,10 @@ export const createExternalService = ( return channelToUse; }; - const postMessage = async ({ - channels, - channelIds = [], - text, - }: PostMessageSubActionParams): Promise> => { + const postMessage = async ( + { channels, channelIds = [], text }: PostMessageSubActionParams, + connectorMetricsService: ConnectorMetricsService + ): Promise> => { try { const channelToUse = getChannelToUse({ channels, channelIds }); @@ -207,6 +209,7 @@ export const createExternalService = ( data: { channel: channelToUse, text }, headers, configurationUtilities, + connectorMetricsService, }); return buildSlackExecutorSuccessResponse({ slackApiResponseData: result.data }); @@ -215,11 +218,10 @@ export const createExternalService = ( } }; - const postBlockkit = async ({ - channels, - channelIds = [], - text, - }: PostBlockkitSubActionParams): Promise> => { + const postBlockkit = async ( + { channels, channelIds = [], text }: PostBlockkitSubActionParams, + connectorMetricsService: ConnectorMetricsService + ): Promise> => { try { const channelToUse = getChannelToUse({ channels, channelIds }); const blockJson = JSON.parse(text); @@ -232,6 +234,7 @@ export const createExternalService = ( data: { channel: channelToUse, blocks: blockJson.blocks }, headers, configurationUtilities, + connectorMetricsService, }); return buildSlackExecutorSuccessResponse({ slackApiResponseData: result.data }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.ts index 78f02d24b9b87..d97f74e14b99e 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.ts @@ -128,7 +128,8 @@ function validateConnectorTypeConfig( export async function executor( execOptions: WebhookConnectorTypeExecutorOptions ): Promise> { - const { actionId, config, params, configurationUtilities, logger } = execOptions; + const { actionId, config, params, configurationUtilities, logger, connectorMetricsService } = + execOptions; const { method, url, headers = {}, hasAuth, authType, ca, verificationMode } = config; const { body: data } = params; @@ -159,6 +160,7 @@ export async function executor( data, configurationUtilities, sslOverrides, + connectorMetricsService, }) ); From 1981342f9126f966c5a302922f9fdf28e62e6422 Mon Sep 17 00:00:00 2001 From: Ersin Erdal Date: Fri, 5 Jul 2024 12:57:50 +0200 Subject: [PATCH 02/25] WIP --- .../create_unsecured_execute_function.ts | 5 +- .../actions/server/lib/action_executor.ts | 2 + .../actions/server/lib/axios_utils.test.ts | 67 +- .../plugins/actions/server/lib/axios_utils.ts | 4 +- .../lib/connector_metrics_service.test.ts | 57 ++ .../server/lib/connector_metrics_service.ts | 9 +- .../server/sub_action_framework/case.test.ts | 56 +- .../server/sub_action_framework/case.ts | 123 ++-- .../sub_action_framework/executor.test.ts | 54 ++ .../server/sub_action_framework/mocks.ts | 63 +- .../sub_action_connector.test.ts | 75 +- .../sub_action_connector.ts | 3 +- .../unsecured_actions_client.ts | 2 - .../common/slack_api/types.ts | 26 +- .../connector_types/bedrock/bedrock.test.ts | 667 ++++++++++-------- .../connector_types/cases_webhook/api.ts | 40 +- .../connector_types/cases_webhook/index.ts | 18 +- .../cases_webhook/service.test.ts | 72 +- .../connector_types/cases_webhook/service.ts | 32 +- .../connector_types/cases_webhook/types.ts | 26 +- .../crowdstrike/crowdstrike.test.ts | 70 +- .../d3security/d3security.test.ts | 29 +- .../connector_types/email/index.test.ts | 3 + .../server/connector_types/email/index.ts | 14 +- .../connector_types/email/send_email.test.ts | 131 +++- .../connector_types/email/send_email.ts | 1 + .../email/send_email_graph_api.test.ts | 19 +- .../connector_types/gemini/gemini.test.ts | 239 ++++--- .../server/connector_types/gemini/gemini.ts | 109 +-- .../server/connector_types/jira/index.ts | 13 +- .../connector_types/jira/service.test.ts | 36 +- .../server/connector_types/jira/service.ts | 14 +- .../lib/servicenow/create_service_wrapper.ts | 8 +- .../connector_types/lib/servicenow/service.ts | 9 + .../connector_types/lib/servicenow/types.ts | 4 +- .../connector_types/openai/openai.test.ts | 661 ++++++++++------- .../server/connector_types/openai/openai.ts | 110 +-- .../opsgenie/connector.test.ts | 21 +- .../connector_types/opsgenie/connector.ts | 45 +- .../connector_types/pagerduty/index.test.ts | 16 +- .../server/connector_types/pagerduty/index.ts | 15 +- .../pagerduty/post_pagerduty.ts | 6 +- .../resilient/resilient.test.ts | 90 ++- .../connector_types/resilient/resilient.ts | 167 +++-- .../sentinelone/sentinelone.test.ts | 23 +- .../sentinelone/sentinelone.ts | 227 +++--- .../connector_types/servicenow_itom/index.ts | 11 +- .../servicenow_itom/service.test.ts | 6 + .../servicenow_itom/service.ts | 3 + .../connector_types/servicenow_itsm/index.ts | 13 +- .../servicenow_itsm/service.test.ts | 36 + .../connector_types/servicenow_sir/index.ts | 13 +- .../servicenow_sir/service.test.ts | 6 + .../connector_types/servicenow_sir/service.ts | 3 + .../connector_types/slack/index.test.ts | 10 + .../server/connector_types/slack_api/api.ts | 13 +- .../server/connector_types/slack_api/index.ts | 6 +- .../connector_types/slack_api/service.test.ts | 16 +- .../connector_types/slack_api/service.ts | 24 +- .../server/connector_types/swimlane/index.ts | 13 +- .../connector_types/swimlane/service.test.ts | 21 +- .../connector_types/swimlane/service.ts | 7 +- .../connector_types/teams/index.test.ts | 16 +- .../server/connector_types/teams/index.ts | 4 +- .../connector_types/tines/tines.test.ts | 49 +- .../server/connector_types/tines/tines.ts | 57 +- .../server/connector_types/torq/index.test.ts | 15 +- .../server/connector_types/torq/index.ts | 2 + .../connector_types/webhook/index.test.ts | 23 +- .../connector_types/xmatters/index.test.ts | 7 +- .../server/connector_types/xmatters/index.ts | 12 +- .../connector_types/xmatters/post_xmatters.ts | 9 +- 72 files changed, 2500 insertions(+), 1376 deletions(-) create mode 100644 x-pack/plugins/actions/server/lib/connector_metrics_service.test.ts diff --git a/x-pack/plugins/actions/server/create_unsecured_execute_function.ts b/x-pack/plugins/actions/server/create_unsecured_execute_function.ts index 71ec6d4e09d00..c37ca980867dd 100644 --- a/x-pack/plugins/actions/server/create_unsecured_execute_function.ts +++ b/x-pack/plugins/actions/server/create_unsecured_execute_function.ts @@ -27,10 +27,7 @@ interface CreateBulkUnsecuredExecuteFunctionOptions { } export interface ExecuteOptions - extends Pick< - ActionExecutorOptions, - 'params' | 'source' | 'relatedSavedObjects' | 'connectorMetricsService' - > { + extends Pick { id: string; } diff --git a/x-pack/plugins/actions/server/lib/action_executor.ts b/x-pack/plugins/actions/server/lib/action_executor.ts index 838a076b1fc16..bcd306a4f8aef 100644 --- a/x-pack/plugins/actions/server/lib/action_executor.ts +++ b/x-pack/plugins/actions/server/lib/action_executor.ts @@ -533,6 +533,8 @@ export class ActionExecutor { status: 'ok', }; + // console.log('body bytes ==> ', connectorMetricsService.getRequestBodyByte()); + event.event = event.event || {}; const { error, ...resultWithoutError } = result; diff --git a/x-pack/plugins/actions/server/lib/axios_utils.test.ts b/x-pack/plugins/actions/server/lib/axios_utils.test.ts index c5e23f6cd3db3..4b9105450154f 100644 --- a/x-pack/plugins/actions/server/lib/axios_utils.test.ts +++ b/x-pack/plugins/actions/server/lib/axios_utils.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import axios, { AxiosInstance } from 'axios'; +import axios, { AxiosError, AxiosInstance } from 'axios'; import { Agent as HttpsAgent } from 'https'; import HttpProxyAgent from 'http-proxy-agent'; import { HttpsProxyAgent } from 'https-proxy-agent'; @@ -21,6 +21,7 @@ import { import { loggingSystemMock } from '@kbn/core/server/mocks'; import { actionsConfigMock } from '../actions_config.mock'; import { getCustomAgents } from './get_custom_agents'; +import { ConnectorMetricsService } from './connector_metrics_service'; const TestUrl = 'https://elastic.co/foo/bar/baz'; @@ -79,6 +80,70 @@ describe('request', () => { }); }); + test('adds request body bytes from request header on a successful request when connectorMetricsService is provided', async () => { + const contentLength = 12; + axiosMock.mockImplementation(() => ({ + status: 200, + headers: { 'content-type': 'application/json' }, + data: { incidentId: '123' }, + request: { + headers: { 'Content-Length': contentLength }, + }, + })); + const connectorMetricsService = new ConnectorMetricsService(); + await request({ + axios, + url: '/test', + logger, + data: { test: 12345 }, + configurationUtilities, + connectorMetricsService, + }); + + expect(connectorMetricsService.getRequestBodyByte()).toBe(contentLength); + }); + + test('adds request body bytes from request header on a failed', async () => { + const contentLength = 12; + axiosMock.mockImplementation( + () => + new AxiosError('failed', '500', undefined, { + headers: { 'Content-Length': contentLength }, + }) + ); + const connectorMetricsService = new ConnectorMetricsService(); + + try { + await request({ + axios, + url: '/test', + logger, + configurationUtilities, + connectorMetricsService, + }); + } catch (e) { + expect(connectorMetricsService.getRequestBodyByte()).toBe(contentLength); + } + }); + + test('adds request body bytes from data when request header does not exist', async () => { + const connectorMetricsService = new ConnectorMetricsService(); + const data = { test: 12345 }; + + await request({ + axios, + url: '/test', + logger, + data, + configurationUtilities, + connectorMetricsService, + }); + + expect(connectorMetricsService.getRequestBodyByte()).toBe( + Buffer.byteLength(JSON.stringify(data), 'utf8') + ); + }); + test('it have been called with proper proxy agent for a valid url', async () => { configurationUtilities.getProxySettings.mockReturnValue({ proxySSLSettings: { diff --git a/x-pack/plugins/actions/server/lib/axios_utils.ts b/x-pack/plugins/actions/server/lib/axios_utils.ts index 4ec72e7f6c064..df160bd2970b0 100644 --- a/x-pack/plugins/actions/server/lib/axios_utils.ts +++ b/x-pack/plugins/actions/server/lib/axios_utils.ts @@ -42,7 +42,7 @@ export const request = async ({ headers?: Record; timeout?: number; sslOverrides?: SSLSettings; - connectorMetricsService?: ConnectorMetricsService; + connectorMetricsService?: ConnectorMetricsService; // TODO make optional } & AxiosRequestConfig): Promise => { if (!isEmpty(axios?.defaults?.baseURL ?? '')) { throw new Error( @@ -106,7 +106,7 @@ export const patch = async ({ data: T; logger: Logger; configurationUtilities: ActionsConfigurationUtilities; - connectorMetricsService: ConnectorMetricsService; + connectorMetricsService?: ConnectorMetricsService; }): Promise => { return request({ axios, diff --git a/x-pack/plugins/actions/server/lib/connector_metrics_service.test.ts b/x-pack/plugins/actions/server/lib/connector_metrics_service.test.ts new file mode 100644 index 0000000000000..a75a5d9c0c2cc --- /dev/null +++ b/x-pack/plugins/actions/server/lib/connector_metrics_service.test.ts @@ -0,0 +1,57 @@ +/* + * 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 { ConnectorMetricsService } from '../types'; +import { AxiosHeaders, AxiosResponse } from 'axios'; + +describe('ConnectorMetricsService', () => { + test('it collects requestBodyBytes from response.request.headers', async () => { + const connectorMetricsService = new ConnectorMetricsService(); + const data = { test: 'foo' }; + const contentLength = Buffer.byteLength(JSON.stringify(data), 'utf8'); + + const axiosResponse: AxiosResponse = { + data, + status: 200, + statusText: 'OK', + headers: {}, + config: { headers: new AxiosHeaders() }, + request: { + headers: { 'Content-Length': contentLength }, + }, + }; + + connectorMetricsService.addRequestBodyBytes(axiosResponse, data); + + expect(connectorMetricsService.getRequestBodyByte()).toBe(contentLength); + + connectorMetricsService.addRequestBodyBytes(axiosResponse, data); + + expect(connectorMetricsService.getRequestBodyByte()).toBe(contentLength + contentLength); + }); + test('it collects requestBodyBytes from data when response.request.headers is missing', async () => { + const connectorMetricsService = new ConnectorMetricsService(); + const data = { test: 'foo' }; + const contentLength = Buffer.byteLength(JSON.stringify(data), 'utf8'); + + const axiosResponse: AxiosResponse = { + data, + status: 200, + statusText: 'OK', + headers: {}, + config: { headers: new AxiosHeaders() }, + }; + + connectorMetricsService.addRequestBodyBytes(axiosResponse, data); + + expect(connectorMetricsService.getRequestBodyByte()).toBe(contentLength); + + connectorMetricsService.addRequestBodyBytes(axiosResponse, data); + + expect(connectorMetricsService.getRequestBodyByte()).toBe(contentLength + contentLength); + }); +}); diff --git a/x-pack/plugins/actions/server/lib/connector_metrics_service.ts b/x-pack/plugins/actions/server/lib/connector_metrics_service.ts index 678d72e6413b0..7e62c3f941d18 100644 --- a/x-pack/plugins/actions/server/lib/connector_metrics_service.ts +++ b/x-pack/plugins/actions/server/lib/connector_metrics_service.ts @@ -17,15 +17,12 @@ export class ConnectorMetricsService { }; public addRequestBodyBytes(result?: AxiosError | AxiosResponse, body: string | object = '') { - this.metrics.requestBodyBytes = this.extractRequestBodyBytes(result, body); + const sBody = typeof body === 'string' ? body : JSON.stringify(body); + const bytes = result?.request?.headers?.['Content-Length'] || Buffer.byteLength(sBody, 'utf8'); + this.metrics.requestBodyBytes = this.metrics.requestBodyBytes + bytes; } public getRequestBodyByte() { return this.metrics.requestBodyBytes; } - - private extractRequestBodyBytes(result?: AxiosError | AxiosResponse, body: string | object = '') { - const stringBody = typeof body === 'string' ? body : JSON.stringify(body); - return result?.request?.headers?.['Content-Length'] || Buffer.byteLength(stringBody, 'utf8'); - } } diff --git a/x-pack/plugins/actions/server/sub_action_framework/case.test.ts b/x-pack/plugins/actions/server/sub_action_framework/case.test.ts index 91e2df1972de8..387cc77af3380 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/case.test.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/case.test.ts @@ -12,6 +12,7 @@ import { actionsConfigMock } from '../actions_config.mock'; import { actionsMock } from '../mocks'; import { TestCaseConnector } from './mocks'; import { ActionsConfigurationUtilities } from '../actions_config'; +import { ConnectorMetricsService } from '../lib'; describe('CaseConnector', () => { let logger: MockedLogger; @@ -26,6 +27,7 @@ describe('CaseConnector', () => { check: schema.nullable(schema.number()), }), }; + const getConnectorMetricsService = () => new ConnectorMetricsService(); const incidentSchemaMock = { name: 'Test', category: null, foo: [false], bar: { check: 1 } }; const pushToServiceParams = { @@ -191,7 +193,7 @@ describe('CaseConnector', () => { describe('pushToService', () => { it('should create an incident if externalId is null', async () => { - const res = await service.pushToService(pushToServiceParams); + const res = await service.pushToService(pushToServiceParams, getConnectorMetricsService()); expect(res).toEqual({ id: 'create-incident', title: 'Test incident', @@ -201,10 +203,13 @@ describe('CaseConnector', () => { }); it('should update an incident if externalId is not null', async () => { - const res = await service.pushToService({ - incident: { ...pushToServiceParams.incident, externalId: 'test-id' }, - comments: [], - }); + const res = await service.pushToService( + { + incident: { ...pushToServiceParams.incident, externalId: 'test-id' }, + comments: [], + }, + getConnectorMetricsService() + ); expect(res).toEqual({ id: 'update-incident', @@ -215,13 +220,16 @@ describe('CaseConnector', () => { }); it('should add comments', async () => { - const res = await service.pushToService({ - ...pushToServiceParams, - comments: [ - { comment: 'comment-1', commentId: 'comment-id-1' }, - { comment: 'comment-2', commentId: 'comment-id-2' }, - ], - }); + const res = await service.pushToService( + { + ...pushToServiceParams, + comments: [ + { comment: 'comment-1', commentId: 'comment-id-1' }, + { comment: 'comment-2', commentId: 'comment-id-2' }, + ], + }, + getConnectorMetricsService() + ); expect(res).toEqual({ id: 'create-incident', @@ -242,11 +250,14 @@ describe('CaseConnector', () => { }); it.each([[undefined], [null]])('should throw if externalId is %p', async (comments) => { - const res = await service.pushToService({ - ...pushToServiceParams, - // @ts-expect-error - comments, - }); + const res = await service.pushToService( + { + ...pushToServiceParams, + // @ts-expect-error + comments, + }, + getConnectorMetricsService() + ); expect(res).toEqual({ id: 'create-incident', @@ -257,10 +268,13 @@ describe('CaseConnector', () => { }); it('should not add comments if comments are an empty array', async () => { - const res = await service.pushToService({ - ...pushToServiceParams, - comments: [], - }); + const res = await service.pushToService( + { + ...pushToServiceParams, + comments: [], + }, + getConnectorMetricsService() + ); expect(res).toEqual({ id: 'create-incident', diff --git a/x-pack/plugins/actions/server/sub_action_framework/case.ts b/x-pack/plugins/actions/server/sub_action_framework/case.ts index 24a0512378912..73ddbd582ea7f 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/case.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/case.ts @@ -9,22 +9,38 @@ import { schema, Type } from '@kbn/config-schema'; import { ExternalServiceIncidentResponse, PushToServiceResponse } from './types'; import { SubActionConnector } from './sub_action_connector'; import { ServiceParams } from './types'; +import { ConnectorMetricsService } from '../lib'; export interface CaseConnectorInterface { - addComment: ({ incidentId, comment }: { incidentId: string; comment: string }) => Promise; - createIncident: (incident: Incident) => Promise; - updateIncident: ({ - incidentId, - incident, - }: { - incidentId: string; - incident: Incident; - }) => Promise; - getIncident: ({ id }: { id: string }) => Promise; - pushToService: (params: { - incident: { externalId: string | null } & Incident; - comments: Array<{ commentId: string; comment: string }>; - }) => Promise; + addComment: ( + { incidentId, comment }: { incidentId: string; comment: string }, + connectorMetricsService: ConnectorMetricsService + ) => Promise; + createIncident: ( + incident: Incident, + connectorMetricsService: ConnectorMetricsService + ) => Promise; + updateIncident: ( + { + incidentId, + incident, + }: { + incidentId: string; + incident: Incident; + }, + connectorMetricsService: ConnectorMetricsService + ) => Promise; + getIncident: ( + { id }: { id: string }, + connectorMetricsService: ConnectorMetricsService + ) => Promise; + pushToService: ( + params: { + incident: { externalId: string | null } & Incident; + comments: Array<{ commentId: string; comment: string }>; + }, + connectorMetricsService: ConnectorMetricsService + ) => Promise; } export abstract class CaseConnector @@ -56,50 +72,71 @@ export abstract class CaseConnector; + public abstract addComment( + { + incidentId, + comment, + }: { + incidentId: string; + comment: string; + }, + connectorMetricsService: ConnectorMetricsService + ): Promise; - public abstract createIncident(incident: Incident): Promise; - public abstract updateIncident({ - incidentId, - incident, - }: { - incidentId: string; - incident: Incident; - }): Promise; - public abstract getIncident({ id }: { id: string }): Promise; + public abstract createIncident( + incident: Incident, + connectorMetricsService: ConnectorMetricsService + ): Promise; + public abstract updateIncident( + { + incidentId, + incident, + }: { + incidentId: string; + incident: Incident; + }, + connectorMetricsService: ConnectorMetricsService + ): Promise; + public abstract getIncident( + { id }: { id: string }, + connectorMetricsService: ConnectorMetricsService + ): Promise; - public async pushToService(params: { - incident: { externalId: string | null } & Incident; - comments: Array<{ commentId: string; comment: string }>; - }) { + public async pushToService( + params: { + incident: { externalId: string | null } & Incident; + comments: Array<{ commentId: string; comment: string }>; + }, + connectorMetricsService: ConnectorMetricsService + ) { const { incident, comments } = params; const { externalId, ...rest } = incident; let res: PushToServiceResponse; if (externalId != null) { - res = await this.updateIncident({ - incidentId: externalId, - incident: rest as Incident, - }); + res = await this.updateIncident( + { + incidentId: externalId, + incident: rest as Incident, + }, + connectorMetricsService + ); } else { - res = await this.createIncident(rest as Incident); + res = await this.createIncident(rest as Incident, connectorMetricsService); } if (comments && Array.isArray(comments) && comments.length > 0) { res.comments = []; for (const currentComment of comments) { - await this.addComment({ - incidentId: res.id, - comment: currentComment.comment, - }); + await this.addComment( + { + incidentId: res.id, + comment: currentComment.comment, + }, + connectorMetricsService + ); res.comments = [ ...(res.comments ?? []), diff --git a/x-pack/plugins/actions/server/sub_action_framework/executor.test.ts b/x-pack/plugins/actions/server/sub_action_framework/executor.test.ts index 35b1fa43c6ce3..4987194b55569 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/executor.test.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/executor.test.ts @@ -21,6 +21,7 @@ import { } from './mocks'; import { IService, ServiceParams } from './types'; import { getErrorSource, TaskErrorSource } from '@kbn/task-manager-plugin/server/task_running'; +import { ConnectorMetricsService } from '../lib'; describe('Executor', () => { const actionId = 'test-action-id'; @@ -30,6 +31,7 @@ describe('Executor', () => { let logger: MockedLogger; let services: ReturnType; let mockedActionsConfig: jest.Mocked; + const getConnectorMetricsService = () => new ConnectorMetricsService(); const createExecutor = (Service: IService) => { const connector = { @@ -68,6 +70,7 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, + connectorMetricsService: getConnectorMetricsService(), }); expect(res).toEqual({ @@ -90,6 +93,7 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, + connectorMetricsService: getConnectorMetricsService(), }); expect(res).toEqual({ @@ -112,6 +116,7 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, + connectorMetricsService: getConnectorMetricsService(), }); expect(res).toEqual({ @@ -132,6 +137,7 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, + connectorMetricsService: getConnectorMetricsService(), }); expect(res).toEqual({ @@ -153,6 +159,7 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, + connectorMetricsService: getConnectorMetricsService(), }) ).rejects.toThrowError('You should register at least one subAction for your connector type'); }); @@ -169,6 +176,7 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, + connectorMetricsService: getConnectorMetricsService(), }) ).rejects.toThrowError( 'Sub action "not-exist" is not registered. Connector id: test-action-id. Connector name: Test. Connector type: .test' @@ -187,6 +195,7 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, + connectorMetricsService: getConnectorMetricsService(), }); } catch (e) { expect(getErrorSource(e)).toBe(TaskErrorSource.USER); @@ -208,6 +217,7 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, + connectorMetricsService: getConnectorMetricsService(), }) ).rejects.toThrowError( 'Method "not-exist" does not exists in service. Sub action: "testUrl". Connector id: test-action-id. Connector name: Test. Connector type: .test' @@ -226,6 +236,7 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, + connectorMetricsService: getConnectorMetricsService(), }) ).rejects.toThrowError( 'Method "notAFunction" must be a function. Connector id: test-action-id. Connector name: Test. Connector type: .test' @@ -244,9 +255,52 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, + connectorMetricsService: getConnectorMetricsService(), }) ).rejects.toThrowError( 'Request validation failed (Error: [id]: expected value of type [string] but got [undefined])' ); }); + + it('Passes connectorMetricsService to the subAction method as a second param', async () => { + let echoSpy; + + const subActionParams = { id: 'test-id' }; + const connector = { + id: '.test', + name: 'Test', + minimumLicenseRequired: 'basic' as const, + supportedFeatureIds: ['alerting'], + schema: { + config: TestConfigSchema, + secrets: TestSecretsSchema, + }, + getService: (serviceParams: ServiceParams) => { + const service = new TestExecutor(serviceParams); + echoSpy = jest.spyOn(service, 'echo').mockResolvedValue(subActionParams); + return service; + }, + }; + + const connectorMetricsService = new ConnectorMetricsService(); + + const executor = buildExecutor({ + configurationUtilities: mockedActionsConfig, + logger, + connector, + }); + + executor({ + actionId, + params: { subAction: 'echo', subActionParams }, + config, + secrets, + services, + configurationUtilities: mockedActionsConfig, + logger, + connectorMetricsService, + }); + + expect(echoSpy).toHaveBeenCalledWith(subActionParams, connectorMetricsService); + }); }); diff --git a/x-pack/plugins/actions/server/sub_action_framework/mocks.ts b/x-pack/plugins/actions/server/sub_action_framework/mocks.ts index f6c8e86dd5af3..adc026cf7f777 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/mocks.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/mocks.ts @@ -8,6 +8,7 @@ import { schema, Type, TypeOf } from '@kbn/config-schema'; import { AxiosError } from 'axios'; +import { ConnectorMetricsService } from '../lib'; import { SubActionConnector } from './sub_action_connector'; import { CaseConnector } from './case'; import { ExternalServiceIncidentResponse, ServiceParams } from './types'; @@ -57,36 +58,54 @@ export class TestSubActionConnector extends SubActionConnector | null }) { - const res = await this.request({ - url, - data, - headers: { 'X-Test-Header': 'test' }, - responseSchema: schema.object({ status: schema.string() }), - }); + public async testUrl( + { url, data = {} }: { url: string; data?: Record | null }, + connectorMetricsService: ConnectorMetricsService + ) { + const res = await this.request( + { + url, + data, + headers: { 'X-Test-Header': 'test' }, + responseSchema: schema.object({ status: schema.string() }), + }, + connectorMetricsService + ); return res; } - public async testData({ data }: { data: Record }) { - const res = await this.request({ - url: 'https://example.com', - data: this.removeNullOrUndefinedFields(data), - headers: { 'X-Test-Header': 'test' }, - responseSchema: schema.object({ status: schema.string() }), - }); + public async testData( + { data }: { data: Record }, + connectorMetricsService: ConnectorMetricsService + ) { + const res = await this.request( + { + url: 'https://example.com', + data: this.removeNullOrUndefinedFields(data), + headers: { 'X-Test-Header': 'test' }, + responseSchema: schema.object({ status: schema.string() }), + }, + connectorMetricsService + ); return res; } - public async testAuth({ headers }: { headers?: Record } = {}) { - const res = await this.request({ - url: 'https://example.com', - data: {}, - auth: { username: 'username', password: 'password' }, - headers: { 'X-Test-Header': 'test', ...headers }, - responseSchema: schema.object({ status: schema.string() }), - }); + public async testAuth( + { headers }: { headers?: Record } = {}, + connectorMetricsService: ConnectorMetricsService + ) { + const res = await this.request( + { + url: 'https://example.com', + data: {}, + auth: { username: 'username', password: 'password' }, + headers: { 'X-Test-Header': 'test', ...headers }, + responseSchema: schema.object({ status: schema.string() }), + }, + connectorMetricsService + ); return res; } diff --git a/x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.test.ts b/x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.test.ts index 1358684d86093..7341986655200 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.test.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.test.ts @@ -13,6 +13,7 @@ import { actionsMock } from '../mocks'; import { TestSubActionConnector } from './mocks'; import { ActionsConfigurationUtilities } from '../actions_config'; import * as utils from '../lib/axios_utils'; +import { ConnectorMetricsService } from '../lib'; jest.mock('axios'); @@ -36,6 +37,7 @@ const createAxiosError = (): AxiosError => { return error; }; +const getConnectorMetricsService = () => new ConnectorMetricsService(); describe('SubActionConnector', () => { const axiosInstanceMock = jest.fn(); @@ -85,34 +87,37 @@ describe('SubActionConnector', () => { describe('URL validation', () => { it('removes double slashes correctly', async () => { - await service.testUrl({ url: 'https://example.com//api///test-endpoint' }); + await service.testUrl( + { url: 'https://example.com//api///test-endpoint' }, + getConnectorMetricsService() + ); expect(requestMock.mock.calls[0][0].url).toBe('https://example.com/api/test-endpoint'); }); it('removes the ending slash correctly', async () => { - await service.testUrl({ url: 'https://example.com/' }); + await service.testUrl({ url: 'https://example.com/' }, getConnectorMetricsService()); expect(requestMock.mock.calls[0][0].url).toBe('https://example.com'); }); it('throws an error if the url is invalid', async () => { expect.assertions(1); - await expect(async () => service.testUrl({ url: 'invalid-url' })).rejects.toThrow( - 'URL Error: Invalid URL: invalid-url' - ); + await expect(async () => + service.testUrl({ url: 'invalid-url' }, getConnectorMetricsService()) + ).rejects.toThrow('URL Error: Invalid URL: invalid-url'); }); it('throws an error if the url starts with backslashes', async () => { expect.assertions(1); - await expect(async () => service.testUrl({ url: '//example.com/foo' })).rejects.toThrow( - 'URL Error: Invalid URL: //example.com/foo' - ); + await expect(async () => + service.testUrl({ url: '//example.com/foo' }, getConnectorMetricsService()) + ).rejects.toThrow('URL Error: Invalid URL: //example.com/foo'); }); it('throws an error if the protocol is not supported', async () => { expect.assertions(1); - await expect(async () => service.testUrl({ url: 'ftp://example.com' })).rejects.toThrow( - 'URL Error: Invalid protocol' - ); + await expect(async () => + service.testUrl({ url: 'ftp://example.com' }, getConnectorMetricsService()) + ).rejects.toThrow('URL Error: Invalid protocol'); }); it('throws if the host is the URI is not allowed', async () => { @@ -122,15 +127,18 @@ describe('SubActionConnector', () => { throw new Error('URI is not allowed'); }); - await expect(async () => service.testUrl({ url: 'https://example.com' })).rejects.toThrow( - 'error configuring connector action: URI is not allowed' - ); + await expect(async () => + service.testUrl({ url: 'https://example.com' }, getConnectorMetricsService()) + ).rejects.toThrow('error configuring connector action: URI is not allowed'); }); }); describe('Data', () => { it('sets data to an empty object if the data are null', async () => { - await service.testUrl({ url: 'https://example.com', data: null }); + await service.testUrl( + { url: 'https://example.com', data: null }, + getConnectorMetricsService() + ); expect(requestMock).toHaveBeenCalledTimes(1); const { data } = requestMock.mock.calls[0][0]; @@ -138,7 +146,10 @@ describe('SubActionConnector', () => { }); it('pass data to axios correctly if not null', async () => { - await service.testUrl({ url: 'https://example.com', data: { foo: 'foo' } }); + await service.testUrl( + { url: 'https://example.com', data: { foo: 'foo' } }, + getConnectorMetricsService() + ); expect(requestMock).toHaveBeenCalledTimes(1); const { data } = requestMock.mock.calls[0][0]; @@ -146,7 +157,10 @@ describe('SubActionConnector', () => { }); it('removeNullOrUndefinedFields: removes null values and undefined values correctly', async () => { - await service.testData({ data: { foo: 'foo', bar: null, baz: undefined } }); + await service.testData( + { data: { foo: 'foo', bar: null, baz: undefined } }, + getConnectorMetricsService() + ); expect(requestMock).toHaveBeenCalledTimes(1); const { data } = requestMock.mock.calls[0][0]; @@ -167,7 +181,8 @@ describe('SubActionConnector', () => { describe('Fetching', () => { it('fetch correctly', async () => { - const res = await service.testUrl({ url: 'https://example.com' }); + const connectorMetricsService = getConnectorMetricsService(); + const res = await service.testUrl({ url: 'https://example.com' }, connectorMetricsService); expect(requestMock).toHaveBeenCalledTimes(1); expect(requestMock).toBeCalledWith({ @@ -181,6 +196,7 @@ describe('SubActionConnector', () => { 'X-Test-Header': 'test', }, url: 'https://example.com', + connectorMetricsService, }); expect(logger.debug).toBeCalledWith( @@ -192,7 +208,9 @@ describe('SubActionConnector', () => { it('validates the response correctly', async () => { requestMock.mockReturnValue({ data: { invalidField: 'test' } }); - await expect(async () => service.testUrl({ url: 'https://example.com' })).rejects.toThrow( + await expect(async () => + service.testUrl({ url: 'https://example.com' }, getConnectorMetricsService()) + ).rejects.toThrow( 'Response validation failed (Error: [status]: expected value of type [string] but got [undefined])' ); }); @@ -202,9 +220,9 @@ describe('SubActionConnector', () => { throw createAxiosError(); }); - await expect(async () => service.testUrl({ url: 'https://example.com' })).rejects.toThrow( - 'Message: An error occurred. Code: 500' - ); + await expect(async () => + service.testUrl({ url: 'https://example.com' }, getConnectorMetricsService()) + ).rejects.toThrow('Message: An error occurred. Code: 500'); expect(logger.debug).toHaveBeenLastCalledWith( 'Request to external service failed. Connector Id: test-id. Connector type: .test. Method: get. URL: https://example.com' @@ -212,7 +230,9 @@ describe('SubActionConnector', () => { }); it('converts auth axios property to a basic auth header if provided', async () => { - await service.testAuth(); + const connectorMetricsService = getConnectorMetricsService(); + + await service.testAuth(undefined, connectorMetricsService); expect(requestMock).toHaveBeenCalledTimes(1); expect(requestMock).toBeCalledWith({ @@ -227,11 +247,17 @@ describe('SubActionConnector', () => { Authorization: `Basic ${Buffer.from('username:password').toString('base64')}`, }, url: 'https://example.com', + connectorMetricsService, }); }); it('does not override an authorization header if provided', async () => { - await service.testAuth({ headers: { Authorization: 'Bearer my_token' } }); + const connectorMetricsService = getConnectorMetricsService(); + + await service.testAuth( + { headers: { Authorization: 'Bearer my_token' } }, + connectorMetricsService + ); expect(requestMock).toHaveBeenCalledTimes(1); expect(requestMock).toBeCalledWith({ @@ -246,6 +272,7 @@ describe('SubActionConnector', () => { Authorization: 'Bearer my_token', }, url: 'https://example.com', + connectorMetricsService, }); }); }); diff --git a/x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.ts b/x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.ts index 92834c6cd8485..d0d00b9d9be23 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.ts @@ -153,7 +153,6 @@ export abstract class SubActionConnector { ); const { auth, ...restConfig } = config; - const normalizedData = this.normalizeData(data); const res = await request({ ...restConfig, @@ -161,7 +160,7 @@ export abstract class SubActionConnector { url: normalizedURL, logger: this.logger, method, - data: normalizedData, + data: this.normalizeData(data), configurationUtilities: this.configurationUtilities, headers: this.getHeaders(auth, headers as AxiosHeaders), timeout, diff --git a/x-pack/plugins/actions/server/unsecured_actions_client/unsecured_actions_client.ts b/x-pack/plugins/actions/server/unsecured_actions_client/unsecured_actions_client.ts index 8394d885158b8..066c477947e2c 100644 --- a/x-pack/plugins/actions/server/unsecured_actions_client/unsecured_actions_client.ts +++ b/x-pack/plugins/actions/server/unsecured_actions_client/unsecured_actions_client.ts @@ -67,7 +67,6 @@ export class UnsecuredActionsClient { params, relatedSavedObjects, spaceId, - connectorMetricsService, }: UnsecuredExecuteOptions) { // Check that requesterId is allowed if (!ALLOWED_REQUESTER_IDS.includes(requesterId)) { @@ -91,7 +90,6 @@ export class UnsecuredActionsClient { relatedSavedObjects, spaceId, ...source, - connectorMetricsService, }); } diff --git a/x-pack/plugins/stack_connectors/common/slack_api/types.ts b/x-pack/plugins/stack_connectors/common/slack_api/types.ts index 16a240778307c..a19aa5c2159fa 100644 --- a/x-pack/plugins/stack_connectors/common/slack_api/types.ts +++ b/x-pack/plugins/stack_connectors/common/slack_api/types.ts @@ -8,10 +8,7 @@ import type { ActionType as ConnectorType } from '@kbn/actions-plugin/server/types'; import { TypeOf } from '@kbn/config-schema'; import type { ActionTypeExecutorOptions as ConnectorTypeExecutorOptions } from '@kbn/actions-plugin/server/types'; -import type { - ActionTypeExecutorResult as ConnectorTypeExecutorResult, - ConnectorMetricsService, -} from '@kbn/actions-plugin/server/types'; +import type { ActionTypeExecutorResult as ConnectorTypeExecutorResult } from '@kbn/actions-plugin/server/types'; import { PostMessageParamsSchema, PostMessageSubActionParamsSchema, @@ -87,15 +84,16 @@ export interface ValidChannelRouteResponse { export interface SlackApiService { validChannelId: ( - channelId: string, - connectorMetricsService: ConnectorMetricsService + channelId: string ) => Promise>; - postMessage: ( - { channels, channelIds, text }: PostMessageSubActionParams, - connectorMetricsService: ConnectorMetricsService - ) => Promise>; - postBlockkit: ( - { channels, channelIds, text }: PostBlockkitSubActionParams, - connectorMetricsService: ConnectorMetricsService - ) => Promise>; + postMessage: ({ + channels, + channelIds, + text, + }: PostMessageSubActionParams) => Promise>; + postBlockkit: ({ + channels, + channelIds, + text, + }: PostBlockkitSubActionParams) => Promise>; } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.test.ts index 24564488ddf57..217dc1164366e 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.test.ts @@ -25,6 +25,7 @@ import { import { DEFAULT_BODY } from '../../../public/connector_types/bedrock/constants'; import { initDashboard } from '../lib/gen_ai/create_gen_ai_dashboard'; import { AxiosError } from 'axios'; +import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; jest.mock('../lib/gen_ai/create_gen_ai_dashboard'); // @ts-ignore @@ -57,12 +58,15 @@ describe('BedrockConnector', () => { headers: {}, data: claude3Response, }; + let connectorMetricsService: ConnectorMetricsService; + beforeEach(() => { jest.clearAllMocks(); mockRequest = jest.fn().mockResolvedValue(mockResponse); mockError = jest.fn().mockImplementation(() => { throw new Error('API Error'); }); + connectorMetricsService = new ConnectorMetricsService(); }); const connector = new BedrockConnector({ @@ -85,7 +89,7 @@ describe('BedrockConnector', () => { describe('runApi', () => { it('the aws signature has non-streaming headers', async () => { - await connector.runApi({ body: DEFAULT_BODY }); + await connector.runApi({ body: DEFAULT_BODY }, new ConnectorMetricsService()); expect(mockSigner).toHaveBeenCalledWith( { body: DEFAULT_BODY, @@ -101,16 +105,19 @@ describe('BedrockConnector', () => { ); }); it('the Bedrock API call is successful with Claude 3 parameters; returns the response formatted for Claude 2 along with usage object', async () => { - const response = await connector.runApi({ body: DEFAULT_BODY }); + const response = await connector.runApi({ body: DEFAULT_BODY }, connectorMetricsService); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - signed: true, - timeout: DEFAULT_TIMEOUT_MS, - url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke`, - method: 'post', - responseSchema: RunApiLatestResponseSchema, - data: DEFAULT_BODY, - }); + expect(mockRequest).toHaveBeenCalledWith( + { + signed: true, + timeout: DEFAULT_TIMEOUT_MS, + url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke`, + method: 'post', + responseSchema: RunApiLatestResponseSchema, + data: DEFAULT_BODY, + }, + connectorMetricsService + ); expect(response).toEqual({ ...claude2Response, usage: claude3Response.usage, @@ -128,16 +135,19 @@ describe('BedrockConnector', () => { }); // @ts-ignore connector.request = mockRequest; - const response = await connector.runApi({ body: v2Body }); + const response = await connector.runApi({ body: v2Body }, connectorMetricsService); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - signed: true, - timeout: DEFAULT_TIMEOUT_MS, - url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke`, - method: 'post', - responseSchema: RunActionResponseSchema, - data: v2Body, - }); + expect(mockRequest).toHaveBeenCalledWith( + { + signed: true, + timeout: DEFAULT_TIMEOUT_MS, + url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke`, + method: 'post', + responseSchema: RunActionResponseSchema, + data: v2Body, + }, + connectorMetricsService + ); expect(response).toEqual(claude2Response); }); @@ -145,7 +155,9 @@ describe('BedrockConnector', () => { // @ts-ignore connector.request = mockError; - await expect(connector.runApi({ body: DEFAULT_BODY })).rejects.toThrow('API Error'); + await expect( + connector.runApi({ body: DEFAULT_BODY }, new ConnectorMetricsService()) + ).rejects.toThrow('API Error'); }); }); @@ -170,7 +182,7 @@ describe('BedrockConnector', () => { }; it('the aws signature has streaming headers', async () => { - await connector.invokeStream(aiAssistantBody); + await connector.invokeStream(aiAssistantBody, connectorMetricsService); expect(mockSigner).toHaveBeenCalledWith( { @@ -189,170 +201,197 @@ describe('BedrockConnector', () => { }); it('the API call is successful with correct request parameters', async () => { - await connector.invokeStream(aiAssistantBody); + await connector.invokeStream(aiAssistantBody, connectorMetricsService); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - signed: true, - url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke-with-response-stream`, - method: 'post', - responseSchema: StreamingResponseSchema, - responseType: 'stream', - data: JSON.stringify({ ...JSON.parse(DEFAULT_BODY), temperature: 0 }), - }); + expect(mockRequest).toHaveBeenCalledWith( + { + signed: true, + url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke-with-response-stream`, + method: 'post', + responseSchema: StreamingResponseSchema, + responseType: 'stream', + data: JSON.stringify({ ...JSON.parse(DEFAULT_BODY), temperature: 0 }), + }, + connectorMetricsService + ); }); it('signal and timeout is properly passed to streamApi', async () => { const signal = jest.fn(); const timeout = 180000; - await connector.invokeStream({ ...aiAssistantBody, timeout, signal }); - - expect(mockRequest).toHaveBeenCalledWith({ - signed: true, - url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke-with-response-stream`, - method: 'post', - responseSchema: StreamingResponseSchema, - responseType: 'stream', - data: JSON.stringify({ ...JSON.parse(DEFAULT_BODY), temperature: 0 }), - timeout, - signal, - }); + await connector.invokeStream( + { ...aiAssistantBody, timeout, signal }, + connectorMetricsService + ); + + expect(mockRequest).toHaveBeenCalledWith( + { + signed: true, + url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke-with-response-stream`, + method: 'post', + responseSchema: StreamingResponseSchema, + responseType: 'stream', + data: JSON.stringify({ ...JSON.parse(DEFAULT_BODY), temperature: 0 }), + timeout, + signal, + }, + connectorMetricsService + ); }); it('ensureMessageFormat - formats messages from user, assistant, and system', async () => { - await connector.invokeStream({ - messages: [ - { - role: 'system', - content: 'Be a good chatbot', - }, - { - role: 'user', - content: 'Hello world', - }, - { - role: 'assistant', - content: 'Hi, I am a good chatbot', - }, - { - role: 'user', - content: 'What is 2+2?', - }, - ], - }); - expect(mockRequest).toHaveBeenCalledWith({ - signed: true, - responseType: 'stream', - url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke-with-response-stream`, - method: 'post', - responseSchema: StreamingResponseSchema, - data: JSON.stringify({ - anthropic_version: 'bedrock-2023-05-31', - system: 'Be a good chatbot', + await connector.invokeStream( + { messages: [ - { content: 'Hello world', role: 'user' }, - { content: 'Hi, I am a good chatbot', role: 'assistant' }, - { content: 'What is 2+2?', role: 'user' }, + { + role: 'system', + content: 'Be a good chatbot', + }, + { + role: 'user', + content: 'Hello world', + }, + { + role: 'assistant', + content: 'Hi, I am a good chatbot', + }, + { + role: 'user', + content: 'What is 2+2?', + }, ], - max_tokens: DEFAULT_TOKEN_LIMIT, - temperature: 0, - }), - }); + }, + connectorMetricsService + ); + expect(mockRequest).toHaveBeenCalledWith( + { + signed: true, + responseType: 'stream', + url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke-with-response-stream`, + method: 'post', + responseSchema: StreamingResponseSchema, + data: JSON.stringify({ + anthropic_version: 'bedrock-2023-05-31', + system: 'Be a good chatbot', + messages: [ + { content: 'Hello world', role: 'user' }, + { content: 'Hi, I am a good chatbot', role: 'assistant' }, + { content: 'What is 2+2?', role: 'user' }, + ], + max_tokens: DEFAULT_TOKEN_LIMIT, + temperature: 0, + }), + }, + connectorMetricsService + ); }); it('ensureMessageFormat - formats messages from when double user/assistant occurs', async () => { - await connector.invokeStream({ - messages: [ - { - role: 'system', - content: 'Be a good chatbot', - }, - { - role: 'assistant', - content: 'Hi, I am a good chatbot', - }, - { - role: 'assistant', - content: 'But I can be naughty', - }, - { - role: 'user', - content: 'What is 2+2?', - }, - { - role: 'user', - content: 'I can be naughty too', - }, - { - role: 'system', - content: 'This is extra tricky', - }, - ], - }); - expect(mockRequest).toHaveBeenCalledWith({ - signed: true, - responseType: 'stream', - url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke-with-response-stream`, - method: 'post', - responseSchema: StreamingResponseSchema, - data: JSON.stringify({ - anthropic_version: 'bedrock-2023-05-31', - system: 'Be a good chatbot\nThis is extra tricky', + await connector.invokeStream( + { messages: [ - { content: 'Hi, I am a good chatbot\nBut I can be naughty', role: 'assistant' }, - { content: 'What is 2+2?\nI can be naughty too', role: 'user' }, + { + role: 'system', + content: 'Be a good chatbot', + }, + { + role: 'assistant', + content: 'Hi, I am a good chatbot', + }, + { + role: 'assistant', + content: 'But I can be naughty', + }, + { + role: 'user', + content: 'What is 2+2?', + }, + { + role: 'user', + content: 'I can be naughty too', + }, + { + role: 'system', + content: 'This is extra tricky', + }, ], - max_tokens: DEFAULT_TOKEN_LIMIT, - temperature: 0, - }), - }); + }, + connectorMetricsService + ); + expect(mockRequest).toHaveBeenCalledWith( + { + signed: true, + responseType: 'stream', + url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke-with-response-stream`, + method: 'post', + responseSchema: StreamingResponseSchema, + data: JSON.stringify({ + anthropic_version: 'bedrock-2023-05-31', + system: 'Be a good chatbot\nThis is extra tricky', + messages: [ + { content: 'Hi, I am a good chatbot\nBut I can be naughty', role: 'assistant' }, + { content: 'What is 2+2?\nI can be naughty too', role: 'user' }, + ], + max_tokens: DEFAULT_TOKEN_LIMIT, + temperature: 0, + }), + }, + connectorMetricsService + ); }); it('formats the system message as a user message for claude<2.1', async () => { const modelOverride = 'anthropic.claude-v2'; - await connector.invokeStream({ - messages: [ - { - role: 'system', - content: 'Be a good chatbot', - }, - { - role: 'user', - content: 'Hello world', - }, - { - role: 'assistant', - content: 'Hi, I am a good chatbot', - }, - { - role: 'user', - content: 'What is 2+2?', - }, - ], - model: modelOverride, - }); - expect(mockRequest).toHaveBeenCalledWith({ - signed: true, - responseType: 'stream', - url: `${DEFAULT_BEDROCK_URL}/model/${modelOverride}/invoke-with-response-stream`, - method: 'post', - responseSchema: StreamingResponseSchema, - data: JSON.stringify({ - anthropic_version: 'bedrock-2023-05-31', - system: 'Be a good chatbot', + await connector.invokeStream( + { messages: [ - { content: 'Hello world', role: 'user' }, - { content: 'Hi, I am a good chatbot', role: 'assistant' }, - { content: 'What is 2+2?', role: 'user' }, + { + role: 'system', + content: 'Be a good chatbot', + }, + { + role: 'user', + content: 'Hello world', + }, + { + role: 'assistant', + content: 'Hi, I am a good chatbot', + }, + { + role: 'user', + content: 'What is 2+2?', + }, ], - max_tokens: DEFAULT_TOKEN_LIMIT, - temperature: 0, - }), - }); + model: modelOverride, + }, + connectorMetricsService + ); + expect(mockRequest).toHaveBeenCalledWith( + { + signed: true, + responseType: 'stream', + url: `${DEFAULT_BEDROCK_URL}/model/${modelOverride}/invoke-with-response-stream`, + method: 'post', + responseSchema: StreamingResponseSchema, + data: JSON.stringify({ + anthropic_version: 'bedrock-2023-05-31', + system: 'Be a good chatbot', + messages: [ + { content: 'Hello world', role: 'user' }, + { content: 'Hi, I am a good chatbot', role: 'assistant' }, + { content: 'What is 2+2?', role: 'user' }, + ], + max_tokens: DEFAULT_TOKEN_LIMIT, + temperature: 0, + }), + }, + connectorMetricsService + ); }); it('responds with a readable stream', async () => { - const response = await connector.invokeStream(aiAssistantBody); + const response = await connector.invokeStream(aiAssistantBody, connectorMetricsService); expect(response instanceof PassThrough).toEqual(true); }); @@ -360,7 +399,9 @@ describe('BedrockConnector', () => { // @ts-ignore connector.request = mockError; - await expect(connector.invokeStream(aiAssistantBody)).rejects.toThrow('API Error'); + await expect( + connector.invokeStream(aiAssistantBody, connectorMetricsService) + ).rejects.toThrow('API Error'); }); }); @@ -376,175 +417,201 @@ describe('BedrockConnector', () => { }; it('the API call is successful with correct parameters', async () => { - const response = await connector.invokeAI(aiAssistantBody); + const response = await connector.invokeAI(aiAssistantBody, connectorMetricsService); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - signed: true, - timeout: DEFAULT_TIMEOUT_MS, - url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke`, - method: 'post', - responseSchema: RunApiLatestResponseSchema, - data: JSON.stringify({ - ...JSON.parse(DEFAULT_BODY), - messages: [{ content: 'Hello world', role: 'user' }], - max_tokens: DEFAULT_TOKEN_LIMIT, - temperature: 0, - }), - }); + expect(mockRequest).toHaveBeenCalledWith( + { + signed: true, + timeout: DEFAULT_TIMEOUT_MS, + url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke`, + method: 'post', + responseSchema: RunApiLatestResponseSchema, + data: JSON.stringify({ + ...JSON.parse(DEFAULT_BODY), + messages: [{ content: 'Hello world', role: 'user' }], + max_tokens: DEFAULT_TOKEN_LIMIT, + temperature: 0, + }), + }, + connectorMetricsService + ); expect(response.message).toEqual(mockResponseString); }); it('formats messages from user, assistant, and system', async () => { - const response = await connector.invokeAI({ - messages: [ - { - role: 'system', - content: 'Be a good chatbot', - }, - { - role: 'user', - content: 'Hello world', - }, - { - role: 'assistant', - content: 'Hi, I am a good chatbot', - }, - { - role: 'user', - content: 'What is 2+2?', - }, - ], - }); - expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - signed: true, - timeout: DEFAULT_TIMEOUT_MS, - url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke`, - method: 'post', - responseSchema: RunApiLatestResponseSchema, - data: JSON.stringify({ - anthropic_version: 'bedrock-2023-05-31', - system: 'Be a good chatbot', + const response = await connector.invokeAI( + { messages: [ - { content: 'Hello world', role: 'user' }, - { content: 'Hi, I am a good chatbot', role: 'assistant' }, - { content: 'What is 2+2?', role: 'user' }, + { + role: 'system', + content: 'Be a good chatbot', + }, + { + role: 'user', + content: 'Hello world', + }, + { + role: 'assistant', + content: 'Hi, I am a good chatbot', + }, + { + role: 'user', + content: 'What is 2+2?', + }, ], - max_tokens: DEFAULT_TOKEN_LIMIT, - temperature: 0, - }), - }); + }, + connectorMetricsService + ); + expect(mockRequest).toBeCalledTimes(1); + expect(mockRequest).toHaveBeenCalledWith( + { + signed: true, + timeout: DEFAULT_TIMEOUT_MS, + url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke`, + method: 'post', + responseSchema: RunApiLatestResponseSchema, + data: JSON.stringify({ + anthropic_version: 'bedrock-2023-05-31', + system: 'Be a good chatbot', + messages: [ + { content: 'Hello world', role: 'user' }, + { content: 'Hi, I am a good chatbot', role: 'assistant' }, + { content: 'What is 2+2?', role: 'user' }, + ], + max_tokens: DEFAULT_TOKEN_LIMIT, + temperature: 0, + }), + }, + connectorMetricsService + ); expect(response.message).toEqual(mockResponseString); }); it('adds system message from argument', async () => { - const response = await connector.invokeAI({ - messages: [ - { - role: 'user', - content: 'Hello world', - }, - { - role: 'assistant', - content: 'Hi, I am a good chatbot', - }, - { - role: 'user', - content: 'What is 2+2?', - }, - ], - system: 'This is a system message', - }); - expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - signed: true, - timeout: DEFAULT_TIMEOUT_MS, - url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke`, - method: 'post', - responseSchema: RunApiLatestResponseSchema, - data: JSON.stringify({ - anthropic_version: 'bedrock-2023-05-31', - system: 'This is a system message', + const response = await connector.invokeAI( + { messages: [ - { content: 'Hello world', role: 'user' }, - { content: 'Hi, I am a good chatbot', role: 'assistant' }, - { content: 'What is 2+2?', role: 'user' }, + { + role: 'user', + content: 'Hello world', + }, + { + role: 'assistant', + content: 'Hi, I am a good chatbot', + }, + { + role: 'user', + content: 'What is 2+2?', + }, ], - max_tokens: DEFAULT_TOKEN_LIMIT, - temperature: 0, - }), - }); + system: 'This is a system message', + }, + connectorMetricsService + ); + expect(mockRequest).toBeCalledTimes(1); + expect(mockRequest).toHaveBeenCalledWith( + { + signed: true, + timeout: DEFAULT_TIMEOUT_MS, + url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke`, + method: 'post', + responseSchema: RunApiLatestResponseSchema, + data: JSON.stringify({ + anthropic_version: 'bedrock-2023-05-31', + system: 'This is a system message', + messages: [ + { content: 'Hello world', role: 'user' }, + { content: 'Hi, I am a good chatbot', role: 'assistant' }, + { content: 'What is 2+2?', role: 'user' }, + ], + max_tokens: DEFAULT_TOKEN_LIMIT, + temperature: 0, + }), + }, + connectorMetricsService + ); expect(response.message).toEqual(mockResponseString); }); it('combines argument system message with conversation system message', async () => { - const response = await connector.invokeAI({ - messages: [ - { - role: 'system', - content: 'Be a good chatbot', - }, - { - role: 'user', - content: 'Hello world', - }, - { - role: 'assistant', - content: 'Hi, I am a good chatbot', - }, - { - role: 'user', - content: 'What is 2+2?', - }, - ], - system: 'This is a system message', - }); - expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - signed: true, - timeout: DEFAULT_TIMEOUT_MS, - url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke`, - method: 'post', - responseSchema: RunApiLatestResponseSchema, - data: JSON.stringify({ - anthropic_version: 'bedrock-2023-05-31', - system: 'This is a system message\nBe a good chatbot', + const response = await connector.invokeAI( + { messages: [ - { content: 'Hello world', role: 'user' }, - { content: 'Hi, I am a good chatbot', role: 'assistant' }, - { content: 'What is 2+2?', role: 'user' }, + { + role: 'system', + content: 'Be a good chatbot', + }, + { + role: 'user', + content: 'Hello world', + }, + { + role: 'assistant', + content: 'Hi, I am a good chatbot', + }, + { + role: 'user', + content: 'What is 2+2?', + }, ], - max_tokens: DEFAULT_TOKEN_LIMIT, - temperature: 0, - }), - }); + system: 'This is a system message', + }, + connectorMetricsService + ); + expect(mockRequest).toBeCalledTimes(1); + expect(mockRequest).toHaveBeenCalledWith( + { + signed: true, + timeout: DEFAULT_TIMEOUT_MS, + url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke`, + method: 'post', + responseSchema: RunApiLatestResponseSchema, + data: JSON.stringify({ + anthropic_version: 'bedrock-2023-05-31', + system: 'This is a system message\nBe a good chatbot', + messages: [ + { content: 'Hello world', role: 'user' }, + { content: 'Hi, I am a good chatbot', role: 'assistant' }, + { content: 'What is 2+2?', role: 'user' }, + ], + max_tokens: DEFAULT_TOKEN_LIMIT, + temperature: 0, + }), + }, + connectorMetricsService + ); expect(response.message).toEqual(mockResponseString); }); it('signal and timeout is properly passed to runApi', async () => { const signal = jest.fn(); const timeout = 180000; - await connector.invokeAI({ ...aiAssistantBody, timeout, signal }); - - expect(mockRequest).toHaveBeenCalledWith({ - signed: true, - url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke`, - method: 'post', - responseSchema: RunApiLatestResponseSchema, - data: JSON.stringify({ - ...JSON.parse(DEFAULT_BODY), - messages: [{ content: 'Hello world', role: 'user' }], - max_tokens: DEFAULT_TOKEN_LIMIT, - temperature: 0, - }), - timeout, - signal, - }); + await connector.invokeAI({ ...aiAssistantBody, timeout, signal }, connectorMetricsService); + + expect(mockRequest).toHaveBeenCalledWith( + { + signed: true, + url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke`, + method: 'post', + responseSchema: RunApiLatestResponseSchema, + data: JSON.stringify({ + ...JSON.parse(DEFAULT_BODY), + messages: [{ content: 'Hello world', role: 'user' }], + max_tokens: DEFAULT_TOKEN_LIMIT, + temperature: 0, + }), + timeout, + signal, + }, + connectorMetricsService + ); }); it('errors during API calls are properly handled', async () => { // @ts-ignore connector.request = mockError; - await expect(connector.invokeAI(aiAssistantBody)).rejects.toThrow('API Error'); + await expect(connector.invokeAI(aiAssistantBody, connectorMetricsService)).rejects.toThrow( + 'API Error' + ); }); }); describe('getResponseErrorMessage', () => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/api.ts b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/api.ts index f2aec6f05fc05..109c1afa920b6 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/api.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/api.ts @@ -5,7 +5,6 @@ * 2.0. */ -import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; import { ExternalServiceApi, Incident, @@ -13,10 +12,10 @@ import { PushToServiceResponse, } from './types'; -const pushToServiceHandler = async ( - { externalService, params }: PushToServiceApiHandlerArgs, - connectorMetricsService: ConnectorMetricsService -): Promise => { +const pushToServiceHandler = async ({ + externalService, + params, +}: PushToServiceApiHandlerArgs): Promise => { const { incident: { externalId, ...rest }, comments, @@ -25,20 +24,14 @@ const pushToServiceHandler = async ( let res: PushToServiceResponse; if (externalId != null) { - res = await externalService.updateIncident( - { - incidentId: externalId, - incident, - }, - connectorMetricsService - ); + res = await externalService.updateIncident({ + incidentId: externalId, + incident, + }); } else { - res = await externalService.createIncident( - { - incident, - }, - connectorMetricsService - ); + res = await externalService.createIncident({ + incident, + }); } if (comments && Array.isArray(comments) && comments.length > 0) { @@ -47,13 +40,10 @@ const pushToServiceHandler = async ( if (!currentComment.comment) { continue; } - await externalService.createComment( - { - incidentId: res.id, - comment: currentComment, - }, - connectorMetricsService - ); + await externalService.createComment({ + incidentId: res.id, + comment: currentComment, + }); res.comments = [ ...(res.comments ?? []), { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/index.ts index eaf99852fd75a..a9964b4106eca 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/index.ts @@ -70,7 +70,7 @@ export async function executor( CasesWebhookActionParamsType > ): Promise> { - const { actionId, configurationUtilities, params, logger } = execOptions; + const { actionId, configurationUtilities, params, logger, connectorMetricsService } = execOptions; const { subAction, subActionParams } = params; let data: CasesWebhookExecutorResultData | undefined; @@ -81,7 +81,8 @@ export async function executor( secrets: execOptions.secrets, }, logger, - configurationUtilities + configurationUtilities, + connectorMetricsService ); if (!api[subAction]) { @@ -98,14 +99,11 @@ export async function executor( if (subAction === 'pushToService') { const pushToServiceParams = subActionParams as ExecutorSubActionPushParams; - data = await api.pushToService( - { - externalService, - params: pushToServiceParams, - logger, - }, - execOptions.connectorMetricsService - ); + data = await api.pushToService({ + externalService, + params: pushToServiceParams, + logger, + }); logger.debug(`response push to service for case id: ${data.id}`); } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts index 3a8cf2895e60e..ff06844c34952 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts @@ -13,7 +13,7 @@ import { CasesWebhookPublicConfigurationType, ExternalService } from './types'; import { Logger } from '@kbn/core/server'; import { loggingSystemMock } from '@kbn/core/server/mocks'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; -import { getBasicAuthHeader } from '@kbn/actions-plugin/server/lib'; +import { ConnectorMetricsService, getBasicAuthHeader } from '@kbn/actions-plugin/server/lib'; import { AuthType, WebhookMethods, SSLCertType } from '../../../common/auth/constants'; import { CRT_FILE, KEY_FILE } from '../../../common/auth/mocks'; @@ -69,12 +69,14 @@ const sslConfig: CasesWebhookPublicConfigurationType = { hasAuth: true, }; const sslSecrets = { crt: CRT_FILE, key: KEY_FILE, password: 'foobar', user: null, pfx: null }; +let connectorMetricsService: ConnectorMetricsService; describe('Cases webhook service', () => { let service: ExternalService; let sslService: ExternalService; beforeAll(() => { + connectorMetricsService = new ConnectorMetricsService(); service = createExternalService( actionId, { @@ -82,7 +84,8 @@ describe('Cases webhook service', () => { secrets, }, logger, - configurationUtilities + configurationUtilities, + connectorMetricsService ); sslService = createExternalService( @@ -92,7 +95,8 @@ describe('Cases webhook service', () => { secrets: sslSecrets, }, logger, - configurationUtilities + configurationUtilities, + connectorMetricsService ); jest.useFakeTimers(); jest.setSystemTime(mockTime); @@ -121,7 +125,8 @@ describe('Cases webhook service', () => { secrets, }, logger, - configurationUtilities + configurationUtilities, + connectorMetricsService ) ).toThrow(); }); @@ -135,7 +140,8 @@ describe('Cases webhook service', () => { secrets: { ...secrets, user: '', password: '' }, }, logger, - configurationUtilities + configurationUtilities, + connectorMetricsService ) ).toThrow(); }); @@ -149,7 +155,8 @@ describe('Cases webhook service', () => { secrets: { ...secrets, user: '', password: '' }, }, logger, - configurationUtilities + configurationUtilities, + connectorMetricsService ) ).not.toThrow(); }); @@ -162,7 +169,8 @@ describe('Cases webhook service', () => { secrets: { ...secrets, user: 'username', password: 'password' }, }, logger, - configurationUtilities + configurationUtilities, + connectorMetricsService ); expect(axios.create).toHaveBeenCalledWith({ @@ -182,7 +190,8 @@ describe('Cases webhook service', () => { secrets: { ...secrets, user: 'username', password: 'password' }, }, logger, - configurationUtilities + configurationUtilities, + connectorMetricsService ); expect(axios.create).toHaveBeenCalledWith({ @@ -225,6 +234,7 @@ describe('Cases webhook service', () => { logger, configurationUtilities, sslOverrides: defaultSSLOverrides, + connectorMetricsService: expect.any(ConnectorMetricsService), }); }); @@ -238,6 +248,11 @@ describe('Cases webhook service', () => { expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "axios": [Function], + "connectorMetricsService": ConnectorMetricsService { + "metrics": Object { + "requestBodyBytes": 0, + }, + }, "logger": Object { "context": Array [], "debug": [MockFunction], @@ -481,6 +496,7 @@ describe('Cases webhook service', () => { configurationUtilities, sslOverrides: defaultSSLOverrides, data: `{"fields":{"title":"title","description":"desc","tags":["hello","world"],"project":{"key":"ROC"},"issuetype":{"id":"10024"}}}`, + connectorMetricsService: expect.any(ConnectorMetricsService), }); }); @@ -510,6 +526,11 @@ describe('Cases webhook service', () => { expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "axios": [Function], + "connectorMetricsService": ConnectorMetricsService { + "metrics": Object { + "requestBodyBytes": 0, + }, + }, "data": "{\\"fields\\":{\\"title\\":\\"title\\",\\"description\\":\\"desc\\",\\"tags\\":[\\"hello\\",\\"world\\"],\\"project\\":{\\"key\\":\\"ROC\\"},\\"issuetype\\":{\\"id\\":\\"10024\\"}}}", "logger": Object { "context": Array [], @@ -756,6 +777,7 @@ describe('Cases webhook service', () => { issuetype: { id: '10024' }, }, }), + connectorMetricsService: expect.any(ConnectorMetricsService), }); }); @@ -776,6 +798,11 @@ describe('Cases webhook service', () => { expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "axios": [Function], + "connectorMetricsService": ConnectorMetricsService { + "metrics": Object { + "requestBodyBytes": 0, + }, + }, "data": "{\\"fields\\":{\\"title\\":\\"title\\",\\"description\\":\\"desc\\",\\"tags\\":[\\"hello\\",\\"world\\"],\\"project\\":{\\"key\\":\\"ROC\\"},\\"issuetype\\":{\\"id\\":\\"10024\\"}}}", "logger": Object { "context": Array [], @@ -984,6 +1011,7 @@ describe('Cases webhook service', () => { sslOverrides: defaultSSLOverrides, url: 'https://coolsite.net/issue/1/comment', data: `{"body":"comment"}`, + connectorMetricsService: expect.any(ConnectorMetricsService), }); }); @@ -1004,6 +1032,11 @@ describe('Cases webhook service', () => { expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "axios": [Function], + "connectorMetricsService": ConnectorMetricsService { + "metrics": Object { + "requestBodyBytes": 0, + }, + }, "data": "{\\"body\\":\\"comment\\"}", "logger": Object { "context": Array [], @@ -1176,7 +1209,8 @@ describe('Cases webhook service', () => { secrets, }, logger, - configurationUtilities + configurationUtilities, + connectorMetricsService ); const res = await service.createComment(commentReq); expect(requestMock).not.toHaveBeenCalled(); @@ -1191,7 +1225,8 @@ describe('Cases webhook service', () => { secrets, }, logger, - configurationUtilities + configurationUtilities, + connectorMetricsService ); const res = await service.createComment(commentReq); expect(requestMock).not.toHaveBeenCalled(); @@ -1217,7 +1252,8 @@ describe('Cases webhook service', () => { secrets, }, logger, - configurationUtilities + configurationUtilities, + connectorMetricsService ); await service.createComment(commentReq); expect(requestMock).toHaveBeenCalledWith({ @@ -1228,6 +1264,7 @@ describe('Cases webhook service', () => { url: 'https://coolsite.net/issue/1/comment', data: `{"body":"comment","id":"1"}`, sslOverrides: defaultSSLOverrides, + connectorMetricsService: expect.any(ConnectorMetricsService), }); }); @@ -1257,7 +1294,8 @@ describe('Cases webhook service', () => { secrets, }, logger, - configurationUtilities + configurationUtilities, + connectorMetricsService ); await service.createComment(commentReq2); expect(requestMock).toHaveBeenCalledWith({ @@ -1268,6 +1306,7 @@ describe('Cases webhook service', () => { url: 'https://coolsite.net/issue/1/comment', data: `{"body":"comment","id":1}`, sslOverrides: defaultSSLOverrides, + connectorMetricsService: expect.any(ConnectorMetricsService), }); }); }); @@ -1286,7 +1325,8 @@ describe('Cases webhook service', () => { ensureUriAllowed: jest.fn().mockImplementation(() => { throw new Error('Uri not allowed'); }), - } + }, + connectorMetricsService ); }); @@ -1360,7 +1400,8 @@ describe('Cases webhook service', () => { secrets, }, logger, - configurationUtilities + configurationUtilities, + connectorMetricsService ); }); @@ -1430,7 +1471,8 @@ describe('Cases webhook service', () => { logger, { ...configurationUtilities, - } + }, + connectorMetricsService ); requestMock.mockImplementation(() => createAxiosResponse({ diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.ts b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.ts index 340bb5c51c3b2..ac5b132c100cb 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.ts @@ -41,7 +41,8 @@ export const createExternalService = ( actionId: string, { config, secrets }: ExternalServiceCredentials, logger: Logger, - configurationUtilities: ActionsConfigurationUtilities + configurationUtilities: ActionsConfigurationUtilities, + connectorMetricsService: ConnectorMetricsService ): ExternalService => { const { createCommentJson, @@ -99,10 +100,7 @@ export const createExternalService = ( const createIncidentUrl = removeSlash(createIncidentUrlConfig); - const getIncident = async ( - id: string, - connectorMetricsService: ConnectorMetricsService - ): Promise => { + const getIncident = async (id: string): Promise => { try { const getUrl = renderMustacheStringNoEscape(getIncidentUrl, { external: { @@ -138,10 +136,9 @@ export const createExternalService = ( } }; - const createIncident = async ( - { incident }: CreateIncidentParams, - connectorMetricsService: ConnectorMetricsService - ): Promise => { + const createIncident = async ({ + incident, + }: CreateIncidentParams): Promise => { try { const { description, id, severity, status: incidentStatus, tags, title } = incident; const normalizedUrl = validateAndNormalizeUrl( @@ -180,7 +177,7 @@ export const createExternalService = ( requiredAttributesToBeInTheResponse: [createIncidentResponseKey], }); const externalId = getObjectValueByKeyAsString(data, createIncidentResponseKey)!; - const insertedIncident = await getIncident(externalId, connectorMetricsService); + const insertedIncident = await getIncident(externalId); logger.debug(`response from webhook action "${actionId}": [HTTP ${status}] ${statusText}`); @@ -208,10 +205,10 @@ export const createExternalService = ( } }; - const updateIncident = async ( - { incidentId, incident }: UpdateIncidentParams, - connectorMetricsService: ConnectorMetricsService - ): Promise => { + const updateIncident = async ({ + incidentId, + incident, + }: UpdateIncidentParams): Promise => { try { const updateUrl = renderMustacheStringNoEscape(updateIncidentUrl, { external: { @@ -262,7 +259,7 @@ export const createExternalService = ( res, }); - const updatedIncident = await getIncident(incidentId as string, connectorMetricsService); + const updatedIncident = await getIncident(incidentId as string); const viewUrl = renderMustacheStringNoEscape(viewIncidentUrl, { external: { @@ -290,10 +287,7 @@ export const createExternalService = ( } }; - const createComment = async ( - { incidentId, comment }: CreateCommentParams, - connectorMetricsService: ConnectorMetricsService - ): Promise => { + const createComment = async ({ incidentId, comment }: CreateCommentParams): Promise => { try { if (!createCommentUrl || !createCommentJson || !createCommentMethod) { return; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/types.ts b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/types.ts index 8328e6a0694a2..95af6d5e306f2 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/types.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/types.ts @@ -7,7 +7,6 @@ import { TypeOf } from '@kbn/config-schema'; import { Logger } from '@kbn/core/server'; -import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; import { ExecutorParamsSchema, ExecutorSubActionPushParamsSchema, @@ -45,22 +44,10 @@ export type PushToServiceApiParams = ExecutorSubActionPushParams; // incident service export interface ExternalService { - createComment: ( - params: CreateCommentParams, - connectorMetricsService: ConnectorMetricsService - ) => Promise; - createIncident: ( - params: CreateIncidentParams, - connectorMetricsService: ConnectorMetricsService - ) => Promise; - getIncident: ( - id: string, - connectorMetricsService: ConnectorMetricsService - ) => Promise; - updateIncident: ( - params: UpdateIncidentParams, - connectorMetricsService: ConnectorMetricsService - ) => Promise; + createComment: (params: CreateCommentParams) => Promise; + createIncident: (params: CreateIncidentParams) => Promise; + getIncident: (id: string) => Promise; + updateIncident: (params: UpdateIncidentParams) => Promise; } export interface CreateIncidentParams { incident: Incident; @@ -104,10 +91,7 @@ export interface GetIncidentResponse { } export interface ExternalServiceApi { - pushToService: ( - args: PushToServiceApiHandlerArgs, - connectorMetricsService: ConnectorMetricsService - ) => Promise; + pushToService: (args: PushToServiceApiHandlerArgs) => Promise; } export type CasesWebhookExecutorResultData = ExternalServiceIncidentResponse; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.test.ts index d53881cae1272..64a98b43bc5e8 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.test.ts @@ -10,6 +10,7 @@ import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.moc import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; import { actionsMock } from '@kbn/actions-plugin/server/mocks'; import { CROWDSTRIKE_CONNECTOR_ID } from '../../../public/common'; +import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; const tokenPath = 'https://api.crowdstrike.com/oauth2/token'; const hostPath = 'https://api.crowdstrike.com/devices/entities/devices/v2'; @@ -25,12 +26,14 @@ describe('CrowdstrikeConnector', () => { services: actionsMock.createServices(), }); let mockedRequest: jest.Mock; + let connectorMetricsService: ConnectorMetricsService; beforeEach(() => { // @ts-expect-error private static - but I still want to reset it CrowdstrikeConnector.token = null; // @ts-expect-error mockedRequest = connector.request = jest.fn() as jest.Mock; + connectorMetricsService = new ConnectorMetricsService(); }); afterEach(() => { jest.clearAllMocks(); @@ -43,10 +46,13 @@ describe('CrowdstrikeConnector', () => { mockedRequest.mockResolvedValueOnce({ data: { access_token: 'testToken' } }); mockedRequest.mockResolvedValueOnce(mockResponse); - const result = await connector.executeHostActions({ - command: 'contain', - ids: ['id1', 'id2'], - }); + const result = await connector.executeHostActions( + { + command: 'contain', + ids: ['id1', 'id2'], + }, + connectorMetricsService + ); expect(mockedRequest).toHaveBeenNthCalledWith( 1, expect.objectContaining({ @@ -58,7 +64,8 @@ describe('CrowdstrikeConnector', () => { method: 'post', responseSchema: expect.any(Object), url: tokenPath, - }) + }), + connectorMetricsService ); expect(mockedRequest).toHaveBeenNthCalledWith( 2, @@ -69,7 +76,8 @@ describe('CrowdstrikeConnector', () => { data: { ids: ['id1', 'id2'] }, paramsSerializer: expect.any(Function), responseSchema: expect.any(Object), - }) + }), + connectorMetricsService ); expect(result).toEqual({ id: 'testid', path: 'testpath' }); }); @@ -82,7 +90,10 @@ describe('CrowdstrikeConnector', () => { mockedRequest.mockResolvedValueOnce({ data: { access_token: 'testToken' } }); mockedRequest.mockResolvedValueOnce(mockResponse); - const result = await connector.getAgentDetails({ ids: ['id1', 'id2'] }); + const result = await connector.getAgentDetails( + { ids: ['id1', 'id2'] }, + connectorMetricsService + ); expect(mockedRequest).toHaveBeenNthCalledWith( 1, @@ -95,7 +106,8 @@ describe('CrowdstrikeConnector', () => { method: 'post', responseSchema: expect.any(Object), url: tokenPath, - }) + }), + connectorMetricsService ); expect(mockedRequest).toHaveBeenNthCalledWith( 2, @@ -108,7 +120,8 @@ describe('CrowdstrikeConnector', () => { paramsSerializer: expect.any(Function), responseSchema: expect.any(Object), url: hostPath, - }) + }), + connectorMetricsService ); expect(result).toEqual({ resources: [{}] }); }); @@ -121,7 +134,10 @@ describe('CrowdstrikeConnector', () => { mockedRequest.mockResolvedValueOnce({ data: { access_token: 'testToken' } }); mockedRequest.mockResolvedValueOnce(mockResponse); - const result = await connector.getAgentOnlineStatus({ ids: ['id1', 'id2'] }); + const result = await connector.getAgentOnlineStatus( + { ids: ['id1', 'id2'] }, + connectorMetricsService + ); expect(mockedRequest).toHaveBeenNthCalledWith( 1, @@ -134,7 +150,8 @@ describe('CrowdstrikeConnector', () => { method: 'post', responseSchema: expect.any(Object), url: tokenPath, - }) + }), + connectorMetricsService ); expect(mockedRequest).toHaveBeenNthCalledWith( 2, @@ -147,7 +164,8 @@ describe('CrowdstrikeConnector', () => { paramsSerializer: expect.any(Function), responseSchema: expect.any(Object), url: onlineStatusPath, - }) + }), + connectorMetricsService ); expect(result).toEqual({ resources: [{}] }); }); @@ -226,7 +244,7 @@ describe('CrowdstrikeConnector', () => { mockedRequest.mockResolvedValueOnce(mockResponse); // @ts-expect-error private method - but I still want to - const result = await connector.getTokenRequest(); + const result = await connector.getTokenRequest(connectorMetricsService); expect(mockedRequest).toHaveBeenCalledWith( expect.objectContaining({ @@ -237,7 +255,8 @@ describe('CrowdstrikeConnector', () => { 'Content-Type': 'application/x-www-form-urlencoded', authorization: expect.stringContaining('Basic'), }, - }) + }), + connectorMetricsService ); expect(result).toEqual('testToken'); }); @@ -247,7 +266,7 @@ describe('CrowdstrikeConnector', () => { mockedRequest.mockResolvedValueOnce({ data: { access_token: 'testToken' } }); mockedRequest.mockResolvedValue(mockResponse); - await connector.getAgentDetails({ ids: ['id1', 'id2'] }); + await connector.getAgentDetails({ ids: ['id1', 'id2'] }, connectorMetricsService); expect(mockedRequest).toHaveBeenNthCalledWith( 1, @@ -260,7 +279,8 @@ describe('CrowdstrikeConnector', () => { method: 'post', responseSchema: expect.any(Object), url: tokenPath, - }) + }), + connectorMetricsService ); expect(mockedRequest).toHaveBeenNthCalledWith( 2, @@ -273,10 +293,11 @@ describe('CrowdstrikeConnector', () => { paramsSerializer: expect.any(Function), responseSchema: expect.any(Object), url: hostPath, - }) + }), + connectorMetricsService ); expect(mockedRequest).toHaveBeenCalledTimes(2); - await connector.getAgentDetails({ ids: ['id1', 'id2'] }); + await connector.getAgentDetails({ ids: ['id1', 'id2'] }, connectorMetricsService); expect(mockedRequest).toHaveBeenNthCalledWith( 3, expect.objectContaining({ @@ -288,7 +309,8 @@ describe('CrowdstrikeConnector', () => { paramsSerializer: expect.any(Function), responseSchema: expect.any(Object), url: hostPath, - }) + }), + connectorMetricsService ); expect(mockedRequest).toHaveBeenCalledTimes(3); }); @@ -298,9 +320,9 @@ describe('CrowdstrikeConnector', () => { mockedRequest.mockResolvedValueOnce({ data: { access_token: 'testToken' } }); mockedRequest.mockRejectedValueOnce(mockResponse); - await expect(() => connector.getAgentDetails({ ids: ['id1', 'id2'] })).rejects.toThrowError( - 'something goes wrong' - ); + await expect(() => + connector.getAgentDetails({ ids: ['id1', 'id2'] }, connectorMetricsService) + ).rejects.toThrowError('something goes wrong'); expect(mockedRequest).toHaveBeenCalledTimes(2); }); it('should repeat the call one time if theres 401 error ', async () => { @@ -309,7 +331,9 @@ describe('CrowdstrikeConnector', () => { mockedRequest.mockResolvedValueOnce({ data: { access_token: 'testToken' } }); mockedRequest.mockRejectedValueOnce(mockResponse); - await expect(() => connector.getAgentDetails({ ids: ['id1', 'id2'] })).rejects.toThrowError(); + await expect(() => + connector.getAgentDetails({ ids: ['id1', 'id2'] }, connectorMetricsService) + ).rejects.toThrowError(); expect(mockedRequest).toHaveBeenCalledTimes(3); }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.test.ts index 6f1a002cdf1d0..1999efb922d26 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.test.ts @@ -11,6 +11,7 @@ import { D3_SECURITY_CONNECTOR_ID } from '../../../common/d3security/constants'; import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; import { actionsMock } from '@kbn/actions-plugin/server/mocks'; import { D3SecurityRunActionResponseSchema } from '../../../common/d3security/schema'; +import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; describe('D3SecurityConnector', () => { const sampleBody = JSON.stringify({ @@ -38,23 +39,29 @@ describe('D3SecurityConnector', () => { logger: loggingSystemMock.createLogger(), services: actionsMock.createServices(), }); + let connectorMetricsService: ConnectorMetricsService; + beforeEach(() => { // @ts-ignore connector.request = mockRequest; jest.clearAllMocks(); + connectorMetricsService = new ConnectorMetricsService(); }); it('the D3 Security API call is successful with correct parameters', async () => { - const response = await connector.runApi({ body: sampleBody }); + const response = await connector.runApi({ body: sampleBody }, connectorMetricsService); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - url: 'https://example.com/api', - method: 'post', - responseSchema: D3SecurityRunActionResponseSchema, - data: sampleBodyFormatted, - headers: { - d3key: '123', + expect(mockRequest).toHaveBeenCalledWith( + { + url: 'https://example.com/api', + method: 'post', + responseSchema: D3SecurityRunActionResponseSchema, + data: sampleBodyFormatted, + headers: { + d3key: '123', + }, }, - }); + connectorMetricsService + ); expect(response).toEqual({ result: 'success' }); }); @@ -62,7 +69,9 @@ describe('D3SecurityConnector', () => { // @ts-ignore connector.request = mockError; - await expect(connector.runApi({ body: sampleBody })).rejects.toThrow('API Error'); + await expect(connector.runApi({ body: sampleBody }, connectorMetricsService)).rejects.toThrow( + 'API Error' + ); }); }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/email/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/email/index.test.ts index fe18cf956c0e4..bde8912adad9b 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/email/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/email/index.test.ts @@ -15,6 +15,7 @@ import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.moc import { actionsMock } from '@kbn/actions-plugin/server/mocks'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; import { + ConnectorMetricsService, validateConfig, validateConnector, validateParams, @@ -514,6 +515,7 @@ describe('execute()', () => { text: 'Go to Elastic', }, }; + const connectorMetricsService = new ConnectorMetricsService(); const actionId = 'some-id'; const executorOptions: EmailConnectorTypeExecutorOptions = { @@ -524,6 +526,7 @@ describe('execute()', () => { services, configurationUtilities: actionsConfigMock.create(), logger: mockedLogger, + connectorMetricsService, }; beforeEach(() => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/email/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/email/index.ts index 364f0528dd6de..87b1942c3e223 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/email/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/email/index.ts @@ -273,8 +273,16 @@ async function executor( }, execOptions: EmailConnectorTypeExecutorOptions ): Promise> { - const { actionId, config, secrets, params, configurationUtilities, services, logger } = - execOptions; + const { + actionId, + config, + secrets, + params, + configurationUtilities, + services, + logger, + connectorMetricsService, + } = execOptions; const connectorTokenClient = services.connectorTokenClient; const emails = params.to.concat(params.cc).concat(params.bcc); @@ -369,7 +377,7 @@ async function executor( logger, sendEmailOptions, connectorTokenClient, - execOptions.connectorMetricsService + connectorMetricsService ); } catch (err) { const message = i18n.translate('xpack.stackConnectors.email.errorSendingErrorMessage', { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.test.ts index 535c3932c04e7..e44bb0189b48d 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.test.ts @@ -10,7 +10,7 @@ import { Logger } from '@kbn/core/server'; import { sendEmail } from './send_email'; import { loggingSystemMock } from '@kbn/core/server/mocks'; import nodemailer from 'nodemailer'; -import { ProxySettings } from '@kbn/actions-plugin/server/types'; +import { ConnectorMetricsService, ProxySettings } from '@kbn/actions-plugin/server/types'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { CustomHostSettings } from '@kbn/actions-plugin/server/config'; import { sendEmailGraphApi } from './send_email_graph_api'; @@ -39,6 +39,7 @@ const sendMailMock = jest.fn(); const mockLogger = loggingSystemMock.create().get() as jest.Mocked; const connectorTokenClient = connectorTokenClientMock.create(); +const getConnectorMetricsService = () => new ConnectorMetricsService(); describe('send_email module', () => { beforeEach(() => { @@ -57,7 +58,12 @@ describe('send_email module', () => { test('handles authenticated email using service', async () => { const sendEmailOptions = getSendEmailOptions({ transport: { service: 'other' } }); - const result = await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient); + const result = await sendEmail( + mockLogger, + sendEmailOptions, + connectorTokenClient, + getConnectorMetricsService() + ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -101,7 +107,12 @@ describe('send_email module', () => { content: { hasHTMLMessage: true }, transport: { service: 'other' }, }); - const result = await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient); + const result = await sendEmail( + mockLogger, + sendEmailOptions, + connectorTokenClient, + getConnectorMetricsService() + ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -159,7 +170,12 @@ describe('send_email module', () => { status: 202, }); - await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient); + await sendEmail( + mockLogger, + sendEmailOptions, + connectorTokenClient, + getConnectorMetricsService() + ); expect(getOAuthClientCredentialsAccessTokenMock).toHaveBeenCalledWith({ configurationUtilities: sendEmailOptions.configurationUtilities, connectorId: '1', @@ -176,6 +192,7 @@ describe('send_email module', () => { delete sendEmailGraphApiMock.mock.calls[0][0].options.configurationUtilities; sendEmailGraphApiMock.mock.calls[0].pop(); sendEmailGraphApiMock.mock.calls[0].pop(); + sendEmailGraphApiMock.mock.calls[0].pop(); expect(sendEmailGraphApiMock.mock.calls[0]).toMatchInlineSnapshot(` Array [ Object { @@ -254,7 +271,12 @@ describe('send_email module', () => { status: 202, }); - await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient); + await sendEmail( + mockLogger, + sendEmailOptions, + connectorTokenClient, + getConnectorMetricsService() + ); expect(getOAuthClientCredentialsAccessTokenMock).toHaveBeenCalledWith({ configurationUtilities: sendEmailOptions.configurationUtilities, connectorId: '1', @@ -292,7 +314,12 @@ describe('send_email module', () => { status: 202, }); - await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient); + await sendEmail( + mockLogger, + sendEmailOptions, + connectorTokenClient, + getConnectorMetricsService() + ); expect(getOAuthClientCredentialsAccessTokenMock).toHaveBeenCalledWith({ configurationUtilities: sendEmailOptions.configurationUtilities, connectorId: '1', @@ -322,7 +349,7 @@ describe('send_email module', () => { getOAuthClientCredentialsAccessTokenMock.mockReturnValueOnce(null); await expect(() => - sendEmail(mockLogger, sendEmailOptions, connectorTokenClient) + sendEmail(mockLogger, sendEmailOptions, connectorTokenClient, getConnectorMetricsService()) ).rejects.toThrowErrorMatchingInlineSnapshot( `"Unable to retrieve access token for connectorId: 1"` ); @@ -362,7 +389,12 @@ describe('send_email module', () => { } ); - const result = await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient); + const result = await sendEmail( + mockLogger, + sendEmailOptions, + connectorTokenClient, + getConnectorMetricsService() + ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -412,7 +444,12 @@ describe('send_email module', () => { delete sendEmailOptions.transport.user; // @ts-expect-error delete sendEmailOptions.transport.password; - const result = await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient); + const result = await sendEmail( + mockLogger, + sendEmailOptions, + connectorTokenClient, + getConnectorMetricsService() + ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -462,7 +499,12 @@ describe('send_email module', () => { // @ts-expect-error delete sendEmailOptions.transport.password; - const result = await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient); + const result = await sendEmail( + mockLogger, + sendEmailOptions, + connectorTokenClient, + getConnectorMetricsService() + ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -503,9 +545,9 @@ describe('send_email module', () => { sendMailMock.mockReset(); sendMailMock.mockRejectedValue(new Error('wops')); - await expect(sendEmail(mockLogger, sendEmailOptions, connectorTokenClient)).rejects.toThrow( - 'wops' - ); + await expect( + sendEmail(mockLogger, sendEmailOptions, connectorTokenClient, getConnectorMetricsService()) + ).rejects.toThrow('wops'); }); test('it bypasses with proxyBypassHosts when expected', async () => { @@ -526,7 +568,12 @@ describe('send_email module', () => { } ); - const result = await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient); + const result = await sendEmail( + mockLogger, + sendEmailOptions, + connectorTokenClient, + getConnectorMetricsService() + ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -560,7 +607,12 @@ describe('send_email module', () => { } ); - const result = await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient); + const result = await sendEmail( + mockLogger, + sendEmailOptions, + connectorTokenClient, + getConnectorMetricsService() + ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -596,7 +648,12 @@ describe('send_email module', () => { } ); - const result = await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient); + const result = await sendEmail( + mockLogger, + sendEmailOptions, + connectorTokenClient, + getConnectorMetricsService() + ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -630,7 +687,12 @@ describe('send_email module', () => { } ); - const result = await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient); + const result = await sendEmail( + mockLogger, + sendEmailOptions, + connectorTokenClient, + getConnectorMetricsService() + ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -667,7 +729,12 @@ describe('send_email module', () => { } ); - const result = await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient); + const result = await sendEmail( + mockLogger, + sendEmailOptions, + connectorTokenClient, + getConnectorMetricsService() + ); expect(result).toBe(sendMailMockResult); // note in the object below, the rejectUnauthenticated got set to false, @@ -710,7 +777,12 @@ describe('send_email module', () => { } ); - const result = await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient); + const result = await sendEmail( + mockLogger, + sendEmailOptions, + connectorTokenClient, + getConnectorMetricsService() + ); expect(result).toBe(sendMailMockResult); // in this case, rejectUnauthorized is true, as the custom host settings @@ -757,7 +829,12 @@ describe('send_email module', () => { } ); - const result = await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient); + const result = await sendEmail( + mockLogger, + sendEmailOptions, + connectorTokenClient, + getConnectorMetricsService() + ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -791,7 +868,12 @@ describe('send_email module', () => { 'Bearer clienttokentokentoken' ); - await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient); + await sendEmail( + mockLogger, + sendEmailOptions, + connectorTokenClient, + getConnectorMetricsService() + ); expect(createAxiosInstanceMock).toHaveBeenCalledTimes(1); expect(createAxiosInstanceMock).toHaveBeenCalledWith(); expect(mockAxiosInstanceInterceptor.response.use).toHaveBeenCalledTimes(1); @@ -834,7 +916,12 @@ describe('send_email module', () => { 'Bearer clienttokentokentoken' ); - await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient); + await sendEmail( + mockLogger, + sendEmailOptions, + connectorTokenClient, + getConnectorMetricsService() + ); expect(createAxiosInstanceMock).toHaveBeenCalledTimes(1); expect(createAxiosInstanceMock).toHaveBeenCalledWith(); expect(mockAxiosInstanceInterceptor.response.use).toHaveBeenCalledTimes(1); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.ts b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.ts index 63d79f0df77d3..5058d8ade2003 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.ts @@ -200,6 +200,7 @@ async function sendEmailWithNodemailer( // some deep properties, so need to use any here. const transportConfig = getTransportConfig(configurationUtilities, logger, transport, hasAuth); const nodemailerTransport = nodemailer.createTransport(transportConfig); + connectorMetricsService.addRequestBodyBytes(undefined, email); const result = await nodemailerTransport.sendMail(email); if (service === JSON_TRANSPORT_SERVICE) { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.test.ts index 03289b79c3004..85303119b75f3 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.test.ts @@ -14,7 +14,7 @@ import { Logger } from '@kbn/core/server'; import { loggingSystemMock } from '@kbn/core/server/mocks'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { CustomHostSettings } from '@kbn/actions-plugin/server/config'; -import { ProxySettings } from '@kbn/actions-plugin/server/types'; +import { ConnectorMetricsService, ProxySettings } from '@kbn/actions-plugin/server/types'; import { sendEmailGraphApi } from './send_email_graph_api'; const createAxiosInstanceMock = axios.create as jest.Mock; @@ -28,6 +28,8 @@ describe('sendEmailGraphApi', () => { const configurationUtilities = actionsConfigMock.create(); test('email contains the proper message', async () => { + const connectorMetricsService = new ConnectorMetricsService(); + axiosInstanceMock.mockReturnValueOnce({ status: 202, }); @@ -38,7 +40,8 @@ describe('sendEmailGraphApi', () => { headers: {}, }, logger, - configurationUtilities + configurationUtilities, + connectorMetricsService ); expect(axiosInstanceMock.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -118,6 +121,7 @@ describe('sendEmailGraphApi', () => { }); test('email was sent on behalf of the user "from" mailbox', async () => { + const connectorMetricsService = new ConnectorMetricsService(); axiosInstanceMock.mockReturnValueOnce({ status: 202, }); @@ -128,7 +132,8 @@ describe('sendEmailGraphApi', () => { headers: { Authorization: 'Bearer 1234567' }, }, logger, - configurationUtilities + configurationUtilities, + connectorMetricsService ); expect(axiosInstanceMock.mock.calls[1]).toMatchInlineSnapshot(` Array [ @@ -210,6 +215,7 @@ describe('sendEmailGraphApi', () => { }); test('sendMail request was sent to the custom configured Graph API URL', async () => { + const connectorMetricsService = new ConnectorMetricsService(); axiosInstanceMock.mockReturnValueOnce({ status: 202, }); @@ -221,7 +227,8 @@ describe('sendEmailGraphApi', () => { headers: {}, }, logger, - configurationUtilities + configurationUtilities, + connectorMetricsService ); expect(axiosInstanceMock.mock.calls[2]).toMatchInlineSnapshot(` Array [ @@ -301,6 +308,7 @@ describe('sendEmailGraphApi', () => { }); test('throw the exception and log the proper error if message was not sent successfuly', async () => { + const connectorMetricsService = new ConnectorMetricsService(); axiosInstanceMock.mockReturnValueOnce({ status: 400, data: { @@ -315,7 +323,8 @@ describe('sendEmailGraphApi', () => { sendEmailGraphApi( { options: getSendEmailOptions(), messageHTML: 'test1', headers: {} }, logger, - configurationUtilities + configurationUtilities, + connectorMetricsService ) ).rejects.toThrowErrorMatchingInlineSnapshot( '"{\\"error\\":{\\"code\\":\\"ErrorMimeContentInvalidBase64String\\",\\"message\\":\\"Invalid base64 string for MIME content.\\"}}"' diff --git a/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.test.ts index ed825d9aecbf3..d88f8f13d9970 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.test.ts @@ -15,6 +15,7 @@ import { RunApiResponseSchema, StreamingResponseSchema } from '../../../common/g import { DEFAULT_GEMINI_MODEL } from '../../../common/gemini/constants'; import { AxiosError } from 'axios'; import { Transform } from 'stream'; +import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; jest.mock('../lib/gen_ai/create_gen_ai_dashboard'); jest.mock('@kbn/actions-plugin/server/sub_action_framework/helpers/validators', () => ({ @@ -87,11 +88,13 @@ describe('GeminiConnector', () => { logger: loggingSystemMock.createLogger(), services: actionsMock.createServices(), }); + let connectorMetricsService: ConnectorMetricsService; describe('Gemini', () => { beforeEach(() => { // @ts-ignore connector.request = mockRequest; + connectorMetricsService = new ConnectorMetricsService(); }); describe('runApi', () => { @@ -101,33 +104,36 @@ describe('GeminiConnector', () => { model: DEFAULT_GEMINI_MODEL, }; - const response = await connector.runApi(runActionParams); + const response = await connector.runApi(runActionParams, connectorMetricsService); // Assertions expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - url: `https://api.gemini.com/v1/projects/my-project-12345/locations/us-central1/publishers/google/models/${DEFAULT_GEMINI_MODEL}:generateContent`, - method: 'post', - data: JSON.stringify({ - messages: [ - { - contents: [ - { - role: 'user', - parts: [{ text: 'What is the capital of France?' }], - }, - ], - }, - ], - }), - headers: { - Authorization: 'Bearer mock_access_token', - 'Content-Type': 'application/json', + expect(mockRequest).toHaveBeenCalledWith( + { + url: `https://api.gemini.com/v1/projects/my-project-12345/locations/us-central1/publishers/google/models/${DEFAULT_GEMINI_MODEL}:generateContent`, + method: 'post', + data: JSON.stringify({ + messages: [ + { + contents: [ + { + role: 'user', + parts: [{ text: 'What is the capital of France?' }], + }, + ], + }, + ], + }), + headers: { + Authorization: 'Bearer mock_access_token', + 'Content-Type': 'application/json', + }, + timeout: 60000, + responseSchema: RunApiResponseSchema, + signal: undefined, }, - timeout: 60000, - responseSchema: RunApiResponseSchema, - signal: undefined, - }); + connectorMetricsService + ); expect(response).toEqual(connectorResponse); }); @@ -144,60 +150,66 @@ describe('GeminiConnector', () => { }; it('the API call is successful with correct parameters', async () => { - await connector.invokeAI(aiAssistantBody); + await connector.invokeAI(aiAssistantBody, connectorMetricsService); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - url: `https://api.gemini.com/v1/projects/my-project-12345/locations/us-central1/publishers/google/models/${DEFAULT_GEMINI_MODEL}:generateContent`, - method: 'post', - responseSchema: RunApiResponseSchema, - data: JSON.stringify({ - contents: [ - { - role: 'user', - parts: [{ text: 'What is the capital of France?' }], + expect(mockRequest).toHaveBeenCalledWith( + { + url: `https://api.gemini.com/v1/projects/my-project-12345/locations/us-central1/publishers/google/models/${DEFAULT_GEMINI_MODEL}:generateContent`, + method: 'post', + responseSchema: RunApiResponseSchema, + data: JSON.stringify({ + contents: [ + { + role: 'user', + parts: [{ text: 'What is the capital of France?' }], + }, + ], + generation_config: { + temperature: 0, + maxOutputTokens: 8192, }, - ], - generation_config: { - temperature: 0, - maxOutputTokens: 8192, + }), + headers: { + Authorization: 'Bearer mock_access_token', + 'Content-Type': 'application/json', }, - }), - headers: { - Authorization: 'Bearer mock_access_token', - 'Content-Type': 'application/json', + signal: undefined, + timeout: 60000, }, - signal: undefined, - timeout: 60000, - }); + connectorMetricsService + ); }); it('signal and timeout is properly passed to runApi', async () => { const signal = jest.fn(); const timeout = 60000; - await connector.invokeAI({ ...aiAssistantBody, timeout, signal }); - expect(mockRequest).toHaveBeenCalledWith({ - url: `https://api.gemini.com/v1/projects/my-project-12345/locations/us-central1/publishers/google/models/${DEFAULT_GEMINI_MODEL}:generateContent`, - method: 'post', - responseSchema: RunApiResponseSchema, - data: JSON.stringify({ - contents: [ - { - role: 'user', - parts: [{ text: 'What is the capital of France?' }], + await connector.invokeAI({ ...aiAssistantBody, timeout, signal }, connectorMetricsService); + expect(mockRequest).toHaveBeenCalledWith( + { + url: `https://api.gemini.com/v1/projects/my-project-12345/locations/us-central1/publishers/google/models/${DEFAULT_GEMINI_MODEL}:generateContent`, + method: 'post', + responseSchema: RunApiResponseSchema, + data: JSON.stringify({ + contents: [ + { + role: 'user', + parts: [{ text: 'What is the capital of France?' }], + }, + ], + generation_config: { + temperature: 0, + maxOutputTokens: 8192, }, - ], - generation_config: { - temperature: 0, - maxOutputTokens: 8192, + }), + headers: { + Authorization: 'Bearer mock_access_token', + 'Content-Type': 'application/json', }, - }), - headers: { - Authorization: 'Bearer mock_access_token', - 'Content-Type': 'application/json', + signal, + timeout: 60000, }, - signal, - timeout: 60000, - }); + connectorMetricsService + ); }); }); @@ -220,62 +232,71 @@ describe('GeminiConnector', () => { }; it('the API call is successful with correct request parameters', async () => { - await connector.invokeStream(aiAssistantBody); + await connector.invokeStream(aiAssistantBody, connectorMetricsService); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - url: `https://api.gemini.com/v1/projects/my-project-12345/locations/us-central1/publishers/google/models/${DEFAULT_GEMINI_MODEL}:streamGenerateContent?alt=sse`, - method: 'post', - responseSchema: StreamingResponseSchema, - data: JSON.stringify({ - contents: [ - { - role: 'user', - parts: [{ text: 'What is the capital of France?' }], + expect(mockRequest).toHaveBeenCalledWith( + { + url: `https://api.gemini.com/v1/projects/my-project-12345/locations/us-central1/publishers/google/models/${DEFAULT_GEMINI_MODEL}:streamGenerateContent?alt=sse`, + method: 'post', + responseSchema: StreamingResponseSchema, + data: JSON.stringify({ + contents: [ + { + role: 'user', + parts: [{ text: 'What is the capital of France?' }], + }, + ], + generation_config: { + temperature: 0, + maxOutputTokens: 8192, }, - ], - generation_config: { - temperature: 0, - maxOutputTokens: 8192, + }), + responseType: 'stream', + headers: { + Authorization: 'Bearer mock_access_token', + 'Content-Type': 'application/json', }, - }), - responseType: 'stream', - headers: { - Authorization: 'Bearer mock_access_token', - 'Content-Type': 'application/json', + signal: undefined, + timeout: 60000, }, - signal: undefined, - timeout: 60000, - }); + connectorMetricsService + ); }); it('signal and timeout is properly passed to streamApi', async () => { const signal = jest.fn(); const timeout = 60000; - await connector.invokeStream({ ...aiAssistantBody, timeout, signal }); - expect(mockRequest).toHaveBeenCalledWith({ - url: `https://api.gemini.com/v1/projects/my-project-12345/locations/us-central1/publishers/google/models/${DEFAULT_GEMINI_MODEL}:streamGenerateContent?alt=sse`, - method: 'post', - responseSchema: StreamingResponseSchema, - data: JSON.stringify({ - contents: [ - { - role: 'user', - parts: [{ text: 'What is the capital of France?' }], + await connector.invokeStream( + { ...aiAssistantBody, timeout, signal }, + connectorMetricsService + ); + expect(mockRequest).toHaveBeenCalledWith( + { + url: `https://api.gemini.com/v1/projects/my-project-12345/locations/us-central1/publishers/google/models/${DEFAULT_GEMINI_MODEL}:streamGenerateContent?alt=sse`, + method: 'post', + responseSchema: StreamingResponseSchema, + data: JSON.stringify({ + contents: [ + { + role: 'user', + parts: [{ text: 'What is the capital of France?' }], + }, + ], + generation_config: { + temperature: 0, + maxOutputTokens: 8192, }, - ], - generation_config: { - temperature: 0, - maxOutputTokens: 8192, + }), + responseType: 'stream', + headers: { + Authorization: 'Bearer mock_access_token', + 'Content-Type': 'application/json', }, - }), - responseType: 'stream', - headers: { - Authorization: 'Bearer mock_access_token', - 'Content-Type': 'application/json', + signal, + timeout: 60000, }, - signal, - timeout: 60000, - }); + connectorMetricsService + ); }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.ts b/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.ts index 323b13d3b768e..335559a1b0ef7 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.ts @@ -12,7 +12,10 @@ import { IncomingMessage } from 'http'; import { SubActionRequestParams } from '@kbn/actions-plugin/server/sub_action_framework/types'; import { getGoogleOAuthJwtAccessToken } from '@kbn/actions-plugin/server/lib/get_gcp_oauth_access_token'; import { Logger } from '@kbn/core/server'; -import { ConnectorTokenClientContract } from '@kbn/actions-plugin/server/types'; +import { + ConnectorMetricsService, + ConnectorTokenClientContract, +} from '@kbn/actions-plugin/server/types'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; import { RunActionParamsSchema, @@ -199,12 +202,10 @@ export class GeminiConnector extends SubActionConnector { * @param body The stringified request body to be sent in the POST request. * @param model Optional model to be used for the API request. If not provided, the default model from the connector will be used. */ - public async runApi({ - body, - model: reqModel, - signal, - timeout, - }: RunActionParams): Promise { + public async runApi( + { body, model: reqModel, signal, timeout }: RunActionParams, + connectorMetricsService: ConnectorMetricsService + ): Promise { // set model on per request basis const currentModel = reqModel ?? this.model; const path = `/v1/projects/${this.gcpProjectID}/locations/${this.gcpRegion}/publishers/google/models/${currentModel}:generateContent`; @@ -223,7 +224,7 @@ export class GeminiConnector extends SubActionConnector { responseSchema: RunApiResponseSchema, } as SubActionRequestParams; - const response = await this.request(requestArgs); + const response = await this.request(requestArgs, connectorMetricsService); const candidate = response.data.candidates[0]; const usageMetadata = response.data.usageMetadata; const completionText = candidate.content.parts[0].text; @@ -231,46 +232,47 @@ export class GeminiConnector extends SubActionConnector { return { completion: completionText, usageMetadata }; } - private async streamAPI({ - body, - model: reqModel, - signal, - timeout, - }: RunActionParams): Promise { + private async streamAPI( + { body, model: reqModel, signal, timeout }: RunActionParams, + connectorMetricsService: ConnectorMetricsService + ): Promise { const currentModel = reqModel ?? this.model; const path = `/v1/projects/${this.gcpProjectID}/locations/${this.gcpRegion}/publishers/google/models/${currentModel}:streamGenerateContent?alt=sse`; const token = await this.getAccessToken(); - const response = await this.request({ - url: `${this.url}${path}`, - method: 'post', - responseSchema: StreamingResponseSchema, - data: body, - responseType: 'stream', - headers: { - Authorization: `Bearer ${token}`, - 'Content-Type': 'application/json', + const response = await this.request( + { + url: `${this.url}${path}`, + method: 'post', + responseSchema: StreamingResponseSchema, + data: body, + responseType: 'stream', + headers: { + Authorization: `Bearer ${token}`, + 'Content-Type': 'application/json', + }, + signal, + timeout: timeout ?? DEFAULT_TIMEOUT_MS, }, - signal, - timeout: timeout ?? DEFAULT_TIMEOUT_MS, - }); + connectorMetricsService + ); return response.data.pipe(new PassThrough()); } - public async invokeAI({ - messages, - model, - temperature = 0, - signal, - timeout, - }: InvokeAIActionParams): Promise { - const res = await this.runApi({ - body: JSON.stringify(formatGeminiPayload(messages, temperature)), - model, - signal, - timeout, - }); + public async invokeAI( + { messages, model, temperature = 0, signal, timeout }: InvokeAIActionParams, + connectorMetricsService: ConnectorMetricsService + ): Promise { + const res = await this.runApi( + { + body: JSON.stringify(formatGeminiPayload(messages, temperature)), + model, + signal, + timeout, + }, + connectorMetricsService + ); return { message: res.completion, usageMetadata: res.usageMetadata }; } @@ -283,21 +285,20 @@ export class GeminiConnector extends SubActionConnector { * @param messages An array of messages to be sent to the API * @param model Optional model to be used for the API request. If not provided, the default model from the connector will be used. */ - public async invokeStream({ - messages, - model, - stopSequences, - temperature = 0, - signal, - timeout, - }: InvokeAIActionParams): Promise { - const res = (await this.streamAPI({ - body: JSON.stringify(formatGeminiPayload(messages, temperature)), - model, - stopSequences, - signal, - timeout, - })) as unknown as IncomingMessage; + public async invokeStream( + { messages, model, stopSequences, temperature = 0, signal, timeout }: InvokeAIActionParams, + connectorMetricsService: ConnectorMetricsService + ): Promise { + const res = (await this.streamAPI( + { + body: JSON.stringify(formatGeminiPayload(messages, temperature)), + model, + stopSequences, + signal, + timeout, + }, + connectorMetricsService + )) as unknown as IncomingMessage; return res; } } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/jira/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/jira/index.ts index 630c0973935cd..16e79ecedd74c 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/jira/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/jira/index.ts @@ -95,7 +95,15 @@ async function executor( ExecutorParams > ): Promise> { - const { actionId, config, params, secrets, configurationUtilities, logger } = execOptions; + const { + actionId, + config, + params, + secrets, + configurationUtilities, + logger, + connectorMetricsService, + } = execOptions; const { subAction, subActionParams } = params as ExecutorParams; let data: JiraExecutorResultData | null = null; @@ -105,7 +113,8 @@ async function executor( secrets, }, logger, - configurationUtilities + configurationUtilities, + connectorMetricsService ); if (!api[subAction]) { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/jira/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/jira/service.test.ts index 34e0f1f799ce5..49c6c4459e8a1 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/jira/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/jira/service.test.ts @@ -14,6 +14,7 @@ import { Logger } from '@kbn/core/server'; import { loggingSystemMock } from '@kbn/core/server/mocks'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { getBasicAuthHeader } from '@kbn/actions-plugin/server'; +import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; const logger = loggingSystemMock.create().get() as jest.Mocked; interface ResponseError extends Error { @@ -135,8 +136,10 @@ const mockOldAPI = () => describe('Jira service', () => { let service: ExternalService; + let connectorMetricsService: ConnectorMetricsService; beforeAll(() => { + connectorMetricsService = new ConnectorMetricsService(); service = createExternalService( { // The trailing slash at the end of the url is intended. @@ -145,7 +148,8 @@ describe('Jira service', () => { secrets: { apiToken: 'token', email: 'elastic@elastic.com' }, }, logger, - configurationUtilities + configurationUtilities, + connectorMetricsService ); }); @@ -162,7 +166,8 @@ describe('Jira service', () => { secrets: { apiToken: 'token', email: 'elastic@elastic.com' }, }, logger, - configurationUtilities + configurationUtilities, + connectorMetricsService ) ).toThrow(); }); @@ -175,7 +180,8 @@ describe('Jira service', () => { secrets: { apiToken: 'token', email: 'elastic@elastic.com' }, }, logger, - configurationUtilities + configurationUtilities, + connectorMetricsService ) ).toThrow(); }); @@ -188,7 +194,8 @@ describe('Jira service', () => { secrets: { apiToken: 'token' }, }, logger, - configurationUtilities + configurationUtilities, + connectorMetricsService ) ).toThrow(); }); @@ -201,7 +208,8 @@ describe('Jira service', () => { secrets: { email: 'elastic@elastic.com' }, }, logger, - configurationUtilities + configurationUtilities, + connectorMetricsService ) ).toThrow(); }); @@ -213,7 +221,8 @@ describe('Jira service', () => { secrets: { apiToken: 'token', email: 'elastic@elastic.com' }, }, logger, - configurationUtilities + configurationUtilities, + connectorMetricsService ); expect(axios.create).toHaveBeenCalledWith({ @@ -258,6 +267,7 @@ describe('Jira service', () => { url: 'https://coolsite.net/rest/api/2/issue/1', logger, configurationUtilities, + connectorMetricsService, }); }); @@ -401,6 +411,7 @@ describe('Jira service', () => { priority: { name: 'High' }, }, }, + connectorMetricsService, }); }); @@ -459,6 +470,7 @@ describe('Jira service', () => { priority: { name: 'High' }, }, }, + connectorMetricsService, }); }); @@ -492,6 +504,7 @@ describe('Jira service', () => { parent: { key: 'RJ-107' }, }, }, + connectorMetricsService, }); }); @@ -561,6 +574,7 @@ describe('Jira service', () => { ...otherFields, }, }, + connectorMetricsService, }); }); }); @@ -631,6 +645,7 @@ describe('Jira service', () => { parent: { key: 'RJ-107' }, }, }, + connectorMetricsService, }); }); @@ -693,6 +708,7 @@ describe('Jira service', () => { ...otherFields, }, }, + connectorMetricsService, }); }); }); @@ -746,6 +762,7 @@ describe('Jira service', () => { configurationUtilities, url: 'https://coolsite.net/rest/api/2/issue/1/comment', data: { body: 'comment' }, + connectorMetricsService, }); }); @@ -802,6 +819,7 @@ describe('Jira service', () => { method: 'get', configurationUtilities, url: 'https://coolsite.net/rest/capabilities', + connectorMetricsService, }); }); @@ -883,6 +901,7 @@ describe('Jira service', () => { method: 'get', configurationUtilities, url: 'https://coolsite.net/rest/api/2/issue/createmeta?projectKeys=CK&expand=projects.issuetypes.fields', + connectorMetricsService, }); }); @@ -957,6 +976,7 @@ describe('Jira service', () => { method: 'get', configurationUtilities, url: 'https://coolsite.net/rest/api/2/issue/createmeta/CK/issuetypes', + connectorMetricsService, }); }); @@ -1032,6 +1052,7 @@ describe('Jira service', () => { method: 'get', configurationUtilities, url: 'https://coolsite.net/rest/api/2/issue/createmeta?projectKeys=CK&issuetypeIds=10006&expand=projects.issuetypes.fields', + connectorMetricsService, }); }); @@ -1240,6 +1261,7 @@ describe('Jira service', () => { method: 'get', configurationUtilities, url: `https://coolsite.net/rest/api/2/search?jql=project%3D%22CK%22%20and%20summary%20~%22Test%20title%22`, + connectorMetricsService, }); }); @@ -1266,6 +1288,7 @@ describe('Jira service', () => { method: 'get', configurationUtilities, url: `https://coolsite.net/rest/api/2/search?jql=project%3D%22CK%22%20and%20summary%20~%22%5C%5C%5Bth%5C%5C!s%5C%5C%5Eis%5C%5C(%5C%5C)a%5C%5C-te%5C%5C%2Bst%5C%5C-%5C%5C%7B%5C%5C~is%5C%5C*s%5C%5C%26ue%5C%5C%3For%5C%5C%7Cand%5C%5Cbye%5C%5C%3A%5C%5C%7D%5C%5C%5D%5C%5C%7D%5C%5C%5D%22`, + connectorMetricsService, }); }); @@ -1344,6 +1367,7 @@ describe('Jira service', () => { method: 'get', configurationUtilities, url: `https://coolsite.net/rest/api/2/issue/RJ-107`, + connectorMetricsService, }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/jira/service.ts b/x-pack/plugins/stack_connectors/server/connector_types/jira/service.ts index 3cd5115234da1..cf229f8aeaedb 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/jira/service.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/jira/service.ts @@ -16,6 +16,7 @@ import { } from '@kbn/actions-plugin/server/lib/axios_utils'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; import { getBasicAuthHeader } from '@kbn/actions-plugin/server'; +import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; import { CreateCommentParams, CreateIncidentParams, @@ -47,7 +48,8 @@ const createMetaCapabilities = ['list-project-issuetypes', 'list-issuetype-field export const createExternalService = ( { config, secrets }: ExternalServiceCredentials, logger: Logger, - configurationUtilities: ActionsConfigurationUtilities + configurationUtilities: ActionsConfigurationUtilities, + connectorMetricsService: ConnectorMetricsService ): ExternalService => { const { apiUrl: url, projectKey } = config as JiraPublicConfigurationType; const { apiToken, email } = secrets as JiraSecretConfigurationType; @@ -189,6 +191,7 @@ export const createExternalService = ( url: `${incidentUrl}/${id}`, logger, configurationUtilities, + connectorMetricsService, }); throwIfResponseIsNotValid({ @@ -242,6 +245,7 @@ export const createExternalService = ( fields, }, configurationUtilities, + connectorMetricsService, }); throwIfResponseIsNotValid({ @@ -288,6 +292,7 @@ export const createExternalService = ( logger, data: { fields }, configurationUtilities, + connectorMetricsService, }); throwIfResponseIsNotValid({ @@ -326,6 +331,7 @@ export const createExternalService = ( logger, data: { body: comment.comment }, configurationUtilities, + connectorMetricsService, }); throwIfResponseIsNotValid({ @@ -358,6 +364,7 @@ export const createExternalService = ( url: capabilitiesUrl, logger, configurationUtilities, + connectorMetricsService, }); throwIfResponseIsNotValid({ @@ -389,6 +396,7 @@ export const createExternalService = ( url: getIssueTypesOldAPIURL, logger, configurationUtilities, + connectorMetricsService, }); throwIfResponseIsNotValid({ @@ -404,6 +412,7 @@ export const createExternalService = ( url: getIssueTypesUrl, logger, configurationUtilities, + connectorMetricsService, }); throwIfResponseIsNotValid({ @@ -436,6 +445,7 @@ export const createExternalService = ( url: createGetIssueTypeFieldsUrl(getIssueTypeFieldsOldAPIURL, issueTypeId), logger, configurationUtilities, + connectorMetricsService, }); throwIfResponseIsNotValid({ @@ -515,6 +525,7 @@ export const createExternalService = ( url: query, logger, configurationUtilities, + connectorMetricsService, }); throwIfResponseIsNotValid({ @@ -543,6 +554,7 @@ export const createExternalService = ( url: getIssueUrl, logger, configurationUtilities, + connectorMetricsService, }); throwIfResponseIsNotValid({ diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/create_service_wrapper.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/create_service_wrapper.ts index f2de6e3787f70..01a215bc8905c 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/create_service_wrapper.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/create_service_wrapper.ts @@ -6,7 +6,10 @@ */ import { Logger } from '@kbn/core/server'; -import type { ConnectorTokenClientContract } from '@kbn/actions-plugin/server/types'; +import { + ConnectorMetricsService, + ConnectorTokenClientContract, +} from '@kbn/actions-plugin/server/types'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; import { ExternalService, ExternalServiceCredentials, SNProductsConfigValue } from './types'; @@ -21,6 +24,7 @@ interface CreateServiceWrapperOpts { serviceConfig: SNProductsConfigValue; connectorTokenClient: ConnectorTokenClientContract; createServiceFn: ServiceFactory; + connectorMetricsService: ConnectorMetricsService; } export function createServiceWrapper({ @@ -31,6 +35,7 @@ export function createServiceWrapper({ serviceConfig, connectorTokenClient, createServiceFn, + connectorMetricsService, }: CreateServiceWrapperOpts): T { const { config } = credentials; const { apiUrl: url } = config as ServiceNowPublicConfigurationType; @@ -50,5 +55,6 @@ export function createServiceWrapper({ configurationUtilities, serviceConfig, axiosInstance, + connectorMetricsService, }); } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.ts index 42aed9dcf8466..de2573463094e 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.ts @@ -37,6 +37,7 @@ export const createExternalService: ServiceFactory = ({ configurationUtilities, serviceConfig, axiosInstance, + connectorMetricsService, }): ExternalService => { const { config, secrets } = credentials; const { table, importSetTable, useImportAPI, appScope } = serviceConfig; @@ -132,6 +133,7 @@ export const createExternalService: ServiceFactory = ({ logger, configurationUtilities, method: 'get', + connectorMetricsService, // TODO check if this is internal }); checkInstance(res); @@ -160,6 +162,7 @@ export const createExternalService: ServiceFactory = ({ logger, configurationUtilities, method: 'get', + connectorMetricsService, }); checkInstance(res); @@ -178,6 +181,7 @@ export const createExternalService: ServiceFactory = ({ logger, params, configurationUtilities, + connectorMetricsService, }); checkInstance(res); @@ -201,6 +205,7 @@ export const createExternalService: ServiceFactory = ({ method: 'post', data: prepareIncident(useTableApi, incident), configurationUtilities, + connectorMetricsService, }); checkInstance(res); @@ -240,6 +245,7 @@ export const createExternalService: ServiceFactory = ({ ...(useTableApi ? {} : { elastic_incident_id: incidentId }), }, configurationUtilities, + connectorMetricsService, }); checkInstance(res); @@ -272,6 +278,7 @@ export const createExternalService: ServiceFactory = ({ method: 'get', logger, configurationUtilities, + connectorMetricsService, }); checkInstance(res); @@ -350,6 +357,7 @@ export const createExternalService: ServiceFactory = ({ url: fieldsUrl, logger, configurationUtilities, + connectorMetricsService, }); checkInstance(res); @@ -367,6 +375,7 @@ export const createExternalService: ServiceFactory = ({ url: getChoicesURL(fields), logger, configurationUtilities, + connectorMetricsService, }); checkInstance(res); return res.data.result; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/types.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/types.ts index 86d037c324e41..adde700b93c4d 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/types.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/types.ts @@ -11,7 +11,7 @@ import { AxiosError, AxiosInstance, AxiosResponse } from 'axios'; import { TypeOf } from '@kbn/config-schema'; import { Logger } from '@kbn/core/server'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; -import { ValidatorServices } from '@kbn/actions-plugin/server/types'; +import { ConnectorMetricsService, ValidatorServices } from '@kbn/actions-plugin/server/types'; import { ExecutorParamsSchemaITSM, ExecutorSubActionCommonFieldsParamsSchema, @@ -305,6 +305,7 @@ interface ServiceFactoryOpts { configurationUtilities: ActionsConfigurationUtilities; serviceConfig: SNProductsConfigValue; axiosInstance: AxiosInstance; + connectorMetricsService: ConnectorMetricsService; } export type ServiceFactory = ({ @@ -313,6 +314,7 @@ export type ServiceFactory = ({ configurationUtilities, serviceConfig, axiosInstance, + connectorMetricsService, }: ServiceFactoryOpts) => T; /** diff --git a/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.test.ts index 6f0974fe1796d..46818b85adc52 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.test.ts @@ -19,6 +19,7 @@ import { actionsMock } from '@kbn/actions-plugin/server/mocks'; import { RunActionResponseSchema, StreamingResponseSchema } from '../../../common/openai/schema'; import { initDashboard } from '../lib/gen_ai/create_gen_ai_dashboard'; import { PassThrough, Transform } from 'stream'; +import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; jest.mock('../lib/gen_ai/create_gen_ai_dashboard'); const mockTee = jest.fn(); @@ -46,6 +47,8 @@ jest.mock('openai', () => ({ describe('OpenAIConnector', () => { let mockRequest: jest.Mock; let mockError: jest.Mock; + let connectorMetricsService: ConnectorMetricsService; + const mockResponseString = 'Hello! How can I assist you today?'; const mockResponse = { headers: {}, @@ -72,6 +75,7 @@ describe('OpenAIConnector', () => { }, }; beforeEach(() => { + connectorMetricsService = new ConnectorMetricsService(); mockRequest = jest.fn().mockResolvedValue(mockResponse); mockError = jest.fn().mockImplementation(() => { throw new Error('API Error'); @@ -113,48 +117,74 @@ describe('OpenAIConnector', () => { describe('runApi', () => { it('uses the default model if none is supplied', async () => { - const response = await connector.runApi({ body: JSON.stringify(sampleOpenAiBody) }); + const response = await connector.runApi( + { body: JSON.stringify(sampleOpenAiBody) }, + connectorMetricsService + ); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - ...mockDefaults, - data: JSON.stringify({ ...sampleOpenAiBody, stream: false, model: DEFAULT_OPENAI_MODEL }), - headers: { - Authorization: 'Bearer 123', - 'X-My-Custom-Header': 'foo', - 'content-type': 'application/json', + expect(mockRequest).toHaveBeenCalledWith( + { + ...mockDefaults, + data: JSON.stringify({ + ...sampleOpenAiBody, + stream: false, + model: DEFAULT_OPENAI_MODEL, + }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, }, - }); + connectorMetricsService + ); expect(response).toEqual(mockResponse.data); }); it('overrides the default model with the default model specified in the body', async () => { const requestBody = { model: 'gpt-3.5-turbo', ...sampleOpenAiBody }; - const response = await connector.runApi({ body: JSON.stringify(requestBody) }); + const response = await connector.runApi( + { body: JSON.stringify(requestBody) }, + connectorMetricsService + ); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - ...mockDefaults, - data: JSON.stringify({ ...requestBody, stream: false }), - headers: { - Authorization: 'Bearer 123', - 'X-My-Custom-Header': 'foo', - 'content-type': 'application/json', + expect(mockRequest).toHaveBeenCalledWith( + { + ...mockDefaults, + data: JSON.stringify({ ...requestBody, stream: false }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, }, - }); + connectorMetricsService + ); expect(response).toEqual(mockResponse.data); }); it('the OpenAI API call is successful with correct parameters', async () => { - const response = await connector.runApi({ body: JSON.stringify(sampleOpenAiBody) }); + const response = await connector.runApi( + { body: JSON.stringify(sampleOpenAiBody) }, + connectorMetricsService + ); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - ...mockDefaults, - data: JSON.stringify({ ...sampleOpenAiBody, stream: false, model: DEFAULT_OPENAI_MODEL }), - headers: { - Authorization: 'Bearer 123', - 'X-My-Custom-Header': 'foo', - 'content-type': 'application/json', + expect(mockRequest).toHaveBeenCalledWith( + { + ...mockDefaults, + data: JSON.stringify({ + ...sampleOpenAiBody, + stream: false, + model: DEFAULT_OPENAI_MODEL, + }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, }, - }); + connectorMetricsService + ); expect(response).toEqual(mockResponse.data); }); @@ -168,25 +198,31 @@ describe('OpenAIConnector', () => { }, ], }; - const response = await connector.runApi({ - body: JSON.stringify({ - ...body, - stream: true, - }), - }); + const response = await connector.runApi( + { + body: JSON.stringify({ + ...body, + stream: true, + }), + }, + connectorMetricsService + ); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - ...mockDefaults, - data: JSON.stringify({ - ...body, - stream: false, - }), - headers: { - Authorization: 'Bearer 123', - 'X-My-Custom-Header': 'foo', - 'content-type': 'application/json', + expect(mockRequest).toHaveBeenCalledWith( + { + ...mockDefaults, + data: JSON.stringify({ + ...body, + stream: false, + }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, }, - }); + connectorMetricsService + ); expect(response).toEqual(mockResponse.data); }); @@ -194,51 +230,71 @@ describe('OpenAIConnector', () => { // @ts-ignore connector.request = mockError; - await expect(connector.runApi({ body: JSON.stringify(sampleOpenAiBody) })).rejects.toThrow( - 'API Error' - ); + await expect( + connector.runApi({ body: JSON.stringify(sampleOpenAiBody) }, connectorMetricsService) + ).rejects.toThrow('API Error'); }); }); describe('streamApi', () => { it('the OpenAI API call is successful with correct parameters when stream = false', async () => { - const response = await connector.streamApi({ - body: JSON.stringify(sampleOpenAiBody), - stream: false, - }); + const response = await connector.streamApi( + { + body: JSON.stringify(sampleOpenAiBody), + stream: false, + }, + connectorMetricsService + ); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - url: 'https://api.openai.com/v1/chat/completions', - method: 'post', - responseSchema: RunActionResponseSchema, - data: JSON.stringify({ ...sampleOpenAiBody, stream: false, model: DEFAULT_OPENAI_MODEL }), - headers: { - Authorization: 'Bearer 123', - 'X-My-Custom-Header': 'foo', - 'content-type': 'application/json', + expect(mockRequest).toHaveBeenCalledWith( + { + url: 'https://api.openai.com/v1/chat/completions', + method: 'post', + responseSchema: RunActionResponseSchema, + data: JSON.stringify({ + ...sampleOpenAiBody, + stream: false, + model: DEFAULT_OPENAI_MODEL, + }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, }, - }); + connectorMetricsService + ); expect(response).toEqual(mockResponse.data); }); it('the OpenAI API call is successful with correct parameters when stream = true', async () => { - const response = await connector.streamApi({ - body: JSON.stringify(sampleOpenAiBody), - stream: true, - }); + const response = await connector.streamApi( + { + body: JSON.stringify(sampleOpenAiBody), + stream: true, + }, + connectorMetricsService + ); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - responseType: 'stream', - url: 'https://api.openai.com/v1/chat/completions', - method: 'post', - responseSchema: StreamingResponseSchema, - data: JSON.stringify({ ...sampleOpenAiBody, stream: true, model: DEFAULT_OPENAI_MODEL }), - headers: { - Authorization: 'Bearer 123', - 'X-My-Custom-Header': 'foo', - 'content-type': 'application/json', + expect(mockRequest).toHaveBeenCalledWith( + { + responseType: 'stream', + url: 'https://api.openai.com/v1/chat/completions', + method: 'post', + responseSchema: StreamingResponseSchema, + data: JSON.stringify({ + ...sampleOpenAiBody, + stream: true, + model: DEFAULT_OPENAI_MODEL, + }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, }, - }); + connectorMetricsService + ); expect(response).toEqual({ headers: { 'Content-Type': 'dont-compress-this' }, ...mockResponse.data, @@ -255,29 +311,35 @@ describe('OpenAIConnector', () => { }, ], }; - const response = await connector.streamApi({ - body: JSON.stringify({ - ...body, - stream: false, - }), - stream: true, - }); - expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - responseType: 'stream', - url: 'https://api.openai.com/v1/chat/completions', - method: 'post', - responseSchema: StreamingResponseSchema, - data: JSON.stringify({ - ...body, + const response = await connector.streamApi( + { + body: JSON.stringify({ + ...body, + stream: false, + }), stream: true, - }), - headers: { - Authorization: 'Bearer 123', - 'X-My-Custom-Header': 'foo', - 'content-type': 'application/json', }, - }); + connectorMetricsService + ); + expect(mockRequest).toBeCalledTimes(1); + expect(mockRequest).toHaveBeenCalledWith( + { + responseType: 'stream', + url: 'https://api.openai.com/v1/chat/completions', + method: 'post', + responseSchema: StreamingResponseSchema, + data: JSON.stringify({ + ...body, + stream: true, + }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, + }, + connectorMetricsService + ); expect(response).toEqual({ headers: { 'Content-Type': 'dont-compress-this' }, ...mockResponse.data, @@ -289,7 +351,10 @@ describe('OpenAIConnector', () => { connector.request = mockError; await expect( - connector.streamApi({ body: JSON.stringify(sampleOpenAiBody), stream: true }) + connector.streamApi( + { body: JSON.stringify(sampleOpenAiBody), stream: true }, + connectorMetricsService + ) ).rejects.toThrow('API Error'); }); }); @@ -314,135 +379,181 @@ describe('OpenAIConnector', () => { }); it('the API call is successful with correct request parameters', async () => { - await connector.invokeStream(sampleOpenAiBody); + await connector.invokeStream(sampleOpenAiBody, connectorMetricsService); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - url: 'https://api.openai.com/v1/chat/completions', - method: 'post', - responseSchema: StreamingResponseSchema, - responseType: 'stream', - data: JSON.stringify({ ...sampleOpenAiBody, stream: true, model: DEFAULT_OPENAI_MODEL }), - headers: { - Authorization: 'Bearer 123', - 'X-My-Custom-Header': 'foo', - 'content-type': 'application/json', + expect(mockRequest).toHaveBeenCalledWith( + { + url: 'https://api.openai.com/v1/chat/completions', + method: 'post', + responseSchema: StreamingResponseSchema, + responseType: 'stream', + data: JSON.stringify({ + ...sampleOpenAiBody, + stream: true, + model: DEFAULT_OPENAI_MODEL, + }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, }, - }); + connectorMetricsService + ); }); it('signal is properly passed to streamApi', async () => { const signal = jest.fn(); - await connector.invokeStream({ ...sampleOpenAiBody, signal }); - - expect(mockRequest).toHaveBeenCalledWith({ - url: 'https://api.openai.com/v1/chat/completions', - method: 'post', - responseSchema: StreamingResponseSchema, - responseType: 'stream', - data: JSON.stringify({ ...sampleOpenAiBody, stream: true, model: DEFAULT_OPENAI_MODEL }), - headers: { - Authorization: 'Bearer 123', - 'X-My-Custom-Header': 'foo', - 'content-type': 'application/json', - }, - signal, - }); + await connector.invokeStream({ ...sampleOpenAiBody, signal }, connectorMetricsService); + + expect(mockRequest).toHaveBeenCalledWith( + { + url: 'https://api.openai.com/v1/chat/completions', + method: 'post', + responseSchema: StreamingResponseSchema, + responseType: 'stream', + data: JSON.stringify({ + ...sampleOpenAiBody, + stream: true, + model: DEFAULT_OPENAI_MODEL, + }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, + signal, + }, + connectorMetricsService + ); }); it('timeout is properly passed to streamApi', async () => { const timeout = 180000; - await connector.invokeStream({ ...sampleOpenAiBody, timeout }); - - expect(mockRequest).toHaveBeenCalledWith({ - url: 'https://api.openai.com/v1/chat/completions', - method: 'post', - responseSchema: StreamingResponseSchema, - responseType: 'stream', - data: JSON.stringify({ ...sampleOpenAiBody, stream: true, model: DEFAULT_OPENAI_MODEL }), - headers: { - Authorization: 'Bearer 123', - 'X-My-Custom-Header': 'foo', - 'content-type': 'application/json', - }, - timeout, - }); + await connector.invokeStream({ ...sampleOpenAiBody, timeout }, connectorMetricsService); + + expect(mockRequest).toHaveBeenCalledWith( + { + url: 'https://api.openai.com/v1/chat/completions', + method: 'post', + responseSchema: StreamingResponseSchema, + responseType: 'stream', + data: JSON.stringify({ + ...sampleOpenAiBody, + stream: true, + model: DEFAULT_OPENAI_MODEL, + }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, + timeout, + }, + connectorMetricsService + ); }); it('errors during API calls are properly handled', async () => { // @ts-ignore connector.request = mockError; - await expect(connector.invokeStream(sampleOpenAiBody)).rejects.toThrow('API Error'); + await expect( + connector.invokeStream(sampleOpenAiBody, connectorMetricsService) + ).rejects.toThrow('API Error'); }); it('responds with a readable stream', async () => { // @ts-ignore connector.request = mockStream(); - const response = await connector.invokeStream(sampleOpenAiBody); + const response = await connector.invokeStream(sampleOpenAiBody, connectorMetricsService); expect(response instanceof PassThrough).toEqual(true); }); }); describe('invokeAI', () => { it('the API call is successful with correct parameters', async () => { - const response = await connector.invokeAI(sampleOpenAiBody); + const response = await connector.invokeAI(sampleOpenAiBody, connectorMetricsService); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - ...mockDefaults, - data: JSON.stringify({ ...sampleOpenAiBody, stream: false, model: DEFAULT_OPENAI_MODEL }), - headers: { - Authorization: 'Bearer 123', - 'X-My-Custom-Header': 'foo', - 'content-type': 'application/json', + expect(mockRequest).toHaveBeenCalledWith( + { + ...mockDefaults, + data: JSON.stringify({ + ...sampleOpenAiBody, + stream: false, + model: DEFAULT_OPENAI_MODEL, + }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, }, - }); + connectorMetricsService + ); expect(response.message).toEqual(mockResponseString); expect(response.usage.total_tokens).toEqual(9); }); it('signal is properly passed to runApi', async () => { const signal = jest.fn(); - await connector.invokeAI({ ...sampleOpenAiBody, signal }); + await connector.invokeAI({ ...sampleOpenAiBody, signal }, connectorMetricsService); - expect(mockRequest).toHaveBeenCalledWith({ - ...mockDefaults, - data: JSON.stringify({ ...sampleOpenAiBody, stream: false, model: DEFAULT_OPENAI_MODEL }), - headers: { - Authorization: 'Bearer 123', - 'X-My-Custom-Header': 'foo', - 'content-type': 'application/json', + expect(mockRequest).toHaveBeenCalledWith( + { + ...mockDefaults, + data: JSON.stringify({ + ...sampleOpenAiBody, + stream: false, + model: DEFAULT_OPENAI_MODEL, + }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, + signal, }, - signal, - }); + connectorMetricsService + ); }); it('timeout is properly passed to runApi', async () => { const timeout = 180000; - await connector.invokeAI({ ...sampleOpenAiBody, timeout }); + await connector.invokeAI({ ...sampleOpenAiBody, timeout }, connectorMetricsService); - expect(mockRequest).toHaveBeenCalledWith({ - ...mockDefaults, - data: JSON.stringify({ ...sampleOpenAiBody, stream: false, model: DEFAULT_OPENAI_MODEL }), - headers: { - Authorization: 'Bearer 123', - 'X-My-Custom-Header': 'foo', - 'content-type': 'application/json', + expect(mockRequest).toHaveBeenCalledWith( + { + ...mockDefaults, + data: JSON.stringify({ + ...sampleOpenAiBody, + stream: false, + model: DEFAULT_OPENAI_MODEL, + }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, + timeout, }, - timeout, - }); + connectorMetricsService + ); }); it('errors during API calls are properly handled', async () => { // @ts-ignore connector.request = mockError; - await expect(connector.invokeAI(sampleOpenAiBody)).rejects.toThrow('API Error'); + await expect(connector.invokeAI(sampleOpenAiBody, connectorMetricsService)).rejects.toThrow( + 'API Error' + ); }); }); describe('invokeAsyncIterator', () => { it('the API call is successful with correct request parameters', async () => { - await connector.invokeAsyncIterator(sampleOpenAiBody); + await connector.invokeAsyncIterator(sampleOpenAiBody, connectorMetricsService); expect(mockRequest).toBeCalledTimes(0); expect(mockCreate).toHaveBeenCalledWith( { @@ -457,7 +568,10 @@ describe('OpenAIConnector', () => { it('signal and timeout is properly passed', async () => { const timeout = 180000; const signal = jest.fn(); - await connector.invokeAsyncIterator({ ...sampleOpenAiBody, signal, timeout }); + await connector.invokeAsyncIterator( + { ...sampleOpenAiBody, signal, timeout }, + connectorMetricsService + ); expect(mockRequest).toBeCalledTimes(0); expect(mockCreate).toHaveBeenCalledWith( { @@ -478,7 +592,9 @@ describe('OpenAIConnector', () => { throw new Error('API Error'); }); - await expect(connector.invokeAsyncIterator(sampleOpenAiBody)).rejects.toThrow('API Error'); + await expect( + connector.invokeAsyncIterator(sampleOpenAiBody, connectorMetricsService) + ).rejects.toThrow('API Error'); }); }); describe('getResponseErrorMessage', () => { @@ -568,16 +684,26 @@ describe('OpenAIConnector', () => { describe('runApi', () => { it('uses the default model if none is supplied', async () => { - const response = await connector.runApi({ body: JSON.stringify(sampleOpenAiBody) }); + const response = await connector.runApi( + { body: JSON.stringify(sampleOpenAiBody) }, + connectorMetricsService + ); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - ...mockDefaults, - data: JSON.stringify({ ...sampleOpenAiBody, stream: false, model: DEFAULT_OPENAI_MODEL }), - headers: { - Authorization: 'Bearer 123', - 'content-type': 'application/json', + expect(mockRequest).toHaveBeenCalledWith( + { + ...mockDefaults, + data: JSON.stringify({ + ...sampleOpenAiBody, + stream: false, + model: DEFAULT_OPENAI_MODEL, + }), + headers: { + Authorization: 'Bearer 123', + 'content-type': 'application/json', + }, }, - }); + connectorMetricsService + ); expect(response).toEqual(mockResponse.data); }); }); @@ -614,17 +740,23 @@ describe('OpenAIConnector', () => { describe('runApi', () => { it('test the AzureAI API call is successful with correct parameters', async () => { - const response = await connector.runApi({ body: JSON.stringify(sampleAzureAiBody) }); + const response = await connector.runApi( + { body: JSON.stringify(sampleAzureAiBody) }, + connectorMetricsService + ); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - ...mockDefaults, - url: 'https://My-test-resource-123.openai.azure.com/openai/deployments/NEW-DEPLOYMENT-321/chat/completions?api-version=2023-05-15', - data: JSON.stringify({ ...sampleAzureAiBody, stream: false }), - headers: { - 'api-key': '123', - 'content-type': 'application/json', + expect(mockRequest).toHaveBeenCalledWith( + { + ...mockDefaults, + url: 'https://My-test-resource-123.openai.azure.com/openai/deployments/NEW-DEPLOYMENT-321/chat/completions?api-version=2023-05-15', + data: JSON.stringify({ ...sampleAzureAiBody, stream: false }), + headers: { + 'api-key': '123', + 'content-type': 'application/json', + }, }, - }); + connectorMetricsService + ); expect(response).toEqual(mockResponse.data); }); @@ -637,19 +769,25 @@ describe('OpenAIConnector', () => { }, ], }; - const response = await connector.runApi({ - body: JSON.stringify({ ...body, stream: true }), - }); + const response = await connector.runApi( + { + body: JSON.stringify({ ...body, stream: true }), + }, + connectorMetricsService + ); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - ...mockDefaults, - url: 'https://My-test-resource-123.openai.azure.com/openai/deployments/NEW-DEPLOYMENT-321/chat/completions?api-version=2023-05-15', - data: JSON.stringify({ ...sampleAzureAiBody, stream: false }), - headers: { - 'api-key': '123', - 'content-type': 'application/json', + expect(mockRequest).toHaveBeenCalledWith( + { + ...mockDefaults, + url: 'https://My-test-resource-123.openai.azure.com/openai/deployments/NEW-DEPLOYMENT-321/chat/completions?api-version=2023-05-15', + data: JSON.stringify({ ...sampleAzureAiBody, stream: false }), + headers: { + 'api-key': '123', + 'content-type': 'application/json', + }, }, - }); + connectorMetricsService + ); expect(response).toEqual(mockResponse.data); }); @@ -657,49 +795,61 @@ describe('OpenAIConnector', () => { // @ts-ignore connector.request = mockError; - await expect(connector.runApi({ body: JSON.stringify(sampleAzureAiBody) })).rejects.toThrow( - 'API Error' - ); + await expect( + connector.runApi({ body: JSON.stringify(sampleAzureAiBody) }, connectorMetricsService) + ).rejects.toThrow('API Error'); }); }); describe('streamApi', () => { it('the AzureAI API call is successful with correct parameters when stream = false', async () => { - const response = await connector.streamApi({ - body: JSON.stringify(sampleAzureAiBody), - stream: false, - }); + const response = await connector.streamApi( + { + body: JSON.stringify(sampleAzureAiBody), + stream: false, + }, + connectorMetricsService + ); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - url: 'https://My-test-resource-123.openai.azure.com/openai/deployments/NEW-DEPLOYMENT-321/chat/completions?api-version=2023-05-15', - method: 'post', - responseSchema: RunActionResponseSchema, - data: JSON.stringify({ ...sampleAzureAiBody, stream: false }), - headers: { - 'api-key': '123', - 'content-type': 'application/json', + expect(mockRequest).toHaveBeenCalledWith( + { + url: 'https://My-test-resource-123.openai.azure.com/openai/deployments/NEW-DEPLOYMENT-321/chat/completions?api-version=2023-05-15', + method: 'post', + responseSchema: RunActionResponseSchema, + data: JSON.stringify({ ...sampleAzureAiBody, stream: false }), + headers: { + 'api-key': '123', + 'content-type': 'application/json', + }, }, - }); + connectorMetricsService + ); expect(response).toEqual(mockResponse.data); }); it('the AzureAI API call is successful with correct parameters when stream = true', async () => { - const response = await connector.streamApi({ - body: JSON.stringify(sampleAzureAiBody), - stream: true, - }); + const response = await connector.streamApi( + { + body: JSON.stringify(sampleAzureAiBody), + stream: true, + }, + connectorMetricsService + ); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - responseType: 'stream', - url: 'https://My-test-resource-123.openai.azure.com/openai/deployments/NEW-DEPLOYMENT-321/chat/completions?api-version=2023-05-15', - method: 'post', - responseSchema: StreamingResponseSchema, - data: JSON.stringify({ ...sampleAzureAiBody, stream: true }), - headers: { - 'api-key': '123', - 'content-type': 'application/json', + expect(mockRequest).toHaveBeenCalledWith( + { + responseType: 'stream', + url: 'https://My-test-resource-123.openai.azure.com/openai/deployments/NEW-DEPLOYMENT-321/chat/completions?api-version=2023-05-15', + method: 'post', + responseSchema: StreamingResponseSchema, + data: JSON.stringify({ ...sampleAzureAiBody, stream: true }), + headers: { + 'api-key': '123', + 'content-type': 'application/json', + }, }, - }); + connectorMetricsService + ); expect(response).toEqual({ headers: { 'Content-Type': 'dont-compress-this' }, ...mockResponse.data, @@ -715,25 +865,31 @@ describe('OpenAIConnector', () => { }, ], }; - const response = await connector.streamApi({ - body: JSON.stringify({ ...body, stream: false }), - stream: true, - }); - expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - responseType: 'stream', - url: 'https://My-test-resource-123.openai.azure.com/openai/deployments/NEW-DEPLOYMENT-321/chat/completions?api-version=2023-05-15', - method: 'post', - responseSchema: StreamingResponseSchema, - data: JSON.stringify({ - ...body, + const response = await connector.streamApi( + { + body: JSON.stringify({ ...body, stream: false }), stream: true, - }), - headers: { - 'api-key': '123', - 'content-type': 'application/json', }, - }); + connectorMetricsService + ); + expect(mockRequest).toBeCalledTimes(1); + expect(mockRequest).toHaveBeenCalledWith( + { + responseType: 'stream', + url: 'https://My-test-resource-123.openai.azure.com/openai/deployments/NEW-DEPLOYMENT-321/chat/completions?api-version=2023-05-15', + method: 'post', + responseSchema: StreamingResponseSchema, + data: JSON.stringify({ + ...body, + stream: true, + }), + headers: { + 'api-key': '123', + 'content-type': 'application/json', + }, + }, + connectorMetricsService + ); expect(response).toEqual({ headers: { 'Content-Type': 'dont-compress-this' }, ...mockResponse.data, @@ -745,7 +901,10 @@ describe('OpenAIConnector', () => { connector.request = mockError; await expect( - connector.streamApi({ body: JSON.stringify(sampleAzureAiBody), stream: true }) + connector.streamApi( + { body: JSON.stringify(sampleAzureAiBody), stream: true }, + connectorMetricsService + ) ).rejects.toThrow('API Error'); }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.ts b/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.ts index 544b6bf7092c2..682cfa95a678a 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.ts @@ -16,6 +16,7 @@ import { ChatCompletionMessageParam, } from 'openai/resources/chat/completions'; import { Stream } from 'openai/streaming'; +import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; import { removeEndpointFromUrl } from './lib/openai_utils'; import { RunActionParamsSchema, @@ -156,7 +157,11 @@ export class OpenAIConnector extends SubActionConnector { * responsible for making a POST request to the external API endpoint and returning the response data * @param body The stringified request body to be sent in the POST request. */ - public async runApi({ body, signal, timeout }: RunActionParams): Promise { + + public async runApi( + { body, signal, timeout }: RunActionParams, + connectorMetricsService: ConnectorMetricsService + ): Promise { const sanitizedBody = sanitizeRequest( this.provider, this.url, @@ -164,20 +169,23 @@ export class OpenAIConnector extends SubActionConnector { ...('defaultModel' in this.config ? [this.config.defaultModel] : []) ); const axiosOptions = getAxiosOptions(this.provider, this.key, false); - const response = await this.request({ - url: this.url, - method: 'post', - responseSchema: RunActionResponseSchema, - data: sanitizedBody, - signal, - // give up to 2 minutes for response - timeout: timeout ?? DEFAULT_TIMEOUT_MS, - ...axiosOptions, - headers: { - ...this.config.headers, - ...axiosOptions.headers, + const response = await this.request( + { + url: this.url, + method: 'post', + responseSchema: RunActionResponseSchema, + data: sanitizedBody, + signal, + // give up to 2 minutes for response + timeout: timeout ?? DEFAULT_TIMEOUT_MS, + ...axiosOptions, + headers: { + ...this.config.headers, + ...axiosOptions.headers, + }, }, - }); + connectorMetricsService + ); return response.data; } @@ -189,12 +197,10 @@ export class OpenAIConnector extends SubActionConnector { * @param body request body for the API request * @param stream flag indicating whether it is a streaming request or not */ - public async streamApi({ - body, - stream, - signal, - timeout, - }: StreamActionParams): Promise { + public async streamApi( + { body, stream, signal, timeout }: StreamActionParams, + connectorMetricsService: ConnectorMetricsService + ): Promise { const executeBody = getRequestWithStreamOption( this.provider, this.url, @@ -205,19 +211,22 @@ export class OpenAIConnector extends SubActionConnector { const axiosOptions = getAxiosOptions(this.provider, this.key, stream); - const response = await this.request({ - url: this.url, - method: 'post', - responseSchema: stream ? StreamingResponseSchema : RunActionResponseSchema, - data: executeBody, - signal, - ...axiosOptions, - headers: { - ...this.config.headers, - ...axiosOptions.headers, + const response = await this.request( + { + url: this.url, + method: 'post', + responseSchema: stream ? StreamingResponseSchema : RunActionResponseSchema, + data: executeBody, + signal, + ...axiosOptions, + headers: { + ...this.config.headers, + ...axiosOptions.headers, + }, + timeout, }, - timeout, - }); + connectorMetricsService + ); return stream ? pipeStreamingResponse(response) : response.data; } @@ -264,15 +273,21 @@ export class OpenAIConnector extends SubActionConnector { * returned directly to the client for streaming * @param body - the OpenAI Invoke request body */ - public async invokeStream(body: InvokeAIActionParams): Promise { + public async invokeStream( + body: InvokeAIActionParams, + connectorMetricsService: ConnectorMetricsService + ): Promise { const { signal, timeout, ...rest } = body; - const res = (await this.streamApi({ - body: JSON.stringify(rest), - stream: true, - signal, - timeout, // do not default if not provided - })) as unknown as IncomingMessage; + const res = (await this.streamApi( + { + body: JSON.stringify(rest), + stream: true, + signal, + timeout, // do not default if not provided + }, + connectorMetricsService + )) as unknown as IncomingMessage; return res.pipe(new PassThrough()); } @@ -286,7 +301,10 @@ export class OpenAIConnector extends SubActionConnector { * tokenCountStream: Stream; the result for token counting stream * } */ - public async invokeAsyncIterator(body: InvokeAIActionParams): Promise<{ + public async invokeAsyncIterator( + body: InvokeAIActionParams, + connectorMetricsService: ConnectorMetricsService + ): Promise<{ consumerStream: Stream; tokenCountStream: Stream; }> { @@ -301,6 +319,8 @@ export class OpenAIConnector extends SubActionConnector { rest.model ?? ('defaultModel' in this.config ? this.config.defaultModel : DEFAULT_OPENAI_MODEL), }; + + connectorMetricsService.addRequestBodyBytes(undefined, requestBody); const stream = await this.openAI.chat.completions.create(requestBody, { signal, timeout, // do not default if not provided @@ -323,9 +343,15 @@ export class OpenAIConnector extends SubActionConnector { * @param body - the OpenAI chat completion request body * @returns an object with the response string and the usage object */ - public async invokeAI(body: InvokeAIActionParams): Promise { + public async invokeAI( + body: InvokeAIActionParams, + connectorMetricsService: ConnectorMetricsService + ): Promise { const { signal, timeout, ...rest } = body; - const res = await this.runApi({ body: JSON.stringify(rest), signal, timeout }); + const res = await this.runApi( + { body: JSON.stringify(rest), signal, timeout }, + connectorMetricsService + ); if (res.choices && res.choices.length > 0 && res.choices[0].message?.content) { const result = res.choices[0].message.content.trim(); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.test.ts index fb11174e20ba5..4b01301ca3d91 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.test.ts @@ -15,6 +15,7 @@ import { MockedLogger } from '@kbn/logging-mocks'; import { OpsgenieConnectorTypeId } from '../../../common'; import { OpsgenieConnector } from './connector'; import * as utils from '@kbn/actions-plugin/server/lib/axios_utils'; +import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; jest.mock('axios'); @@ -36,6 +37,7 @@ describe('OpsgenieConnector', () => { let mockedActionsConfig: jest.Mocked; let logger: MockedLogger; let services: ReturnType; + let connectorMetricsService: ConnectorMetricsService; const defaultCreateAlertExpect = { method: 'post', @@ -75,36 +77,40 @@ describe('OpsgenieConnector', () => { logger, services, }); + connectorMetricsService = new ConnectorMetricsService(); }); it('calls request with the correct arguments for creating an alert', async () => { - await connector.createAlert({ message: 'hello' }); + await connector.createAlert({ message: 'hello' }, connectorMetricsService); expect(requestMock.mock.calls[0][0]).toEqual({ data: { message: 'hello' }, ...ignoredRequestFields, ...defaultCreateAlertExpect, + connectorMetricsService, }); }); it('calls request without modifying the alias when it is less than 512 characters when creating an alert', async () => { - await connector.createAlert({ message: 'hello', alias: '111' }); + await connector.createAlert({ message: 'hello', alias: '111' }, connectorMetricsService); expect(requestMock.mock.calls[0][0]).toEqual({ ...ignoredRequestFields, ...defaultCreateAlertExpect, data: { message: 'hello', alias: '111' }, + connectorMetricsService, }); }); it('calls request without modifying the alias when it is equal to 512 characters when creating an alert', async () => { const alias = 'a'.repeat(512); - await connector.createAlert({ message: 'hello', alias }); + await connector.createAlert({ message: 'hello', alias }, connectorMetricsService); expect(requestMock.mock.calls[0][0]).toEqual({ ...ignoredRequestFields, ...defaultCreateAlertExpect, data: { message: 'hello', alias }, + connectorMetricsService, }); }); @@ -114,12 +120,13 @@ describe('OpsgenieConnector', () => { const hasher = crypto.createHash('sha256'); const sha256Hash = hasher.update(alias); - await connector.createAlert({ message: 'hello', alias }); + await connector.createAlert({ message: 'hello', alias }, connectorMetricsService); expect(requestMock.mock.calls[0][0]).toEqual({ ...ignoredRequestFields, ...defaultCreateAlertExpect, data: { message: 'hello', alias: `sha-${sha256Hash.digest('hex')}` }, + connectorMetricsService, }); }); @@ -129,22 +136,24 @@ describe('OpsgenieConnector', () => { const hasher = crypto.createHash('sha256'); const sha256Hash = hasher.update(alias); - await connector.closeAlert({ alias }); + await connector.closeAlert({ alias }, connectorMetricsService); expect(requestMock.mock.calls[0][0]).toEqual({ ...ignoredRequestFields, ...createCloseAlertExpect(`sha-${sha256Hash.digest('hex')}`), data: {}, + connectorMetricsService, }); }); it('calls request with the correct arguments for closing an alert', async () => { - await connector.closeAlert({ user: 'sam', alias: '111' }); + await connector.closeAlert({ user: 'sam', alias: '111' }, connectorMetricsService); expect(requestMock.mock.calls[0][0]).toEqual({ ...ignoredRequestFields, ...createCloseAlertExpect('111'), data: { user: 'sam' }, + connectorMetricsService, }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.ts b/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.ts index cd86a8ac7542a..6091734c0b51c 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.ts @@ -9,6 +9,7 @@ import crypto from 'crypto'; import { ServiceParams, SubActionConnector } from '@kbn/actions-plugin/server'; import { AxiosError } from 'axios'; import { isEmpty } from 'lodash'; +import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; import { OpsgenieSubActions } from '../../../common'; import { CreateAlertParamsSchema, CloseAlertParamsSchema, Response } from './schema'; import { CloseAlertParams, Config, CreateAlertParams, FailureResponseType, Secrets } from './types'; @@ -67,14 +68,20 @@ export class OpsgenieConnector extends SubActionConnector { } } - public async createAlert(params: CreateAlertParams) { - const res = await this.request({ - method: 'post', - url: this.concatPathToURL('v2/alerts').toString(), - data: { ...params, ...OpsgenieConnector.createAliasObj(params.alias) }, - headers: this.createHeaders(), - responseSchema: Response, - }); + public async createAlert( + params: CreateAlertParams, + connectorMetricsService: ConnectorMetricsService + ) { + const res = await this.request( + { + method: 'post', + url: this.concatPathToURL('v2/alerts').toString(), + data: { ...params, ...OpsgenieConnector.createAliasObj(params.alias) }, + headers: this.createHeaders(), + responseSchema: Response, + }, + connectorMetricsService + ); return res.data; } @@ -107,7 +114,10 @@ export class OpsgenieConnector extends SubActionConnector { return { Authorization: `GenieKey ${this.secrets.apiKey}` }; } - public async closeAlert(params: CloseAlertParams) { + public async closeAlert( + params: CloseAlertParams, + connectorMetricsService: ConnectorMetricsService + ) { const newAlias = OpsgenieConnector.createAlias(params.alias); const fullURL = this.concatPathToURL(`v2/alerts/${newAlias}/close`); @@ -115,13 +125,16 @@ export class OpsgenieConnector extends SubActionConnector { const { alias, ...paramsWithoutAlias } = params; - const res = await this.request({ - method: 'post', - url: fullURL.toString(), - data: paramsWithoutAlias, - headers: this.createHeaders(), - responseSchema: Response, - }); + const res = await this.request( + { + method: 'post', + url: fullURL.toString(), + data: paramsWithoutAlias, + headers: this.createHeaders(), + responseSchema: Response, + }, + connectorMetricsService + ); return res.data; } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.test.ts index 86cdca4740f6d..9446221ea2f1a 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.test.ts @@ -10,7 +10,7 @@ import moment from 'moment'; jest.mock('./post_pagerduty', () => ({ postPagerduty: jest.fn(), })); -import { Services } from '@kbn/actions-plugin/server/types'; +import { ConnectorMetricsService, Services } from '@kbn/actions-plugin/server/types'; import { validateConfig, validateSecrets, validateParams } from '@kbn/actions-plugin/server/lib'; import { postPagerduty } from './post_pagerduty'; import { Logger } from '@kbn/core/server'; @@ -31,10 +31,12 @@ const mockedLogger: jest.Mocked = loggerMock.create(); let connectorType: PagerDutyConnectorType; let configurationUtilities: jest.Mocked; +let connectorMetricsService: ConnectorMetricsService; beforeEach(() => { configurationUtilities = actionsConfigMock.create(); connectorType = getConnectorType(); + connectorMetricsService = new ConnectorMetricsService(); }); describe('get()', () => { @@ -269,6 +271,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, + connectorMetricsService, }; const actionResponse = await connectorType.executor(executorOptions); const { apiUrl, data, headers } = postPagerdutyMock.mock.calls[0][0]; @@ -350,6 +353,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, + connectorMetricsService, }; const actionResponse = await connectorType.executor(executorOptions); const { apiUrl, data, headers } = postPagerdutyMock.mock.calls[0][0]; @@ -458,6 +462,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, + connectorMetricsService, }; const actionResponse = await connectorType.executor(executorOptions); const { apiUrl, data, headers } = postPagerdutyMock.mock.calls[0][0]; @@ -535,6 +540,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, + connectorMetricsService, }; const actionResponse = await connectorType.executor(executorOptions); const { apiUrl, data, headers } = postPagerdutyMock.mock.calls[0][0]; @@ -578,6 +584,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, + connectorMetricsService, }; const actionResponse = await connectorType.executor(executorOptions); expect(actionResponse).toMatchInlineSnapshot(` @@ -608,6 +615,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, + connectorMetricsService, }; const actionResponse = await connectorType.executor(executorOptions); expect(actionResponse).toMatchInlineSnapshot(` @@ -638,6 +646,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, + connectorMetricsService, }; const actionResponse = await connectorType.executor(executorOptions); expect(actionResponse).toMatchInlineSnapshot(` @@ -668,6 +677,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, + connectorMetricsService, }; const actionResponse = await connectorType.executor(executorOptions); expect(actionResponse).toMatchInlineSnapshot(` @@ -708,6 +718,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, + connectorMetricsService, }; const actionResponse = await connectorType.executor(executorOptions); const { apiUrl, data, headers } = postPagerdutyMock.mock.calls[0][0]; @@ -771,6 +782,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, + connectorMetricsService, }; const actionResponse = await connectorType.executor(executorOptions); const { apiUrl, data, headers } = postPagerdutyMock.mock.calls[0][0]; @@ -837,6 +849,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, + connectorMetricsService, }; const actionResponse = await connectorType.executor(executorOptions); const { apiUrl, data, headers } = postPagerdutyMock.mock.calls[0][0]; @@ -902,6 +915,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, + connectorMetricsService, }; const actionResponse = await connectorType.executor(executorOptions); const { apiUrl, data, headers } = postPagerdutyMock.mock.calls[0][0]; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.ts index cfd11d6803df8..319f38125face 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.ts @@ -198,8 +198,16 @@ function getPagerDutyApiUrl(config: ConnectorTypeConfigType): string { async function executor( execOptions: PagerDutyConnectorTypeExecutorOptions ): Promise> { - const { actionId, config, secrets, params, services, configurationUtilities, logger } = - execOptions; + const { + actionId, + config, + secrets, + params, + services, + configurationUtilities, + logger, + connectorMetricsService, + } = execOptions; const apiUrl = getPagerDutyApiUrl(config); const headers = { @@ -213,7 +221,8 @@ async function executor( response = await postPagerduty( { apiUrl, data, headers, services }, logger, - configurationUtilities + configurationUtilities, + connectorMetricsService ); } catch (err) { const message = i18n.translate('xpack.stackConnectors.pagerduty.postingErrorMessage', { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/post_pagerduty.ts b/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/post_pagerduty.ts index 0ef41637967d2..7754e02f3c0a3 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/post_pagerduty.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/post_pagerduty.ts @@ -7,7 +7,7 @@ import axios, { AxiosResponse } from 'axios'; import { Logger } from '@kbn/core/server'; -import { Services } from '@kbn/actions-plugin/server/types'; +import { ConnectorMetricsService, Services } from '@kbn/actions-plugin/server/types'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; import { request } from '@kbn/actions-plugin/server/lib/axios_utils'; @@ -22,7 +22,8 @@ interface PostPagerdutyOptions { export async function postPagerduty( options: PostPagerdutyOptions, logger: Logger, - configurationUtilities: ActionsConfigurationUtilities + configurationUtilities: ActionsConfigurationUtilities, + connectorMetricsService: ConnectorMetricsService ): Promise { const { apiUrl, data, headers } = options; const axiosInstance = axios.create(); @@ -36,5 +37,6 @@ export async function postPagerduty( headers, configurationUtilities, validateStatus: () => true, + connectorMetricsService, }); } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.test.ts index 4e031bdaafeea..fa1e591f82ebb 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.test.ts @@ -13,6 +13,7 @@ import { ResilientConnector } from './resilient'; import { actionsMock } from '@kbn/actions-plugin/server/mocks'; import { RESILIENT_CONNECTOR_ID } from './constants'; import { PushToServiceIncidentSchema } from './schema'; +import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; jest.mock('axios'); jest.mock('@kbn/actions-plugin/server/lib/axios_utils', () => { @@ -83,6 +84,7 @@ const mockIncidentUpdate = (withUpdateError = false) => { }) ); }; +let connectorMetricsService: ConnectorMetricsService; describe('IBM Resilient connector', () => { const connector = new ResilientConnector( @@ -107,6 +109,7 @@ describe('IBM Resilient connector', () => { beforeEach(() => { jest.resetAllMocks(); jest.setSystemTime(TIMESTAMP); + connectorMetricsService = new ConnectorMetricsService(); }); describe('getIncident', () => { @@ -129,12 +132,12 @@ describe('IBM Resilient connector', () => { }); it('returns the incident correctly', async () => { - const res = await connector.getIncident({ id: '1' }); + const res = await connector.getIncident({ id: '1' }, connectorMetricsService); expect(res).toEqual(incidentMock); }); it('should call request with correct arguments', async () => { - await connector.getIncident({ id: '1' }); + await connector.getIncident({ id: '1' }, connectorMetricsService); expect(requestMock).toHaveBeenCalledWith({ ...ignoredRequestFields, method: 'GET', @@ -147,6 +150,7 @@ describe('IBM Resilient connector', () => { params: { text_content_output_format: 'objects_convert', }, + connectorMetricsService, }); }); @@ -154,7 +158,7 @@ describe('IBM Resilient connector', () => { requestMock.mockImplementation(() => { throw new Error('An error has occurred'); }); - await expect(connector.getIncident({ id: '1' })).rejects.toThrow( + await expect(connector.getIncident({ id: '1' }, connectorMetricsService)).rejects.toThrow( 'Unable to get incident with id 1. Error: An error has occurred' ); }); @@ -183,7 +187,7 @@ describe('IBM Resilient connector', () => { }); it('creates the incident correctly', async () => { - const res = await connector.createIncident(incidentMock); + const res = await connector.createIncident(incidentMock, connectorMetricsService); expect(res).toEqual({ title: '1', @@ -194,7 +198,7 @@ describe('IBM Resilient connector', () => { }); it('should call request with correct arguments', async () => { - await connector.createIncident(incidentMock); + await connector.createIncident(incidentMock, connectorMetricsService); expect(requestMock).toHaveBeenCalledWith({ ...ignoredRequestFields, @@ -214,6 +218,7 @@ describe('IBM Resilient connector', () => { Authorization: `Basic ${token}`, 'Content-Type': 'application/json', }, + connectorMetricsService, }); }); @@ -223,12 +228,15 @@ describe('IBM Resilient connector', () => { }); await expect( - connector.createIncident({ - name: 'title', - description: 'desc', - incidentTypes: [1001], - severityCode: 6, - }) + connector.createIncident( + { + name: 'title', + description: 'desc', + incidentTypes: [1001], + severityCode: 6, + }, + connectorMetricsService + ) ).rejects.toThrow( '[Action][IBM Resilient]: Unable to create incident. Error: An error has occurred' ); @@ -237,7 +245,7 @@ describe('IBM Resilient connector', () => { it('should throw if the required attributes are not received in response', async () => { requestMock.mockImplementation(() => createAxiosResponse({ data: { notRequired: 'test' } })); - await expect(connector.createIncident(incidentMock)).rejects.toThrow( + await expect(connector.createIncident(incidentMock, connectorMetricsService)).rejects.toThrow( '[Action][IBM Resilient]: Unable to create incident. Error: Response validation failed (Error: [id]: expected value of type [number] but got [undefined]).' ); }); @@ -255,7 +263,7 @@ describe('IBM Resilient connector', () => { }; it('updates the incident correctly', async () => { mockIncidentUpdate(); - const res = await connector.updateIncident(req); + const res = await connector.updateIncident(req, connectorMetricsService); expect(res).toEqual({ title: '1', @@ -268,15 +276,18 @@ describe('IBM Resilient connector', () => { it('should call request with correct arguments', async () => { mockIncidentUpdate(); - await connector.updateIncident({ - incidentId: '1', - incident: { - name: 'title_updated', - description: 'desc_updated', - incidentTypes: [1001], - severityCode: 5, + await connector.updateIncident( + { + incidentId: '1', + incident: { + name: 'title_updated', + description: 'desc_updated', + incidentTypes: [1001], + severityCode: 5, + }, }, - }); + connectorMetricsService + ); expect(requestMock.mock.calls[1][0]).toEqual({ ...ignoredRequestFields, @@ -332,13 +343,14 @@ describe('IBM Resilient connector', () => { }, ], }, + connectorMetricsService, }); }); it('it should throw an error', async () => { mockIncidentUpdate(true); - await expect(connector.updateIncident(req)).rejects.toThrow( + await expect(connector.updateIncident(req, connectorMetricsService)).rejects.toThrow( '[Action][IBM Resilient]: Unable to update incident with id 1. Error: An error has occurred' ); }); @@ -361,7 +373,7 @@ describe('IBM Resilient connector', () => { ); requestMock.mockImplementation(() => createAxiosResponse({ data: { notRequired: 'test' } })); - await expect(connector.updateIncident(req)).rejects.toThrow( + await expect(connector.updateIncident(req, connectorMetricsService)).rejects.toThrow( '[Action][IBM Resilient]: Unable to update incident with id 1. Error: Response validation failed (Error: [success]: expected value of type [boolean] but got [undefined]).' ); }); @@ -388,7 +400,7 @@ describe('IBM Resilient connector', () => { }); it('should call request with correct arguments', async () => { - await connector.addComment(req); + await connector.addComment(req, connectorMetricsService); expect(requestMock).toHaveBeenCalledWith({ ...ignoredRequestFields, @@ -404,6 +416,7 @@ describe('IBM Resilient connector', () => { format: 'text', }, }, + connectorMetricsService, }); }); @@ -412,7 +425,7 @@ describe('IBM Resilient connector', () => { throw new Error('An error has occurred'); }); - await expect(connector.addComment(req)).rejects.toThrow( + await expect(connector.addComment(req, connectorMetricsService)).rejects.toThrow( '[Action][IBM Resilient]: Unable to create comment at incident with id 1. Error: An error has occurred.' ); }); @@ -428,7 +441,7 @@ describe('IBM Resilient connector', () => { }); it('should call request with correct arguments', async () => { - await connector.getIncidentTypes(); + await connector.getIncidentTypes(undefined, connectorMetricsService); expect(requestMock).toBeCalledTimes(1); expect(requestMock).toHaveBeenCalledWith({ ...ignoredRequestFields, @@ -439,11 +452,12 @@ describe('IBM Resilient connector', () => { Authorization: `Basic ${token}`, 'Content-Type': 'application/json', }, + connectorMetricsService, }); }); it('returns incident types correctly', async () => { - const res = await connector.getIncidentTypes(); + const res = await connector.getIncidentTypes(undefined, connectorMetricsService); expect(res).toEqual([ { id: '17', name: 'Communication error (fax; email)' }, @@ -456,7 +470,7 @@ describe('IBM Resilient connector', () => { throw new Error('An error has occurred'); }); - await expect(connector.getIncidentTypes()).rejects.toThrow( + await expect(connector.getIncidentTypes(undefined, connectorMetricsService)).rejects.toThrow( '[Action][IBM Resilient]: Unable to get incident types. Error: An error has occurred.' ); }); @@ -466,7 +480,7 @@ describe('IBM Resilient connector', () => { createAxiosResponse({ data: { id: '1001', name: 'Custom type' } }) ); - await expect(connector.getIncidentTypes()).rejects.toThrow( + await expect(connector.getIncidentTypes(undefined, connectorMetricsService)).rejects.toThrow( '[Action][IBM Resilient]: Unable to get incident types. Error: Response validation failed (Error: [values]: expected value of type [array] but got [undefined]).' ); }); @@ -484,7 +498,7 @@ describe('IBM Resilient connector', () => { }); it('should call request with correct arguments', async () => { - await connector.getSeverity(); + await connector.getSeverity(undefined, connectorMetricsService); expect(requestMock).toBeCalledTimes(1); expect(requestMock).toHaveBeenCalledWith({ ...ignoredRequestFields, @@ -495,11 +509,12 @@ describe('IBM Resilient connector', () => { Authorization: `Basic ${token}`, 'Content-Type': 'application/json', }, + connectorMetricsService, }); }); it('returns severity correctly', async () => { - const res = await connector.getSeverity(); + const res = await connector.getSeverity(undefined, connectorMetricsService); expect(res).toEqual([ { @@ -522,7 +537,7 @@ describe('IBM Resilient connector', () => { throw new Error('An error has occurred'); }); - await expect(connector.getSeverity()).rejects.toThrow( + await expect(connector.getSeverity(undefined, connectorMetricsService)).rejects.toThrow( '[Action][IBM Resilient]: Unable to get severity. Error: An error has occurred.' ); }); @@ -532,7 +547,7 @@ describe('IBM Resilient connector', () => { createAxiosResponse({ data: { id: '10', name: 'Critical' } }) ); - await expect(connector.getSeverity()).rejects.toThrow( + await expect(connector.getSeverity(undefined, connectorMetricsService)).rejects.toThrow( '[Action][IBM Resilient]: Unable to get severity. Error: Response validation failed (Error: [values]: expected value of type [array] but got [undefined]).' ); }); @@ -547,7 +562,7 @@ describe('IBM Resilient connector', () => { ); }); it('should call request with correct arguments', async () => { - await connector.getFields(); + await connector.getFields(undefined, connectorMetricsService); expect(requestMock).toBeCalledTimes(1); expect(requestMock).toHaveBeenCalledWith({ @@ -559,11 +574,12 @@ describe('IBM Resilient connector', () => { Authorization: `Basic ${token}`, 'Content-Type': 'application/json', }, + connectorMetricsService, }); }); it('returns common fields correctly', async () => { - const res = await connector.getFields(); + const res = await connector.getFields(undefined, connectorMetricsService); expect(res).toEqual(resilientFields); }); @@ -571,7 +587,7 @@ describe('IBM Resilient connector', () => { requestMock.mockImplementation(() => { throw new Error('An error has occurred'); }); - await expect(connector.getFields()).rejects.toThrow( + await expect(connector.getFields(undefined, connectorMetricsService)).rejects.toThrow( 'Unable to get fields. Error: An error has occurred' ); }); @@ -579,7 +595,7 @@ describe('IBM Resilient connector', () => { it('should throw if the required attributes are not received in response', async () => { requestMock.mockImplementation(() => createAxiosResponse({ data: { someField: 'test' } })); - await expect(connector.getFields()).rejects.toThrow( + await expect(connector.getFields(undefined, connectorMetricsService)).rejects.toThrow( '[Action][IBM Resilient]: Unable to get fields. Error: Response validation failed (Error: expected value of type [array] but got [Object]).' ); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.ts b/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.ts index 1351488dbf892..bd7c47619c7a4 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.ts @@ -10,6 +10,7 @@ import { omitBy, isNil } from 'lodash/fp'; import { CaseConnector, getBasicAuthHeader, ServiceParams } from '@kbn/actions-plugin/server'; import { schema, Type } from '@kbn/config-schema'; import { getErrorMessage } from '@kbn/actions-plugin/server/lib/axios_utils'; +import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; import { CreateIncidentData, ExternalServiceIncidentResponse, @@ -117,7 +118,10 @@ export class ResilientConnector extends CaseConnector< return `${urlWithoutTrailingSlash}/${VIEW_INCIDENT_URL}/${key}`; } - public async createIncident(incident: Incident): Promise { + public async createIncident( + incident: Incident, + connectorMetricsService: ConnectorMetricsService + ): Promise { try { let data: CreateIncidentData = { name: incident.name, @@ -150,19 +154,22 @@ export class ResilientConnector extends CaseConnector< }; } - const res = await this.request({ - url: `${this.urls.incident}?text_content_output_format=objects_convert`, - method: 'POST', - data, - headers: this.getAuthHeaders(), - responseSchema: schema.object( - { - id: schema.number(), - create_date: schema.number(), - }, - { unknowns: 'allow' } - ), - }); + const res = await this.request( + { + url: `${this.urls.incident}?text_content_output_format=objects_convert`, + method: 'POST', + data, + headers: this.getAuthHeaders(), + responseSchema: schema.object( + { + id: schema.number(), + create_date: schema.number(), + }, + { unknowns: 'allow' } + ), + }, + connectorMetricsService + ); const { id, create_date: createDate } = res.data; @@ -179,30 +186,33 @@ export class ResilientConnector extends CaseConnector< } } - public async updateIncident({ - incidentId, - incident, - }: UpdateIncidentParams): Promise { + public async updateIncident( + { incidentId, incident }: UpdateIncidentParams, + connectorMetricsService: ConnectorMetricsService + ): Promise { try { - const latestIncident = await this.getIncident({ id: incidentId }); + const latestIncident = await this.getIncident({ id: incidentId }, connectorMetricsService); // Remove null or undefined values. Allowing null values sets the field in IBM Resilient to empty. const newIncident = omitBy(isNil, incident); const data = formatUpdateRequest({ oldIncident: latestIncident, newIncident }); - const res = await this.request({ - method: 'PATCH', - url: `${this.urls.incident}/${incidentId}`, - data, - headers: this.getAuthHeaders(), - responseSchema: schema.object({ success: schema.boolean() }, { unknowns: 'allow' }), - }); + const res = await this.request( + { + method: 'PATCH', + url: `${this.urls.incident}/${incidentId}`, + data, + headers: this.getAuthHeaders(), + responseSchema: schema.object({ success: schema.boolean() }, { unknowns: 'allow' }), + }, + connectorMetricsService + ); if (!res.data.success) { throw new Error('Error while updating incident'); } - const updatedIncident = await this.getIncident({ id: incidentId }); + const updatedIncident = await this.getIncident({ id: incidentId }, connectorMetricsService); return { title: `${updatedIncident.id}`, @@ -220,15 +230,21 @@ export class ResilientConnector extends CaseConnector< } } - public async addComment({ incidentId, comment }: { incidentId: string; comment: string }) { + public async addComment( + { incidentId, comment }: { incidentId: string; comment: string }, + connectorMetricsService: ConnectorMetricsService + ) { try { - await this.request({ - method: 'POST', - url: this.urls.comment.replace('{inc_id}', incidentId), - data: { text: { format: 'text', content: comment } }, - headers: this.getAuthHeaders(), - responseSchema: schema.object({}, { unknowns: 'allow' }), - }); + await this.request( + { + method: 'POST', + url: this.urls.comment.replace('{inc_id}', incidentId), + data: { text: { format: 'text', content: comment } }, + headers: this.getAuthHeaders(), + responseSchema: schema.object({}, { unknowns: 'allow' }), + }, + connectorMetricsService + ); } catch (error) { throw new Error( getErrorMessage( @@ -239,17 +255,23 @@ export class ResilientConnector extends CaseConnector< } } - public async getIncident({ id }: { id: string }): Promise { + public async getIncident( + { id }: { id: string }, + connectorMetricsService: ConnectorMetricsService + ): Promise { try { - const res = await this.request({ - method: 'GET', - url: `${this.urls.incident}/${id}`, - params: { - text_content_output_format: 'objects_convert', + const res = await this.request( + { + method: 'GET', + url: `${this.urls.incident}/${id}`, + params: { + text_content_output_format: 'objects_convert', + }, + headers: this.getAuthHeaders(), + responseSchema: GetIncidentResponseSchema, }, - headers: this.getAuthHeaders(), - responseSchema: GetIncidentResponseSchema, - }); + connectorMetricsService + ); return res.data; } catch (error) { @@ -259,14 +281,20 @@ export class ResilientConnector extends CaseConnector< } } - public async getIncidentTypes(): Promise { + public async getIncidentTypes( + params: unknown, + connectorMetricsService: ConnectorMetricsService + ): Promise { try { - const res = await this.request({ - method: 'GET', - url: this.urls.incidentTypes, - headers: this.getAuthHeaders(), - responseSchema: GetIncidentTypesResponseSchema, - }); + const res = await this.request( + { + method: 'GET', + url: this.urls.incidentTypes, + headers: this.getAuthHeaders(), + responseSchema: GetIncidentTypesResponseSchema, + }, + connectorMetricsService + ); const incidentTypes = res.data?.values ?? []; @@ -281,14 +309,20 @@ export class ResilientConnector extends CaseConnector< } } - public async getSeverity(): Promise { + public async getSeverity( + params: unknown, + connectorMetricsService: ConnectorMetricsService + ): Promise { try { - const res = await this.request({ - method: 'GET', - url: this.urls.severity, - headers: this.getAuthHeaders(), - responseSchema: GetSeverityResponseSchema, - }); + const res = await this.request( + { + method: 'GET', + url: this.urls.severity, + headers: this.getAuthHeaders(), + responseSchema: GetSeverityResponseSchema, + }, + connectorMetricsService + ); const severities = res.data?.values ?? []; return severities.map((type: { value: number; label: string }) => ({ @@ -302,14 +336,17 @@ export class ResilientConnector extends CaseConnector< } } - public async getFields() { + public async getFields(params: unknown, connectorMetricsService: ConnectorMetricsService) { try { - const res = await this.request({ - method: 'GET', - url: this.getIncidentFieldsUrl(), - headers: this.getAuthHeaders(), - responseSchema: GetCommonFieldsResponseSchema, - }); + const res = await this.request( + { + method: 'GET', + url: this.getIncidentFieldsUrl(), + headers: this.getAuthHeaders(), + responseSchema: GetCommonFieldsResponseSchema, + }, + connectorMetricsService + ); const fields = res.data.map((field) => { return { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.test.ts index 3dc41d461670c..1cf6104a7c008 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.test.ts @@ -13,12 +13,15 @@ import { } from '../../../common/sentinelone/types'; import { API_PATH } from './sentinelone'; import { SentinelOneGetActivitiesResponseSchema } from '../../../common/sentinelone/schema'; +import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; describe('SentinelOne Connector', () => { let connectorInstance: ReturnType; + let connectorMetricsService: ConnectorMetricsService; beforeEach(() => { connectorInstance = sentinelOneConnectorMocks.create(); + connectorMetricsService = new ConnectorMetricsService(); }); describe('#fetchAgentFiles()', () => { @@ -35,15 +38,17 @@ describe('SentinelOne Connector', () => { it('should error if agent UUID is invalid', async () => { connectorInstance.mockResponses.getAgentsApiResponse.data.length = 0; - await expect(connectorInstance.fetchAgentFiles(fetchAgentFilesParams)).rejects.toHaveProperty( - 'message', - 'No agent found in SentinelOne for UUID [uuid-1]' - ); + await expect( + connectorInstance.fetchAgentFiles(fetchAgentFilesParams, connectorMetricsService) + ).rejects.toHaveProperty('message', 'No agent found in SentinelOne for UUID [uuid-1]'); }); it('should call SentinelOne fetch-files API with expected data', async () => { const fetchFilesUrl = `${connectorInstance.constructorParams.config.url}${API_PATH}/agents/1913920934584665209/actions/fetch-files`; - const response = await connectorInstance.fetchAgentFiles(fetchAgentFilesParams); + const response = await connectorInstance.fetchAgentFiles( + fetchAgentFilesParams, + connectorMetricsService + ); expect(response).toEqual({ data: { success: true }, errors: null }); expect(connectorInstance.requestSpy).toHaveBeenLastCalledWith({ @@ -77,14 +82,14 @@ describe('SentinelOne Connector', () => { connectorInstance.mockResponses.getAgentsApiResponse.data.length = 0; await expect( - connectorInstance.downloadAgentFile(downloadAgentFileParams) + connectorInstance.downloadAgentFile(downloadAgentFileParams, connectorMetricsService) ).rejects.toHaveProperty('message', 'No agent found in SentinelOne for UUID [uuid-1]'); }); it('should call SentinelOne api with expected url', async () => { - await expect(connectorInstance.downloadAgentFile(downloadAgentFileParams)).resolves.toEqual( - connectorInstance.mockResponses.downloadAgentFileApiResponse - ); + await expect( + connectorInstance.downloadAgentFile(downloadAgentFileParams, connectorMetricsService) + ).resolves.toEqual(connectorInstance.mockResponses.downloadAgentFileApiResponse); }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.ts b/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.ts index 028e6ad1a7643..68f2527889163 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.ts @@ -8,6 +8,7 @@ import { ServiceParams, SubActionConnector } from '@kbn/actions-plugin/server'; import type { AxiosError } from 'axios'; import { SubActionRequestParams } from '@kbn/actions-plugin/server/sub_action_framework/types'; +import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; import type { SentinelOneConfig, SentinelOneSecrets, @@ -134,77 +135,100 @@ export class SentinelOneConnector extends SubActionConnector< }); } - public async fetchAgentFiles({ - files, - agentUUID, - zipPassCode, - }: SentinelOneFetchAgentFilesParams) { - const agent = await this.getAgents({ uuid: agentUUID }); + public async fetchAgentFiles( + { files, agentUUID, zipPassCode }: SentinelOneFetchAgentFilesParams, + connectorMetricsService: ConnectorMetricsService + ) { + const agent = await this.getAgents({ uuid: agentUUID }, connectorMetricsService); const agentId = agent.data[0]?.id; if (!agentId) { throw new Error(`No agent found in SentinelOne for UUID [${agentUUID}]`); } - return this.sentinelOneApiRequest({ - url: `${this.urls.agents}/${agentId}/actions/fetch-files`, - method: 'post', - data: { + return this.sentinelOneApiRequest( + { + url: `${this.urls.agents}/${agentId}/actions/fetch-files`, + method: 'post', data: { - password: zipPassCode, - files, + data: { + password: zipPassCode, + files, + }, }, + responseSchema: SentinelOneFetchAgentFilesResponseSchema, }, - responseSchema: SentinelOneFetchAgentFilesResponseSchema, - }); + connectorMetricsService + ); } - public async downloadAgentFile({ agentUUID, activityId }: SentinelOneDownloadAgentFileParams) { - const agent = await this.getAgents({ uuid: agentUUID }); + public async downloadAgentFile( + { agentUUID, activityId }: SentinelOneDownloadAgentFileParams, + connectorMetricsService: ConnectorMetricsService + ) { + const agent = await this.getAgents({ uuid: agentUUID }, connectorMetricsService); const agentId = agent.data[0]?.id; if (!agentId) { throw new Error(`No agent found in SentinelOne for UUID [${agentUUID}]`); } - return this.sentinelOneApiRequest({ - url: `${this.urls.agents}/${agentId}/uploads/${activityId}`, - method: 'get', - responseType: 'stream', - responseSchema: SentinelOneDownloadAgentFileResponseSchema, - }); + return this.sentinelOneApiRequest( + { + url: `${this.urls.agents}/${agentId}/uploads/${activityId}`, + method: 'get', + responseType: 'stream', + responseSchema: SentinelOneDownloadAgentFileResponseSchema, + }, + connectorMetricsService + ); } - public async getActivities(queryParams?: SentinelOneGetActivitiesParams) { - return this.sentinelOneApiRequest({ - url: this.urls.activities, - method: 'get', - params: queryParams, - responseSchema: SentinelOneGetActivitiesResponseSchema, - }); + public async getActivities( + queryParams?: SentinelOneGetActivitiesParams, + connectorMetricsService?: ConnectorMetricsService + ) { + return this.sentinelOneApiRequest( + { + url: this.urls.activities, + method: 'get', + params: queryParams, + responseSchema: SentinelOneGetActivitiesResponseSchema, + }, + connectorMetricsService! + ); } - public async executeScript({ filter, script }: SentinelOneExecuteScriptParams) { + public async executeScript( + { filter, script }: SentinelOneExecuteScriptParams, + connectorMetricsService: ConnectorMetricsService + ) { if (!filter.ids && !filter.uuids) { throw new Error(`A filter must be defined; either 'ids' or 'uuids'`); } - return this.sentinelOneApiRequest({ - url: this.urls.remoteScriptsExecute, - method: 'post', - data: { + return this.sentinelOneApiRequest( + { + url: this.urls.remoteScriptsExecute, + method: 'post', data: { - outputDestination: 'SentinelCloud', - ...script, + data: { + outputDestination: 'SentinelCloud', + ...script, + }, + filter, }, - filter, + responseSchema: SentinelOneExecuteScriptResponseSchema, }, - responseSchema: SentinelOneExecuteScriptResponseSchema, - }); + connectorMetricsService + ); } - public async isolateHost({ alertIds, ...payload }: SentinelOneIsolateHostParams) { - const response = await this.getAgents(payload); + public async isolateHost( + { alertIds, ...payload }: SentinelOneIsolateHostParams, + connectorMetricsService: ConnectorMetricsService + ) { + const response = await this.getAgents(payload, connectorMetricsService); if (response.data.length === 0) { const errorMessage = 'No agents found'; @@ -220,20 +244,26 @@ export class SentinelOneConnector extends SubActionConnector< const agentId = response.data[0].id; - return this.sentinelOneApiRequest({ - url: this.urls.isolateHost, - method: 'post', - data: { - filter: { - ids: agentId, + return this.sentinelOneApiRequest( + { + url: this.urls.isolateHost, + method: 'post', + data: { + filter: { + ids: agentId, + }, }, + responseSchema: SentinelOneIsolateHostResponseSchema, }, - responseSchema: SentinelOneIsolateHostResponseSchema, - }); + connectorMetricsService + ); } - public async releaseHost({ alertIds, ...payload }: SentinelOneIsolateHostParams) { - const response = await this.getAgents(payload); + public async releaseHost( + { alertIds, ...payload }: SentinelOneIsolateHostParams, + connectorMetricsService: ConnectorMetricsService + ) { + const response = await this.getAgents(payload, connectorMetricsService); if (response.data.length === 0) { throw new Error('No agents found'); @@ -245,50 +275,67 @@ export class SentinelOneConnector extends SubActionConnector< const agentId = response.data[0].id; - return this.sentinelOneApiRequest({ - url: this.urls.releaseHost, - method: 'post', - data: { - filter: { - ids: agentId, + return this.sentinelOneApiRequest( + { + url: this.urls.releaseHost, + method: 'post', + data: { + filter: { + ids: agentId, + }, }, + responseSchema: SentinelOneIsolateHostResponseSchema, }, - responseSchema: SentinelOneIsolateHostResponseSchema, - }); + connectorMetricsService + ); } public async getAgents( - payload: SentinelOneGetAgentsParams + payload: SentinelOneGetAgentsParams, + connectorMetricsService: ConnectorMetricsService ): Promise { - return this.sentinelOneApiRequest({ - url: this.urls.agents, - params: { - ...payload, + return this.sentinelOneApiRequest( + { + url: this.urls.agents, + params: { + ...payload, + }, + responseSchema: SentinelOneGetAgentsResponseSchema, }, - responseSchema: SentinelOneGetAgentsResponseSchema, - }); + connectorMetricsService + ); } - public async getRemoteScriptStatus(payload: SentinelOneGetRemoteScriptStatusParams) { - return this.sentinelOneApiRequest({ - url: this.urls.remoteScriptStatus, - params: { - parent_task_id: payload.parentTaskId, + public async getRemoteScriptStatus( + payload: SentinelOneGetRemoteScriptStatusParams, + connectorMetricsService: ConnectorMetricsService + ) { + return this.sentinelOneApiRequest( + { + url: this.urls.remoteScriptStatus, + params: { + parent_task_id: payload.parentTaskId, + }, + responseSchema: SentinelOneGetRemoteScriptStatusResponseSchema, }, - responseSchema: SentinelOneGetRemoteScriptStatusResponseSchema, - }); + connectorMetricsService + ); } private async sentinelOneApiRequest( - req: SubActionRequestParams + req: SubActionRequestParams, + connectorMetricsService: ConnectorMetricsService ): Promise { - const response = await this.request({ - ...req, - params: { - ...req.params, - APIToken: this.secrets.token, + const response = await this.request( + { + ...req, + params: { + ...req.params, + APIToken: this.secrets.token, + }, }, - }); + connectorMetricsService + ); return response.data; } @@ -316,15 +363,19 @@ export class SentinelOneConnector extends SubActionConnector< } public async getRemoteScripts( - payload: SentinelOneGetRemoteScriptsParams + payload: SentinelOneGetRemoteScriptsParams, + connectorMetricsService: ConnectorMetricsService ): Promise { - return this.sentinelOneApiRequest({ - url: this.urls.remoteScripts, - params: { - limit: API_MAX_RESULTS, - ...payload, + return this.sentinelOneApiRequest( + { + url: this.urls.remoteScripts, + params: { + limit: API_MAX_RESULTS, + ...payload, + }, + responseSchema: SentinelOneGetRemoteScriptsResponseSchema, }, - responseSchema: SentinelOneGetRemoteScriptsResponseSchema, - }); + connectorMetricsService + ); } } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/index.ts index bbfaf902ba671..c456f4f6b5a1b 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/index.ts @@ -102,7 +102,15 @@ async function executorITOM( ExecutorParamsITOM > ): Promise> { - const { actionId, config, params, secrets, configurationUtilities, logger } = execOptions; + const { + actionId, + config, + params, + secrets, + configurationUtilities, + logger, + connectorMetricsService, + } = execOptions; const { subAction, subActionParams } = params; const connectorTokenClient = execOptions.services.connectorTokenClient; const externalServiceConfig = snExternalServiceConfig[actionTypeId]; @@ -119,6 +127,7 @@ async function executorITOM( serviceConfig: externalServiceConfig, connectorTokenClient, createServiceFn: createService, + connectorMetricsService, }); const apiAsRecord = api as unknown as Record; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.test.ts index 01d8ed53478ca..b77206888ee62 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.test.ts @@ -15,6 +15,7 @@ import { loggingSystemMock } from '@kbn/core/server/mocks'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { snExternalServiceConfig } from '../lib/servicenow/config'; import { itomEventParams, serviceNowChoices } from '../lib/servicenow/mocks'; +import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; const logger = loggingSystemMock.create().get() as jest.Mocked; @@ -33,8 +34,10 @@ const configurationUtilities = actionsConfigMock.create(); describe('ServiceNow SIR service', () => { let service: ExternalServiceITOM; + let connectorMetricsService: ConnectorMetricsService; beforeEach(() => { + connectorMetricsService = new ConnectorMetricsService(); service = createExternalService({ credentials: { config: { apiUrl: 'https://example.com/', isOAuth: false }, @@ -44,6 +47,7 @@ describe('ServiceNow SIR service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow-itom'], axiosInstance: axios, + connectorMetricsService, }) as ExternalServiceITOM; }); @@ -69,6 +73,7 @@ describe('ServiceNow SIR service', () => { url: 'https://example.com/api/global/em/jsonv2', method: 'post', data: { records: [itomEventParams] }, + connectorMetricsService, }); }); }); @@ -85,6 +90,7 @@ describe('ServiceNow SIR service', () => { logger, configurationUtilities, url: 'https://example.com/api/now/table/sys_choice?sysparm_query=name=task^ORname=em_event^element=severity^language=en&sysparm_fields=label,value,dependent_value,element', + connectorMetricsService, }); }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.ts index e096b67de7ef4..7215e1cf638ca 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.ts @@ -23,6 +23,7 @@ export const createExternalService: ServiceFactory = ({ configurationUtilities, serviceConfig, axiosInstance, + connectorMetricsService, }): ExternalServiceITOM => { const snService = createExternalServiceCommon({ credentials, @@ -30,6 +31,7 @@ export const createExternalService: ServiceFactory = ({ configurationUtilities, serviceConfig, axiosInstance, + connectorMetricsService, }); const addEvent = async (params: ExecutorSubActionAddEventParams) => { @@ -41,6 +43,7 @@ export const createExternalService: ServiceFactory = ({ method: 'post', data: { records: [params] }, configurationUtilities, + connectorMetricsService, }); snService.checkInstance(res); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/index.ts index 0322b0e341844..d58dff262d0a1 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/index.ts @@ -125,8 +125,16 @@ async function executor( ExecutorParams > ): Promise> { - const { actionId, config, params, secrets, services, configurationUtilities, logger } = - execOptions; + const { + actionId, + config, + params, + secrets, + services, + configurationUtilities, + logger, + connectorMetricsService, + } = execOptions; const { subAction, subActionParams } = params; const connectorTokenClient = services.connectorTokenClient; const externalServiceConfig = snExternalServiceConfig[actionTypeId]; @@ -143,6 +151,7 @@ async function executor( serviceConfig: externalServiceConfig, connectorTokenClient, createServiceFn: createService, + connectorMetricsService, }); const apiAsRecord = api as unknown as Record; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/service.test.ts index 1c068dc60489d..9fb52bab57a7d 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/service.test.ts @@ -15,6 +15,7 @@ import { loggingSystemMock } from '@kbn/core/server/mocks'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { serviceNowCommonFields, serviceNowChoices } from '../lib/servicenow/mocks'; import { snExternalServiceConfig } from '../lib/servicenow/config'; +import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; const logger = loggingSystemMock.create().get() as jest.Mocked; jest.mock('axios', () => ({ @@ -122,6 +123,7 @@ const expectImportedIncident = (update: boolean) => { configurationUtilities, url: 'https://example.com/api/x_elas2_inc_int/elastic_api/health', method: 'get', + connectorMetricsService: expect.any(ConnectorMetricsService), }); expect(requestMock).toHaveBeenNthCalledWith(2, { @@ -135,6 +137,7 @@ const expectImportedIncident = (update: boolean) => { u_description: 'desc', ...(update ? { elastic_incident_id: '1' } : {}), }, + connectorMetricsService: expect.any(ConnectorMetricsService), }); expect(requestMock).toHaveBeenNthCalledWith(3, { @@ -143,14 +146,17 @@ const expectImportedIncident = (update: boolean) => { configurationUtilities, url: 'https://example.com/api/now/v2/table/incident/1', method: 'get', + connectorMetricsService: expect.any(ConnectorMetricsService), }); }; describe('ServiceNow service', () => { let service: ExternalService; + let connectorMetricsService: ConnectorMetricsService; beforeEach(() => { jest.clearAllMocks(); + connectorMetricsService = new ConnectorMetricsService(); service = createExternalService({ credentials: { // The trailing slash at the end of the url is intended. @@ -162,6 +168,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow'], axiosInstance: axios, + connectorMetricsService, }); }); @@ -177,6 +184,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow'], axiosInstance: axios, + connectorMetricsService, }) ).toThrow(); }); @@ -217,6 +225,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow'], axiosInstance: axios, + connectorMetricsService, }) ).toThrow(); }); @@ -381,6 +390,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow'], axiosInstance: axios, + connectorMetricsService, }) ).toThrow(); }); @@ -408,6 +418,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/incident/1', method: 'get', + connectorMetricsService, }); }); @@ -421,6 +432,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], table: 'sn_si_incident' }, axiosInstance: axios, + connectorMetricsService, }); requestMock.mockImplementation(() => ({ @@ -434,6 +446,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/sn_si_incident/1', method: 'get', + connectorMetricsService, }); }); @@ -487,6 +500,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow-sir'], axiosInstance: axios, + connectorMetricsService, }); const res = await createIncident(service); @@ -497,6 +511,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/x_elas2_sir_int/elastic_api/health', method: 'get', + connectorMetricsService, }); expect(requestMock).toHaveBeenNthCalledWith(2, { @@ -506,6 +521,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/import/x_elas2_sir_int_elastic_si_incident', method: 'post', data: { u_short_description: 'title', u_description: 'desc' }, + connectorMetricsService, }); expect(requestMock).toHaveBeenNthCalledWith(3, { @@ -514,6 +530,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/sn_si_incident/1', method: 'get', + connectorMetricsService, }); expect(res.url).toEqual('https://example.com/nav_to.do?uri=sn_si_incident.do?sys_id=1'); @@ -572,6 +589,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], useImportAPI: false }, axiosInstance: axios, + connectorMetricsService, }); }); @@ -596,6 +614,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/v2/table/incident', method: 'post', data: { short_description: 'title', description: 'desc' }, + connectorMetricsService, }); }); @@ -609,6 +628,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow-sir'], useImportAPI: false }, axiosInstance: axios, + connectorMetricsService, }); mockIncidentResponse(false); @@ -624,6 +644,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/v2/table/sn_si_incident', method: 'post', data: { short_description: 'title', description: 'desc' }, + connectorMetricsService, }); expect(res.url).toEqual('https://example.com/nav_to.do?uri=sn_si_incident.do?sys_id=1'); @@ -660,6 +681,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow-sir'], axiosInstance: axios, + connectorMetricsService, }); const res = await updateIncident(service); @@ -669,6 +691,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/x_elas2_sir_int/elastic_api/health', method: 'get', + connectorMetricsService, }); expect(requestMock).toHaveBeenNthCalledWith(2, { @@ -678,6 +701,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/import/x_elas2_sir_int_elastic_si_incident', method: 'post', data: { u_short_description: 'title', u_description: 'desc', elastic_incident_id: '1' }, + connectorMetricsService, }); expect(requestMock).toHaveBeenNthCalledWith(3, { @@ -686,6 +710,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/sn_si_incident/1', method: 'get', + connectorMetricsService, }); expect(res.url).toEqual('https://example.com/nav_to.do?uri=sn_si_incident.do?sys_id=1'); @@ -747,6 +772,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], useImportAPI: false }, axiosInstance: axios, + connectorMetricsService, }); }); @@ -772,6 +798,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/v2/table/incident/1', method: 'patch', data: { short_description: 'title', description: 'desc' }, + connectorMetricsService, }); }); @@ -785,6 +812,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow-sir'], useImportAPI: false }, axiosInstance: axios, + connectorMetricsService, }); mockIncidentResponse(false); @@ -801,6 +829,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/v2/table/sn_si_incident/1', method: 'patch', data: { short_description: 'title', description: 'desc' }, + connectorMetricsService, }); expect(res.url).toEqual('https://example.com/nav_to.do?uri=sn_si_incident.do?sys_id=1'); @@ -820,6 +849,7 @@ describe('ServiceNow service', () => { logger, configurationUtilities, url: 'https://example.com/api/now/table/sys_dictionary?sysparm_query=name=task^ORname=incident^internal_type=string&active=true&array=false&read_only=false&sysparm_fields=max_length,element,column_label,mandatory', + connectorMetricsService, }); }); @@ -841,6 +871,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], table: 'sn_si_incident' }, axiosInstance: axios, + connectorMetricsService, }); requestMock.mockImplementation(() => ({ @@ -853,6 +884,7 @@ describe('ServiceNow service', () => { logger, configurationUtilities, url: 'https://example.com/api/now/table/sys_dictionary?sysparm_query=name=task^ORname=sn_si_incident^internal_type=string&active=true&array=false&read_only=false&sysparm_fields=max_length,element,column_label,mandatory', + connectorMetricsService, }); }); @@ -889,6 +921,7 @@ describe('ServiceNow service', () => { logger, configurationUtilities, url: 'https://example.com/api/now/table/sys_choice?sysparm_query=name=task^ORname=incident^element=priority^ORelement=category^language=en&sysparm_fields=label,value,dependent_value,element', + connectorMetricsService, }); }); @@ -910,6 +943,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], table: 'sn_si_incident' }, axiosInstance: axios, + connectorMetricsService, }); requestMock.mockImplementation(() => ({ @@ -923,6 +957,7 @@ describe('ServiceNow service', () => { logger, configurationUtilities, url: 'https://example.com/api/now/table/sys_choice?sysparm_query=name=task^ORname=sn_si_incident^element=priority^ORelement=category^language=en&sysparm_fields=label,value,dependent_value,element', + connectorMetricsService, }); }); @@ -1015,6 +1050,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], useImportAPI: false }, axiosInstance: axios, + connectorMetricsService, }); await service.checkIfApplicationIsInstalled(); expect(requestMock).not.toHaveBeenCalled(); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/index.ts index d564d6bc79d62..f48e87280f2d3 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/index.ts @@ -116,8 +116,16 @@ async function executor( ExecutorParams > ): Promise> { - const { actionId, config, params, secrets, services, configurationUtilities, logger } = - execOptions; + const { + actionId, + config, + params, + secrets, + services, + configurationUtilities, + logger, + connectorMetricsService, + } = execOptions; const { subAction, subActionParams } = params; const connectorTokenClient = services.connectorTokenClient; const externalServiceConfig = snExternalServiceConfig[actionTypeId]; @@ -134,6 +142,7 @@ async function executor( serviceConfig: externalServiceConfig, connectorTokenClient, createServiceFn: createService, + connectorMetricsService, }); const apiAsRecord = api as unknown as Record; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.test.ts index 97a0570eb50db..eaf0a91f02a03 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.test.ts @@ -15,6 +15,7 @@ import { loggingSystemMock } from '@kbn/core/server/mocks'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { observables } from '../lib/servicenow/mocks'; import { snExternalServiceConfig } from '../lib/servicenow/config'; +import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; const logger = loggingSystemMock.create().get() as jest.Mocked; @@ -31,6 +32,7 @@ jest.mock('@kbn/actions-plugin/server/lib/axios_utils', () => { axios.create = jest.fn(() => axios); const requestMock = utils.request as jest.Mock; const configurationUtilities = actionsConfigMock.create(); +let connectorMetricsService: ConnectorMetricsService; const mockApplicationVersion = () => requestMock.mockImplementationOnce(() => ({ @@ -70,6 +72,7 @@ const expectAddObservables = (single: boolean) => { configurationUtilities, url: 'https://example.com/api/x_elas2_sir_int/elastic_api/health', method: 'get', + connectorMetricsService: expect.any(ConnectorMetricsService), }); const url = single @@ -85,6 +88,7 @@ const expectAddObservables = (single: boolean) => { url, method: 'post', data, + connectorMetricsService: expect.any(ConnectorMetricsService), }); }; @@ -92,6 +96,7 @@ describe('ServiceNow SIR service', () => { let service: ExternalServiceSIR; beforeEach(() => { + connectorMetricsService = new ConnectorMetricsService(); service = createExternalService({ credentials: { config: { apiUrl: 'https://example.com/', isOAuth: false }, @@ -101,6 +106,7 @@ describe('ServiceNow SIR service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow-sir'], axiosInstance: axios, + connectorMetricsService, }) as ExternalServiceSIR; }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.ts index 69836a5b95e29..80c37c6ab9a81 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.ts @@ -28,6 +28,7 @@ export const createExternalService: ServiceFactory = ({ configurationUtilities, serviceConfig, axiosInstance, + connectorMetricsService, }): ExternalServiceSIR => { const snService = createExternalServiceCommon({ credentials, @@ -35,6 +36,7 @@ export const createExternalService: ServiceFactory = ({ configurationUtilities, serviceConfig, axiosInstance, + connectorMetricsService, }); const _addObservable = async (data: Observable | Observable[], url: string) => { @@ -47,6 +49,7 @@ export const createExternalService: ServiceFactory = ({ method: 'post', data, configurationUtilities, + connectorMetricsService, }); snService.checkInstance(res); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack/index.test.ts index 3f6203b725913..154603acfb45c 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack/index.test.ts @@ -9,6 +9,7 @@ import { Logger } from '@kbn/core/server'; import { Services, ActionTypeExecutorResult as ConnectorTypeExecutorResult, + ConnectorMetricsService, } from '@kbn/actions-plugin/server/types'; import { validateParams, validateSecrets } from '@kbn/actions-plugin/server/lib'; import { @@ -35,6 +36,7 @@ const mockedLogger: jest.Mocked = loggerMock.create(); let connectorType: SlackConnectorType; let configurationUtilities: jest.Mocked; +let connectorMetricsService: ConnectorMetricsService; beforeEach(() => { configurationUtilities = actionsConfigMock.create(); @@ -43,6 +45,7 @@ beforeEach(() => { return { status: 'ok', actionId: options.actionId }; }, }); + connectorMetricsService = new ConnectorMetricsService(); }); describe('connector registration', () => { @@ -181,6 +184,7 @@ describe('execute()', () => { params: { message: 'this invocation should succeed' }, configurationUtilities, logger: mockedLogger, + connectorMetricsService, }); expect(response).toMatchInlineSnapshot(` Object { @@ -201,6 +205,7 @@ describe('execute()', () => { params: { message: 'failure: this invocation should fail' }, configurationUtilities, logger: mockedLogger, + connectorMetricsService, }) ).rejects.toThrowErrorMatchingInlineSnapshot( `"slack mockExecutor failure: this invocation should fail"` @@ -226,6 +231,7 @@ describe('execute()', () => { params: { message: 'this invocation should succeed' }, configurationUtilities: configUtils, logger: mockedLogger, + connectorMetricsService, }); expect(mockedLogger.debug).toHaveBeenCalledWith( 'IncomingWebhook was called with proxyUrl https://someproxyhost' @@ -252,6 +258,7 @@ describe('execute()', () => { params: { message: 'this invocation should succeed' }, configurationUtilities: configUtils, logger: mockedLogger, + connectorMetricsService, }); expect(mockedLogger.debug).not.toHaveBeenCalledWith( 'IncomingWebhook was called with proxyUrl https://someproxyhost' @@ -278,6 +285,7 @@ describe('execute()', () => { params: { message: 'this invocation should succeed' }, configurationUtilities: configUtils, logger: mockedLogger, + connectorMetricsService, }); expect(mockedLogger.debug).toHaveBeenCalledWith( 'IncomingWebhook was called with proxyUrl https://someproxyhost' @@ -304,6 +312,7 @@ describe('execute()', () => { params: { message: 'this invocation should succeed' }, configurationUtilities: configUtils, logger: mockedLogger, + connectorMetricsService, }); expect(mockedLogger.debug).toHaveBeenCalledWith( 'IncomingWebhook was called with proxyUrl https://someproxyhost' @@ -330,6 +339,7 @@ describe('execute()', () => { params: { message: 'this invocation should succeed' }, configurationUtilities: configUtils, logger: mockedLogger, + connectorMetricsService, }); expect(mockedLogger.debug).not.toHaveBeenCalledWith( 'IncomingWebhook was called with proxyUrl https://someproxyhost' diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/api.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/api.ts index 1014c43605134..89205d1418209 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/api.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/api.ts @@ -5,7 +5,6 @@ * 2.0. */ -import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; import type { PostMessageSubActionParams, PostBlockkitSubActionParams, @@ -16,32 +15,26 @@ import type { const validChannelIdHandler = async ({ externalService, params: { channelId }, - connectorMetricsService, }: { externalService: SlackApiService; params: ValidChannelIdSubActionParams; - connectorMetricsService: ConnectorMetricsService; -}) => await externalService.validChannelId(channelId ?? '', connectorMetricsService); +}) => await externalService.validChannelId(channelId ?? ''); const postMessageHandler = async ({ externalService, params: { channelIds, channels, text }, - connectorMetricsService, }: { externalService: SlackApiService; params: PostMessageSubActionParams; - connectorMetricsService: ConnectorMetricsService; -}) => await externalService.postMessage({ channelIds, channels, text }, connectorMetricsService); +}) => await externalService.postMessage({ channelIds, channels, text }); const postBlockkitHandler = async ({ externalService, params: { channelIds, channels, text }, - connectorMetricsService, }: { externalService: SlackApiService; params: PostBlockkitSubActionParams; - connectorMetricsService: ConnectorMetricsService; -}) => await externalService.postBlockkit({ channelIds, channels, text }, connectorMetricsService); +}) => await externalService.postBlockkit({ channelIds, channels, text }); export const api = { validChannelId: validChannelIdHandler, diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.ts index 5584dc90469d4..2389198b74cf1 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.ts @@ -124,14 +124,14 @@ const slackApiExecutor = async ({ secrets, }, logger, - configurationUtilities + configurationUtilities, + connectorMetricsService ); if (subAction === 'validChannelId') { return await api.validChannelId({ externalService, params: params.subActionParams, - connectorMetricsService, }); } @@ -139,7 +139,6 @@ const slackApiExecutor = async ({ return await api.postMessage({ externalService, params: params.subActionParams, - connectorMetricsService, }); } @@ -147,7 +146,6 @@ const slackApiExecutor = async ({ return await api.postBlockkit({ externalService, params: params.subActionParams, - connectorMetricsService, }); } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.test.ts index 1389d4a98e9ec..dc2a9a4a61538 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.test.ts @@ -13,6 +13,7 @@ import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.moc import { createExternalService } from './service'; import { SlackApiService } from '../../../common/slack_api/types'; import { SLACK_API_CONNECTOR_ID } from '../../../common/slack_api/constants'; +import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; const logger = loggingSystemMock.create().get() as jest.Mocked; @@ -28,6 +29,7 @@ jest.mock('@kbn/actions-plugin/server/lib/axios_utils', () => { axios.create = jest.fn(() => axios); const requestMock = request as jest.Mock; const configurationUtilities = actionsConfigMock.create(); +let connectorMetricsService: ConnectorMetricsService; const channel = { id: 'channel_id_1', @@ -117,12 +119,14 @@ describe('Slack API service', () => { let service: SlackApiService; beforeAll(() => { + connectorMetricsService = new ConnectorMetricsService(); service = createExternalService( { secrets: { token: 'token' }, }, logger, - configurationUtilities + configurationUtilities, + connectorMetricsService ); }); @@ -138,7 +142,8 @@ describe('Slack API service', () => { secrets: { token: '' }, }, logger, - configurationUtilities + configurationUtilities, + connectorMetricsService ) ).toThrowErrorMatchingInlineSnapshot(`"[Action][Slack API]: Wrong configuration."`); }); @@ -172,6 +177,7 @@ describe('Slack API service', () => { configurationUtilities, method: 'get', url: 'https://slack.com/api/conversations.info?channel=channel_id_1', + connectorMetricsService, }); }); @@ -207,6 +213,7 @@ describe('Slack API service', () => { method: 'post', url: 'https://slack.com/api/chat.postMessage', data: { channel: 'general', text: 'a message' }, + connectorMetricsService, }); }); @@ -231,6 +238,7 @@ describe('Slack API service', () => { method: 'post', url: 'https://slack.com/api/chat.postMessage', data: { channel: 'QWEERTYU987', text: 'a message' }, + connectorMetricsService, }); }); @@ -251,6 +259,7 @@ describe('Slack API service', () => { method: 'post', url: 'https://slack.com/api/chat.postMessage', data: { channel: 'QWEERTYU987', text: 'a message' }, + connectorMetricsService, }); }); @@ -291,6 +300,7 @@ describe('Slack API service', () => { method: 'post', url: 'https://slack.com/api/chat.postMessage', data: { channel: 'general', blocks: testBlock.blocks }, + connectorMetricsService, }); }); @@ -315,6 +325,7 @@ describe('Slack API service', () => { method: 'post', url: 'https://slack.com/api/chat.postMessage', data: { channel: 'QWEERTYU987', blocks: testBlock.blocks }, + connectorMetricsService, }); }); @@ -338,6 +349,7 @@ describe('Slack API service', () => { method: 'post', url: 'https://slack.com/api/chat.postMessage', data: { channel: 'QWEERTYU987', blocks: testBlock.blocks }, + connectorMetricsService, }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.ts index 9a028f274a005..eefb3713a6416 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.ts @@ -112,7 +112,8 @@ export const createExternalService = ( secrets: { token: string }; }, logger: Logger, - configurationUtilities: ActionsConfigurationUtilities + configurationUtilities: ActionsConfigurationUtilities, + connectorMetricsService: ConnectorMetricsService ): SlackApiService => { const { token } = secrets; const { allowedChannels } = config || { allowedChannels: [] }; @@ -129,8 +130,7 @@ export const createExternalService = ( }; const validChannelId = async ( - channelId: string, - connectorMetricsService: ConnectorMetricsService + channelId: string ): Promise> => { try { const validChannel = (): Promise> => { @@ -194,10 +194,11 @@ export const createExternalService = ( return channelToUse; }; - const postMessage = async ( - { channels, channelIds = [], text }: PostMessageSubActionParams, - connectorMetricsService: ConnectorMetricsService - ): Promise> => { + const postMessage = async ({ + channels, + channelIds = [], + text, + }: PostMessageSubActionParams): Promise> => { try { const channelToUse = getChannelToUse({ channels, channelIds }); @@ -218,10 +219,11 @@ export const createExternalService = ( } }; - const postBlockkit = async ( - { channels, channelIds = [], text }: PostBlockkitSubActionParams, - connectorMetricsService: ConnectorMetricsService - ): Promise> => { + const postBlockkit = async ({ + channels, + channelIds = [], + text, + }: PostBlockkitSubActionParams): Promise> => { try { const channelToUse = getChannelToUse({ channels, channelIds }); const blockJson = JSON.parse(text); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/swimlane/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/swimlane/index.ts index d24febcccaad3..2afc1624d034d 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/swimlane/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/swimlane/index.ts @@ -76,7 +76,15 @@ async function executor( ExecutorParams > ): Promise> { - const { actionId, config, params, secrets, configurationUtilities, logger } = execOptions; + const { + actionId, + config, + params, + secrets, + configurationUtilities, + logger, + connectorMetricsService, + } = execOptions; const { subAction, subActionParams } = params as ExecutorParams; let data: SwimlaneExecutorResultData | null = null; @@ -86,7 +94,8 @@ async function executor( secrets, }, logger, - configurationUtilities + configurationUtilities, + connectorMetricsService ); if (!api[subAction]) { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.test.ts index 1aeee9c586fd5..0749b2171bcea 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.test.ts @@ -14,6 +14,7 @@ import { request, createAxiosResponse } from '@kbn/actions-plugin/server/lib/axi import { createExternalService } from './service'; import { mappings } from './mocks'; import { ExternalService } from './types'; +import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; const logger = loggingSystemMock.create().get() as jest.Mocked; @@ -56,8 +57,10 @@ describe('Swimlane Service', () => { }; const url = config.apiUrl.slice(0, -1); + let connectorMetricsService: ConnectorMetricsService; beforeAll(() => { + connectorMetricsService = new ConnectorMetricsService(); service = createExternalService( { // The trailing slash at the end of the url is intended. @@ -66,7 +69,8 @@ describe('Swimlane Service', () => { secrets: { apiToken }, }, logger, - configurationUtilities + configurationUtilities, + connectorMetricsService ); }); beforeEach(() => { @@ -87,7 +91,8 @@ describe('Swimlane Service', () => { secrets: { apiToken }, }, logger, - configurationUtilities + configurationUtilities, + connectorMetricsService ) ).toThrow(); }); @@ -104,7 +109,8 @@ describe('Swimlane Service', () => { secrets: { apiToken }, }, logger, - configurationUtilities + configurationUtilities, + connectorMetricsService ) ).toThrow(); }); @@ -122,7 +128,8 @@ describe('Swimlane Service', () => { secrets: { apiToken }, }, logger, - configurationUtilities + configurationUtilities, + connectorMetricsService ) ).toThrow(); }); @@ -138,7 +145,8 @@ describe('Swimlane Service', () => { }, }, logger, - configurationUtilities + configurationUtilities, + connectorMetricsService ); }).toThrow(); }); @@ -191,6 +199,7 @@ describe('Swimlane Service', () => { url: `${url}/api/app/${config.appId}/record`, method: 'post', configurationUtilities, + connectorMetricsService, }); }); @@ -274,6 +283,7 @@ describe('Swimlane Service', () => { url: `${url}/api/app/${config.appId}/record/${incidentId}`, method: 'patch', configurationUtilities, + connectorMetricsService, }); }); @@ -353,6 +363,7 @@ describe('Swimlane Service', () => { url: `${url}/api/app/${config.appId}/record/${incidentId}/${mappings.commentsConfig.id}/comment`, method: 'post', configurationUtilities, + connectorMetricsService, }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.ts b/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.ts index 42c4b65408f21..261de60646510 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.ts @@ -14,6 +14,7 @@ import { throwIfResponseIsNotValid, } from '@kbn/actions-plugin/server/lib/axios_utils'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; +import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; import { getBodyForEventAction } from './helpers'; import { CreateCommentParams, @@ -42,7 +43,8 @@ const createErrorMessage = (errorResponse: ResponseError | null | undefined): st export const createExternalService = ( { config, secrets }: ExternalServiceCredentials, logger: Logger, - configurationUtilities: ActionsConfigurationUtilities + configurationUtilities: ActionsConfigurationUtilities, + connectorMetricsService: ConnectorMetricsService ): ExternalService => { const { apiUrl: url, appId, mappings } = config as SwimlanePublicConfigurationType; const { apiToken } = secrets as SwimlaneSecretConfigurationType; @@ -92,6 +94,7 @@ export const createExternalService = ( logger, method: 'post', url: getPostRecordUrl(appId), + connectorMetricsService, }); throwIfResponseIsNotValid({ @@ -132,6 +135,7 @@ export const createExternalService = ( logger, method: 'patch', url: getPostRecordIdUrl(appId, params.incidentId), + connectorMetricsService, }); throwIfResponseIsNotValid({ @@ -181,6 +185,7 @@ export const createExternalService = ( logger, method: 'post', url: getPostCommentUrl(appId, incidentId, fieldId), + connectorMetricsService, }); /** diff --git a/x-pack/plugins/stack_connectors/server/connector_types/teams/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/teams/index.test.ts index 0b144bceb05c7..2600340b92526 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/teams/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/teams/index.test.ts @@ -6,7 +6,7 @@ */ import { Logger } from '@kbn/core/server'; -import { Services } from '@kbn/actions-plugin/server/types'; +import { ConnectorMetricsService, Services } from '@kbn/actions-plugin/server/types'; import { validateParams, validateSecrets } from '@kbn/actions-plugin/server/lib'; import axios from 'axios'; import { getConnectorType, TeamsConnectorType, ConnectorTypeId } from '.'; @@ -34,10 +34,12 @@ const mockedLogger: jest.Mocked = loggerMock.create(); let connectorType: TeamsConnectorType; let configurationUtilities: jest.Mocked; +let connectorMetricsService: ConnectorMetricsService; beforeEach(() => { configurationUtilities = actionsConfigMock.create(); connectorType = getConnectorType(); + connectorMetricsService = new ConnectorMetricsService(); }); describe('connector registration', () => { @@ -167,11 +169,17 @@ describe('execute()', () => { params: { message: 'this invocation should succeed' }, configurationUtilities, logger: mockedLogger, + connectorMetricsService, }); delete requestMock.mock.calls[0][0].configurationUtilities; expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "axios": undefined, + "connectorMetricsService": ConnectorMetricsService { + "metrics": Object { + "requestBodyBytes": 0, + }, + }, "data": Object { "text": "this invocation should succeed", }, @@ -223,11 +231,17 @@ describe('execute()', () => { params: { message: 'this invocation should succeed' }, configurationUtilities, logger: mockedLogger, + connectorMetricsService, }); delete requestMock.mock.calls[0][0].configurationUtilities; expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "axios": undefined, + "connectorMetricsService": ConnectorMetricsService { + "metrics": Object { + "requestBodyBytes": 0, + }, + }, "data": Object { "text": "this invocation should succeed", }, diff --git a/x-pack/plugins/stack_connectors/server/connector_types/teams/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/teams/index.ts index 84aa7449725c8..ce578a2f66c86 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/teams/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/teams/index.ts @@ -119,7 +119,8 @@ function validateConnectorTypeConfig( async function teamsExecutor( execOptions: TeamsConnectorTypeExecutorOptions ): Promise> { - const { actionId, secrets, params, configurationUtilities, logger } = execOptions; + const { actionId, secrets, params, configurationUtilities, logger, connectorMetricsService } = + execOptions; const { webhookUrl } = secrets; const { message } = params; const data = { text: message }; @@ -134,6 +135,7 @@ async function teamsExecutor( logger, data, configurationUtilities, + connectorMetricsService, }) ); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.test.ts index b30a888f27998..3ed2d3afa46db 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.test.ts @@ -12,6 +12,7 @@ import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; import { TinesConnector } from './tines'; import { request } from '@kbn/actions-plugin/server/lib/axios_utils'; import { API_MAX_RESULTS, TINES_CONNECTOR_ID } from '../../../common/tines/constants'; +import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; jest.mock('axios'); (axios as jest.Mocked).create.mockImplementation( @@ -78,6 +79,7 @@ const storiesGetRequestExpected = { 'Content-Type': 'application/json', }, params: { per_page: API_MAX_RESULTS }, + connectorMetricsService: expect.any(ConnectorMetricsService), }; const agentsGetRequestExpected = { @@ -91,8 +93,11 @@ const agentsGetRequestExpected = { 'Content-Type': 'application/json', }, params: { story_id: story.id, per_page: API_MAX_RESULTS }, + connectorMetricsService: expect.any(ConnectorMetricsService), }; +let connectorMetricsService: ConnectorMetricsService; + describe('TinesConnector', () => { const connector = new TinesConnector({ configurationUtilities: actionsConfigMock.create(), @@ -105,6 +110,7 @@ describe('TinesConnector', () => { beforeEach(() => { jest.clearAllMocks(); + connectorMetricsService = new ConnectorMetricsService(); }); describe('getStories', () => { @@ -113,13 +119,13 @@ describe('TinesConnector', () => { }); it('should request Tines stories', async () => { - await connector.getStories(); + await connector.getStories(undefined, connectorMetricsService); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith(storiesGetRequestExpected); }); it('should return the Tines stories reduced array', async () => { - const { stories } = await connector.getStories(); + const { stories } = await connector.getStories(undefined, connectorMetricsService); expect(stories).toEqual([storyResult]); }); @@ -127,7 +133,7 @@ describe('TinesConnector', () => { mockRequest.mockReturnValueOnce({ data: { stories: [story], meta: { pages: 1 } }, }); - const response = await connector.getStories(); + const response = await connector.getStories(undefined, connectorMetricsService); expect(response.incompleteResponse).toEqual(false); }); @@ -135,7 +141,7 @@ describe('TinesConnector', () => { mockRequest.mockReturnValueOnce({ data: { stories: [story], meta: { pages: 2 } }, }); - const response = await connector.getStories(); + const response = await connector.getStories(undefined, connectorMetricsService); expect(response.incompleteResponse).toEqual(true); }); }); @@ -146,14 +152,17 @@ describe('TinesConnector', () => { }); it('should request Tines webhook actions', async () => { - await connector.getWebhooks({ storyId: story.id }); + await connector.getWebhooks({ storyId: story.id }, connectorMetricsService); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith(agentsGetRequestExpected); }); it('should return the Tines webhooks reduced array', async () => { - const { webhooks } = await connector.getWebhooks({ storyId: story.id }); + const { webhooks } = await connector.getWebhooks( + { storyId: story.id }, + connectorMetricsService + ); expect(webhooks).toEqual([webhookResult]); }); @@ -161,7 +170,7 @@ describe('TinesConnector', () => { mockRequest.mockReturnValueOnce({ data: { agents: [webhookAgent], meta: { pages: 1 } }, }); - const response = await connector.getWebhooks({ storyId: story.id }); + const response = await connector.getWebhooks({ storyId: story.id }, connectorMetricsService); expect(response.incompleteResponse).toEqual(false); }); @@ -169,7 +178,7 @@ describe('TinesConnector', () => { mockRequest.mockReturnValueOnce({ data: { agents: [webhookAgent], meta: { pages: 2 } }, }); - const response = await connector.getWebhooks({ storyId: story.id }); + const response = await connector.getWebhooks({ storyId: story.id }, connectorMetricsService); expect(response.incompleteResponse).toEqual(true); }); }); @@ -180,10 +189,13 @@ describe('TinesConnector', () => { }); it('should send data to Tines webhook using selected webhook parameter', async () => { - await connector.runWebhook({ - webhook: webhookResult, - body: '[]', - }); + await connector.runWebhook( + { + webhook: webhookResult, + body: '[]', + }, + connectorMetricsService + ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith({ @@ -194,14 +206,18 @@ describe('TinesConnector', () => { headers: { 'Content-Type': 'application/json', }, + connectorMetricsService, }); }); it('should send data to Tines webhook using webhook url parameter', async () => { - await connector.runWebhook({ - webhookUrl, - body: '[]', - }); + await connector.runWebhook( + { + webhookUrl, + body: '[]', + }, + connectorMetricsService + ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith({ @@ -212,6 +228,7 @@ describe('TinesConnector', () => { headers: { 'Content-Type': 'application/json', }, + connectorMetricsService, }); }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.ts b/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.ts index cb46a9abea3cc..9b9234894f189 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.ts @@ -8,6 +8,7 @@ import { ServiceParams, SubActionConnector } from '@kbn/actions-plugin/server'; import type { AxiosError } from 'axios'; import { SubActionRequestParams } from '@kbn/actions-plugin/server/sub_action_framework/types'; +import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; import { TinesStoriesActionParamsSchema, TinesWebhooksActionParamsSchema, @@ -108,12 +109,16 @@ export class TinesConnector extends SubActionConnector( req: SubActionRequestParams, - reducer: (response: R) => T + reducer: (response: R) => T, + connectorMetricsService: ConnectorMetricsService ): Promise { - const response = await this.request({ - ...req, - params: { ...req.params, per_page: API_MAX_RESULTS }, - }); + const response = await this.request( + { + ...req, + params: { ...req.params, per_page: API_MAX_RESULTS }, + }, + connectorMetricsService + ); return { ...reducer(response.data), incompleteResponse: response.data.meta.pages > 1, @@ -130,20 +135,25 @@ export class TinesConnector extends SubActionConnector { + public async getStories( + params: unknown, + connectorMetricsService: ConnectorMetricsService + ): Promise { return this.tinesApiRequest( { url: this.urls.stories, headers: this.getAuthHeaders(), responseSchema: TinesStoriesApiResponseSchema, }, - storiesReducer + storiesReducer, + connectorMetricsService ); } - public async getWebhooks({ - storyId, - }: TinesWebhooksActionParams): Promise { + public async getWebhooks( + { storyId }: TinesWebhooksActionParams, + connectorMetricsService: ConnectorMetricsService + ): Promise { return this.tinesApiRequest( { url: this.urls.agents, @@ -151,24 +161,27 @@ export class TinesConnector extends SubActionConnector { + public async runWebhook( + { webhook, webhookUrl, body }: TinesRunActionParams, + connectorMetricsService: ConnectorMetricsService + ): Promise { if (!webhook && !webhookUrl) { throw Error('Invalid subActionsParams: [webhook] or [webhookUrl] expected but got none'); } - const response = await this.request({ - url: webhookUrl ? webhookUrl : this.urls.getRunWebhookURL(webhook!), - method: 'post', - responseSchema: TinesRunApiResponseSchema, - data: body, - }); + const response = await this.request( + { + url: webhookUrl ? webhookUrl : this.urls.getRunWebhookURL(webhook!), + method: 'post', + responseSchema: TinesRunApiResponseSchema, + data: body, + }, + connectorMetricsService + ); return response.data; } } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/torq/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/torq/index.test.ts index 4bf60d10eb789..870c0cf12394e 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/torq/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/torq/index.test.ts @@ -11,7 +11,12 @@ import axios from 'axios'; import { ActionTypeConfigType, getActionType, TorqActionType } from '.'; import * as utils from '@kbn/actions-plugin/server/lib/axios_utils'; -import { validateConfig, validateParams, validateSecrets } from '@kbn/actions-plugin/server/lib'; +import { + ConnectorMetricsService, + validateConfig, + validateParams, + validateSecrets, +} from '@kbn/actions-plugin/server/lib'; import { actionsMock } from '@kbn/actions-plugin/server/mocks'; import { Services } from '@kbn/actions-plugin/server/types'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; @@ -37,10 +42,12 @@ const services: Services = actionsMock.createServices(); let actionType: TorqActionType; const mockedLogger: jest.Mocked = loggerMock.create(); let configurationUtilities: jest.Mocked; +let connectorMetricsService: ConnectorMetricsService; beforeAll(() => { actionType = getActionType(); configurationUtilities = actionsConfigMock.create(); + connectorMetricsService = new ConnectorMetricsService(); }); describe('actionType', () => { @@ -171,12 +178,18 @@ describe('execute Torq action', () => { params: { body: '{"msg": "some data"}' }, configurationUtilities, logger: mockedLogger, + connectorMetricsService, }); delete requestMock.mock.calls[0][0].configurationUtilities; expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "axios": [MockFunction], + "connectorMetricsService": ConnectorMetricsService { + "metrics": Object { + "requestBodyBytes": 0, + }, + }, "data": Object { "msg": "some data", }, diff --git a/x-pack/plugins/stack_connectors/server/connector_types/torq/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/torq/index.ts index c3e7dc4f1533c..3667ec5e7f072 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/torq/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/torq/index.ts @@ -146,6 +146,7 @@ export async function executor( const { webhookIntegrationUrl } = execOptions.config; const { body: data } = execOptions.params; const configurationUtilities = execOptions.configurationUtilities; + const connectorMetricsService = execOptions.connectorMetricsService; const secrets: ActionTypeSecretsType = execOptions.secrets; const token = secrets.token; @@ -171,6 +172,7 @@ export async function executor( configurationUtilities, logger: execOptions.logger, validateStatus: (status: number) => status >= 200 && status < 300, + connectorMetricsService, }) ); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.test.ts index 6c51fe11e97de..a2e7794eaeadb 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { Services } from '@kbn/actions-plugin/server/types'; +import { ConnectorMetricsService, Services } from '@kbn/actions-plugin/server/types'; import { validateConfig, validateParams, validateSecrets } from '@kbn/actions-plugin/server/lib'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; @@ -41,10 +41,12 @@ const mockedLogger: jest.Mocked = loggerMock.create(); let connectorType: WebhookConnectorType; let configurationUtilities: jest.Mocked; +let connectorMetricsService: ConnectorMetricsService; beforeEach(() => { configurationUtilities = actionsConfigMock.create(); connectorType = getConnectorType(); + connectorMetricsService = new ConnectorMetricsService(); }); describe('connectorType', () => { @@ -339,12 +341,18 @@ describe('execute()', () => { params: { body: 'some data' }, configurationUtilities, logger: mockedLogger, + connectorMetricsService, }); delete requestMock.mock.calls[0][0].configurationUtilities; expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "axios": undefined, + "connectorMetricsService": ConnectorMetricsService { + "metrics": Object { + "requestBodyBytes": 0, + }, + }, "data": "some data", "headers": Object { "Authorization": "Basic YWJjOjEyMw==", @@ -400,6 +408,7 @@ describe('execute()', () => { params: { body: 'some data' }, configurationUtilities, logger: mockedLogger, + connectorMetricsService, }); delete requestMock.mock.calls[0][0].configurationUtilities; @@ -407,6 +416,11 @@ describe('execute()', () => { expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "axios": undefined, + "connectorMetricsService": ConnectorMetricsService { + "metrics": Object { + "requestBodyBytes": 0, + }, + }, "data": "some data", "headers": Object { "aheader": "a value", @@ -588,6 +602,7 @@ describe('execute()', () => { params: { body: 'some data' }, configurationUtilities, logger: mockedLogger, + connectorMetricsService, }); expect(mockedLogger.error).toBeCalledWith( 'error on some-id webhook event: maxContentLength size of 1000000 exceeded' @@ -618,12 +633,18 @@ describe('execute()', () => { params: { body: 'some data' }, configurationUtilities, logger: mockedLogger, + connectorMetricsService, }); delete requestMock.mock.calls[0][0].configurationUtilities; expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "axios": undefined, + "connectorMetricsService": ConnectorMetricsService { + "metrics": Object { + "requestBodyBytes": 0, + }, + }, "data": "some data", "headers": Object { "aheader": "a value", diff --git a/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.test.ts index 9205c3fef91c9..d74f95ee08cf1 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.test.ts @@ -14,7 +14,7 @@ import { XmattersConnectorType, } from '.'; import { actionsMock } from '@kbn/actions-plugin/server/mocks'; -import { Services } from '@kbn/actions-plugin/server/types'; +import { ConnectorMetricsService, Services } from '@kbn/actions-plugin/server/types'; import { validateConfig, validateConnector, @@ -45,10 +45,12 @@ const mockedLogger: jest.Mocked = loggerMock.create(); let connectorType: XmattersConnectorType; let configurationUtilities: jest.Mocked; +let connectorMetricsService: ConnectorMetricsService; beforeEach(() => { configurationUtilities = actionsConfigMock.create(); connectorType = getConnectorType(); + connectorMetricsService = new ConnectorMetricsService(); }); describe('connectorType', () => { @@ -423,6 +425,7 @@ describe('execute()', () => { }, configurationUtilities, logger: mockedLogger, + connectorMetricsService, }); const { method, url, headers, data } = requestMock.mock.calls[0][0]; @@ -472,6 +475,7 @@ describe('execute()', () => { }, configurationUtilities, logger: mockedLogger, + connectorMetricsService, }); expect(mockedLogger.warn).toBeCalledWith( 'Error thrown triggering xMatters workflow: maxContentLength size of 1000000 exceeded' @@ -504,6 +508,7 @@ describe('execute()', () => { }, configurationUtilities, logger: mockedLogger, + connectorMetricsService, }); const { method, url, headers, data } = requestMock.mock.calls[0][0]; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.ts index 880c2278ca923..1a1121e8a75a1 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.ts @@ -8,7 +8,7 @@ import { isString } from 'lodash'; import { i18n } from '@kbn/i18n'; import { schema, TypeOf } from '@kbn/config-schema'; -import type { +import { ActionType as ConnectorType, ActionTypeExecutorOptions as ConnectorTypeExecutorOptions, ActionTypeExecutorResult as ConnectorTypeExecutorResult, @@ -247,7 +247,8 @@ function validateConnectorTypeSecrets( export async function executor( execOptions: XmattersConnectorTypeExecutorOptions ): Promise> { - const { actionId, configurationUtilities, config, params, logger } = execOptions; + const { actionId, configurationUtilities, config, params, logger, connectorMetricsService } = + execOptions; const { configUrl, usesBasic } = config; const data = getPayloadForRequest(params); @@ -263,7 +264,12 @@ export async function executor( if (!url) { throw new Error('Error: no url provided'); } - result = await postXmatters({ url, data, basicAuth }, logger, configurationUtilities); + result = await postXmatters( + { url, data, basicAuth }, + logger, + configurationUtilities, + connectorMetricsService + ); } catch (err) { const message = i18n.translate('xpack.stackConnectors.xmatters.postingErrorMessage', { defaultMessage: 'Error triggering xMatters workflow', diff --git a/x-pack/plugins/stack_connectors/server/connector_types/xmatters/post_xmatters.ts b/x-pack/plugins/stack_connectors/server/connector_types/xmatters/post_xmatters.ts index 2c2a08901cec3..4051f75c8a4d0 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/xmatters/post_xmatters.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/xmatters/post_xmatters.ts @@ -9,7 +9,10 @@ import axios, { AxiosResponse } from 'axios'; import { Logger } from '@kbn/core/server'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; import { request } from '@kbn/actions-plugin/server/lib/axios_utils'; -import { combineHeadersWithBasicAuthHeader } from '@kbn/actions-plugin/server/lib'; +import { + combineHeadersWithBasicAuthHeader, + ConnectorMetricsService, +} from '@kbn/actions-plugin/server/lib'; interface PostXmattersOptions { url: string; @@ -34,7 +37,8 @@ interface PostXmattersOptions { export async function postXmatters( options: PostXmattersOptions, logger: Logger, - configurationUtilities: ActionsConfigurationUtilities + configurationUtilities: ActionsConfigurationUtilities, + connectorMetricsService: ConnectorMetricsService ): Promise { const { url, data, basicAuth } = options; const axiosInstance = axios.create(); @@ -50,5 +54,6 @@ export async function postXmatters( data, configurationUtilities, validateStatus: () => true, + connectorMetricsService, }); } From 4d180d61bce28e96d4e77253f3b78081dfbb16ef Mon Sep 17 00:00:00 2001 From: Ersin Erdal Date: Sun, 7 Jul 2024 23:52:18 +0200 Subject: [PATCH 03/25] Collect request body bytes of the outgoing requests from the connectors --- .../server/lib/action_executor.test.ts | 45 +++++++- .../actions/server/lib/action_executor.ts | 15 ++- .../actions/server/lib/axios_utils.test.ts | 22 ++-- .../plugins/actions/server/lib/axios_utils.ts | 20 ++-- ...ts => connector_metrics_collector.test.ts} | 24 ++-- ...vice.ts => connector_metrics_collector.ts} | 2 +- .../create_action_event_log_record_object.ts | 3 + x-pack/plugins/actions/server/lib/index.ts | 2 +- .../server/sub_action_framework/case.test.ts | 16 +-- .../server/sub_action_framework/case.ts | 28 ++--- .../sub_action_framework/executor.test.ts | 35 +++--- .../server/sub_action_framework/executor.ts | 4 +- .../server/sub_action_framework/mocks.ts | 14 +-- .../sub_action_connector.test.ts | 48 ++++---- .../sub_action_connector.ts | 6 +- x-pack/plugins/actions/server/types.ts | 6 +- .../plugins/event_log/generated/mappings.json | 11 ++ x-pack/plugins/event_log/generated/schemas.ts | 6 + x-pack/plugins/event_log/scripts/mappings.js | 11 ++ .../connector_types/bedrock/bedrock.test.ts | 73 ++++++------ .../server/connector_types/bedrock/bedrock.ts | 28 ++--- .../connector_types/cases_webhook/index.ts | 5 +- .../cases_webhook/service.test.ts | 54 ++++----- .../connector_types/cases_webhook/service.ts | 12 +- .../crowdstrike/crowdstrike.test.ts | 42 +++---- .../crowdstrike/crowdstrike.ts | 26 ++--- .../d3security/d3security.test.ts | 16 +-- .../connector_types/d3security/d3security.ts | 6 +- .../connector_types/email/index.test.ts | 6 +- .../server/connector_types/email/index.ts | 4 +- .../connector_types/email/send_email.test.ts | 69 ++++-------- .../connector_types/email/send_email.ts | 21 ++-- .../email/send_email_graph_api.test.ts | 18 +-- .../email/send_email_graph_api.ts | 6 +- .../connector_types/es_index/index.test.ts | 16 ++- .../connector_types/gemini/gemini.test.ts | 29 ++--- .../server/connector_types/gemini/gemini.ts | 18 +-- .../server/connector_types/jira/index.ts | 4 +- .../connector_types/jira/service.test.ts | 48 ++++---- .../server/connector_types/jira/service.ts | 24 ++-- .../servicenow/create_service_wrapper.test.ts | 7 ++ .../lib/servicenow/create_service_wrapper.ts | 8 +- .../lib/servicenow/service.test.ts | 55 +++++++++ .../connector_types/lib/servicenow/service.ts | 18 +-- .../connector_types/lib/servicenow/types.ts | 6 +- .../connector_types/openai/openai.test.ts | 106 +++++++++--------- .../server/connector_types/openai/openai.ts | 22 ++-- .../opsgenie/connector.test.ts | 30 ++--- .../connector_types/opsgenie/connector.ts | 10 +- .../connector_types/pagerduty/index.test.ts | 30 ++--- .../server/connector_types/pagerduty/index.ts | 4 +- .../pagerduty/post_pagerduty.ts | 6 +- .../resilient/resilient.test.ts | 76 +++++++------ .../connector_types/resilient/resilient.ts | 34 +++--- .../sentinelone/sentinelone.test.ts | 14 +-- .../sentinelone/sentinelone.ts | 50 ++++----- .../connector_types/server_log/index.test.ts | 3 +- .../connector_types/servicenow_itom/index.ts | 4 +- .../servicenow_itom/service.test.ts | 12 +- .../servicenow_itom/service.ts | 6 +- .../connector_types/servicenow_itsm/index.ts | 4 +- .../servicenow_itsm/service.test.ts | 72 ++++++------ .../connector_types/servicenow_sir/index.ts | 4 +- .../servicenow_sir/service.test.ts | 12 +- .../connector_types/servicenow_sir/service.ts | 6 +- .../connector_types/slack/index.test.ts | 20 ++-- .../server/connector_types/slack/index.ts | 4 +- .../connector_types/slack_api/index.test.ts | 13 ++- .../server/connector_types/slack_api/index.ts | 4 +- .../connector_types/slack_api/service.test.ts | 24 ++-- .../connector_types/slack_api/service.ts | 10 +- .../server/connector_types/swimlane/index.ts | 4 +- .../connector_types/swimlane/service.test.ts | 22 ++-- .../connector_types/swimlane/service.ts | 10 +- .../connector_types/teams/index.test.ts | 14 +-- .../server/connector_types/teams/index.ts | 4 +- .../connector_types/tines/tines.test.ts | 40 ++++--- .../server/connector_types/tines/tines.ts | 18 +-- .../server/connector_types/torq/index.test.ts | 10 +- .../server/connector_types/torq/index.ts | 4 +- .../connector_types/webhook/index.test.ts | 20 ++-- .../server/connector_types/webhook/index.ts | 4 +- .../connector_types/xmatters/index.test.ts | 12 +- .../server/connector_types/xmatters/index.ts | 4 +- .../connector_types/xmatters/post_xmatters.ts | 6 +- .../alerts/server/sub_action_connector.ts | 7 +- .../tests/actions/connector_types/bedrock.ts | 25 ++++- .../actions/connector_types/cases_webhook.ts | 20 ++++ .../actions/connector_types/d3security.ts | 21 ++++ .../tests/actions/connector_types/email.ts | 22 +++- .../tests/actions/connector_types/es_index.ts | 20 ++++ .../tests/actions/connector_types/jira.ts | 20 ++++ .../tests/actions/connector_types/openai.ts | 21 +++- .../tests/actions/connector_types/opsgenie.ts | 20 ++++ .../actions/connector_types/pagerduty.ts | 20 ++++ .../actions/connector_types/resilient.ts | 20 ++++ .../actions/connector_types/server_log.ts | 20 ++++ .../connector_types/servicenow_itom.ts | 37 ++++++ .../connector_types/servicenow_itsm.ts | 70 ++++++++++++ .../actions/connector_types/servicenow_sir.ts | 53 +++++++++ .../actions/connector_types/slack_webhook.ts | 21 ++++ .../tests/actions/connector_types/swimlane.ts | 37 ++++++ .../tests/actions/connector_types/tines.ts | 84 ++++++++++++++ .../tests/actions/connector_types/torq.ts | 19 ++++ .../tests/actions/connector_types/webhook.ts | 21 ++++ .../tests/actions/connector_types/xmatters.ts | 20 ++++ .../group2/tests/actions/execute.ts | 2 + .../actions/sub_action_framework/index.ts | 30 ++++- 108 files changed, 1548 insertions(+), 771 deletions(-) rename x-pack/plugins/actions/server/lib/{connector_metrics_service.test.ts => connector_metrics_collector.test.ts} (56%) rename x-pack/plugins/actions/server/lib/{connector_metrics_service.ts => connector_metrics_collector.ts} (95%) diff --git a/x-pack/plugins/actions/server/lib/action_executor.test.ts b/x-pack/plugins/actions/server/lib/action_executor.test.ts index bfcedc821368f..15e0234404a8a 100644 --- a/x-pack/plugins/actions/server/lib/action_executor.test.ts +++ b/x-pack/plugins/actions/server/lib/action_executor.test.ts @@ -18,7 +18,7 @@ import { } from '@kbn/core/server/mocks'; import { eventLoggerMock } from '@kbn/event-log-plugin/server/mocks'; import { spacesServiceMock } from '@kbn/spaces-plugin/server/spaces_service/spaces_service.mock'; -import { ActionType as ConnectorType } from '../types'; +import { ActionType as ConnectorType, ConnectorMetricsCollector } from '../types'; import { actionsAuthorizationMock, actionsMock } from '../mocks'; import { asBackgroundTaskExecutionSource, @@ -31,6 +31,8 @@ import { SecurityConnectorFeatureId } from '../../common'; import { TaskErrorSource } from '@kbn/task-manager-plugin/common'; import { createTaskRunError, getErrorSource } from '@kbn/task-manager-plugin/server/task_running'; import { GEN_AI_TOKEN_COUNT_EVENT } from './event_based_telemetry'; +import { Event } from './create_action_event_log_record_object'; +import { set } from '@kbn/safer-lodash-set'; const actionExecutor = new ActionExecutor({ isESOCanEncrypt: true }); const services = actionsMock.createServices(); @@ -163,6 +165,7 @@ const getBaseExecuteStartEventLogDoc = (unsecured: boolean) => { }, id: CONNECTOR_ID, name: '1', + type_id: 'test', }, ...(unsecured ? {} @@ -211,6 +214,10 @@ const getBaseExecuteEventLogDoc = (unsecured: boolean) => { }; }; +const addConnectorMetrics = (event: Event, value: number) => { + set(event, 'kibana.action.execution.metrics.request_body_bytes', value); +}; + beforeEach(() => { jest.resetAllMocks(); jest.clearAllMocks(); @@ -280,6 +287,7 @@ describe('Action Executor', () => { }, params: { foo: true }, logger: loggerMock, + connectorMetricsCollector: expect.any(ConnectorMetricsCollector), }); expect(loggerMock.debug).toBeCalledWith('executing action test:1: 1'); @@ -287,6 +295,7 @@ describe('Action Executor', () => { const execStartDoc = getBaseExecuteStartEventLogDoc(executeUnsecure); const execDoc = getBaseExecuteEventLogDoc(executeUnsecure); + addConnectorMetrics(execDoc, 0); expect(eventLogger.logEvent).toHaveBeenNthCalledWith(1, execStartDoc); expect(eventLogger.logEvent).toHaveBeenNthCalledWith(2, execDoc); }); @@ -353,6 +362,7 @@ describe('Action Executor', () => { params: { foo: true }, logger: loggerMock, source: executionSource.source, + connectorMetricsCollector: expect.any(ConnectorMetricsCollector), }); expect(loggerMock.debug).toBeCalledWith('executing action test:1: 1'); @@ -360,6 +370,7 @@ describe('Action Executor', () => { const execStartDoc = getBaseExecuteStartEventLogDoc(executeUnsecure); const execDoc = getBaseExecuteEventLogDoc(executeUnsecure); + addConnectorMetrics(execDoc, 0); expect(eventLogger.logEvent).toHaveBeenNthCalledWith(1, { ...execStartDoc, kibana: { @@ -431,6 +442,7 @@ describe('Action Executor', () => { }, params: { foo: true }, logger: loggerMock, + connectorMetricsCollector: expect.any(ConnectorMetricsCollector), }); expect(loggerMock.debug).toBeCalledWith('executing action test:preconfigured: Preconfigured'); @@ -438,6 +450,7 @@ describe('Action Executor', () => { const execStartDoc = getBaseExecuteStartEventLogDoc(executeUnsecure); const execDoc = getBaseExecuteEventLogDoc(executeUnsecure); + addConnectorMetrics(execDoc, 0); expect(eventLogger.logEvent).toHaveBeenNthCalledWith(1, { ...execStartDoc, kibana: { @@ -513,6 +526,7 @@ describe('Action Executor', () => { params: { foo: true }, logger: loggerMock, request: {}, + connectorMetricsCollector: expect.any(ConnectorMetricsCollector), }); } @@ -532,6 +546,7 @@ describe('Action Executor', () => { const execStartDoc = getBaseExecuteStartEventLogDoc(executeUnsecure); const execDoc = getBaseExecuteEventLogDoc(executeUnsecure); + addConnectorMetrics(execDoc, 0); expect(eventLogger.logEvent).toHaveBeenNthCalledWith(1, { ...execStartDoc, kibana: { @@ -540,6 +555,7 @@ describe('Action Executor', () => { ...execStartDoc.kibana.action, id: 'system-connector-.cases', name: 'System action: .cases', + type_id: '.cases', }, saved_objects: [ { @@ -569,6 +585,7 @@ describe('Action Executor', () => { ...execDoc.kibana.action, id: 'system-connector-.cases', name: 'System action: .cases', + type_id: '.cases', }, saved_objects: [ { @@ -890,6 +907,7 @@ describe('Action Executor', () => { }, params: { foo: true }, logger: loggerMock, + connectorMetricsCollector: expect.any(ConnectorMetricsCollector), }); }); @@ -921,6 +939,7 @@ describe('Action Executor', () => { params: { foo: true }, logger: loggerMock, request: {}, + connectorMetricsCollector: expect.any(ConnectorMetricsCollector), }); }); @@ -989,6 +1008,7 @@ describe('Action Executor', () => { }, params: { foo: true }, logger: loggerMock, + connectorMetricsCollector: expect.any(ConnectorMetricsCollector), }); expect(loggerMock.debug).toBeCalledWith('executing action test:preconfigured: Preconfigured'); @@ -996,6 +1016,7 @@ describe('Action Executor', () => { const execStartDoc = getBaseExecuteStartEventLogDoc(executeUnsecure); const execDoc = getBaseExecuteEventLogDoc(executeUnsecure); + addConnectorMetrics(execDoc, 0); expect(eventLogger.logEvent).toHaveBeenNthCalledWith(1, { ...execStartDoc, kibana: { @@ -1026,6 +1047,12 @@ describe('Action Executor', () => { ...execDoc.kibana.action, id: 'preconfigured', name: 'Preconfigured', + execution: { + ...execStartDoc.kibana.action.execution, + metrics: { + request_body_bytes: 0, + }, + }, }, saved_objects: [ { @@ -1074,6 +1101,7 @@ describe('Action Executor', () => { params: { foo: true }, logger: loggerMock, request: {}, + connectorMetricsCollector: expect.any(ConnectorMetricsCollector), }); expect(loggerMock.debug).toBeCalledWith( @@ -1083,6 +1111,7 @@ describe('Action Executor', () => { const execStartDoc = getBaseExecuteStartEventLogDoc(executeUnsecure); const execDoc = getBaseExecuteEventLogDoc(executeUnsecure); + addConnectorMetrics(execDoc, 0); expect(eventLogger.logEvent).toHaveBeenNthCalledWith(1, { ...execStartDoc, kibana: { @@ -1091,6 +1120,7 @@ describe('Action Executor', () => { ...execStartDoc.kibana.action, id: 'system-connector-.cases', name: 'System action: .cases', + type_id: '.cases', }, saved_objects: [ { @@ -1120,6 +1150,7 @@ describe('Action Executor', () => { ...execDoc.kibana.action, id: 'system-connector-.cases', name: 'System action: .cases', + type_id: '.cases', }, saved_objects: [ { @@ -1290,6 +1321,7 @@ describe('Action Executor', () => { }, params: { foo: true }, logger: loggerMock, + connectorMetricsCollector: expect.any(ConnectorMetricsCollector), }); } }); @@ -1385,6 +1417,7 @@ describe('Event log', () => { }, name: undefined, id: 'action1', + type_id: 'test', }, alert: { rule: { @@ -1430,6 +1463,7 @@ describe('Event log', () => { }, name: 'action-1', id: '1', + type_id: 'test', }, alert: { rule: { @@ -1483,6 +1517,7 @@ describe('Event log', () => { }, name: 'action-1', id: '1', + type_id: 'test', }, alert: { rule: { @@ -1559,9 +1594,13 @@ describe('Event log', () => { gen_ai: { usage: mockGenAi.usage, }, + metrics: { + request_body_bytes: 0, + }, }, name: 'action-1', id: '1', + type_id: '.gen-ai', }, alert: { rule: { @@ -1655,9 +1694,13 @@ describe('Event log', () => { total_tokens: 35, }, }, + metrics: { + request_body_bytes: 0, + }, }, name: 'action-1', id: '1', + type_id: '.gen-ai', }, alert: { rule: { diff --git a/x-pack/plugins/actions/server/lib/action_executor.ts b/x-pack/plugins/actions/server/lib/action_executor.ts index ec7375949fff0..271cf96d1ab17 100644 --- a/x-pack/plugins/actions/server/lib/action_executor.ts +++ b/x-pack/plugins/actions/server/lib/action_executor.ts @@ -23,7 +23,7 @@ import { IEventLogger, SAVED_OBJECT_REL_PRIMARY } from '@kbn/event-log-plugin/se import { createTaskRunError, TaskErrorSource } from '@kbn/task-manager-plugin/server'; import { getErrorSource } from '@kbn/task-manager-plugin/server/task_running'; import { GEN_AI_TOKEN_COUNT_EVENT } from './event_based_telemetry'; -import { ConnectorMetricsService } from './connector_metrics_service'; +import { ConnectorMetricsCollector } from './connector_metrics_collector'; import { getGenAiTokenTracking, shouldTrackGenAiToken } from './gen_ai_token_tracking'; import { validateConfig, @@ -294,6 +294,7 @@ export class ActionExecutor { actionExecutionId, isInMemory: this.actionInfo.isInMemory, ...(source ? { source } : {}), + actionTypeId: this.actionInfo.actionTypeId, }); eventLogger.logEvent(event); @@ -390,7 +391,7 @@ export class ActionExecutor { }, async (span) => { const { actionTypeRegistry, analyticsService, eventLogger } = this.actionExecutorContext!; - const connectorMetricsService = new ConnectorMetricsService(); + const connectorMetricsCollector = new ConnectorMetricsCollector(); const actionInfo = await this.getActionInfoInternal(actionId, namespace.namespace); @@ -479,6 +480,7 @@ export class ActionExecutor { actionExecutionId, isInMemory: this.actionInfo.isInMemory, ...(source ? { source } : {}), + actionTypeId, }); eventLogger.startTiming(event); @@ -512,7 +514,7 @@ export class ActionExecutor { logger, source, ...(actionType.isSystemActionType ? { request } : {}), - connectorMetricsService, + connectorMetricsCollector, }); if (rawResult && rawResult.status === 'error') { @@ -541,8 +543,6 @@ export class ActionExecutor { status: 'ok', }; - // console.log('body bytes ==> ', connectorMetricsService.getRequestBodyByte()); - event.event = event.event || {}; const { error, ...resultWithoutError } = result; @@ -553,6 +553,11 @@ export class ActionExecutor { event.user = event.user || {}; event.user.name = currentUser?.username; event.user.id = currentUser?.profile_uid; + set( + event, + 'kibana.action.execution.metrics.request_body_bytes', + connectorMetricsCollector.getRequestBodyByte() + ); if (result.status === 'ok') { span?.setOutcome('success'); diff --git a/x-pack/plugins/actions/server/lib/axios_utils.test.ts b/x-pack/plugins/actions/server/lib/axios_utils.test.ts index 4b9105450154f..a78a1b2537401 100644 --- a/x-pack/plugins/actions/server/lib/axios_utils.test.ts +++ b/x-pack/plugins/actions/server/lib/axios_utils.test.ts @@ -21,7 +21,7 @@ import { import { loggingSystemMock } from '@kbn/core/server/mocks'; import { actionsConfigMock } from '../actions_config.mock'; import { getCustomAgents } from './get_custom_agents'; -import { ConnectorMetricsService } from './connector_metrics_service'; +import { ConnectorMetricsCollector } from './connector_metrics_collector'; const TestUrl = 'https://elastic.co/foo/bar/baz'; @@ -80,7 +80,7 @@ describe('request', () => { }); }); - test('adds request body bytes from request header on a successful request when connectorMetricsService is provided', async () => { + test('adds request body bytes from request header on a successful request when connectorMetricsCollector is provided', async () => { const contentLength = 12; axiosMock.mockImplementation(() => ({ status: 200, @@ -90,17 +90,17 @@ describe('request', () => { headers: { 'Content-Length': contentLength }, }, })); - const connectorMetricsService = new ConnectorMetricsService(); + const connectorMetricsCollector = new ConnectorMetricsCollector(); await request({ axios, url: '/test', logger, data: { test: 12345 }, configurationUtilities, - connectorMetricsService, + connectorMetricsCollector, }); - expect(connectorMetricsService.getRequestBodyByte()).toBe(contentLength); + expect(connectorMetricsCollector.getRequestBodyByte()).toBe(contentLength); }); test('adds request body bytes from request header on a failed', async () => { @@ -111,7 +111,7 @@ describe('request', () => { headers: { 'Content-Length': contentLength }, }) ); - const connectorMetricsService = new ConnectorMetricsService(); + const connectorMetricsCollector = new ConnectorMetricsCollector(); try { await request({ @@ -119,15 +119,15 @@ describe('request', () => { url: '/test', logger, configurationUtilities, - connectorMetricsService, + connectorMetricsCollector, }); } catch (e) { - expect(connectorMetricsService.getRequestBodyByte()).toBe(contentLength); + expect(connectorMetricsCollector.getRequestBodyByte()).toBe(contentLength); } }); test('adds request body bytes from data when request header does not exist', async () => { - const connectorMetricsService = new ConnectorMetricsService(); + const connectorMetricsCollector = new ConnectorMetricsCollector(); const data = { test: 12345 }; await request({ @@ -136,10 +136,10 @@ describe('request', () => { logger, data, configurationUtilities, - connectorMetricsService, + connectorMetricsCollector, }); - expect(connectorMetricsService.getRequestBodyByte()).toBe( + expect(connectorMetricsCollector.getRequestBodyByte()).toBe( Buffer.byteLength(JSON.stringify(data), 'utf8') ); }); diff --git a/x-pack/plugins/actions/server/lib/axios_utils.ts b/x-pack/plugins/actions/server/lib/axios_utils.ts index df160bd2970b0..f1a361ad18b2b 100644 --- a/x-pack/plugins/actions/server/lib/axios_utils.ts +++ b/x-pack/plugins/actions/server/lib/axios_utils.ts @@ -17,7 +17,7 @@ import { import { Logger } from '@kbn/core/server'; import { getCustomAgents } from './get_custom_agents'; import { ActionsConfigurationUtilities } from '../actions_config'; -import { ConnectorMetricsService, SSLSettings } from '../types'; +import { ConnectorMetricsCollector, SSLSettings } from '../types'; import { combineHeadersWithBasicAuthHeader } from './get_basic_auth_header'; export const request = async ({ @@ -30,7 +30,7 @@ export const request = async ({ headers, sslOverrides, timeout, - connectorMetricsService, + connectorMetricsCollector, ...config }: { axios: AxiosInstance; @@ -42,7 +42,7 @@ export const request = async ({ headers?: Record; timeout?: number; sslOverrides?: SSLSettings; - connectorMetricsService?: ConnectorMetricsService; // TODO make optional + connectorMetricsCollector?: ConnectorMetricsCollector; // TODO make optional } & AxiosRequestConfig): Promise => { if (!isEmpty(axios?.defaults?.baseURL ?? '')) { throw new Error( @@ -80,14 +80,14 @@ export const request = async ({ timeout: Math.max(settingsTimeout, timeout ?? 0), }); - if (connectorMetricsService) { - connectorMetricsService.addRequestBodyBytes(result, data); + if (connectorMetricsCollector) { + connectorMetricsCollector.addRequestBodyBytes(result, data); } return result; } catch (error) { - if (connectorMetricsService) { - connectorMetricsService.addRequestBodyBytes(error, data); + if (connectorMetricsCollector) { + connectorMetricsCollector.addRequestBodyBytes(error, data); } throw error; } @@ -99,14 +99,14 @@ export const patch = async ({ data, logger, configurationUtilities, - connectorMetricsService, + connectorMetricsCollector, }: { axios: AxiosInstance; url: string; data: T; logger: Logger; configurationUtilities: ActionsConfigurationUtilities; - connectorMetricsService?: ConnectorMetricsService; + connectorMetricsCollector?: ConnectorMetricsCollector; }): Promise => { return request({ axios, @@ -115,7 +115,7 @@ export const patch = async ({ method: 'patch', data, configurationUtilities, - connectorMetricsService, + connectorMetricsCollector, }); }; diff --git a/x-pack/plugins/actions/server/lib/connector_metrics_service.test.ts b/x-pack/plugins/actions/server/lib/connector_metrics_collector.test.ts similarity index 56% rename from x-pack/plugins/actions/server/lib/connector_metrics_service.test.ts rename to x-pack/plugins/actions/server/lib/connector_metrics_collector.test.ts index a75a5d9c0c2cc..09137fc1c6c87 100644 --- a/x-pack/plugins/actions/server/lib/connector_metrics_service.test.ts +++ b/x-pack/plugins/actions/server/lib/connector_metrics_collector.test.ts @@ -5,12 +5,12 @@ * 2.0. */ -import { ConnectorMetricsService } from '../types'; +import { ConnectorMetricsCollector } from '../types'; import { AxiosHeaders, AxiosResponse } from 'axios'; -describe('ConnectorMetricsService', () => { +describe('ConnectorMetricsCollector', () => { test('it collects requestBodyBytes from response.request.headers', async () => { - const connectorMetricsService = new ConnectorMetricsService(); + const connectorMetricsCollector = new ConnectorMetricsCollector(); const data = { test: 'foo' }; const contentLength = Buffer.byteLength(JSON.stringify(data), 'utf8'); @@ -25,16 +25,16 @@ describe('ConnectorMetricsService', () => { }, }; - connectorMetricsService.addRequestBodyBytes(axiosResponse, data); + connectorMetricsCollector.addRequestBodyBytes(axiosResponse, data); - expect(connectorMetricsService.getRequestBodyByte()).toBe(contentLength); + expect(connectorMetricsCollector.getRequestBodyByte()).toBe(contentLength); - connectorMetricsService.addRequestBodyBytes(axiosResponse, data); + connectorMetricsCollector.addRequestBodyBytes(axiosResponse, data); - expect(connectorMetricsService.getRequestBodyByte()).toBe(contentLength + contentLength); + expect(connectorMetricsCollector.getRequestBodyByte()).toBe(contentLength + contentLength); }); test('it collects requestBodyBytes from data when response.request.headers is missing', async () => { - const connectorMetricsService = new ConnectorMetricsService(); + const connectorMetricsCollector = new ConnectorMetricsCollector(); const data = { test: 'foo' }; const contentLength = Buffer.byteLength(JSON.stringify(data), 'utf8'); @@ -46,12 +46,12 @@ describe('ConnectorMetricsService', () => { config: { headers: new AxiosHeaders() }, }; - connectorMetricsService.addRequestBodyBytes(axiosResponse, data); + connectorMetricsCollector.addRequestBodyBytes(axiosResponse, data); - expect(connectorMetricsService.getRequestBodyByte()).toBe(contentLength); + expect(connectorMetricsCollector.getRequestBodyByte()).toBe(contentLength); - connectorMetricsService.addRequestBodyBytes(axiosResponse, data); + connectorMetricsCollector.addRequestBodyBytes(axiosResponse, data); - expect(connectorMetricsService.getRequestBodyByte()).toBe(contentLength + contentLength); + expect(connectorMetricsCollector.getRequestBodyByte()).toBe(contentLength + contentLength); }); }); diff --git a/x-pack/plugins/actions/server/lib/connector_metrics_service.ts b/x-pack/plugins/actions/server/lib/connector_metrics_collector.ts similarity index 95% rename from x-pack/plugins/actions/server/lib/connector_metrics_service.ts rename to x-pack/plugins/actions/server/lib/connector_metrics_collector.ts index 7e62c3f941d18..580ab70752f1b 100644 --- a/x-pack/plugins/actions/server/lib/connector_metrics_service.ts +++ b/x-pack/plugins/actions/server/lib/connector_metrics_collector.ts @@ -11,7 +11,7 @@ interface ConnectorMetrics { requestBodyBytes: number; } -export class ConnectorMetricsService { +export class ConnectorMetricsCollector { private metrics: ConnectorMetrics = { requestBodyBytes: 0, }; diff --git a/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.ts b/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.ts index 4f8bf08966c59..c3b7a3b35f512 100644 --- a/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.ts +++ b/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.ts @@ -37,6 +37,7 @@ interface CreateActionEventLogRecordParams { relatedSavedObjects?: RelatedSavedObjects; isInMemory?: boolean; source?: ActionExecutionSource; + actionTypeId: string; } export function createActionEventLogRecordObject(params: CreateActionEventLogRecordParams): Event { @@ -54,6 +55,7 @@ export function createActionEventLogRecordObject(params: CreateActionEventLogRec isInMemory, actionId, source, + actionTypeId, } = params; const kibanaAlertRule = { @@ -89,6 +91,7 @@ export function createActionEventLogRecordObject(params: CreateActionEventLogRec action: { ...(name ? { name } : {}), id: actionId, + type_id: actionTypeId, execution: { uuid: actionExecutionId, }, diff --git a/x-pack/plugins/actions/server/lib/index.ts b/x-pack/plugins/actions/server/lib/index.ts index ada48f8beefd0..07939fc920590 100644 --- a/x-pack/plugins/actions/server/lib/index.ts +++ b/x-pack/plugins/actions/server/lib/index.ts @@ -39,4 +39,4 @@ export { validateEmptyStrings } from './validate_empty_strings'; export { parseDate } from './parse_date'; export type { RelatedSavedObjects } from './related_saved_objects'; export { getBasicAuthHeader, combineHeadersWithBasicAuthHeader } from './get_basic_auth_header'; -export { ConnectorMetricsService } from './connector_metrics_service'; +export { ConnectorMetricsCollector } from './connector_metrics_collector'; diff --git a/x-pack/plugins/actions/server/sub_action_framework/case.test.ts b/x-pack/plugins/actions/server/sub_action_framework/case.test.ts index 387cc77af3380..c74adabca30e8 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/case.test.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/case.test.ts @@ -12,13 +12,14 @@ import { actionsConfigMock } from '../actions_config.mock'; import { actionsMock } from '../mocks'; import { TestCaseConnector } from './mocks'; import { ActionsConfigurationUtilities } from '../actions_config'; -import { ConnectorMetricsService } from '../lib'; +import { ConnectorMetricsCollector } from '../lib'; describe('CaseConnector', () => { let logger: MockedLogger; let services: ReturnType; let mockedActionsConfig: jest.Mocked; let service: TestCaseConnector; + let connectorMetricsCollector: ConnectorMetricsCollector; const pushToServiceIncidentParamsSchema = { name: schema.string(), category: schema.nullable(schema.string()), @@ -27,7 +28,6 @@ describe('CaseConnector', () => { check: schema.nullable(schema.number()), }), }; - const getConnectorMetricsService = () => new ConnectorMetricsService(); const incidentSchemaMock = { name: 'Test', category: null, foo: [false], bar: { check: 1 } }; const pushToServiceParams = { @@ -59,6 +59,8 @@ describe('CaseConnector', () => { }, pushToServiceIncidentParamsSchema ); + + connectorMetricsCollector = new ConnectorMetricsCollector(); }); describe('Sub actions', () => { @@ -193,7 +195,7 @@ describe('CaseConnector', () => { describe('pushToService', () => { it('should create an incident if externalId is null', async () => { - const res = await service.pushToService(pushToServiceParams, getConnectorMetricsService()); + const res = await service.pushToService(pushToServiceParams, connectorMetricsCollector); expect(res).toEqual({ id: 'create-incident', title: 'Test incident', @@ -208,7 +210,7 @@ describe('CaseConnector', () => { incident: { ...pushToServiceParams.incident, externalId: 'test-id' }, comments: [], }, - getConnectorMetricsService() + connectorMetricsCollector ); expect(res).toEqual({ @@ -228,7 +230,7 @@ describe('CaseConnector', () => { { comment: 'comment-2', commentId: 'comment-id-2' }, ], }, - getConnectorMetricsService() + connectorMetricsCollector ); expect(res).toEqual({ @@ -256,7 +258,7 @@ describe('CaseConnector', () => { // @ts-expect-error comments, }, - getConnectorMetricsService() + connectorMetricsCollector ); expect(res).toEqual({ @@ -273,7 +275,7 @@ describe('CaseConnector', () => { ...pushToServiceParams, comments: [], }, - getConnectorMetricsService() + connectorMetricsCollector ); expect(res).toEqual({ diff --git a/x-pack/plugins/actions/server/sub_action_framework/case.ts b/x-pack/plugins/actions/server/sub_action_framework/case.ts index 73ddbd582ea7f..b03d6e3001205 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/case.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/case.ts @@ -9,16 +9,16 @@ import { schema, Type } from '@kbn/config-schema'; import { ExternalServiceIncidentResponse, PushToServiceResponse } from './types'; import { SubActionConnector } from './sub_action_connector'; import { ServiceParams } from './types'; -import { ConnectorMetricsService } from '../lib'; +import { ConnectorMetricsCollector } from '../lib'; export interface CaseConnectorInterface { addComment: ( { incidentId, comment }: { incidentId: string; comment: string }, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ) => Promise; createIncident: ( incident: Incident, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ) => Promise; updateIncident: ( { @@ -28,18 +28,18 @@ export interface CaseConnectorInterface { incidentId: string; incident: Incident; }, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ) => Promise; getIncident: ( { id }: { id: string }, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ) => Promise; pushToService: ( params: { incident: { externalId: string | null } & Incident; comments: Array<{ commentId: string; comment: string }>; }, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ) => Promise; } @@ -80,12 +80,12 @@ export abstract class CaseConnector; public abstract createIncident( incident: Incident, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): Promise; public abstract updateIncident( { @@ -95,11 +95,11 @@ export abstract class CaseConnector; public abstract getIncident( { id }: { id: string }, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): Promise; public async pushToService( @@ -107,7 +107,7 @@ export abstract class CaseConnector; }, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ) { const { incident, comments } = params; const { externalId, ...rest } = incident; @@ -120,10 +120,10 @@ export abstract class CaseConnector 0) { @@ -135,7 +135,7 @@ export abstract class CaseConnector { const actionId = 'test-action-id'; @@ -31,7 +31,7 @@ describe('Executor', () => { let logger: MockedLogger; let services: ReturnType; let mockedActionsConfig: jest.Mocked; - const getConnectorMetricsService = () => new ConnectorMetricsService(); + let connectorMetricsCollector: ConnectorMetricsCollector; const createExecutor = (Service: IService) => { const connector = { @@ -57,6 +57,7 @@ describe('Executor', () => { logger = loggingSystemMock.createLogger(); services = actionsMock.createServices(); mockedActionsConfig = actionsConfigMock.create(); + connectorMetricsCollector = new ConnectorMetricsCollector(); }); it('should execute correctly', async () => { @@ -70,7 +71,7 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, - connectorMetricsService: getConnectorMetricsService(), + connectorMetricsCollector, }); expect(res).toEqual({ @@ -93,7 +94,7 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, - connectorMetricsService: getConnectorMetricsService(), + connectorMetricsCollector, }); expect(res).toEqual({ @@ -116,7 +117,7 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, - connectorMetricsService: getConnectorMetricsService(), + connectorMetricsCollector, }); expect(res).toEqual({ @@ -137,7 +138,7 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, - connectorMetricsService: getConnectorMetricsService(), + connectorMetricsCollector, }); expect(res).toEqual({ @@ -159,7 +160,7 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, - connectorMetricsService: getConnectorMetricsService(), + connectorMetricsCollector, }) ).rejects.toThrowError('You should register at least one subAction for your connector type'); }); @@ -176,7 +177,7 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, - connectorMetricsService: getConnectorMetricsService(), + connectorMetricsCollector, }) ).rejects.toThrowError( 'Sub action "not-exist" is not registered. Connector id: test-action-id. Connector name: Test. Connector type: .test' @@ -195,7 +196,7 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, - connectorMetricsService: getConnectorMetricsService(), + connectorMetricsCollector, }); } catch (e) { expect(getErrorSource(e)).toBe(TaskErrorSource.USER); @@ -217,7 +218,7 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, - connectorMetricsService: getConnectorMetricsService(), + connectorMetricsCollector, }) ).rejects.toThrowError( 'Method "not-exist" does not exists in service. Sub action: "testUrl". Connector id: test-action-id. Connector name: Test. Connector type: .test' @@ -236,7 +237,7 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, - connectorMetricsService: getConnectorMetricsService(), + connectorMetricsCollector, }) ).rejects.toThrowError( 'Method "notAFunction" must be a function. Connector id: test-action-id. Connector name: Test. Connector type: .test' @@ -255,14 +256,14 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, - connectorMetricsService: getConnectorMetricsService(), + connectorMetricsCollector, }) ).rejects.toThrowError( 'Request validation failed (Error: [id]: expected value of type [string] but got [undefined])' ); }); - it('Passes connectorMetricsService to the subAction method as a second param', async () => { + it('Passes connectorMetricsCollector to the subAction method as a second param', async () => { let echoSpy; const subActionParams = { id: 'test-id' }; @@ -282,15 +283,13 @@ describe('Executor', () => { }, }; - const connectorMetricsService = new ConnectorMetricsService(); - const executor = buildExecutor({ configurationUtilities: mockedActionsConfig, logger, connector, }); - executor({ + await executor({ actionId, params: { subAction: 'echo', subActionParams }, config, @@ -298,9 +297,9 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, - connectorMetricsService, + connectorMetricsCollector, }); - expect(echoSpy).toHaveBeenCalledWith(subActionParams, connectorMetricsService); + expect(echoSpy).toHaveBeenCalledWith(subActionParams, connectorMetricsCollector); }); }); diff --git a/x-pack/plugins/actions/server/sub_action_framework/executor.ts b/x-pack/plugins/actions/server/sub_action_framework/executor.ts index 5e8d79264b3e6..50c6b0d760e2a 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/executor.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/executor.ts @@ -37,7 +37,7 @@ export const buildExecutor = < secrets, services, request, - connectorMetricsService, + connectorMetricsCollector, }) => { const subAction = params.subAction; const subActionParams = params.subActionParams; @@ -96,7 +96,7 @@ export const buildExecutor = < } } - const data = await func.call(service, subActionParams, connectorMetricsService); + const data = await func.call(service, subActionParams, connectorMetricsCollector); return { status: 'ok', data: data ?? {}, actionId }; }; }; diff --git a/x-pack/plugins/actions/server/sub_action_framework/mocks.ts b/x-pack/plugins/actions/server/sub_action_framework/mocks.ts index adc026cf7f777..2ed6afe191501 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/mocks.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/mocks.ts @@ -8,7 +8,7 @@ import { schema, Type, TypeOf } from '@kbn/config-schema'; import { AxiosError } from 'axios'; -import { ConnectorMetricsService } from '../lib'; +import { ConnectorMetricsCollector } from '../lib'; import { SubActionConnector } from './sub_action_connector'; import { CaseConnector } from './case'; import { ExternalServiceIncidentResponse, ServiceParams } from './types'; @@ -60,7 +60,7 @@ export class TestSubActionConnector extends SubActionConnector | null }, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ) { const res = await this.request( { @@ -69,7 +69,7 @@ export class TestSubActionConnector extends SubActionConnector }, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ) { const res = await this.request( { @@ -86,7 +86,7 @@ export class TestSubActionConnector extends SubActionConnector } = {}, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ) { const res = await this.request( { @@ -104,7 +104,7 @@ export class TestSubActionConnector extends SubActionConnector { return error; }; -const getConnectorMetricsService = () => new ConnectorMetricsService(); describe('SubActionConnector', () => { const axiosInstanceMock = jest.fn(); @@ -45,6 +44,7 @@ describe('SubActionConnector', () => { let services: ReturnType; let mockedActionsConfig: jest.Mocked; let service: TestSubActionConnector; + let connectorMetricsCollector: ConnectorMetricsCollector; beforeEach(() => { jest.resetAllMocks(); @@ -72,6 +72,8 @@ describe('SubActionConnector', () => { secrets: { username: 'elastic', password: 'changeme' }, services, }); + + connectorMetricsCollector = new ConnectorMetricsCollector(); }); describe('Sub actions', () => { @@ -89,34 +91,34 @@ describe('SubActionConnector', () => { it('removes double slashes correctly', async () => { await service.testUrl( { url: 'https://example.com//api///test-endpoint' }, - getConnectorMetricsService() + connectorMetricsCollector ); expect(requestMock.mock.calls[0][0].url).toBe('https://example.com/api/test-endpoint'); }); it('removes the ending slash correctly', async () => { - await service.testUrl({ url: 'https://example.com/' }, getConnectorMetricsService()); + await service.testUrl({ url: 'https://example.com/' }, connectorMetricsCollector); expect(requestMock.mock.calls[0][0].url).toBe('https://example.com'); }); it('throws an error if the url is invalid', async () => { expect.assertions(1); await expect(async () => - service.testUrl({ url: 'invalid-url' }, getConnectorMetricsService()) + service.testUrl({ url: 'invalid-url' }, connectorMetricsCollector) ).rejects.toThrow('URL Error: Invalid URL: invalid-url'); }); it('throws an error if the url starts with backslashes', async () => { expect.assertions(1); await expect(async () => - service.testUrl({ url: '//example.com/foo' }, getConnectorMetricsService()) + service.testUrl({ url: '//example.com/foo' }, connectorMetricsCollector) ).rejects.toThrow('URL Error: Invalid URL: //example.com/foo'); }); it('throws an error if the protocol is not supported', async () => { expect.assertions(1); await expect(async () => - service.testUrl({ url: 'ftp://example.com' }, getConnectorMetricsService()) + service.testUrl({ url: 'ftp://example.com' }, connectorMetricsCollector) ).rejects.toThrow('URL Error: Invalid protocol'); }); @@ -128,17 +130,14 @@ describe('SubActionConnector', () => { }); await expect(async () => - service.testUrl({ url: 'https://example.com' }, getConnectorMetricsService()) + service.testUrl({ url: 'https://example.com' }, connectorMetricsCollector) ).rejects.toThrow('error configuring connector action: URI is not allowed'); }); }); describe('Data', () => { it('sets data to an empty object if the data are null', async () => { - await service.testUrl( - { url: 'https://example.com', data: null }, - getConnectorMetricsService() - ); + await service.testUrl({ url: 'https://example.com', data: null }, connectorMetricsCollector); expect(requestMock).toHaveBeenCalledTimes(1); const { data } = requestMock.mock.calls[0][0]; @@ -148,7 +147,7 @@ describe('SubActionConnector', () => { it('pass data to axios correctly if not null', async () => { await service.testUrl( { url: 'https://example.com', data: { foo: 'foo' } }, - getConnectorMetricsService() + connectorMetricsCollector ); expect(requestMock).toHaveBeenCalledTimes(1); @@ -159,7 +158,7 @@ describe('SubActionConnector', () => { it('removeNullOrUndefinedFields: removes null values and undefined values correctly', async () => { await service.testData( { data: { foo: 'foo', bar: null, baz: undefined } }, - getConnectorMetricsService() + connectorMetricsCollector ); expect(requestMock).toHaveBeenCalledTimes(1); @@ -181,8 +180,7 @@ describe('SubActionConnector', () => { describe('Fetching', () => { it('fetch correctly', async () => { - const connectorMetricsService = getConnectorMetricsService(); - const res = await service.testUrl({ url: 'https://example.com' }, connectorMetricsService); + const res = await service.testUrl({ url: 'https://example.com' }, connectorMetricsCollector); expect(requestMock).toHaveBeenCalledTimes(1); expect(requestMock).toBeCalledWith({ @@ -196,7 +194,7 @@ describe('SubActionConnector', () => { 'X-Test-Header': 'test', }, url: 'https://example.com', - connectorMetricsService, + connectorMetricsCollector, }); expect(logger.debug).toBeCalledWith( @@ -209,7 +207,7 @@ describe('SubActionConnector', () => { it('validates the response correctly', async () => { requestMock.mockReturnValue({ data: { invalidField: 'test' } }); await expect(async () => - service.testUrl({ url: 'https://example.com' }, getConnectorMetricsService()) + service.testUrl({ url: 'https://example.com' }, connectorMetricsCollector) ).rejects.toThrow( 'Response validation failed (Error: [status]: expected value of type [string] but got [undefined])' ); @@ -221,7 +219,7 @@ describe('SubActionConnector', () => { }); await expect(async () => - service.testUrl({ url: 'https://example.com' }, getConnectorMetricsService()) + service.testUrl({ url: 'https://example.com' }, connectorMetricsCollector) ).rejects.toThrow('Message: An error occurred. Code: 500'); expect(logger.debug).toHaveBeenLastCalledWith( @@ -230,9 +228,7 @@ describe('SubActionConnector', () => { }); it('converts auth axios property to a basic auth header if provided', async () => { - const connectorMetricsService = getConnectorMetricsService(); - - await service.testAuth(undefined, connectorMetricsService); + await service.testAuth(undefined, connectorMetricsCollector); expect(requestMock).toHaveBeenCalledTimes(1); expect(requestMock).toBeCalledWith({ @@ -247,16 +243,14 @@ describe('SubActionConnector', () => { Authorization: `Basic ${Buffer.from('username:password').toString('base64')}`, }, url: 'https://example.com', - connectorMetricsService, + connectorMetricsCollector, }); }); it('does not override an authorization header if provided', async () => { - const connectorMetricsService = getConnectorMetricsService(); - await service.testAuth( { headers: { Authorization: 'Bearer my_token' } }, - connectorMetricsService + connectorMetricsCollector ); expect(requestMock).toHaveBeenCalledTimes(1); @@ -272,7 +266,7 @@ describe('SubActionConnector', () => { Authorization: 'Bearer my_token', }, url: 'https://example.com', - connectorMetricsService, + connectorMetricsCollector, }); }); }); diff --git a/x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.ts b/x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.ts index d0d00b9d9be23..5c43683f1e58e 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.ts @@ -24,7 +24,7 @@ import { IncomingMessage } from 'http'; import { PassThrough } from 'stream'; import { KibanaRequest } from '@kbn/core-http-server'; import { inspect } from 'util'; -import { ConnectorMetricsService } from '../lib'; +import { ConnectorMetricsCollector } from '../lib'; import { assertURL } from './helpers/validators'; import { ActionsConfigurationUtilities } from '../actions_config'; import { SubAction, SubActionRequestParams } from './types'; @@ -141,7 +141,7 @@ export abstract class SubActionConnector { timeout, ...config }: SubActionRequestParams, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): Promise> { try { this.assertURL(url); @@ -164,7 +164,7 @@ export abstract class SubActionConnector { configurationUtilities: this.configurationUtilities, headers: this.getHeaders(auth, headers as AxiosHeaders), timeout, - connectorMetricsService, + connectorMetricsCollector, }); this.validateResponse(responseSchema, res.data); diff --git a/x-pack/plugins/actions/server/types.ts b/x-pack/plugins/actions/server/types.ts index d4bb89618e0e5..ffac1a9151c42 100644 --- a/x-pack/plugins/actions/server/types.ts +++ b/x-pack/plugins/actions/server/types.ts @@ -40,8 +40,8 @@ export type ActionTypeParams = Record; export type ConnectorTokenClientContract = PublicMethodsOf; import { Connector, ConnectorWithExtraFindData } from './application/connector/types'; -import type { ActionExecutionSource, ConnectorMetricsService } from './lib'; -export { ActionExecutionSourceType, ConnectorMetricsService } from './lib'; +import type { ActionExecutionSource, ConnectorMetricsCollector } from './lib'; +export { ActionExecutionSourceType, ConnectorMetricsCollector } from './lib'; export interface Services { savedObjectsClient: SavedObjectsClientContract; @@ -86,7 +86,7 @@ export interface ActionTypeExecutorOptions< configurationUtilities: ActionsConfigurationUtilities; source?: ActionExecutionSource; request?: KibanaRequest; - connectorMetricsService: ConnectorMetricsService; + connectorMetricsCollector: ConnectorMetricsCollector; } export type ActionResult = Connector; diff --git a/x-pack/plugins/event_log/generated/mappings.json b/x-pack/plugins/event_log/generated/mappings.json index 98908f516fc96..9626958958ff7 100644 --- a/x-pack/plugins/event_log/generated/mappings.json +++ b/x-pack/plugins/event_log/generated/mappings.json @@ -482,6 +482,10 @@ "type": "keyword", "ignore_above": 1024 }, + "type_id": { + "type": "keyword", + "ignore_above": 1024 + }, "execution": { "properties": { "source": { @@ -508,6 +512,13 @@ } } } + }, + "metrics": { + "properties": { + "request_body_bytes": { + "type": "long" + } + } } } } diff --git a/x-pack/plugins/event_log/generated/schemas.ts b/x-pack/plugins/event_log/generated/schemas.ts index f8db21105539e..eac5fe08ee0be 100644 --- a/x-pack/plugins/event_log/generated/schemas.ts +++ b/x-pack/plugins/event_log/generated/schemas.ts @@ -212,6 +212,7 @@ export const EventSchema = schema.maybe( schema.object({ name: ecsString(), id: ecsString(), + type_id: ecsString(), execution: schema.maybe( schema.object({ source: ecsString(), @@ -227,6 +228,11 @@ export const EventSchema = schema.maybe( ), }) ), + metrics: schema.maybe( + schema.object({ + request_body_bytes: ecsStringOrNumber(), + }) + ), }) ), }) diff --git a/x-pack/plugins/event_log/scripts/mappings.js b/x-pack/plugins/event_log/scripts/mappings.js index aa91f7fc5c2d6..360faaf488b9b 100644 --- a/x-pack/plugins/event_log/scripts/mappings.js +++ b/x-pack/plugins/event_log/scripts/mappings.js @@ -257,6 +257,10 @@ exports.EcsCustomPropertyMappings = { type: 'keyword', ignore_above: 1024, }, + type_id: { + type: 'keyword', + ignore_above: 1024, + }, execution: { properties: { source: { @@ -284,6 +288,13 @@ exports.EcsCustomPropertyMappings = { }, }, }, + metrics: { + properties: { + request_body_bytes: { + type: 'long', + }, + }, + }, }, }, }, diff --git a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.test.ts index 7090bf8092e45..96a51d47f0988 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.test.ts @@ -25,7 +25,7 @@ import { import { DEFAULT_BODY } from '../../../public/connector_types/bedrock/constants'; import { initDashboard } from '../lib/gen_ai/create_gen_ai_dashboard'; import { AxiosError } from 'axios'; -import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; +import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; jest.mock('../lib/gen_ai/create_gen_ai_dashboard'); // @ts-ignore @@ -58,7 +58,7 @@ describe('BedrockConnector', () => { headers: {}, data: claude3Response, }; - let connectorMetricsService: ConnectorMetricsService; + let connectorMetricsCollector: ConnectorMetricsCollector; beforeEach(() => { jest.clearAllMocks(); @@ -66,7 +66,7 @@ describe('BedrockConnector', () => { mockError = jest.fn().mockImplementation(() => { throw new Error('API Error'); }); - connectorMetricsService = new ConnectorMetricsService(); + connectorMetricsCollector = new ConnectorMetricsCollector(); }); const connector = new BedrockConnector({ @@ -89,7 +89,7 @@ describe('BedrockConnector', () => { describe('runApi', () => { it('the aws signature has non-streaming headers', async () => { - await connector.runApi({ body: DEFAULT_BODY }, new ConnectorMetricsService()); + await connector.runApi({ body: DEFAULT_BODY }, new ConnectorMetricsCollector()); expect(mockSigner).toHaveBeenCalledWith( { body: DEFAULT_BODY, @@ -105,7 +105,7 @@ describe('BedrockConnector', () => { ); }); it('the Bedrock API call is successful with Claude 3 parameters; returns the response formatted for Claude 2 along with usage object', async () => { - const response = await connector.runApi({ body: DEFAULT_BODY }, connectorMetricsService); + const response = await connector.runApi({ body: DEFAULT_BODY }, connectorMetricsCollector); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( { @@ -116,7 +116,7 @@ describe('BedrockConnector', () => { responseSchema: RunApiLatestResponseSchema, data: DEFAULT_BODY, }, - connectorMetricsService + connectorMetricsCollector ); expect(response).toEqual({ ...claude2Response, @@ -135,7 +135,7 @@ describe('BedrockConnector', () => { }); // @ts-ignore connector.request = mockRequest; - const response = await connector.runApi({ body: v2Body }, connectorMetricsService); + const response = await connector.runApi({ body: v2Body }, connectorMetricsCollector); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( { @@ -146,7 +146,7 @@ describe('BedrockConnector', () => { responseSchema: RunActionResponseSchema, data: v2Body, }, - connectorMetricsService + connectorMetricsCollector ); expect(response).toEqual(claude2Response); }); @@ -156,7 +156,7 @@ describe('BedrockConnector', () => { connector.request = mockError; await expect( - connector.runApi({ body: DEFAULT_BODY }, new ConnectorMetricsService()) + connector.runApi({ body: DEFAULT_BODY }, new ConnectorMetricsCollector()) ).rejects.toThrow('API Error'); }); }); @@ -182,7 +182,7 @@ describe('BedrockConnector', () => { }; it('the aws signature has streaming headers', async () => { - await connector.invokeStream(aiAssistantBody, connectorMetricsService); + await connector.invokeStream(aiAssistantBody, connectorMetricsCollector); expect(mockSigner).toHaveBeenCalledWith( { @@ -201,7 +201,7 @@ describe('BedrockConnector', () => { }); it('the API call is successful with correct request parameters', async () => { - await connector.invokeStream(aiAssistantBody, connectorMetricsService); + await connector.invokeStream(aiAssistantBody, connectorMetricsCollector); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( { @@ -212,7 +212,7 @@ describe('BedrockConnector', () => { responseType: 'stream', data: JSON.stringify({ ...JSON.parse(DEFAULT_BODY), temperature: 0 }), }, - connectorMetricsService + connectorMetricsCollector ); }); @@ -221,7 +221,7 @@ describe('BedrockConnector', () => { const timeout = 180000; await connector.invokeStream( { ...aiAssistantBody, timeout, signal }, - connectorMetricsService + connectorMetricsCollector ); expect(mockRequest).toHaveBeenCalledWith( @@ -235,7 +235,7 @@ describe('BedrockConnector', () => { timeout, signal, }, - connectorMetricsService + connectorMetricsCollector ); }); @@ -261,7 +261,7 @@ describe('BedrockConnector', () => { }, ], }, - connectorMetricsService + connectorMetricsCollector ); expect(mockRequest).toHaveBeenCalledWith( { @@ -282,7 +282,7 @@ describe('BedrockConnector', () => { temperature: 0, }), }, - connectorMetricsService + connectorMetricsCollector ); }); @@ -316,7 +316,7 @@ describe('BedrockConnector', () => { }, ], }, - connectorMetricsService + connectorMetricsCollector ); expect(mockRequest).toHaveBeenCalledWith( { @@ -336,7 +336,7 @@ describe('BedrockConnector', () => { temperature: 0, }), }, - connectorMetricsService + connectorMetricsCollector ); }); @@ -365,7 +365,7 @@ describe('BedrockConnector', () => { ], model: modelOverride, }, - connectorMetricsService + connectorMetricsCollector ); expect(mockRequest).toHaveBeenCalledWith( { @@ -386,12 +386,12 @@ describe('BedrockConnector', () => { temperature: 0, }), }, - connectorMetricsService + connectorMetricsCollector ); }); it('responds with a readable stream', async () => { - const response = await connector.invokeStream(aiAssistantBody, connectorMetricsService); + const response = await connector.invokeStream(aiAssistantBody, connectorMetricsCollector); expect(response instanceof PassThrough).toEqual(true); }); @@ -400,7 +400,7 @@ describe('BedrockConnector', () => { connector.request = mockError; await expect( - connector.invokeStream(aiAssistantBody, connectorMetricsService) + connector.invokeStream(aiAssistantBody, connectorMetricsCollector) ).rejects.toThrow('API Error'); }); }); @@ -417,7 +417,7 @@ describe('BedrockConnector', () => { }; it('the API call is successful with correct parameters', async () => { - const response = await connector.invokeAI(aiAssistantBody, connectorMetricsService); + const response = await connector.invokeAI(aiAssistantBody, connectorMetricsCollector); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( { @@ -433,7 +433,7 @@ describe('BedrockConnector', () => { temperature: 0, }), }, - connectorMetricsService + connectorMetricsCollector ); expect(response.message).toEqual(mockResponseString); }); @@ -460,7 +460,7 @@ describe('BedrockConnector', () => { }, ], }, - connectorMetricsService + connectorMetricsCollector ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( @@ -482,7 +482,7 @@ describe('BedrockConnector', () => { temperature: 0, }), }, - connectorMetricsService + connectorMetricsCollector ); expect(response.message).toEqual(mockResponseString); }); @@ -506,7 +506,7 @@ describe('BedrockConnector', () => { ], system: 'This is a system message', }, - connectorMetricsService + connectorMetricsCollector ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( @@ -528,7 +528,7 @@ describe('BedrockConnector', () => { temperature: 0, }), }, - connectorMetricsService + connectorMetricsCollector ); expect(response.message).toEqual(mockResponseString); }); @@ -556,7 +556,7 @@ describe('BedrockConnector', () => { ], system: 'This is a system message', }, - connectorMetricsService + connectorMetricsCollector ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( @@ -578,14 +578,17 @@ describe('BedrockConnector', () => { temperature: 0, }), }, - connectorMetricsService + connectorMetricsCollector ); expect(response.message).toEqual(mockResponseString); }); it('signal and timeout is properly passed to runApi', async () => { const signal = jest.fn(); const timeout = 180000; - await connector.invokeAI({ ...aiAssistantBody, timeout, signal }, connectorMetricsService); + await connector.invokeAI( + { ...aiAssistantBody, timeout, signal }, + connectorMetricsCollector + ); expect(mockRequest).toHaveBeenCalledWith( { @@ -602,16 +605,16 @@ describe('BedrockConnector', () => { timeout, signal, }, - connectorMetricsService + connectorMetricsCollector ); }); it('errors during API calls are properly handled', async () => { // @ts-ignore connector.request = mockError; - await expect(connector.invokeAI(aiAssistantBody, connectorMetricsService)).rejects.toThrow( - 'API Error' - ); + await expect( + connector.invokeAI(aiAssistantBody, connectorMetricsCollector) + ).rejects.toThrow('API Error'); }); }); describe('getResponseErrorMessage', () => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.ts b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.ts index c9c4a3404d6ae..c79827df550bc 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.ts @@ -11,7 +11,7 @@ import { AxiosError, Method } from 'axios'; import { IncomingMessage } from 'http'; import { PassThrough } from 'stream'; import { SubActionRequestParams } from '@kbn/actions-plugin/server/sub_action_framework/types'; -import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; +import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; import { initDashboard } from '../lib/gen_ai/create_gen_ai_dashboard'; import { RunActionParamsSchema, @@ -186,17 +186,17 @@ The Kibana Connector in use may need to be reconfigured with an updated Amazon B private async runApiDeprecated( params: SubActionRequestParams, // : SubActionRequestParams - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): Promise { - const response = await this.request(params, connectorMetricsService); + const response = await this.request(params, connectorMetricsCollector); return response.data; } private async runApiLatest( params: SubActionRequestParams, // : SubActionRequestParams - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): Promise { - const response = await this.request(params, connectorMetricsService); + const response = await this.request(params, connectorMetricsCollector); // keeping the response the same as claude 2 for our APIs // adding the usage object for better token tracking return { @@ -213,7 +213,7 @@ The Kibana Connector in use may need to be reconfigured with an updated Amazon B */ public async runApi( { body, model: reqModel, signal, timeout }: RunActionParams, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): Promise { // set model on per request basis const currentModel = reqModel ?? this.model; @@ -232,12 +232,12 @@ The Kibana Connector in use may need to be reconfigured with an updated Amazon B if (usesDeprecatedArguments(body)) { return this.runApiDeprecated( { ...requestArgs, responseSchema: RunActionResponseSchema }, - connectorMetricsService + connectorMetricsCollector ); } return this.runApiLatest( { ...requestArgs, responseSchema: RunApiLatestResponseSchema }, - connectorMetricsService + connectorMetricsCollector ); } @@ -251,7 +251,7 @@ The Kibana Connector in use may need to be reconfigured with an updated Amazon B */ private async streamApi( { body, model: reqModel, signal, timeout }: RunActionParams, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): Promise { // set model on per request basis const path = `/model/${reqModel ?? this.model}/invoke-with-response-stream`; @@ -268,7 +268,7 @@ The Kibana Connector in use may need to be reconfigured with an updated Amazon B signal, timeout, }, - connectorMetricsService + connectorMetricsCollector ); return response.data.pipe(new PassThrough()); @@ -284,7 +284,7 @@ The Kibana Connector in use may need to be reconfigured with an updated Amazon B */ public async invokeStream( { messages, model, stopSequences, system, temperature, signal, timeout }: InvokeAIActionParams, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): Promise { const res = (await this.streamApi( { @@ -293,7 +293,7 @@ The Kibana Connector in use may need to be reconfigured with an updated Amazon B signal, timeout, }, - connectorMetricsService + connectorMetricsCollector )) as unknown as IncomingMessage; return res; } @@ -317,7 +317,7 @@ The Kibana Connector in use may need to be reconfigured with an updated Amazon B signal, timeout, }: InvokeAIActionParams, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): Promise { const res = await this.runApi( { @@ -328,7 +328,7 @@ The Kibana Connector in use may need to be reconfigured with an updated Amazon B signal, timeout, }, - connectorMetricsService + connectorMetricsCollector ); return { message: res.completion.trim() }; } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/index.ts index a9964b4106eca..431fb3ed7984b 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/index.ts @@ -70,7 +70,8 @@ export async function executor( CasesWebhookActionParamsType > ): Promise> { - const { actionId, configurationUtilities, params, logger, connectorMetricsService } = execOptions; + const { actionId, configurationUtilities, params, logger, connectorMetricsCollector } = + execOptions; const { subAction, subActionParams } = params; let data: CasesWebhookExecutorResultData | undefined; @@ -82,7 +83,7 @@ export async function executor( }, logger, configurationUtilities, - connectorMetricsService + connectorMetricsCollector ); if (!api[subAction]) { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts index ff06844c34952..7d1ea93b662db 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts @@ -13,7 +13,7 @@ import { CasesWebhookPublicConfigurationType, ExternalService } from './types'; import { Logger } from '@kbn/core/server'; import { loggingSystemMock } from '@kbn/core/server/mocks'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; -import { ConnectorMetricsService, getBasicAuthHeader } from '@kbn/actions-plugin/server/lib'; +import { ConnectorMetricsCollector, getBasicAuthHeader } from '@kbn/actions-plugin/server/lib'; import { AuthType, WebhookMethods, SSLCertType } from '../../../common/auth/constants'; import { CRT_FILE, KEY_FILE } from '../../../common/auth/mocks'; @@ -69,14 +69,14 @@ const sslConfig: CasesWebhookPublicConfigurationType = { hasAuth: true, }; const sslSecrets = { crt: CRT_FILE, key: KEY_FILE, password: 'foobar', user: null, pfx: null }; -let connectorMetricsService: ConnectorMetricsService; +let connectorMetricsCollector: ConnectorMetricsCollector; describe('Cases webhook service', () => { let service: ExternalService; let sslService: ExternalService; beforeAll(() => { - connectorMetricsService = new ConnectorMetricsService(); + connectorMetricsCollector = new ConnectorMetricsCollector(); service = createExternalService( actionId, { @@ -85,7 +85,7 @@ describe('Cases webhook service', () => { }, logger, configurationUtilities, - connectorMetricsService + connectorMetricsCollector ); sslService = createExternalService( @@ -96,7 +96,7 @@ describe('Cases webhook service', () => { }, logger, configurationUtilities, - connectorMetricsService + connectorMetricsCollector ); jest.useFakeTimers(); jest.setSystemTime(mockTime); @@ -126,7 +126,7 @@ describe('Cases webhook service', () => { }, logger, configurationUtilities, - connectorMetricsService + connectorMetricsCollector ) ).toThrow(); }); @@ -141,7 +141,7 @@ describe('Cases webhook service', () => { }, logger, configurationUtilities, - connectorMetricsService + connectorMetricsCollector ) ).toThrow(); }); @@ -156,7 +156,7 @@ describe('Cases webhook service', () => { }, logger, configurationUtilities, - connectorMetricsService + connectorMetricsCollector ) ).not.toThrow(); }); @@ -170,7 +170,7 @@ describe('Cases webhook service', () => { }, logger, configurationUtilities, - connectorMetricsService + connectorMetricsCollector ); expect(axios.create).toHaveBeenCalledWith({ @@ -191,7 +191,7 @@ describe('Cases webhook service', () => { }, logger, configurationUtilities, - connectorMetricsService + connectorMetricsCollector ); expect(axios.create).toHaveBeenCalledWith({ @@ -234,7 +234,7 @@ describe('Cases webhook service', () => { logger, configurationUtilities, sslOverrides: defaultSSLOverrides, - connectorMetricsService: expect.any(ConnectorMetricsService), + connectorMetricsCollector: expect.any(ConnectorMetricsCollector), }); }); @@ -248,7 +248,7 @@ describe('Cases webhook service', () => { expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "axios": [Function], - "connectorMetricsService": ConnectorMetricsService { + "connectorMetricsCollector": ConnectorMetricsCollector { "metrics": Object { "requestBodyBytes": 0, }, @@ -496,7 +496,7 @@ describe('Cases webhook service', () => { configurationUtilities, sslOverrides: defaultSSLOverrides, data: `{"fields":{"title":"title","description":"desc","tags":["hello","world"],"project":{"key":"ROC"},"issuetype":{"id":"10024"}}}`, - connectorMetricsService: expect.any(ConnectorMetricsService), + connectorMetricsCollector: expect.any(ConnectorMetricsCollector), }); }); @@ -526,7 +526,7 @@ describe('Cases webhook service', () => { expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "axios": [Function], - "connectorMetricsService": ConnectorMetricsService { + "connectorMetricsCollector": ConnectorMetricsCollector { "metrics": Object { "requestBodyBytes": 0, }, @@ -777,7 +777,7 @@ describe('Cases webhook service', () => { issuetype: { id: '10024' }, }, }), - connectorMetricsService: expect.any(ConnectorMetricsService), + connectorMetricsCollector: expect.any(ConnectorMetricsCollector), }); }); @@ -798,7 +798,7 @@ describe('Cases webhook service', () => { expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "axios": [Function], - "connectorMetricsService": ConnectorMetricsService { + "connectorMetricsCollector": ConnectorMetricsCollector { "metrics": Object { "requestBodyBytes": 0, }, @@ -1011,7 +1011,7 @@ describe('Cases webhook service', () => { sslOverrides: defaultSSLOverrides, url: 'https://coolsite.net/issue/1/comment', data: `{"body":"comment"}`, - connectorMetricsService: expect.any(ConnectorMetricsService), + connectorMetricsCollector: expect.any(ConnectorMetricsCollector), }); }); @@ -1032,7 +1032,7 @@ describe('Cases webhook service', () => { expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "axios": [Function], - "connectorMetricsService": ConnectorMetricsService { + "connectorMetricsCollector": ConnectorMetricsCollector { "metrics": Object { "requestBodyBytes": 0, }, @@ -1210,7 +1210,7 @@ describe('Cases webhook service', () => { }, logger, configurationUtilities, - connectorMetricsService + connectorMetricsCollector ); const res = await service.createComment(commentReq); expect(requestMock).not.toHaveBeenCalled(); @@ -1226,7 +1226,7 @@ describe('Cases webhook service', () => { }, logger, configurationUtilities, - connectorMetricsService + connectorMetricsCollector ); const res = await service.createComment(commentReq); expect(requestMock).not.toHaveBeenCalled(); @@ -1253,7 +1253,7 @@ describe('Cases webhook service', () => { }, logger, configurationUtilities, - connectorMetricsService + connectorMetricsCollector ); await service.createComment(commentReq); expect(requestMock).toHaveBeenCalledWith({ @@ -1264,7 +1264,7 @@ describe('Cases webhook service', () => { url: 'https://coolsite.net/issue/1/comment', data: `{"body":"comment","id":"1"}`, sslOverrides: defaultSSLOverrides, - connectorMetricsService: expect.any(ConnectorMetricsService), + connectorMetricsCollector: expect.any(ConnectorMetricsCollector), }); }); @@ -1295,7 +1295,7 @@ describe('Cases webhook service', () => { }, logger, configurationUtilities, - connectorMetricsService + connectorMetricsCollector ); await service.createComment(commentReq2); expect(requestMock).toHaveBeenCalledWith({ @@ -1306,7 +1306,7 @@ describe('Cases webhook service', () => { url: 'https://coolsite.net/issue/1/comment', data: `{"body":"comment","id":1}`, sslOverrides: defaultSSLOverrides, - connectorMetricsService: expect.any(ConnectorMetricsService), + connectorMetricsCollector: expect.any(ConnectorMetricsCollector), }); }); }); @@ -1326,7 +1326,7 @@ describe('Cases webhook service', () => { throw new Error('Uri not allowed'); }), }, - connectorMetricsService + connectorMetricsCollector ); }); @@ -1401,7 +1401,7 @@ describe('Cases webhook service', () => { }, logger, configurationUtilities, - connectorMetricsService + connectorMetricsCollector ); }); @@ -1472,7 +1472,7 @@ describe('Cases webhook service', () => { { ...configurationUtilities, }, - connectorMetricsService + connectorMetricsCollector ); requestMock.mockImplementation(() => createAxiosResponse({ diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.ts b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.ts index ac5b132c100cb..c5fdb53e5e7e0 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.ts @@ -13,7 +13,7 @@ import { request } from '@kbn/actions-plugin/server/lib/axios_utils'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; import { combineHeadersWithBasicAuthHeader, - ConnectorMetricsService, + ConnectorMetricsCollector, } from '@kbn/actions-plugin/server/lib'; import { buildConnectorAuth, validateConnectorAuthConfiguration } from '../../../common/auth/utils'; import { validateAndNormalizeUrl, validateJson } from './validators'; @@ -42,7 +42,7 @@ export const createExternalService = ( { config, secrets }: ExternalServiceCredentials, logger: Logger, configurationUtilities: ActionsConfigurationUtilities, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): ExternalService => { const { createCommentJson, @@ -121,7 +121,7 @@ export const createExternalService = ( logger, configurationUtilities, sslOverrides, - connectorMetricsService, + connectorMetricsCollector, }); throwDescriptiveErrorIfResponseIsNotValid({ @@ -167,7 +167,7 @@ export const createExternalService = ( data: json, configurationUtilities, sslOverrides, - connectorMetricsService, + connectorMetricsCollector, }); const { status, statusText, data } = res; @@ -252,7 +252,7 @@ export const createExternalService = ( data: json, configurationUtilities, sslOverrides, - connectorMetricsService, + connectorMetricsCollector, }); throwDescriptiveErrorIfResponseIsNotValid({ @@ -326,7 +326,7 @@ export const createExternalService = ( data: json, configurationUtilities, sslOverrides, - connectorMetricsService, + connectorMetricsCollector, }); throwDescriptiveErrorIfResponseIsNotValid({ diff --git a/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.test.ts index 64a98b43bc5e8..1eb1d89d09c6a 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.test.ts @@ -10,7 +10,7 @@ import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.moc import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; import { actionsMock } from '@kbn/actions-plugin/server/mocks'; import { CROWDSTRIKE_CONNECTOR_ID } from '../../../public/common'; -import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; +import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; const tokenPath = 'https://api.crowdstrike.com/oauth2/token'; const hostPath = 'https://api.crowdstrike.com/devices/entities/devices/v2'; @@ -26,14 +26,14 @@ describe('CrowdstrikeConnector', () => { services: actionsMock.createServices(), }); let mockedRequest: jest.Mock; - let connectorMetricsService: ConnectorMetricsService; + let connectorMetricsCollector: ConnectorMetricsCollector; beforeEach(() => { // @ts-expect-error private static - but I still want to reset it CrowdstrikeConnector.token = null; // @ts-expect-error mockedRequest = connector.request = jest.fn() as jest.Mock; - connectorMetricsService = new ConnectorMetricsService(); + connectorMetricsCollector = new ConnectorMetricsCollector(); }); afterEach(() => { jest.clearAllMocks(); @@ -51,7 +51,7 @@ describe('CrowdstrikeConnector', () => { command: 'contain', ids: ['id1', 'id2'], }, - connectorMetricsService + connectorMetricsCollector ); expect(mockedRequest).toHaveBeenNthCalledWith( 1, @@ -65,7 +65,7 @@ describe('CrowdstrikeConnector', () => { responseSchema: expect.any(Object), url: tokenPath, }), - connectorMetricsService + connectorMetricsCollector ); expect(mockedRequest).toHaveBeenNthCalledWith( 2, @@ -77,7 +77,7 @@ describe('CrowdstrikeConnector', () => { paramsSerializer: expect.any(Function), responseSchema: expect.any(Object), }), - connectorMetricsService + connectorMetricsCollector ); expect(result).toEqual({ id: 'testid', path: 'testpath' }); }); @@ -92,7 +92,7 @@ describe('CrowdstrikeConnector', () => { const result = await connector.getAgentDetails( { ids: ['id1', 'id2'] }, - connectorMetricsService + connectorMetricsCollector ); expect(mockedRequest).toHaveBeenNthCalledWith( @@ -107,7 +107,7 @@ describe('CrowdstrikeConnector', () => { responseSchema: expect.any(Object), url: tokenPath, }), - connectorMetricsService + connectorMetricsCollector ); expect(mockedRequest).toHaveBeenNthCalledWith( 2, @@ -121,7 +121,7 @@ describe('CrowdstrikeConnector', () => { responseSchema: expect.any(Object), url: hostPath, }), - connectorMetricsService + connectorMetricsCollector ); expect(result).toEqual({ resources: [{}] }); }); @@ -136,7 +136,7 @@ describe('CrowdstrikeConnector', () => { const result = await connector.getAgentOnlineStatus( { ids: ['id1', 'id2'] }, - connectorMetricsService + connectorMetricsCollector ); expect(mockedRequest).toHaveBeenNthCalledWith( @@ -151,7 +151,7 @@ describe('CrowdstrikeConnector', () => { responseSchema: expect.any(Object), url: tokenPath, }), - connectorMetricsService + connectorMetricsCollector ); expect(mockedRequest).toHaveBeenNthCalledWith( 2, @@ -165,7 +165,7 @@ describe('CrowdstrikeConnector', () => { responseSchema: expect.any(Object), url: onlineStatusPath, }), - connectorMetricsService + connectorMetricsCollector ); expect(result).toEqual({ resources: [{}] }); }); @@ -244,7 +244,7 @@ describe('CrowdstrikeConnector', () => { mockedRequest.mockResolvedValueOnce(mockResponse); // @ts-expect-error private method - but I still want to - const result = await connector.getTokenRequest(connectorMetricsService); + const result = await connector.getTokenRequest(connectorMetricsCollector); expect(mockedRequest).toHaveBeenCalledWith( expect.objectContaining({ @@ -256,7 +256,7 @@ describe('CrowdstrikeConnector', () => { authorization: expect.stringContaining('Basic'), }, }), - connectorMetricsService + connectorMetricsCollector ); expect(result).toEqual('testToken'); }); @@ -266,7 +266,7 @@ describe('CrowdstrikeConnector', () => { mockedRequest.mockResolvedValueOnce({ data: { access_token: 'testToken' } }); mockedRequest.mockResolvedValue(mockResponse); - await connector.getAgentDetails({ ids: ['id1', 'id2'] }, connectorMetricsService); + await connector.getAgentDetails({ ids: ['id1', 'id2'] }, connectorMetricsCollector); expect(mockedRequest).toHaveBeenNthCalledWith( 1, @@ -280,7 +280,7 @@ describe('CrowdstrikeConnector', () => { responseSchema: expect.any(Object), url: tokenPath, }), - connectorMetricsService + connectorMetricsCollector ); expect(mockedRequest).toHaveBeenNthCalledWith( 2, @@ -294,10 +294,10 @@ describe('CrowdstrikeConnector', () => { responseSchema: expect.any(Object), url: hostPath, }), - connectorMetricsService + connectorMetricsCollector ); expect(mockedRequest).toHaveBeenCalledTimes(2); - await connector.getAgentDetails({ ids: ['id1', 'id2'] }, connectorMetricsService); + await connector.getAgentDetails({ ids: ['id1', 'id2'] }, connectorMetricsCollector); expect(mockedRequest).toHaveBeenNthCalledWith( 3, expect.objectContaining({ @@ -310,7 +310,7 @@ describe('CrowdstrikeConnector', () => { responseSchema: expect.any(Object), url: hostPath, }), - connectorMetricsService + connectorMetricsCollector ); expect(mockedRequest).toHaveBeenCalledTimes(3); }); @@ -321,7 +321,7 @@ describe('CrowdstrikeConnector', () => { mockedRequest.mockRejectedValueOnce(mockResponse); await expect(() => - connector.getAgentDetails({ ids: ['id1', 'id2'] }, connectorMetricsService) + connector.getAgentDetails({ ids: ['id1', 'id2'] }, connectorMetricsCollector) ).rejects.toThrowError('something goes wrong'); expect(mockedRequest).toHaveBeenCalledTimes(2); }); @@ -332,7 +332,7 @@ describe('CrowdstrikeConnector', () => { mockedRequest.mockRejectedValueOnce(mockResponse); await expect(() => - connector.getAgentDetails({ ids: ['id1', 'id2'] }, connectorMetricsService) + connector.getAgentDetails({ ids: ['id1', 'id2'] }, connectorMetricsCollector) ).rejects.toThrowError(); expect(mockedRequest).toHaveBeenCalledTimes(3); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.ts b/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.ts index 0ffaf72d06db0..15299c2e159b9 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.ts @@ -9,7 +9,7 @@ import { ServiceParams, SubActionConnector } from '@kbn/actions-plugin/server'; import type { AxiosError } from 'axios'; import { SubActionRequestParams } from '@kbn/actions-plugin/server/sub_action_framework/types'; -import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; +import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; import { isAggregateError, NodeSystemError } from './types'; import type { CrowdstrikeConfig, @@ -99,7 +99,7 @@ export class CrowdstrikeConnector extends SubActionConnector< public async executeHostActions( { alertIds, ...payload }: CrowdstrikeHostActionsParams, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ) { return this.crowdstrikeApiRequest( { @@ -124,13 +124,13 @@ export class CrowdstrikeConnector extends SubActionConnector< paramsSerializer, responseSchema: CrowdstrikeHostActionsResponseSchema, }, - connectorMetricsService + connectorMetricsCollector ); } public async getAgentDetails( payload: CrowdstrikeGetAgentsParams, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): Promise { return this.crowdstrikeApiRequest( { @@ -142,13 +142,13 @@ export class CrowdstrikeConnector extends SubActionConnector< paramsSerializer, responseSchema: RelaxedCrowdstrikeBaseApiResponseSchema, }, - connectorMetricsService + connectorMetricsCollector ) as Promise; } public async getAgentOnlineStatus( payload: CrowdstrikeGetAgentsParams, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): Promise { return this.crowdstrikeApiRequest( { @@ -160,11 +160,11 @@ export class CrowdstrikeConnector extends SubActionConnector< paramsSerializer, responseSchema: RelaxedCrowdstrikeBaseApiResponseSchema, }, - connectorMetricsService + connectorMetricsCollector ) as Promise; } - private async getTokenRequest(connectorMetricsService: ConnectorMetricsService) { + private async getTokenRequest(connectorMetricsCollector: ConnectorMetricsCollector) { const response = await this.request( { url: this.urls.getToken, @@ -176,7 +176,7 @@ export class CrowdstrikeConnector extends SubActionConnector< }, responseSchema: CrowdstrikeGetTokenResponseSchema, }, - connectorMetricsService + connectorMetricsCollector ); const token = response.data?.access_token; if (token) { @@ -193,13 +193,13 @@ export class CrowdstrikeConnector extends SubActionConnector< private async crowdstrikeApiRequest( req: SubActionRequestParams, - connectorMetricsService: ConnectorMetricsService, + connectorMetricsCollector: ConnectorMetricsCollector, retried?: boolean ): Promise { try { if (!CrowdstrikeConnector.token) { CrowdstrikeConnector.token = (await this.getTokenRequest( - connectorMetricsService + connectorMetricsCollector )) as string; } @@ -211,14 +211,14 @@ export class CrowdstrikeConnector extends SubActionConnector< Authorization: `Bearer ${CrowdstrikeConnector.token}`, }, }, - connectorMetricsService + connectorMetricsCollector ); return response.data; } catch (error) { if (error.code === 401 && !retried) { CrowdstrikeConnector.token = null; - return this.crowdstrikeApiRequest(req, connectorMetricsService, true); + return this.crowdstrikeApiRequest(req, connectorMetricsCollector, true); } throw new CrowdstrikeError(error.message); } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.test.ts index 1999efb922d26..4dd4fdcf7abcf 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.test.ts @@ -11,7 +11,7 @@ import { D3_SECURITY_CONNECTOR_ID } from '../../../common/d3security/constants'; import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; import { actionsMock } from '@kbn/actions-plugin/server/mocks'; import { D3SecurityRunActionResponseSchema } from '../../../common/d3security/schema'; -import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; +import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; describe('D3SecurityConnector', () => { const sampleBody = JSON.stringify({ @@ -39,16 +39,16 @@ describe('D3SecurityConnector', () => { logger: loggingSystemMock.createLogger(), services: actionsMock.createServices(), }); - let connectorMetricsService: ConnectorMetricsService; + let connectorMetricsCollector: ConnectorMetricsCollector; beforeEach(() => { // @ts-ignore connector.request = mockRequest; jest.clearAllMocks(); - connectorMetricsService = new ConnectorMetricsService(); + connectorMetricsCollector = new ConnectorMetricsCollector(); }); it('the D3 Security API call is successful with correct parameters', async () => { - const response = await connector.runApi({ body: sampleBody }, connectorMetricsService); + const response = await connector.runApi({ body: sampleBody }, connectorMetricsCollector); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( { @@ -60,7 +60,7 @@ describe('D3SecurityConnector', () => { d3key: '123', }, }, - connectorMetricsService + connectorMetricsCollector ); expect(response).toEqual({ result: 'success' }); }); @@ -69,9 +69,9 @@ describe('D3SecurityConnector', () => { // @ts-ignore connector.request = mockError; - await expect(connector.runApi({ body: sampleBody }, connectorMetricsService)).rejects.toThrow( - 'API Error' - ); + await expect( + connector.runApi({ body: sampleBody }, connectorMetricsCollector) + ).rejects.toThrow('API Error'); }); }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.ts b/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.ts index c2c08ccbe6830..d92ed428440d9 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.ts @@ -7,7 +7,7 @@ import { ServiceParams, SubActionConnector } from '@kbn/actions-plugin/server'; import type { AxiosError } from 'axios'; -import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; +import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; import { addSeverityAndEventTypeInBody } from './helpers'; import { D3SecurityRunActionParamsSchema, @@ -60,7 +60,7 @@ export class D3SecurityConnector extends SubActionConnector { const response = await this.request( { @@ -74,7 +74,7 @@ export class D3SecurityConnector extends SubActionConnector { text: 'Go to Elastic', }, }; - const connectorMetricsService = new ConnectorMetricsService(); + const connectorMetricsCollector = new ConnectorMetricsCollector(); const actionId = 'some-id'; const executorOptions: EmailConnectorTypeExecutorOptions = { @@ -526,7 +526,7 @@ describe('execute()', () => { services, configurationUtilities: actionsConfigMock.create(), logger: mockedLogger, - connectorMetricsService, + connectorMetricsCollector, }; beforeEach(() => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/email/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/email/index.ts index c173da89eb9c4..da22352b7af36 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/email/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/email/index.ts @@ -282,7 +282,7 @@ async function executor( configurationUtilities, services, logger, - connectorMetricsService, + connectorMetricsCollector, } = execOptions; const connectorTokenClient = services.connectorTokenClient; @@ -378,7 +378,7 @@ async function executor( logger, sendEmailOptions, connectorTokenClient, - connectorMetricsService + connectorMetricsCollector ); } catch (err) { const message = i18n.translate('xpack.stackConnectors.email.errorSendingErrorMessage', { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.test.ts index e44bb0189b48d..573cd732bd01d 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.test.ts @@ -10,7 +10,7 @@ import { Logger } from '@kbn/core/server'; import { sendEmail } from './send_email'; import { loggingSystemMock } from '@kbn/core/server/mocks'; import nodemailer from 'nodemailer'; -import { ConnectorMetricsService, ProxySettings } from '@kbn/actions-plugin/server/types'; +import { ConnectorMetricsCollector, ProxySettings } from '@kbn/actions-plugin/server/types'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { CustomHostSettings } from '@kbn/actions-plugin/server/config'; import { sendEmailGraphApi } from './send_email_graph_api'; @@ -39,7 +39,7 @@ const sendMailMock = jest.fn(); const mockLogger = loggingSystemMock.create().get() as jest.Mocked; const connectorTokenClient = connectorTokenClientMock.create(); -const getConnectorMetricsService = () => new ConnectorMetricsService(); +let connectorMetricsCollector: ConnectorMetricsCollector; describe('send_email module', () => { beforeEach(() => { @@ -54,6 +54,8 @@ describe('send_email module', () => { interceptors: mockAxiosInstanceInterceptor, }; }); + + connectorMetricsCollector = new ConnectorMetricsCollector(); }); test('handles authenticated email using service', async () => { @@ -62,7 +64,7 @@ describe('send_email module', () => { mockLogger, sendEmailOptions, connectorTokenClient, - getConnectorMetricsService() + connectorMetricsCollector ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` @@ -111,7 +113,7 @@ describe('send_email module', () => { mockLogger, sendEmailOptions, connectorTokenClient, - getConnectorMetricsService() + connectorMetricsCollector ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` @@ -170,12 +172,7 @@ describe('send_email module', () => { status: 202, }); - await sendEmail( - mockLogger, - sendEmailOptions, - connectorTokenClient, - getConnectorMetricsService() - ); + await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient, connectorMetricsCollector); expect(getOAuthClientCredentialsAccessTokenMock).toHaveBeenCalledWith({ configurationUtilities: sendEmailOptions.configurationUtilities, connectorId: '1', @@ -271,12 +268,7 @@ describe('send_email module', () => { status: 202, }); - await sendEmail( - mockLogger, - sendEmailOptions, - connectorTokenClient, - getConnectorMetricsService() - ); + await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient, connectorMetricsCollector); expect(getOAuthClientCredentialsAccessTokenMock).toHaveBeenCalledWith({ configurationUtilities: sendEmailOptions.configurationUtilities, connectorId: '1', @@ -314,12 +306,7 @@ describe('send_email module', () => { status: 202, }); - await sendEmail( - mockLogger, - sendEmailOptions, - connectorTokenClient, - getConnectorMetricsService() - ); + await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient, connectorMetricsCollector); expect(getOAuthClientCredentialsAccessTokenMock).toHaveBeenCalledWith({ configurationUtilities: sendEmailOptions.configurationUtilities, connectorId: '1', @@ -349,7 +336,7 @@ describe('send_email module', () => { getOAuthClientCredentialsAccessTokenMock.mockReturnValueOnce(null); await expect(() => - sendEmail(mockLogger, sendEmailOptions, connectorTokenClient, getConnectorMetricsService()) + sendEmail(mockLogger, sendEmailOptions, connectorTokenClient, connectorMetricsCollector) ).rejects.toThrowErrorMatchingInlineSnapshot( `"Unable to retrieve access token for connectorId: 1"` ); @@ -393,7 +380,7 @@ describe('send_email module', () => { mockLogger, sendEmailOptions, connectorTokenClient, - getConnectorMetricsService() + connectorMetricsCollector ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` @@ -448,7 +435,7 @@ describe('send_email module', () => { mockLogger, sendEmailOptions, connectorTokenClient, - getConnectorMetricsService() + connectorMetricsCollector ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` @@ -503,7 +490,7 @@ describe('send_email module', () => { mockLogger, sendEmailOptions, connectorTokenClient, - getConnectorMetricsService() + connectorMetricsCollector ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` @@ -546,7 +533,7 @@ describe('send_email module', () => { sendMailMock.mockRejectedValue(new Error('wops')); await expect( - sendEmail(mockLogger, sendEmailOptions, connectorTokenClient, getConnectorMetricsService()) + sendEmail(mockLogger, sendEmailOptions, connectorTokenClient, connectorMetricsCollector) ).rejects.toThrow('wops'); }); @@ -572,7 +559,7 @@ describe('send_email module', () => { mockLogger, sendEmailOptions, connectorTokenClient, - getConnectorMetricsService() + connectorMetricsCollector ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` @@ -611,7 +598,7 @@ describe('send_email module', () => { mockLogger, sendEmailOptions, connectorTokenClient, - getConnectorMetricsService() + connectorMetricsCollector ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` @@ -652,7 +639,7 @@ describe('send_email module', () => { mockLogger, sendEmailOptions, connectorTokenClient, - getConnectorMetricsService() + connectorMetricsCollector ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` @@ -691,7 +678,7 @@ describe('send_email module', () => { mockLogger, sendEmailOptions, connectorTokenClient, - getConnectorMetricsService() + connectorMetricsCollector ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` @@ -733,7 +720,7 @@ describe('send_email module', () => { mockLogger, sendEmailOptions, connectorTokenClient, - getConnectorMetricsService() + connectorMetricsCollector ); expect(result).toBe(sendMailMockResult); @@ -781,7 +768,7 @@ describe('send_email module', () => { mockLogger, sendEmailOptions, connectorTokenClient, - getConnectorMetricsService() + connectorMetricsCollector ); expect(result).toBe(sendMailMockResult); @@ -833,7 +820,7 @@ describe('send_email module', () => { mockLogger, sendEmailOptions, connectorTokenClient, - getConnectorMetricsService() + connectorMetricsCollector ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` @@ -868,12 +855,7 @@ describe('send_email module', () => { 'Bearer clienttokentokentoken' ); - await sendEmail( - mockLogger, - sendEmailOptions, - connectorTokenClient, - getConnectorMetricsService() - ); + await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient, connectorMetricsCollector); expect(createAxiosInstanceMock).toHaveBeenCalledTimes(1); expect(createAxiosInstanceMock).toHaveBeenCalledWith(); expect(mockAxiosInstanceInterceptor.response.use).toHaveBeenCalledTimes(1); @@ -916,12 +898,7 @@ describe('send_email module', () => { 'Bearer clienttokentokentoken' ); - await sendEmail( - mockLogger, - sendEmailOptions, - connectorTokenClient, - getConnectorMetricsService() - ); + await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient, connectorMetricsCollector); expect(createAxiosInstanceMock).toHaveBeenCalledTimes(1); expect(createAxiosInstanceMock).toHaveBeenCalledWith(); expect(mockAxiosInstanceInterceptor.response.use).toHaveBeenCalledTimes(1); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.ts b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.ts index 5058d8ade2003..377a0bfe50a02 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.ts @@ -18,7 +18,7 @@ import { getSSLSettingsFromConfig, } from '@kbn/actions-plugin/server/lib/get_node_ssl_options'; import { - ConnectorMetricsService, + ConnectorMetricsCollector, ConnectorTokenClientContract, ProxySettings, } from '@kbn/actions-plugin/server/types'; @@ -71,7 +71,7 @@ export async function sendEmail( logger: Logger, options: SendEmailOptions, connectorTokenClient: ConnectorTokenClientContract, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): Promise { const { transport, content } = options; const { message, messageHTML } = content; @@ -84,10 +84,15 @@ export async function sendEmail( options, renderedMessage, connectorTokenClient, - connectorMetricsService + connectorMetricsCollector ); } else { - return await sendEmailWithNodemailer(logger, options, renderedMessage, connectorMetricsService); + return await sendEmailWithNodemailer( + logger, + options, + renderedMessage, + connectorMetricsCollector + ); } } @@ -97,7 +102,7 @@ export async function sendEmailWithExchange( options: SendEmailOptions, messageHTML: string, connectorTokenClient: ConnectorTokenClientContract, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): Promise { const { transport, configurationUtilities, connectorId } = options; const { clientId, clientSecret, tenantId, oauthTokenUrl } = transport; @@ -167,7 +172,7 @@ export async function sendEmailWithExchange( }, logger, configurationUtilities, - connectorMetricsService, + connectorMetricsCollector, axiosInstance ); } @@ -177,7 +182,7 @@ async function sendEmailWithNodemailer( logger: Logger, options: SendEmailOptions, messageHTML: string, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): Promise { const { transport, routing, content, configurationUtilities, hasAuth } = options; const { service } = transport; @@ -200,7 +205,7 @@ async function sendEmailWithNodemailer( // some deep properties, so need to use any here. const transportConfig = getTransportConfig(configurationUtilities, logger, transport, hasAuth); const nodemailerTransport = nodemailer.createTransport(transportConfig); - connectorMetricsService.addRequestBodyBytes(undefined, email); + connectorMetricsCollector.addRequestBodyBytes(undefined, email); const result = await nodemailerTransport.sendMail(email); if (service === JSON_TRANSPORT_SERVICE) { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.test.ts index 85303119b75f3..ef4e088dd2dab 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.test.ts @@ -14,7 +14,7 @@ import { Logger } from '@kbn/core/server'; import { loggingSystemMock } from '@kbn/core/server/mocks'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { CustomHostSettings } from '@kbn/actions-plugin/server/config'; -import { ConnectorMetricsService, ProxySettings } from '@kbn/actions-plugin/server/types'; +import { ConnectorMetricsCollector, ProxySettings } from '@kbn/actions-plugin/server/types'; import { sendEmailGraphApi } from './send_email_graph_api'; const createAxiosInstanceMock = axios.create as jest.Mock; @@ -28,7 +28,7 @@ describe('sendEmailGraphApi', () => { const configurationUtilities = actionsConfigMock.create(); test('email contains the proper message', async () => { - const connectorMetricsService = new ConnectorMetricsService(); + const connectorMetricsCollector = new ConnectorMetricsCollector(); axiosInstanceMock.mockReturnValueOnce({ status: 202, @@ -41,7 +41,7 @@ describe('sendEmailGraphApi', () => { }, logger, configurationUtilities, - connectorMetricsService + connectorMetricsCollector ); expect(axiosInstanceMock.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -121,7 +121,7 @@ describe('sendEmailGraphApi', () => { }); test('email was sent on behalf of the user "from" mailbox', async () => { - const connectorMetricsService = new ConnectorMetricsService(); + const connectorMetricsCollector = new ConnectorMetricsCollector(); axiosInstanceMock.mockReturnValueOnce({ status: 202, }); @@ -133,7 +133,7 @@ describe('sendEmailGraphApi', () => { }, logger, configurationUtilities, - connectorMetricsService + connectorMetricsCollector ); expect(axiosInstanceMock.mock.calls[1]).toMatchInlineSnapshot(` Array [ @@ -215,7 +215,7 @@ describe('sendEmailGraphApi', () => { }); test('sendMail request was sent to the custom configured Graph API URL', async () => { - const connectorMetricsService = new ConnectorMetricsService(); + const connectorMetricsCollector = new ConnectorMetricsCollector(); axiosInstanceMock.mockReturnValueOnce({ status: 202, }); @@ -228,7 +228,7 @@ describe('sendEmailGraphApi', () => { }, logger, configurationUtilities, - connectorMetricsService + connectorMetricsCollector ); expect(axiosInstanceMock.mock.calls[2]).toMatchInlineSnapshot(` Array [ @@ -308,7 +308,7 @@ describe('sendEmailGraphApi', () => { }); test('throw the exception and log the proper error if message was not sent successfuly', async () => { - const connectorMetricsService = new ConnectorMetricsService(); + const connectorMetricsCollector = new ConnectorMetricsCollector(); axiosInstanceMock.mockReturnValueOnce({ status: 400, data: { @@ -324,7 +324,7 @@ describe('sendEmailGraphApi', () => { { options: getSendEmailOptions(), messageHTML: 'test1', headers: {} }, logger, configurationUtilities, - connectorMetricsService + connectorMetricsCollector ) ).rejects.toThrowErrorMatchingInlineSnapshot( '"{\\"error\\":{\\"code\\":\\"ErrorMimeContentInvalidBase64String\\",\\"message\\":\\"Invalid base64 string for MIME content.\\"}}"' diff --git a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.ts b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.ts index 104fe34bfea57..f0b7f3cdddb3c 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.ts @@ -11,14 +11,14 @@ import axios, { AxiosInstance, AxiosResponse } from 'axios'; import { Logger } from '@kbn/core/server'; import { request } from '@kbn/actions-plugin/server/lib/axios_utils'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; -import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; +import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; import { SendEmailOptions } from './send_email'; export async function sendEmailGraphApi( sendEmailOptions: SendEmailGraphApiOptions, logger: Logger, configurationUtilities: ActionsConfigurationUtilities, - connectorMetricsService: ConnectorMetricsService, + connectorMetricsCollector: ConnectorMetricsCollector, axiosInstance?: AxiosInstance ): Promise { const { options, headers, messageHTML } = sendEmailOptions; @@ -38,7 +38,7 @@ export async function sendEmailGraphApi( headers, configurationUtilities, validateStatus: () => true, - connectorMetricsService, + connectorMetricsCollector, }); if (res.status === 202) { return res.data; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/es_index/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/es_index/index.test.ts index 2b3fab30432fa..636cbd8596027 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/es_index/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/es_index/index.test.ts @@ -6,7 +6,11 @@ */ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { validateConfig, validateParams } from '@kbn/actions-plugin/server/lib'; +import { + ConnectorMetricsCollector, + validateConfig, + validateParams, +} from '@kbn/actions-plugin/server/lib'; import { actionsMock } from '@kbn/actions-plugin/server/mocks'; import { ActionParamsType, @@ -27,11 +31,13 @@ const mockedLogger: jest.Mocked = loggerMock.create(); let connectorType: ESIndexConnectorType; let configurationUtilities: ActionsConfigurationUtilities; +let connectorMetricsCollector: ConnectorMetricsCollector; beforeEach(() => { jest.resetAllMocks(); configurationUtilities = actionsConfigMock.create(); connectorType = getConnectorType(); + connectorMetricsCollector = new ConnectorMetricsCollector(); }); describe('connector registration', () => { @@ -185,6 +191,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, + connectorMetricsCollector, }; const scopedClusterClient = elasticsearchClientMock .createClusterClient() @@ -230,6 +237,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, + connectorMetricsCollector, }; scopedClusterClient.bulk.mockClear(); await connectorType.executor({ @@ -280,6 +288,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, + connectorMetricsCollector, }; scopedClusterClient.bulk.mockClear(); @@ -324,6 +333,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, + connectorMetricsCollector, }; scopedClusterClient.bulk.mockClear(); await connectorType.executor({ @@ -656,6 +666,7 @@ describe('execute()', () => { services: { ...services, scopedClusterClient }, configurationUtilities, logger: mockedLogger, + connectorMetricsCollector, }) ).toMatchInlineSnapshot(` Object { @@ -695,6 +706,7 @@ describe('execute()', () => { services: { ...services, scopedClusterClient }, configurationUtilities, logger: mockedLogger, + connectorMetricsCollector, }) ).toMatchInlineSnapshot(` Object { @@ -757,6 +769,7 @@ describe('execute()', () => { services: { ...services, scopedClusterClient }, configurationUtilities, logger: mockedLogger, + connectorMetricsCollector, }) ).toMatchInlineSnapshot(` Object { @@ -824,6 +837,7 @@ describe('execute()', () => { services: { ...services, scopedClusterClient }, configurationUtilities, logger: mockedLogger, + connectorMetricsCollector, }) ).toMatchInlineSnapshot(` Object { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.test.ts index d88f8f13d9970..85fa03faf345b 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.test.ts @@ -15,7 +15,7 @@ import { RunApiResponseSchema, StreamingResponseSchema } from '../../../common/g import { DEFAULT_GEMINI_MODEL } from '../../../common/gemini/constants'; import { AxiosError } from 'axios'; import { Transform } from 'stream'; -import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; +import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; jest.mock('../lib/gen_ai/create_gen_ai_dashboard'); jest.mock('@kbn/actions-plugin/server/sub_action_framework/helpers/validators', () => ({ @@ -88,13 +88,13 @@ describe('GeminiConnector', () => { logger: loggingSystemMock.createLogger(), services: actionsMock.createServices(), }); - let connectorMetricsService: ConnectorMetricsService; + let connectorMetricsCollector: ConnectorMetricsCollector; describe('Gemini', () => { beforeEach(() => { // @ts-ignore connector.request = mockRequest; - connectorMetricsService = new ConnectorMetricsService(); + connectorMetricsCollector = new ConnectorMetricsCollector(); }); describe('runApi', () => { @@ -104,7 +104,7 @@ describe('GeminiConnector', () => { model: DEFAULT_GEMINI_MODEL, }; - const response = await connector.runApi(runActionParams, connectorMetricsService); + const response = await connector.runApi(runActionParams, connectorMetricsCollector); // Assertions expect(mockRequest).toBeCalledTimes(1); @@ -132,7 +132,7 @@ describe('GeminiConnector', () => { responseSchema: RunApiResponseSchema, signal: undefined, }, - connectorMetricsService + connectorMetricsCollector ); expect(response).toEqual(connectorResponse); @@ -150,7 +150,7 @@ describe('GeminiConnector', () => { }; it('the API call is successful with correct parameters', async () => { - await connector.invokeAI(aiAssistantBody, connectorMetricsService); + await connector.invokeAI(aiAssistantBody, connectorMetricsCollector); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( { @@ -176,14 +176,17 @@ describe('GeminiConnector', () => { signal: undefined, timeout: 60000, }, - connectorMetricsService + connectorMetricsCollector ); }); it('signal and timeout is properly passed to runApi', async () => { const signal = jest.fn(); const timeout = 60000; - await connector.invokeAI({ ...aiAssistantBody, timeout, signal }, connectorMetricsService); + await connector.invokeAI( + { ...aiAssistantBody, timeout, signal }, + connectorMetricsCollector + ); expect(mockRequest).toHaveBeenCalledWith( { url: `https://api.gemini.com/v1/projects/my-project-12345/locations/us-central1/publishers/google/models/${DEFAULT_GEMINI_MODEL}:generateContent`, @@ -208,7 +211,7 @@ describe('GeminiConnector', () => { signal, timeout: 60000, }, - connectorMetricsService + connectorMetricsCollector ); }); }); @@ -232,7 +235,7 @@ describe('GeminiConnector', () => { }; it('the API call is successful with correct request parameters', async () => { - await connector.invokeStream(aiAssistantBody, connectorMetricsService); + await connector.invokeStream(aiAssistantBody, connectorMetricsCollector); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( { @@ -259,7 +262,7 @@ describe('GeminiConnector', () => { signal: undefined, timeout: 60000, }, - connectorMetricsService + connectorMetricsCollector ); }); @@ -268,7 +271,7 @@ describe('GeminiConnector', () => { const timeout = 60000; await connector.invokeStream( { ...aiAssistantBody, timeout, signal }, - connectorMetricsService + connectorMetricsCollector ); expect(mockRequest).toHaveBeenCalledWith( { @@ -295,7 +298,7 @@ describe('GeminiConnector', () => { signal, timeout: 60000, }, - connectorMetricsService + connectorMetricsCollector ); }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.ts b/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.ts index 335559a1b0ef7..523ecef34cba0 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.ts @@ -13,7 +13,7 @@ import { SubActionRequestParams } from '@kbn/actions-plugin/server/sub_action_fr import { getGoogleOAuthJwtAccessToken } from '@kbn/actions-plugin/server/lib/get_gcp_oauth_access_token'; import { Logger } from '@kbn/core/server'; import { - ConnectorMetricsService, + ConnectorMetricsCollector, ConnectorTokenClientContract, } from '@kbn/actions-plugin/server/types'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; @@ -204,7 +204,7 @@ export class GeminiConnector extends SubActionConnector { */ public async runApi( { body, model: reqModel, signal, timeout }: RunActionParams, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): Promise { // set model on per request basis const currentModel = reqModel ?? this.model; @@ -224,7 +224,7 @@ export class GeminiConnector extends SubActionConnector { responseSchema: RunApiResponseSchema, } as SubActionRequestParams; - const response = await this.request(requestArgs, connectorMetricsService); + const response = await this.request(requestArgs, connectorMetricsCollector); const candidate = response.data.candidates[0]; const usageMetadata = response.data.usageMetadata; const completionText = candidate.content.parts[0].text; @@ -234,7 +234,7 @@ export class GeminiConnector extends SubActionConnector { private async streamAPI( { body, model: reqModel, signal, timeout }: RunActionParams, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): Promise { const currentModel = reqModel ?? this.model; const path = `/v1/projects/${this.gcpProjectID}/locations/${this.gcpRegion}/publishers/google/models/${currentModel}:streamGenerateContent?alt=sse`; @@ -254,7 +254,7 @@ export class GeminiConnector extends SubActionConnector { signal, timeout: timeout ?? DEFAULT_TIMEOUT_MS, }, - connectorMetricsService + connectorMetricsCollector ); return response.data.pipe(new PassThrough()); @@ -262,7 +262,7 @@ export class GeminiConnector extends SubActionConnector { public async invokeAI( { messages, model, temperature = 0, signal, timeout }: InvokeAIActionParams, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): Promise { const res = await this.runApi( { @@ -271,7 +271,7 @@ export class GeminiConnector extends SubActionConnector { signal, timeout, }, - connectorMetricsService + connectorMetricsCollector ); return { message: res.completion, usageMetadata: res.usageMetadata }; @@ -287,7 +287,7 @@ export class GeminiConnector extends SubActionConnector { */ public async invokeStream( { messages, model, stopSequences, temperature = 0, signal, timeout }: InvokeAIActionParams, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): Promise { const res = (await this.streamAPI( { @@ -297,7 +297,7 @@ export class GeminiConnector extends SubActionConnector { signal, timeout, }, - connectorMetricsService + connectorMetricsCollector )) as unknown as IncomingMessage; return res; } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/jira/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/jira/index.ts index 16e79ecedd74c..bcb9b79660741 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/jira/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/jira/index.ts @@ -102,7 +102,7 @@ async function executor( secrets, configurationUtilities, logger, - connectorMetricsService, + connectorMetricsCollector, } = execOptions; const { subAction, subActionParams } = params as ExecutorParams; let data: JiraExecutorResultData | null = null; @@ -114,7 +114,7 @@ async function executor( }, logger, configurationUtilities, - connectorMetricsService + connectorMetricsCollector ); if (!api[subAction]) { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/jira/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/jira/service.test.ts index 49c6c4459e8a1..74091388eee5f 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/jira/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/jira/service.test.ts @@ -14,7 +14,7 @@ import { Logger } from '@kbn/core/server'; import { loggingSystemMock } from '@kbn/core/server/mocks'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { getBasicAuthHeader } from '@kbn/actions-plugin/server'; -import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; +import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; const logger = loggingSystemMock.create().get() as jest.Mocked; interface ResponseError extends Error { @@ -136,10 +136,10 @@ const mockOldAPI = () => describe('Jira service', () => { let service: ExternalService; - let connectorMetricsService: ConnectorMetricsService; + let connectorMetricsCollector: ConnectorMetricsCollector; beforeAll(() => { - connectorMetricsService = new ConnectorMetricsService(); + connectorMetricsCollector = new ConnectorMetricsCollector(); service = createExternalService( { // The trailing slash at the end of the url is intended. @@ -149,7 +149,7 @@ describe('Jira service', () => { }, logger, configurationUtilities, - connectorMetricsService + connectorMetricsCollector ); }); @@ -167,7 +167,7 @@ describe('Jira service', () => { }, logger, configurationUtilities, - connectorMetricsService + connectorMetricsCollector ) ).toThrow(); }); @@ -181,7 +181,7 @@ describe('Jira service', () => { }, logger, configurationUtilities, - connectorMetricsService + connectorMetricsCollector ) ).toThrow(); }); @@ -195,7 +195,7 @@ describe('Jira service', () => { }, logger, configurationUtilities, - connectorMetricsService + connectorMetricsCollector ) ).toThrow(); }); @@ -209,7 +209,7 @@ describe('Jira service', () => { }, logger, configurationUtilities, - connectorMetricsService + connectorMetricsCollector ) ).toThrow(); }); @@ -222,7 +222,7 @@ describe('Jira service', () => { }, logger, configurationUtilities, - connectorMetricsService + connectorMetricsCollector ); expect(axios.create).toHaveBeenCalledWith({ @@ -267,7 +267,7 @@ describe('Jira service', () => { url: 'https://coolsite.net/rest/api/2/issue/1', logger, configurationUtilities, - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -411,7 +411,7 @@ describe('Jira service', () => { priority: { name: 'High' }, }, }, - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -470,7 +470,7 @@ describe('Jira service', () => { priority: { name: 'High' }, }, }, - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -504,7 +504,7 @@ describe('Jira service', () => { parent: { key: 'RJ-107' }, }, }, - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -574,7 +574,7 @@ describe('Jira service', () => { ...otherFields, }, }, - connectorMetricsService, + connectorMetricsCollector, }); }); }); @@ -645,7 +645,7 @@ describe('Jira service', () => { parent: { key: 'RJ-107' }, }, }, - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -708,7 +708,7 @@ describe('Jira service', () => { ...otherFields, }, }, - connectorMetricsService, + connectorMetricsCollector, }); }); }); @@ -762,7 +762,7 @@ describe('Jira service', () => { configurationUtilities, url: 'https://coolsite.net/rest/api/2/issue/1/comment', data: { body: 'comment' }, - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -819,7 +819,7 @@ describe('Jira service', () => { method: 'get', configurationUtilities, url: 'https://coolsite.net/rest/capabilities', - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -901,7 +901,7 @@ describe('Jira service', () => { method: 'get', configurationUtilities, url: 'https://coolsite.net/rest/api/2/issue/createmeta?projectKeys=CK&expand=projects.issuetypes.fields', - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -976,7 +976,7 @@ describe('Jira service', () => { method: 'get', configurationUtilities, url: 'https://coolsite.net/rest/api/2/issue/createmeta/CK/issuetypes', - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -1052,7 +1052,7 @@ describe('Jira service', () => { method: 'get', configurationUtilities, url: 'https://coolsite.net/rest/api/2/issue/createmeta?projectKeys=CK&issuetypeIds=10006&expand=projects.issuetypes.fields', - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -1261,7 +1261,7 @@ describe('Jira service', () => { method: 'get', configurationUtilities, url: `https://coolsite.net/rest/api/2/search?jql=project%3D%22CK%22%20and%20summary%20~%22Test%20title%22`, - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -1288,7 +1288,7 @@ describe('Jira service', () => { method: 'get', configurationUtilities, url: `https://coolsite.net/rest/api/2/search?jql=project%3D%22CK%22%20and%20summary%20~%22%5C%5C%5Bth%5C%5C!s%5C%5C%5Eis%5C%5C(%5C%5C)a%5C%5C-te%5C%5C%2Bst%5C%5C-%5C%5C%7B%5C%5C~is%5C%5C*s%5C%5C%26ue%5C%5C%3For%5C%5C%7Cand%5C%5Cbye%5C%5C%3A%5C%5C%7D%5C%5C%5D%5C%5C%7D%5C%5C%5D%22`, - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -1367,7 +1367,7 @@ describe('Jira service', () => { method: 'get', configurationUtilities, url: `https://coolsite.net/rest/api/2/issue/RJ-107`, - connectorMetricsService, + connectorMetricsCollector, }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/jira/service.ts b/x-pack/plugins/stack_connectors/server/connector_types/jira/service.ts index cf229f8aeaedb..aa3b862c48815 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/jira/service.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/jira/service.ts @@ -16,7 +16,7 @@ import { } from '@kbn/actions-plugin/server/lib/axios_utils'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; import { getBasicAuthHeader } from '@kbn/actions-plugin/server'; -import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; +import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; import { CreateCommentParams, CreateIncidentParams, @@ -49,7 +49,7 @@ export const createExternalService = ( { config, secrets }: ExternalServiceCredentials, logger: Logger, configurationUtilities: ActionsConfigurationUtilities, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): ExternalService => { const { apiUrl: url, projectKey } = config as JiraPublicConfigurationType; const { apiToken, email } = secrets as JiraSecretConfigurationType; @@ -191,7 +191,7 @@ export const createExternalService = ( url: `${incidentUrl}/${id}`, logger, configurationUtilities, - connectorMetricsService, + connectorMetricsCollector, }); throwIfResponseIsNotValid({ @@ -245,7 +245,7 @@ export const createExternalService = ( fields, }, configurationUtilities, - connectorMetricsService, + connectorMetricsCollector, }); throwIfResponseIsNotValid({ @@ -292,7 +292,7 @@ export const createExternalService = ( logger, data: { fields }, configurationUtilities, - connectorMetricsService, + connectorMetricsCollector, }); throwIfResponseIsNotValid({ @@ -331,7 +331,7 @@ export const createExternalService = ( logger, data: { body: comment.comment }, configurationUtilities, - connectorMetricsService, + connectorMetricsCollector, }); throwIfResponseIsNotValid({ @@ -364,7 +364,7 @@ export const createExternalService = ( url: capabilitiesUrl, logger, configurationUtilities, - connectorMetricsService, + connectorMetricsCollector, }); throwIfResponseIsNotValid({ @@ -396,7 +396,7 @@ export const createExternalService = ( url: getIssueTypesOldAPIURL, logger, configurationUtilities, - connectorMetricsService, + connectorMetricsCollector, }); throwIfResponseIsNotValid({ @@ -412,7 +412,7 @@ export const createExternalService = ( url: getIssueTypesUrl, logger, configurationUtilities, - connectorMetricsService, + connectorMetricsCollector, }); throwIfResponseIsNotValid({ @@ -445,7 +445,7 @@ export const createExternalService = ( url: createGetIssueTypeFieldsUrl(getIssueTypeFieldsOldAPIURL, issueTypeId), logger, configurationUtilities, - connectorMetricsService, + connectorMetricsCollector, }); throwIfResponseIsNotValid({ @@ -525,7 +525,7 @@ export const createExternalService = ( url: query, logger, configurationUtilities, - connectorMetricsService, + connectorMetricsCollector, }); throwIfResponseIsNotValid({ @@ -554,7 +554,7 @@ export const createExternalService = ( url: getIssueUrl, logger, configurationUtilities, - connectorMetricsService, + connectorMetricsCollector, }); throwIfResponseIsNotValid({ diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/create_service_wrapper.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/create_service_wrapper.test.ts index 311de65eb4abe..9f984de648ae9 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/create_service_wrapper.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/create_service_wrapper.test.ts @@ -12,6 +12,7 @@ import { loggingSystemMock } from '@kbn/core/server/mocks'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { connectorTokenClientMock } from '@kbn/actions-plugin/server/lib/connector_token_client.mock'; import { snExternalServiceConfig } from './config'; +import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; const logger = loggingSystemMock.create().get() as jest.Mocked; const connectorTokenClient = connectorTokenClientMock.create(); @@ -19,10 +20,12 @@ const configurationUtilities = actionsConfigMock.create(); jest.mock('axios'); axios.create = jest.fn(() => axios); +let connectorMetricsCollector: ConnectorMetricsCollector; describe('createServiceWrapper', () => { beforeEach(() => { jest.clearAllMocks(); + connectorMetricsCollector = new ConnectorMetricsCollector(); }); test('creates axios instance with apiUrl', () => { @@ -45,6 +48,7 @@ describe('createServiceWrapper', () => { serviceConfig, connectorTokenClient, createServiceFn, + connectorMetricsCollector, }); expect(createServiceFn).toHaveBeenCalledWith({ @@ -53,6 +57,7 @@ describe('createServiceWrapper', () => { configurationUtilities, serviceConfig, axiosInstance: axios, + connectorMetricsCollector, }); }); @@ -76,6 +81,7 @@ describe('createServiceWrapper', () => { serviceConfig, connectorTokenClient, createServiceFn, + connectorMetricsCollector, }); expect(createServiceFn).toHaveBeenCalledWith({ @@ -84,6 +90,7 @@ describe('createServiceWrapper', () => { configurationUtilities, serviceConfig, axiosInstance: axios, + connectorMetricsCollector, }); }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/create_service_wrapper.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/create_service_wrapper.ts index 01a215bc8905c..7d4e2715be9c0 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/create_service_wrapper.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/create_service_wrapper.ts @@ -7,7 +7,7 @@ import { Logger } from '@kbn/core/server'; import { - ConnectorMetricsService, + ConnectorMetricsCollector, ConnectorTokenClientContract, } from '@kbn/actions-plugin/server/types'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; @@ -24,7 +24,7 @@ interface CreateServiceWrapperOpts { serviceConfig: SNProductsConfigValue; connectorTokenClient: ConnectorTokenClientContract; createServiceFn: ServiceFactory; - connectorMetricsService: ConnectorMetricsService; + connectorMetricsCollector: ConnectorMetricsCollector; } export function createServiceWrapper({ @@ -35,7 +35,7 @@ export function createServiceWrapper({ serviceConfig, connectorTokenClient, createServiceFn, - connectorMetricsService, + connectorMetricsCollector, }: CreateServiceWrapperOpts): T { const { config } = credentials; const { apiUrl: url } = config as ServiceNowPublicConfigurationType; @@ -55,6 +55,6 @@ export function createServiceWrapper({ configurationUtilities, serviceConfig, axiosInstance, - connectorMetricsService, + connectorMetricsCollector, }); } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.test.ts index ce6f33e1cc0d1..58ac9f19a5176 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.test.ts @@ -15,6 +15,7 @@ import { loggingSystemMock } from '@kbn/core/server/mocks'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { serviceNowCommonFields, serviceNowChoices } from './mocks'; import { snExternalServiceConfig } from './config'; +import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; const logger = loggingSystemMock.create().get() as jest.Mocked; jest.mock('axios', () => ({ @@ -178,6 +179,7 @@ const expectImportedIncident = (update: boolean) => { configurationUtilities, url: 'https://example.com/api/x_elas2_inc_int/elastic_api/health', method: 'get', + connectorMetricsCollector: expect.any(ConnectorMetricsCollector), }); expect(requestMock).toHaveBeenNthCalledWith(2, { @@ -191,6 +193,7 @@ const expectImportedIncident = (update: boolean) => { u_description: 'desc', ...(update ? { elastic_incident_id: '1' } : {}), }, + connectorMetricsCollector: expect.any(ConnectorMetricsCollector), }); expect(requestMock).toHaveBeenNthCalledWith(3, { @@ -199,14 +202,18 @@ const expectImportedIncident = (update: boolean) => { configurationUtilities, url: 'https://example.com/api/now/v2/table/incident/1', method: 'get', + connectorMetricsCollector: expect.any(ConnectorMetricsCollector), }); }; describe('ServiceNow service', () => { let service: ExternalService; + let connectorMetricsCollector: ConnectorMetricsCollector; beforeEach(() => { jest.clearAllMocks(); + connectorMetricsCollector = new ConnectorMetricsCollector(); + service = createExternalService({ credentials: { // The trailing slash at the end of the url is intended. @@ -218,6 +225,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow'], axiosInstance: axios, + connectorMetricsCollector, }); }); @@ -233,6 +241,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow'], axiosInstance: axios, + connectorMetricsCollector, }) ).toThrow(); }); @@ -273,6 +282,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow'], axiosInstance: axios, + connectorMetricsCollector, }) ).toThrow(); }); @@ -437,6 +447,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow'], axiosInstance: axios, + connectorMetricsCollector, }) ).toThrow(); }); @@ -464,6 +475,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/incident/1', method: 'get', + connectorMetricsCollector, }); }); @@ -477,6 +489,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], table: 'sn_si_incident' }, axiosInstance: axios, + connectorMetricsCollector, }); requestMock.mockImplementation(() => ({ @@ -490,6 +503,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/sn_si_incident/1', method: 'get', + connectorMetricsCollector, }); }); @@ -535,6 +549,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/incident?sysparm_query=ORDERBYDESCsys_created_on^correlation_id=custom_correlation_id', method: 'get', + connectorMetricsCollector, }); }); @@ -559,6 +574,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], table: 'sn_si_incident' }, axiosInstance: axios, + connectorMetricsCollector, }); requestMock.mockImplementation(() => ({ @@ -572,6 +588,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/sn_si_incident?sysparm_query=ORDERBYDESCsys_created_on^correlation_id=custom_correlation_id', method: 'get', + connectorMetricsCollector, }); }); @@ -625,6 +642,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow-sir'], axiosInstance: axios, + connectorMetricsCollector, }); const res = await createIncident(service); @@ -635,6 +653,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/x_elas2_sir_int/elastic_api/health', method: 'get', + connectorMetricsCollector, }); expect(requestMock).toHaveBeenNthCalledWith(2, { @@ -644,6 +663,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/import/x_elas2_sir_int_elastic_si_incident', method: 'post', data: { u_short_description: 'title', u_description: 'desc' }, + connectorMetricsCollector, }); expect(requestMock).toHaveBeenNthCalledWith(3, { @@ -652,6 +672,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/sn_si_incident/1', method: 'get', + connectorMetricsCollector, }); expect(res.url).toEqual('https://example.com/nav_to.do?uri=sn_si_incident.do?sys_id=1'); @@ -707,6 +728,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/import/x_elas2_inc_int_elastic_incident', method: 'post', data: { u_short_description: 'title', u_description: 'desc', foo: 'test' }, + connectorMetricsCollector, }); }); }); @@ -723,6 +745,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], useImportAPI: false }, axiosInstance: axios, + connectorMetricsCollector, }); }); @@ -749,6 +772,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/v2/table/incident', method: 'post', data: { short_description: 'title', description: 'desc' }, + connectorMetricsCollector, }); }); @@ -762,6 +786,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow-sir'], useImportAPI: false }, axiosInstance: axios, + connectorMetricsCollector, }); mockIncidentResponse(false); @@ -778,6 +803,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/v2/table/sn_si_incident', method: 'post', data: { short_description: 'title', description: 'desc' }, + connectorMetricsCollector, }); expect(res.url).toEqual('https://example.com/nav_to.do?uri=sn_si_incident.do?sys_id=1'); @@ -826,6 +852,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow-sir'], axiosInstance: axios, + connectorMetricsCollector, }); const res = await updateIncident(service); @@ -835,6 +862,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/x_elas2_sir_int/elastic_api/health', method: 'get', + connectorMetricsCollector, }); expect(requestMock).toHaveBeenNthCalledWith(2, { @@ -844,6 +872,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/import/x_elas2_sir_int_elastic_si_incident', method: 'post', data: { u_short_description: 'title', u_description: 'desc', elastic_incident_id: '1' }, + connectorMetricsCollector, }); expect(requestMock).toHaveBeenNthCalledWith(3, { @@ -852,6 +881,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/sn_si_incident/1', method: 'get', + connectorMetricsCollector, }); expect(res.url).toEqual('https://example.com/nav_to.do?uri=sn_si_incident.do?sys_id=1'); @@ -915,6 +945,7 @@ describe('ServiceNow service', () => { elastic_incident_id: '1', foo: 'test', }, + connectorMetricsCollector, }); }); }); @@ -931,6 +962,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], useImportAPI: false }, axiosInstance: axios, + connectorMetricsCollector, }); }); @@ -958,6 +990,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/v2/table/incident/1', method: 'patch', data: { short_description: 'title', description: 'desc' }, + connectorMetricsCollector, }); }); @@ -971,6 +1004,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow-sir'], useImportAPI: false }, axiosInstance: axios, + connectorMetricsCollector, }); mockIncidentResponse(false); @@ -988,6 +1022,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/v2/table/sn_si_incident/1', method: 'patch', data: { short_description: 'title', description: 'desc' }, + connectorMetricsCollector, }); expect(res.url).toEqual('https://example.com/nav_to.do?uri=sn_si_incident.do?sys_id=1'); @@ -1032,6 +1067,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/incident/1', method: 'get', + connectorMetricsCollector, }); expect(requestMock).toHaveBeenNthCalledWith(2, { @@ -1040,6 +1076,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/x_elas2_inc_int/elastic_api/health', method: 'get', + connectorMetricsCollector, }); expect(requestMock).toHaveBeenNthCalledWith(3, { @@ -1054,6 +1091,7 @@ describe('ServiceNow service', () => { u_state: '7', u_close_notes: 'Closed by Caller', }, + connectorMetricsCollector, }); expect(requestMock).toHaveBeenNthCalledWith(4, { @@ -1062,6 +1100,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/incident/1', method: 'get', + connectorMetricsCollector, }); expect(res?.url).toEqual('https://example.com/nav_to.do?uri=incident.do?sys_id=1'); @@ -1097,6 +1136,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/incident?sysparm_query=ORDERBYDESCsys_created_on^correlation_id=custom_correlation_id', method: 'get', + connectorMetricsCollector, }); expect(requestMock).toHaveBeenNthCalledWith(2, { @@ -1105,6 +1145,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/x_elas2_inc_int/elastic_api/health', method: 'get', + connectorMetricsCollector, }); expect(requestMock).toHaveBeenNthCalledWith(3, { @@ -1119,6 +1160,7 @@ describe('ServiceNow service', () => { u_state: '7', u_close_notes: 'Closed by Caller', }, + connectorMetricsCollector, }); expect(requestMock).toHaveBeenNthCalledWith(4, { @@ -1127,6 +1169,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/incident/1', method: 'get', + connectorMetricsCollector, }); expect(res?.url).toEqual('https://example.com/nav_to.do?uri=incident.do?sys_id=1'); @@ -1237,6 +1280,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], useImportAPI: false }, axiosInstance: axios, + connectorMetricsCollector, }); }); @@ -1268,6 +1312,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow-sir'], useImportAPI: false }, axiosInstance: axios, + connectorMetricsCollector, }); mockIncidentResponse(false); @@ -1285,6 +1330,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/sn_si_incident/1', method: 'get', + connectorMetricsCollector, }); expect(requestMock).toHaveBeenNthCalledWith(2, { @@ -1298,6 +1344,7 @@ describe('ServiceNow service', () => { state: '7', close_notes: 'Closed by Caller', }, + connectorMetricsCollector, }); expect(requestMock).toHaveBeenNthCalledWith(3, { @@ -1306,6 +1353,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/sn_si_incident/1', method: 'get', + connectorMetricsCollector, }); expect(res?.url).toEqual('https://example.com/nav_to.do?uri=sn_si_incident.do?sys_id=1'); @@ -1325,6 +1373,7 @@ describe('ServiceNow service', () => { logger, configurationUtilities, url: 'https://example.com/api/now/table/sys_dictionary?sysparm_query=name=task^ORname=incident^internal_type=string&active=true&array=false&read_only=false&sysparm_fields=max_length,element,column_label,mandatory', + connectorMetricsCollector, }); }); @@ -1346,6 +1395,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], table: 'sn_si_incident' }, axiosInstance: axios, + connectorMetricsCollector, }); requestMock.mockImplementation(() => ({ @@ -1358,6 +1408,7 @@ describe('ServiceNow service', () => { logger, configurationUtilities, url: 'https://example.com/api/now/table/sys_dictionary?sysparm_query=name=task^ORname=sn_si_incident^internal_type=string&active=true&array=false&read_only=false&sysparm_fields=max_length,element,column_label,mandatory', + connectorMetricsCollector, }); }); @@ -1394,6 +1445,7 @@ describe('ServiceNow service', () => { logger, configurationUtilities, url: 'https://example.com/api/now/table/sys_choice?sysparm_query=name=task^ORname=incident^element=priority^ORelement=category^language=en&sysparm_fields=label,value,dependent_value,element', + connectorMetricsCollector, }); }); @@ -1415,6 +1467,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], table: 'sn_si_incident' }, axiosInstance: axios, + connectorMetricsCollector, }); requestMock.mockImplementation(() => ({ @@ -1428,6 +1481,7 @@ describe('ServiceNow service', () => { logger, configurationUtilities, url: 'https://example.com/api/now/table/sys_choice?sysparm_query=name=task^ORname=sn_si_incident^element=priority^ORelement=category^language=en&sysparm_fields=label,value,dependent_value,element', + connectorMetricsCollector, }); }); @@ -1520,6 +1574,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], useImportAPI: false }, axiosInstance: axios, + connectorMetricsCollector, }); await service.checkIfApplicationIsInstalled(); expect(requestMock).not.toHaveBeenCalled(); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.ts index de2573463094e..a8e4f66263379 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.ts @@ -37,7 +37,7 @@ export const createExternalService: ServiceFactory = ({ configurationUtilities, serviceConfig, axiosInstance, - connectorMetricsService, + connectorMetricsCollector, }): ExternalService => { const { config, secrets } = credentials; const { table, importSetTable, useImportAPI, appScope } = serviceConfig; @@ -133,7 +133,7 @@ export const createExternalService: ServiceFactory = ({ logger, configurationUtilities, method: 'get', - connectorMetricsService, // TODO check if this is internal + connectorMetricsCollector, // TODO check if this is internal }); checkInstance(res); @@ -162,7 +162,7 @@ export const createExternalService: ServiceFactory = ({ logger, configurationUtilities, method: 'get', - connectorMetricsService, + connectorMetricsCollector, }); checkInstance(res); @@ -181,7 +181,7 @@ export const createExternalService: ServiceFactory = ({ logger, params, configurationUtilities, - connectorMetricsService, + connectorMetricsCollector, }); checkInstance(res); @@ -205,7 +205,7 @@ export const createExternalService: ServiceFactory = ({ method: 'post', data: prepareIncident(useTableApi, incident), configurationUtilities, - connectorMetricsService, + connectorMetricsCollector, }); checkInstance(res); @@ -245,7 +245,7 @@ export const createExternalService: ServiceFactory = ({ ...(useTableApi ? {} : { elastic_incident_id: incidentId }), }, configurationUtilities, - connectorMetricsService, + connectorMetricsCollector, }); checkInstance(res); @@ -278,7 +278,7 @@ export const createExternalService: ServiceFactory = ({ method: 'get', logger, configurationUtilities, - connectorMetricsService, + connectorMetricsCollector, }); checkInstance(res); @@ -357,7 +357,7 @@ export const createExternalService: ServiceFactory = ({ url: fieldsUrl, logger, configurationUtilities, - connectorMetricsService, + connectorMetricsCollector, }); checkInstance(res); @@ -375,7 +375,7 @@ export const createExternalService: ServiceFactory = ({ url: getChoicesURL(fields), logger, configurationUtilities, - connectorMetricsService, + connectorMetricsCollector, }); checkInstance(res); return res.data.result; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/types.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/types.ts index adde700b93c4d..93462e2811826 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/types.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/types.ts @@ -11,7 +11,7 @@ import { AxiosError, AxiosInstance, AxiosResponse } from 'axios'; import { TypeOf } from '@kbn/config-schema'; import { Logger } from '@kbn/core/server'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; -import { ConnectorMetricsService, ValidatorServices } from '@kbn/actions-plugin/server/types'; +import { ConnectorMetricsCollector, ValidatorServices } from '@kbn/actions-plugin/server/types'; import { ExecutorParamsSchemaITSM, ExecutorSubActionCommonFieldsParamsSchema, @@ -305,7 +305,7 @@ interface ServiceFactoryOpts { configurationUtilities: ActionsConfigurationUtilities; serviceConfig: SNProductsConfigValue; axiosInstance: AxiosInstance; - connectorMetricsService: ConnectorMetricsService; + connectorMetricsCollector: ConnectorMetricsCollector; } export type ServiceFactory = ({ @@ -314,7 +314,7 @@ export type ServiceFactory = ({ configurationUtilities, serviceConfig, axiosInstance, - connectorMetricsService, + connectorMetricsCollector, }: ServiceFactoryOpts) => T; /** diff --git a/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.test.ts index 46818b85adc52..ea0b48e116832 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.test.ts @@ -19,7 +19,7 @@ import { actionsMock } from '@kbn/actions-plugin/server/mocks'; import { RunActionResponseSchema, StreamingResponseSchema } from '../../../common/openai/schema'; import { initDashboard } from '../lib/gen_ai/create_gen_ai_dashboard'; import { PassThrough, Transform } from 'stream'; -import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; +import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; jest.mock('../lib/gen_ai/create_gen_ai_dashboard'); const mockTee = jest.fn(); @@ -47,7 +47,7 @@ jest.mock('openai', () => ({ describe('OpenAIConnector', () => { let mockRequest: jest.Mock; let mockError: jest.Mock; - let connectorMetricsService: ConnectorMetricsService; + let connectorMetricsCollector: ConnectorMetricsCollector; const mockResponseString = 'Hello! How can I assist you today?'; const mockResponse = { @@ -75,7 +75,7 @@ describe('OpenAIConnector', () => { }, }; beforeEach(() => { - connectorMetricsService = new ConnectorMetricsService(); + connectorMetricsCollector = new ConnectorMetricsCollector(); mockRequest = jest.fn().mockResolvedValue(mockResponse); mockError = jest.fn().mockImplementation(() => { throw new Error('API Error'); @@ -119,7 +119,7 @@ describe('OpenAIConnector', () => { it('uses the default model if none is supplied', async () => { const response = await connector.runApi( { body: JSON.stringify(sampleOpenAiBody) }, - connectorMetricsService + connectorMetricsCollector ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( @@ -136,7 +136,7 @@ describe('OpenAIConnector', () => { 'content-type': 'application/json', }, }, - connectorMetricsService + connectorMetricsCollector ); expect(response).toEqual(mockResponse.data); }); @@ -145,7 +145,7 @@ describe('OpenAIConnector', () => { const requestBody = { model: 'gpt-3.5-turbo', ...sampleOpenAiBody }; const response = await connector.runApi( { body: JSON.stringify(requestBody) }, - connectorMetricsService + connectorMetricsCollector ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( @@ -158,7 +158,7 @@ describe('OpenAIConnector', () => { 'content-type': 'application/json', }, }, - connectorMetricsService + connectorMetricsCollector ); expect(response).toEqual(mockResponse.data); }); @@ -166,7 +166,7 @@ describe('OpenAIConnector', () => { it('the OpenAI API call is successful with correct parameters', async () => { const response = await connector.runApi( { body: JSON.stringify(sampleOpenAiBody) }, - connectorMetricsService + connectorMetricsCollector ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( @@ -183,7 +183,7 @@ describe('OpenAIConnector', () => { 'content-type': 'application/json', }, }, - connectorMetricsService + connectorMetricsCollector ); expect(response).toEqual(mockResponse.data); }); @@ -205,7 +205,7 @@ describe('OpenAIConnector', () => { stream: true, }), }, - connectorMetricsService + connectorMetricsCollector ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( @@ -221,7 +221,7 @@ describe('OpenAIConnector', () => { 'content-type': 'application/json', }, }, - connectorMetricsService + connectorMetricsCollector ); expect(response).toEqual(mockResponse.data); }); @@ -231,7 +231,7 @@ describe('OpenAIConnector', () => { connector.request = mockError; await expect( - connector.runApi({ body: JSON.stringify(sampleOpenAiBody) }, connectorMetricsService) + connector.runApi({ body: JSON.stringify(sampleOpenAiBody) }, connectorMetricsCollector) ).rejects.toThrow('API Error'); }); }); @@ -243,7 +243,7 @@ describe('OpenAIConnector', () => { body: JSON.stringify(sampleOpenAiBody), stream: false, }, - connectorMetricsService + connectorMetricsCollector ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( @@ -262,7 +262,7 @@ describe('OpenAIConnector', () => { 'content-type': 'application/json', }, }, - connectorMetricsService + connectorMetricsCollector ); expect(response).toEqual(mockResponse.data); }); @@ -273,7 +273,7 @@ describe('OpenAIConnector', () => { body: JSON.stringify(sampleOpenAiBody), stream: true, }, - connectorMetricsService + connectorMetricsCollector ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( @@ -293,7 +293,7 @@ describe('OpenAIConnector', () => { 'content-type': 'application/json', }, }, - connectorMetricsService + connectorMetricsCollector ); expect(response).toEqual({ headers: { 'Content-Type': 'dont-compress-this' }, @@ -319,7 +319,7 @@ describe('OpenAIConnector', () => { }), stream: true, }, - connectorMetricsService + connectorMetricsCollector ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( @@ -338,7 +338,7 @@ describe('OpenAIConnector', () => { 'content-type': 'application/json', }, }, - connectorMetricsService + connectorMetricsCollector ); expect(response).toEqual({ headers: { 'Content-Type': 'dont-compress-this' }, @@ -353,7 +353,7 @@ describe('OpenAIConnector', () => { await expect( connector.streamApi( { body: JSON.stringify(sampleOpenAiBody), stream: true }, - connectorMetricsService + connectorMetricsCollector ) ).rejects.toThrow('API Error'); }); @@ -379,7 +379,7 @@ describe('OpenAIConnector', () => { }); it('the API call is successful with correct request parameters', async () => { - await connector.invokeStream(sampleOpenAiBody, connectorMetricsService); + await connector.invokeStream(sampleOpenAiBody, connectorMetricsCollector); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( { @@ -398,13 +398,13 @@ describe('OpenAIConnector', () => { 'content-type': 'application/json', }, }, - connectorMetricsService + connectorMetricsCollector ); }); it('signal is properly passed to streamApi', async () => { const signal = jest.fn(); - await connector.invokeStream({ ...sampleOpenAiBody, signal }, connectorMetricsService); + await connector.invokeStream({ ...sampleOpenAiBody, signal }, connectorMetricsCollector); expect(mockRequest).toHaveBeenCalledWith( { @@ -424,13 +424,13 @@ describe('OpenAIConnector', () => { }, signal, }, - connectorMetricsService + connectorMetricsCollector ); }); it('timeout is properly passed to streamApi', async () => { const timeout = 180000; - await connector.invokeStream({ ...sampleOpenAiBody, timeout }, connectorMetricsService); + await connector.invokeStream({ ...sampleOpenAiBody, timeout }, connectorMetricsCollector); expect(mockRequest).toHaveBeenCalledWith( { @@ -450,7 +450,7 @@ describe('OpenAIConnector', () => { }, timeout, }, - connectorMetricsService + connectorMetricsCollector ); }); @@ -459,21 +459,21 @@ describe('OpenAIConnector', () => { connector.request = mockError; await expect( - connector.invokeStream(sampleOpenAiBody, connectorMetricsService) + connector.invokeStream(sampleOpenAiBody, connectorMetricsCollector) ).rejects.toThrow('API Error'); }); it('responds with a readable stream', async () => { // @ts-ignore connector.request = mockStream(); - const response = await connector.invokeStream(sampleOpenAiBody, connectorMetricsService); + const response = await connector.invokeStream(sampleOpenAiBody, connectorMetricsCollector); expect(response instanceof PassThrough).toEqual(true); }); }); describe('invokeAI', () => { it('the API call is successful with correct parameters', async () => { - const response = await connector.invokeAI(sampleOpenAiBody, connectorMetricsService); + const response = await connector.invokeAI(sampleOpenAiBody, connectorMetricsCollector); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( { @@ -489,7 +489,7 @@ describe('OpenAIConnector', () => { 'content-type': 'application/json', }, }, - connectorMetricsService + connectorMetricsCollector ); expect(response.message).toEqual(mockResponseString); expect(response.usage.total_tokens).toEqual(9); @@ -497,7 +497,7 @@ describe('OpenAIConnector', () => { it('signal is properly passed to runApi', async () => { const signal = jest.fn(); - await connector.invokeAI({ ...sampleOpenAiBody, signal }, connectorMetricsService); + await connector.invokeAI({ ...sampleOpenAiBody, signal }, connectorMetricsCollector); expect(mockRequest).toHaveBeenCalledWith( { @@ -514,13 +514,13 @@ describe('OpenAIConnector', () => { }, signal, }, - connectorMetricsService + connectorMetricsCollector ); }); it('timeout is properly passed to runApi', async () => { const timeout = 180000; - await connector.invokeAI({ ...sampleOpenAiBody, timeout }, connectorMetricsService); + await connector.invokeAI({ ...sampleOpenAiBody, timeout }, connectorMetricsCollector); expect(mockRequest).toHaveBeenCalledWith( { @@ -537,7 +537,7 @@ describe('OpenAIConnector', () => { }, timeout, }, - connectorMetricsService + connectorMetricsCollector ); }); @@ -545,15 +545,15 @@ describe('OpenAIConnector', () => { // @ts-ignore connector.request = mockError; - await expect(connector.invokeAI(sampleOpenAiBody, connectorMetricsService)).rejects.toThrow( - 'API Error' - ); + await expect( + connector.invokeAI(sampleOpenAiBody, connectorMetricsCollector) + ).rejects.toThrow('API Error'); }); }); describe('invokeAsyncIterator', () => { it('the API call is successful with correct request parameters', async () => { - await connector.invokeAsyncIterator(sampleOpenAiBody, connectorMetricsService); + await connector.invokeAsyncIterator(sampleOpenAiBody, connectorMetricsCollector); expect(mockRequest).toBeCalledTimes(0); expect(mockCreate).toHaveBeenCalledWith( { @@ -570,7 +570,7 @@ describe('OpenAIConnector', () => { const signal = jest.fn(); await connector.invokeAsyncIterator( { ...sampleOpenAiBody, signal, timeout }, - connectorMetricsService + connectorMetricsCollector ); expect(mockRequest).toBeCalledTimes(0); expect(mockCreate).toHaveBeenCalledWith( @@ -593,7 +593,7 @@ describe('OpenAIConnector', () => { }); await expect( - connector.invokeAsyncIterator(sampleOpenAiBody, connectorMetricsService) + connector.invokeAsyncIterator(sampleOpenAiBody, connectorMetricsCollector) ).rejects.toThrow('API Error'); }); }); @@ -686,7 +686,7 @@ describe('OpenAIConnector', () => { it('uses the default model if none is supplied', async () => { const response = await connector.runApi( { body: JSON.stringify(sampleOpenAiBody) }, - connectorMetricsService + connectorMetricsCollector ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( @@ -702,7 +702,7 @@ describe('OpenAIConnector', () => { 'content-type': 'application/json', }, }, - connectorMetricsService + connectorMetricsCollector ); expect(response).toEqual(mockResponse.data); }); @@ -742,7 +742,7 @@ describe('OpenAIConnector', () => { it('test the AzureAI API call is successful with correct parameters', async () => { const response = await connector.runApi( { body: JSON.stringify(sampleAzureAiBody) }, - connectorMetricsService + connectorMetricsCollector ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( @@ -755,7 +755,7 @@ describe('OpenAIConnector', () => { 'content-type': 'application/json', }, }, - connectorMetricsService + connectorMetricsCollector ); expect(response).toEqual(mockResponse.data); }); @@ -773,7 +773,7 @@ describe('OpenAIConnector', () => { { body: JSON.stringify({ ...body, stream: true }), }, - connectorMetricsService + connectorMetricsCollector ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( @@ -786,7 +786,7 @@ describe('OpenAIConnector', () => { 'content-type': 'application/json', }, }, - connectorMetricsService + connectorMetricsCollector ); expect(response).toEqual(mockResponse.data); }); @@ -796,7 +796,7 @@ describe('OpenAIConnector', () => { connector.request = mockError; await expect( - connector.runApi({ body: JSON.stringify(sampleAzureAiBody) }, connectorMetricsService) + connector.runApi({ body: JSON.stringify(sampleAzureAiBody) }, connectorMetricsCollector) ).rejects.toThrow('API Error'); }); }); @@ -808,7 +808,7 @@ describe('OpenAIConnector', () => { body: JSON.stringify(sampleAzureAiBody), stream: false, }, - connectorMetricsService + connectorMetricsCollector ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( @@ -822,7 +822,7 @@ describe('OpenAIConnector', () => { 'content-type': 'application/json', }, }, - connectorMetricsService + connectorMetricsCollector ); expect(response).toEqual(mockResponse.data); }); @@ -833,7 +833,7 @@ describe('OpenAIConnector', () => { body: JSON.stringify(sampleAzureAiBody), stream: true, }, - connectorMetricsService + connectorMetricsCollector ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( @@ -848,7 +848,7 @@ describe('OpenAIConnector', () => { 'content-type': 'application/json', }, }, - connectorMetricsService + connectorMetricsCollector ); expect(response).toEqual({ headers: { 'Content-Type': 'dont-compress-this' }, @@ -870,7 +870,7 @@ describe('OpenAIConnector', () => { body: JSON.stringify({ ...body, stream: false }), stream: true, }, - connectorMetricsService + connectorMetricsCollector ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( @@ -888,7 +888,7 @@ describe('OpenAIConnector', () => { 'content-type': 'application/json', }, }, - connectorMetricsService + connectorMetricsCollector ); expect(response).toEqual({ headers: { 'Content-Type': 'dont-compress-this' }, @@ -903,7 +903,7 @@ describe('OpenAIConnector', () => { await expect( connector.streamApi( { body: JSON.stringify(sampleAzureAiBody), stream: true }, - connectorMetricsService + connectorMetricsCollector ) ).rejects.toThrow('API Error'); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.ts b/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.ts index 682cfa95a678a..191bfb3693538 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.ts @@ -16,7 +16,7 @@ import { ChatCompletionMessageParam, } from 'openai/resources/chat/completions'; import { Stream } from 'openai/streaming'; -import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; +import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; import { removeEndpointFromUrl } from './lib/openai_utils'; import { RunActionParamsSchema, @@ -160,7 +160,7 @@ export class OpenAIConnector extends SubActionConnector { public async runApi( { body, signal, timeout }: RunActionParams, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): Promise { const sanitizedBody = sanitizeRequest( this.provider, @@ -184,7 +184,7 @@ export class OpenAIConnector extends SubActionConnector { ...axiosOptions.headers, }, }, - connectorMetricsService + connectorMetricsCollector ); return response.data; } @@ -199,7 +199,7 @@ export class OpenAIConnector extends SubActionConnector { */ public async streamApi( { body, stream, signal, timeout }: StreamActionParams, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): Promise { const executeBody = getRequestWithStreamOption( this.provider, @@ -225,7 +225,7 @@ export class OpenAIConnector extends SubActionConnector { }, timeout, }, - connectorMetricsService + connectorMetricsCollector ); return stream ? pipeStreamingResponse(response) : response.data; } @@ -275,7 +275,7 @@ export class OpenAIConnector extends SubActionConnector { */ public async invokeStream( body: InvokeAIActionParams, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): Promise { const { signal, timeout, ...rest } = body; @@ -286,7 +286,7 @@ export class OpenAIConnector extends SubActionConnector { signal, timeout, // do not default if not provided }, - connectorMetricsService + connectorMetricsCollector )) as unknown as IncomingMessage; return res.pipe(new PassThrough()); @@ -303,7 +303,7 @@ export class OpenAIConnector extends SubActionConnector { */ public async invokeAsyncIterator( body: InvokeAIActionParams, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): Promise<{ consumerStream: Stream; tokenCountStream: Stream; @@ -320,7 +320,7 @@ export class OpenAIConnector extends SubActionConnector { ('defaultModel' in this.config ? this.config.defaultModel : DEFAULT_OPENAI_MODEL), }; - connectorMetricsService.addRequestBodyBytes(undefined, requestBody); + connectorMetricsCollector.addRequestBodyBytes(undefined, requestBody); const stream = await this.openAI.chat.completions.create(requestBody, { signal, timeout, // do not default if not provided @@ -345,12 +345,12 @@ export class OpenAIConnector extends SubActionConnector { */ public async invokeAI( body: InvokeAIActionParams, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): Promise { const { signal, timeout, ...rest } = body; const res = await this.runApi( { body: JSON.stringify(rest), signal, timeout }, - connectorMetricsService + connectorMetricsCollector ); if (res.choices && res.choices.length > 0 && res.choices[0].message?.content) { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.test.ts index 4b01301ca3d91..98f98c4c79d33 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.test.ts @@ -15,7 +15,7 @@ import { MockedLogger } from '@kbn/logging-mocks'; import { OpsgenieConnectorTypeId } from '../../../common'; import { OpsgenieConnector } from './connector'; import * as utils from '@kbn/actions-plugin/server/lib/axios_utils'; -import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; +import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; jest.mock('axios'); @@ -37,7 +37,7 @@ describe('OpsgenieConnector', () => { let mockedActionsConfig: jest.Mocked; let logger: MockedLogger; let services: ReturnType; - let connectorMetricsService: ConnectorMetricsService; + let connectorMetricsCollector: ConnectorMetricsCollector; const defaultCreateAlertExpect = { method: 'post', @@ -77,40 +77,40 @@ describe('OpsgenieConnector', () => { logger, services, }); - connectorMetricsService = new ConnectorMetricsService(); + connectorMetricsCollector = new ConnectorMetricsCollector(); }); it('calls request with the correct arguments for creating an alert', async () => { - await connector.createAlert({ message: 'hello' }, connectorMetricsService); + await connector.createAlert({ message: 'hello' }, connectorMetricsCollector); expect(requestMock.mock.calls[0][0]).toEqual({ data: { message: 'hello' }, ...ignoredRequestFields, ...defaultCreateAlertExpect, - connectorMetricsService, + connectorMetricsCollector, }); }); it('calls request without modifying the alias when it is less than 512 characters when creating an alert', async () => { - await connector.createAlert({ message: 'hello', alias: '111' }, connectorMetricsService); + await connector.createAlert({ message: 'hello', alias: '111' }, connectorMetricsCollector); expect(requestMock.mock.calls[0][0]).toEqual({ ...ignoredRequestFields, ...defaultCreateAlertExpect, data: { message: 'hello', alias: '111' }, - connectorMetricsService, + connectorMetricsCollector, }); }); it('calls request without modifying the alias when it is equal to 512 characters when creating an alert', async () => { const alias = 'a'.repeat(512); - await connector.createAlert({ message: 'hello', alias }, connectorMetricsService); + await connector.createAlert({ message: 'hello', alias }, connectorMetricsCollector); expect(requestMock.mock.calls[0][0]).toEqual({ ...ignoredRequestFields, ...defaultCreateAlertExpect, data: { message: 'hello', alias }, - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -120,13 +120,13 @@ describe('OpsgenieConnector', () => { const hasher = crypto.createHash('sha256'); const sha256Hash = hasher.update(alias); - await connector.createAlert({ message: 'hello', alias }, connectorMetricsService); + await connector.createAlert({ message: 'hello', alias }, connectorMetricsCollector); expect(requestMock.mock.calls[0][0]).toEqual({ ...ignoredRequestFields, ...defaultCreateAlertExpect, data: { message: 'hello', alias: `sha-${sha256Hash.digest('hex')}` }, - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -136,24 +136,24 @@ describe('OpsgenieConnector', () => { const hasher = crypto.createHash('sha256'); const sha256Hash = hasher.update(alias); - await connector.closeAlert({ alias }, connectorMetricsService); + await connector.closeAlert({ alias }, connectorMetricsCollector); expect(requestMock.mock.calls[0][0]).toEqual({ ...ignoredRequestFields, ...createCloseAlertExpect(`sha-${sha256Hash.digest('hex')}`), data: {}, - connectorMetricsService, + connectorMetricsCollector, }); }); it('calls request with the correct arguments for closing an alert', async () => { - await connector.closeAlert({ user: 'sam', alias: '111' }, connectorMetricsService); + await connector.closeAlert({ user: 'sam', alias: '111' }, connectorMetricsCollector); expect(requestMock.mock.calls[0][0]).toEqual({ ...ignoredRequestFields, ...createCloseAlertExpect('111'), data: { user: 'sam' }, - connectorMetricsService, + connectorMetricsCollector, }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.ts b/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.ts index 6091734c0b51c..16b91e2256284 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.ts @@ -9,7 +9,7 @@ import crypto from 'crypto'; import { ServiceParams, SubActionConnector } from '@kbn/actions-plugin/server'; import { AxiosError } from 'axios'; import { isEmpty } from 'lodash'; -import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; +import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; import { OpsgenieSubActions } from '../../../common'; import { CreateAlertParamsSchema, CloseAlertParamsSchema, Response } from './schema'; import { CloseAlertParams, Config, CreateAlertParams, FailureResponseType, Secrets } from './types'; @@ -70,7 +70,7 @@ export class OpsgenieConnector extends SubActionConnector { public async createAlert( params: CreateAlertParams, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ) { const res = await this.request( { @@ -80,7 +80,7 @@ export class OpsgenieConnector extends SubActionConnector { headers: this.createHeaders(), responseSchema: Response, }, - connectorMetricsService + connectorMetricsCollector ); return res.data; @@ -116,7 +116,7 @@ export class OpsgenieConnector extends SubActionConnector { public async closeAlert( params: CloseAlertParams, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ) { const newAlias = OpsgenieConnector.createAlias(params.alias); @@ -133,7 +133,7 @@ export class OpsgenieConnector extends SubActionConnector { headers: this.createHeaders(), responseSchema: Response, }, - connectorMetricsService + connectorMetricsCollector ); return res.data; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.test.ts index 9446221ea2f1a..770bdca23d25d 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.test.ts @@ -10,7 +10,7 @@ import moment from 'moment'; jest.mock('./post_pagerduty', () => ({ postPagerduty: jest.fn(), })); -import { ConnectorMetricsService, Services } from '@kbn/actions-plugin/server/types'; +import { ConnectorMetricsCollector, Services } from '@kbn/actions-plugin/server/types'; import { validateConfig, validateSecrets, validateParams } from '@kbn/actions-plugin/server/lib'; import { postPagerduty } from './post_pagerduty'; import { Logger } from '@kbn/core/server'; @@ -31,12 +31,12 @@ const mockedLogger: jest.Mocked = loggerMock.create(); let connectorType: PagerDutyConnectorType; let configurationUtilities: jest.Mocked; -let connectorMetricsService: ConnectorMetricsService; +let connectorMetricsCollector: ConnectorMetricsCollector; beforeEach(() => { configurationUtilities = actionsConfigMock.create(); connectorType = getConnectorType(); - connectorMetricsService = new ConnectorMetricsService(); + connectorMetricsCollector = new ConnectorMetricsCollector(); }); describe('get()', () => { @@ -271,7 +271,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, - connectorMetricsService, + connectorMetricsCollector, }; const actionResponse = await connectorType.executor(executorOptions); const { apiUrl, data, headers } = postPagerdutyMock.mock.calls[0][0]; @@ -353,7 +353,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, - connectorMetricsService, + connectorMetricsCollector, }; const actionResponse = await connectorType.executor(executorOptions); const { apiUrl, data, headers } = postPagerdutyMock.mock.calls[0][0]; @@ -462,7 +462,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, - connectorMetricsService, + connectorMetricsCollector, }; const actionResponse = await connectorType.executor(executorOptions); const { apiUrl, data, headers } = postPagerdutyMock.mock.calls[0][0]; @@ -540,7 +540,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, - connectorMetricsService, + connectorMetricsCollector, }; const actionResponse = await connectorType.executor(executorOptions); const { apiUrl, data, headers } = postPagerdutyMock.mock.calls[0][0]; @@ -584,7 +584,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, - connectorMetricsService, + connectorMetricsCollector, }; const actionResponse = await connectorType.executor(executorOptions); expect(actionResponse).toMatchInlineSnapshot(` @@ -615,7 +615,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, - connectorMetricsService, + connectorMetricsCollector, }; const actionResponse = await connectorType.executor(executorOptions); expect(actionResponse).toMatchInlineSnapshot(` @@ -646,7 +646,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, - connectorMetricsService, + connectorMetricsCollector, }; const actionResponse = await connectorType.executor(executorOptions); expect(actionResponse).toMatchInlineSnapshot(` @@ -677,7 +677,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, - connectorMetricsService, + connectorMetricsCollector, }; const actionResponse = await connectorType.executor(executorOptions); expect(actionResponse).toMatchInlineSnapshot(` @@ -718,7 +718,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, - connectorMetricsService, + connectorMetricsCollector, }; const actionResponse = await connectorType.executor(executorOptions); const { apiUrl, data, headers } = postPagerdutyMock.mock.calls[0][0]; @@ -782,7 +782,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, - connectorMetricsService, + connectorMetricsCollector, }; const actionResponse = await connectorType.executor(executorOptions); const { apiUrl, data, headers } = postPagerdutyMock.mock.calls[0][0]; @@ -849,7 +849,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, - connectorMetricsService, + connectorMetricsCollector, }; const actionResponse = await connectorType.executor(executorOptions); const { apiUrl, data, headers } = postPagerdutyMock.mock.calls[0][0]; @@ -915,7 +915,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, - connectorMetricsService, + connectorMetricsCollector, }; const actionResponse = await connectorType.executor(executorOptions); const { apiUrl, data, headers } = postPagerdutyMock.mock.calls[0][0]; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.ts index 319f38125face..ee56b9e2d58d8 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.ts @@ -206,7 +206,7 @@ async function executor( services, configurationUtilities, logger, - connectorMetricsService, + connectorMetricsCollector, } = execOptions; const apiUrl = getPagerDutyApiUrl(config); @@ -222,7 +222,7 @@ async function executor( { apiUrl, data, headers, services }, logger, configurationUtilities, - connectorMetricsService + connectorMetricsCollector ); } catch (err) { const message = i18n.translate('xpack.stackConnectors.pagerduty.postingErrorMessage', { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/post_pagerduty.ts b/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/post_pagerduty.ts index 7754e02f3c0a3..b93cc81f74492 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/post_pagerduty.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/post_pagerduty.ts @@ -7,7 +7,7 @@ import axios, { AxiosResponse } from 'axios'; import { Logger } from '@kbn/core/server'; -import { ConnectorMetricsService, Services } from '@kbn/actions-plugin/server/types'; +import { ConnectorMetricsCollector, Services } from '@kbn/actions-plugin/server/types'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; import { request } from '@kbn/actions-plugin/server/lib/axios_utils'; @@ -23,7 +23,7 @@ export async function postPagerduty( options: PostPagerdutyOptions, logger: Logger, configurationUtilities: ActionsConfigurationUtilities, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): Promise { const { apiUrl, data, headers } = options; const axiosInstance = axios.create(); @@ -37,6 +37,6 @@ export async function postPagerduty( headers, configurationUtilities, validateStatus: () => true, - connectorMetricsService, + connectorMetricsCollector, }); } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.test.ts index fa1e591f82ebb..7a2cb567cdf8b 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.test.ts @@ -13,7 +13,7 @@ import { ResilientConnector } from './resilient'; import { actionsMock } from '@kbn/actions-plugin/server/mocks'; import { RESILIENT_CONNECTOR_ID } from './constants'; import { PushToServiceIncidentSchema } from './schema'; -import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; +import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; jest.mock('axios'); jest.mock('@kbn/actions-plugin/server/lib/axios_utils', () => { @@ -84,7 +84,7 @@ const mockIncidentUpdate = (withUpdateError = false) => { }) ); }; -let connectorMetricsService: ConnectorMetricsService; +let connectorMetricsCollector: ConnectorMetricsCollector; describe('IBM Resilient connector', () => { const connector = new ResilientConnector( @@ -109,7 +109,7 @@ describe('IBM Resilient connector', () => { beforeEach(() => { jest.resetAllMocks(); jest.setSystemTime(TIMESTAMP); - connectorMetricsService = new ConnectorMetricsService(); + connectorMetricsCollector = new ConnectorMetricsCollector(); }); describe('getIncident', () => { @@ -132,12 +132,12 @@ describe('IBM Resilient connector', () => { }); it('returns the incident correctly', async () => { - const res = await connector.getIncident({ id: '1' }, connectorMetricsService); + const res = await connector.getIncident({ id: '1' }, connectorMetricsCollector); expect(res).toEqual(incidentMock); }); it('should call request with correct arguments', async () => { - await connector.getIncident({ id: '1' }, connectorMetricsService); + await connector.getIncident({ id: '1' }, connectorMetricsCollector); expect(requestMock).toHaveBeenCalledWith({ ...ignoredRequestFields, method: 'GET', @@ -150,7 +150,7 @@ describe('IBM Resilient connector', () => { params: { text_content_output_format: 'objects_convert', }, - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -158,7 +158,7 @@ describe('IBM Resilient connector', () => { requestMock.mockImplementation(() => { throw new Error('An error has occurred'); }); - await expect(connector.getIncident({ id: '1' }, connectorMetricsService)).rejects.toThrow( + await expect(connector.getIncident({ id: '1' }, connectorMetricsCollector)).rejects.toThrow( 'Unable to get incident with id 1. Error: An error has occurred' ); }); @@ -187,7 +187,7 @@ describe('IBM Resilient connector', () => { }); it('creates the incident correctly', async () => { - const res = await connector.createIncident(incidentMock, connectorMetricsService); + const res = await connector.createIncident(incidentMock, connectorMetricsCollector); expect(res).toEqual({ title: '1', @@ -198,7 +198,7 @@ describe('IBM Resilient connector', () => { }); it('should call request with correct arguments', async () => { - await connector.createIncident(incidentMock, connectorMetricsService); + await connector.createIncident(incidentMock, connectorMetricsCollector); expect(requestMock).toHaveBeenCalledWith({ ...ignoredRequestFields, @@ -218,7 +218,7 @@ describe('IBM Resilient connector', () => { Authorization: `Basic ${token}`, 'Content-Type': 'application/json', }, - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -235,7 +235,7 @@ describe('IBM Resilient connector', () => { incidentTypes: [1001], severityCode: 6, }, - connectorMetricsService + connectorMetricsCollector ) ).rejects.toThrow( '[Action][IBM Resilient]: Unable to create incident. Error: An error has occurred' @@ -245,7 +245,9 @@ describe('IBM Resilient connector', () => { it('should throw if the required attributes are not received in response', async () => { requestMock.mockImplementation(() => createAxiosResponse({ data: { notRequired: 'test' } })); - await expect(connector.createIncident(incidentMock, connectorMetricsService)).rejects.toThrow( + await expect( + connector.createIncident(incidentMock, connectorMetricsCollector) + ).rejects.toThrow( '[Action][IBM Resilient]: Unable to create incident. Error: Response validation failed (Error: [id]: expected value of type [number] but got [undefined]).' ); }); @@ -263,7 +265,7 @@ describe('IBM Resilient connector', () => { }; it('updates the incident correctly', async () => { mockIncidentUpdate(); - const res = await connector.updateIncident(req, connectorMetricsService); + const res = await connector.updateIncident(req, connectorMetricsCollector); expect(res).toEqual({ title: '1', @@ -286,7 +288,7 @@ describe('IBM Resilient connector', () => { severityCode: 5, }, }, - connectorMetricsService + connectorMetricsCollector ); expect(requestMock.mock.calls[1][0]).toEqual({ @@ -343,14 +345,14 @@ describe('IBM Resilient connector', () => { }, ], }, - connectorMetricsService, + connectorMetricsCollector, }); }); it('it should throw an error', async () => { mockIncidentUpdate(true); - await expect(connector.updateIncident(req, connectorMetricsService)).rejects.toThrow( + await expect(connector.updateIncident(req, connectorMetricsCollector)).rejects.toThrow( '[Action][IBM Resilient]: Unable to update incident with id 1. Error: An error has occurred' ); }); @@ -373,7 +375,7 @@ describe('IBM Resilient connector', () => { ); requestMock.mockImplementation(() => createAxiosResponse({ data: { notRequired: 'test' } })); - await expect(connector.updateIncident(req, connectorMetricsService)).rejects.toThrow( + await expect(connector.updateIncident(req, connectorMetricsCollector)).rejects.toThrow( '[Action][IBM Resilient]: Unable to update incident with id 1. Error: Response validation failed (Error: [success]: expected value of type [boolean] but got [undefined]).' ); }); @@ -400,7 +402,7 @@ describe('IBM Resilient connector', () => { }); it('should call request with correct arguments', async () => { - await connector.addComment(req, connectorMetricsService); + await connector.addComment(req, connectorMetricsCollector); expect(requestMock).toHaveBeenCalledWith({ ...ignoredRequestFields, @@ -416,7 +418,7 @@ describe('IBM Resilient connector', () => { format: 'text', }, }, - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -425,7 +427,7 @@ describe('IBM Resilient connector', () => { throw new Error('An error has occurred'); }); - await expect(connector.addComment(req, connectorMetricsService)).rejects.toThrow( + await expect(connector.addComment(req, connectorMetricsCollector)).rejects.toThrow( '[Action][IBM Resilient]: Unable to create comment at incident with id 1. Error: An error has occurred.' ); }); @@ -441,7 +443,7 @@ describe('IBM Resilient connector', () => { }); it('should call request with correct arguments', async () => { - await connector.getIncidentTypes(undefined, connectorMetricsService); + await connector.getIncidentTypes(undefined, connectorMetricsCollector); expect(requestMock).toBeCalledTimes(1); expect(requestMock).toHaveBeenCalledWith({ ...ignoredRequestFields, @@ -452,12 +454,12 @@ describe('IBM Resilient connector', () => { Authorization: `Basic ${token}`, 'Content-Type': 'application/json', }, - connectorMetricsService, + connectorMetricsCollector, }); }); it('returns incident types correctly', async () => { - const res = await connector.getIncidentTypes(undefined, connectorMetricsService); + const res = await connector.getIncidentTypes(undefined, connectorMetricsCollector); expect(res).toEqual([ { id: '17', name: 'Communication error (fax; email)' }, @@ -470,7 +472,9 @@ describe('IBM Resilient connector', () => { throw new Error('An error has occurred'); }); - await expect(connector.getIncidentTypes(undefined, connectorMetricsService)).rejects.toThrow( + await expect( + connector.getIncidentTypes(undefined, connectorMetricsCollector) + ).rejects.toThrow( '[Action][IBM Resilient]: Unable to get incident types. Error: An error has occurred.' ); }); @@ -480,7 +484,9 @@ describe('IBM Resilient connector', () => { createAxiosResponse({ data: { id: '1001', name: 'Custom type' } }) ); - await expect(connector.getIncidentTypes(undefined, connectorMetricsService)).rejects.toThrow( + await expect( + connector.getIncidentTypes(undefined, connectorMetricsCollector) + ).rejects.toThrow( '[Action][IBM Resilient]: Unable to get incident types. Error: Response validation failed (Error: [values]: expected value of type [array] but got [undefined]).' ); }); @@ -498,7 +504,7 @@ describe('IBM Resilient connector', () => { }); it('should call request with correct arguments', async () => { - await connector.getSeverity(undefined, connectorMetricsService); + await connector.getSeverity(undefined, connectorMetricsCollector); expect(requestMock).toBeCalledTimes(1); expect(requestMock).toHaveBeenCalledWith({ ...ignoredRequestFields, @@ -509,12 +515,12 @@ describe('IBM Resilient connector', () => { Authorization: `Basic ${token}`, 'Content-Type': 'application/json', }, - connectorMetricsService, + connectorMetricsCollector, }); }); it('returns severity correctly', async () => { - const res = await connector.getSeverity(undefined, connectorMetricsService); + const res = await connector.getSeverity(undefined, connectorMetricsCollector); expect(res).toEqual([ { @@ -537,7 +543,7 @@ describe('IBM Resilient connector', () => { throw new Error('An error has occurred'); }); - await expect(connector.getSeverity(undefined, connectorMetricsService)).rejects.toThrow( + await expect(connector.getSeverity(undefined, connectorMetricsCollector)).rejects.toThrow( '[Action][IBM Resilient]: Unable to get severity. Error: An error has occurred.' ); }); @@ -547,7 +553,7 @@ describe('IBM Resilient connector', () => { createAxiosResponse({ data: { id: '10', name: 'Critical' } }) ); - await expect(connector.getSeverity(undefined, connectorMetricsService)).rejects.toThrow( + await expect(connector.getSeverity(undefined, connectorMetricsCollector)).rejects.toThrow( '[Action][IBM Resilient]: Unable to get severity. Error: Response validation failed (Error: [values]: expected value of type [array] but got [undefined]).' ); }); @@ -562,7 +568,7 @@ describe('IBM Resilient connector', () => { ); }); it('should call request with correct arguments', async () => { - await connector.getFields(undefined, connectorMetricsService); + await connector.getFields(undefined, connectorMetricsCollector); expect(requestMock).toBeCalledTimes(1); expect(requestMock).toHaveBeenCalledWith({ @@ -574,12 +580,12 @@ describe('IBM Resilient connector', () => { Authorization: `Basic ${token}`, 'Content-Type': 'application/json', }, - connectorMetricsService, + connectorMetricsCollector, }); }); it('returns common fields correctly', async () => { - const res = await connector.getFields(undefined, connectorMetricsService); + const res = await connector.getFields(undefined, connectorMetricsCollector); expect(res).toEqual(resilientFields); }); @@ -587,7 +593,7 @@ describe('IBM Resilient connector', () => { requestMock.mockImplementation(() => { throw new Error('An error has occurred'); }); - await expect(connector.getFields(undefined, connectorMetricsService)).rejects.toThrow( + await expect(connector.getFields(undefined, connectorMetricsCollector)).rejects.toThrow( 'Unable to get fields. Error: An error has occurred' ); }); @@ -595,7 +601,7 @@ describe('IBM Resilient connector', () => { it('should throw if the required attributes are not received in response', async () => { requestMock.mockImplementation(() => createAxiosResponse({ data: { someField: 'test' } })); - await expect(connector.getFields(undefined, connectorMetricsService)).rejects.toThrow( + await expect(connector.getFields(undefined, connectorMetricsCollector)).rejects.toThrow( '[Action][IBM Resilient]: Unable to get fields. Error: Response validation failed (Error: expected value of type [array] but got [Object]).' ); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.ts b/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.ts index bd7c47619c7a4..6a5b9f36a20ea 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.ts @@ -10,7 +10,7 @@ import { omitBy, isNil } from 'lodash/fp'; import { CaseConnector, getBasicAuthHeader, ServiceParams } from '@kbn/actions-plugin/server'; import { schema, Type } from '@kbn/config-schema'; import { getErrorMessage } from '@kbn/actions-plugin/server/lib/axios_utils'; -import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; +import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; import { CreateIncidentData, ExternalServiceIncidentResponse, @@ -120,7 +120,7 @@ export class ResilientConnector extends CaseConnector< public async createIncident( incident: Incident, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): Promise { try { let data: CreateIncidentData = { @@ -168,7 +168,7 @@ export class ResilientConnector extends CaseConnector< { unknowns: 'allow' } ), }, - connectorMetricsService + connectorMetricsCollector ); const { id, create_date: createDate } = res.data; @@ -188,10 +188,10 @@ export class ResilientConnector extends CaseConnector< public async updateIncident( { incidentId, incident }: UpdateIncidentParams, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): Promise { try { - const latestIncident = await this.getIncident({ id: incidentId }, connectorMetricsService); + const latestIncident = await this.getIncident({ id: incidentId }, connectorMetricsCollector); // Remove null or undefined values. Allowing null values sets the field in IBM Resilient to empty. const newIncident = omitBy(isNil, incident); @@ -205,14 +205,14 @@ export class ResilientConnector extends CaseConnector< headers: this.getAuthHeaders(), responseSchema: schema.object({ success: schema.boolean() }, { unknowns: 'allow' }), }, - connectorMetricsService + connectorMetricsCollector ); if (!res.data.success) { throw new Error('Error while updating incident'); } - const updatedIncident = await this.getIncident({ id: incidentId }, connectorMetricsService); + const updatedIncident = await this.getIncident({ id: incidentId }, connectorMetricsCollector); return { title: `${updatedIncident.id}`, @@ -232,7 +232,7 @@ export class ResilientConnector extends CaseConnector< public async addComment( { incidentId, comment }: { incidentId: string; comment: string }, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ) { try { await this.request( @@ -243,7 +243,7 @@ export class ResilientConnector extends CaseConnector< headers: this.getAuthHeaders(), responseSchema: schema.object({}, { unknowns: 'allow' }), }, - connectorMetricsService + connectorMetricsCollector ); } catch (error) { throw new Error( @@ -257,7 +257,7 @@ export class ResilientConnector extends CaseConnector< public async getIncident( { id }: { id: string }, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): Promise { try { const res = await this.request( @@ -270,7 +270,7 @@ export class ResilientConnector extends CaseConnector< headers: this.getAuthHeaders(), responseSchema: GetIncidentResponseSchema, }, - connectorMetricsService + connectorMetricsCollector ); return res.data; @@ -283,7 +283,7 @@ export class ResilientConnector extends CaseConnector< public async getIncidentTypes( params: unknown, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): Promise { try { const res = await this.request( @@ -293,7 +293,7 @@ export class ResilientConnector extends CaseConnector< headers: this.getAuthHeaders(), responseSchema: GetIncidentTypesResponseSchema, }, - connectorMetricsService + connectorMetricsCollector ); const incidentTypes = res.data?.values ?? []; @@ -311,7 +311,7 @@ export class ResilientConnector extends CaseConnector< public async getSeverity( params: unknown, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): Promise { try { const res = await this.request( @@ -321,7 +321,7 @@ export class ResilientConnector extends CaseConnector< headers: this.getAuthHeaders(), responseSchema: GetSeverityResponseSchema, }, - connectorMetricsService + connectorMetricsCollector ); const severities = res.data?.values ?? []; @@ -336,7 +336,7 @@ export class ResilientConnector extends CaseConnector< } } - public async getFields(params: unknown, connectorMetricsService: ConnectorMetricsService) { + public async getFields(params: unknown, connectorMetricsCollector: ConnectorMetricsCollector) { try { const res = await this.request( { @@ -345,7 +345,7 @@ export class ResilientConnector extends CaseConnector< headers: this.getAuthHeaders(), responseSchema: GetCommonFieldsResponseSchema, }, - connectorMetricsService + connectorMetricsCollector ); const fields = res.data.map((field) => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.test.ts index 1cf6104a7c008..80bd1fcb9a816 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.test.ts @@ -13,15 +13,15 @@ import { } from '../../../common/sentinelone/types'; import { API_PATH } from './sentinelone'; import { SentinelOneGetActivitiesResponseSchema } from '../../../common/sentinelone/schema'; -import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; +import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; describe('SentinelOne Connector', () => { let connectorInstance: ReturnType; - let connectorMetricsService: ConnectorMetricsService; + let connectorMetricsCollector: ConnectorMetricsCollector; beforeEach(() => { connectorInstance = sentinelOneConnectorMocks.create(); - connectorMetricsService = new ConnectorMetricsService(); + connectorMetricsCollector = new ConnectorMetricsCollector(); }); describe('#fetchAgentFiles()', () => { @@ -39,7 +39,7 @@ describe('SentinelOne Connector', () => { connectorInstance.mockResponses.getAgentsApiResponse.data.length = 0; await expect( - connectorInstance.fetchAgentFiles(fetchAgentFilesParams, connectorMetricsService) + connectorInstance.fetchAgentFiles(fetchAgentFilesParams, connectorMetricsCollector) ).rejects.toHaveProperty('message', 'No agent found in SentinelOne for UUID [uuid-1]'); }); @@ -47,7 +47,7 @@ describe('SentinelOne Connector', () => { const fetchFilesUrl = `${connectorInstance.constructorParams.config.url}${API_PATH}/agents/1913920934584665209/actions/fetch-files`; const response = await connectorInstance.fetchAgentFiles( fetchAgentFilesParams, - connectorMetricsService + connectorMetricsCollector ); expect(response).toEqual({ data: { success: true }, errors: null }); @@ -82,13 +82,13 @@ describe('SentinelOne Connector', () => { connectorInstance.mockResponses.getAgentsApiResponse.data.length = 0; await expect( - connectorInstance.downloadAgentFile(downloadAgentFileParams, connectorMetricsService) + connectorInstance.downloadAgentFile(downloadAgentFileParams, connectorMetricsCollector) ).rejects.toHaveProperty('message', 'No agent found in SentinelOne for UUID [uuid-1]'); }); it('should call SentinelOne api with expected url', async () => { await expect( - connectorInstance.downloadAgentFile(downloadAgentFileParams, connectorMetricsService) + connectorInstance.downloadAgentFile(downloadAgentFileParams, connectorMetricsCollector) ).resolves.toEqual(connectorInstance.mockResponses.downloadAgentFileApiResponse); }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.ts b/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.ts index 68f2527889163..ad04ca7930eb7 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.ts @@ -8,7 +8,7 @@ import { ServiceParams, SubActionConnector } from '@kbn/actions-plugin/server'; import type { AxiosError } from 'axios'; import { SubActionRequestParams } from '@kbn/actions-plugin/server/sub_action_framework/types'; -import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; +import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; import type { SentinelOneConfig, SentinelOneSecrets, @@ -137,9 +137,9 @@ export class SentinelOneConnector extends SubActionConnector< public async fetchAgentFiles( { files, agentUUID, zipPassCode }: SentinelOneFetchAgentFilesParams, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ) { - const agent = await this.getAgents({ uuid: agentUUID }, connectorMetricsService); + const agent = await this.getAgents({ uuid: agentUUID }, connectorMetricsCollector); const agentId = agent.data[0]?.id; if (!agentId) { @@ -158,15 +158,15 @@ export class SentinelOneConnector extends SubActionConnector< }, responseSchema: SentinelOneFetchAgentFilesResponseSchema, }, - connectorMetricsService + connectorMetricsCollector ); } public async downloadAgentFile( { agentUUID, activityId }: SentinelOneDownloadAgentFileParams, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ) { - const agent = await this.getAgents({ uuid: agentUUID }, connectorMetricsService); + const agent = await this.getAgents({ uuid: agentUUID }, connectorMetricsCollector); const agentId = agent.data[0]?.id; if (!agentId) { @@ -180,13 +180,13 @@ export class SentinelOneConnector extends SubActionConnector< responseType: 'stream', responseSchema: SentinelOneDownloadAgentFileResponseSchema, }, - connectorMetricsService + connectorMetricsCollector ); } public async getActivities( queryParams?: SentinelOneGetActivitiesParams, - connectorMetricsService?: ConnectorMetricsService + connectorMetricsCollector?: ConnectorMetricsCollector ) { return this.sentinelOneApiRequest( { @@ -195,13 +195,13 @@ export class SentinelOneConnector extends SubActionConnector< params: queryParams, responseSchema: SentinelOneGetActivitiesResponseSchema, }, - connectorMetricsService! + connectorMetricsCollector! ); } public async executeScript( { filter, script }: SentinelOneExecuteScriptParams, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ) { if (!filter.ids && !filter.uuids) { throw new Error(`A filter must be defined; either 'ids' or 'uuids'`); @@ -220,15 +220,15 @@ export class SentinelOneConnector extends SubActionConnector< }, responseSchema: SentinelOneExecuteScriptResponseSchema, }, - connectorMetricsService + connectorMetricsCollector ); } public async isolateHost( { alertIds, ...payload }: SentinelOneIsolateHostParams, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ) { - const response = await this.getAgents(payload, connectorMetricsService); + const response = await this.getAgents(payload, connectorMetricsCollector); if (response.data.length === 0) { const errorMessage = 'No agents found'; @@ -255,15 +255,15 @@ export class SentinelOneConnector extends SubActionConnector< }, responseSchema: SentinelOneIsolateHostResponseSchema, }, - connectorMetricsService + connectorMetricsCollector ); } public async releaseHost( { alertIds, ...payload }: SentinelOneIsolateHostParams, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ) { - const response = await this.getAgents(payload, connectorMetricsService); + const response = await this.getAgents(payload, connectorMetricsCollector); if (response.data.length === 0) { throw new Error('No agents found'); @@ -286,13 +286,13 @@ export class SentinelOneConnector extends SubActionConnector< }, responseSchema: SentinelOneIsolateHostResponseSchema, }, - connectorMetricsService + connectorMetricsCollector ); } public async getAgents( payload: SentinelOneGetAgentsParams, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): Promise { return this.sentinelOneApiRequest( { @@ -302,13 +302,13 @@ export class SentinelOneConnector extends SubActionConnector< }, responseSchema: SentinelOneGetAgentsResponseSchema, }, - connectorMetricsService + connectorMetricsCollector ); } public async getRemoteScriptStatus( payload: SentinelOneGetRemoteScriptStatusParams, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ) { return this.sentinelOneApiRequest( { @@ -318,13 +318,13 @@ export class SentinelOneConnector extends SubActionConnector< }, responseSchema: SentinelOneGetRemoteScriptStatusResponseSchema, }, - connectorMetricsService + connectorMetricsCollector ); } private async sentinelOneApiRequest( req: SubActionRequestParams, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): Promise { const response = await this.request( { @@ -334,7 +334,7 @@ export class SentinelOneConnector extends SubActionConnector< APIToken: this.secrets.token, }, }, - connectorMetricsService + connectorMetricsCollector ); return response.data; @@ -364,7 +364,7 @@ export class SentinelOneConnector extends SubActionConnector< public async getRemoteScripts( payload: SentinelOneGetRemoteScriptsParams, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): Promise { return this.sentinelOneApiRequest( { @@ -375,7 +375,7 @@ export class SentinelOneConnector extends SubActionConnector< }, responseSchema: SentinelOneGetRemoteScriptsResponseSchema, }, - connectorMetricsService + connectorMetricsCollector ); } } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/server_log/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/server_log/index.test.ts index 082098023fc3f..fd819854b1ccb 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/server_log/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/server_log/index.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { validateParams } from '@kbn/actions-plugin/server/lib'; +import { ConnectorMetricsCollector, validateParams } from '@kbn/actions-plugin/server/lib'; import { Logger } from '@kbn/core/server'; import { actionsMock } from '@kbn/actions-plugin/server/mocks'; import { getConnectorType, ServerLogConnectorType, ServerLogConnectorTypeExecutorOptions } from '.'; @@ -107,6 +107,7 @@ describe('execute()', () => { secrets: {}, configurationUtilities, logger: mockedLogger, + connectorMetricsCollector: new ConnectorMetricsCollector(), }; await connectorType.executor(executorOptions); expect(mockedLogger.info).toHaveBeenCalledWith('Server log: message text here'); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/index.ts index c456f4f6b5a1b..236589545dd36 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/index.ts @@ -109,7 +109,7 @@ async function executorITOM( secrets, configurationUtilities, logger, - connectorMetricsService, + connectorMetricsCollector, } = execOptions; const { subAction, subActionParams } = params; const connectorTokenClient = execOptions.services.connectorTokenClient; @@ -127,7 +127,7 @@ async function executorITOM( serviceConfig: externalServiceConfig, connectorTokenClient, createServiceFn: createService, - connectorMetricsService, + connectorMetricsCollector, }); const apiAsRecord = api as unknown as Record; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.test.ts index b77206888ee62..2dafe4f83be60 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.test.ts @@ -15,7 +15,7 @@ import { loggingSystemMock } from '@kbn/core/server/mocks'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { snExternalServiceConfig } from '../lib/servicenow/config'; import { itomEventParams, serviceNowChoices } from '../lib/servicenow/mocks'; -import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; +import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; const logger = loggingSystemMock.create().get() as jest.Mocked; @@ -34,10 +34,10 @@ const configurationUtilities = actionsConfigMock.create(); describe('ServiceNow SIR service', () => { let service: ExternalServiceITOM; - let connectorMetricsService: ConnectorMetricsService; + let connectorMetricsCollector: ConnectorMetricsCollector; beforeEach(() => { - connectorMetricsService = new ConnectorMetricsService(); + connectorMetricsCollector = new ConnectorMetricsCollector(); service = createExternalService({ credentials: { config: { apiUrl: 'https://example.com/', isOAuth: false }, @@ -47,7 +47,7 @@ describe('ServiceNow SIR service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow-itom'], axiosInstance: axios, - connectorMetricsService, + connectorMetricsCollector, }) as ExternalServiceITOM; }); @@ -73,7 +73,7 @@ describe('ServiceNow SIR service', () => { url: 'https://example.com/api/global/em/jsonv2', method: 'post', data: { records: [itomEventParams] }, - connectorMetricsService, + connectorMetricsCollector, }); }); }); @@ -90,7 +90,7 @@ describe('ServiceNow SIR service', () => { logger, configurationUtilities, url: 'https://example.com/api/now/table/sys_choice?sysparm_query=name=task^ORname=em_event^element=severity^language=en&sysparm_fields=label,value,dependent_value,element', - connectorMetricsService, + connectorMetricsCollector, }); }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.ts index 7215e1cf638ca..ba99737c4f75d 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.ts @@ -23,7 +23,7 @@ export const createExternalService: ServiceFactory = ({ configurationUtilities, serviceConfig, axiosInstance, - connectorMetricsService, + connectorMetricsCollector, }): ExternalServiceITOM => { const snService = createExternalServiceCommon({ credentials, @@ -31,7 +31,7 @@ export const createExternalService: ServiceFactory = ({ configurationUtilities, serviceConfig, axiosInstance, - connectorMetricsService, + connectorMetricsCollector, }); const addEvent = async (params: ExecutorSubActionAddEventParams) => { @@ -43,7 +43,7 @@ export const createExternalService: ServiceFactory = ({ method: 'post', data: { records: [params] }, configurationUtilities, - connectorMetricsService, + connectorMetricsCollector, }); snService.checkInstance(res); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/index.ts index d58dff262d0a1..4e20e027a2481 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/index.ts @@ -133,7 +133,7 @@ async function executor( services, configurationUtilities, logger, - connectorMetricsService, + connectorMetricsCollector, } = execOptions; const { subAction, subActionParams } = params; const connectorTokenClient = services.connectorTokenClient; @@ -151,7 +151,7 @@ async function executor( serviceConfig: externalServiceConfig, connectorTokenClient, createServiceFn: createService, - connectorMetricsService, + connectorMetricsCollector, }); const apiAsRecord = api as unknown as Record; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/service.test.ts index 9fb52bab57a7d..8bc567dde9bc5 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/service.test.ts @@ -15,7 +15,7 @@ import { loggingSystemMock } from '@kbn/core/server/mocks'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { serviceNowCommonFields, serviceNowChoices } from '../lib/servicenow/mocks'; import { snExternalServiceConfig } from '../lib/servicenow/config'; -import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; +import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; const logger = loggingSystemMock.create().get() as jest.Mocked; jest.mock('axios', () => ({ @@ -123,7 +123,7 @@ const expectImportedIncident = (update: boolean) => { configurationUtilities, url: 'https://example.com/api/x_elas2_inc_int/elastic_api/health', method: 'get', - connectorMetricsService: expect.any(ConnectorMetricsService), + connectorMetricsCollector: expect.any(ConnectorMetricsCollector), }); expect(requestMock).toHaveBeenNthCalledWith(2, { @@ -137,7 +137,7 @@ const expectImportedIncident = (update: boolean) => { u_description: 'desc', ...(update ? { elastic_incident_id: '1' } : {}), }, - connectorMetricsService: expect.any(ConnectorMetricsService), + connectorMetricsCollector: expect.any(ConnectorMetricsCollector), }); expect(requestMock).toHaveBeenNthCalledWith(3, { @@ -146,17 +146,17 @@ const expectImportedIncident = (update: boolean) => { configurationUtilities, url: 'https://example.com/api/now/v2/table/incident/1', method: 'get', - connectorMetricsService: expect.any(ConnectorMetricsService), + connectorMetricsCollector: expect.any(ConnectorMetricsCollector), }); }; describe('ServiceNow service', () => { let service: ExternalService; - let connectorMetricsService: ConnectorMetricsService; + let connectorMetricsCollector: ConnectorMetricsCollector; beforeEach(() => { jest.clearAllMocks(); - connectorMetricsService = new ConnectorMetricsService(); + connectorMetricsCollector = new ConnectorMetricsCollector(); service = createExternalService({ credentials: { // The trailing slash at the end of the url is intended. @@ -168,7 +168,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow'], axiosInstance: axios, - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -184,7 +184,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow'], axiosInstance: axios, - connectorMetricsService, + connectorMetricsCollector, }) ).toThrow(); }); @@ -225,7 +225,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow'], axiosInstance: axios, - connectorMetricsService, + connectorMetricsCollector, }) ).toThrow(); }); @@ -390,7 +390,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow'], axiosInstance: axios, - connectorMetricsService, + connectorMetricsCollector, }) ).toThrow(); }); @@ -418,7 +418,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/incident/1', method: 'get', - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -432,7 +432,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], table: 'sn_si_incident' }, axiosInstance: axios, - connectorMetricsService, + connectorMetricsCollector, }); requestMock.mockImplementation(() => ({ @@ -446,7 +446,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/sn_si_incident/1', method: 'get', - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -500,7 +500,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow-sir'], axiosInstance: axios, - connectorMetricsService, + connectorMetricsCollector, }); const res = await createIncident(service); @@ -511,7 +511,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/x_elas2_sir_int/elastic_api/health', method: 'get', - connectorMetricsService, + connectorMetricsCollector, }); expect(requestMock).toHaveBeenNthCalledWith(2, { @@ -521,7 +521,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/import/x_elas2_sir_int_elastic_si_incident', method: 'post', data: { u_short_description: 'title', u_description: 'desc' }, - connectorMetricsService, + connectorMetricsCollector, }); expect(requestMock).toHaveBeenNthCalledWith(3, { @@ -530,7 +530,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/sn_si_incident/1', method: 'get', - connectorMetricsService, + connectorMetricsCollector, }); expect(res.url).toEqual('https://example.com/nav_to.do?uri=sn_si_incident.do?sys_id=1'); @@ -589,7 +589,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], useImportAPI: false }, axiosInstance: axios, - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -614,7 +614,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/v2/table/incident', method: 'post', data: { short_description: 'title', description: 'desc' }, - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -628,7 +628,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow-sir'], useImportAPI: false }, axiosInstance: axios, - connectorMetricsService, + connectorMetricsCollector, }); mockIncidentResponse(false); @@ -644,7 +644,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/v2/table/sn_si_incident', method: 'post', data: { short_description: 'title', description: 'desc' }, - connectorMetricsService, + connectorMetricsCollector, }); expect(res.url).toEqual('https://example.com/nav_to.do?uri=sn_si_incident.do?sys_id=1'); @@ -681,7 +681,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow-sir'], axiosInstance: axios, - connectorMetricsService, + connectorMetricsCollector, }); const res = await updateIncident(service); @@ -691,7 +691,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/x_elas2_sir_int/elastic_api/health', method: 'get', - connectorMetricsService, + connectorMetricsCollector, }); expect(requestMock).toHaveBeenNthCalledWith(2, { @@ -701,7 +701,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/import/x_elas2_sir_int_elastic_si_incident', method: 'post', data: { u_short_description: 'title', u_description: 'desc', elastic_incident_id: '1' }, - connectorMetricsService, + connectorMetricsCollector, }); expect(requestMock).toHaveBeenNthCalledWith(3, { @@ -710,7 +710,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/sn_si_incident/1', method: 'get', - connectorMetricsService, + connectorMetricsCollector, }); expect(res.url).toEqual('https://example.com/nav_to.do?uri=sn_si_incident.do?sys_id=1'); @@ -772,7 +772,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], useImportAPI: false }, axiosInstance: axios, - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -798,7 +798,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/v2/table/incident/1', method: 'patch', data: { short_description: 'title', description: 'desc' }, - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -812,7 +812,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow-sir'], useImportAPI: false }, axiosInstance: axios, - connectorMetricsService, + connectorMetricsCollector, }); mockIncidentResponse(false); @@ -829,7 +829,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/v2/table/sn_si_incident/1', method: 'patch', data: { short_description: 'title', description: 'desc' }, - connectorMetricsService, + connectorMetricsCollector, }); expect(res.url).toEqual('https://example.com/nav_to.do?uri=sn_si_incident.do?sys_id=1'); @@ -849,7 +849,7 @@ describe('ServiceNow service', () => { logger, configurationUtilities, url: 'https://example.com/api/now/table/sys_dictionary?sysparm_query=name=task^ORname=incident^internal_type=string&active=true&array=false&read_only=false&sysparm_fields=max_length,element,column_label,mandatory', - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -871,7 +871,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], table: 'sn_si_incident' }, axiosInstance: axios, - connectorMetricsService, + connectorMetricsCollector, }); requestMock.mockImplementation(() => ({ @@ -884,7 +884,7 @@ describe('ServiceNow service', () => { logger, configurationUtilities, url: 'https://example.com/api/now/table/sys_dictionary?sysparm_query=name=task^ORname=sn_si_incident^internal_type=string&active=true&array=false&read_only=false&sysparm_fields=max_length,element,column_label,mandatory', - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -921,7 +921,7 @@ describe('ServiceNow service', () => { logger, configurationUtilities, url: 'https://example.com/api/now/table/sys_choice?sysparm_query=name=task^ORname=incident^element=priority^ORelement=category^language=en&sysparm_fields=label,value,dependent_value,element', - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -943,7 +943,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], table: 'sn_si_incident' }, axiosInstance: axios, - connectorMetricsService, + connectorMetricsCollector, }); requestMock.mockImplementation(() => ({ @@ -957,7 +957,7 @@ describe('ServiceNow service', () => { logger, configurationUtilities, url: 'https://example.com/api/now/table/sys_choice?sysparm_query=name=task^ORname=sn_si_incident^element=priority^ORelement=category^language=en&sysparm_fields=label,value,dependent_value,element', - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -1050,7 +1050,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], useImportAPI: false }, axiosInstance: axios, - connectorMetricsService, + connectorMetricsCollector, }); await service.checkIfApplicationIsInstalled(); expect(requestMock).not.toHaveBeenCalled(); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/index.ts index f48e87280f2d3..c880848d0667c 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/index.ts @@ -124,7 +124,7 @@ async function executor( services, configurationUtilities, logger, - connectorMetricsService, + connectorMetricsCollector, } = execOptions; const { subAction, subActionParams } = params; const connectorTokenClient = services.connectorTokenClient; @@ -142,7 +142,7 @@ async function executor( serviceConfig: externalServiceConfig, connectorTokenClient, createServiceFn: createService, - connectorMetricsService, + connectorMetricsCollector, }); const apiAsRecord = api as unknown as Record; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.test.ts index eaf0a91f02a03..cb590d85f6298 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.test.ts @@ -15,7 +15,7 @@ import { loggingSystemMock } from '@kbn/core/server/mocks'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { observables } from '../lib/servicenow/mocks'; import { snExternalServiceConfig } from '../lib/servicenow/config'; -import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; +import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; const logger = loggingSystemMock.create().get() as jest.Mocked; @@ -32,7 +32,7 @@ jest.mock('@kbn/actions-plugin/server/lib/axios_utils', () => { axios.create = jest.fn(() => axios); const requestMock = utils.request as jest.Mock; const configurationUtilities = actionsConfigMock.create(); -let connectorMetricsService: ConnectorMetricsService; +let connectorMetricsCollector: ConnectorMetricsCollector; const mockApplicationVersion = () => requestMock.mockImplementationOnce(() => ({ @@ -72,7 +72,7 @@ const expectAddObservables = (single: boolean) => { configurationUtilities, url: 'https://example.com/api/x_elas2_sir_int/elastic_api/health', method: 'get', - connectorMetricsService: expect.any(ConnectorMetricsService), + connectorMetricsCollector: expect.any(ConnectorMetricsCollector), }); const url = single @@ -88,7 +88,7 @@ const expectAddObservables = (single: boolean) => { url, method: 'post', data, - connectorMetricsService: expect.any(ConnectorMetricsService), + connectorMetricsCollector: expect.any(ConnectorMetricsCollector), }); }; @@ -96,7 +96,7 @@ describe('ServiceNow SIR service', () => { let service: ExternalServiceSIR; beforeEach(() => { - connectorMetricsService = new ConnectorMetricsService(); + connectorMetricsCollector = new ConnectorMetricsCollector(); service = createExternalService({ credentials: { config: { apiUrl: 'https://example.com/', isOAuth: false }, @@ -106,7 +106,7 @@ describe('ServiceNow SIR service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow-sir'], axiosInstance: axios, - connectorMetricsService, + connectorMetricsCollector, }) as ExternalServiceSIR; }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.ts index 80c37c6ab9a81..b8ba4826d6838 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.ts @@ -28,7 +28,7 @@ export const createExternalService: ServiceFactory = ({ configurationUtilities, serviceConfig, axiosInstance, - connectorMetricsService, + connectorMetricsCollector, }): ExternalServiceSIR => { const snService = createExternalServiceCommon({ credentials, @@ -36,7 +36,7 @@ export const createExternalService: ServiceFactory = ({ configurationUtilities, serviceConfig, axiosInstance, - connectorMetricsService, + connectorMetricsCollector, }); const _addObservable = async (data: Observable | Observable[], url: string) => { @@ -49,7 +49,7 @@ export const createExternalService: ServiceFactory = ({ method: 'post', data, configurationUtilities, - connectorMetricsService, + connectorMetricsCollector, }); snService.checkInstance(res); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack/index.test.ts index 154603acfb45c..aa08139915739 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack/index.test.ts @@ -9,7 +9,7 @@ import { Logger } from '@kbn/core/server'; import { Services, ActionTypeExecutorResult as ConnectorTypeExecutorResult, - ConnectorMetricsService, + ConnectorMetricsCollector, } from '@kbn/actions-plugin/server/types'; import { validateParams, validateSecrets } from '@kbn/actions-plugin/server/lib'; import { @@ -36,7 +36,7 @@ const mockedLogger: jest.Mocked = loggerMock.create(); let connectorType: SlackConnectorType; let configurationUtilities: jest.Mocked; -let connectorMetricsService: ConnectorMetricsService; +let connectorMetricsCollector: ConnectorMetricsCollector; beforeEach(() => { configurationUtilities = actionsConfigMock.create(); @@ -45,7 +45,7 @@ beforeEach(() => { return { status: 'ok', actionId: options.actionId }; }, }); - connectorMetricsService = new ConnectorMetricsService(); + connectorMetricsCollector = new ConnectorMetricsCollector(); }); describe('connector registration', () => { @@ -184,7 +184,7 @@ describe('execute()', () => { params: { message: 'this invocation should succeed' }, configurationUtilities, logger: mockedLogger, - connectorMetricsService, + connectorMetricsCollector, }); expect(response).toMatchInlineSnapshot(` Object { @@ -205,7 +205,7 @@ describe('execute()', () => { params: { message: 'failure: this invocation should fail' }, configurationUtilities, logger: mockedLogger, - connectorMetricsService, + connectorMetricsCollector, }) ).rejects.toThrowErrorMatchingInlineSnapshot( `"slack mockExecutor failure: this invocation should fail"` @@ -231,7 +231,7 @@ describe('execute()', () => { params: { message: 'this invocation should succeed' }, configurationUtilities: configUtils, logger: mockedLogger, - connectorMetricsService, + connectorMetricsCollector, }); expect(mockedLogger.debug).toHaveBeenCalledWith( 'IncomingWebhook was called with proxyUrl https://someproxyhost' @@ -258,7 +258,7 @@ describe('execute()', () => { params: { message: 'this invocation should succeed' }, configurationUtilities: configUtils, logger: mockedLogger, - connectorMetricsService, + connectorMetricsCollector, }); expect(mockedLogger.debug).not.toHaveBeenCalledWith( 'IncomingWebhook was called with proxyUrl https://someproxyhost' @@ -285,7 +285,7 @@ describe('execute()', () => { params: { message: 'this invocation should succeed' }, configurationUtilities: configUtils, logger: mockedLogger, - connectorMetricsService, + connectorMetricsCollector, }); expect(mockedLogger.debug).toHaveBeenCalledWith( 'IncomingWebhook was called with proxyUrl https://someproxyhost' @@ -312,7 +312,7 @@ describe('execute()', () => { params: { message: 'this invocation should succeed' }, configurationUtilities: configUtils, logger: mockedLogger, - connectorMetricsService, + connectorMetricsCollector, }); expect(mockedLogger.debug).toHaveBeenCalledWith( 'IncomingWebhook was called with proxyUrl https://someproxyhost' @@ -339,7 +339,7 @@ describe('execute()', () => { params: { message: 'this invocation should succeed' }, configurationUtilities: configUtils, logger: mockedLogger, - connectorMetricsService, + connectorMetricsCollector, }); expect(mockedLogger.debug).not.toHaveBeenCalledWith( 'IncomingWebhook was called with proxyUrl https://someproxyhost' diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack/index.ts index fd76e736e4ef3..173f309072bb5 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack/index.ts @@ -139,7 +139,7 @@ function validateConnectorTypeConfig( async function slackExecutor( execOptions: SlackConnectorTypeExecutorOptions ): Promise> { - const { actionId, secrets, params, configurationUtilities, logger, connectorMetricsService } = + const { actionId, secrets, params, configurationUtilities, logger, connectorMetricsCollector } = execOptions; let result: IncomingWebhookResult; @@ -164,7 +164,7 @@ async function slackExecutor( const webhook = new IncomingWebhook(webhookUrl, { agent, }); - connectorMetricsService.addRequestBodyBytes(undefined, { text: message }); + connectorMetricsCollector.addRequestBodyBytes(undefined, { text: message }); result = await webhook.send(message); } catch (err) { if (err.original == null || err.original.response == null) { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.test.ts index 59030a71aaa05..6f183f9988516 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.test.ts @@ -7,7 +7,7 @@ import axios from 'axios'; import { Logger } from '@kbn/core/server'; -import { Services } from '@kbn/actions-plugin/server/types'; +import { ConnectorMetricsCollector, Services } from '@kbn/actions-plugin/server/types'; import { validateConfig, validateParams, validateSecrets } from '@kbn/actions-plugin/server/lib'; import { getConnectorType } from '.'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; @@ -39,10 +39,12 @@ const headers = { let connectorType: SlackApiConnectorType; let configurationUtilities: jest.Mocked; +let connectorMetricsCollector: ConnectorMetricsCollector; beforeEach(() => { configurationUtilities = actionsConfigMock.create(); connectorType = getConnectorType(); + connectorMetricsCollector = new ConnectorMetricsCollector(); }); describe('connector registration', () => { @@ -198,6 +200,7 @@ describe('execute', () => { params: {} as PostMessageParams, configurationUtilities, logger: mockedLogger, + connectorMetricsCollector, }) ).rejects.toThrowErrorMatchingInlineSnapshot( `"[Action][ExternalService] -> [Slack API] Unsupported subAction type undefined."` @@ -296,6 +299,7 @@ describe('execute', () => { }, configurationUtilities, logger: mockedLogger, + connectorMetricsCollector, }); expect(requestMock).toHaveBeenCalledWith({ @@ -306,6 +310,7 @@ describe('execute', () => { method: 'post', url: 'https://slack.com/api/chat.postMessage', data: { channel: 'general', text: 'some text' }, + connectorMetricsCollector, }); expect(response).toEqual({ @@ -386,6 +391,7 @@ describe('execute', () => { }, configurationUtilities, logger: mockedLogger, + connectorMetricsCollector, }); expect(requestMock).toHaveBeenCalledWith({ @@ -396,6 +402,7 @@ describe('execute', () => { method: 'post', url: 'https://slack.com/api/chat.postMessage', data: { channel: 'LKJHGF345', text: 'some text' }, + connectorMetricsCollector, }); expect(response).toEqual({ @@ -476,6 +483,7 @@ describe('execute', () => { }, configurationUtilities, logger: mockedLogger, + connectorMetricsCollector, }); expect(requestMock).toHaveBeenCalledWith({ @@ -486,6 +494,7 @@ describe('execute', () => { method: 'post', url: 'https://slack.com/api/chat.postMessage', data: { channel: 'LKJHGF345', blocks: testBlock.blocks }, + connectorMetricsCollector, }); expect(response).toEqual({ @@ -525,6 +534,7 @@ describe('execute', () => { }, configurationUtilities, logger: mockedLogger, + connectorMetricsCollector, }); expect(requestMock).toHaveBeenCalledWith({ @@ -534,6 +544,7 @@ describe('execute', () => { logger: mockedLogger, method: 'get', url: 'https://slack.com/api/conversations.info?channel=ZXCVBNM567', + connectorMetricsCollector, }); expect(response).toEqual({ diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.ts index 2389198b74cf1..4d5052f50fb35 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.ts @@ -102,7 +102,7 @@ const slackApiExecutor = async ({ secrets, configurationUtilities, logger, - connectorMetricsService, + connectorMetricsCollector, }: SlackApiExecutorOptions): Promise> => { const subAction = params.subAction; @@ -125,7 +125,7 @@ const slackApiExecutor = async ({ }, logger, configurationUtilities, - connectorMetricsService + connectorMetricsCollector ); if (subAction === 'validChannelId') { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.test.ts index dc2a9a4a61538..4befb126fe14f 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.test.ts @@ -13,7 +13,7 @@ import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.moc import { createExternalService } from './service'; import { SlackApiService } from '../../../common/slack_api/types'; import { SLACK_API_CONNECTOR_ID } from '../../../common/slack_api/constants'; -import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; +import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; const logger = loggingSystemMock.create().get() as jest.Mocked; @@ -29,7 +29,7 @@ jest.mock('@kbn/actions-plugin/server/lib/axios_utils', () => { axios.create = jest.fn(() => axios); const requestMock = request as jest.Mock; const configurationUtilities = actionsConfigMock.create(); -let connectorMetricsService: ConnectorMetricsService; +let connectorMetricsCollector: ConnectorMetricsCollector; const channel = { id: 'channel_id_1', @@ -119,14 +119,14 @@ describe('Slack API service', () => { let service: SlackApiService; beforeAll(() => { - connectorMetricsService = new ConnectorMetricsService(); + connectorMetricsCollector = new ConnectorMetricsCollector(); service = createExternalService( { secrets: { token: 'token' }, }, logger, configurationUtilities, - connectorMetricsService + connectorMetricsCollector ); }); @@ -143,7 +143,7 @@ describe('Slack API service', () => { }, logger, configurationUtilities, - connectorMetricsService + connectorMetricsCollector ) ).toThrowErrorMatchingInlineSnapshot(`"[Action][Slack API]: Wrong configuration."`); }); @@ -177,7 +177,7 @@ describe('Slack API service', () => { configurationUtilities, method: 'get', url: 'https://slack.com/api/conversations.info?channel=channel_id_1', - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -213,7 +213,7 @@ describe('Slack API service', () => { method: 'post', url: 'https://slack.com/api/chat.postMessage', data: { channel: 'general', text: 'a message' }, - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -238,7 +238,7 @@ describe('Slack API service', () => { method: 'post', url: 'https://slack.com/api/chat.postMessage', data: { channel: 'QWEERTYU987', text: 'a message' }, - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -259,7 +259,7 @@ describe('Slack API service', () => { method: 'post', url: 'https://slack.com/api/chat.postMessage', data: { channel: 'QWEERTYU987', text: 'a message' }, - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -300,7 +300,7 @@ describe('Slack API service', () => { method: 'post', url: 'https://slack.com/api/chat.postMessage', data: { channel: 'general', blocks: testBlock.blocks }, - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -325,7 +325,7 @@ describe('Slack API service', () => { method: 'post', url: 'https://slack.com/api/chat.postMessage', data: { channel: 'QWEERTYU987', blocks: testBlock.blocks }, - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -349,7 +349,7 @@ describe('Slack API service', () => { method: 'post', url: 'https://slack.com/api/chat.postMessage', data: { channel: 'QWEERTYU987', blocks: testBlock.blocks }, - connectorMetricsService, + connectorMetricsCollector, }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.ts index eefb3713a6416..a21c07ccef45b 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.ts @@ -13,7 +13,7 @@ import { request } from '@kbn/actions-plugin/server/lib/axios_utils'; import { pipe } from 'fp-ts/lib/pipeable'; import { map, getOrElse } from 'fp-ts/lib/Option'; import type { ActionTypeExecutorResult as ConnectorTypeExecutorResult } from '@kbn/actions-plugin/server/types'; -import { ConnectorMetricsService } from '@kbn/actions-plugin/server/types'; +import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/types'; import { SLACK_CONNECTOR_NAME } from './translations'; import type { PostMessageSubActionParams, @@ -113,7 +113,7 @@ export const createExternalService = ( }, logger: Logger, configurationUtilities: ActionsConfigurationUtilities, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): SlackApiService => { const { token } = secrets; const { allowedChannels } = config || { allowedChannels: [] }; @@ -141,7 +141,7 @@ export const createExternalService = ( method: 'get', headers, url: `${SLACK_URL}conversations.info?channel=${channelId}`, - connectorMetricsService, + connectorMetricsCollector, }); }; if (channelId.length === 0) { @@ -210,7 +210,7 @@ export const createExternalService = ( data: { channel: channelToUse, text }, headers, configurationUtilities, - connectorMetricsService, + connectorMetricsCollector, }); return buildSlackExecutorSuccessResponse({ slackApiResponseData: result.data }); @@ -236,7 +236,7 @@ export const createExternalService = ( data: { channel: channelToUse, blocks: blockJson.blocks }, headers, configurationUtilities, - connectorMetricsService, + connectorMetricsCollector, }); return buildSlackExecutorSuccessResponse({ slackApiResponseData: result.data }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/swimlane/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/swimlane/index.ts index 2afc1624d034d..edf0a4a0edf2b 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/swimlane/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/swimlane/index.ts @@ -83,7 +83,7 @@ async function executor( secrets, configurationUtilities, logger, - connectorMetricsService, + connectorMetricsCollector, } = execOptions; const { subAction, subActionParams } = params as ExecutorParams; let data: SwimlaneExecutorResultData | null = null; @@ -95,7 +95,7 @@ async function executor( }, logger, configurationUtilities, - connectorMetricsService + connectorMetricsCollector ); if (!api[subAction]) { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.test.ts index 0749b2171bcea..2b17e1b480783 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.test.ts @@ -14,7 +14,7 @@ import { request, createAxiosResponse } from '@kbn/actions-plugin/server/lib/axi import { createExternalService } from './service'; import { mappings } from './mocks'; import { ExternalService } from './types'; -import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; +import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; const logger = loggingSystemMock.create().get() as jest.Mocked; @@ -57,10 +57,10 @@ describe('Swimlane Service', () => { }; const url = config.apiUrl.slice(0, -1); - let connectorMetricsService: ConnectorMetricsService; + let connectorMetricsCollector: ConnectorMetricsCollector; beforeAll(() => { - connectorMetricsService = new ConnectorMetricsService(); + connectorMetricsCollector = new ConnectorMetricsCollector(); service = createExternalService( { // The trailing slash at the end of the url is intended. @@ -70,7 +70,7 @@ describe('Swimlane Service', () => { }, logger, configurationUtilities, - connectorMetricsService + connectorMetricsCollector ); }); beforeEach(() => { @@ -92,7 +92,7 @@ describe('Swimlane Service', () => { }, logger, configurationUtilities, - connectorMetricsService + connectorMetricsCollector ) ).toThrow(); }); @@ -110,7 +110,7 @@ describe('Swimlane Service', () => { }, logger, configurationUtilities, - connectorMetricsService + connectorMetricsCollector ) ).toThrow(); }); @@ -129,7 +129,7 @@ describe('Swimlane Service', () => { }, logger, configurationUtilities, - connectorMetricsService + connectorMetricsCollector ) ).toThrow(); }); @@ -146,7 +146,7 @@ describe('Swimlane Service', () => { }, logger, configurationUtilities, - connectorMetricsService + connectorMetricsCollector ); }).toThrow(); }); @@ -199,7 +199,7 @@ describe('Swimlane Service', () => { url: `${url}/api/app/${config.appId}/record`, method: 'post', configurationUtilities, - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -283,7 +283,7 @@ describe('Swimlane Service', () => { url: `${url}/api/app/${config.appId}/record/${incidentId}`, method: 'patch', configurationUtilities, - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -363,7 +363,7 @@ describe('Swimlane Service', () => { url: `${url}/api/app/${config.appId}/record/${incidentId}/${mappings.commentsConfig.id}/comment`, method: 'post', configurationUtilities, - connectorMetricsService, + connectorMetricsCollector, }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.ts b/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.ts index 261de60646510..bd0f4367e1313 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.ts @@ -14,7 +14,7 @@ import { throwIfResponseIsNotValid, } from '@kbn/actions-plugin/server/lib/axios_utils'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; -import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; +import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; import { getBodyForEventAction } from './helpers'; import { CreateCommentParams, @@ -44,7 +44,7 @@ export const createExternalService = ( { config, secrets }: ExternalServiceCredentials, logger: Logger, configurationUtilities: ActionsConfigurationUtilities, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): ExternalService => { const { apiUrl: url, appId, mappings } = config as SwimlanePublicConfigurationType; const { apiToken } = secrets as SwimlaneSecretConfigurationType; @@ -94,7 +94,7 @@ export const createExternalService = ( logger, method: 'post', url: getPostRecordUrl(appId), - connectorMetricsService, + connectorMetricsCollector, }); throwIfResponseIsNotValid({ @@ -135,7 +135,7 @@ export const createExternalService = ( logger, method: 'patch', url: getPostRecordIdUrl(appId, params.incidentId), - connectorMetricsService, + connectorMetricsCollector, }); throwIfResponseIsNotValid({ @@ -185,7 +185,7 @@ export const createExternalService = ( logger, method: 'post', url: getPostCommentUrl(appId, incidentId, fieldId), - connectorMetricsService, + connectorMetricsCollector, }); /** diff --git a/x-pack/plugins/stack_connectors/server/connector_types/teams/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/teams/index.test.ts index 2600340b92526..ac88dfadf60db 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/teams/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/teams/index.test.ts @@ -6,7 +6,7 @@ */ import { Logger } from '@kbn/core/server'; -import { ConnectorMetricsService, Services } from '@kbn/actions-plugin/server/types'; +import { ConnectorMetricsCollector, Services } from '@kbn/actions-plugin/server/types'; import { validateParams, validateSecrets } from '@kbn/actions-plugin/server/lib'; import axios from 'axios'; import { getConnectorType, TeamsConnectorType, ConnectorTypeId } from '.'; @@ -34,12 +34,12 @@ const mockedLogger: jest.Mocked = loggerMock.create(); let connectorType: TeamsConnectorType; let configurationUtilities: jest.Mocked; -let connectorMetricsService: ConnectorMetricsService; +let connectorMetricsCollector: ConnectorMetricsCollector; beforeEach(() => { configurationUtilities = actionsConfigMock.create(); connectorType = getConnectorType(); - connectorMetricsService = new ConnectorMetricsService(); + connectorMetricsCollector = new ConnectorMetricsCollector(); }); describe('connector registration', () => { @@ -169,13 +169,13 @@ describe('execute()', () => { params: { message: 'this invocation should succeed' }, configurationUtilities, logger: mockedLogger, - connectorMetricsService, + connectorMetricsCollector, }); delete requestMock.mock.calls[0][0].configurationUtilities; expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "axios": undefined, - "connectorMetricsService": ConnectorMetricsService { + "connectorMetricsCollector": ConnectorMetricsCollector { "metrics": Object { "requestBodyBytes": 0, }, @@ -231,13 +231,13 @@ describe('execute()', () => { params: { message: 'this invocation should succeed' }, configurationUtilities, logger: mockedLogger, - connectorMetricsService, + connectorMetricsCollector, }); delete requestMock.mock.calls[0][0].configurationUtilities; expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "axios": undefined, - "connectorMetricsService": ConnectorMetricsService { + "connectorMetricsCollector": ConnectorMetricsCollector { "metrics": Object { "requestBodyBytes": 0, }, diff --git a/x-pack/plugins/stack_connectors/server/connector_types/teams/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/teams/index.ts index ce578a2f66c86..a4a89501773d1 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/teams/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/teams/index.ts @@ -119,7 +119,7 @@ function validateConnectorTypeConfig( async function teamsExecutor( execOptions: TeamsConnectorTypeExecutorOptions ): Promise> { - const { actionId, secrets, params, configurationUtilities, logger, connectorMetricsService } = + const { actionId, secrets, params, configurationUtilities, logger, connectorMetricsCollector } = execOptions; const { webhookUrl } = secrets; const { message } = params; @@ -135,7 +135,7 @@ async function teamsExecutor( logger, data, configurationUtilities, - connectorMetricsService, + connectorMetricsCollector, }) ); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.test.ts index 3ed2d3afa46db..c6c6e02e2c4de 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.test.ts @@ -12,7 +12,7 @@ import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; import { TinesConnector } from './tines'; import { request } from '@kbn/actions-plugin/server/lib/axios_utils'; import { API_MAX_RESULTS, TINES_CONNECTOR_ID } from '../../../common/tines/constants'; -import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; +import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; jest.mock('axios'); (axios as jest.Mocked).create.mockImplementation( @@ -79,7 +79,7 @@ const storiesGetRequestExpected = { 'Content-Type': 'application/json', }, params: { per_page: API_MAX_RESULTS }, - connectorMetricsService: expect.any(ConnectorMetricsService), + connectorMetricsCollector: expect.any(ConnectorMetricsCollector), }; const agentsGetRequestExpected = { @@ -93,10 +93,10 @@ const agentsGetRequestExpected = { 'Content-Type': 'application/json', }, params: { story_id: story.id, per_page: API_MAX_RESULTS }, - connectorMetricsService: expect.any(ConnectorMetricsService), + connectorMetricsCollector: expect.any(ConnectorMetricsCollector), }; -let connectorMetricsService: ConnectorMetricsService; +let connectorMetricsCollector: ConnectorMetricsCollector; describe('TinesConnector', () => { const connector = new TinesConnector({ @@ -110,7 +110,7 @@ describe('TinesConnector', () => { beforeEach(() => { jest.clearAllMocks(); - connectorMetricsService = new ConnectorMetricsService(); + connectorMetricsCollector = new ConnectorMetricsCollector(); }); describe('getStories', () => { @@ -119,13 +119,13 @@ describe('TinesConnector', () => { }); it('should request Tines stories', async () => { - await connector.getStories(undefined, connectorMetricsService); + await connector.getStories(undefined, connectorMetricsCollector); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith(storiesGetRequestExpected); }); it('should return the Tines stories reduced array', async () => { - const { stories } = await connector.getStories(undefined, connectorMetricsService); + const { stories } = await connector.getStories(undefined, connectorMetricsCollector); expect(stories).toEqual([storyResult]); }); @@ -133,7 +133,7 @@ describe('TinesConnector', () => { mockRequest.mockReturnValueOnce({ data: { stories: [story], meta: { pages: 1 } }, }); - const response = await connector.getStories(undefined, connectorMetricsService); + const response = await connector.getStories(undefined, connectorMetricsCollector); expect(response.incompleteResponse).toEqual(false); }); @@ -141,7 +141,7 @@ describe('TinesConnector', () => { mockRequest.mockReturnValueOnce({ data: { stories: [story], meta: { pages: 2 } }, }); - const response = await connector.getStories(undefined, connectorMetricsService); + const response = await connector.getStories(undefined, connectorMetricsCollector); expect(response.incompleteResponse).toEqual(true); }); }); @@ -152,7 +152,7 @@ describe('TinesConnector', () => { }); it('should request Tines webhook actions', async () => { - await connector.getWebhooks({ storyId: story.id }, connectorMetricsService); + await connector.getWebhooks({ storyId: story.id }, connectorMetricsCollector); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith(agentsGetRequestExpected); @@ -161,7 +161,7 @@ describe('TinesConnector', () => { it('should return the Tines webhooks reduced array', async () => { const { webhooks } = await connector.getWebhooks( { storyId: story.id }, - connectorMetricsService + connectorMetricsCollector ); expect(webhooks).toEqual([webhookResult]); }); @@ -170,7 +170,10 @@ describe('TinesConnector', () => { mockRequest.mockReturnValueOnce({ data: { agents: [webhookAgent], meta: { pages: 1 } }, }); - const response = await connector.getWebhooks({ storyId: story.id }, connectorMetricsService); + const response = await connector.getWebhooks( + { storyId: story.id }, + connectorMetricsCollector + ); expect(response.incompleteResponse).toEqual(false); }); @@ -178,7 +181,10 @@ describe('TinesConnector', () => { mockRequest.mockReturnValueOnce({ data: { agents: [webhookAgent], meta: { pages: 2 } }, }); - const response = await connector.getWebhooks({ storyId: story.id }, connectorMetricsService); + const response = await connector.getWebhooks( + { storyId: story.id }, + connectorMetricsCollector + ); expect(response.incompleteResponse).toEqual(true); }); }); @@ -194,7 +200,7 @@ describe('TinesConnector', () => { webhook: webhookResult, body: '[]', }, - connectorMetricsService + connectorMetricsCollector ); expect(mockRequest).toBeCalledTimes(1); @@ -206,7 +212,7 @@ describe('TinesConnector', () => { headers: { 'Content-Type': 'application/json', }, - connectorMetricsService, + connectorMetricsCollector, }); }); @@ -216,7 +222,7 @@ describe('TinesConnector', () => { webhookUrl, body: '[]', }, - connectorMetricsService + connectorMetricsCollector ); expect(mockRequest).toBeCalledTimes(1); @@ -228,7 +234,7 @@ describe('TinesConnector', () => { headers: { 'Content-Type': 'application/json', }, - connectorMetricsService, + connectorMetricsCollector, }); }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.ts b/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.ts index 9b9234894f189..0a1f3964731d6 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.ts @@ -8,7 +8,7 @@ import { ServiceParams, SubActionConnector } from '@kbn/actions-plugin/server'; import type { AxiosError } from 'axios'; import { SubActionRequestParams } from '@kbn/actions-plugin/server/sub_action_framework/types'; -import { ConnectorMetricsService } from '@kbn/actions-plugin/server/lib'; +import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; import { TinesStoriesActionParamsSchema, TinesWebhooksActionParamsSchema, @@ -110,14 +110,14 @@ export class TinesConnector extends SubActionConnector( req: SubActionRequestParams, reducer: (response: R) => T, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): Promise { const response = await this.request( { ...req, params: { ...req.params, per_page: API_MAX_RESULTS }, }, - connectorMetricsService + connectorMetricsCollector ); return { ...reducer(response.data), @@ -137,7 +137,7 @@ export class TinesConnector extends SubActionConnector { return this.tinesApiRequest( { @@ -146,13 +146,13 @@ export class TinesConnector extends SubActionConnector { return this.tinesApiRequest( { @@ -162,13 +162,13 @@ export class TinesConnector extends SubActionConnector { if (!webhook && !webhookUrl) { throw Error('Invalid subActionsParams: [webhook] or [webhookUrl] expected but got none'); @@ -180,7 +180,7 @@ export class TinesConnector extends SubActionConnector = loggerMock.create(); let configurationUtilities: jest.Mocked; -let connectorMetricsService: ConnectorMetricsService; +let connectorMetricsCollector: ConnectorMetricsCollector; beforeAll(() => { actionType = getActionType(); configurationUtilities = actionsConfigMock.create(); - connectorMetricsService = new ConnectorMetricsService(); + connectorMetricsCollector = new ConnectorMetricsCollector(); }); describe('actionType', () => { @@ -178,14 +178,14 @@ describe('execute Torq action', () => { params: { body: '{"msg": "some data"}' }, configurationUtilities, logger: mockedLogger, - connectorMetricsService, + connectorMetricsCollector, }); delete requestMock.mock.calls[0][0].configurationUtilities; expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "axios": [MockFunction], - "connectorMetricsService": ConnectorMetricsService { + "connectorMetricsCollector": ConnectorMetricsCollector { "metrics": Object { "requestBodyBytes": 0, }, diff --git a/x-pack/plugins/stack_connectors/server/connector_types/torq/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/torq/index.ts index 3667ec5e7f072..af03b10667dea 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/torq/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/torq/index.ts @@ -146,7 +146,7 @@ export async function executor( const { webhookIntegrationUrl } = execOptions.config; const { body: data } = execOptions.params; const configurationUtilities = execOptions.configurationUtilities; - const connectorMetricsService = execOptions.connectorMetricsService; + const connectorMetricsCollector = execOptions.connectorMetricsCollector; const secrets: ActionTypeSecretsType = execOptions.secrets; const token = secrets.token; @@ -172,7 +172,7 @@ export async function executor( configurationUtilities, logger: execOptions.logger, validateStatus: (status: number) => status >= 200 && status < 300, - connectorMetricsService, + connectorMetricsCollector, }) ); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.test.ts index a2e7794eaeadb..8bb52b90d309a 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { ConnectorMetricsService, Services } from '@kbn/actions-plugin/server/types'; +import { ConnectorMetricsCollector, Services } from '@kbn/actions-plugin/server/types'; import { validateConfig, validateParams, validateSecrets } from '@kbn/actions-plugin/server/lib'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; @@ -41,12 +41,12 @@ const mockedLogger: jest.Mocked = loggerMock.create(); let connectorType: WebhookConnectorType; let configurationUtilities: jest.Mocked; -let connectorMetricsService: ConnectorMetricsService; +let connectorMetricsCollector: ConnectorMetricsCollector; beforeEach(() => { configurationUtilities = actionsConfigMock.create(); connectorType = getConnectorType(); - connectorMetricsService = new ConnectorMetricsService(); + connectorMetricsCollector = new ConnectorMetricsCollector(); }); describe('connectorType', () => { @@ -341,14 +341,14 @@ describe('execute()', () => { params: { body: 'some data' }, configurationUtilities, logger: mockedLogger, - connectorMetricsService, + connectorMetricsCollector, }); delete requestMock.mock.calls[0][0].configurationUtilities; expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "axios": undefined, - "connectorMetricsService": ConnectorMetricsService { + "connectorMetricsCollector": ConnectorMetricsCollector { "metrics": Object { "requestBodyBytes": 0, }, @@ -408,7 +408,7 @@ describe('execute()', () => { params: { body: 'some data' }, configurationUtilities, logger: mockedLogger, - connectorMetricsService, + connectorMetricsCollector, }); delete requestMock.mock.calls[0][0].configurationUtilities; @@ -416,7 +416,7 @@ describe('execute()', () => { expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "axios": undefined, - "connectorMetricsService": ConnectorMetricsService { + "connectorMetricsCollector": ConnectorMetricsCollector { "metrics": Object { "requestBodyBytes": 0, }, @@ -602,7 +602,7 @@ describe('execute()', () => { params: { body: 'some data' }, configurationUtilities, logger: mockedLogger, - connectorMetricsService, + connectorMetricsCollector, }); expect(mockedLogger.error).toBeCalledWith( 'error on some-id webhook event: maxContentLength size of 1000000 exceeded' @@ -633,14 +633,14 @@ describe('execute()', () => { params: { body: 'some data' }, configurationUtilities, logger: mockedLogger, - connectorMetricsService, + connectorMetricsCollector, }); delete requestMock.mock.calls[0][0].configurationUtilities; expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "axios": undefined, - "connectorMetricsService": ConnectorMetricsService { + "connectorMetricsCollector": ConnectorMetricsCollector { "metrics": Object { "requestBodyBytes": 0, }, diff --git a/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.ts index d97f74e14b99e..a3cb8172b2237 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.ts @@ -128,7 +128,7 @@ function validateConnectorTypeConfig( export async function executor( execOptions: WebhookConnectorTypeExecutorOptions ): Promise> { - const { actionId, config, params, configurationUtilities, logger, connectorMetricsService } = + const { actionId, config, params, configurationUtilities, logger, connectorMetricsCollector } = execOptions; const { method, url, headers = {}, hasAuth, authType, ca, verificationMode } = config; const { body: data } = params; @@ -160,7 +160,7 @@ export async function executor( data, configurationUtilities, sslOverrides, - connectorMetricsService, + connectorMetricsCollector, }) ); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.test.ts index d74f95ee08cf1..5bb69deba4fa1 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.test.ts @@ -14,7 +14,7 @@ import { XmattersConnectorType, } from '.'; import { actionsMock } from '@kbn/actions-plugin/server/mocks'; -import { ConnectorMetricsService, Services } from '@kbn/actions-plugin/server/types'; +import { ConnectorMetricsCollector, Services } from '@kbn/actions-plugin/server/types'; import { validateConfig, validateConnector, @@ -45,12 +45,12 @@ const mockedLogger: jest.Mocked = loggerMock.create(); let connectorType: XmattersConnectorType; let configurationUtilities: jest.Mocked; -let connectorMetricsService: ConnectorMetricsService; +let connectorMetricsCollector: ConnectorMetricsCollector; beforeEach(() => { configurationUtilities = actionsConfigMock.create(); connectorType = getConnectorType(); - connectorMetricsService = new ConnectorMetricsService(); + connectorMetricsCollector = new ConnectorMetricsCollector(); }); describe('connectorType', () => { @@ -425,7 +425,7 @@ describe('execute()', () => { }, configurationUtilities, logger: mockedLogger, - connectorMetricsService, + connectorMetricsCollector, }); const { method, url, headers, data } = requestMock.mock.calls[0][0]; @@ -475,7 +475,7 @@ describe('execute()', () => { }, configurationUtilities, logger: mockedLogger, - connectorMetricsService, + connectorMetricsCollector, }); expect(mockedLogger.warn).toBeCalledWith( 'Error thrown triggering xMatters workflow: maxContentLength size of 1000000 exceeded' @@ -508,7 +508,7 @@ describe('execute()', () => { }, configurationUtilities, logger: mockedLogger, - connectorMetricsService, + connectorMetricsCollector, }); const { method, url, headers, data } = requestMock.mock.calls[0][0]; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.ts index 1a1121e8a75a1..034a884573f9e 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.ts @@ -247,7 +247,7 @@ function validateConnectorTypeSecrets( export async function executor( execOptions: XmattersConnectorTypeExecutorOptions ): Promise> { - const { actionId, configurationUtilities, config, params, logger, connectorMetricsService } = + const { actionId, configurationUtilities, config, params, logger, connectorMetricsCollector } = execOptions; const { configUrl, usesBasic } = config; const data = getPayloadForRequest(params); @@ -268,7 +268,7 @@ export async function executor( { url, data, basicAuth }, logger, configurationUtilities, - connectorMetricsService + connectorMetricsCollector ); } catch (err) { const message = i18n.translate('xpack.stackConnectors.xmatters.postingErrorMessage', { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/xmatters/post_xmatters.ts b/x-pack/plugins/stack_connectors/server/connector_types/xmatters/post_xmatters.ts index 4051f75c8a4d0..d0dbba93e2fde 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/xmatters/post_xmatters.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/xmatters/post_xmatters.ts @@ -11,7 +11,7 @@ import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/action import { request } from '@kbn/actions-plugin/server/lib/axios_utils'; import { combineHeadersWithBasicAuthHeader, - ConnectorMetricsService, + ConnectorMetricsCollector, } from '@kbn/actions-plugin/server/lib'; interface PostXmattersOptions { @@ -38,7 +38,7 @@ export async function postXmatters( options: PostXmattersOptions, logger: Logger, configurationUtilities: ActionsConfigurationUtilities, - connectorMetricsService: ConnectorMetricsService + connectorMetricsCollector: ConnectorMetricsCollector ): Promise { const { url, data, basicAuth } = options; const axiosInstance = axios.create(); @@ -54,6 +54,6 @@ export async function postXmatters( data, configurationUtilities, validateStatus: () => true, - connectorMetricsService, + connectorMetricsCollector, }); } diff --git a/x-pack/test/alerting_api_integration/common/plugins/alerts/server/sub_action_connector.ts b/x-pack/test/alerting_api_integration/common/plugins/alerts/server/sub_action_connector.ts index 7bd9db83dcc00..1dd361ebb814b 100644 --- a/x-pack/test/alerting_api_integration/common/plugins/alerts/server/sub_action_connector.ts +++ b/x-pack/test/alerting_api_integration/common/plugins/alerts/server/sub_action_connector.ts @@ -11,6 +11,7 @@ import type { ServiceParams } from '@kbn/actions-plugin/server'; import { PluginSetupContract as ActionsPluginSetup } from '@kbn/actions-plugin/server/plugin'; import { schema, TypeOf } from '@kbn/config-schema'; import { SubActionConnectorType } from '@kbn/actions-plugin/server/sub_action_framework/types'; +import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; const TestConfigSchema = schema.object({ url: schema.string() }); const TestSecretsSchema = schema.object({ @@ -69,7 +70,11 @@ export const getTestSubActionConnector = ( return `Message: ${error.response?.data.errorMessage}. Code: ${error.response?.data.errorCode}`; } - public async subActionWithParams({ id }: { id: string }) { + public async subActionWithParams( + { id }: { id: string }, + connectorMetricsCollector: ConnectorMetricsCollector + ) { + connectorMetricsCollector.addRequestBodyBytes(undefined, { id }); return { id }; } diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/bedrock.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/bedrock.ts index 93c8cd40fb37f..1b7bce71aaefc 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/bedrock.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/bedrock.ts @@ -20,8 +20,9 @@ import { ELASTIC_HTTP_VERSION_HEADER, X_ELASTIC_INTERNAL_ORIGIN_REQUEST, } from '@kbn/core-http-common'; +import { IValidatedEvent } from '@kbn/event-log-plugin/generated/schemas'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; -import { getUrlPrefix, ObjectRemover } from '../../../../../common/lib'; +import { getEventLog, getUrlPrefix, ObjectRemover } from '../../../../../common/lib'; const connectorTypeId = '.bedrock'; const name = 'A bedrock action'; @@ -456,9 +457,29 @@ export default function bedrockTest({ getService }: FtrProviderContext) { responseBuffer.push(chunk); }); - passThrough.on('end', () => { + passThrough.on('end', async () => { const parsed = parseBedrockBuffer(responseBuffer); expect(parsed).to.eql('Hello world, what a unique string!'); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: bedrockActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be( + 110 + ); + resolve(); }); }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/cases_webhook.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/cases_webhook.ts index f26ba86f6fa3a..71198328160b5 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/cases_webhook.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/cases_webhook.ts @@ -14,13 +14,16 @@ import { ExternalServiceSimulator, } from '@kbn/actions-simulators-plugin/server/plugin'; import { TaskErrorSource } from '@kbn/task-manager-plugin/common'; +import { IValidatedEvent } from '@kbn/event-log-plugin/generated/schemas'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; +import { getEventLog } from '../../../../../common/lib'; // eslint-disable-next-line import/no-default-export export default function casesWebhookTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const kibanaServer = getService('kibanaServer'); const configService = getService('config'); + const retry = getService('retry'); const config = { createCommentJson: '{"body":{{{case.comment}}}}', createCommentMethod: 'post', @@ -398,6 +401,23 @@ export default function casesWebhookTest({ getService }: FtrProviderContext) { const { pushedDate, ...dataWithoutTime } = body.data; body.data = dataWithoutTime; + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: simulatedActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(125); + expect(body).to.eql({ status: 'ok', connector_id: simulatedActionId, diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/d3security.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/d3security.ts index 7e1f0636b3a96..0c47f176efc42 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/d3security.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/d3security.ts @@ -12,7 +12,9 @@ import { d3SecuritySuccessResponse, } from '@kbn/actions-simulators-plugin/server/d3security_simulation'; import { TaskErrorSource } from '@kbn/task-manager-plugin/common'; +import { IValidatedEvent } from '@kbn/event-log-plugin/generated/schemas'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; +import { getEventLog } from '../../../../../common/lib'; const connectorTypeId = '.d3security'; const name = 'A D3 Security action'; @@ -24,6 +26,7 @@ const secrets = { export default function d3SecurityTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const configService = getService('config'); + const retry = getService('retry'); const createConnector = async (url: string) => { const { body } = await supertest @@ -248,6 +251,24 @@ export default function d3SecurityTest({ getService }: FtrProviderContext) { }, }, }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: d3SecurityActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(99); + expect(body).to.eql({ status: 'ok', connector_id: d3SecurityActionId, diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/email.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/email.ts index cfffe90126fac..21d0f8f5ee0f3 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/email.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/email.ts @@ -11,12 +11,15 @@ import { ExternalServiceSimulator, getExternalServiceSimulatorPath, } from '@kbn/actions-simulators-plugin/server/plugin'; +import { IValidatedEvent } from '@kbn/event-log-plugin/generated/schemas'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; +import { getEventLog } from '../../../../../common/lib'; // eslint-disable-next-line import/no-default-export export default function emailTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const kibanaServer = getService('kibanaServer'); + const retry = getService('retry'); describe('create email action', () => { let createdActionId = ''; @@ -103,7 +106,7 @@ export default function emailTest({ getService }: FtrProviderContext) { }, }) .expect(200) - .then((resp: any) => { + .then(async (resp: any) => { expect(resp.body.data.message.messageId).to.be.a('string'); expect(resp.body.data.messageId).to.be.a('string'); @@ -131,6 +134,23 @@ export default function emailTest({ getService }: FtrProviderContext) { headers: {}, }, }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: createdActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(350); }); }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/es_index.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/es_index.ts index 46287db208b87..0ffe702a50143 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/es_index.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/es_index.ts @@ -7,7 +7,9 @@ import type { Client } from '@elastic/elasticsearch'; import expect from '@kbn/expect'; +import { IValidatedEvent } from '@kbn/event-log-plugin/generated/schemas'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; +import { getEventLog } from '../../../../../common/lib'; const ES_TEST_INDEX_NAME = 'functional-test-actions-index'; @@ -16,6 +18,7 @@ export default function indexTest({ getService }: FtrProviderContext) { const es: Client = getService('es'); const supertest = getService('supertest'); const esDeleteAllIndices = getService('esDeleteAllIndices'); + const retry = getService('retry'); describe('index action', () => { beforeEach(() => esDeleteAllIndices(ES_TEST_INDEX_NAME)); @@ -214,6 +217,23 @@ export default function indexTest({ getService }: FtrProviderContext) { } expect(passed1).to.be(true); expect(passed2).to.be(true); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: createdAction.id, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(0); }); it('should execute successly with refresh false', async () => { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/jira.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/jira.ts index 054678996888f..f355e6793fecf 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/jira.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/jira.ts @@ -7,6 +7,7 @@ import httpProxy from 'http-proxy'; import expect from '@kbn/expect'; +import { IValidatedEvent } from '@kbn/event-log-plugin/generated/schemas'; import { getHttpProxyServer } from '@kbn/alerting-api-integration-helpers'; import { @@ -16,12 +17,14 @@ import { import { TaskErrorSource } from '@kbn/task-manager-plugin/common'; import { MAX_OTHER_FIELDS_LENGTH } from '@kbn/stack-connectors-plugin/common/jira/constants'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; +import { getEventLog } from '../../../../../common/lib'; // eslint-disable-next-line import/no-default-export export default function jiraTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const kibanaServer = getService('kibanaServer'); const configService = getService('config'); + const retry = getService('retry'); const mockJira = { config: { @@ -517,6 +520,23 @@ export default function jiraTest({ getService }: FtrProviderContext) { url: `${jiraSimulatorURL}/browse/CK-1`, }, }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: simulatedActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { gte: 2 }], + ['execute', { gte: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(124); }); it('should handle creating an incident with other fields', async () => { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/openai.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/openai.ts index a971f18b7130d..15a8296244906 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/openai.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/openai.ts @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import { IValidatedEvent } from '@kbn/event-log-plugin/server'; import { OpenAISimulator, @@ -14,6 +15,7 @@ import { import { TaskErrorSource } from '@kbn/task-manager-plugin/common'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; import { getUrlPrefix, ObjectRemover } from '../../../../../common/lib'; +import { getEventLog } from '../../../../../common/lib'; const connectorTypeId = '.gen-ai'; const name = 'A genAi action'; @@ -274,7 +276,7 @@ export default function genAiTest({ getService }: FtrProviderContext) { }); describe('execution', () => { - describe('successful response simulator', () => { + describe('successful response simulator x', () => { const simulator = new OpenAISimulator({ proxy: { config: configService.get('kbnTestServer.serverArgs'), @@ -315,6 +317,23 @@ export default function genAiTest({ getService }: FtrProviderContext) { connector_id: genAiActionId, data: genAiSuccessResponse, }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: genAiActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(78); }); describe('Token tracking dashboard', () => { const dashboardId = 'specific-dashboard-id-default'; diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/opsgenie.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/opsgenie.ts index 48386480b00da..4625364e9bb7a 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/opsgenie.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/opsgenie.ts @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import { IValidatedEvent } from '@kbn/event-log-plugin/server'; import { OpsgenieSimulator, @@ -13,11 +14,13 @@ import { } from '@kbn/actions-simulators-plugin/server/opsgenie_simulation'; import { TaskErrorSource } from '@kbn/task-manager-plugin/common'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; +import { getEventLog } from '../../../../../common/lib'; // eslint-disable-next-line import/no-default-export export default function opsgenieTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const configService = getService('config'); + const retry = getService('retry'); describe('Opsgenie', () => { describe('action creation', () => { @@ -535,6 +538,23 @@ export default function opsgenieTest({ getService }: FtrProviderContext) { connector_id: opsgenieActionId, data: opsgenieSuccessResponse, }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: opsgenieActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(21); }); it('should preserve the alias when it is 512 characters when creating an alert', async () => { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/pagerduty.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/pagerduty.ts index 7148ac962c728..940ef8f89467f 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/pagerduty.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/pagerduty.ts @@ -7,6 +7,7 @@ import httpProxy from 'http-proxy'; import expect from '@kbn/expect'; +import { IValidatedEvent } from '@kbn/event-log-plugin/server'; import { getHttpProxyServer } from '@kbn/alerting-api-integration-helpers'; import { @@ -14,12 +15,14 @@ import { ExternalServiceSimulator, } from '@kbn/actions-simulators-plugin/server/plugin'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; +import { getEventLog } from '../../../../../common/lib'; // eslint-disable-next-line import/no-default-export export default function pagerdutyTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const kibanaServer = getService('kibanaServer'); const configService = getService('config'); + const retry = getService('retry'); describe('pagerduty action', () => { let simulatedActionId = ''; @@ -173,6 +176,23 @@ export default function pagerdutyTest({ getService }: FtrProviderContext) { status: 'success', }, }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: simulatedActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(142); }); it('should execute successfully with links and customDetails', async () => { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/resilient.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/resilient.ts index c9b4e7ecafa3f..fd69794863164 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/resilient.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/resilient.ts @@ -6,15 +6,18 @@ */ import expect from '@kbn/expect'; +import { IValidatedEvent } from '@kbn/event-log-plugin/server'; import { TaskErrorSource } from '@kbn/task-manager-plugin/common'; import { ResilientSimulator } from '@kbn/actions-simulators-plugin/server/resilient_simulation'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; +import { getEventLog } from '../../../../../common/lib'; // eslint-disable-next-line import/no-default-export export default function resilientTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const configService = getService('config'); + const retry = getService('retry'); const mockResilient = { config: { @@ -409,6 +412,23 @@ export default function resilientTest({ getService }: FtrProviderContext) { url: `${simulatorUrl}/#incidents/123`, }, }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: resilientActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(167); }); }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/server_log.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/server_log.ts index a5f14e512ddb1..0fd72a2b8ec7a 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/server_log.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/server_log.ts @@ -6,12 +6,15 @@ */ import expect from '@kbn/expect'; +import { IValidatedEvent } from '@kbn/event-log-plugin/server'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; +import { getEventLog } from '../../../../../common/lib'; // eslint-disable-next-line import/no-default-export export default function serverLogTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); + const retry = getService('retry'); describe('server-log action', () => { let serverLogActionId: string; @@ -69,6 +72,23 @@ export default function serverLogTest({ getService }: FtrProviderContext) { .expect(200); expect(result.status).to.eql('ok'); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: serverLogActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(0); }); }); } diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_itom.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_itom.ts index 4702d3bbe6df7..c150003339f0d 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_itom.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_itom.ts @@ -10,16 +10,19 @@ import expect from '@kbn/expect'; import { asyncForEach } from '@kbn/std'; import getPort from 'get-port'; import http from 'http'; +import { IValidatedEvent } from '@kbn/event-log-plugin/server'; import { getHttpProxyServer } from '@kbn/alerting-api-integration-helpers'; import { getServiceNowServer } from '@kbn/actions-simulators-plugin/server/plugin'; import { TaskErrorSource } from '@kbn/task-manager-plugin/common'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; +import { getEventLog } from '../../../../../common/lib'; // eslint-disable-next-line import/no-default-export export default function serviceNowITOMTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const configService = getService('config'); + const retry = getService('retry'); const mockServiceNowCommon = { params: { @@ -500,6 +503,23 @@ export default function serviceNowITOMTest({ getService }: FtrProviderContext) { }) .expect(200); expect(result.status).to.eql('ok'); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: simulatedActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(317); }); }); @@ -548,6 +568,23 @@ export default function serviceNowITOMTest({ getService }: FtrProviderContext) { }, ], }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: simulatedActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 2 }], + ['execute', { equal: 2 }], + ]), + }); + }); + + const executeEvent = events[3]; + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(0); }); }); }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_itsm.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_itsm.ts index ec62e6d30f6ff..ee470a85101ab 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_itsm.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_itsm.ts @@ -10,17 +10,20 @@ import expect from '@kbn/expect'; import { asyncForEach } from '@kbn/std'; import getPort from 'get-port'; import http from 'http'; +import { IValidatedEvent } from '@kbn/event-log-plugin/server'; import { getHttpProxyServer } from '@kbn/alerting-api-integration-helpers'; import { getServiceNowServer } from '@kbn/actions-simulators-plugin/server/plugin'; import { TaskErrorSource } from '@kbn/task-manager-plugin/common'; import { MAX_ADDITIONAL_FIELDS_LENGTH } from '@kbn/stack-connectors-plugin/common/servicenow/constants'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; +import { getEventLog } from '../../../../../common/lib'; // eslint-disable-next-line import/no-default-export export default function serviceNowITSMTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const configService = getService('config'); + const retry = getService('retry'); const mockServiceNowCommon = { params: { @@ -708,6 +711,23 @@ export default function serviceNowITSMTest({ getService }: FtrProviderContext) { url: `${serviceNowSimulatorURL}/nav_to.do?uri=incident.do?sys_id=123`, }, }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: simulatedActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(261); }); }); @@ -755,6 +775,23 @@ export default function serviceNowITSMTest({ getService }: FtrProviderContext) { url: `${serviceNowSimulatorURL}/nav_to.do?uri=incident.do?sys_id=123`, }, }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: simulatedActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(239); }); }); @@ -803,6 +840,23 @@ export default function serviceNowITSMTest({ getService }: FtrProviderContext) { }, ], }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: simulatedActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { gte: 2 }], + ['execute', { gte: 2 }], + ]), + }); + }); + + const executeEvent = events[3]; + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(0); }); }); @@ -829,6 +883,22 @@ export default function serviceNowITSMTest({ getService }: FtrProviderContext) { connector_id: simulatedActionId, data: {}, }); + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: simulatedActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { gte: 3 }], + ['execute', { gte: 3 }], + ]), + }); + }); + + const executeEvent = events[5]; + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(0); }); }); }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_sir.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_sir.ts index fd4781f6d9e62..f5246766b744c 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_sir.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_sir.ts @@ -10,17 +10,20 @@ import expect from '@kbn/expect'; import { asyncForEach } from '@kbn/std'; import getPort from 'get-port'; import http from 'http'; +import { IValidatedEvent } from '@kbn/event-log-plugin/server'; import { getHttpProxyServer } from '@kbn/alerting-api-integration-helpers'; import { getServiceNowServer } from '@kbn/actions-simulators-plugin/server/plugin'; import { TaskErrorSource } from '@kbn/task-manager-plugin/common'; import { MAX_ADDITIONAL_FIELDS_LENGTH } from '@kbn/stack-connectors-plugin/common/servicenow/constants'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; +import { getEventLog } from '../../../../../common/lib'; // eslint-disable-next-line import/no-default-export export default function serviceNowSIRTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const configService = getService('config'); + const retry = getService('retry'); const mockServiceNowCommon = { config: { @@ -721,6 +724,23 @@ export default function serviceNowSIRTest({ getService }: FtrProviderContext) { url: `${serviceNowSimulatorURL}/nav_to.do?uri=sn_si_incident.do?sys_id=123`, }, }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: simulatedActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(645); }); }); @@ -768,6 +788,22 @@ export default function serviceNowSIRTest({ getService }: FtrProviderContext) { url: `${serviceNowSimulatorURL}/nav_to.do?uri=sn_si_incident.do?sys_id=123`, }, }); + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: simulatedActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(429); }); }); @@ -816,6 +852,23 @@ export default function serviceNowSIRTest({ getService }: FtrProviderContext) { }, ], }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: simulatedActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { gte: 2 }], + ['execute', { gte: 2 }], + ]), + }); + }); + + const executeEvent = events[3]; + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(0); }); }); }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/slack_webhook.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/slack_webhook.ts index 4941bec1844ca..ff574fd0aea31 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/slack_webhook.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/slack_webhook.ts @@ -9,14 +9,18 @@ import httpProxy from 'http-proxy'; import expect from '@kbn/expect'; import http from 'http'; import getPort from 'get-port'; +import { IValidatedEvent } from '@kbn/event-log-plugin/server'; + import { getHttpProxyServer } from '@kbn/alerting-api-integration-helpers'; import { getSlackServer } from '@kbn/actions-simulators-plugin/server/plugin'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; +import { getEventLog } from '../../../../../common/lib'; // eslint-disable-next-line import/no-default-export export default function slackTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const configService = getService('config'); + const retry = getService('retry'); describe('Slack webhook action', () => { let simulatedActionId = ''; @@ -175,6 +179,23 @@ export default function slackTest({ getService }: FtrProviderContext) { .expect(200); expect(result.status).to.eql('ok'); expect(proxyHaveBeenCalled).to.equal(true); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: simulatedActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(18); }); it('should handle an empty message error', async () => { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/swimlane.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/swimlane.ts index 859f4f952fe58..75cfc23bca764 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/swimlane.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/swimlane.ts @@ -9,16 +9,19 @@ import httpProxy from 'http-proxy'; import expect from '@kbn/expect'; import getPort from 'get-port'; import http from 'http'; +import { IValidatedEvent } from '@kbn/event-log-plugin/server'; import { getHttpProxyServer } from '@kbn/alerting-api-integration-helpers'; import { getSwimlaneServer } from '@kbn/actions-simulators-plugin/server/plugin'; import { TaskErrorSource } from '@kbn/task-manager-plugin/common'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; +import { getEventLog } from '../../../../../common/lib'; // eslint-disable-next-line import/no-default-export export default function swimlaneTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const configService = getService('config'); + const retry = getService('retry'); const mockSwimlane = { name: 'A swimlane action', @@ -459,6 +462,23 @@ export default function swimlaneTest({ getService }: FtrProviderContext) { url: `${swimlaneSimulatorURL}/record/123456asdf/wowzeronza`, }, }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: simulatedActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(175); }); it('should handle updating an incident', async () => { @@ -490,6 +510,23 @@ export default function swimlaneTest({ getService }: FtrProviderContext) { url: `${swimlaneSimulatorURL}/record/123456asdf/wowzeronza`, }, }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: simulatedActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { gte: 1 }], + ['execute', { gte: 2 }], + ]), + }); + }); + + const executeEvent = events[3]; + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(193); }); }); }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/tines.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/tines.ts index 53dd3aaaf026a..7eeb2712cc81d 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/tines.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/tines.ts @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import { IValidatedEvent } from '@kbn/event-log-plugin/server'; import { TinesSimulator, @@ -16,6 +17,7 @@ import { } from '@kbn/actions-simulators-plugin/server/tines_simulation'; import { TaskErrorSource } from '@kbn/task-manager-plugin/common'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; +import { getEventLog } from '../../../../../common/lib'; const connectorTypeId = '.tines'; const name = 'A tines action'; @@ -35,6 +37,7 @@ const webhook = { export default function tinesTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const configService = getService('config'); + const retry = getService('retry'); const createConnector = async (url: string) => { const { body } = await supertest @@ -392,6 +395,23 @@ export default function tinesTest({ getService }: FtrProviderContext) { incompleteResponse: false, }, }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: tinesActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(2); }); it('should get webhooks', async () => { @@ -422,6 +442,22 @@ export default function tinesTest({ getService }: FtrProviderContext) { incompleteResponse: false, }, }); + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: tinesActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { gte: 2 }], + ['execute', { gte: 2 }], + ]), + }); + }); + + const executeEvent = events[3]; + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(2); }); it('should run the webhook', async () => { @@ -440,6 +476,22 @@ export default function tinesTest({ getService }: FtrProviderContext) { connector_id: tinesActionId, data: tinesWebhookSuccessResponse, }); + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: tinesActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { gte: 3 }], + ['execute', { gte: 3 }], + ]), + }); + }); + + const executeEvent = events[5]; + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(8); }); it('should run the webhook url', async () => { @@ -464,6 +516,22 @@ export default function tinesTest({ getService }: FtrProviderContext) { connector_id: tinesActionId, data: tinesWebhookSuccessResponse, }); + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: tinesActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { gte: 3 }], + ['execute', { gte: 3 }], + ]), + }); + }); + + const executeEvent = events[5]; + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(8); }); }); @@ -506,6 +574,22 @@ export default function tinesTest({ getService }: FtrProviderContext) { errorSource: TaskErrorSource.FRAMEWORK, service_message: 'Status code: 422. Message: API Error: Unprocessable Entity', }); + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: tinesActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { gte: 1 }], + ['execute', { gte: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(2); }); it('should return a failure when attempting to get webhooks', async () => { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/torq.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/torq.ts index 257378b406da5..e5857443a0afd 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/torq.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/torq.ts @@ -7,6 +7,7 @@ import httpProxy from 'http-proxy'; import expect from '@kbn/expect'; +import { IValidatedEvent } from '@kbn/event-log-plugin/server'; import { getHttpProxyServer } from '@kbn/alerting-api-integration-helpers/get_proxy_server'; import { @@ -14,12 +15,14 @@ import { ExternalServiceSimulator, } from '@kbn/actions-simulators-plugin/server/plugin'; import { FtrProviderContext } from '../../../../../../common/ftr_provider_context'; +import { getEventLog } from '../../../../../common/lib'; // eslint-disable-next-line import/no-default-export export default function torqTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const kibanaServer = getService('kibanaServer'); const configService = getService('config'); + const retry = getService('retry'); describe('Torq action', () => { let simulatedActionId = ''; @@ -159,6 +162,22 @@ export default function torqTest({ getService }: FtrProviderContext) { connector_id: simulatedActionId, data: `{"msg": "test"}`, }); + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: simulatedActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { gte: 1 }], + ['execute', { gte: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(14); }); it('should handle a 400 Torq error', async () => { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/webhook.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/webhook.ts index c7a8f1c1b2524..5e0298ac3b944 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/webhook.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/webhook.ts @@ -8,6 +8,8 @@ import httpProxy from 'http-proxy'; import http from 'http'; import expect from '@kbn/expect'; +import { IValidatedEvent } from '@kbn/event-log-plugin/server'; + import { URL, format as formatUrl } from 'url'; import getPort from 'get-port'; import { getHttpProxyServer } from '@kbn/alerting-api-integration-helpers'; @@ -17,6 +19,7 @@ import { getWebhookServer, } from '@kbn/actions-simulators-plugin/server/plugin'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; +import { getEventLog } from '../../../../../common/lib'; const defaultValues: Record = { headers: null, @@ -36,6 +39,7 @@ export default function webhookTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const kibanaServer = getService('kibanaServer'); const configService = getService('config'); + const retry = getService('retry'); async function createWebhookAction( webhookSimulatorURL: string, @@ -258,6 +262,23 @@ export default function webhookTest({ getService }: FtrProviderContext) { .expect(200); expect(result.status).to.eql('ok'); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: webhookActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { gte: 1 }], + ['execute', { gte: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(19); }); it('should support the PUT method against webhook target', async () => { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/xmatters.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/xmatters.ts index 4efacbf78f951..00dd7137fdf8f 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/xmatters.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/xmatters.ts @@ -7,6 +7,7 @@ import httpProxy from 'http-proxy'; import expect from '@kbn/expect'; +import { IValidatedEvent } from '@kbn/event-log-plugin/server'; import { getHttpProxyServer } from '@kbn/alerting-api-integration-helpers'; import { @@ -14,12 +15,14 @@ import { ExternalServiceSimulator, } from '@kbn/actions-simulators-plugin/server/plugin'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; +import { getEventLog } from '../../../../../common/lib'; // eslint-disable-next-line import/no-default-export export default function xmattersTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const kibanaServer = getService('kibanaServer'); const configService = getService('config'); + const retry = getService('retry'); describe('xmatters action', () => { let simulatedActionId = ''; @@ -180,6 +183,23 @@ export default function xmattersTest({ getService }: FtrProviderContext) { spaceId: '', }, }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: simulatedActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { gte: 1 }], + ['execute', { gte: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(130); }); it('should handle a 40x xmatters error', async () => { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/execute.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/execute.ts index acfb06e64cff6..6ce3261fe7790 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/execute.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/execute.ts @@ -652,6 +652,8 @@ export default function ({ getService }: FtrProviderContext) { expect(executeEvent?.message).to.eql(message); expect(startExecuteEvent?.message).to.eql(message.replace('executed', 'started')); + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.eql(0); + if (source) { expect(executeEvent?.kibana?.action?.execution?.source).to.eql(source.toLowerCase()); } diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/sub_action_framework/index.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/sub_action_framework/index.ts index c8fb3e4b6ce2d..8582509722719 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/sub_action_framework/index.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/sub_action_framework/index.ts @@ -8,8 +8,9 @@ import type SuperTest from 'supertest'; import expect from '@kbn/expect'; import { TaskErrorSource } from '@kbn/task-manager-plugin/common'; +import { IValidatedEvent } from '@kbn/event-log-plugin/generated/schemas'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; -import { getUrlPrefix, ObjectRemover } from '../../../../../common/lib'; +import { getEventLog, getUrlPrefix, ObjectRemover } from '../../../../../common/lib'; /** * The sub action connector is defined here @@ -79,6 +80,7 @@ const executeSubAction = async ({ // eslint-disable-next-line import/no-default-export export default function createActionTests({ getService }: FtrProviderContext) { const supertest = getService('supertest'); + const retry = getService('retry'); describe('Sub action framework', () => { const objectRemover = new ObjectRemover(supertest); @@ -140,13 +142,35 @@ export default function createActionTests({ getService }: FtrProviderContext) { const res = await createSubActionConnector({ supertest }); objectRemover.add('default', res.body.id, 'action', 'actions'); + const connectorId = res.body.id as string; + const subActionParams = { id: 'test-id' }; + const execRes = await executeSubAction({ supertest, - connectorId: res.body.id as string, + connectorId, subAction: 'subActionWithParams', - subActionParams: { id: 'test-id' }, + subActionParams, + }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: connectorId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); }); + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.eql( + Buffer.byteLength(JSON.stringify(subActionParams)) + ); + expect(execRes.body).to.eql({ status: 'ok', data: { id: 'test-id' }, From c6dff6c178b61238c7273894d494c89091b78302 Mon Sep 17 00:00:00 2001 From: Ersin Erdal Date: Tue, 9 Jul 2024 21:18:17 +0200 Subject: [PATCH 04/25] fix unit test --- ...create_action_event_log_record_object.test.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.test.ts b/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.test.ts index cb6390a4b3335..46f13ae1182ac 100644 --- a/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.test.ts +++ b/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.test.ts @@ -33,6 +33,7 @@ describe('createActionEventLogRecordObject', () => { spaceId: 'default', name: 'test name', actionExecutionId: '123abc', + actionTypeId: '.slack', }) ).toStrictEqual({ '@timestamp': '1970-01-01T00:00:00.000Z', @@ -64,6 +65,7 @@ describe('createActionEventLogRecordObject', () => { }, action: { name: 'test name', + type_id: '.slack', id: '1', execution: { uuid: '123abc', @@ -92,6 +94,7 @@ describe('createActionEventLogRecordObject', () => { }, ], actionExecutionId: '123abc', + actionTypeId: '.slack', }) ).toStrictEqual({ event: { @@ -118,6 +121,7 @@ describe('createActionEventLogRecordObject', () => { ], action: { name: 'test name', + type_id: '.slack', id: '1', execution: { uuid: '123abc', @@ -145,6 +149,7 @@ describe('createActionEventLogRecordObject', () => { }, ], actionExecutionId: '123abc', + actionTypeId: '.slack', }) ).toStrictEqual({ event: { @@ -163,6 +168,7 @@ describe('createActionEventLogRecordObject', () => { ], action: { name: 'test name', + type_id: '.slack', id: '1', execution: { uuid: '123abc', @@ -192,6 +198,7 @@ describe('createActionEventLogRecordObject', () => { ], name: 'test name', actionExecutionId: '123abc', + actionTypeId: '.slack', }) ).toStrictEqual({ event: { @@ -220,6 +227,7 @@ describe('createActionEventLogRecordObject', () => { }, action: { name: 'test name', + type_id: '.slack', id: '1', execution: { uuid: '123abc', @@ -255,6 +263,7 @@ describe('createActionEventLogRecordObject', () => { }, ], actionExecutionId: '123abc', + actionTypeId: '.slack', }) ).toStrictEqual({ event: { @@ -289,6 +298,7 @@ describe('createActionEventLogRecordObject', () => { ], action: { name: 'test name', + type_id: '.slack', id: '1', execution: { uuid: '123abc', @@ -319,6 +329,7 @@ describe('createActionEventLogRecordObject', () => { ], actionExecutionId: '123abc', source: asHttpRequestExecutionSource(httpServerMock.createKibanaRequest()), + actionTypeId: '.slack', }) ).toStrictEqual({ event: { @@ -345,6 +356,7 @@ describe('createActionEventLogRecordObject', () => { ], action: { name: 'test name', + type_id: '.slack', id: '1', execution: { source: 'http_request', @@ -376,6 +388,7 @@ describe('createActionEventLogRecordObject', () => { ], actionExecutionId: '123abc', source: asHttpRequestExecutionSource(httpServerMock.createKibanaRequest()), + actionTypeId: '.slack', }) ).toStrictEqual({ event: { @@ -402,6 +415,7 @@ describe('createActionEventLogRecordObject', () => { ], action: { name: 'test name', + type_id: '.slack', id: '1', execution: { source: 'http_request', @@ -433,6 +447,7 @@ describe('createActionEventLogRecordObject', () => { ], actionExecutionId: '123abc', isInMemory: true, + actionTypeId: '.slack', }) ).toStrictEqual({ event: { @@ -460,6 +475,7 @@ describe('createActionEventLogRecordObject', () => { ], action: { name: 'test name', + type_id: '.slack', id: '1', execution: { uuid: '123abc', From 8fdd8fc6f56bed71afa9942fcb56f8937a269230 Mon Sep 17 00:00:00 2001 From: Ersin Erdal Date: Tue, 9 Jul 2024 23:07:08 +0200 Subject: [PATCH 05/25] fix bedrock functional test --- .../tests/actions/connector_types/bedrock.ts | 57 ++++++++++++++++++- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/bedrock.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/bedrock.ts index 1b7bce71aaefc..cc74fc8a72437 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/bedrock.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/bedrock.ts @@ -352,6 +352,23 @@ export default function bedrockTest({ getService }: FtrProviderContext) { }, }, }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: bedrockActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(145); }); it('should overwrite the model when a model argument is provided', async () => { @@ -382,6 +399,23 @@ export default function bedrockTest({ getService }: FtrProviderContext) { }, }, }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: bedrockActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { gte: 2 }], + ['execute', { gte: 2 }], + ]), + }); + }); + + const executeEvent = events[3]; + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(145); }); it('should invoke AI with assistant AI body argument formatted to bedrock expectations', async () => { @@ -431,6 +465,23 @@ export default function bedrockTest({ getService }: FtrProviderContext) { connector_id: bedrockActionId, data: { message: bedrockClaude2SuccessResponse.completion }, }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: bedrockActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { gte: 3 }], + ['execute', { gte: 3 }], + ]), + }); + }); + + const executeEvent = events[5]; + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(256); }); it('should invoke stream with assistant AI body argument formatted to bedrock expectations', async () => { @@ -469,13 +520,13 @@ export default function bedrockTest({ getService }: FtrProviderContext) { id: bedrockActionId, provider: 'actions', actions: new Map([ - ['execute-start', { equal: 1 }], - ['execute', { equal: 1 }], + ['execute-start', { gte: 4 }], + ['execute', { gte: 4 }], ]), }); }); - const executeEvent = events[1]; + const executeEvent = events[7]; expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be( 110 ); From ce5158c831c2a4f21aec2e3970041c47a0431d10 Mon Sep 17 00:00:00 2001 From: Ersin Erdal Date: Thu, 11 Jul 2024 11:14:46 +0200 Subject: [PATCH 06/25] Add comments to trigger security solutions unit tests --- .../actions/clients/crowdstrike/crowdstrike_actions_client.ts | 2 ++ .../actions/clients/sentinelone/sentinel_one_actions_client.ts | 2 ++ 2 files changed, 4 insertions(+) diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/crowdstrike/crowdstrike_actions_client.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/crowdstrike/crowdstrike_actions_client.ts index 958c51014c6a0..92c4db4122e82 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/crowdstrike/crowdstrike_actions_client.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/crowdstrike/crowdstrike_actions_client.ts @@ -43,6 +43,8 @@ export type CrowdstrikeActionsClientOptions = ResponseActionsClientOptions & { connectorActions: NormalizedExternalConnectorClient; }; +// Temporary comment to trigger unit tests + export class CrowdstrikeActionsClient extends ResponseActionsClientImpl { protected readonly agentType: ResponseActionAgentType = 'crowdstrike'; private readonly connectorActionsClient: NormalizedExternalConnectorClient; diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/sentinel_one_actions_client.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/sentinel_one_actions_client.ts index 54d2147cbe2e2..7f3bee9371488 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/sentinel_one_actions_client.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/sentinel_one_actions_client.ts @@ -95,6 +95,8 @@ interface FetchScriptInfoResponse< buildScriptArgs: (options: TScriptOptions) => string; } +// Temporary comment to trigger unit tests + export class SentinelOneActionsClient extends ResponseActionsClientImpl { protected readonly agentType: ResponseActionAgentType = 'sentinel_one'; private readonly connectorActionsClient: NormalizedExternalConnectorClient; From 7bd6af01a9c9b98937037f59ed75d2177c74d25a Mon Sep 17 00:00:00 2001 From: Ersin Erdal Date: Sat, 13 Jul 2024 14:15:30 +0200 Subject: [PATCH 07/25] try-catch stringify in collector --- .../actions/server/lib/action_executor.ts | 9 ++--- .../lib/connector_metrics_collector.test.ts | 33 +++++++++++++++++-- .../server/lib/connector_metrics_collector.ts | 23 +++++++++++-- 3 files changed, 57 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/actions/server/lib/action_executor.ts b/x-pack/plugins/actions/server/lib/action_executor.ts index 781432b92e335..054df88f1d757 100644 --- a/x-pack/plugins/actions/server/lib/action_executor.ts +++ b/x-pack/plugins/actions/server/lib/action_executor.ts @@ -391,12 +391,16 @@ export class ActionExecutor { }, async (span) => { const { actionTypeRegistry, analyticsService, eventLogger } = this.actionExecutorContext!; - const connectorMetricsCollector = new ConnectorMetricsCollector(); const actionInfo = await this.getActionInfoInternal(actionId, namespace.namespace); const { actionTypeId, name, config, secrets } = actionInfo; + const loggerId = actionTypeId.startsWith('.') ? actionTypeId.substring(1) : actionTypeId; + const logger = this.actionExecutorContext!.logger.get(loggerId); + + const connectorMetricsCollector = new ConnectorMetricsCollector(logger); + if (!this.actionInfo || this.actionInfo.actionId !== actionId) { this.actionInfo = actionInfo; } @@ -437,9 +441,6 @@ export class ActionExecutor { return err.result; } - const loggerId = actionTypeId.startsWith('.') ? actionTypeId.substring(1) : actionTypeId; - const logger = this.actionExecutorContext!.logger.get(loggerId); - if (span) { span.name = `${executeLabel} ${actionTypeId}`; span.addLabels({ diff --git a/x-pack/plugins/actions/server/lib/connector_metrics_collector.test.ts b/x-pack/plugins/actions/server/lib/connector_metrics_collector.test.ts index 09137fc1c6c87..8dff307452a94 100644 --- a/x-pack/plugins/actions/server/lib/connector_metrics_collector.test.ts +++ b/x-pack/plugins/actions/server/lib/connector_metrics_collector.test.ts @@ -7,10 +7,13 @@ import { ConnectorMetricsCollector } from '../types'; import { AxiosHeaders, AxiosResponse } from 'axios'; +import { loggingSystemMock } from '@kbn/core/server/mocks'; describe('ConnectorMetricsCollector', () => { + const logger = loggingSystemMock.createLogger(); + test('it collects requestBodyBytes from response.request.headers', async () => { - const connectorMetricsCollector = new ConnectorMetricsCollector(); + const connectorMetricsCollector = new ConnectorMetricsCollector(logger); const data = { test: 'foo' }; const contentLength = Buffer.byteLength(JSON.stringify(data), 'utf8'); @@ -34,7 +37,7 @@ describe('ConnectorMetricsCollector', () => { expect(connectorMetricsCollector.getRequestBodyByte()).toBe(contentLength + contentLength); }); test('it collects requestBodyBytes from data when response.request.headers is missing', async () => { - const connectorMetricsCollector = new ConnectorMetricsCollector(); + const connectorMetricsCollector = new ConnectorMetricsCollector(logger); const data = { test: 'foo' }; const contentLength = Buffer.byteLength(JSON.stringify(data), 'utf8'); @@ -54,4 +57,30 @@ describe('ConnectorMetricsCollector', () => { expect(connectorMetricsCollector.getRequestBodyByte()).toBe(contentLength + contentLength); }); + + test('it logs an error when the body cannot be stringified ', async () => { + const connectorMetricsCollector = new ConnectorMetricsCollector(logger); + + const data = { + name: 'arun', + }; + + // @ts-ignore + data.foo = data; // this is to force JSON.stringify to throw + + const axiosResponse: AxiosResponse = { + data, + status: 200, + statusText: 'OK', + headers: {}, + config: { headers: new AxiosHeaders() }, + }; + + connectorMetricsCollector.addRequestBodyBytes(axiosResponse, data); + + expect(logger.error).toHaveBeenCalledTimes(1); + expect(logger.error).toHaveBeenCalledWith( + expect.stringContaining("Request body bytes couldn't be calculated, Error: ") + ); + }); }); diff --git a/x-pack/plugins/actions/server/lib/connector_metrics_collector.ts b/x-pack/plugins/actions/server/lib/connector_metrics_collector.ts index 580ab70752f1b..eca16705f6880 100644 --- a/x-pack/plugins/actions/server/lib/connector_metrics_collector.ts +++ b/x-pack/plugins/actions/server/lib/connector_metrics_collector.ts @@ -6,6 +6,7 @@ */ import { AxiosError, AxiosResponse } from 'axios'; +import { Logger } from '@kbn/core/server'; interface ConnectorMetrics { requestBodyBytes: number; @@ -16,9 +17,27 @@ export class ConnectorMetricsCollector { requestBodyBytes: 0, }; + private logger: Logger; + + constructor(logger: Logger) { + this.logger = logger; + } + public addRequestBodyBytes(result?: AxiosError | AxiosResponse, body: string | object = '') { - const sBody = typeof body === 'string' ? body : JSON.stringify(body); - const bytes = result?.request?.headers?.['Content-Length'] || Buffer.byteLength(sBody, 'utf8'); + const contentLength = result?.request?.headers?.['Content-Length']; + let bytes = 0; + + if (!!contentLength) { + bytes = contentLength; + } else { + try { + const sBody = typeof body === 'string' ? body : JSON.stringify(body); + bytes = Buffer.byteLength(sBody, 'utf8'); + } catch (e) { + this.logger.error(`Request body bytes couldn't be calculated, Error: ${e.message}`); + } + } + this.metrics.requestBodyBytes = this.metrics.requestBodyBytes + bytes; } From a50e49e97594ff39ca180509edc80f8e9068e69a Mon Sep 17 00:00:00 2001 From: Ersin Erdal Date: Sat, 13 Jul 2024 17:15:49 +0200 Subject: [PATCH 08/25] Add logger to tests --- .../actions/server/lib/axios_utils.test.ts | 6 +- .../server/sub_action_framework/case.test.ts | 2 +- .../sub_action_framework/executor.test.ts | 2 +- .../sub_action_connector.test.ts | 2 +- .../connector_types/bedrock/bedrock.test.ts | 9 ++- .../cases_webhook/service.test.ts | 62 +++++++++++++++- .../crowdstrike/crowdstrike.test.ts | 5 +- .../d3security/d3security.test.ts | 5 +- .../connector_types/email/index.test.ts | 2 +- .../connector_types/email/send_email.test.ts | 2 +- .../email/send_email_graph_api.test.ts | 8 +- .../connector_types/es_index/index.test.ts | 2 +- .../connector_types/gemini/gemini.test.ts | 5 +- .../connector_types/jira/service.test.ts | 2 +- .../servicenow/create_service_wrapper.test.ts | 2 +- .../lib/servicenow/service.test.ts | 2 +- .../connector_types/openai/openai.test.ts | 5 +- .../opsgenie/connector.test.ts | 2 +- .../connector_types/pagerduty/index.test.ts | 2 +- .../resilient/resilient.test.ts | 5 +- .../sentinelone/sentinelone.test.ts | 4 +- .../connector_types/server_log/index.test.ts | 2 +- .../servicenow_itom/service.test.ts | 2 +- .../servicenow_itsm/service.test.ts | 2 +- .../servicenow_sir/service.test.ts | 2 +- .../connector_types/slack/index.test.ts | 2 +- .../connector_types/slack_api/index.test.ts | 2 +- .../connector_types/slack_api/service.test.ts | 2 +- .../connector_types/swimlane/service.test.ts | 2 +- .../connector_types/teams/index.test.ts | 50 ++++++++++++- .../connector_types/tines/tines.test.ts | 5 +- .../server/connector_types/torq/index.test.ts | 26 ++++++- .../connector_types/webhook/index.test.ts | 74 ++++++++++++++++++- .../connector_types/xmatters/index.test.ts | 2 +- 34 files changed, 261 insertions(+), 48 deletions(-) diff --git a/x-pack/plugins/actions/server/lib/axios_utils.test.ts b/x-pack/plugins/actions/server/lib/axios_utils.test.ts index a78a1b2537401..dd0bd086b987b 100644 --- a/x-pack/plugins/actions/server/lib/axios_utils.test.ts +++ b/x-pack/plugins/actions/server/lib/axios_utils.test.ts @@ -90,7 +90,7 @@ describe('request', () => { headers: { 'Content-Length': contentLength }, }, })); - const connectorMetricsCollector = new ConnectorMetricsCollector(); + const connectorMetricsCollector = new ConnectorMetricsCollector(logger); await request({ axios, url: '/test', @@ -111,7 +111,7 @@ describe('request', () => { headers: { 'Content-Length': contentLength }, }) ); - const connectorMetricsCollector = new ConnectorMetricsCollector(); + const connectorMetricsCollector = new ConnectorMetricsCollector(logger); try { await request({ @@ -127,7 +127,7 @@ describe('request', () => { }); test('adds request body bytes from data when request header does not exist', async () => { - const connectorMetricsCollector = new ConnectorMetricsCollector(); + const connectorMetricsCollector = new ConnectorMetricsCollector(logger); const data = { test: 12345 }; await request({ diff --git a/x-pack/plugins/actions/server/sub_action_framework/case.test.ts b/x-pack/plugins/actions/server/sub_action_framework/case.test.ts index c74adabca30e8..ca99260e36e07 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/case.test.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/case.test.ts @@ -60,7 +60,7 @@ describe('CaseConnector', () => { pushToServiceIncidentParamsSchema ); - connectorMetricsCollector = new ConnectorMetricsCollector(); + connectorMetricsCollector = new ConnectorMetricsCollector(logger); }); describe('Sub actions', () => { diff --git a/x-pack/plugins/actions/server/sub_action_framework/executor.test.ts b/x-pack/plugins/actions/server/sub_action_framework/executor.test.ts index d231e239103ed..bc23a273f29e5 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/executor.test.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/executor.test.ts @@ -57,7 +57,7 @@ describe('Executor', () => { logger = loggingSystemMock.createLogger(); services = actionsMock.createServices(); mockedActionsConfig = actionsConfigMock.create(); - connectorMetricsCollector = new ConnectorMetricsCollector(); + connectorMetricsCollector = new ConnectorMetricsCollector(logger); }); it('should execute correctly', async () => { diff --git a/x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.test.ts b/x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.test.ts index 19b595a85b509..d99b3ea4b9a13 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.test.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.test.ts @@ -73,7 +73,7 @@ describe('SubActionConnector', () => { services, }); - connectorMetricsCollector = new ConnectorMetricsCollector(); + connectorMetricsCollector = new ConnectorMetricsCollector(logger); }); describe('Sub actions', () => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.test.ts index 96a51d47f0988..22f0d2a766baf 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.test.ts @@ -38,6 +38,7 @@ describe('BedrockConnector', () => { completion: mockResponseString, stop_reason: 'stop_sequence', }; + const logger = loggingSystemMock.createLogger(); const claude3Response = { id: 'compl_01E7D3vTBHdNdKWCe6zALmLH', @@ -66,7 +67,7 @@ describe('BedrockConnector', () => { mockError = jest.fn().mockImplementation(() => { throw new Error('API Error'); }); - connectorMetricsCollector = new ConnectorMetricsCollector(); + connectorMetricsCollector = new ConnectorMetricsCollector(logger); }); const connector = new BedrockConnector({ @@ -77,7 +78,7 @@ describe('BedrockConnector', () => { defaultModel: DEFAULT_BEDROCK_MODEL, }, secrets: { accessKey: '123', secret: 'secret' }, - logger: loggingSystemMock.createLogger(), + logger, services: actionsMock.createServices(), }); @@ -89,7 +90,7 @@ describe('BedrockConnector', () => { describe('runApi', () => { it('the aws signature has non-streaming headers', async () => { - await connector.runApi({ body: DEFAULT_BODY }, new ConnectorMetricsCollector()); + await connector.runApi({ body: DEFAULT_BODY }, new ConnectorMetricsCollector(logger)); expect(mockSigner).toHaveBeenCalledWith( { body: DEFAULT_BODY, @@ -156,7 +157,7 @@ describe('BedrockConnector', () => { connector.request = mockError; await expect( - connector.runApi({ body: DEFAULT_BODY }, new ConnectorMetricsCollector()) + connector.runApi({ body: DEFAULT_BODY }, new ConnectorMetricsCollector(logger)) ).rejects.toThrow('API Error'); }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts index 7d1ea93b662db..cad8852ce49c4 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts @@ -76,7 +76,7 @@ describe('Cases webhook service', () => { let sslService: ExternalService; beforeAll(() => { - connectorMetricsCollector = new ConnectorMetricsCollector(); + connectorMetricsCollector = new ConnectorMetricsCollector(logger); service = createExternalService( actionId, { @@ -249,6 +249,18 @@ describe('Cases webhook service', () => { Object { "axios": [Function], "connectorMetricsCollector": ConnectorMetricsCollector { + "logger": Object { + "context": Array [], + "debug": [MockFunction], + "error": [MockFunction], + "fatal": [MockFunction], + "get": [MockFunction], + "info": [MockFunction], + "isLevelEnabled": [MockFunction], + "log": [MockFunction], + "trace": [MockFunction], + "warn": [MockFunction], + }, "metrics": Object { "requestBodyBytes": 0, }, @@ -527,6 +539,30 @@ describe('Cases webhook service', () => { Object { "axios": [Function], "connectorMetricsCollector": ConnectorMetricsCollector { + "logger": Object { + "context": Array [], + "debug": [MockFunction] { + "calls": Array [ + Array [ + "response from webhook action \\"1234\\": [HTTP 200] OK", + ], + ], + "results": Array [ + Object { + "type": "return", + "value": undefined, + }, + ], + }, + "error": [MockFunction], + "fatal": [MockFunction], + "get": [MockFunction], + "info": [MockFunction], + "isLevelEnabled": [MockFunction], + "log": [MockFunction], + "trace": [MockFunction], + "warn": [MockFunction], + }, "metrics": Object { "requestBodyBytes": 0, }, @@ -799,6 +835,18 @@ describe('Cases webhook service', () => { Object { "axios": [Function], "connectorMetricsCollector": ConnectorMetricsCollector { + "logger": Object { + "context": Array [], + "debug": [MockFunction], + "error": [MockFunction], + "fatal": [MockFunction], + "get": [MockFunction], + "info": [MockFunction], + "isLevelEnabled": [MockFunction], + "log": [MockFunction], + "trace": [MockFunction], + "warn": [MockFunction], + }, "metrics": Object { "requestBodyBytes": 0, }, @@ -1033,6 +1081,18 @@ describe('Cases webhook service', () => { Object { "axios": [Function], "connectorMetricsCollector": ConnectorMetricsCollector { + "logger": Object { + "context": Array [], + "debug": [MockFunction], + "error": [MockFunction], + "fatal": [MockFunction], + "get": [MockFunction], + "info": [MockFunction], + "isLevelEnabled": [MockFunction], + "log": [MockFunction], + "trace": [MockFunction], + "warn": [MockFunction], + }, "metrics": Object { "requestBodyBytes": 0, }, diff --git a/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.test.ts index 1eb1d89d09c6a..2daab8c04cc2a 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.test.ts @@ -17,12 +17,13 @@ const hostPath = 'https://api.crowdstrike.com/devices/entities/devices/v2'; const onlineStatusPath = 'https://api.crowdstrike.com/devices/entities/online-state/v1'; const actionsPath = 'https://api.crowdstrike.com/devices/entities/devices-actions/v2'; describe('CrowdstrikeConnector', () => { + const logger = loggingSystemMock.createLogger(); const connector = new CrowdstrikeConnector({ configurationUtilities: actionsConfigMock.create(), connector: { id: '1', type: CROWDSTRIKE_CONNECTOR_ID }, config: { url: 'https://api.crowdstrike.com' }, secrets: { clientId: '123', clientSecret: 'secret' }, - logger: loggingSystemMock.createLogger(), + logger, services: actionsMock.createServices(), }); let mockedRequest: jest.Mock; @@ -33,7 +34,7 @@ describe('CrowdstrikeConnector', () => { CrowdstrikeConnector.token = null; // @ts-expect-error mockedRequest = connector.request = jest.fn() as jest.Mock; - connectorMetricsCollector = new ConnectorMetricsCollector(); + connectorMetricsCollector = new ConnectorMetricsCollector(logger); }); afterEach(() => { jest.clearAllMocks(); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.test.ts index 4dd4fdcf7abcf..492d19e5be02b 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.test.ts @@ -29,6 +29,7 @@ describe('D3SecurityConnector', () => { const mockError = jest.fn().mockImplementation(() => { throw new Error('API Error'); }); + const logger = loggingSystemMock.createLogger(); describe('D3 Security', () => { const connector = new D3SecurityConnector({ @@ -36,7 +37,7 @@ describe('D3SecurityConnector', () => { connector: { id: '1', type: D3_SECURITY_CONNECTOR_ID }, config: { url: 'https://example.com/api' }, secrets: { token: '123' }, - logger: loggingSystemMock.createLogger(), + logger, services: actionsMock.createServices(), }); let connectorMetricsCollector: ConnectorMetricsCollector; @@ -45,7 +46,7 @@ describe('D3SecurityConnector', () => { // @ts-ignore connector.request = mockRequest; jest.clearAllMocks(); - connectorMetricsCollector = new ConnectorMetricsCollector(); + connectorMetricsCollector = new ConnectorMetricsCollector(logger); }); it('the D3 Security API call is successful with correct parameters', async () => { const response = await connector.runApi({ body: sampleBody }, connectorMetricsCollector); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/email/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/email/index.test.ts index 3a2c670a9ebb7..11afd240bddb7 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/email/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/email/index.test.ts @@ -515,7 +515,7 @@ describe('execute()', () => { text: 'Go to Elastic', }, }; - const connectorMetricsCollector = new ConnectorMetricsCollector(); + const connectorMetricsCollector = new ConnectorMetricsCollector(mockedLogger); const actionId = 'some-id'; const executorOptions: EmailConnectorTypeExecutorOptions = { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.test.ts index 573cd732bd01d..d9a3cbf8489b4 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.test.ts @@ -55,7 +55,7 @@ describe('send_email module', () => { }; }); - connectorMetricsCollector = new ConnectorMetricsCollector(); + connectorMetricsCollector = new ConnectorMetricsCollector(mockLogger); }); test('handles authenticated email using service', async () => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.test.ts index ef4e088dd2dab..59f7874af4f1f 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.test.ts @@ -28,7 +28,7 @@ describe('sendEmailGraphApi', () => { const configurationUtilities = actionsConfigMock.create(); test('email contains the proper message', async () => { - const connectorMetricsCollector = new ConnectorMetricsCollector(); + const connectorMetricsCollector = new ConnectorMetricsCollector(logger); axiosInstanceMock.mockReturnValueOnce({ status: 202, @@ -121,7 +121,7 @@ describe('sendEmailGraphApi', () => { }); test('email was sent on behalf of the user "from" mailbox', async () => { - const connectorMetricsCollector = new ConnectorMetricsCollector(); + const connectorMetricsCollector = new ConnectorMetricsCollector(logger); axiosInstanceMock.mockReturnValueOnce({ status: 202, }); @@ -215,7 +215,7 @@ describe('sendEmailGraphApi', () => { }); test('sendMail request was sent to the custom configured Graph API URL', async () => { - const connectorMetricsCollector = new ConnectorMetricsCollector(); + const connectorMetricsCollector = new ConnectorMetricsCollector(logger); axiosInstanceMock.mockReturnValueOnce({ status: 202, }); @@ -308,7 +308,7 @@ describe('sendEmailGraphApi', () => { }); test('throw the exception and log the proper error if message was not sent successfuly', async () => { - const connectorMetricsCollector = new ConnectorMetricsCollector(); + const connectorMetricsCollector = new ConnectorMetricsCollector(logger); axiosInstanceMock.mockReturnValueOnce({ status: 400, data: { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/es_index/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/es_index/index.test.ts index 636cbd8596027..700a95e30b7e8 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/es_index/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/es_index/index.test.ts @@ -37,7 +37,7 @@ beforeEach(() => { jest.resetAllMocks(); configurationUtilities = actionsConfigMock.create(); connectorType = getConnectorType(); - connectorMetricsCollector = new ConnectorMetricsCollector(); + connectorMetricsCollector = new ConnectorMetricsCollector(mockedLogger); }); describe('connector registration', () => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.test.ts index 85fa03faf345b..2150aa7c68f99 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.test.ts @@ -62,6 +62,7 @@ describe('GeminiConnector', () => { mockRequest = connector.request = jest.fn().mockResolvedValue(defaultResponse); }); + const logger = loggingSystemMock.createLogger(); const connector = new GeminiConnector({ connector: { id: '1', type: '.gemini' }, configurationUtilities: actionsConfigMock.create(), @@ -85,7 +86,7 @@ describe('GeminiConnector', () => { client_x509_cert_url: '', }), }, - logger: loggingSystemMock.createLogger(), + logger, services: actionsMock.createServices(), }); let connectorMetricsCollector: ConnectorMetricsCollector; @@ -94,7 +95,7 @@ describe('GeminiConnector', () => { beforeEach(() => { // @ts-ignore connector.request = mockRequest; - connectorMetricsCollector = new ConnectorMetricsCollector(); + connectorMetricsCollector = new ConnectorMetricsCollector(logger); }); describe('runApi', () => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/jira/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/jira/service.test.ts index 74091388eee5f..68abc0d29162c 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/jira/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/jira/service.test.ts @@ -139,7 +139,7 @@ describe('Jira service', () => { let connectorMetricsCollector: ConnectorMetricsCollector; beforeAll(() => { - connectorMetricsCollector = new ConnectorMetricsCollector(); + connectorMetricsCollector = new ConnectorMetricsCollector(logger); service = createExternalService( { // The trailing slash at the end of the url is intended. diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/create_service_wrapper.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/create_service_wrapper.test.ts index 9f984de648ae9..bf1c4777ef9a5 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/create_service_wrapper.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/create_service_wrapper.test.ts @@ -25,7 +25,7 @@ let connectorMetricsCollector: ConnectorMetricsCollector; describe('createServiceWrapper', () => { beforeEach(() => { jest.clearAllMocks(); - connectorMetricsCollector = new ConnectorMetricsCollector(); + connectorMetricsCollector = new ConnectorMetricsCollector(logger); }); test('creates axios instance with apiUrl', () => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.test.ts index 58ac9f19a5176..586ffa0e955a6 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.test.ts @@ -212,7 +212,7 @@ describe('ServiceNow service', () => { beforeEach(() => { jest.clearAllMocks(); - connectorMetricsCollector = new ConnectorMetricsCollector(); + connectorMetricsCollector = new ConnectorMetricsCollector(logger); service = createExternalService({ credentials: { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.test.ts index ea0b48e116832..3662ae506252f 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.test.ts @@ -49,6 +49,7 @@ describe('OpenAIConnector', () => { let mockError: jest.Mock; let connectorMetricsCollector: ConnectorMetricsCollector; + const logger = loggingSystemMock.createLogger(); const mockResponseString = 'Hello! How can I assist you today?'; const mockResponse = { headers: {}, @@ -75,7 +76,7 @@ describe('OpenAIConnector', () => { }, }; beforeEach(() => { - connectorMetricsCollector = new ConnectorMetricsCollector(); + connectorMetricsCollector = new ConnectorMetricsCollector(logger); mockRequest = jest.fn().mockResolvedValue(mockResponse); mockError = jest.fn().mockImplementation(() => { throw new Error('API Error'); @@ -96,7 +97,7 @@ describe('OpenAIConnector', () => { }, }, secrets: { apiKey: '123' }, - logger: loggingSystemMock.createLogger(), + logger, services: actionsMock.createServices(), }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.test.ts index 98f98c4c79d33..8740eb3c79ded 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.test.ts @@ -77,7 +77,7 @@ describe('OpsgenieConnector', () => { logger, services, }); - connectorMetricsCollector = new ConnectorMetricsCollector(); + connectorMetricsCollector = new ConnectorMetricsCollector(logger); }); it('calls request with the correct arguments for creating an alert', async () => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.test.ts index 770bdca23d25d..40ff5f9a5c051 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.test.ts @@ -36,7 +36,7 @@ let connectorMetricsCollector: ConnectorMetricsCollector; beforeEach(() => { configurationUtilities = actionsConfigMock.create(); connectorType = getConnectorType(); - connectorMetricsCollector = new ConnectorMetricsCollector(); + connectorMetricsCollector = new ConnectorMetricsCollector(mockedLogger); }); describe('get()', () => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.test.ts index 7a2cb567cdf8b..d4a517ed851d7 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.test.ts @@ -87,11 +87,12 @@ const mockIncidentUpdate = (withUpdateError = false) => { let connectorMetricsCollector: ConnectorMetricsCollector; describe('IBM Resilient connector', () => { + const logger = loggingSystemMock.createLogger(); const connector = new ResilientConnector( { connector: { id: '1', type: RESILIENT_CONNECTOR_ID }, configurationUtilities: actionsConfigMock.create(), - logger: loggingSystemMock.createLogger(), + logger, services: actionsMock.createServices(), config: { orgId, apiUrl }, secrets: { apiKeyId, apiKeySecret }, @@ -109,7 +110,7 @@ describe('IBM Resilient connector', () => { beforeEach(() => { jest.resetAllMocks(); jest.setSystemTime(TIMESTAMP); - connectorMetricsCollector = new ConnectorMetricsCollector(); + connectorMetricsCollector = new ConnectorMetricsCollector(logger); }); describe('getIncident', () => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.test.ts index 80bd1fcb9a816..f2f2186607808 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.test.ts @@ -14,14 +14,16 @@ import { import { API_PATH } from './sentinelone'; import { SentinelOneGetActivitiesResponseSchema } from '../../../common/sentinelone/schema'; import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; +import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; describe('SentinelOne Connector', () => { let connectorInstance: ReturnType; let connectorMetricsCollector: ConnectorMetricsCollector; + const logger = loggingSystemMock.createLogger(); beforeEach(() => { connectorInstance = sentinelOneConnectorMocks.create(); - connectorMetricsCollector = new ConnectorMetricsCollector(); + connectorMetricsCollector = new ConnectorMetricsCollector(logger); }); describe('#fetchAgentFiles()', () => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/server_log/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/server_log/index.test.ts index fd819854b1ccb..5aeae506bac02 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/server_log/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/server_log/index.test.ts @@ -107,7 +107,7 @@ describe('execute()', () => { secrets: {}, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector: new ConnectorMetricsCollector(), + connectorMetricsCollector: new ConnectorMetricsCollector(mockedLogger), }; await connectorType.executor(executorOptions); expect(mockedLogger.info).toHaveBeenCalledWith('Server log: message text here'); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.test.ts index 2dafe4f83be60..2de375094bb33 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.test.ts @@ -37,7 +37,7 @@ describe('ServiceNow SIR service', () => { let connectorMetricsCollector: ConnectorMetricsCollector; beforeEach(() => { - connectorMetricsCollector = new ConnectorMetricsCollector(); + connectorMetricsCollector = new ConnectorMetricsCollector(logger); service = createExternalService({ credentials: { config: { apiUrl: 'https://example.com/', isOAuth: false }, diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/service.test.ts index 8bc567dde9bc5..28181071ee214 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/service.test.ts @@ -156,7 +156,7 @@ describe('ServiceNow service', () => { beforeEach(() => { jest.clearAllMocks(); - connectorMetricsCollector = new ConnectorMetricsCollector(); + connectorMetricsCollector = new ConnectorMetricsCollector(logger); service = createExternalService({ credentials: { // The trailing slash at the end of the url is intended. diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.test.ts index cb590d85f6298..ff3152f33f1c6 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.test.ts @@ -96,7 +96,7 @@ describe('ServiceNow SIR service', () => { let service: ExternalServiceSIR; beforeEach(() => { - connectorMetricsCollector = new ConnectorMetricsCollector(); + connectorMetricsCollector = new ConnectorMetricsCollector(logger); service = createExternalService({ credentials: { config: { apiUrl: 'https://example.com/', isOAuth: false }, diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack/index.test.ts index aa08139915739..fc89378993a56 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack/index.test.ts @@ -45,7 +45,7 @@ beforeEach(() => { return { status: 'ok', actionId: options.actionId }; }, }); - connectorMetricsCollector = new ConnectorMetricsCollector(); + connectorMetricsCollector = new ConnectorMetricsCollector(mockedLogger); }); describe('connector registration', () => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.test.ts index 6f183f9988516..c34dcec01f716 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.test.ts @@ -44,7 +44,7 @@ let connectorMetricsCollector: ConnectorMetricsCollector; beforeEach(() => { configurationUtilities = actionsConfigMock.create(); connectorType = getConnectorType(); - connectorMetricsCollector = new ConnectorMetricsCollector(); + connectorMetricsCollector = new ConnectorMetricsCollector(mockedLogger); }); describe('connector registration', () => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.test.ts index 4befb126fe14f..836e6bdbe5ce7 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.test.ts @@ -119,7 +119,7 @@ describe('Slack API service', () => { let service: SlackApiService; beforeAll(() => { - connectorMetricsCollector = new ConnectorMetricsCollector(); + connectorMetricsCollector = new ConnectorMetricsCollector(logger); service = createExternalService( { secrets: { token: 'token' }, diff --git a/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.test.ts index 2b17e1b480783..84430fb81c39e 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.test.ts @@ -60,7 +60,7 @@ describe('Swimlane Service', () => { let connectorMetricsCollector: ConnectorMetricsCollector; beforeAll(() => { - connectorMetricsCollector = new ConnectorMetricsCollector(); + connectorMetricsCollector = new ConnectorMetricsCollector(logger); service = createExternalService( { // The trailing slash at the end of the url is intended. diff --git a/x-pack/plugins/stack_connectors/server/connector_types/teams/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/teams/index.test.ts index ac88dfadf60db..0701118e6ef40 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/teams/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/teams/index.test.ts @@ -39,7 +39,7 @@ let connectorMetricsCollector: ConnectorMetricsCollector; beforeEach(() => { configurationUtilities = actionsConfigMock.create(); connectorType = getConnectorType(); - connectorMetricsCollector = new ConnectorMetricsCollector(); + connectorMetricsCollector = new ConnectorMetricsCollector(mockedLogger); }); describe('connector registration', () => { @@ -176,6 +176,30 @@ describe('execute()', () => { Object { "axios": undefined, "connectorMetricsCollector": ConnectorMetricsCollector { + "logger": Object { + "context": Array [], + "debug": [MockFunction] { + "calls": Array [ + Array [ + "response from teams action \\"some-id\\": [HTTP 200] ", + ], + ], + "results": Array [ + Object { + "type": "return", + "value": undefined, + }, + ], + }, + "error": [MockFunction], + "fatal": [MockFunction], + "get": [MockFunction], + "info": [MockFunction], + "isLevelEnabled": [MockFunction], + "log": [MockFunction], + "trace": [MockFunction], + "warn": [MockFunction], + }, "metrics": Object { "requestBodyBytes": 0, }, @@ -238,6 +262,30 @@ describe('execute()', () => { Object { "axios": undefined, "connectorMetricsCollector": ConnectorMetricsCollector { + "logger": Object { + "context": Array [], + "debug": [MockFunction] { + "calls": Array [ + Array [ + "response from teams action \\"some-id\\": [HTTP 200] ", + ], + ], + "results": Array [ + Object { + "type": "return", + "value": undefined, + }, + ], + }, + "error": [MockFunction], + "fatal": [MockFunction], + "get": [MockFunction], + "info": [MockFunction], + "isLevelEnabled": [MockFunction], + "log": [MockFunction], + "trace": [MockFunction], + "warn": [MockFunction], + }, "metrics": Object { "requestBodyBytes": 0, }, diff --git a/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.test.ts index c6c6e02e2c4de..ba8b92398c95c 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.test.ts @@ -99,18 +99,19 @@ const agentsGetRequestExpected = { let connectorMetricsCollector: ConnectorMetricsCollector; describe('TinesConnector', () => { + const logger = loggingSystemMock.createLogger(); const connector = new TinesConnector({ configurationUtilities: actionsConfigMock.create(), config: { url }, connector: { id: '1', type: TINES_CONNECTOR_ID }, secrets: { email, token }, - logger: loggingSystemMock.createLogger(), + logger, services: actionsMock.createServices(), }); beforeEach(() => { jest.clearAllMocks(); - connectorMetricsCollector = new ConnectorMetricsCollector(); + connectorMetricsCollector = new ConnectorMetricsCollector(logger); }); describe('getStories', () => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/torq/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/torq/index.test.ts index 35dabb66c9002..f76029f4b2bb1 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/torq/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/torq/index.test.ts @@ -47,7 +47,7 @@ let connectorMetricsCollector: ConnectorMetricsCollector; beforeAll(() => { actionType = getActionType(); configurationUtilities = actionsConfigMock.create(); - connectorMetricsCollector = new ConnectorMetricsCollector(); + connectorMetricsCollector = new ConnectorMetricsCollector(mockedLogger); }); describe('actionType', () => { @@ -186,6 +186,30 @@ describe('execute Torq action', () => { Object { "axios": [MockFunction], "connectorMetricsCollector": ConnectorMetricsCollector { + "logger": Object { + "context": Array [], + "debug": [MockFunction] { + "calls": Array [ + Array [ + "response from Torq action \\"some-id\\": [HTTP 200] ", + ], + ], + "results": Array [ + Object { + "type": "return", + "value": undefined, + }, + ], + }, + "error": [MockFunction], + "fatal": [MockFunction], + "get": [MockFunction], + "info": [MockFunction], + "isLevelEnabled": [MockFunction], + "log": [MockFunction], + "trace": [MockFunction], + "warn": [MockFunction], + }, "metrics": Object { "requestBodyBytes": 0, }, diff --git a/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.test.ts index 8bb52b90d309a..a2c0097346391 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.test.ts @@ -46,7 +46,7 @@ let connectorMetricsCollector: ConnectorMetricsCollector; beforeEach(() => { configurationUtilities = actionsConfigMock.create(); connectorType = getConnectorType(); - connectorMetricsCollector = new ConnectorMetricsCollector(); + connectorMetricsCollector = new ConnectorMetricsCollector(mockedLogger); }); describe('connectorType', () => { @@ -349,6 +349,30 @@ describe('execute()', () => { Object { "axios": undefined, "connectorMetricsCollector": ConnectorMetricsCollector { + "logger": Object { + "context": Array [], + "debug": [MockFunction] { + "calls": Array [ + Array [ + "response from webhook action \\"some-id\\": [HTTP 200] ", + ], + ], + "results": Array [ + Object { + "type": "return", + "value": undefined, + }, + ], + }, + "error": [MockFunction], + "fatal": [MockFunction], + "get": [MockFunction], + "info": [MockFunction], + "isLevelEnabled": [MockFunction], + "log": [MockFunction], + "trace": [MockFunction], + "warn": [MockFunction], + }, "metrics": Object { "requestBodyBytes": 0, }, @@ -417,6 +441,30 @@ describe('execute()', () => { Object { "axios": undefined, "connectorMetricsCollector": ConnectorMetricsCollector { + "logger": Object { + "context": Array [], + "debug": [MockFunction] { + "calls": Array [ + Array [ + "response from webhook action \\"some-id\\": [HTTP 200] ", + ], + ], + "results": Array [ + Object { + "type": "return", + "value": undefined, + }, + ], + }, + "error": [MockFunction], + "fatal": [MockFunction], + "get": [MockFunction], + "info": [MockFunction], + "isLevelEnabled": [MockFunction], + "log": [MockFunction], + "trace": [MockFunction], + "warn": [MockFunction], + }, "metrics": Object { "requestBodyBytes": 0, }, @@ -641,6 +689,30 @@ describe('execute()', () => { Object { "axios": undefined, "connectorMetricsCollector": ConnectorMetricsCollector { + "logger": Object { + "context": Array [], + "debug": [MockFunction] { + "calls": Array [ + Array [ + "response from webhook action \\"some-id\\": [HTTP 200] ", + ], + ], + "results": Array [ + Object { + "type": "return", + "value": undefined, + }, + ], + }, + "error": [MockFunction], + "fatal": [MockFunction], + "get": [MockFunction], + "info": [MockFunction], + "isLevelEnabled": [MockFunction], + "log": [MockFunction], + "trace": [MockFunction], + "warn": [MockFunction], + }, "metrics": Object { "requestBodyBytes": 0, }, diff --git a/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.test.ts index 5bb69deba4fa1..5d1b27af98401 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.test.ts @@ -50,7 +50,7 @@ let connectorMetricsCollector: ConnectorMetricsCollector; beforeEach(() => { configurationUtilities = actionsConfigMock.create(); connectorType = getConnectorType(); - connectorMetricsCollector = new ConnectorMetricsCollector(); + connectorMetricsCollector = new ConnectorMetricsCollector(mockedLogger); }); describe('connectorType', () => { From 159143d108449663cf5d868e73f2f5cd7d3d3de8 Mon Sep 17 00:00:00 2001 From: Ersin Erdal Date: Wed, 7 Aug 2024 14:04:08 +0300 Subject: [PATCH 09/25] add connector id to log --- .../server/lib/action_executor.test.ts | 15 +- .../actions/server/lib/action_executor.ts | 5 +- .../actions/server/lib/axios_utils.test.ts | 15 +- .../plugins/actions/server/lib/axios_utils.ts | 2 +- .../lib/connector_metrics_collector.test.ts | 24 ++- .../server/lib/connector_metrics_collector.ts | 13 +- .../server/sub_action_framework/case.test.ts | 5 +- .../sub_action_framework/executor.test.ts | 5 +- .../sub_action_connector.test.ts | 5 +- .../connector_types/bedrock/bedrock.test.ts | 21 ++- .../server/connector_types/bedrock/bedrock.ts | 61 ++++--- .../cases_webhook/service.test.ts | 5 +- .../crowdstrike/crowdstrike.test.ts | 5 +- .../d3security/d3security.test.ts | 5 +- .../connector_types/email/index.test.ts | 5 +- .../connector_types/email/send_email.test.ts | 5 +- .../email/send_email_graph_api.test.ts | 20 ++- .../connector_types/es_index/index.test.ts | 5 +- .../connector_types/gemini/gemini.test.ts | 15 +- .../server/connector_types/gemini/gemini.ts | 50 +++--- .../connector_types/jira/service.test.ts | 5 +- .../servicenow/create_service_wrapper.test.ts | 5 +- .../lib/servicenow/service.test.ts | 5 +- .../connector_types/openai/openai.test.ts | 5 +- .../opsgenie/connector.test.ts | 5 +- .../connector_types/pagerduty/index.test.ts | 5 +- .../resilient/resilient.test.ts | 5 +- .../sentinelone/sentinelone.test.ts | 20 ++- .../sentinelone/sentinelone.ts | 5 +- .../connector_types/server_log/index.test.ts | 5 +- .../servicenow_itom/service.test.ts | 5 +- .../servicenow_itsm/service.test.ts | 5 +- .../servicenow_sir/service.test.ts | 5 +- .../connector_types/slack/index.test.ts | 5 +- .../connector_types/slack_api/index.test.ts | 5 +- .../connector_types/slack_api/service.test.ts | 5 +- .../connector_types/swimlane/service.test.ts | 5 +- .../connector_types/teams/index.test.ts | 5 +- .../connector_types/thehive/thehive.test.ts | 156 +++++++++++------- .../server/connector_types/thehive/thehive.ts | 119 ++++++++----- .../connector_types/tines/tines.test.ts | 5 +- .../server/connector_types/torq/index.test.ts | 90 +++------- .../connector_types/webhook/index.test.ts | 86 +++------- .../connector_types/xmatters/index.test.ts | 5 +- .../tests/actions/connector_types/openai.ts | 2 +- 45 files changed, 506 insertions(+), 348 deletions(-) diff --git a/x-pack/plugins/actions/server/lib/action_executor.test.ts b/x-pack/plugins/actions/server/lib/action_executor.test.ts index 0a6945b055f5c..f4bec07701099 100644 --- a/x-pack/plugins/actions/server/lib/action_executor.test.ts +++ b/x-pack/plugins/actions/server/lib/action_executor.test.ts @@ -152,7 +152,11 @@ const connectorSavedObject = { references: [], }; -const getBaseExecuteStartEventLogDoc = (unsecured: boolean) => { +interface ActionMetrics { + request_body_bytes: number; +} + +const getBaseExecuteStartEventLogDoc = (unsecured: boolean, actionMetrics?: ActionMetrics) => { return { event: { action: 'execute-start', @@ -162,6 +166,7 @@ const getBaseExecuteStartEventLogDoc = (unsecured: boolean) => { action: { execution: { uuid: ACTION_EXECUTION_ID, + ...(actionMetrics ? { metrics: actionMetrics } : {}), }, id: CONNECTOR_ID, name: '1', @@ -193,8 +198,8 @@ const getBaseExecuteStartEventLogDoc = (unsecured: boolean) => { }; }; -const getBaseExecuteEventLogDoc = (unsecured: boolean) => { - const base = getBaseExecuteStartEventLogDoc(unsecured); +const getBaseExecuteEventLogDoc = (unsecured: boolean, actionMetrics?: ActionMetrics) => { + const base = getBaseExecuteStartEventLogDoc(unsecured, actionMetrics); return { ...base, event: { @@ -294,8 +299,8 @@ describe('Action Executor', () => { expect(eventLogger.logEvent).toHaveBeenCalledTimes(2); const execStartDoc = getBaseExecuteStartEventLogDoc(executeUnsecure); - const execDoc = getBaseExecuteEventLogDoc(executeUnsecure); - addConnectorMetrics(execDoc, 0); + const execDoc = getBaseExecuteEventLogDoc(executeUnsecure, { request_body_bytes: 300 }); + addConnectorMetrics(execDoc, 300); expect(eventLogger.logEvent).toHaveBeenNthCalledWith(1, execStartDoc); expect(eventLogger.logEvent).toHaveBeenNthCalledWith(2, execDoc); }); diff --git a/x-pack/plugins/actions/server/lib/action_executor.ts b/x-pack/plugins/actions/server/lib/action_executor.ts index 054df88f1d757..4e9ddd4559dd3 100644 --- a/x-pack/plugins/actions/server/lib/action_executor.ts +++ b/x-pack/plugins/actions/server/lib/action_executor.ts @@ -399,7 +399,10 @@ export class ActionExecutor { const loggerId = actionTypeId.startsWith('.') ? actionTypeId.substring(1) : actionTypeId; const logger = this.actionExecutorContext!.logger.get(loggerId); - const connectorMetricsCollector = new ConnectorMetricsCollector(logger); + const connectorMetricsCollector = new ConnectorMetricsCollector({ + logger, + connectorId: actionId, + }); if (!this.actionInfo || this.actionInfo.actionId !== actionId) { this.actionInfo = actionInfo; diff --git a/x-pack/plugins/actions/server/lib/axios_utils.test.ts b/x-pack/plugins/actions/server/lib/axios_utils.test.ts index dd0bd086b987b..131bb7a32e274 100644 --- a/x-pack/plugins/actions/server/lib/axios_utils.test.ts +++ b/x-pack/plugins/actions/server/lib/axios_utils.test.ts @@ -90,7 +90,10 @@ describe('request', () => { headers: { 'Content-Length': contentLength }, }, })); - const connectorMetricsCollector = new ConnectorMetricsCollector(logger); + const connectorMetricsCollector = new ConnectorMetricsCollector({ + logger, + connectorId: 'test-connector-id', + }); await request({ axios, url: '/test', @@ -111,7 +114,10 @@ describe('request', () => { headers: { 'Content-Length': contentLength }, }) ); - const connectorMetricsCollector = new ConnectorMetricsCollector(logger); + const connectorMetricsCollector = new ConnectorMetricsCollector({ + logger, + connectorId: 'test-connector-id', + }); try { await request({ @@ -127,7 +133,10 @@ describe('request', () => { }); test('adds request body bytes from data when request header does not exist', async () => { - const connectorMetricsCollector = new ConnectorMetricsCollector(logger); + const connectorMetricsCollector = new ConnectorMetricsCollector({ + logger, + connectorId: 'test-connector-id', + }); const data = { test: 12345 }; await request({ diff --git a/x-pack/plugins/actions/server/lib/axios_utils.ts b/x-pack/plugins/actions/server/lib/axios_utils.ts index f1a361ad18b2b..2782d4bd9cfb6 100644 --- a/x-pack/plugins/actions/server/lib/axios_utils.ts +++ b/x-pack/plugins/actions/server/lib/axios_utils.ts @@ -42,7 +42,7 @@ export const request = async ({ headers?: Record; timeout?: number; sslOverrides?: SSLSettings; - connectorMetricsCollector?: ConnectorMetricsCollector; // TODO make optional + connectorMetricsCollector?: ConnectorMetricsCollector; } & AxiosRequestConfig): Promise => { if (!isEmpty(axios?.defaults?.baseURL ?? '')) { throw new Error( diff --git a/x-pack/plugins/actions/server/lib/connector_metrics_collector.test.ts b/x-pack/plugins/actions/server/lib/connector_metrics_collector.test.ts index 8dff307452a94..00d5dd4af1105 100644 --- a/x-pack/plugins/actions/server/lib/connector_metrics_collector.test.ts +++ b/x-pack/plugins/actions/server/lib/connector_metrics_collector.test.ts @@ -13,7 +13,10 @@ describe('ConnectorMetricsCollector', () => { const logger = loggingSystemMock.createLogger(); test('it collects requestBodyBytes from response.request.headers', async () => { - const connectorMetricsCollector = new ConnectorMetricsCollector(logger); + const connectorMetricsCollector = new ConnectorMetricsCollector({ + logger, + connectorId: 'test-connector-id', + }); const data = { test: 'foo' }; const contentLength = Buffer.byteLength(JSON.stringify(data), 'utf8'); @@ -25,6 +28,7 @@ describe('ConnectorMetricsCollector', () => { config: { headers: new AxiosHeaders() }, request: { headers: { 'Content-Length': contentLength }, + getHeader: () => contentLength, }, }; @@ -36,8 +40,11 @@ describe('ConnectorMetricsCollector', () => { expect(connectorMetricsCollector.getRequestBodyByte()).toBe(contentLength + contentLength); }); - test('it collects requestBodyBytes from data when response.request.headers is missing', async () => { - const connectorMetricsCollector = new ConnectorMetricsCollector(logger); + test('it collects requestBodyBytes from data when header is is missing', async () => { + const connectorMetricsCollector = new ConnectorMetricsCollector({ + logger, + connectorId: 'test-connector-id', + }); const data = { test: 'foo' }; const contentLength = Buffer.byteLength(JSON.stringify(data), 'utf8'); @@ -47,6 +54,9 @@ describe('ConnectorMetricsCollector', () => { statusText: 'OK', headers: {}, config: { headers: new AxiosHeaders() }, + request: { + getHeader: () => undefined, + }, }; connectorMetricsCollector.addRequestBodyBytes(axiosResponse, data); @@ -59,7 +69,10 @@ describe('ConnectorMetricsCollector', () => { }); test('it logs an error when the body cannot be stringified ', async () => { - const connectorMetricsCollector = new ConnectorMetricsCollector(logger); + const connectorMetricsCollector = new ConnectorMetricsCollector({ + logger, + connectorId: 'test-connector-id', + }); const data = { name: 'arun', @@ -74,6 +87,9 @@ describe('ConnectorMetricsCollector', () => { statusText: 'OK', headers: {}, config: { headers: new AxiosHeaders() }, + request: { + getHeader: () => undefined, + }, }; connectorMetricsCollector.addRequestBodyBytes(axiosResponse, data); diff --git a/x-pack/plugins/actions/server/lib/connector_metrics_collector.ts b/x-pack/plugins/actions/server/lib/connector_metrics_collector.ts index eca16705f6880..b9ad88abe464d 100644 --- a/x-pack/plugins/actions/server/lib/connector_metrics_collector.ts +++ b/x-pack/plugins/actions/server/lib/connector_metrics_collector.ts @@ -7,34 +7,39 @@ import { AxiosError, AxiosResponse } from 'axios'; import { Logger } from '@kbn/core/server'; +import { isUndefined } from 'lodash'; interface ConnectorMetrics { requestBodyBytes: number; } export class ConnectorMetricsCollector { + private connectorId: string; private metrics: ConnectorMetrics = { requestBodyBytes: 0, }; private logger: Logger; - constructor(logger: Logger) { + constructor({ logger, connectorId }: { logger: Logger; connectorId: string }) { this.logger = logger; + this.connectorId = connectorId; } public addRequestBodyBytes(result?: AxiosError | AxiosResponse, body: string | object = '') { - const contentLength = result?.request?.headers?.['Content-Length']; + const contentLength = result?.request.getHeader('content-length'); let bytes = 0; - if (!!contentLength) { + if (!isUndefined(contentLength)) { bytes = contentLength; } else { try { const sBody = typeof body === 'string' ? body : JSON.stringify(body); bytes = Buffer.byteLength(sBody, 'utf8'); } catch (e) { - this.logger.error(`Request body bytes couldn't be calculated, Error: ${e.message}`); + this.logger.error( + `Request body bytes couldn't be calculated, Error: ${e.message}, connectorId:${this.connectorId}` + ); } } diff --git a/x-pack/plugins/actions/server/sub_action_framework/case.test.ts b/x-pack/plugins/actions/server/sub_action_framework/case.test.ts index ca99260e36e07..3811d73e7000f 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/case.test.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/case.test.ts @@ -60,7 +60,10 @@ describe('CaseConnector', () => { pushToServiceIncidentParamsSchema ); - connectorMetricsCollector = new ConnectorMetricsCollector(logger); + connectorMetricsCollector = new ConnectorMetricsCollector({ + logger, + connectorId: 'test-connector-id', + }); }); describe('Sub actions', () => { diff --git a/x-pack/plugins/actions/server/sub_action_framework/executor.test.ts b/x-pack/plugins/actions/server/sub_action_framework/executor.test.ts index bc23a273f29e5..195b948c40db3 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/executor.test.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/executor.test.ts @@ -57,7 +57,10 @@ describe('Executor', () => { logger = loggingSystemMock.createLogger(); services = actionsMock.createServices(); mockedActionsConfig = actionsConfigMock.create(); - connectorMetricsCollector = new ConnectorMetricsCollector(logger); + connectorMetricsCollector = new ConnectorMetricsCollector({ + logger, + connectorId: 'test-connector-id', + }); }); it('should execute correctly', async () => { diff --git a/x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.test.ts b/x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.test.ts index d99b3ea4b9a13..ce52b718f8f97 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.test.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.test.ts @@ -73,7 +73,10 @@ describe('SubActionConnector', () => { services, }); - connectorMetricsCollector = new ConnectorMetricsCollector(logger); + connectorMetricsCollector = new ConnectorMetricsCollector({ + logger, + connectorId: 'test-connector-id', + }); }); describe('Sub actions', () => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.test.ts index 22f0d2a766baf..e56c269c12630 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.test.ts @@ -67,7 +67,10 @@ describe('BedrockConnector', () => { mockError = jest.fn().mockImplementation(() => { throw new Error('API Error'); }); - connectorMetricsCollector = new ConnectorMetricsCollector(logger); + connectorMetricsCollector = new ConnectorMetricsCollector({ + logger, + connectorId: 'test-connector-id', + }); }); const connector = new BedrockConnector({ @@ -90,7 +93,13 @@ describe('BedrockConnector', () => { describe('runApi', () => { it('the aws signature has non-streaming headers', async () => { - await connector.runApi({ body: DEFAULT_BODY }, new ConnectorMetricsCollector(logger)); + await connector.runApi( + { body: DEFAULT_BODY }, + new ConnectorMetricsCollector({ + logger, + connectorId: 'test-connector-id', + }) + ); expect(mockSigner).toHaveBeenCalledWith( { body: DEFAULT_BODY, @@ -157,7 +166,13 @@ describe('BedrockConnector', () => { connector.request = mockError; await expect( - connector.runApi({ body: DEFAULT_BODY }, new ConnectorMetricsCollector(logger)) + connector.runApi( + { body: DEFAULT_BODY }, + new ConnectorMetricsCollector({ + logger, + connectorId: 'test-connector-id', + }) + ) ).rejects.toThrow('API Error'); }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.ts b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.ts index 9b67af5111776..2cabf6c791b79 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.ts @@ -198,7 +198,7 @@ The Kibana Connector in use may need to be reconfigured with an updated Amazon B params: SubActionRequestParams, connectorMetricsCollector: ConnectorMetricsCollector ): Promise { - const response = await this.request(params); + const response = await this.request(params, connectorMetricsCollector); return response.data; } @@ -240,7 +240,10 @@ The Kibana Connector in use may need to be reconfigured with an updated Amazon B }; if (raw) { - return this.runApiRaw({ ...requestArgs, responseSchema: InvokeAIRawActionResponseSchema }); + return this.runApiRaw( + { ...requestArgs, responseSchema: InvokeAIRawActionResponseSchema }, + connectorMetricsCollector + ); } // possible api received deprecated arguments, which will still work with the deprecated Claude 2 models if (usesDeprecatedArguments(body)) { @@ -358,33 +361,39 @@ The Kibana Connector in use may need to be reconfigured with an updated Amazon B return { message: res.completion.trim() }; } - public async invokeAIRaw({ - messages, - model, - stopSequences, - system, - temperature, - maxTokens = DEFAULT_TOKEN_LIMIT, - signal, - timeout, - tools, - anthropicVersion, - }: InvokeAIRawActionParams): Promise { - const res = await this.runApi({ - body: JSON.stringify({ - messages, - stop_sequences: stopSequences, - system, - temperature, - max_tokens: maxTokens, - tools, - anthropic_version: anthropicVersion, - }), + public async invokeAIRaw( + { + messages, model, + stopSequences, + system, + temperature, + maxTokens = DEFAULT_TOKEN_LIMIT, signal, timeout, - raw: true, - }); + tools, + anthropicVersion, + }: InvokeAIRawActionParams, + connectorMetricsCollector: ConnectorMetricsCollector + ): Promise { + const res = await this.runApi( + { + body: JSON.stringify({ + messages, + stop_sequences: stopSequences, + system, + temperature, + max_tokens: maxTokens, + tools, + anthropic_version: anthropicVersion, + }), + model, + signal, + timeout, + raw: true, + }, + connectorMetricsCollector + ); return res; } } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts index cad8852ce49c4..014d0cfda006b 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts @@ -76,7 +76,10 @@ describe('Cases webhook service', () => { let sslService: ExternalService; beforeAll(() => { - connectorMetricsCollector = new ConnectorMetricsCollector(logger); + connectorMetricsCollector = new ConnectorMetricsCollector({ + logger, + connectorId: 'test-connector-id', + }); service = createExternalService( actionId, { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.test.ts index 2daab8c04cc2a..ec079296cce13 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.test.ts @@ -34,7 +34,10 @@ describe('CrowdstrikeConnector', () => { CrowdstrikeConnector.token = null; // @ts-expect-error mockedRequest = connector.request = jest.fn() as jest.Mock; - connectorMetricsCollector = new ConnectorMetricsCollector(logger); + connectorMetricsCollector = new ConnectorMetricsCollector({ + logger, + connectorId: 'test-connector-id', + }); }); afterEach(() => { jest.clearAllMocks(); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.test.ts index 492d19e5be02b..b5f4b04c8e136 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.test.ts @@ -46,7 +46,10 @@ describe('D3SecurityConnector', () => { // @ts-ignore connector.request = mockRequest; jest.clearAllMocks(); - connectorMetricsCollector = new ConnectorMetricsCollector(logger); + connectorMetricsCollector = new ConnectorMetricsCollector({ + logger, + connectorId: 'test-connector-id', + }); }); it('the D3 Security API call is successful with correct parameters', async () => { const response = await connector.runApi({ body: sampleBody }, connectorMetricsCollector); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/email/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/email/index.test.ts index 11afd240bddb7..5fbaabdb33d9a 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/email/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/email/index.test.ts @@ -515,7 +515,10 @@ describe('execute()', () => { text: 'Go to Elastic', }, }; - const connectorMetricsCollector = new ConnectorMetricsCollector(mockedLogger); + const connectorMetricsCollector = new ConnectorMetricsCollector({ + logger: mockedLogger, + connectorId: 'test-connector-id', + }); const actionId = 'some-id'; const executorOptions: EmailConnectorTypeExecutorOptions = { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.test.ts index d9a3cbf8489b4..cf6d634b086a7 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.test.ts @@ -55,7 +55,10 @@ describe('send_email module', () => { }; }); - connectorMetricsCollector = new ConnectorMetricsCollector(mockLogger); + connectorMetricsCollector = new ConnectorMetricsCollector({ + logger: mockedLogger, + connectorId: 'test-connector-id', + }); }); test('handles authenticated email using service', async () => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.test.ts index 59f7874af4f1f..e1ebeb84859e3 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.test.ts @@ -28,7 +28,10 @@ describe('sendEmailGraphApi', () => { const configurationUtilities = actionsConfigMock.create(); test('email contains the proper message', async () => { - const connectorMetricsCollector = new ConnectorMetricsCollector(logger); + const connectorMetricsCollector = new ConnectorMetricsCollector({ + logger, + connectorId: 'test-connector-id', + }); axiosInstanceMock.mockReturnValueOnce({ status: 202, @@ -121,7 +124,10 @@ describe('sendEmailGraphApi', () => { }); test('email was sent on behalf of the user "from" mailbox', async () => { - const connectorMetricsCollector = new ConnectorMetricsCollector(logger); + const connectorMetricsCollector = new ConnectorMetricsCollector({ + logger, + connectorId: 'test-connector-id', + }); axiosInstanceMock.mockReturnValueOnce({ status: 202, }); @@ -215,7 +221,10 @@ describe('sendEmailGraphApi', () => { }); test('sendMail request was sent to the custom configured Graph API URL', async () => { - const connectorMetricsCollector = new ConnectorMetricsCollector(logger); + const connectorMetricsCollector = new ConnectorMetricsCollector({ + logger, + connectorId: 'test-connector-id', + }); axiosInstanceMock.mockReturnValueOnce({ status: 202, }); @@ -308,7 +317,10 @@ describe('sendEmailGraphApi', () => { }); test('throw the exception and log the proper error if message was not sent successfuly', async () => { - const connectorMetricsCollector = new ConnectorMetricsCollector(logger); + const connectorMetricsCollector = new ConnectorMetricsCollector({ + logger, + connectorId: 'test-connector-id', + }); axiosInstanceMock.mockReturnValueOnce({ status: 400, data: { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/es_index/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/es_index/index.test.ts index 700a95e30b7e8..9812c1bb615c5 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/es_index/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/es_index/index.test.ts @@ -37,7 +37,10 @@ beforeEach(() => { jest.resetAllMocks(); configurationUtilities = actionsConfigMock.create(); connectorType = getConnectorType(); - connectorMetricsCollector = new ConnectorMetricsCollector(mockedLogger); + connectorMetricsCollector = new ConnectorMetricsCollector({ + logger: mockedLogger, + connectorId: 'test-connector-id', + }); }); describe('connector registration', () => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.test.ts index 314cb8790abc9..b28906509ad09 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.test.ts @@ -95,7 +95,10 @@ describe('GeminiConnector', () => { beforeEach(() => { // @ts-ignore connector.request = mockRequest; - connectorMetricsCollector = new ConnectorMetricsCollector(logger); + connectorMetricsCollector = new ConnectorMetricsCollector({ + logger, + connectorId: 'test-connector-id', + }); }); describe('runApi', () => { @@ -187,7 +190,10 @@ describe('GeminiConnector', () => { it('signal and timeout is properly passed to runApi', async () => { const signal = jest.fn(); const timeout = 60000; - await connector.invokeAI({ ...aiAssistantBody, timeout, signal }); + await connector.invokeAI( + { ...aiAssistantBody, timeout, signal }, + connectorMetricsCollector + ); expect(mockRequest).toHaveBeenCalledWith( { url: `https://api.gemini.com/v1/projects/my-project-12345/locations/us-central1/publishers/google/models/${DEFAULT_GEMINI_MODEL}:generateContent`, @@ -276,7 +282,10 @@ describe('GeminiConnector', () => { it('signal and timeout is properly passed to streamApi', async () => { const signal = jest.fn(); const timeout = 60000; - await connector.invokeStream({ ...aiAssistantBody, timeout, signal }); + await connector.invokeStream( + { ...aiAssistantBody, timeout, signal }, + connectorMetricsCollector + ); expect(mockRequest).toHaveBeenCalledWith( { url: `https://api.gemini.com/v1/projects/my-project-12345/locations/us-central1/publishers/google/models/${DEFAULT_GEMINI_MODEL}:streamGenerateContent?alt=sse`, diff --git a/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.ts b/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.ts index f7f2905714cc3..bc3ae38fc57a6 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.ts @@ -294,21 +294,20 @@ export class GeminiConnector extends SubActionConnector { return { message: res.completion, usageMetadata: res.usageMetadata }; } - public async invokeAIRaw({ - messages, - model, - temperature = 0, - signal, - timeout, - tools, - }: InvokeAIRawActionParams): Promise { - const res = await this.runApi({ - body: JSON.stringify({ ...formatGeminiPayload(messages, temperature), tools }), - model, - signal, - timeout, - raw: true, - }); + public async invokeAIRaw( + { messages, model, temperature = 0, signal, timeout, tools }: InvokeAIRawActionParams, + connectorMetricsCollector: ConnectorMetricsCollector + ): Promise { + const res = await this.runApi( + { + body: JSON.stringify({ ...formatGeminiPayload(messages, temperature), tools }), + model, + signal, + timeout, + raw: true, + }, + connectorMetricsCollector + ); return res; } @@ -321,15 +320,18 @@ export class GeminiConnector extends SubActionConnector { * @param messages An array of messages to be sent to the API * @param model Optional model to be used for the API request. If not provided, the default model from the connector will be used. */ - public async invokeStream({ - messages, - model, - stopSequences, - temperature = 0, - signal, - timeout, - tools, - }: InvokeAIActionParams): Promise { + public async invokeStream( + { + messages, + model, + stopSequences, + temperature = 0, + signal, + timeout, + tools, + }: InvokeAIActionParams, + connectorMetricsCollector: ConnectorMetricsCollector + ): Promise { return (await this.streamAPI( { body: JSON.stringify({ ...formatGeminiPayload(messages, temperature), tools }), diff --git a/x-pack/plugins/stack_connectors/server/connector_types/jira/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/jira/service.test.ts index 68abc0d29162c..1e8407ea6d23b 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/jira/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/jira/service.test.ts @@ -139,7 +139,10 @@ describe('Jira service', () => { let connectorMetricsCollector: ConnectorMetricsCollector; beforeAll(() => { - connectorMetricsCollector = new ConnectorMetricsCollector(logger); + connectorMetricsCollector = new ConnectorMetricsCollector({ + logger, + connectorId: 'test-connector-id', + }); service = createExternalService( { // The trailing slash at the end of the url is intended. diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/create_service_wrapper.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/create_service_wrapper.test.ts index bf1c4777ef9a5..471c6fbce97fd 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/create_service_wrapper.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/create_service_wrapper.test.ts @@ -25,7 +25,10 @@ let connectorMetricsCollector: ConnectorMetricsCollector; describe('createServiceWrapper', () => { beforeEach(() => { jest.clearAllMocks(); - connectorMetricsCollector = new ConnectorMetricsCollector(logger); + connectorMetricsCollector = new ConnectorMetricsCollector({ + logger, + connectorId: 'test-connector-id', + }); }); test('creates axios instance with apiUrl', () => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.test.ts index 586ffa0e955a6..0dac24bdc4d84 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.test.ts @@ -212,7 +212,10 @@ describe('ServiceNow service', () => { beforeEach(() => { jest.clearAllMocks(); - connectorMetricsCollector = new ConnectorMetricsCollector(logger); + connectorMetricsCollector = new ConnectorMetricsCollector({ + logger, + connectorId: 'test-connector-id', + }); service = createExternalService({ credentials: { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.test.ts index 3662ae506252f..79ffa4bce0c1f 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.test.ts @@ -76,7 +76,10 @@ describe('OpenAIConnector', () => { }, }; beforeEach(() => { - connectorMetricsCollector = new ConnectorMetricsCollector(logger); + connectorMetricsCollector = new ConnectorMetricsCollector({ + logger, + connectorId: 'test-connector-id', + }); mockRequest = jest.fn().mockResolvedValue(mockResponse); mockError = jest.fn().mockImplementation(() => { throw new Error('API Error'); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.test.ts index 8740eb3c79ded..1c47d11192fd3 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.test.ts @@ -77,7 +77,10 @@ describe('OpsgenieConnector', () => { logger, services, }); - connectorMetricsCollector = new ConnectorMetricsCollector(logger); + connectorMetricsCollector = new ConnectorMetricsCollector({ + logger, + connectorId: 'test-connector-id', + }); }); it('calls request with the correct arguments for creating an alert', async () => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.test.ts index 40ff5f9a5c051..f9f9492eb7981 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.test.ts @@ -36,7 +36,10 @@ let connectorMetricsCollector: ConnectorMetricsCollector; beforeEach(() => { configurationUtilities = actionsConfigMock.create(); connectorType = getConnectorType(); - connectorMetricsCollector = new ConnectorMetricsCollector(mockedLogger); + connectorMetricsCollector = new ConnectorMetricsCollector({ + logger: mockedLogger, + connectorId: 'test-connector-id', + }); }); describe('get()', () => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.test.ts index d4a517ed851d7..68c05db76512a 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.test.ts @@ -110,7 +110,10 @@ describe('IBM Resilient connector', () => { beforeEach(() => { jest.resetAllMocks(); jest.setSystemTime(TIMESTAMP); - connectorMetricsCollector = new ConnectorMetricsCollector(logger); + connectorMetricsCollector = new ConnectorMetricsCollector({ + logger, + connectorId: 'test-connector-id', + }); }); describe('getIncident', () => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.test.ts index 69b50ff2fb863..d358086ef49fa 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.test.ts @@ -23,7 +23,10 @@ describe('SentinelOne Connector', () => { beforeEach(() => { connectorInstance = sentinelOneConnectorMocks.create(); - connectorMetricsCollector = new ConnectorMetricsCollector(logger); + connectorMetricsCollector = new ConnectorMetricsCollector({ + logger, + connectorId: 'test-connector-id', + }); }); describe('#fetchAgentFiles()', () => { @@ -130,7 +133,10 @@ describe('SentinelOne Connector', () => { describe('#downloadRemoteScriptResults()', () => { it('should call SentinelOne api to retrieve task results', async () => { - await connectorInstance.downloadRemoteScriptResults({ taskId: 'task-123' }); + await connectorInstance.downloadRemoteScriptResults( + { taskId: 'task-123' }, + connectorMetricsCollector + ); expect(connectorInstance.requestSpy).toHaveBeenCalledWith( expect.objectContaining({ @@ -144,13 +150,19 @@ describe('SentinelOne Connector', () => { connectorInstance.mockResponses.getRemoteScriptResults.data.download_links = []; await expect( - connectorInstance.downloadRemoteScriptResults({ taskId: 'task-123' }) + connectorInstance.downloadRemoteScriptResults( + { taskId: 'task-123' }, + connectorMetricsCollector + ) ).rejects.toThrow('Download URL for script results of task id [task-123] not found'); }); it('should return a Stream for downloading the file', async () => { await expect( - connectorInstance.downloadRemoteScriptResults({ taskId: 'task-123' }) + connectorInstance.downloadRemoteScriptResults( + { taskId: 'task-123' }, + connectorMetricsCollector + ) ).resolves.toEqual(connectorInstance.mockResponses.downloadRemoteScriptResults); }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.ts b/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.ts index c98f304b845f0..4471d368a05e4 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.ts @@ -364,7 +364,10 @@ export class SentinelOneConnector extends SubActionConnector< { taskId }: SentinelOneDownloadRemoteScriptResultsParams, connectorMetricsCollector: ConnectorMetricsCollector ): Promise { - const scriptResultsInfo = await this.getRemoteScriptResults({ taskIds: [taskId] }); + const scriptResultsInfo = await this.getRemoteScriptResults( + { taskIds: [taskId] }, + connectorMetricsCollector + ); this.logger.debug( () => `script results for taskId [${taskId}]:\n${JSON.stringify(scriptResultsInfo)}` diff --git a/x-pack/plugins/stack_connectors/server/connector_types/server_log/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/server_log/index.test.ts index 5aeae506bac02..85fb63bd28cfe 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/server_log/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/server_log/index.test.ts @@ -107,7 +107,10 @@ describe('execute()', () => { secrets: {}, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector: new ConnectorMetricsCollector(mockedLogger), + connectorMetricsCollector: new ConnectorMetricsCollector({ + logger: mockedLogger, + connectorId: 'test-connector-id', + }), }; await connectorType.executor(executorOptions); expect(mockedLogger.info).toHaveBeenCalledWith('Server log: message text here'); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.test.ts index 2de375094bb33..57ae7f16fdd0f 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.test.ts @@ -37,7 +37,10 @@ describe('ServiceNow SIR service', () => { let connectorMetricsCollector: ConnectorMetricsCollector; beforeEach(() => { - connectorMetricsCollector = new ConnectorMetricsCollector(logger); + connectorMetricsCollector = new ConnectorMetricsCollector({ + logger, + connectorId: 'test-connector-id', + }); service = createExternalService({ credentials: { config: { apiUrl: 'https://example.com/', isOAuth: false }, diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/service.test.ts index 28181071ee214..529b2bc18f073 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/service.test.ts @@ -156,7 +156,10 @@ describe('ServiceNow service', () => { beforeEach(() => { jest.clearAllMocks(); - connectorMetricsCollector = new ConnectorMetricsCollector(logger); + connectorMetricsCollector = new ConnectorMetricsCollector({ + logger, + connectorId: 'test-connector-id', + }); service = createExternalService({ credentials: { // The trailing slash at the end of the url is intended. diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.test.ts index ff3152f33f1c6..17a211458351f 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.test.ts @@ -96,7 +96,10 @@ describe('ServiceNow SIR service', () => { let service: ExternalServiceSIR; beforeEach(() => { - connectorMetricsCollector = new ConnectorMetricsCollector(logger); + connectorMetricsCollector = new ConnectorMetricsCollector({ + logger, + connectorId: 'test-connector-id', + }); service = createExternalService({ credentials: { config: { apiUrl: 'https://example.com/', isOAuth: false }, diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack/index.test.ts index fc89378993a56..25fc03895fcdb 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack/index.test.ts @@ -45,7 +45,10 @@ beforeEach(() => { return { status: 'ok', actionId: options.actionId }; }, }); - connectorMetricsCollector = new ConnectorMetricsCollector(mockedLogger); + connectorMetricsCollector = new ConnectorMetricsCollector({ + logger: mockedLogger, + connectorId: 'test-connector-id', + }); }); describe('connector registration', () => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.test.ts index c34dcec01f716..ca0e24dc4e11d 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.test.ts @@ -44,7 +44,10 @@ let connectorMetricsCollector: ConnectorMetricsCollector; beforeEach(() => { configurationUtilities = actionsConfigMock.create(); connectorType = getConnectorType(); - connectorMetricsCollector = new ConnectorMetricsCollector(mockedLogger); + connectorMetricsCollector = new ConnectorMetricsCollector({ + logger: mockedLogger, + connectorId: 'test-connector-id', + }); }); describe('connector registration', () => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.test.ts index 836e6bdbe5ce7..2e398fa4017c4 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.test.ts @@ -119,7 +119,10 @@ describe('Slack API service', () => { let service: SlackApiService; beforeAll(() => { - connectorMetricsCollector = new ConnectorMetricsCollector(logger); + connectorMetricsCollector = new ConnectorMetricsCollector({ + logger, + connectorId: 'test-connector-id', + }); service = createExternalService( { secrets: { token: 'token' }, diff --git a/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.test.ts index 84430fb81c39e..11bbcbd4e30d8 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.test.ts @@ -60,7 +60,10 @@ describe('Swimlane Service', () => { let connectorMetricsCollector: ConnectorMetricsCollector; beforeAll(() => { - connectorMetricsCollector = new ConnectorMetricsCollector(logger); + connectorMetricsCollector = new ConnectorMetricsCollector({ + logger, + connectorId: 'test-connector-id', + }); service = createExternalService( { // The trailing slash at the end of the url is intended. diff --git a/x-pack/plugins/stack_connectors/server/connector_types/teams/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/teams/index.test.ts index 0701118e6ef40..7ed0e85d7fdd7 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/teams/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/teams/index.test.ts @@ -39,7 +39,10 @@ let connectorMetricsCollector: ConnectorMetricsCollector; beforeEach(() => { configurationUtilities = actionsConfigMock.create(); connectorType = getConnectorType(); - connectorMetricsCollector = new ConnectorMetricsCollector(mockedLogger); + connectorMetricsCollector = new ConnectorMetricsCollector({ + logger: mockedLogger, + connectorId: 'test-connector-id', + }); }); describe('connector registration', () => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/thehive/thehive.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/thehive/thehive.test.ts index 6218d48ae33fa..6015588c2bb4e 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/thehive/thehive.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/thehive/thehive.test.ts @@ -18,17 +18,20 @@ import { PushToServiceIncidentSchema, } from '../../../common/thehive/schema'; import type { ExecutorSubActionCreateAlertParams, Incident } from '../../../common/thehive/types'; +import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; const mockTime = new Date('2024-04-03T09:10:30.000'); describe('TheHiveConnector', () => { + const logger = loggingSystemMock.createLogger(); + const connector = new TheHiveConnector( { configurationUtilities: actionsConfigMock.create(), connector: { id: '1', type: THEHIVE_CONNECTOR_ID }, config: { url: 'https://example.com', organisation: null }, secrets: { apiKey: 'test123' }, - logger: loggingSystemMock.createLogger(), + logger, services: actionsMock.createServices(), }, PushToServiceIncidentSchema @@ -36,6 +39,7 @@ describe('TheHiveConnector', () => { let mockRequest: jest.Mock; let mockError: jest.Mock; + let connectorMetricsCollector: ConnectorMetricsCollector; beforeAll(() => { jest.useFakeTimers(); @@ -51,6 +55,10 @@ describe('TheHiveConnector', () => { throw new Error('API Error'); }); jest.clearAllMocks(); + connectorMetricsCollector = new ConnectorMetricsCollector({ + logger, + connectorId: 'test-connector-id', + }); }); describe('createIncident', () => { @@ -124,18 +132,21 @@ describe('TheHiveConnector', () => { }; it('TheHive API call is successful with correct parameters', async () => { - const response = await connector.createIncident(incident); + const response = await connector.createIncident(incident, connectorMetricsCollector); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - url: 'https://example.com/api/v1/case', - method: 'post', - responseSchema: TheHiveIncidentResponseSchema, - data: incident, - headers: { - Authorization: 'Bearer test123', - 'X-Organisation': null, + expect(mockRequest).toHaveBeenCalledWith( + { + url: 'https://example.com/api/v1/case', + method: 'post', + responseSchema: TheHiveIncidentResponseSchema, + data: incident, + headers: { + Authorization: 'Bearer test123', + 'X-Organisation': null, + }, }, - }); + connectorMetricsCollector + ); expect(response).toEqual({ id: '~172064', url: 'https://example.com/cases/~172064/details', @@ -148,7 +159,9 @@ describe('TheHiveConnector', () => { // @ts-ignore connector.request = mockError; - await expect(connector.createIncident(incident)).rejects.toThrow('API Error'); + await expect(connector.createIncident(incident, connectorMetricsCollector)).rejects.toThrow( + 'API Error' + ); }); }); @@ -173,18 +186,24 @@ describe('TheHiveConnector', () => { }; it('TheHive API call is successful with correct parameters', async () => { - const response = await connector.updateIncident({ incidentId: '~172064', incident }); + const response = await connector.updateIncident( + { incidentId: '~172064', incident }, + connectorMetricsCollector + ); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - url: 'https://example.com/api/v1/case/~172064', - method: 'patch', - responseSchema: TheHiveUpdateIncidentResponseSchema, - data: incident, - headers: { - Authorization: 'Bearer test123', - 'X-Organisation': null, + expect(mockRequest).toHaveBeenCalledWith( + { + url: 'https://example.com/api/v1/case/~172064', + method: 'patch', + responseSchema: TheHiveUpdateIncidentResponseSchema, + data: incident, + headers: { + Authorization: 'Bearer test123', + 'X-Organisation': null, + }, }, - }); + connectorMetricsCollector + ); expect(response).toEqual({ id: '~172064', url: 'https://example.com/cases/~172064/details', @@ -197,9 +216,9 @@ describe('TheHiveConnector', () => { // @ts-ignore connector.request = mockError; - await expect(connector.updateIncident({ incidentId: '~172064', incident })).rejects.toThrow( - 'API Error' - ); + await expect( + connector.updateIncident({ incidentId: '~172064', incident }, connectorMetricsCollector) + ).rejects.toThrow('API Error'); }); }); @@ -224,21 +243,27 @@ describe('TheHiveConnector', () => { }); it('TheHive API call is successful with correct parameters', async () => { - await connector.addComment({ - incidentId: '~172064', - comment: 'test comment', - }); + await connector.addComment( + { + incidentId: '~172064', + comment: 'test comment', + }, + connectorMetricsCollector + ); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - url: 'https://example.com/api/v1/case/~172064/comment', - method: 'post', - responseSchema: TheHiveAddCommentResponseSchema, - data: { message: 'test comment' }, - headers: { - Authorization: 'Bearer test123', - 'X-Organisation': null, + expect(mockRequest).toHaveBeenCalledWith( + { + url: 'https://example.com/api/v1/case/~172064/comment', + method: 'post', + responseSchema: TheHiveAddCommentResponseSchema, + data: { message: 'test comment' }, + headers: { + Authorization: 'Bearer test123', + 'X-Organisation': null, + }, }, - }); + connectorMetricsCollector + ); }); it('errors during API calls are properly handled', async () => { @@ -246,7 +271,10 @@ describe('TheHiveConnector', () => { connector.request = mockError; await expect( - connector.addComment({ incidentId: '~172064', comment: 'test comment' }) + connector.addComment( + { incidentId: '~172064', comment: 'test comment' }, + connectorMetricsCollector + ) ).rejects.toThrow('API Error'); }); }); @@ -314,16 +342,19 @@ describe('TheHiveConnector', () => { }); it('TheHive API call is successful with correct parameters', async () => { - const response = await connector.getIncident({ id: '~172064' }); + const response = await connector.getIncident({ id: '~172064' }, connectorMetricsCollector); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - url: 'https://example.com/api/v1/case/~172064', - responseSchema: TheHiveIncidentResponseSchema, - headers: { - Authorization: 'Bearer test123', - 'X-Organisation': null, + expect(mockRequest).toHaveBeenCalledWith( + { + url: 'https://example.com/api/v1/case/~172064', + responseSchema: TheHiveIncidentResponseSchema, + headers: { + Authorization: 'Bearer test123', + 'X-Organisation': null, + }, }, - }); + connectorMetricsCollector + ); expect(response).toEqual(mockResponse.data); }); @@ -331,7 +362,9 @@ describe('TheHiveConnector', () => { // @ts-ignore connector.request = mockError; - await expect(connector.getIncident({ id: '~172064' })).rejects.toThrow('API Error'); + await expect( + connector.getIncident({ id: '~172064' }, connectorMetricsCollector) + ).rejects.toThrow('API Error'); }); }); @@ -385,25 +418,30 @@ describe('TheHiveConnector', () => { }; it('TheHive API call is successful with correct parameters', async () => { - await connector.createAlert(alert); + await connector.createAlert(alert, connectorMetricsCollector); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - url: 'https://example.com/api/v1/alert', - method: 'post', - responseSchema: TheHiveCreateAlertResponseSchema, - data: alert, - headers: { - Authorization: 'Bearer test123', - 'X-Organisation': null, + expect(mockRequest).toHaveBeenCalledWith( + { + url: 'https://example.com/api/v1/alert', + method: 'post', + responseSchema: TheHiveCreateAlertResponseSchema, + data: alert, + headers: { + Authorization: 'Bearer test123', + 'X-Organisation': null, + }, }, - }); + connectorMetricsCollector + ); }); it('errors during API calls are properly handled', async () => { // @ts-ignore connector.request = mockError; - await expect(connector.createAlert(alert)).rejects.toThrow('API Error'); + await expect(connector.createAlert(alert, connectorMetricsCollector)).rejects.toThrow( + 'API Error' + ); }); }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/thehive/thehive.ts b/x-pack/plugins/stack_connectors/server/connector_types/thehive/thehive.ts index fe0caf8788f28..887ba24d16ca4 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/thehive/thehive.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/thehive/thehive.ts @@ -8,6 +8,7 @@ import { ServiceParams, CaseConnector } from '@kbn/actions-plugin/server'; import type { AxiosError } from 'axios'; import { Type } from '@kbn/config-schema'; +import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; import { SUB_ACTION } from '../../../common/thehive/constants'; import { TheHiveIncidentResponseSchema, @@ -68,14 +69,20 @@ export class TheHiveConnector extends CaseConnector< return `API Error: ${error.response?.data?.type} - ${error.response?.data?.message}`; } - public async createIncident(incident: Incident): Promise { - const res = await this.request({ - method: 'post', - url: `${this.url}/api/${API_VERSION}/case`, - data: incident, - headers: this.getAuthHeaders(), - responseSchema: TheHiveIncidentResponseSchema, - }); + public async createIncident( + incident: Incident, + connectorMetricsCollector: ConnectorMetricsCollector + ): Promise { + const res = await this.request( + { + method: 'post', + url: `${this.url}/api/${API_VERSION}/case`, + data: incident, + headers: this.getAuthHeaders(), + responseSchema: TheHiveIncidentResponseSchema, + }, + connectorMetricsCollector + ); return { id: res.data._id, @@ -85,30 +92,42 @@ export class TheHiveConnector extends CaseConnector< }; } - public async addComment({ incidentId, comment }: { incidentId: string; comment: string }) { - await this.request({ - method: 'post', - url: `${this.url}/api/${API_VERSION}/case/${incidentId}/comment`, - data: { message: comment }, - headers: this.getAuthHeaders(), - responseSchema: TheHiveAddCommentResponseSchema, - }); + public async addComment( + { incidentId, comment }: { incidentId: string; comment: string }, + connectorMetricsCollector: ConnectorMetricsCollector + ) { + await this.request( + { + method: 'post', + url: `${this.url}/api/${API_VERSION}/case/${incidentId}/comment`, + data: { message: comment }, + headers: this.getAuthHeaders(), + responseSchema: TheHiveAddCommentResponseSchema, + }, + connectorMetricsCollector + ); } - public async updateIncident({ - incidentId, - incident, - }: { - incidentId: string; - incident: Incident; - }): Promise { - await this.request({ - method: 'patch', - url: `${this.url}/api/${API_VERSION}/case/${incidentId}`, - data: incident, - headers: this.getAuthHeaders(), - responseSchema: TheHiveUpdateIncidentResponseSchema, - }); + public async updateIncident( + { + incidentId, + incident, + }: { + incidentId: string; + incident: Incident; + }, + connectorMetricsCollector: ConnectorMetricsCollector + ): Promise { + await this.request( + { + method: 'patch', + url: `${this.url}/api/${API_VERSION}/case/${incidentId}`, + data: incident, + headers: this.getAuthHeaders(), + responseSchema: TheHiveUpdateIncidentResponseSchema, + }, + connectorMetricsCollector + ); return { id: incidentId, @@ -118,23 +137,35 @@ export class TheHiveConnector extends CaseConnector< }; } - public async getIncident({ id }: { id: string }): Promise { - const res = await this.request({ - url: `${this.url}/api/${API_VERSION}/case/${id}`, - headers: this.getAuthHeaders(), - responseSchema: TheHiveIncidentResponseSchema, - }); + public async getIncident( + { id }: { id: string }, + connectorMetricsCollector: ConnectorMetricsCollector + ): Promise { + const res = await this.request( + { + url: `${this.url}/api/${API_VERSION}/case/${id}`, + headers: this.getAuthHeaders(), + responseSchema: TheHiveIncidentResponseSchema, + }, + connectorMetricsCollector + ); return res.data; } - public async createAlert(alert: ExecutorSubActionCreateAlertParams) { - await this.request({ - method: 'post', - url: `${this.url}/api/${API_VERSION}/alert`, - data: alert, - headers: this.getAuthHeaders(), - responseSchema: TheHiveCreateAlertResponseSchema, - }); + public async createAlert( + alert: ExecutorSubActionCreateAlertParams, + connectorMetricsCollector: ConnectorMetricsCollector + ) { + await this.request( + { + method: 'post', + url: `${this.url}/api/${API_VERSION}/alert`, + data: alert, + headers: this.getAuthHeaders(), + responseSchema: TheHiveCreateAlertResponseSchema, + }, + connectorMetricsCollector + ); } } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.test.ts index ba8b92398c95c..b24564a3f3419 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.test.ts @@ -111,7 +111,10 @@ describe('TinesConnector', () => { beforeEach(() => { jest.clearAllMocks(); - connectorMetricsCollector = new ConnectorMetricsCollector(logger); + connectorMetricsCollector = new ConnectorMetricsCollector({ + logger, + connectorId: 'test-connector-id', + }); }); describe('getStories', () => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/torq/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/torq/index.test.ts index f76029f4b2bb1..0841502f1f195 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/torq/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/torq/index.test.ts @@ -47,7 +47,10 @@ let connectorMetricsCollector: ConnectorMetricsCollector; beforeAll(() => { actionType = getActionType(); configurationUtilities = actionsConfigMock.create(); - connectorMetricsCollector = new ConnectorMetricsCollector(mockedLogger); + connectorMetricsCollector = new ConnectorMetricsCollector({ + logger: mockedLogger, + connectorId: 'test-connector-id', + }); }); describe('actionType', () => { @@ -182,74 +185,25 @@ describe('execute Torq action', () => { }); delete requestMock.mock.calls[0][0].configurationUtilities; - expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` - Object { - "axios": [MockFunction], - "connectorMetricsCollector": ConnectorMetricsCollector { - "logger": Object { - "context": Array [], - "debug": [MockFunction] { - "calls": Array [ - Array [ - "response from Torq action \\"some-id\\": [HTTP 200] ", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": undefined, - }, - ], - }, - "error": [MockFunction], - "fatal": [MockFunction], - "get": [MockFunction], - "info": [MockFunction], - "isLevelEnabled": [MockFunction], - "log": [MockFunction], - "trace": [MockFunction], - "warn": [MockFunction], - }, - "metrics": Object { - "requestBodyBytes": 0, - }, - }, - "data": Object { - "msg": "some data", - }, - "headers": Object { - "Content-Type": "application/json", - "X-Torq-Token": "1234", - }, - "logger": Object { - "context": Array [], - "debug": [MockFunction] { - "calls": Array [ - Array [ - "response from Torq action \\"some-id\\": [HTTP 200] ", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": undefined, - }, - ], - }, - "error": [MockFunction], - "fatal": [MockFunction], - "get": [MockFunction], - "info": [MockFunction], - "isLevelEnabled": [MockFunction], - "log": [MockFunction], - "trace": [MockFunction], - "warn": [MockFunction], + expect(requestMock.mock.calls[0][0]).toMatchSnapshot({ + axios: expect.any(Function), + connectorMetricsCollector: { + metrics: { + requestBodyBytes: 0, }, - "method": "post", - "url": "https://hooks.torq.io/v1/test", - "validateStatus": [Function], - } - `); + }, + data: { + msg: 'some data', + }, + headers: { + 'Content-Type': 'application/json', + 'X-Torq-Token': '1234', + }, + logger: expect.any(Object), + method: 'post', + url: 'https://hooks.torq.io/v1/test', + validateStatus: expect.any(Function), + }); }); test('renders parameter templates as expected', async () => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.test.ts index a2c0097346391..f8d534b10f7d0 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.test.ts @@ -46,7 +46,10 @@ let connectorMetricsCollector: ConnectorMetricsCollector; beforeEach(() => { configurationUtilities = actionsConfigMock.create(); connectorType = getConnectorType(); - connectorMetricsCollector = new ConnectorMetricsCollector(mockedLogger); + connectorMetricsCollector = new ConnectorMetricsCollector({ + logger: mockedLogger, + connectorId: 'test-connector-id', + }); }); describe('connectorType', () => { @@ -345,72 +348,23 @@ describe('execute()', () => { }); delete requestMock.mock.calls[0][0].configurationUtilities; - expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` - Object { - "axios": undefined, - "connectorMetricsCollector": ConnectorMetricsCollector { - "logger": Object { - "context": Array [], - "debug": [MockFunction] { - "calls": Array [ - Array [ - "response from webhook action \\"some-id\\": [HTTP 200] ", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": undefined, - }, - ], - }, - "error": [MockFunction], - "fatal": [MockFunction], - "get": [MockFunction], - "info": [MockFunction], - "isLevelEnabled": [MockFunction], - "log": [MockFunction], - "trace": [MockFunction], - "warn": [MockFunction], - }, - "metrics": Object { - "requestBodyBytes": 0, - }, - }, - "data": "some data", - "headers": Object { - "Authorization": "Basic YWJjOjEyMw==", - "aheader": "a value", + expect(requestMock.mock.calls[0][0]).toMatchSnapshot({ + axios: undefined, + connectorMetricsCollector: { + metrics: { + requestBodyBytes: 0, }, - "logger": Object { - "context": Array [], - "debug": [MockFunction] { - "calls": Array [ - Array [ - "response from webhook action \\"some-id\\": [HTTP 200] ", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": undefined, - }, - ], - }, - "error": [MockFunction], - "fatal": [MockFunction], - "get": [MockFunction], - "info": [MockFunction], - "isLevelEnabled": [MockFunction], - "log": [MockFunction], - "trace": [MockFunction], - "warn": [MockFunction], - }, - "method": "post", - "sslOverrides": Object {}, - "url": "https://abc.def/my-webhook", - } - `); + }, + data: 'some data', + headers: { + Authorization: 'Basic YWJjOjEyMw==', + aheader: 'a value', + }, + logger: expect.any(Object), + method: 'post', + sslOverrides: {}, + url: 'https://abc.def/my-webhook', + }); }); test('execute with ssl adds ssl settings to sslOverrides', async () => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.test.ts index 5d1b27af98401..e6ae05810a1f2 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.test.ts @@ -50,7 +50,10 @@ let connectorMetricsCollector: ConnectorMetricsCollector; beforeEach(() => { configurationUtilities = actionsConfigMock.create(); connectorType = getConnectorType(); - connectorMetricsCollector = new ConnectorMetricsCollector(mockedLogger); + connectorMetricsCollector = new ConnectorMetricsCollector({ + logger: mockedLogger, + connectorId: 'test-connector-id', + }); }); describe('connectorType', () => { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/openai.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/openai.ts index ad02037ac89df..e2fdf58704da4 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/openai.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/openai.ts @@ -276,7 +276,7 @@ export default function genAiTest({ getService }: FtrProviderContext) { }); describe('execution', () => { - describe('successful response simulator x', () => { + describe('successful response simulator', () => { const simulator = new OpenAISimulator({ proxy: { config: configService.get('kbnTestServer.serverArgs'), From 229de0cef0952ff830c722fbf11ce86e0402e7e5 Mon Sep 17 00:00:00 2001 From: Ersin Erdal Date: Wed, 7 Aug 2024 14:48:14 +0300 Subject: [PATCH 10/25] add connector id to log --- .../server/connector_types/email/send_email.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.test.ts index cf6d634b086a7..817a2c8bbb11c 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.test.ts @@ -56,7 +56,7 @@ describe('send_email module', () => { }); connectorMetricsCollector = new ConnectorMetricsCollector({ - logger: mockedLogger, + logger: mockLogger, connectorId: 'test-connector-id', }); }); From 6a09ee2e6b405c928d941046426c354488ec7254 Mon Sep 17 00:00:00 2001 From: Ersin Erdal Date: Wed, 7 Aug 2024 15:59:22 +0300 Subject: [PATCH 11/25] parse header --- .../plugins/actions/server/lib/connector_metrics_collector.ts | 2 +- .../group2/tests/actions/connector_types/bedrock.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/actions/server/lib/connector_metrics_collector.ts b/x-pack/plugins/actions/server/lib/connector_metrics_collector.ts index b9ad88abe464d..a32bd50548f0b 100644 --- a/x-pack/plugins/actions/server/lib/connector_metrics_collector.ts +++ b/x-pack/plugins/actions/server/lib/connector_metrics_collector.ts @@ -31,7 +31,7 @@ export class ConnectorMetricsCollector { let bytes = 0; if (!isUndefined(contentLength)) { - bytes = contentLength; + bytes = parseInt(contentLength, 10); } else { try { const sBody = typeof body === 'string' ? body : JSON.stringify(body); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/bedrock.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/bedrock.ts index 0fffabf1b49d6..f613d56eab507 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/bedrock.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/bedrock.ts @@ -13,6 +13,7 @@ import { } from '@kbn/actions-simulators-plugin/server/bedrock_simulation'; import { DEFAULT_TOKEN_LIMIT } from '@kbn/stack-connectors-plugin/common/bedrock/constants'; import { TaskErrorSource } from '@kbn/task-manager-plugin/common'; +import { IValidatedEvent } from '@kbn/event-log-plugin/generated/schemas'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; import { getEventLog, getUrlPrefix, ObjectRemover } from '../../../../../common/lib'; From 0b18887bfcea9b40ba535160e81d540e2cbdd894 Mon Sep 17 00:00:00 2001 From: Ersin Erdal Date: Wed, 7 Aug 2024 16:02:15 +0300 Subject: [PATCH 12/25] parse header --- .../group2/tests/actions/connector_types/cases_webhook.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/cases_webhook.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/cases_webhook.ts index 71198328160b5..d53d1f4e6eaa8 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/cases_webhook.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/cases_webhook.ts @@ -416,7 +416,7 @@ export default function casesWebhookTest({ getService }: FtrProviderContext) { }); const executeEvent = events[1]; - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(125); + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(1250); expect(body).to.eql({ status: 'ok', From 83bf59aeaefc36b90a7bb35e2a1d60b012c16d32 Mon Sep 17 00:00:00 2001 From: Ersin Erdal Date: Wed, 7 Aug 2024 16:22:55 +0300 Subject: [PATCH 13/25] fix undefined getHeader --- .../plugins/actions/server/lib/connector_metrics_collector.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/actions/server/lib/connector_metrics_collector.ts b/x-pack/plugins/actions/server/lib/connector_metrics_collector.ts index a32bd50548f0b..1cfa6888e4f1f 100644 --- a/x-pack/plugins/actions/server/lib/connector_metrics_collector.ts +++ b/x-pack/plugins/actions/server/lib/connector_metrics_collector.ts @@ -27,7 +27,7 @@ export class ConnectorMetricsCollector { } public addRequestBodyBytes(result?: AxiosError | AxiosResponse, body: string | object = '') { - const contentLength = result?.request.getHeader('content-length'); + const contentLength = result?.request?.getHeader('content-length'); let bytes = 0; if (!isUndefined(contentLength)) { From f9ef8e1ac2217dcd8d4ed40c28fb1290adb1b8d3 Mon Sep 17 00:00:00 2001 From: Ersin Erdal Date: Wed, 7 Aug 2024 18:29:09 +0300 Subject: [PATCH 14/25] test action executor with a non-zero value --- .../server/lib/action_executor.test.ts | 44 ++++++++++++------- .../actions/server/lib/axios_utils.test.ts | 1 + .../actions/connector_types/cases_webhook.ts | 2 +- 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/x-pack/plugins/actions/server/lib/action_executor.test.ts b/x-pack/plugins/actions/server/lib/action_executor.test.ts index f4bec07701099..c643156886454 100644 --- a/x-pack/plugins/actions/server/lib/action_executor.test.ts +++ b/x-pack/plugins/actions/server/lib/action_executor.test.ts @@ -31,8 +31,6 @@ import { SecurityConnectorFeatureId } from '../../common'; import { TaskErrorSource } from '@kbn/task-manager-plugin/common'; import { createTaskRunError, getErrorSource } from '@kbn/task-manager-plugin/server/task_running'; import { GEN_AI_TOKEN_COUNT_EVENT } from './event_based_telemetry'; -import { Event } from './create_action_event_log_record_object'; -import { set } from '@kbn/safer-lodash-set'; const actionExecutor = new ActionExecutor({ isESOCanEncrypt: true }); const services = actionsMock.createServices(); @@ -156,7 +154,7 @@ interface ActionMetrics { request_body_bytes: number; } -const getBaseExecuteStartEventLogDoc = (unsecured: boolean, actionMetrics?: ActionMetrics) => { +const getBaseExecuteStartEventLogDoc = (unsecured: boolean) => { return { event: { action: 'execute-start', @@ -166,7 +164,6 @@ const getBaseExecuteStartEventLogDoc = (unsecured: boolean, actionMetrics?: Acti action: { execution: { uuid: ACTION_EXECUTION_ID, - ...(actionMetrics ? { metrics: actionMetrics } : {}), }, id: CONNECTOR_ID, name: '1', @@ -198,10 +195,23 @@ const getBaseExecuteStartEventLogDoc = (unsecured: boolean, actionMetrics?: Acti }; }; -const getBaseExecuteEventLogDoc = (unsecured: boolean, actionMetrics?: ActionMetrics) => { - const base = getBaseExecuteStartEventLogDoc(unsecured, actionMetrics); +const getBaseExecuteEventLogDoc = ( + unsecured: boolean, + actionMetrics: ActionMetrics = { request_body_bytes: 0 } +) => { + const base = getBaseExecuteStartEventLogDoc(unsecured); return { ...base, + kibana: { + ...base.kibana, + action: { + ...base.kibana.action, + execution: { + ...base.kibana.action.execution, + metrics: actionMetrics, + }, + }, + }, event: { ...base.event, action: 'execute', @@ -219,10 +229,6 @@ const getBaseExecuteEventLogDoc = (unsecured: boolean, actionMetrics?: ActionMet }; }; -const addConnectorMetrics = (event: Event, value: number) => { - set(event, 'kibana.action.execution.metrics.request_body_bytes', value); -}; - beforeEach(() => { jest.resetAllMocks(); jest.clearAllMocks(); @@ -244,11 +250,17 @@ beforeEach(() => { getActionsAuthorizationWithRequest.mockReturnValue(authorizationMock); }); +const mockGetRequestBodyByte = jest.spyOn( + ConnectorMetricsCollector.prototype, + 'getRequestBodyByte' +); + describe('Action Executor', () => { for (const executeUnsecure of [false, true]) { const label = executeUnsecure ? 'executes unsecured' : 'executes'; test(`successfully ${label}`, async () => { + mockGetRequestBodyByte.mockReturnValue(300); encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce( connectorSavedObject ); @@ -300,7 +312,7 @@ describe('Action Executor', () => { const execStartDoc = getBaseExecuteStartEventLogDoc(executeUnsecure); const execDoc = getBaseExecuteEventLogDoc(executeUnsecure, { request_body_bytes: 300 }); - addConnectorMetrics(execDoc, 300); + expect(eventLogger.logEvent).toHaveBeenNthCalledWith(1, execStartDoc); expect(eventLogger.logEvent).toHaveBeenNthCalledWith(2, execDoc); }); @@ -375,7 +387,7 @@ describe('Action Executor', () => { const execStartDoc = getBaseExecuteStartEventLogDoc(executeUnsecure); const execDoc = getBaseExecuteEventLogDoc(executeUnsecure); - addConnectorMetrics(execDoc, 0); + expect(eventLogger.logEvent).toHaveBeenNthCalledWith(1, { ...execStartDoc, kibana: { @@ -455,7 +467,7 @@ describe('Action Executor', () => { const execStartDoc = getBaseExecuteStartEventLogDoc(executeUnsecure); const execDoc = getBaseExecuteEventLogDoc(executeUnsecure); - addConnectorMetrics(execDoc, 0); + expect(eventLogger.logEvent).toHaveBeenNthCalledWith(1, { ...execStartDoc, kibana: { @@ -551,7 +563,7 @@ describe('Action Executor', () => { const execStartDoc = getBaseExecuteStartEventLogDoc(executeUnsecure); const execDoc = getBaseExecuteEventLogDoc(executeUnsecure); - addConnectorMetrics(execDoc, 0); + expect(eventLogger.logEvent).toHaveBeenNthCalledWith(1, { ...execStartDoc, kibana: { @@ -1021,7 +1033,7 @@ describe('Action Executor', () => { const execStartDoc = getBaseExecuteStartEventLogDoc(executeUnsecure); const execDoc = getBaseExecuteEventLogDoc(executeUnsecure); - addConnectorMetrics(execDoc, 0); + expect(eventLogger.logEvent).toHaveBeenNthCalledWith(1, { ...execStartDoc, kibana: { @@ -1116,7 +1128,7 @@ describe('Action Executor', () => { const execStartDoc = getBaseExecuteStartEventLogDoc(executeUnsecure); const execDoc = getBaseExecuteEventLogDoc(executeUnsecure); - addConnectorMetrics(execDoc, 0); + expect(eventLogger.logEvent).toHaveBeenNthCalledWith(1, { ...execStartDoc, kibana: { diff --git a/x-pack/plugins/actions/server/lib/axios_utils.test.ts b/x-pack/plugins/actions/server/lib/axios_utils.test.ts index 131bb7a32e274..1ca09888e0f5a 100644 --- a/x-pack/plugins/actions/server/lib/axios_utils.test.ts +++ b/x-pack/plugins/actions/server/lib/axios_utils.test.ts @@ -88,6 +88,7 @@ describe('request', () => { data: { incidentId: '123' }, request: { headers: { 'Content-Length': contentLength }, + getHeader: () => contentLength, }, })); const connectorMetricsCollector = new ConnectorMetricsCollector({ diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/cases_webhook.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/cases_webhook.ts index d53d1f4e6eaa8..71198328160b5 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/cases_webhook.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/cases_webhook.ts @@ -416,7 +416,7 @@ export default function casesWebhookTest({ getService }: FtrProviderContext) { }); const executeEvent = events[1]; - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(1250); + expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(125); expect(body).to.eql({ status: 'ok', From 6ba986a6de1f1b4f42f35c52a9db054afb5e0cff Mon Sep 17 00:00:00 2001 From: Ersin Erdal Date: Wed, 7 Aug 2024 20:37:18 +0300 Subject: [PATCH 15/25] fix unit tests --- .../cases_webhook/service.test.ts | 6 ++- .../connector_types/teams/index.test.ts | 2 + .../torq/__snapshots__/index.test.ts.snap | 48 +++++++++++++++++++ .../connector_types/webhook/index.test.ts | 2 + 4 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 x-pack/plugins/stack_connectors/server/connector_types/torq/__snapshots__/index.test.ts.snap diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts index 014d0cfda006b..6258341e3ac80 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts @@ -252,6 +252,7 @@ describe('Cases webhook service', () => { Object { "axios": [Function], "connectorMetricsCollector": ConnectorMetricsCollector { + "connectorId": "test-connector-id", "logger": Object { "context": Array [], "debug": [MockFunction], @@ -542,6 +543,7 @@ describe('Cases webhook service', () => { Object { "axios": [Function], "connectorMetricsCollector": ConnectorMetricsCollector { + "connectorId": "test-connector-id", "logger": Object { "context": Array [], "debug": [MockFunction] { @@ -838,6 +840,7 @@ describe('Cases webhook service', () => { Object { "axios": [Function], "connectorMetricsCollector": ConnectorMetricsCollector { + "connectorId": "test-connector-id", "logger": Object { "context": Array [], "debug": [MockFunction], @@ -1080,10 +1083,11 @@ describe('Cases webhook service', () => { // irrelevant snapshot content delete requestMock.mock.calls[0][0].configurationUtilities; - expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` + expect(requestMock.mock.calls[0][0]).toMatchSnapshot(` Object { "axios": [Function], "connectorMetricsCollector": ConnectorMetricsCollector { + "connectorId": "test-connector-id", "logger": Object { "context": Array [], "debug": [MockFunction], diff --git a/x-pack/plugins/stack_connectors/server/connector_types/teams/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/teams/index.test.ts index 7ed0e85d7fdd7..f31ae33af68bf 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/teams/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/teams/index.test.ts @@ -179,6 +179,7 @@ describe('execute()', () => { Object { "axios": undefined, "connectorMetricsCollector": ConnectorMetricsCollector { + "connectorId": "test-connector-id", "logger": Object { "context": Array [], "debug": [MockFunction] { @@ -265,6 +266,7 @@ describe('execute()', () => { Object { "axios": undefined, "connectorMetricsCollector": ConnectorMetricsCollector { + "connectorId": "test-connector-id", "logger": Object { "context": Array [], "debug": [MockFunction] { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/torq/__snapshots__/index.test.ts.snap b/x-pack/plugins/stack_connectors/server/connector_types/torq/__snapshots__/index.test.ts.snap new file mode 100644 index 0000000000000..6d154c0d53db5 --- /dev/null +++ b/x-pack/plugins/stack_connectors/server/connector_types/torq/__snapshots__/index.test.ts.snap @@ -0,0 +1,48 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`execute Torq action execute with token happy flow 1`] = ` +Object { + "axios": Any, + "connectorMetricsCollector": Object { + "connectorId": "test-connector-id", + "logger": Object { + "context": Array [], + "debug": [MockFunction] { + "calls": Array [ + Array [ + "response from Torq action \\"some-id\\": [HTTP 200] ", + ], + ], + "results": Array [ + Object { + "type": "return", + "value": undefined, + }, + ], + }, + "error": [MockFunction], + "fatal": [MockFunction], + "get": [MockFunction], + "info": [MockFunction], + "isLevelEnabled": [MockFunction], + "log": [MockFunction], + "trace": [MockFunction], + "warn": [MockFunction], + }, + "metrics": Object { + "requestBodyBytes": 0, + }, + }, + "data": Object { + "msg": "some data", + }, + "headers": Object { + "Content-Type": "application/json", + "X-Torq-Token": "1234", + }, + "logger": Any, + "method": "post", + "url": "https://hooks.torq.io/v1/test", + "validateStatus": Any, +} +`; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.test.ts index f8d534b10f7d0..8e10ba515ad99 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.test.ts @@ -395,6 +395,7 @@ describe('execute()', () => { Object { "axios": undefined, "connectorMetricsCollector": ConnectorMetricsCollector { + "connectorId": "test-connector-id", "logger": Object { "context": Array [], "debug": [MockFunction] { @@ -643,6 +644,7 @@ describe('execute()', () => { Object { "axios": undefined, "connectorMetricsCollector": ConnectorMetricsCollector { + "connectorId": "test-connector-id", "logger": Object { "context": Array [], "debug": [MockFunction] { From 1d580c1b3a64e087c90721ed0fc5ee8a9400cf8f Mon Sep 17 00:00:00 2001 From: Ersin Erdal Date: Wed, 7 Aug 2024 23:20:16 +0300 Subject: [PATCH 16/25] fix unit tests --- .../webhook/__snapshots__/index.test.ts.snap | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 x-pack/plugins/stack_connectors/server/connector_types/webhook/__snapshots__/index.test.ts.snap diff --git a/x-pack/plugins/stack_connectors/server/connector_types/webhook/__snapshots__/index.test.ts.snap b/x-pack/plugins/stack_connectors/server/connector_types/webhook/__snapshots__/index.test.ts.snap new file mode 100644 index 0000000000000..17304a2e94cea --- /dev/null +++ b/x-pack/plugins/stack_connectors/server/connector_types/webhook/__snapshots__/index.test.ts.snap @@ -0,0 +1,46 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`execute() execute with username/password sends request with basic auth 1`] = ` +Object { + "axios": undefined, + "connectorMetricsCollector": Object { + "connectorId": "test-connector-id", + "logger": Object { + "context": Array [], + "debug": [MockFunction] { + "calls": Array [ + Array [ + "response from webhook action \\"some-id\\": [HTTP 200] ", + ], + ], + "results": Array [ + Object { + "type": "return", + "value": undefined, + }, + ], + }, + "error": [MockFunction], + "fatal": [MockFunction], + "get": [MockFunction], + "info": [MockFunction], + "isLevelEnabled": [MockFunction], + "log": [MockFunction], + "trace": [MockFunction], + "warn": [MockFunction], + }, + "metrics": Object { + "requestBodyBytes": 0, + }, + }, + "data": "some data", + "headers": Object { + "Authorization": "Basic YWJjOjEyMw==", + "aheader": "a value", + }, + "logger": Any, + "method": "post", + "sslOverrides": Object {}, + "url": "https://abc.def/my-webhook", +} +`; From a9f69bb0d08810bc7483712965a10b8ea04abe06 Mon Sep 17 00:00:00 2001 From: Ersin Erdal Date: Thu, 8 Aug 2024 09:26:05 +0300 Subject: [PATCH 17/25] fix unit tests --- .../__snapshots__/service.test.ts.snap | 323 ++++++++++++++++++ 1 file changed, 323 insertions(+) create mode 100644 x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/__snapshots__/service.test.ts.snap diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/__snapshots__/service.test.ts.snap b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/__snapshots__/service.test.ts.snap new file mode 100644 index 0000000000000..aaa40000c2740 --- /dev/null +++ b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/__snapshots__/service.test.ts.snap @@ -0,0 +1,323 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Cases webhook service createComment it should call request with correct arguments when authType=SSL: + Object { + "axios": [Function], + "connectorMetricsCollector": ConnectorMetricsCollector { + "connectorId": "test-connector-id", + "logger": Object { + "context": Array [], + "debug": [MockFunction], + "error": [MockFunction], + "fatal": [MockFunction], + "get": [MockFunction], + "info": [MockFunction], + "isLevelEnabled": [MockFunction], + "log": [MockFunction], + "trace": [MockFunction], + "warn": [MockFunction], + }, + "metrics": Object { + "requestBodyBytes": 0, + }, + }, + "data": "{\\"body\\":\\"comment\\"}", + "logger": Object { + "context": Array [], + "debug": [MockFunction], + "error": [MockFunction], + "fatal": [MockFunction], + "get": [MockFunction], + "info": [MockFunction], + "isLevelEnabled": [MockFunction], + "log": [MockFunction], + "trace": [MockFunction], + "warn": [MockFunction], + }, + "method": "post", + "sslOverrides": Object { + "cert": Object { + "data": Array [ + 10, + 45, + 45, + 45, + 45, + 45, + 66, + 69, + 71, + 73, + 78, + 32, + 67, + 69, + 82, + 84, + 73, + 70, + 73, + 67, + 65, + 84, + 69, + 45, + 45, + 45, + 45, + 45, + 10, + 45, + 45, + 45, + 45, + 45, + 69, + 78, + 68, + 32, + 67, + 69, + 82, + 84, + 73, + 70, + 73, + 67, + 65, + 84, + 69, + 45, + 45, + 45, + 45, + 45, + 10, + ], + "type": "Buffer", + }, + "key": Object { + "data": Array [ + 10, + 45, + 45, + 45, + 45, + 45, + 66, + 69, + 71, + 73, + 78, + 32, + 80, + 82, + 73, + 86, + 65, + 84, + 69, + 32, + 75, + 69, + 89, + 45, + 45, + 45, + 45, + 45, + 10, + 45, + 45, + 45, + 45, + 45, + 69, + 78, + 68, + 32, + 80, + 82, + 73, + 86, + 65, + 84, + 69, + 32, + 75, + 69, + 89, + 45, + 45, + 45, + 45, + 45, + 10, + ], + "type": "Buffer", + }, + "passphrase": "foobar", + }, + "url": "https://coolsite.net/issue/1/comment", + } + 1`] = ` +Object { + "axios": [Function], + "connectorMetricsCollector": ConnectorMetricsCollector { + "connectorId": "test-connector-id", + "logger": Object { + "context": Array [], + "debug": [MockFunction], + "error": [MockFunction], + "fatal": [MockFunction], + "get": [MockFunction], + "info": [MockFunction], + "isLevelEnabled": [MockFunction], + "log": [MockFunction], + "trace": [MockFunction], + "warn": [MockFunction], + }, + "metrics": Object { + "requestBodyBytes": 0, + }, + }, + "data": "{\\"body\\":\\"comment\\"}", + "logger": Object { + "context": Array [], + "debug": [MockFunction], + "error": [MockFunction], + "fatal": [MockFunction], + "get": [MockFunction], + "info": [MockFunction], + "isLevelEnabled": [MockFunction], + "log": [MockFunction], + "trace": [MockFunction], + "warn": [MockFunction], + }, + "method": "post", + "sslOverrides": Object { + "cert": Object { + "data": Array [ + 10, + 45, + 45, + 45, + 45, + 45, + 66, + 69, + 71, + 73, + 78, + 32, + 67, + 69, + 82, + 84, + 73, + 70, + 73, + 67, + 65, + 84, + 69, + 45, + 45, + 45, + 45, + 45, + 10, + 45, + 45, + 45, + 45, + 45, + 69, + 78, + 68, + 32, + 67, + 69, + 82, + 84, + 73, + 70, + 73, + 67, + 65, + 84, + 69, + 45, + 45, + 45, + 45, + 45, + 10, + ], + "type": "Buffer", + }, + "key": Object { + "data": Array [ + 10, + 45, + 45, + 45, + 45, + 45, + 66, + 69, + 71, + 73, + 78, + 32, + 80, + 82, + 73, + 86, + 65, + 84, + 69, + 32, + 75, + 69, + 89, + 45, + 45, + 45, + 45, + 45, + 10, + 45, + 45, + 45, + 45, + 45, + 69, + 78, + 68, + 32, + 80, + 82, + 73, + 86, + 65, + 84, + 69, + 32, + 75, + 69, + 89, + 45, + 45, + 45, + 45, + 45, + 10, + ], + "type": "Buffer", + }, + "passphrase": "foobar", + }, + "url": "https://coolsite.net/issue/1/comment", +} +`; From 06abcd45818dd30948b12e6b440d20c1468237e2 Mon Sep 17 00:00:00 2001 From: Ersin Erdal Date: Tue, 13 Aug 2024 12:04:19 +0300 Subject: [PATCH 18/25] Rename ConnectorMetricCollector to ConnectorUsageCollector --- .../server/lib/action_executor.test.ts | 37 +++--- .../actions/server/lib/action_executor.ts | 10 +- .../actions/server/lib/axios_utils.test.ts | 22 ++-- .../plugins/actions/server/lib/axios_utils.ts | 20 ++-- x-pack/plugins/actions/server/lib/index.ts | 1 - .../server/sub_action_framework/case.test.ts | 16 +-- .../server/sub_action_framework/case.ts | 28 ++--- .../sub_action_framework/executor.test.ts | 32 +++--- .../server/sub_action_framework/executor.ts | 4 +- .../server/sub_action_framework/mocks.ts | 14 +-- .../sub_action_connector.test.ts | 40 +++---- .../sub_action_connector.ts | 6 +- x-pack/plugins/actions/server/types.ts | 8 +- .../connector_usage_collector.test.ts} | 28 ++--- .../connector_usage_collector.ts} | 10 +- x-pack/plugins/actions/server/usage/index.ts | 1 + .../server/lib/trim_recovered_alerts.ts | 4 +- .../plugins/event_log/generated/mappings.json | 2 +- x-pack/plugins/event_log/generated/schemas.ts | 2 +- x-pack/plugins/event_log/scripts/mappings.js | 2 +- .../connector_types/bedrock/bedrock.test.ts | 73 ++++++------ .../server/connector_types/bedrock/bedrock.ts | 34 +++--- .../__snapshots__/service.test.ts.snap | 10 +- .../connector_types/cases_webhook/index.ts | 5 +- .../cases_webhook/service.test.ts | 63 +++++----- .../connector_types/cases_webhook/service.ts | 16 ++- .../crowdstrike/crowdstrike.test.ts | 42 +++---- .../crowdstrike/crowdstrike.ts | 26 ++--- .../d3security/d3security.test.ts | 16 +-- .../connector_types/d3security/d3security.ts | 6 +- .../connector_types/email/index.test.ts | 7 +- .../server/connector_types/email/index.ts | 4 +- .../connector_types/email/send_email.test.ts | 44 +++---- .../connector_types/email/send_email.ts | 21 ++-- .../email/send_email_graph_api.test.ts | 18 +-- .../email/send_email_graph_api.ts | 6 +- .../connector_types/es_index/index.test.ts | 27 ++--- .../connector_types/gemini/gemini.test.ts | 29 +++-- .../server/connector_types/gemini/gemini.ts | 22 ++-- .../server/connector_types/jira/index.ts | 4 +- .../connector_types/jira/service.test.ts | 48 ++++---- .../server/connector_types/jira/service.ts | 24 ++-- .../servicenow/create_service_wrapper.test.ts | 14 +-- .../lib/servicenow/create_service_wrapper.ts | 8 +- .../lib/servicenow/service.test.ts | 108 +++++++++--------- .../connector_types/lib/servicenow/service.ts | 18 +-- .../connector_types/lib/servicenow/types.ts | 6 +- .../connector_types/openai/openai.test.ts | 106 ++++++++--------- .../server/connector_types/openai/openai.ts | 22 ++-- .../opsgenie/connector.test.ts | 30 ++--- .../connector_types/opsgenie/connector.ts | 10 +- .../connector_types/pagerduty/index.test.ts | 30 ++--- .../server/connector_types/pagerduty/index.ts | 4 +- .../pagerduty/post_pagerduty.ts | 6 +- .../resilient/resilient.test.ts | 76 ++++++------ .../connector_types/resilient/resilient.ts | 34 +++--- .../sentinelone/sentinelone.test.ts | 20 ++-- .../sentinelone/sentinelone.ts | 56 ++++----- .../connector_types/server_log/index.test.ts | 5 +- .../connector_types/servicenow_itom/index.ts | 4 +- .../servicenow_itom/service.test.ts | 12 +- .../servicenow_itom/service.ts | 6 +- .../connector_types/servicenow_itsm/index.ts | 4 +- .../servicenow_itsm/service.test.ts | 72 ++++++------ .../connector_types/servicenow_sir/index.ts | 4 +- .../servicenow_sir/service.test.ts | 12 +- .../connector_types/servicenow_sir/service.ts | 6 +- .../connector_types/slack/index.test.ts | 20 ++-- .../server/connector_types/slack/index.ts | 4 +- .../connector_types/slack_api/index.test.ts | 24 ++-- .../server/connector_types/slack_api/index.ts | 4 +- .../connector_types/slack_api/service.test.ts | 24 ++-- .../connector_types/slack_api/service.ts | 10 +- .../server/connector_types/swimlane/index.ts | 4 +- .../connector_types/swimlane/service.test.ts | 22 ++-- .../connector_types/swimlane/service.ts | 10 +- .../connector_types/teams/index.test.ts | 18 +-- .../server/connector_types/teams/index.ts | 4 +- .../connector_types/thehive/thehive.test.ts | 36 +++--- .../server/connector_types/thehive/thehive.ts | 22 ++-- .../connector_types/tines/tines.test.ts | 40 +++---- .../server/connector_types/tines/tines.ts | 18 +-- .../torq/__snapshots__/index.test.ts.snap | 4 +- .../server/connector_types/torq/index.test.ts | 18 ++- .../server/connector_types/torq/index.ts | 4 +- .../webhook/__snapshots__/index.test.ts.snap | 4 +- .../connector_types/webhook/index.test.ts | 26 ++--- .../server/connector_types/webhook/index.ts | 4 +- .../connector_types/xmatters/index.test.ts | 12 +- .../server/connector_types/xmatters/index.ts | 4 +- .../connector_types/xmatters/post_xmatters.ts | 10 +- .../alerts/server/sub_action_connector.ts | 6 +- .../tests/actions/connector_types/bedrock.ts | 6 +- .../actions/connector_types/cases_webhook.ts | 2 +- .../actions/connector_types/d3security.ts | 2 +- .../tests/actions/connector_types/email.ts | 2 +- .../tests/actions/connector_types/es_index.ts | 2 +- .../tests/actions/connector_types/jira.ts | 2 +- .../tests/actions/connector_types/openai.ts | 2 +- .../tests/actions/connector_types/opsgenie.ts | 2 +- .../actions/connector_types/pagerduty.ts | 2 +- .../actions/connector_types/resilient.ts | 2 +- .../actions/connector_types/server_log.ts | 2 +- .../connector_types/servicenow_itom.ts | 4 +- .../connector_types/servicenow_itsm.ts | 8 +- .../actions/connector_types/servicenow_sir.ts | 6 +- .../actions/connector_types/slack_webhook.ts | 2 +- .../tests/actions/connector_types/swimlane.ts | 4 +- .../tests/actions/connector_types/tines.ts | 10 +- .../tests/actions/connector_types/torq.ts | 2 +- .../tests/actions/connector_types/webhook.ts | 2 +- .../tests/actions/connector_types/xmatters.ts | 2 +- .../group2/tests/actions/execute.ts | 2 +- .../actions/sub_action_framework/index.ts | 2 +- 114 files changed, 946 insertions(+), 981 deletions(-) rename x-pack/plugins/actions/server/{lib/connector_metrics_collector.test.ts => usage/connector_usage_collector.test.ts} (68%) rename x-pack/plugins/actions/server/{lib/connector_metrics_collector.ts => usage/connector_usage_collector.ts} (85%) diff --git a/x-pack/plugins/actions/server/lib/action_executor.test.ts b/x-pack/plugins/actions/server/lib/action_executor.test.ts index c643156886454..9c6313964ac02 100644 --- a/x-pack/plugins/actions/server/lib/action_executor.test.ts +++ b/x-pack/plugins/actions/server/lib/action_executor.test.ts @@ -18,7 +18,7 @@ import { } from '@kbn/core/server/mocks'; import { eventLoggerMock } from '@kbn/event-log-plugin/server/mocks'; import { spacesServiceMock } from '@kbn/spaces-plugin/server/spaces_service/spaces_service.mock'; -import { ActionType as ConnectorType, ConnectorMetricsCollector } from '../types'; +import { ActionType as ConnectorType, ConnectorUsageCollector } from '../types'; import { actionsAuthorizationMock, actionsMock } from '../mocks'; import { asBackgroundTaskExecutionSource, @@ -150,7 +150,7 @@ const connectorSavedObject = { references: [], }; -interface ActionMetrics { +interface ActionUsage { request_body_bytes: number; } @@ -197,7 +197,7 @@ const getBaseExecuteStartEventLogDoc = (unsecured: boolean) => { const getBaseExecuteEventLogDoc = ( unsecured: boolean, - actionMetrics: ActionMetrics = { request_body_bytes: 0 } + actionUsage: ActionUsage = { request_body_bytes: 0 } ) => { const base = getBaseExecuteStartEventLogDoc(unsecured); return { @@ -208,7 +208,7 @@ const getBaseExecuteEventLogDoc = ( ...base.kibana.action, execution: { ...base.kibana.action.execution, - metrics: actionMetrics, + usage: actionUsage, }, }, }, @@ -250,10 +250,7 @@ beforeEach(() => { getActionsAuthorizationWithRequest.mockReturnValue(authorizationMock); }); -const mockGetRequestBodyByte = jest.spyOn( - ConnectorMetricsCollector.prototype, - 'getRequestBodyByte' -); +const mockGetRequestBodyByte = jest.spyOn(ConnectorUsageCollector.prototype, 'getRequestBodyByte'); describe('Action Executor', () => { for (const executeUnsecure of [false, true]) { @@ -304,7 +301,7 @@ describe('Action Executor', () => { }, params: { foo: true }, logger: loggerMock, - connectorMetricsCollector: expect.any(ConnectorMetricsCollector), + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); expect(loggerMock.debug).toBeCalledWith('executing action test:1: 1'); @@ -379,7 +376,7 @@ describe('Action Executor', () => { params: { foo: true }, logger: loggerMock, source: executionSource.source, - connectorMetricsCollector: expect.any(ConnectorMetricsCollector), + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); expect(loggerMock.debug).toBeCalledWith('executing action test:1: 1'); @@ -459,7 +456,7 @@ describe('Action Executor', () => { }, params: { foo: true }, logger: loggerMock, - connectorMetricsCollector: expect.any(ConnectorMetricsCollector), + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); expect(loggerMock.debug).toBeCalledWith('executing action test:preconfigured: Preconfigured'); @@ -543,7 +540,7 @@ describe('Action Executor', () => { params: { foo: true }, logger: loggerMock, request: {}, - connectorMetricsCollector: expect.any(ConnectorMetricsCollector), + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); } @@ -924,7 +921,7 @@ describe('Action Executor', () => { }, params: { foo: true }, logger: loggerMock, - connectorMetricsCollector: expect.any(ConnectorMetricsCollector), + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); }); @@ -956,7 +953,7 @@ describe('Action Executor', () => { params: { foo: true }, logger: loggerMock, request: {}, - connectorMetricsCollector: expect.any(ConnectorMetricsCollector), + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); }); @@ -1025,7 +1022,7 @@ describe('Action Executor', () => { }, params: { foo: true }, logger: loggerMock, - connectorMetricsCollector: expect.any(ConnectorMetricsCollector), + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); expect(loggerMock.debug).toBeCalledWith('executing action test:preconfigured: Preconfigured'); @@ -1066,7 +1063,7 @@ describe('Action Executor', () => { name: 'Preconfigured', execution: { ...execStartDoc.kibana.action.execution, - metrics: { + usage: { request_body_bytes: 0, }, }, @@ -1118,7 +1115,7 @@ describe('Action Executor', () => { params: { foo: true }, logger: loggerMock, request: {}, - connectorMetricsCollector: expect.any(ConnectorMetricsCollector), + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); expect(loggerMock.debug).toBeCalledWith( @@ -1338,7 +1335,7 @@ describe('Action Executor', () => { }, params: { foo: true }, logger: loggerMock, - connectorMetricsCollector: expect.any(ConnectorMetricsCollector), + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); } }); @@ -1611,7 +1608,7 @@ describe('Event log', () => { gen_ai: { usage: mockGenAi.usage, }, - metrics: { + usage: { request_body_bytes: 0, }, }, @@ -1711,7 +1708,7 @@ describe('Event log', () => { total_tokens: 35, }, }, - metrics: { + usage: { request_body_bytes: 0, }, }, diff --git a/x-pack/plugins/actions/server/lib/action_executor.ts b/x-pack/plugins/actions/server/lib/action_executor.ts index 4e9ddd4559dd3..c302b0da3e886 100644 --- a/x-pack/plugins/actions/server/lib/action_executor.ts +++ b/x-pack/plugins/actions/server/lib/action_executor.ts @@ -23,7 +23,7 @@ import { IEventLogger, SAVED_OBJECT_REL_PRIMARY } from '@kbn/event-log-plugin/se import { createTaskRunError, TaskErrorSource } from '@kbn/task-manager-plugin/server'; import { getErrorSource } from '@kbn/task-manager-plugin/server/task_running'; import { GEN_AI_TOKEN_COUNT_EVENT } from './event_based_telemetry'; -import { ConnectorMetricsCollector } from './connector_metrics_collector'; +import { ConnectorUsageCollector } from '../usage/connector_usage_collector'; import { getGenAiTokenTracking, shouldTrackGenAiToken } from './gen_ai_token_tracking'; import { validateConfig, @@ -399,7 +399,7 @@ export class ActionExecutor { const loggerId = actionTypeId.startsWith('.') ? actionTypeId.substring(1) : actionTypeId; const logger = this.actionExecutorContext!.logger.get(loggerId); - const connectorMetricsCollector = new ConnectorMetricsCollector({ + const connectorUsageCollector = new ConnectorUsageCollector({ logger, connectorId: actionId, }); @@ -518,7 +518,7 @@ export class ActionExecutor { logger, source, ...(actionType.isSystemActionType ? { request } : {}), - connectorMetricsCollector, + connectorUsageCollector, }); if (rawResult && rawResult.status === 'error') { @@ -559,8 +559,8 @@ export class ActionExecutor { event.user.id = currentUser?.profile_uid; set( event, - 'kibana.action.execution.metrics.request_body_bytes', - connectorMetricsCollector.getRequestBodyByte() + 'kibana.action.execution.usage.request_body_bytes', + connectorUsageCollector.getRequestBodyByte() ); if (result.status === 'ok') { diff --git a/x-pack/plugins/actions/server/lib/axios_utils.test.ts b/x-pack/plugins/actions/server/lib/axios_utils.test.ts index 1ca09888e0f5a..bee09a90ed27b 100644 --- a/x-pack/plugins/actions/server/lib/axios_utils.test.ts +++ b/x-pack/plugins/actions/server/lib/axios_utils.test.ts @@ -21,7 +21,7 @@ import { import { loggingSystemMock } from '@kbn/core/server/mocks'; import { actionsConfigMock } from '../actions_config.mock'; import { getCustomAgents } from './get_custom_agents'; -import { ConnectorMetricsCollector } from './connector_metrics_collector'; +import { ConnectorUsageCollector } from '../usage/connector_usage_collector'; const TestUrl = 'https://elastic.co/foo/bar/baz'; @@ -80,7 +80,7 @@ describe('request', () => { }); }); - test('adds request body bytes from request header on a successful request when connectorMetricsCollector is provided', async () => { + test('adds request body bytes from request header on a successful request when connectorUsageCollector is provided', async () => { const contentLength = 12; axiosMock.mockImplementation(() => ({ status: 200, @@ -91,7 +91,7 @@ describe('request', () => { getHeader: () => contentLength, }, })); - const connectorMetricsCollector = new ConnectorMetricsCollector({ + const connectorUsageCollector = new ConnectorUsageCollector({ logger, connectorId: 'test-connector-id', }); @@ -101,10 +101,10 @@ describe('request', () => { logger, data: { test: 12345 }, configurationUtilities, - connectorMetricsCollector, + connectorUsageCollector, }); - expect(connectorMetricsCollector.getRequestBodyByte()).toBe(contentLength); + expect(connectorUsageCollector.getRequestBodyByte()).toBe(contentLength); }); test('adds request body bytes from request header on a failed', async () => { @@ -115,7 +115,7 @@ describe('request', () => { headers: { 'Content-Length': contentLength }, }) ); - const connectorMetricsCollector = new ConnectorMetricsCollector({ + const connectorUsageCollector = new ConnectorUsageCollector({ logger, connectorId: 'test-connector-id', }); @@ -126,15 +126,15 @@ describe('request', () => { url: '/test', logger, configurationUtilities, - connectorMetricsCollector, + connectorUsageCollector, }); } catch (e) { - expect(connectorMetricsCollector.getRequestBodyByte()).toBe(contentLength); + expect(connectorUsageCollector.getRequestBodyByte()).toBe(contentLength); } }); test('adds request body bytes from data when request header does not exist', async () => { - const connectorMetricsCollector = new ConnectorMetricsCollector({ + const connectorUsageCollector = new ConnectorUsageCollector({ logger, connectorId: 'test-connector-id', }); @@ -146,10 +146,10 @@ describe('request', () => { logger, data, configurationUtilities, - connectorMetricsCollector, + connectorUsageCollector, }); - expect(connectorMetricsCollector.getRequestBodyByte()).toBe( + expect(connectorUsageCollector.getRequestBodyByte()).toBe( Buffer.byteLength(JSON.stringify(data), 'utf8') ); }); diff --git a/x-pack/plugins/actions/server/lib/axios_utils.ts b/x-pack/plugins/actions/server/lib/axios_utils.ts index 2782d4bd9cfb6..254ad1a36f6e2 100644 --- a/x-pack/plugins/actions/server/lib/axios_utils.ts +++ b/x-pack/plugins/actions/server/lib/axios_utils.ts @@ -17,7 +17,7 @@ import { import { Logger } from '@kbn/core/server'; import { getCustomAgents } from './get_custom_agents'; import { ActionsConfigurationUtilities } from '../actions_config'; -import { ConnectorMetricsCollector, SSLSettings } from '../types'; +import { ConnectorUsageCollector, SSLSettings } from '../types'; import { combineHeadersWithBasicAuthHeader } from './get_basic_auth_header'; export const request = async ({ @@ -30,7 +30,7 @@ export const request = async ({ headers, sslOverrides, timeout, - connectorMetricsCollector, + connectorUsageCollector, ...config }: { axios: AxiosInstance; @@ -42,7 +42,7 @@ export const request = async ({ headers?: Record; timeout?: number; sslOverrides?: SSLSettings; - connectorMetricsCollector?: ConnectorMetricsCollector; + connectorUsageCollector?: ConnectorUsageCollector; } & AxiosRequestConfig): Promise => { if (!isEmpty(axios?.defaults?.baseURL ?? '')) { throw new Error( @@ -80,14 +80,14 @@ export const request = async ({ timeout: Math.max(settingsTimeout, timeout ?? 0), }); - if (connectorMetricsCollector) { - connectorMetricsCollector.addRequestBodyBytes(result, data); + if (connectorUsageCollector) { + connectorUsageCollector.addRequestBodyBytes(result, data); } return result; } catch (error) { - if (connectorMetricsCollector) { - connectorMetricsCollector.addRequestBodyBytes(error, data); + if (connectorUsageCollector) { + connectorUsageCollector.addRequestBodyBytes(error, data); } throw error; } @@ -99,14 +99,14 @@ export const patch = async ({ data, logger, configurationUtilities, - connectorMetricsCollector, + connectorUsageCollector, }: { axios: AxiosInstance; url: string; data: T; logger: Logger; configurationUtilities: ActionsConfigurationUtilities; - connectorMetricsCollector?: ConnectorMetricsCollector; + connectorUsageCollector?: ConnectorUsageCollector; }): Promise => { return request({ axios, @@ -115,7 +115,7 @@ export const patch = async ({ method: 'patch', data, configurationUtilities, - connectorMetricsCollector, + connectorUsageCollector, }); }; diff --git a/x-pack/plugins/actions/server/lib/index.ts b/x-pack/plugins/actions/server/lib/index.ts index 07939fc920590..2737d83abfff6 100644 --- a/x-pack/plugins/actions/server/lib/index.ts +++ b/x-pack/plugins/actions/server/lib/index.ts @@ -39,4 +39,3 @@ export { validateEmptyStrings } from './validate_empty_strings'; export { parseDate } from './parse_date'; export type { RelatedSavedObjects } from './related_saved_objects'; export { getBasicAuthHeader, combineHeadersWithBasicAuthHeader } from './get_basic_auth_header'; -export { ConnectorMetricsCollector } from './connector_metrics_collector'; diff --git a/x-pack/plugins/actions/server/sub_action_framework/case.test.ts b/x-pack/plugins/actions/server/sub_action_framework/case.test.ts index 3811d73e7000f..aa32dd8853dba 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/case.test.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/case.test.ts @@ -12,14 +12,14 @@ import { actionsConfigMock } from '../actions_config.mock'; import { actionsMock } from '../mocks'; import { TestCaseConnector } from './mocks'; import { ActionsConfigurationUtilities } from '../actions_config'; -import { ConnectorMetricsCollector } from '../lib'; +import { ConnectorUsageCollector } from '../usage'; describe('CaseConnector', () => { let logger: MockedLogger; let services: ReturnType; let mockedActionsConfig: jest.Mocked; let service: TestCaseConnector; - let connectorMetricsCollector: ConnectorMetricsCollector; + let connectorUsageCollector: ConnectorUsageCollector; const pushToServiceIncidentParamsSchema = { name: schema.string(), category: schema.nullable(schema.string()), @@ -60,7 +60,7 @@ describe('CaseConnector', () => { pushToServiceIncidentParamsSchema ); - connectorMetricsCollector = new ConnectorMetricsCollector({ + connectorUsageCollector = new ConnectorUsageCollector({ logger, connectorId: 'test-connector-id', }); @@ -198,7 +198,7 @@ describe('CaseConnector', () => { describe('pushToService', () => { it('should create an incident if externalId is null', async () => { - const res = await service.pushToService(pushToServiceParams, connectorMetricsCollector); + const res = await service.pushToService(pushToServiceParams, connectorUsageCollector); expect(res).toEqual({ id: 'create-incident', title: 'Test incident', @@ -213,7 +213,7 @@ describe('CaseConnector', () => { incident: { ...pushToServiceParams.incident, externalId: 'test-id' }, comments: [], }, - connectorMetricsCollector + connectorUsageCollector ); expect(res).toEqual({ @@ -233,7 +233,7 @@ describe('CaseConnector', () => { { comment: 'comment-2', commentId: 'comment-id-2' }, ], }, - connectorMetricsCollector + connectorUsageCollector ); expect(res).toEqual({ @@ -261,7 +261,7 @@ describe('CaseConnector', () => { // @ts-expect-error comments, }, - connectorMetricsCollector + connectorUsageCollector ); expect(res).toEqual({ @@ -278,7 +278,7 @@ describe('CaseConnector', () => { ...pushToServiceParams, comments: [], }, - connectorMetricsCollector + connectorUsageCollector ); expect(res).toEqual({ diff --git a/x-pack/plugins/actions/server/sub_action_framework/case.ts b/x-pack/plugins/actions/server/sub_action_framework/case.ts index b03d6e3001205..1d942b210dbf9 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/case.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/case.ts @@ -9,16 +9,16 @@ import { schema, Type } from '@kbn/config-schema'; import { ExternalServiceIncidentResponse, PushToServiceResponse } from './types'; import { SubActionConnector } from './sub_action_connector'; import { ServiceParams } from './types'; -import { ConnectorMetricsCollector } from '../lib'; +import { ConnectorUsageCollector } from '../usage'; export interface CaseConnectorInterface { addComment: ( { incidentId, comment }: { incidentId: string; comment: string }, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ) => Promise; createIncident: ( incident: Incident, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ) => Promise; updateIncident: ( { @@ -28,18 +28,18 @@ export interface CaseConnectorInterface { incidentId: string; incident: Incident; }, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ) => Promise; getIncident: ( { id }: { id: string }, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ) => Promise; pushToService: ( params: { incident: { externalId: string | null } & Incident; comments: Array<{ commentId: string; comment: string }>; }, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ) => Promise; } @@ -80,12 +80,12 @@ export abstract class CaseConnector; public abstract createIncident( incident: Incident, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise; public abstract updateIncident( { @@ -95,11 +95,11 @@ export abstract class CaseConnector; public abstract getIncident( { id }: { id: string }, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise; public async pushToService( @@ -107,7 +107,7 @@ export abstract class CaseConnector; }, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ) { const { incident, comments } = params; const { externalId, ...rest } = incident; @@ -120,10 +120,10 @@ export abstract class CaseConnector 0) { @@ -135,7 +135,7 @@ export abstract class CaseConnector { const actionId = 'test-action-id'; @@ -31,7 +31,7 @@ describe('Executor', () => { let logger: MockedLogger; let services: ReturnType; let mockedActionsConfig: jest.Mocked; - let connectorMetricsCollector: ConnectorMetricsCollector; + let connectorUsageCollector: ConnectorUsageCollector; const createExecutor = (Service: IService) => { const connector = { @@ -57,7 +57,7 @@ describe('Executor', () => { logger = loggingSystemMock.createLogger(); services = actionsMock.createServices(); mockedActionsConfig = actionsConfigMock.create(); - connectorMetricsCollector = new ConnectorMetricsCollector({ + connectorUsageCollector = new ConnectorUsageCollector({ logger, connectorId: 'test-connector-id', }); @@ -74,7 +74,7 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, - connectorMetricsCollector, + connectorUsageCollector, }); expect(res).toEqual({ @@ -97,7 +97,7 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, - connectorMetricsCollector, + connectorUsageCollector, }); expect(res).toEqual({ @@ -120,7 +120,7 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, - connectorMetricsCollector, + connectorUsageCollector, }); expect(res).toEqual({ @@ -141,7 +141,7 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, - connectorMetricsCollector, + connectorUsageCollector, }); expect(res).toEqual({ @@ -163,7 +163,7 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, - connectorMetricsCollector, + connectorUsageCollector, }) ).rejects.toThrowError('You should register at least one subAction for your connector type'); }); @@ -180,7 +180,7 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, - connectorMetricsCollector, + connectorUsageCollector, }) ).rejects.toThrowError( 'Sub action "not-exist" is not registered. Connector id: test-action-id. Connector name: Test. Connector type: .test' @@ -199,7 +199,7 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, - connectorMetricsCollector, + connectorUsageCollector, }); } catch (e) { expect(getErrorSource(e)).toBe(TaskErrorSource.USER); @@ -221,7 +221,7 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, - connectorMetricsCollector, + connectorUsageCollector, }) ).rejects.toThrowError( 'Method "not-exist" does not exists in service. Sub action: "testUrl". Connector id: test-action-id. Connector name: Test. Connector type: .test' @@ -240,7 +240,7 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, - connectorMetricsCollector, + connectorUsageCollector, }) ).rejects.toThrowError( 'Method "notAFunction" must be a function. Connector id: test-action-id. Connector name: Test. Connector type: .test' @@ -259,14 +259,14 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, - connectorMetricsCollector, + connectorUsageCollector, }) ).rejects.toThrowError( 'Request validation failed (Error: [id]: expected value of type [string] but got [undefined])' ); }); - it('Passes connectorMetricsCollector to the subAction method as a second param', async () => { + it('Passes connectorUsageCollector to the subAction method as a second param', async () => { let echoSpy; const subActionParams = { id: 'test-id' }; @@ -300,9 +300,9 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, - connectorMetricsCollector, + connectorUsageCollector, }); - expect(echoSpy).toHaveBeenCalledWith(subActionParams, connectorMetricsCollector); + expect(echoSpy).toHaveBeenCalledWith(subActionParams, connectorUsageCollector); }); }); diff --git a/x-pack/plugins/actions/server/sub_action_framework/executor.ts b/x-pack/plugins/actions/server/sub_action_framework/executor.ts index 50c6b0d760e2a..a8fbcb6e05984 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/executor.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/executor.ts @@ -37,7 +37,7 @@ export const buildExecutor = < secrets, services, request, - connectorMetricsCollector, + connectorUsageCollector, }) => { const subAction = params.subAction; const subActionParams = params.subActionParams; @@ -96,7 +96,7 @@ export const buildExecutor = < } } - const data = await func.call(service, subActionParams, connectorMetricsCollector); + const data = await func.call(service, subActionParams, connectorUsageCollector); return { status: 'ok', data: data ?? {}, actionId }; }; }; diff --git a/x-pack/plugins/actions/server/sub_action_framework/mocks.ts b/x-pack/plugins/actions/server/sub_action_framework/mocks.ts index 2ed6afe191501..28e4a2abc224e 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/mocks.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/mocks.ts @@ -8,7 +8,7 @@ import { schema, Type, TypeOf } from '@kbn/config-schema'; import { AxiosError } from 'axios'; -import { ConnectorMetricsCollector } from '../lib'; +import { ConnectorUsageCollector } from '../usage'; import { SubActionConnector } from './sub_action_connector'; import { CaseConnector } from './case'; import { ExternalServiceIncidentResponse, ServiceParams } from './types'; @@ -60,7 +60,7 @@ export class TestSubActionConnector extends SubActionConnector | null }, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ) { const res = await this.request( { @@ -69,7 +69,7 @@ export class TestSubActionConnector extends SubActionConnector }, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ) { const res = await this.request( { @@ -86,7 +86,7 @@ export class TestSubActionConnector extends SubActionConnector } = {}, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ) { const res = await this.request( { @@ -104,7 +104,7 @@ export class TestSubActionConnector extends SubActionConnector { let services: ReturnType; let mockedActionsConfig: jest.Mocked; let service: TestSubActionConnector; - let connectorMetricsCollector: ConnectorMetricsCollector; + let connectorUsageCollector: ConnectorUsageCollector; beforeEach(() => { jest.resetAllMocks(); @@ -73,7 +73,7 @@ describe('SubActionConnector', () => { services, }); - connectorMetricsCollector = new ConnectorMetricsCollector({ + connectorUsageCollector = new ConnectorUsageCollector({ logger, connectorId: 'test-connector-id', }); @@ -94,34 +94,34 @@ describe('SubActionConnector', () => { it('removes double slashes correctly', async () => { await service.testUrl( { url: 'https://example.com//api///test-endpoint' }, - connectorMetricsCollector + connectorUsageCollector ); expect(requestMock.mock.calls[0][0].url).toBe('https://example.com/api/test-endpoint'); }); it('removes the ending slash correctly', async () => { - await service.testUrl({ url: 'https://example.com/' }, connectorMetricsCollector); + await service.testUrl({ url: 'https://example.com/' }, connectorUsageCollector); expect(requestMock.mock.calls[0][0].url).toBe('https://example.com'); }); it('throws an error if the url is invalid', async () => { expect.assertions(1); await expect(async () => - service.testUrl({ url: 'invalid-url' }, connectorMetricsCollector) + service.testUrl({ url: 'invalid-url' }, connectorUsageCollector) ).rejects.toThrow('URL Error: Invalid URL: invalid-url'); }); it('throws an error if the url starts with backslashes', async () => { expect.assertions(1); await expect(async () => - service.testUrl({ url: '//example.com/foo' }, connectorMetricsCollector) + service.testUrl({ url: '//example.com/foo' }, connectorUsageCollector) ).rejects.toThrow('URL Error: Invalid URL: //example.com/foo'); }); it('throws an error if the protocol is not supported', async () => { expect.assertions(1); await expect(async () => - service.testUrl({ url: 'ftp://example.com' }, connectorMetricsCollector) + service.testUrl({ url: 'ftp://example.com' }, connectorUsageCollector) ).rejects.toThrow('URL Error: Invalid protocol'); }); @@ -133,14 +133,14 @@ describe('SubActionConnector', () => { }); await expect(async () => - service.testUrl({ url: 'https://example.com' }, connectorMetricsCollector) + service.testUrl({ url: 'https://example.com' }, connectorUsageCollector) ).rejects.toThrow('error configuring connector action: URI is not allowed'); }); }); describe('Data', () => { it('sets data to an empty object if the data are null', async () => { - await service.testUrl({ url: 'https://example.com', data: null }, connectorMetricsCollector); + await service.testUrl({ url: 'https://example.com', data: null }, connectorUsageCollector); expect(requestMock).toHaveBeenCalledTimes(1); const { data } = requestMock.mock.calls[0][0]; @@ -150,7 +150,7 @@ describe('SubActionConnector', () => { it('pass data to axios correctly if not null', async () => { await service.testUrl( { url: 'https://example.com', data: { foo: 'foo' } }, - connectorMetricsCollector + connectorUsageCollector ); expect(requestMock).toHaveBeenCalledTimes(1); @@ -161,7 +161,7 @@ describe('SubActionConnector', () => { it('removeNullOrUndefinedFields: removes null values and undefined values correctly', async () => { await service.testData( { data: { foo: 'foo', bar: null, baz: undefined } }, - connectorMetricsCollector + connectorUsageCollector ); expect(requestMock).toHaveBeenCalledTimes(1); @@ -183,7 +183,7 @@ describe('SubActionConnector', () => { describe('Fetching', () => { it('fetch correctly', async () => { - const res = await service.testUrl({ url: 'https://example.com' }, connectorMetricsCollector); + const res = await service.testUrl({ url: 'https://example.com' }, connectorUsageCollector); expect(requestMock).toHaveBeenCalledTimes(1); expect(requestMock).toBeCalledWith({ @@ -197,7 +197,7 @@ describe('SubActionConnector', () => { 'X-Test-Header': 'test', }, url: 'https://example.com', - connectorMetricsCollector, + connectorUsageCollector, }); expect(logger.debug).toBeCalledWith( @@ -210,7 +210,7 @@ describe('SubActionConnector', () => { it('validates the response correctly', async () => { requestMock.mockReturnValue({ data: { invalidField: 'test' } }); await expect(async () => - service.testUrl({ url: 'https://example.com' }, connectorMetricsCollector) + service.testUrl({ url: 'https://example.com' }, connectorUsageCollector) ).rejects.toThrow( 'Response validation failed (Error: [status]: expected value of type [string] but got [undefined])' ); @@ -222,7 +222,7 @@ describe('SubActionConnector', () => { }); await expect(async () => - service.testUrl({ url: 'https://example.com' }, connectorMetricsCollector) + service.testUrl({ url: 'https://example.com' }, connectorUsageCollector) ).rejects.toThrow('Message: An error occurred. Code: 500'); expect(logger.debug).toHaveBeenLastCalledWith( @@ -231,7 +231,7 @@ describe('SubActionConnector', () => { }); it('converts auth axios property to a basic auth header if provided', async () => { - await service.testAuth(undefined, connectorMetricsCollector); + await service.testAuth(undefined, connectorUsageCollector); expect(requestMock).toHaveBeenCalledTimes(1); expect(requestMock).toBeCalledWith({ @@ -246,14 +246,14 @@ describe('SubActionConnector', () => { Authorization: `Basic ${Buffer.from('username:password').toString('base64')}`, }, url: 'https://example.com', - connectorMetricsCollector, + connectorUsageCollector, }); }); it('does not override an authorization header if provided', async () => { await service.testAuth( { headers: { Authorization: 'Bearer my_token' } }, - connectorMetricsCollector + connectorUsageCollector ); expect(requestMock).toHaveBeenCalledTimes(1); @@ -269,7 +269,7 @@ describe('SubActionConnector', () => { Authorization: 'Bearer my_token', }, url: 'https://example.com', - connectorMetricsCollector, + connectorUsageCollector, }); }); }); diff --git a/x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.ts b/x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.ts index cc35e7f074ba6..fe59feab4376b 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.ts @@ -24,7 +24,7 @@ import { IncomingMessage } from 'http'; import { PassThrough } from 'stream'; import { KibanaRequest } from '@kbn/core-http-server'; import { inspect } from 'util'; -import { ConnectorMetricsCollector } from '../lib'; +import { ConnectorUsageCollector } from '../usage'; import { assertURL } from './helpers/validators'; import { ActionsConfigurationUtilities } from '../actions_config'; import { SubAction, SubActionRequestParams } from './types'; @@ -141,7 +141,7 @@ export abstract class SubActionConnector { timeout, ...config }: SubActionRequestParams, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise> { try { this.assertURL(url); @@ -164,7 +164,7 @@ export abstract class SubActionConnector { configurationUtilities: this.configurationUtilities, headers: this.getHeaders(auth, headers as AxiosHeaders), timeout, - connectorMetricsCollector, + connectorUsageCollector, }); this.validateResponse(responseSchema, res.data); diff --git a/x-pack/plugins/actions/server/types.ts b/x-pack/plugins/actions/server/types.ts index ffac1a9151c42..487e7630d40f9 100644 --- a/x-pack/plugins/actions/server/types.ts +++ b/x-pack/plugins/actions/server/types.ts @@ -40,8 +40,10 @@ export type ActionTypeParams = Record; export type ConnectorTokenClientContract = PublicMethodsOf; import { Connector, ConnectorWithExtraFindData } from './application/connector/types'; -import type { ActionExecutionSource, ConnectorMetricsCollector } from './lib'; -export { ActionExecutionSourceType, ConnectorMetricsCollector } from './lib'; +import type { ActionExecutionSource } from './lib'; +export { ActionExecutionSourceType } from './lib'; +import { ConnectorUsageCollector } from './usage'; +export { ConnectorUsageCollector } from './usage'; export interface Services { savedObjectsClient: SavedObjectsClientContract; @@ -86,7 +88,7 @@ export interface ActionTypeExecutorOptions< configurationUtilities: ActionsConfigurationUtilities; source?: ActionExecutionSource; request?: KibanaRequest; - connectorMetricsCollector: ConnectorMetricsCollector; + connectorUsageCollector: ConnectorUsageCollector; } export type ActionResult = Connector; diff --git a/x-pack/plugins/actions/server/lib/connector_metrics_collector.test.ts b/x-pack/plugins/actions/server/usage/connector_usage_collector.test.ts similarity index 68% rename from x-pack/plugins/actions/server/lib/connector_metrics_collector.test.ts rename to x-pack/plugins/actions/server/usage/connector_usage_collector.test.ts index 00d5dd4af1105..dcf071685f24f 100644 --- a/x-pack/plugins/actions/server/lib/connector_metrics_collector.test.ts +++ b/x-pack/plugins/actions/server/usage/connector_usage_collector.test.ts @@ -5,15 +5,15 @@ * 2.0. */ -import { ConnectorMetricsCollector } from '../types'; +import { ConnectorUsageCollector } from '../types'; import { AxiosHeaders, AxiosResponse } from 'axios'; import { loggingSystemMock } from '@kbn/core/server/mocks'; -describe('ConnectorMetricsCollector', () => { +describe('ConnectorUsageCollector', () => { const logger = loggingSystemMock.createLogger(); test('it collects requestBodyBytes from response.request.headers', async () => { - const connectorMetricsCollector = new ConnectorMetricsCollector({ + const connectorUsageCollector = new ConnectorUsageCollector({ logger, connectorId: 'test-connector-id', }); @@ -32,16 +32,16 @@ describe('ConnectorMetricsCollector', () => { }, }; - connectorMetricsCollector.addRequestBodyBytes(axiosResponse, data); + connectorUsageCollector.addRequestBodyBytes(axiosResponse, data); - expect(connectorMetricsCollector.getRequestBodyByte()).toBe(contentLength); + expect(connectorUsageCollector.getRequestBodyByte()).toBe(contentLength); - connectorMetricsCollector.addRequestBodyBytes(axiosResponse, data); + connectorUsageCollector.addRequestBodyBytes(axiosResponse, data); - expect(connectorMetricsCollector.getRequestBodyByte()).toBe(contentLength + contentLength); + expect(connectorUsageCollector.getRequestBodyByte()).toBe(contentLength + contentLength); }); test('it collects requestBodyBytes from data when header is is missing', async () => { - const connectorMetricsCollector = new ConnectorMetricsCollector({ + const connectorUsageCollector = new ConnectorUsageCollector({ logger, connectorId: 'test-connector-id', }); @@ -59,17 +59,17 @@ describe('ConnectorMetricsCollector', () => { }, }; - connectorMetricsCollector.addRequestBodyBytes(axiosResponse, data); + connectorUsageCollector.addRequestBodyBytes(axiosResponse, data); - expect(connectorMetricsCollector.getRequestBodyByte()).toBe(contentLength); + expect(connectorUsageCollector.getRequestBodyByte()).toBe(contentLength); - connectorMetricsCollector.addRequestBodyBytes(axiosResponse, data); + connectorUsageCollector.addRequestBodyBytes(axiosResponse, data); - expect(connectorMetricsCollector.getRequestBodyByte()).toBe(contentLength + contentLength); + expect(connectorUsageCollector.getRequestBodyByte()).toBe(contentLength + contentLength); }); test('it logs an error when the body cannot be stringified ', async () => { - const connectorMetricsCollector = new ConnectorMetricsCollector({ + const connectorUsageCollector = new ConnectorUsageCollector({ logger, connectorId: 'test-connector-id', }); @@ -92,7 +92,7 @@ describe('ConnectorMetricsCollector', () => { }, }; - connectorMetricsCollector.addRequestBodyBytes(axiosResponse, data); + connectorUsageCollector.addRequestBodyBytes(axiosResponse, data); expect(logger.error).toHaveBeenCalledTimes(1); expect(logger.error).toHaveBeenCalledWith( diff --git a/x-pack/plugins/actions/server/lib/connector_metrics_collector.ts b/x-pack/plugins/actions/server/usage/connector_usage_collector.ts similarity index 85% rename from x-pack/plugins/actions/server/lib/connector_metrics_collector.ts rename to x-pack/plugins/actions/server/usage/connector_usage_collector.ts index 1cfa6888e4f1f..542be0ebf7c70 100644 --- a/x-pack/plugins/actions/server/lib/connector_metrics_collector.ts +++ b/x-pack/plugins/actions/server/usage/connector_usage_collector.ts @@ -9,13 +9,13 @@ import { AxiosError, AxiosResponse } from 'axios'; import { Logger } from '@kbn/core/server'; import { isUndefined } from 'lodash'; -interface ConnectorMetrics { +interface ConnectorUsage { requestBodyBytes: number; } -export class ConnectorMetricsCollector { +export class ConnectorUsageCollector { private connectorId: string; - private metrics: ConnectorMetrics = { + private usage: ConnectorUsage = { requestBodyBytes: 0, }; @@ -43,10 +43,10 @@ export class ConnectorMetricsCollector { } } - this.metrics.requestBodyBytes = this.metrics.requestBodyBytes + bytes; + this.usage.requestBodyBytes = this.usage.requestBodyBytes + bytes; } public getRequestBodyByte() { - return this.metrics.requestBodyBytes; + return this.usage.requestBodyBytes; } } diff --git a/x-pack/plugins/actions/server/usage/index.ts b/x-pack/plugins/actions/server/usage/index.ts index 722ad76014f07..d4faf364b7295 100644 --- a/x-pack/plugins/actions/server/usage/index.ts +++ b/x-pack/plugins/actions/server/usage/index.ts @@ -6,3 +6,4 @@ */ export { registerActionsUsageCollector } from './actions_usage_collector'; +export { ConnectorUsageCollector } from './connector_usage_collector'; diff --git a/x-pack/plugins/alerting/server/lib/trim_recovered_alerts.ts b/x-pack/plugins/alerting/server/lib/trim_recovered_alerts.ts index 95763237264b7..779bf0023a3c3 100644 --- a/x-pack/plugins/alerting/server/lib/trim_recovered_alerts.ts +++ b/x-pack/plugins/alerting/server/lib/trim_recovered_alerts.ts @@ -67,9 +67,7 @@ export function getEarlyRecoveredAlerts( earlyRecoveredAlerts = recoveredAlerts.slice(maxAlerts); logger.warn( - `Recovered alerts (${ - recoveredAlerts.length - }) have exceeded the max alert limit of ${maxAlerts} : dropping ${ + `Recovered alerts have exceeded the max alert limit of ${maxAlerts} : dropping ${ earlyRecoveredAlerts.length } ${earlyRecoveredAlerts.length > 1 ? 'alerts' : 'alert'}.` ); diff --git a/x-pack/plugins/event_log/generated/mappings.json b/x-pack/plugins/event_log/generated/mappings.json index 9626958958ff7..5fc8128baa7ae 100644 --- a/x-pack/plugins/event_log/generated/mappings.json +++ b/x-pack/plugins/event_log/generated/mappings.json @@ -513,7 +513,7 @@ } } }, - "metrics": { + "usage": { "properties": { "request_body_bytes": { "type": "long" diff --git a/x-pack/plugins/event_log/generated/schemas.ts b/x-pack/plugins/event_log/generated/schemas.ts index eac5fe08ee0be..7542d6db5213a 100644 --- a/x-pack/plugins/event_log/generated/schemas.ts +++ b/x-pack/plugins/event_log/generated/schemas.ts @@ -228,7 +228,7 @@ export const EventSchema = schema.maybe( ), }) ), - metrics: schema.maybe( + usage: schema.maybe( schema.object({ request_body_bytes: ecsStringOrNumber(), }) diff --git a/x-pack/plugins/event_log/scripts/mappings.js b/x-pack/plugins/event_log/scripts/mappings.js index 360faaf488b9b..770f9e6d45f9a 100644 --- a/x-pack/plugins/event_log/scripts/mappings.js +++ b/x-pack/plugins/event_log/scripts/mappings.js @@ -288,7 +288,7 @@ exports.EcsCustomPropertyMappings = { }, }, }, - metrics: { + usage: { properties: { request_body_bytes: { type: 'long', diff --git a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.test.ts index e56c269c12630..2a4d91a07f1d3 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.test.ts @@ -25,7 +25,7 @@ import { import { DEFAULT_BODY } from '../../../public/connector_types/bedrock/constants'; import { initDashboard } from '../lib/gen_ai/create_gen_ai_dashboard'; import { AxiosError } from 'axios'; -import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; jest.mock('../lib/gen_ai/create_gen_ai_dashboard'); // @ts-ignore @@ -59,7 +59,7 @@ describe('BedrockConnector', () => { headers: {}, data: claude3Response, }; - let connectorMetricsCollector: ConnectorMetricsCollector; + let connectorUsageCollector: ConnectorUsageCollector; beforeEach(() => { jest.clearAllMocks(); @@ -67,7 +67,7 @@ describe('BedrockConnector', () => { mockError = jest.fn().mockImplementation(() => { throw new Error('API Error'); }); - connectorMetricsCollector = new ConnectorMetricsCollector({ + connectorUsageCollector = new ConnectorUsageCollector({ logger, connectorId: 'test-connector-id', }); @@ -95,7 +95,7 @@ describe('BedrockConnector', () => { it('the aws signature has non-streaming headers', async () => { await connector.runApi( { body: DEFAULT_BODY }, - new ConnectorMetricsCollector({ + new ConnectorUsageCollector({ logger, connectorId: 'test-connector-id', }) @@ -115,7 +115,7 @@ describe('BedrockConnector', () => { ); }); it('the Bedrock API call is successful with Claude 3 parameters; returns the response formatted for Claude 2 along with usage object', async () => { - const response = await connector.runApi({ body: DEFAULT_BODY }, connectorMetricsCollector); + const response = await connector.runApi({ body: DEFAULT_BODY }, connectorUsageCollector); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( { @@ -126,7 +126,7 @@ describe('BedrockConnector', () => { responseSchema: RunApiLatestResponseSchema, data: DEFAULT_BODY, }, - connectorMetricsCollector + connectorUsageCollector ); expect(response).toEqual({ ...claude2Response, @@ -145,7 +145,7 @@ describe('BedrockConnector', () => { }); // @ts-ignore connector.request = mockRequest; - const response = await connector.runApi({ body: v2Body }, connectorMetricsCollector); + const response = await connector.runApi({ body: v2Body }, connectorUsageCollector); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( { @@ -156,7 +156,7 @@ describe('BedrockConnector', () => { responseSchema: RunActionResponseSchema, data: v2Body, }, - connectorMetricsCollector + connectorUsageCollector ); expect(response).toEqual(claude2Response); }); @@ -168,7 +168,7 @@ describe('BedrockConnector', () => { await expect( connector.runApi( { body: DEFAULT_BODY }, - new ConnectorMetricsCollector({ + new ConnectorUsageCollector({ logger, connectorId: 'test-connector-id', }) @@ -198,7 +198,7 @@ describe('BedrockConnector', () => { }; it('the aws signature has streaming headers', async () => { - await connector.invokeStream(aiAssistantBody, connectorMetricsCollector); + await connector.invokeStream(aiAssistantBody, connectorUsageCollector); expect(mockSigner).toHaveBeenCalledWith( { @@ -217,7 +217,7 @@ describe('BedrockConnector', () => { }); it('the API call is successful with correct request parameters', async () => { - await connector.invokeStream(aiAssistantBody, connectorMetricsCollector); + await connector.invokeStream(aiAssistantBody, connectorUsageCollector); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( { @@ -228,7 +228,7 @@ describe('BedrockConnector', () => { responseType: 'stream', data: JSON.stringify({ ...JSON.parse(DEFAULT_BODY), temperature: 0 }), }, - connectorMetricsCollector + connectorUsageCollector ); }); @@ -237,7 +237,7 @@ describe('BedrockConnector', () => { const timeout = 180000; await connector.invokeStream( { ...aiAssistantBody, timeout, signal }, - connectorMetricsCollector + connectorUsageCollector ); expect(mockRequest).toHaveBeenCalledWith( @@ -251,7 +251,7 @@ describe('BedrockConnector', () => { timeout, signal, }, - connectorMetricsCollector + connectorUsageCollector ); }); @@ -277,7 +277,7 @@ describe('BedrockConnector', () => { }, ], }, - connectorMetricsCollector + connectorUsageCollector ); expect(mockRequest).toHaveBeenCalledWith( { @@ -298,7 +298,7 @@ describe('BedrockConnector', () => { temperature: 0, }), }, - connectorMetricsCollector + connectorUsageCollector ); }); @@ -332,7 +332,7 @@ describe('BedrockConnector', () => { }, ], }, - connectorMetricsCollector + connectorUsageCollector ); expect(mockRequest).toHaveBeenCalledWith( { @@ -352,7 +352,7 @@ describe('BedrockConnector', () => { temperature: 0, }), }, - connectorMetricsCollector + connectorUsageCollector ); }); @@ -381,7 +381,7 @@ describe('BedrockConnector', () => { ], model: modelOverride, }, - connectorMetricsCollector + connectorUsageCollector ); expect(mockRequest).toHaveBeenCalledWith( { @@ -402,12 +402,12 @@ describe('BedrockConnector', () => { temperature: 0, }), }, - connectorMetricsCollector + connectorUsageCollector ); }); it('responds with a readable stream', async () => { - const response = await connector.invokeStream(aiAssistantBody, connectorMetricsCollector); + const response = await connector.invokeStream(aiAssistantBody, connectorUsageCollector); expect(response instanceof PassThrough).toEqual(true); }); @@ -416,7 +416,7 @@ describe('BedrockConnector', () => { connector.request = mockError; await expect( - connector.invokeStream(aiAssistantBody, connectorMetricsCollector) + connector.invokeStream(aiAssistantBody, connectorUsageCollector) ).rejects.toThrow('API Error'); }); }); @@ -433,7 +433,7 @@ describe('BedrockConnector', () => { }; it('the API call is successful with correct parameters', async () => { - const response = await connector.invokeAI(aiAssistantBody, connectorMetricsCollector); + const response = await connector.invokeAI(aiAssistantBody, connectorUsageCollector); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( { @@ -449,7 +449,7 @@ describe('BedrockConnector', () => { temperature: 0, }), }, - connectorMetricsCollector + connectorUsageCollector ); expect(response.message).toEqual(mockResponseString); }); @@ -476,7 +476,7 @@ describe('BedrockConnector', () => { }, ], }, - connectorMetricsCollector + connectorUsageCollector ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( @@ -498,7 +498,7 @@ describe('BedrockConnector', () => { temperature: 0, }), }, - connectorMetricsCollector + connectorUsageCollector ); expect(response.message).toEqual(mockResponseString); }); @@ -522,7 +522,7 @@ describe('BedrockConnector', () => { ], system: 'This is a system message', }, - connectorMetricsCollector + connectorUsageCollector ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( @@ -544,7 +544,7 @@ describe('BedrockConnector', () => { temperature: 0, }), }, - connectorMetricsCollector + connectorUsageCollector ); expect(response.message).toEqual(mockResponseString); }); @@ -572,7 +572,7 @@ describe('BedrockConnector', () => { ], system: 'This is a system message', }, - connectorMetricsCollector + connectorUsageCollector ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( @@ -594,17 +594,14 @@ describe('BedrockConnector', () => { temperature: 0, }), }, - connectorMetricsCollector + connectorUsageCollector ); expect(response.message).toEqual(mockResponseString); }); it('signal and timeout is properly passed to runApi', async () => { const signal = jest.fn(); const timeout = 180000; - await connector.invokeAI( - { ...aiAssistantBody, timeout, signal }, - connectorMetricsCollector - ); + await connector.invokeAI({ ...aiAssistantBody, timeout, signal }, connectorUsageCollector); expect(mockRequest).toHaveBeenCalledWith( { @@ -621,16 +618,16 @@ describe('BedrockConnector', () => { timeout, signal, }, - connectorMetricsCollector + connectorUsageCollector ); }); it('errors during API calls are properly handled', async () => { // @ts-ignore connector.request = mockError; - await expect( - connector.invokeAI(aiAssistantBody, connectorMetricsCollector) - ).rejects.toThrow('API Error'); + await expect(connector.invokeAI(aiAssistantBody, connectorUsageCollector)).rejects.toThrow( + 'API Error' + ); }); }); describe('getResponseErrorMessage', () => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.ts b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.ts index 2cabf6c791b79..b5ec114a9c456 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.ts @@ -11,7 +11,7 @@ import { AxiosError, Method } from 'axios'; import { IncomingMessage } from 'http'; import { PassThrough } from 'stream'; import { SubActionRequestParams } from '@kbn/actions-plugin/server/sub_action_framework/types'; -import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { initDashboard } from '../lib/gen_ai/create_gen_ai_dashboard'; import { RunActionParamsSchema, @@ -196,17 +196,17 @@ The Kibana Connector in use may need to be reconfigured with an updated Amazon B private async runApiRaw( params: SubActionRequestParams, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { - const response = await this.request(params, connectorMetricsCollector); + const response = await this.request(params, connectorUsageCollector); return response.data; } private async runApiLatest( params: SubActionRequestParams, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { - const response = await this.request(params, connectorMetricsCollector); + const response = await this.request(params, connectorUsageCollector); // keeping the response the same as claude 2 for our APIs // adding the usage object for better token tracking return { @@ -223,7 +223,7 @@ The Kibana Connector in use may need to be reconfigured with an updated Amazon B */ public async runApi( { body, model: reqModel, signal, timeout, raw }: RunActionParams, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { // set model on per request basis const currentModel = reqModel ?? this.model; @@ -242,19 +242,19 @@ The Kibana Connector in use may need to be reconfigured with an updated Amazon B if (raw) { return this.runApiRaw( { ...requestArgs, responseSchema: InvokeAIRawActionResponseSchema }, - connectorMetricsCollector + connectorUsageCollector ); } // possible api received deprecated arguments, which will still work with the deprecated Claude 2 models if (usesDeprecatedArguments(body)) { return this.runApiRaw( { ...requestArgs, responseSchema: RunActionResponseSchema }, - connectorMetricsCollector + connectorUsageCollector ); } return this.runApiLatest( { ...requestArgs, responseSchema: RunApiLatestResponseSchema }, - connectorMetricsCollector + connectorUsageCollector ); } @@ -268,7 +268,7 @@ The Kibana Connector in use may need to be reconfigured with an updated Amazon B */ private async streamApi( { body, model: reqModel, signal, timeout }: RunActionParams, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { // set model on per request basis const path = `/model/${reqModel ?? this.model}/invoke-with-response-stream`; @@ -285,7 +285,7 @@ The Kibana Connector in use may need to be reconfigured with an updated Amazon B signal, timeout, }, - connectorMetricsCollector + connectorUsageCollector ); return response.data.pipe(new PassThrough()); @@ -310,7 +310,7 @@ The Kibana Connector in use may need to be reconfigured with an updated Amazon B timeout, tools, }: InvokeAIActionParams | InvokeAIRawActionParams, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { const res = (await this.streamApi( { @@ -321,7 +321,7 @@ The Kibana Connector in use may need to be reconfigured with an updated Amazon B signal, timeout, }, - connectorMetricsCollector + connectorUsageCollector )) as unknown as IncomingMessage; return res; } @@ -345,7 +345,7 @@ The Kibana Connector in use may need to be reconfigured with an updated Amazon B signal, timeout, }: InvokeAIActionParams, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { const res = (await this.runApi( { @@ -356,7 +356,7 @@ The Kibana Connector in use may need to be reconfigured with an updated Amazon B signal, timeout, }, - connectorMetricsCollector + connectorUsageCollector )) as RunActionResponse; return { message: res.completion.trim() }; } @@ -374,7 +374,7 @@ The Kibana Connector in use may need to be reconfigured with an updated Amazon B tools, anthropicVersion, }: InvokeAIRawActionParams, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { const res = await this.runApi( { @@ -392,7 +392,7 @@ The Kibana Connector in use may need to be reconfigured with an updated Amazon B timeout, raw: true, }, - connectorMetricsCollector + connectorUsageCollector ); return res; } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/__snapshots__/service.test.ts.snap b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/__snapshots__/service.test.ts.snap index aaa40000c2740..12a4e93def576 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/__snapshots__/service.test.ts.snap +++ b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/__snapshots__/service.test.ts.snap @@ -1,9 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Cases webhook service createComment it should call request with correct arguments when authType=SSL: +exports[`Cases webhook service createComment it should call request with correct arguments when authType=SSL: Object { "axios": [Function], - "connectorMetricsCollector": ConnectorMetricsCollector { + "connectorUsageCollector": ConnectorUsageCollector { "connectorId": "test-connector-id", "logger": Object { "context": Array [], @@ -17,7 +17,7 @@ exports[`Cases webhook service createComment it should call request with correct "trace": [MockFunction], "warn": [MockFunction], }, - "metrics": Object { + "usage": Object { "requestBodyBytes": 0, }, }, @@ -163,7 +163,7 @@ exports[`Cases webhook service createComment it should call request with correct 1`] = ` Object { "axios": [Function], - "connectorMetricsCollector": ConnectorMetricsCollector { + "connectorUsageCollector": ConnectorUsageCollector { "connectorId": "test-connector-id", "logger": Object { "context": Array [], @@ -177,7 +177,7 @@ Object { "trace": [MockFunction], "warn": [MockFunction], }, - "metrics": Object { + "usage": Object { "requestBodyBytes": 0, }, }, diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/index.ts index 431fb3ed7984b..ccd777634ec37 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/index.ts @@ -70,8 +70,7 @@ export async function executor( CasesWebhookActionParamsType > ): Promise> { - const { actionId, configurationUtilities, params, logger, connectorMetricsCollector } = - execOptions; + const { actionId, configurationUtilities, params, logger, connectorUsageCollector } = execOptions; const { subAction, subActionParams } = params; let data: CasesWebhookExecutorResultData | undefined; @@ -83,7 +82,7 @@ export async function executor( }, logger, configurationUtilities, - connectorMetricsCollector + connectorUsageCollector ); if (!api[subAction]) { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts index 6258341e3ac80..27cce1d9f6a35 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts @@ -13,7 +13,8 @@ import { CasesWebhookPublicConfigurationType, ExternalService } from './types'; import { Logger } from '@kbn/core/server'; import { loggingSystemMock } from '@kbn/core/server/mocks'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; -import { ConnectorMetricsCollector, getBasicAuthHeader } from '@kbn/actions-plugin/server/lib'; +import { getBasicAuthHeader } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { AuthType, WebhookMethods, SSLCertType } from '../../../common/auth/constants'; import { CRT_FILE, KEY_FILE } from '../../../common/auth/mocks'; @@ -69,14 +70,14 @@ const sslConfig: CasesWebhookPublicConfigurationType = { hasAuth: true, }; const sslSecrets = { crt: CRT_FILE, key: KEY_FILE, password: 'foobar', user: null, pfx: null }; -let connectorMetricsCollector: ConnectorMetricsCollector; +let connectorUsageCollector: ConnectorUsageCollector; describe('Cases webhook service', () => { let service: ExternalService; let sslService: ExternalService; beforeAll(() => { - connectorMetricsCollector = new ConnectorMetricsCollector({ + connectorUsageCollector = new ConnectorUsageCollector({ logger, connectorId: 'test-connector-id', }); @@ -88,7 +89,7 @@ describe('Cases webhook service', () => { }, logger, configurationUtilities, - connectorMetricsCollector + connectorUsageCollector ); sslService = createExternalService( @@ -99,7 +100,7 @@ describe('Cases webhook service', () => { }, logger, configurationUtilities, - connectorMetricsCollector + connectorUsageCollector ); jest.useFakeTimers(); jest.setSystemTime(mockTime); @@ -129,7 +130,7 @@ describe('Cases webhook service', () => { }, logger, configurationUtilities, - connectorMetricsCollector + connectorUsageCollector ) ).toThrow(); }); @@ -144,7 +145,7 @@ describe('Cases webhook service', () => { }, logger, configurationUtilities, - connectorMetricsCollector + connectorUsageCollector ) ).toThrow(); }); @@ -159,7 +160,7 @@ describe('Cases webhook service', () => { }, logger, configurationUtilities, - connectorMetricsCollector + connectorUsageCollector ) ).not.toThrow(); }); @@ -173,7 +174,7 @@ describe('Cases webhook service', () => { }, logger, configurationUtilities, - connectorMetricsCollector + connectorUsageCollector ); expect(axios.create).toHaveBeenCalledWith({ @@ -194,7 +195,7 @@ describe('Cases webhook service', () => { }, logger, configurationUtilities, - connectorMetricsCollector + connectorUsageCollector ); expect(axios.create).toHaveBeenCalledWith({ @@ -237,7 +238,7 @@ describe('Cases webhook service', () => { logger, configurationUtilities, sslOverrides: defaultSSLOverrides, - connectorMetricsCollector: expect.any(ConnectorMetricsCollector), + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); }); @@ -251,7 +252,7 @@ describe('Cases webhook service', () => { expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "axios": [Function], - "connectorMetricsCollector": ConnectorMetricsCollector { + "connectorUsageCollector": ConnectorUsageCollector { "connectorId": "test-connector-id", "logger": Object { "context": Array [], @@ -265,7 +266,7 @@ describe('Cases webhook service', () => { "trace": [MockFunction], "warn": [MockFunction], }, - "metrics": Object { + "usage": Object { "requestBodyBytes": 0, }, }, @@ -512,7 +513,7 @@ describe('Cases webhook service', () => { configurationUtilities, sslOverrides: defaultSSLOverrides, data: `{"fields":{"title":"title","description":"desc","tags":["hello","world"],"project":{"key":"ROC"},"issuetype":{"id":"10024"}}}`, - connectorMetricsCollector: expect.any(ConnectorMetricsCollector), + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); }); @@ -542,7 +543,7 @@ describe('Cases webhook service', () => { expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "axios": [Function], - "connectorMetricsCollector": ConnectorMetricsCollector { + "connectorUsageCollector": ConnectorUsageCollector { "connectorId": "test-connector-id", "logger": Object { "context": Array [], @@ -568,7 +569,7 @@ describe('Cases webhook service', () => { "trace": [MockFunction], "warn": [MockFunction], }, - "metrics": Object { + "usage": Object { "requestBodyBytes": 0, }, }, @@ -818,7 +819,7 @@ describe('Cases webhook service', () => { issuetype: { id: '10024' }, }, }), - connectorMetricsCollector: expect.any(ConnectorMetricsCollector), + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); }); @@ -839,7 +840,7 @@ describe('Cases webhook service', () => { expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "axios": [Function], - "connectorMetricsCollector": ConnectorMetricsCollector { + "connectorUsageCollector": ConnectorUsageCollector { "connectorId": "test-connector-id", "logger": Object { "context": Array [], @@ -853,7 +854,7 @@ describe('Cases webhook service', () => { "trace": [MockFunction], "warn": [MockFunction], }, - "metrics": Object { + "usage": Object { "requestBodyBytes": 0, }, }, @@ -1065,7 +1066,7 @@ describe('Cases webhook service', () => { sslOverrides: defaultSSLOverrides, url: 'https://coolsite.net/issue/1/comment', data: `{"body":"comment"}`, - connectorMetricsCollector: expect.any(ConnectorMetricsCollector), + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); }); @@ -1086,7 +1087,7 @@ describe('Cases webhook service', () => { expect(requestMock.mock.calls[0][0]).toMatchSnapshot(` Object { "axios": [Function], - "connectorMetricsCollector": ConnectorMetricsCollector { + "connectorUsageCollector": ConnectorUsageCollector { "connectorId": "test-connector-id", "logger": Object { "context": Array [], @@ -1100,7 +1101,7 @@ describe('Cases webhook service', () => { "trace": [MockFunction], "warn": [MockFunction], }, - "metrics": Object { + "usage": Object { "requestBodyBytes": 0, }, }, @@ -1277,7 +1278,7 @@ describe('Cases webhook service', () => { }, logger, configurationUtilities, - connectorMetricsCollector + connectorUsageCollector ); const res = await service.createComment(commentReq); expect(requestMock).not.toHaveBeenCalled(); @@ -1293,7 +1294,7 @@ describe('Cases webhook service', () => { }, logger, configurationUtilities, - connectorMetricsCollector + connectorUsageCollector ); const res = await service.createComment(commentReq); expect(requestMock).not.toHaveBeenCalled(); @@ -1320,7 +1321,7 @@ describe('Cases webhook service', () => { }, logger, configurationUtilities, - connectorMetricsCollector + connectorUsageCollector ); await service.createComment(commentReq); expect(requestMock).toHaveBeenCalledWith({ @@ -1331,7 +1332,7 @@ describe('Cases webhook service', () => { url: 'https://coolsite.net/issue/1/comment', data: `{"body":"comment","id":"1"}`, sslOverrides: defaultSSLOverrides, - connectorMetricsCollector: expect.any(ConnectorMetricsCollector), + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); }); @@ -1362,7 +1363,7 @@ describe('Cases webhook service', () => { }, logger, configurationUtilities, - connectorMetricsCollector + connectorUsageCollector ); await service.createComment(commentReq2); expect(requestMock).toHaveBeenCalledWith({ @@ -1373,7 +1374,7 @@ describe('Cases webhook service', () => { url: 'https://coolsite.net/issue/1/comment', data: `{"body":"comment","id":1}`, sslOverrides: defaultSSLOverrides, - connectorMetricsCollector: expect.any(ConnectorMetricsCollector), + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); }); }); @@ -1393,7 +1394,7 @@ describe('Cases webhook service', () => { throw new Error('Uri not allowed'); }), }, - connectorMetricsCollector + connectorUsageCollector ); }); @@ -1468,7 +1469,7 @@ describe('Cases webhook service', () => { }, logger, configurationUtilities, - connectorMetricsCollector + connectorUsageCollector ); }); @@ -1539,7 +1540,7 @@ describe('Cases webhook service', () => { { ...configurationUtilities, }, - connectorMetricsCollector + connectorUsageCollector ); requestMock.mockImplementation(() => createAxiosResponse({ diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.ts b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.ts index c5fdb53e5e7e0..170c63a1d4e5b 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.ts @@ -11,10 +11,8 @@ import { Logger } from '@kbn/core/server'; import { renderMustacheStringNoEscape } from '@kbn/actions-plugin/server/lib/mustache_renderer'; import { request } from '@kbn/actions-plugin/server/lib/axios_utils'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; -import { - combineHeadersWithBasicAuthHeader, - ConnectorMetricsCollector, -} from '@kbn/actions-plugin/server/lib'; +import { combineHeadersWithBasicAuthHeader } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { buildConnectorAuth, validateConnectorAuthConfiguration } from '../../../common/auth/utils'; import { validateAndNormalizeUrl, validateJson } from './validators'; import { @@ -42,7 +40,7 @@ export const createExternalService = ( { config, secrets }: ExternalServiceCredentials, logger: Logger, configurationUtilities: ActionsConfigurationUtilities, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): ExternalService => { const { createCommentJson, @@ -121,7 +119,7 @@ export const createExternalService = ( logger, configurationUtilities, sslOverrides, - connectorMetricsCollector, + connectorUsageCollector, }); throwDescriptiveErrorIfResponseIsNotValid({ @@ -167,7 +165,7 @@ export const createExternalService = ( data: json, configurationUtilities, sslOverrides, - connectorMetricsCollector, + connectorUsageCollector, }); const { status, statusText, data } = res; @@ -252,7 +250,7 @@ export const createExternalService = ( data: json, configurationUtilities, sslOverrides, - connectorMetricsCollector, + connectorUsageCollector, }); throwDescriptiveErrorIfResponseIsNotValid({ @@ -326,7 +324,7 @@ export const createExternalService = ( data: json, configurationUtilities, sslOverrides, - connectorMetricsCollector, + connectorUsageCollector, }); throwDescriptiveErrorIfResponseIsNotValid({ diff --git a/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.test.ts index ec079296cce13..0c3d851981fde 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.test.ts @@ -10,7 +10,7 @@ import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.moc import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; import { actionsMock } from '@kbn/actions-plugin/server/mocks'; import { CROWDSTRIKE_CONNECTOR_ID } from '../../../public/common'; -import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; const tokenPath = 'https://api.crowdstrike.com/oauth2/token'; const hostPath = 'https://api.crowdstrike.com/devices/entities/devices/v2'; @@ -27,14 +27,14 @@ describe('CrowdstrikeConnector', () => { services: actionsMock.createServices(), }); let mockedRequest: jest.Mock; - let connectorMetricsCollector: ConnectorMetricsCollector; + let connectorUsageCollector: ConnectorUsageCollector; beforeEach(() => { // @ts-expect-error private static - but I still want to reset it CrowdstrikeConnector.token = null; // @ts-expect-error mockedRequest = connector.request = jest.fn() as jest.Mock; - connectorMetricsCollector = new ConnectorMetricsCollector({ + connectorUsageCollector = new ConnectorUsageCollector({ logger, connectorId: 'test-connector-id', }); @@ -55,7 +55,7 @@ describe('CrowdstrikeConnector', () => { command: 'contain', ids: ['id1', 'id2'], }, - connectorMetricsCollector + connectorUsageCollector ); expect(mockedRequest).toHaveBeenNthCalledWith( 1, @@ -69,7 +69,7 @@ describe('CrowdstrikeConnector', () => { responseSchema: expect.any(Object), url: tokenPath, }), - connectorMetricsCollector + connectorUsageCollector ); expect(mockedRequest).toHaveBeenNthCalledWith( 2, @@ -81,7 +81,7 @@ describe('CrowdstrikeConnector', () => { paramsSerializer: expect.any(Function), responseSchema: expect.any(Object), }), - connectorMetricsCollector + connectorUsageCollector ); expect(result).toEqual({ id: 'testid', path: 'testpath' }); }); @@ -96,7 +96,7 @@ describe('CrowdstrikeConnector', () => { const result = await connector.getAgentDetails( { ids: ['id1', 'id2'] }, - connectorMetricsCollector + connectorUsageCollector ); expect(mockedRequest).toHaveBeenNthCalledWith( @@ -111,7 +111,7 @@ describe('CrowdstrikeConnector', () => { responseSchema: expect.any(Object), url: tokenPath, }), - connectorMetricsCollector + connectorUsageCollector ); expect(mockedRequest).toHaveBeenNthCalledWith( 2, @@ -125,7 +125,7 @@ describe('CrowdstrikeConnector', () => { responseSchema: expect.any(Object), url: hostPath, }), - connectorMetricsCollector + connectorUsageCollector ); expect(result).toEqual({ resources: [{}] }); }); @@ -140,7 +140,7 @@ describe('CrowdstrikeConnector', () => { const result = await connector.getAgentOnlineStatus( { ids: ['id1', 'id2'] }, - connectorMetricsCollector + connectorUsageCollector ); expect(mockedRequest).toHaveBeenNthCalledWith( @@ -155,7 +155,7 @@ describe('CrowdstrikeConnector', () => { responseSchema: expect.any(Object), url: tokenPath, }), - connectorMetricsCollector + connectorUsageCollector ); expect(mockedRequest).toHaveBeenNthCalledWith( 2, @@ -169,7 +169,7 @@ describe('CrowdstrikeConnector', () => { responseSchema: expect.any(Object), url: onlineStatusPath, }), - connectorMetricsCollector + connectorUsageCollector ); expect(result).toEqual({ resources: [{}] }); }); @@ -248,7 +248,7 @@ describe('CrowdstrikeConnector', () => { mockedRequest.mockResolvedValueOnce(mockResponse); // @ts-expect-error private method - but I still want to - const result = await connector.getTokenRequest(connectorMetricsCollector); + const result = await connector.getTokenRequest(connectorUsageCollector); expect(mockedRequest).toHaveBeenCalledWith( expect.objectContaining({ @@ -260,7 +260,7 @@ describe('CrowdstrikeConnector', () => { authorization: expect.stringContaining('Basic'), }, }), - connectorMetricsCollector + connectorUsageCollector ); expect(result).toEqual('testToken'); }); @@ -270,7 +270,7 @@ describe('CrowdstrikeConnector', () => { mockedRequest.mockResolvedValueOnce({ data: { access_token: 'testToken' } }); mockedRequest.mockResolvedValue(mockResponse); - await connector.getAgentDetails({ ids: ['id1', 'id2'] }, connectorMetricsCollector); + await connector.getAgentDetails({ ids: ['id1', 'id2'] }, connectorUsageCollector); expect(mockedRequest).toHaveBeenNthCalledWith( 1, @@ -284,7 +284,7 @@ describe('CrowdstrikeConnector', () => { responseSchema: expect.any(Object), url: tokenPath, }), - connectorMetricsCollector + connectorUsageCollector ); expect(mockedRequest).toHaveBeenNthCalledWith( 2, @@ -298,10 +298,10 @@ describe('CrowdstrikeConnector', () => { responseSchema: expect.any(Object), url: hostPath, }), - connectorMetricsCollector + connectorUsageCollector ); expect(mockedRequest).toHaveBeenCalledTimes(2); - await connector.getAgentDetails({ ids: ['id1', 'id2'] }, connectorMetricsCollector); + await connector.getAgentDetails({ ids: ['id1', 'id2'] }, connectorUsageCollector); expect(mockedRequest).toHaveBeenNthCalledWith( 3, expect.objectContaining({ @@ -314,7 +314,7 @@ describe('CrowdstrikeConnector', () => { responseSchema: expect.any(Object), url: hostPath, }), - connectorMetricsCollector + connectorUsageCollector ); expect(mockedRequest).toHaveBeenCalledTimes(3); }); @@ -325,7 +325,7 @@ describe('CrowdstrikeConnector', () => { mockedRequest.mockRejectedValueOnce(mockResponse); await expect(() => - connector.getAgentDetails({ ids: ['id1', 'id2'] }, connectorMetricsCollector) + connector.getAgentDetails({ ids: ['id1', 'id2'] }, connectorUsageCollector) ).rejects.toThrowError('something goes wrong'); expect(mockedRequest).toHaveBeenCalledTimes(2); }); @@ -336,7 +336,7 @@ describe('CrowdstrikeConnector', () => { mockedRequest.mockRejectedValueOnce(mockResponse); await expect(() => - connector.getAgentDetails({ ids: ['id1', 'id2'] }, connectorMetricsCollector) + connector.getAgentDetails({ ids: ['id1', 'id2'] }, connectorUsageCollector) ).rejects.toThrowError(); expect(mockedRequest).toHaveBeenCalledTimes(3); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.ts b/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.ts index 15299c2e159b9..d0be6467e3a8e 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.ts @@ -9,7 +9,7 @@ import { ServiceParams, SubActionConnector } from '@kbn/actions-plugin/server'; import type { AxiosError } from 'axios'; import { SubActionRequestParams } from '@kbn/actions-plugin/server/sub_action_framework/types'; -import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { isAggregateError, NodeSystemError } from './types'; import type { CrowdstrikeConfig, @@ -99,7 +99,7 @@ export class CrowdstrikeConnector extends SubActionConnector< public async executeHostActions( { alertIds, ...payload }: CrowdstrikeHostActionsParams, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ) { return this.crowdstrikeApiRequest( { @@ -124,13 +124,13 @@ export class CrowdstrikeConnector extends SubActionConnector< paramsSerializer, responseSchema: CrowdstrikeHostActionsResponseSchema, }, - connectorMetricsCollector + connectorUsageCollector ); } public async getAgentDetails( payload: CrowdstrikeGetAgentsParams, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { return this.crowdstrikeApiRequest( { @@ -142,13 +142,13 @@ export class CrowdstrikeConnector extends SubActionConnector< paramsSerializer, responseSchema: RelaxedCrowdstrikeBaseApiResponseSchema, }, - connectorMetricsCollector + connectorUsageCollector ) as Promise; } public async getAgentOnlineStatus( payload: CrowdstrikeGetAgentsParams, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { return this.crowdstrikeApiRequest( { @@ -160,11 +160,11 @@ export class CrowdstrikeConnector extends SubActionConnector< paramsSerializer, responseSchema: RelaxedCrowdstrikeBaseApiResponseSchema, }, - connectorMetricsCollector + connectorUsageCollector ) as Promise; } - private async getTokenRequest(connectorMetricsCollector: ConnectorMetricsCollector) { + private async getTokenRequest(connectorUsageCollector: ConnectorUsageCollector) { const response = await this.request( { url: this.urls.getToken, @@ -176,7 +176,7 @@ export class CrowdstrikeConnector extends SubActionConnector< }, responseSchema: CrowdstrikeGetTokenResponseSchema, }, - connectorMetricsCollector + connectorUsageCollector ); const token = response.data?.access_token; if (token) { @@ -193,13 +193,13 @@ export class CrowdstrikeConnector extends SubActionConnector< private async crowdstrikeApiRequest( req: SubActionRequestParams, - connectorMetricsCollector: ConnectorMetricsCollector, + connectorUsageCollector: ConnectorUsageCollector, retried?: boolean ): Promise { try { if (!CrowdstrikeConnector.token) { CrowdstrikeConnector.token = (await this.getTokenRequest( - connectorMetricsCollector + connectorUsageCollector )) as string; } @@ -211,14 +211,14 @@ export class CrowdstrikeConnector extends SubActionConnector< Authorization: `Bearer ${CrowdstrikeConnector.token}`, }, }, - connectorMetricsCollector + connectorUsageCollector ); return response.data; } catch (error) { if (error.code === 401 && !retried) { CrowdstrikeConnector.token = null; - return this.crowdstrikeApiRequest(req, connectorMetricsCollector, true); + return this.crowdstrikeApiRequest(req, connectorUsageCollector, true); } throw new CrowdstrikeError(error.message); } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.test.ts index b5f4b04c8e136..055a7fe7a7dba 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.test.ts @@ -11,7 +11,7 @@ import { D3_SECURITY_CONNECTOR_ID } from '../../../common/d3security/constants'; import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; import { actionsMock } from '@kbn/actions-plugin/server/mocks'; import { D3SecurityRunActionResponseSchema } from '../../../common/d3security/schema'; -import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; describe('D3SecurityConnector', () => { const sampleBody = JSON.stringify({ @@ -40,19 +40,19 @@ describe('D3SecurityConnector', () => { logger, services: actionsMock.createServices(), }); - let connectorMetricsCollector: ConnectorMetricsCollector; + let connectorUsageCollector: ConnectorUsageCollector; beforeEach(() => { // @ts-ignore connector.request = mockRequest; jest.clearAllMocks(); - connectorMetricsCollector = new ConnectorMetricsCollector({ + connectorUsageCollector = new ConnectorUsageCollector({ logger, connectorId: 'test-connector-id', }); }); it('the D3 Security API call is successful with correct parameters', async () => { - const response = await connector.runApi({ body: sampleBody }, connectorMetricsCollector); + const response = await connector.runApi({ body: sampleBody }, connectorUsageCollector); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( { @@ -64,7 +64,7 @@ describe('D3SecurityConnector', () => { d3key: '123', }, }, - connectorMetricsCollector + connectorUsageCollector ); expect(response).toEqual({ result: 'success' }); }); @@ -73,9 +73,9 @@ describe('D3SecurityConnector', () => { // @ts-ignore connector.request = mockError; - await expect( - connector.runApi({ body: sampleBody }, connectorMetricsCollector) - ).rejects.toThrow('API Error'); + await expect(connector.runApi({ body: sampleBody }, connectorUsageCollector)).rejects.toThrow( + 'API Error' + ); }); }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.ts b/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.ts index d92ed428440d9..0c35766a3ddf3 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.ts @@ -7,7 +7,7 @@ import { ServiceParams, SubActionConnector } from '@kbn/actions-plugin/server'; import type { AxiosError } from 'axios'; -import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { addSeverityAndEventTypeInBody } from './helpers'; import { D3SecurityRunActionParamsSchema, @@ -60,7 +60,7 @@ export class D3SecurityConnector extends SubActionConnector { const response = await this.request( { @@ -74,7 +74,7 @@ export class D3SecurityConnector extends SubActionConnector { text: 'Go to Elastic', }, }; - const connectorMetricsCollector = new ConnectorMetricsCollector({ + const connectorUsageCollector = new ConnectorUsageCollector({ logger: mockedLogger, connectorId: 'test-connector-id', }); @@ -529,7 +530,7 @@ describe('execute()', () => { services, configurationUtilities: actionsConfigMock.create(), logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }; beforeEach(() => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/email/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/email/index.ts index da22352b7af36..3a1d01732eb7d 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/email/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/email/index.ts @@ -282,7 +282,7 @@ async function executor( configurationUtilities, services, logger, - connectorMetricsCollector, + connectorUsageCollector, } = execOptions; const connectorTokenClient = services.connectorTokenClient; @@ -378,7 +378,7 @@ async function executor( logger, sendEmailOptions, connectorTokenClient, - connectorMetricsCollector + connectorUsageCollector ); } catch (err) { const message = i18n.translate('xpack.stackConnectors.email.errorSendingErrorMessage', { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.test.ts index 817a2c8bbb11c..77de60660a975 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.test.ts @@ -10,7 +10,7 @@ import { Logger } from '@kbn/core/server'; import { sendEmail } from './send_email'; import { loggingSystemMock } from '@kbn/core/server/mocks'; import nodemailer from 'nodemailer'; -import { ConnectorMetricsCollector, ProxySettings } from '@kbn/actions-plugin/server/types'; +import { ConnectorUsageCollector, ProxySettings } from '@kbn/actions-plugin/server/types'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { CustomHostSettings } from '@kbn/actions-plugin/server/config'; import { sendEmailGraphApi } from './send_email_graph_api'; @@ -39,7 +39,7 @@ const sendMailMock = jest.fn(); const mockLogger = loggingSystemMock.create().get() as jest.Mocked; const connectorTokenClient = connectorTokenClientMock.create(); -let connectorMetricsCollector: ConnectorMetricsCollector; +let connectorUsageCollector: ConnectorUsageCollector; describe('send_email module', () => { beforeEach(() => { @@ -55,7 +55,7 @@ describe('send_email module', () => { }; }); - connectorMetricsCollector = new ConnectorMetricsCollector({ + connectorUsageCollector = new ConnectorUsageCollector({ logger: mockLogger, connectorId: 'test-connector-id', }); @@ -67,7 +67,7 @@ describe('send_email module', () => { mockLogger, sendEmailOptions, connectorTokenClient, - connectorMetricsCollector + connectorUsageCollector ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` @@ -116,7 +116,7 @@ describe('send_email module', () => { mockLogger, sendEmailOptions, connectorTokenClient, - connectorMetricsCollector + connectorUsageCollector ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` @@ -175,7 +175,7 @@ describe('send_email module', () => { status: 202, }); - await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient, connectorMetricsCollector); + await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient, connectorUsageCollector); expect(getOAuthClientCredentialsAccessTokenMock).toHaveBeenCalledWith({ configurationUtilities: sendEmailOptions.configurationUtilities, connectorId: '1', @@ -271,7 +271,7 @@ describe('send_email module', () => { status: 202, }); - await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient, connectorMetricsCollector); + await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient, connectorUsageCollector); expect(getOAuthClientCredentialsAccessTokenMock).toHaveBeenCalledWith({ configurationUtilities: sendEmailOptions.configurationUtilities, connectorId: '1', @@ -309,7 +309,7 @@ describe('send_email module', () => { status: 202, }); - await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient, connectorMetricsCollector); + await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient, connectorUsageCollector); expect(getOAuthClientCredentialsAccessTokenMock).toHaveBeenCalledWith({ configurationUtilities: sendEmailOptions.configurationUtilities, connectorId: '1', @@ -339,7 +339,7 @@ describe('send_email module', () => { getOAuthClientCredentialsAccessTokenMock.mockReturnValueOnce(null); await expect(() => - sendEmail(mockLogger, sendEmailOptions, connectorTokenClient, connectorMetricsCollector) + sendEmail(mockLogger, sendEmailOptions, connectorTokenClient, connectorUsageCollector) ).rejects.toThrowErrorMatchingInlineSnapshot( `"Unable to retrieve access token for connectorId: 1"` ); @@ -383,7 +383,7 @@ describe('send_email module', () => { mockLogger, sendEmailOptions, connectorTokenClient, - connectorMetricsCollector + connectorUsageCollector ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` @@ -438,7 +438,7 @@ describe('send_email module', () => { mockLogger, sendEmailOptions, connectorTokenClient, - connectorMetricsCollector + connectorUsageCollector ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` @@ -493,7 +493,7 @@ describe('send_email module', () => { mockLogger, sendEmailOptions, connectorTokenClient, - connectorMetricsCollector + connectorUsageCollector ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` @@ -536,7 +536,7 @@ describe('send_email module', () => { sendMailMock.mockRejectedValue(new Error('wops')); await expect( - sendEmail(mockLogger, sendEmailOptions, connectorTokenClient, connectorMetricsCollector) + sendEmail(mockLogger, sendEmailOptions, connectorTokenClient, connectorUsageCollector) ).rejects.toThrow('wops'); }); @@ -562,7 +562,7 @@ describe('send_email module', () => { mockLogger, sendEmailOptions, connectorTokenClient, - connectorMetricsCollector + connectorUsageCollector ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` @@ -601,7 +601,7 @@ describe('send_email module', () => { mockLogger, sendEmailOptions, connectorTokenClient, - connectorMetricsCollector + connectorUsageCollector ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` @@ -642,7 +642,7 @@ describe('send_email module', () => { mockLogger, sendEmailOptions, connectorTokenClient, - connectorMetricsCollector + connectorUsageCollector ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` @@ -681,7 +681,7 @@ describe('send_email module', () => { mockLogger, sendEmailOptions, connectorTokenClient, - connectorMetricsCollector + connectorUsageCollector ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` @@ -723,7 +723,7 @@ describe('send_email module', () => { mockLogger, sendEmailOptions, connectorTokenClient, - connectorMetricsCollector + connectorUsageCollector ); expect(result).toBe(sendMailMockResult); @@ -771,7 +771,7 @@ describe('send_email module', () => { mockLogger, sendEmailOptions, connectorTokenClient, - connectorMetricsCollector + connectorUsageCollector ); expect(result).toBe(sendMailMockResult); @@ -823,7 +823,7 @@ describe('send_email module', () => { mockLogger, sendEmailOptions, connectorTokenClient, - connectorMetricsCollector + connectorUsageCollector ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` @@ -858,7 +858,7 @@ describe('send_email module', () => { 'Bearer clienttokentokentoken' ); - await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient, connectorMetricsCollector); + await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient, connectorUsageCollector); expect(createAxiosInstanceMock).toHaveBeenCalledTimes(1); expect(createAxiosInstanceMock).toHaveBeenCalledWith(); expect(mockAxiosInstanceInterceptor.response.use).toHaveBeenCalledTimes(1); @@ -901,7 +901,7 @@ describe('send_email module', () => { 'Bearer clienttokentokentoken' ); - await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient, connectorMetricsCollector); + await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient, connectorUsageCollector); expect(createAxiosInstanceMock).toHaveBeenCalledTimes(1); expect(createAxiosInstanceMock).toHaveBeenCalledWith(); expect(mockAxiosInstanceInterceptor.response.use).toHaveBeenCalledTimes(1); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.ts b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.ts index 377a0bfe50a02..199d96f352389 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.ts @@ -18,7 +18,7 @@ import { getSSLSettingsFromConfig, } from '@kbn/actions-plugin/server/lib/get_node_ssl_options'; import { - ConnectorMetricsCollector, + ConnectorUsageCollector, ConnectorTokenClientContract, ProxySettings, } from '@kbn/actions-plugin/server/types'; @@ -71,7 +71,7 @@ export async function sendEmail( logger: Logger, options: SendEmailOptions, connectorTokenClient: ConnectorTokenClientContract, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { const { transport, content } = options; const { message, messageHTML } = content; @@ -84,15 +84,10 @@ export async function sendEmail( options, renderedMessage, connectorTokenClient, - connectorMetricsCollector + connectorUsageCollector ); } else { - return await sendEmailWithNodemailer( - logger, - options, - renderedMessage, - connectorMetricsCollector - ); + return await sendEmailWithNodemailer(logger, options, renderedMessage, connectorUsageCollector); } } @@ -102,7 +97,7 @@ export async function sendEmailWithExchange( options: SendEmailOptions, messageHTML: string, connectorTokenClient: ConnectorTokenClientContract, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { const { transport, configurationUtilities, connectorId } = options; const { clientId, clientSecret, tenantId, oauthTokenUrl } = transport; @@ -172,7 +167,7 @@ export async function sendEmailWithExchange( }, logger, configurationUtilities, - connectorMetricsCollector, + connectorUsageCollector, axiosInstance ); } @@ -182,7 +177,7 @@ async function sendEmailWithNodemailer( logger: Logger, options: SendEmailOptions, messageHTML: string, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { const { transport, routing, content, configurationUtilities, hasAuth } = options; const { service } = transport; @@ -205,7 +200,7 @@ async function sendEmailWithNodemailer( // some deep properties, so need to use any here. const transportConfig = getTransportConfig(configurationUtilities, logger, transport, hasAuth); const nodemailerTransport = nodemailer.createTransport(transportConfig); - connectorMetricsCollector.addRequestBodyBytes(undefined, email); + connectorUsageCollector.addRequestBodyBytes(undefined, email); const result = await nodemailerTransport.sendMail(email); if (service === JSON_TRANSPORT_SERVICE) { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.test.ts index e1ebeb84859e3..6166082345243 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.test.ts @@ -14,7 +14,7 @@ import { Logger } from '@kbn/core/server'; import { loggingSystemMock } from '@kbn/core/server/mocks'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { CustomHostSettings } from '@kbn/actions-plugin/server/config'; -import { ConnectorMetricsCollector, ProxySettings } from '@kbn/actions-plugin/server/types'; +import { ConnectorUsageCollector, ProxySettings } from '@kbn/actions-plugin/server/types'; import { sendEmailGraphApi } from './send_email_graph_api'; const createAxiosInstanceMock = axios.create as jest.Mock; @@ -28,7 +28,7 @@ describe('sendEmailGraphApi', () => { const configurationUtilities = actionsConfigMock.create(); test('email contains the proper message', async () => { - const connectorMetricsCollector = new ConnectorMetricsCollector({ + const connectorUsageCollector = new ConnectorUsageCollector({ logger, connectorId: 'test-connector-id', }); @@ -44,7 +44,7 @@ describe('sendEmailGraphApi', () => { }, logger, configurationUtilities, - connectorMetricsCollector + connectorUsageCollector ); expect(axiosInstanceMock.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -124,7 +124,7 @@ describe('sendEmailGraphApi', () => { }); test('email was sent on behalf of the user "from" mailbox', async () => { - const connectorMetricsCollector = new ConnectorMetricsCollector({ + const connectorUsageCollector = new ConnectorUsageCollector({ logger, connectorId: 'test-connector-id', }); @@ -139,7 +139,7 @@ describe('sendEmailGraphApi', () => { }, logger, configurationUtilities, - connectorMetricsCollector + connectorUsageCollector ); expect(axiosInstanceMock.mock.calls[1]).toMatchInlineSnapshot(` Array [ @@ -221,7 +221,7 @@ describe('sendEmailGraphApi', () => { }); test('sendMail request was sent to the custom configured Graph API URL', async () => { - const connectorMetricsCollector = new ConnectorMetricsCollector({ + const connectorUsageCollector = new ConnectorUsageCollector({ logger, connectorId: 'test-connector-id', }); @@ -237,7 +237,7 @@ describe('sendEmailGraphApi', () => { }, logger, configurationUtilities, - connectorMetricsCollector + connectorUsageCollector ); expect(axiosInstanceMock.mock.calls[2]).toMatchInlineSnapshot(` Array [ @@ -317,7 +317,7 @@ describe('sendEmailGraphApi', () => { }); test('throw the exception and log the proper error if message was not sent successfuly', async () => { - const connectorMetricsCollector = new ConnectorMetricsCollector({ + const connectorUsageCollector = new ConnectorUsageCollector({ logger, connectorId: 'test-connector-id', }); @@ -336,7 +336,7 @@ describe('sendEmailGraphApi', () => { { options: getSendEmailOptions(), messageHTML: 'test1', headers: {} }, logger, configurationUtilities, - connectorMetricsCollector + connectorUsageCollector ) ).rejects.toThrowErrorMatchingInlineSnapshot( '"{\\"error\\":{\\"code\\":\\"ErrorMimeContentInvalidBase64String\\",\\"message\\":\\"Invalid base64 string for MIME content.\\"}}"' diff --git a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.ts b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.ts index f0b7f3cdddb3c..ed624299b3535 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.ts @@ -11,14 +11,14 @@ import axios, { AxiosInstance, AxiosResponse } from 'axios'; import { Logger } from '@kbn/core/server'; import { request } from '@kbn/actions-plugin/server/lib/axios_utils'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; -import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { SendEmailOptions } from './send_email'; export async function sendEmailGraphApi( sendEmailOptions: SendEmailGraphApiOptions, logger: Logger, configurationUtilities: ActionsConfigurationUtilities, - connectorMetricsCollector: ConnectorMetricsCollector, + connectorUsageCollector: ConnectorUsageCollector, axiosInstance?: AxiosInstance ): Promise { const { options, headers, messageHTML } = sendEmailOptions; @@ -38,7 +38,7 @@ export async function sendEmailGraphApi( headers, configurationUtilities, validateStatus: () => true, - connectorMetricsCollector, + connectorUsageCollector, }); if (res.status === 202) { return res.data; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/es_index/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/es_index/index.test.ts index 9812c1bb615c5..5b7353ef58291 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/es_index/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/es_index/index.test.ts @@ -6,11 +6,8 @@ */ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { - ConnectorMetricsCollector, - validateConfig, - validateParams, -} from '@kbn/actions-plugin/server/lib'; +import { validateConfig, validateParams } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { actionsMock } from '@kbn/actions-plugin/server/mocks'; import { ActionParamsType, @@ -31,13 +28,13 @@ const mockedLogger: jest.Mocked = loggerMock.create(); let connectorType: ESIndexConnectorType; let configurationUtilities: ActionsConfigurationUtilities; -let connectorMetricsCollector: ConnectorMetricsCollector; +let connectorUsageCollector: ConnectorUsageCollector; beforeEach(() => { jest.resetAllMocks(); configurationUtilities = actionsConfigMock.create(); connectorType = getConnectorType(); - connectorMetricsCollector = new ConnectorMetricsCollector({ + connectorUsageCollector = new ConnectorUsageCollector({ logger: mockedLogger, connectorId: 'test-connector-id', }); @@ -194,7 +191,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }; const scopedClusterClient = elasticsearchClientMock .createClusterClient() @@ -240,7 +237,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }; scopedClusterClient.bulk.mockClear(); await connectorType.executor({ @@ -291,7 +288,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }; scopedClusterClient.bulk.mockClear(); @@ -336,7 +333,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }; scopedClusterClient.bulk.mockClear(); await connectorType.executor({ @@ -669,7 +666,7 @@ describe('execute()', () => { services: { ...services, scopedClusterClient }, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }) ).toMatchInlineSnapshot(` Object { @@ -709,7 +706,7 @@ describe('execute()', () => { services: { ...services, scopedClusterClient }, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }) ).toMatchInlineSnapshot(` Object { @@ -772,7 +769,7 @@ describe('execute()', () => { services: { ...services, scopedClusterClient }, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }) ).toMatchInlineSnapshot(` Object { @@ -840,7 +837,7 @@ describe('execute()', () => { services: { ...services, scopedClusterClient }, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }) ).toMatchInlineSnapshot(` Object { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.test.ts index b28906509ad09..949ae0a6c1bd2 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.test.ts @@ -15,7 +15,7 @@ import { RunApiResponseSchema, StreamingResponseSchema } from '../../../common/g import { DEFAULT_GEMINI_MODEL } from '../../../common/gemini/constants'; import { AxiosError } from 'axios'; import { Transform } from 'stream'; -import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; jest.mock('../lib/gen_ai/create_gen_ai_dashboard'); jest.mock('@kbn/actions-plugin/server/sub_action_framework/helpers/validators', () => ({ @@ -89,13 +89,13 @@ describe('GeminiConnector', () => { logger, services: actionsMock.createServices(), }); - let connectorMetricsCollector: ConnectorMetricsCollector; + let connectorUsageCollector: ConnectorUsageCollector; describe('Gemini', () => { beforeEach(() => { // @ts-ignore connector.request = mockRequest; - connectorMetricsCollector = new ConnectorMetricsCollector({ + connectorUsageCollector = new ConnectorUsageCollector({ logger, connectorId: 'test-connector-id', }); @@ -108,7 +108,7 @@ describe('GeminiConnector', () => { model: DEFAULT_GEMINI_MODEL, }; - const response = await connector.runApi(runActionParams, connectorMetricsCollector); + const response = await connector.runApi(runActionParams, connectorUsageCollector); // Assertions expect(mockRequest).toBeCalledTimes(1); @@ -136,7 +136,7 @@ describe('GeminiConnector', () => { responseSchema: RunApiResponseSchema, signal: undefined, }, - connectorMetricsCollector + connectorUsageCollector ); expect(response).toEqual(connectorResponse); @@ -154,7 +154,7 @@ describe('GeminiConnector', () => { }; it('the API call is successful with correct parameters', async () => { - await connector.invokeAI(aiAssistantBody, connectorMetricsCollector); + await connector.invokeAI(aiAssistantBody, connectorUsageCollector); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( { @@ -183,17 +183,14 @@ describe('GeminiConnector', () => { signal: undefined, timeout: 60000, }, - connectorMetricsCollector + connectorUsageCollector ); }); it('signal and timeout is properly passed to runApi', async () => { const signal = jest.fn(); const timeout = 60000; - await connector.invokeAI( - { ...aiAssistantBody, timeout, signal }, - connectorMetricsCollector - ); + await connector.invokeAI({ ...aiAssistantBody, timeout, signal }, connectorUsageCollector); expect(mockRequest).toHaveBeenCalledWith( { url: `https://api.gemini.com/v1/projects/my-project-12345/locations/us-central1/publishers/google/models/${DEFAULT_GEMINI_MODEL}:generateContent`, @@ -221,7 +218,7 @@ describe('GeminiConnector', () => { signal, timeout: 60000, }, - connectorMetricsCollector + connectorUsageCollector ); }); }); @@ -245,7 +242,7 @@ describe('GeminiConnector', () => { }; it('the API call is successful with correct request parameters', async () => { - await connector.invokeStream(aiAssistantBody, connectorMetricsCollector); + await connector.invokeStream(aiAssistantBody, connectorUsageCollector); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( { @@ -275,7 +272,7 @@ describe('GeminiConnector', () => { signal: undefined, timeout: 60000, }, - connectorMetricsCollector + connectorUsageCollector ); }); @@ -284,7 +281,7 @@ describe('GeminiConnector', () => { const timeout = 60000; await connector.invokeStream( { ...aiAssistantBody, timeout, signal }, - connectorMetricsCollector + connectorUsageCollector ); expect(mockRequest).toHaveBeenCalledWith( { @@ -314,7 +311,7 @@ describe('GeminiConnector', () => { signal, timeout: 60000, }, - connectorMetricsCollector + connectorUsageCollector ); }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.ts b/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.ts index bc3ae38fc57a6..75f7458d3d6b3 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.ts @@ -12,7 +12,7 @@ import { IncomingMessage } from 'http'; import { SubActionRequestParams } from '@kbn/actions-plugin/server/sub_action_framework/types'; import { getGoogleOAuthJwtAccessToken } from '@kbn/actions-plugin/server/lib/get_gcp_oauth_access_token'; import { - ConnectorMetricsCollector, + ConnectorUsageCollector, ConnectorTokenClientContract, } from '@kbn/actions-plugin/server/types'; @@ -216,7 +216,7 @@ export class GeminiConnector extends SubActionConnector { */ public async runApi( { body, model: reqModel, signal, timeout, raw }: RunActionParams, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { // set model on per request basis const currentModel = reqModel ?? this.model; @@ -236,7 +236,7 @@ export class GeminiConnector extends SubActionConnector { responseSchema: raw ? RunActionRawResponseSchema : RunApiResponseSchema, } as SubActionRequestParams; - const response = await this.request(requestArgs, connectorMetricsCollector); + const response = await this.request(requestArgs, connectorUsageCollector); if (raw) { return response.data; @@ -251,7 +251,7 @@ export class GeminiConnector extends SubActionConnector { private async streamAPI( { body, model: reqModel, signal, timeout }: RunActionParams, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { const currentModel = reqModel ?? this.model; const path = `/v1/projects/${this.gcpProjectID}/locations/${this.gcpRegion}/publishers/google/models/${currentModel}:streamGenerateContent?alt=sse`; @@ -271,7 +271,7 @@ export class GeminiConnector extends SubActionConnector { signal, timeout: timeout ?? DEFAULT_TIMEOUT_MS, }, - connectorMetricsCollector + connectorUsageCollector ); return response.data.pipe(new PassThrough()); @@ -279,7 +279,7 @@ export class GeminiConnector extends SubActionConnector { public async invokeAI( { messages, model, temperature = 0, signal, timeout }: InvokeAIActionParams, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { const res = await this.runApi( { @@ -288,7 +288,7 @@ export class GeminiConnector extends SubActionConnector { signal, timeout, }, - connectorMetricsCollector + connectorUsageCollector ); return { message: res.completion, usageMetadata: res.usageMetadata }; @@ -296,7 +296,7 @@ export class GeminiConnector extends SubActionConnector { public async invokeAIRaw( { messages, model, temperature = 0, signal, timeout, tools }: InvokeAIRawActionParams, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { const res = await this.runApi( { @@ -306,7 +306,7 @@ export class GeminiConnector extends SubActionConnector { timeout, raw: true, }, - connectorMetricsCollector + connectorUsageCollector ); return res; @@ -330,7 +330,7 @@ export class GeminiConnector extends SubActionConnector { timeout, tools, }: InvokeAIActionParams, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { return (await this.streamAPI( { @@ -340,7 +340,7 @@ export class GeminiConnector extends SubActionConnector { signal, timeout, }, - connectorMetricsCollector + connectorUsageCollector )) as unknown as IncomingMessage; } } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/jira/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/jira/index.ts index bcb9b79660741..1481ab8601fa6 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/jira/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/jira/index.ts @@ -102,7 +102,7 @@ async function executor( secrets, configurationUtilities, logger, - connectorMetricsCollector, + connectorUsageCollector, } = execOptions; const { subAction, subActionParams } = params as ExecutorParams; let data: JiraExecutorResultData | null = null; @@ -114,7 +114,7 @@ async function executor( }, logger, configurationUtilities, - connectorMetricsCollector + connectorUsageCollector ); if (!api[subAction]) { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/jira/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/jira/service.test.ts index 1e8407ea6d23b..5e98bdc96c0ee 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/jira/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/jira/service.test.ts @@ -14,7 +14,7 @@ import { Logger } from '@kbn/core/server'; import { loggingSystemMock } from '@kbn/core/server/mocks'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { getBasicAuthHeader } from '@kbn/actions-plugin/server'; -import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; const logger = loggingSystemMock.create().get() as jest.Mocked; interface ResponseError extends Error { @@ -136,10 +136,10 @@ const mockOldAPI = () => describe('Jira service', () => { let service: ExternalService; - let connectorMetricsCollector: ConnectorMetricsCollector; + let connectorUsageCollector: ConnectorUsageCollector; beforeAll(() => { - connectorMetricsCollector = new ConnectorMetricsCollector({ + connectorUsageCollector = new ConnectorUsageCollector({ logger, connectorId: 'test-connector-id', }); @@ -152,7 +152,7 @@ describe('Jira service', () => { }, logger, configurationUtilities, - connectorMetricsCollector + connectorUsageCollector ); }); @@ -170,7 +170,7 @@ describe('Jira service', () => { }, logger, configurationUtilities, - connectorMetricsCollector + connectorUsageCollector ) ).toThrow(); }); @@ -184,7 +184,7 @@ describe('Jira service', () => { }, logger, configurationUtilities, - connectorMetricsCollector + connectorUsageCollector ) ).toThrow(); }); @@ -198,7 +198,7 @@ describe('Jira service', () => { }, logger, configurationUtilities, - connectorMetricsCollector + connectorUsageCollector ) ).toThrow(); }); @@ -212,7 +212,7 @@ describe('Jira service', () => { }, logger, configurationUtilities, - connectorMetricsCollector + connectorUsageCollector ) ).toThrow(); }); @@ -225,7 +225,7 @@ describe('Jira service', () => { }, logger, configurationUtilities, - connectorMetricsCollector + connectorUsageCollector ); expect(axios.create).toHaveBeenCalledWith({ @@ -270,7 +270,7 @@ describe('Jira service', () => { url: 'https://coolsite.net/rest/api/2/issue/1', logger, configurationUtilities, - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -414,7 +414,7 @@ describe('Jira service', () => { priority: { name: 'High' }, }, }, - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -473,7 +473,7 @@ describe('Jira service', () => { priority: { name: 'High' }, }, }, - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -507,7 +507,7 @@ describe('Jira service', () => { parent: { key: 'RJ-107' }, }, }, - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -577,7 +577,7 @@ describe('Jira service', () => { ...otherFields, }, }, - connectorMetricsCollector, + connectorUsageCollector, }); }); }); @@ -648,7 +648,7 @@ describe('Jira service', () => { parent: { key: 'RJ-107' }, }, }, - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -711,7 +711,7 @@ describe('Jira service', () => { ...otherFields, }, }, - connectorMetricsCollector, + connectorUsageCollector, }); }); }); @@ -765,7 +765,7 @@ describe('Jira service', () => { configurationUtilities, url: 'https://coolsite.net/rest/api/2/issue/1/comment', data: { body: 'comment' }, - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -822,7 +822,7 @@ describe('Jira service', () => { method: 'get', configurationUtilities, url: 'https://coolsite.net/rest/capabilities', - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -904,7 +904,7 @@ describe('Jira service', () => { method: 'get', configurationUtilities, url: 'https://coolsite.net/rest/api/2/issue/createmeta?projectKeys=CK&expand=projects.issuetypes.fields', - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -979,7 +979,7 @@ describe('Jira service', () => { method: 'get', configurationUtilities, url: 'https://coolsite.net/rest/api/2/issue/createmeta/CK/issuetypes', - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -1055,7 +1055,7 @@ describe('Jira service', () => { method: 'get', configurationUtilities, url: 'https://coolsite.net/rest/api/2/issue/createmeta?projectKeys=CK&issuetypeIds=10006&expand=projects.issuetypes.fields', - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -1264,7 +1264,7 @@ describe('Jira service', () => { method: 'get', configurationUtilities, url: `https://coolsite.net/rest/api/2/search?jql=project%3D%22CK%22%20and%20summary%20~%22Test%20title%22`, - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -1291,7 +1291,7 @@ describe('Jira service', () => { method: 'get', configurationUtilities, url: `https://coolsite.net/rest/api/2/search?jql=project%3D%22CK%22%20and%20summary%20~%22%5C%5C%5Bth%5C%5C!s%5C%5C%5Eis%5C%5C(%5C%5C)a%5C%5C-te%5C%5C%2Bst%5C%5C-%5C%5C%7B%5C%5C~is%5C%5C*s%5C%5C%26ue%5C%5C%3For%5C%5C%7Cand%5C%5Cbye%5C%5C%3A%5C%5C%7D%5C%5C%5D%5C%5C%7D%5C%5C%5D%22`, - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -1370,7 +1370,7 @@ describe('Jira service', () => { method: 'get', configurationUtilities, url: `https://coolsite.net/rest/api/2/issue/RJ-107`, - connectorMetricsCollector, + connectorUsageCollector, }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/jira/service.ts b/x-pack/plugins/stack_connectors/server/connector_types/jira/service.ts index aa3b862c48815..064667558b37e 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/jira/service.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/jira/service.ts @@ -16,7 +16,7 @@ import { } from '@kbn/actions-plugin/server/lib/axios_utils'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; import { getBasicAuthHeader } from '@kbn/actions-plugin/server'; -import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { CreateCommentParams, CreateIncidentParams, @@ -49,7 +49,7 @@ export const createExternalService = ( { config, secrets }: ExternalServiceCredentials, logger: Logger, configurationUtilities: ActionsConfigurationUtilities, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): ExternalService => { const { apiUrl: url, projectKey } = config as JiraPublicConfigurationType; const { apiToken, email } = secrets as JiraSecretConfigurationType; @@ -191,7 +191,7 @@ export const createExternalService = ( url: `${incidentUrl}/${id}`, logger, configurationUtilities, - connectorMetricsCollector, + connectorUsageCollector, }); throwIfResponseIsNotValid({ @@ -245,7 +245,7 @@ export const createExternalService = ( fields, }, configurationUtilities, - connectorMetricsCollector, + connectorUsageCollector, }); throwIfResponseIsNotValid({ @@ -292,7 +292,7 @@ export const createExternalService = ( logger, data: { fields }, configurationUtilities, - connectorMetricsCollector, + connectorUsageCollector, }); throwIfResponseIsNotValid({ @@ -331,7 +331,7 @@ export const createExternalService = ( logger, data: { body: comment.comment }, configurationUtilities, - connectorMetricsCollector, + connectorUsageCollector, }); throwIfResponseIsNotValid({ @@ -364,7 +364,7 @@ export const createExternalService = ( url: capabilitiesUrl, logger, configurationUtilities, - connectorMetricsCollector, + connectorUsageCollector, }); throwIfResponseIsNotValid({ @@ -396,7 +396,7 @@ export const createExternalService = ( url: getIssueTypesOldAPIURL, logger, configurationUtilities, - connectorMetricsCollector, + connectorUsageCollector, }); throwIfResponseIsNotValid({ @@ -412,7 +412,7 @@ export const createExternalService = ( url: getIssueTypesUrl, logger, configurationUtilities, - connectorMetricsCollector, + connectorUsageCollector, }); throwIfResponseIsNotValid({ @@ -445,7 +445,7 @@ export const createExternalService = ( url: createGetIssueTypeFieldsUrl(getIssueTypeFieldsOldAPIURL, issueTypeId), logger, configurationUtilities, - connectorMetricsCollector, + connectorUsageCollector, }); throwIfResponseIsNotValid({ @@ -525,7 +525,7 @@ export const createExternalService = ( url: query, logger, configurationUtilities, - connectorMetricsCollector, + connectorUsageCollector, }); throwIfResponseIsNotValid({ @@ -554,7 +554,7 @@ export const createExternalService = ( url: getIssueUrl, logger, configurationUtilities, - connectorMetricsCollector, + connectorUsageCollector, }); throwIfResponseIsNotValid({ diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/create_service_wrapper.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/create_service_wrapper.test.ts index 471c6fbce97fd..4f6133891c431 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/create_service_wrapper.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/create_service_wrapper.test.ts @@ -12,7 +12,7 @@ import { loggingSystemMock } from '@kbn/core/server/mocks'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { connectorTokenClientMock } from '@kbn/actions-plugin/server/lib/connector_token_client.mock'; import { snExternalServiceConfig } from './config'; -import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; const logger = loggingSystemMock.create().get() as jest.Mocked; const connectorTokenClient = connectorTokenClientMock.create(); @@ -20,12 +20,12 @@ const configurationUtilities = actionsConfigMock.create(); jest.mock('axios'); axios.create = jest.fn(() => axios); -let connectorMetricsCollector: ConnectorMetricsCollector; +let connectorUsageCollector: ConnectorUsageCollector; describe('createServiceWrapper', () => { beforeEach(() => { jest.clearAllMocks(); - connectorMetricsCollector = new ConnectorMetricsCollector({ + connectorUsageCollector = new ConnectorUsageCollector({ logger, connectorId: 'test-connector-id', }); @@ -51,7 +51,7 @@ describe('createServiceWrapper', () => { serviceConfig, connectorTokenClient, createServiceFn, - connectorMetricsCollector, + connectorUsageCollector, }); expect(createServiceFn).toHaveBeenCalledWith({ @@ -60,7 +60,7 @@ describe('createServiceWrapper', () => { configurationUtilities, serviceConfig, axiosInstance: axios, - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -84,7 +84,7 @@ describe('createServiceWrapper', () => { serviceConfig, connectorTokenClient, createServiceFn, - connectorMetricsCollector, + connectorUsageCollector, }); expect(createServiceFn).toHaveBeenCalledWith({ @@ -93,7 +93,7 @@ describe('createServiceWrapper', () => { configurationUtilities, serviceConfig, axiosInstance: axios, - connectorMetricsCollector, + connectorUsageCollector, }); }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/create_service_wrapper.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/create_service_wrapper.ts index 7d4e2715be9c0..dbadbf66f8d5f 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/create_service_wrapper.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/create_service_wrapper.ts @@ -7,7 +7,7 @@ import { Logger } from '@kbn/core/server'; import { - ConnectorMetricsCollector, + ConnectorUsageCollector, ConnectorTokenClientContract, } from '@kbn/actions-plugin/server/types'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; @@ -24,7 +24,7 @@ interface CreateServiceWrapperOpts { serviceConfig: SNProductsConfigValue; connectorTokenClient: ConnectorTokenClientContract; createServiceFn: ServiceFactory; - connectorMetricsCollector: ConnectorMetricsCollector; + connectorUsageCollector: ConnectorUsageCollector; } export function createServiceWrapper({ @@ -35,7 +35,7 @@ export function createServiceWrapper({ serviceConfig, connectorTokenClient, createServiceFn, - connectorMetricsCollector, + connectorUsageCollector, }: CreateServiceWrapperOpts): T { const { config } = credentials; const { apiUrl: url } = config as ServiceNowPublicConfigurationType; @@ -55,6 +55,6 @@ export function createServiceWrapper({ configurationUtilities, serviceConfig, axiosInstance, - connectorMetricsCollector, + connectorUsageCollector, }); } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.test.ts index 0dac24bdc4d84..aa8d248566d9a 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.test.ts @@ -15,7 +15,7 @@ import { loggingSystemMock } from '@kbn/core/server/mocks'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { serviceNowCommonFields, serviceNowChoices } from './mocks'; import { snExternalServiceConfig } from './config'; -import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; const logger = loggingSystemMock.create().get() as jest.Mocked; jest.mock('axios', () => ({ @@ -179,7 +179,7 @@ const expectImportedIncident = (update: boolean) => { configurationUtilities, url: 'https://example.com/api/x_elas2_inc_int/elastic_api/health', method: 'get', - connectorMetricsCollector: expect.any(ConnectorMetricsCollector), + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); expect(requestMock).toHaveBeenNthCalledWith(2, { @@ -193,7 +193,7 @@ const expectImportedIncident = (update: boolean) => { u_description: 'desc', ...(update ? { elastic_incident_id: '1' } : {}), }, - connectorMetricsCollector: expect.any(ConnectorMetricsCollector), + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); expect(requestMock).toHaveBeenNthCalledWith(3, { @@ -202,17 +202,17 @@ const expectImportedIncident = (update: boolean) => { configurationUtilities, url: 'https://example.com/api/now/v2/table/incident/1', method: 'get', - connectorMetricsCollector: expect.any(ConnectorMetricsCollector), + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); }; describe('ServiceNow service', () => { let service: ExternalService; - let connectorMetricsCollector: ConnectorMetricsCollector; + let connectorUsageCollector: ConnectorUsageCollector; beforeEach(() => { jest.clearAllMocks(); - connectorMetricsCollector = new ConnectorMetricsCollector({ + connectorUsageCollector = new ConnectorUsageCollector({ logger, connectorId: 'test-connector-id', }); @@ -228,7 +228,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow'], axiosInstance: axios, - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -244,7 +244,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow'], axiosInstance: axios, - connectorMetricsCollector, + connectorUsageCollector, }) ).toThrow(); }); @@ -285,7 +285,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow'], axiosInstance: axios, - connectorMetricsCollector, + connectorUsageCollector, }) ).toThrow(); }); @@ -450,7 +450,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow'], axiosInstance: axios, - connectorMetricsCollector, + connectorUsageCollector, }) ).toThrow(); }); @@ -478,7 +478,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/incident/1', method: 'get', - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -492,7 +492,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], table: 'sn_si_incident' }, axiosInstance: axios, - connectorMetricsCollector, + connectorUsageCollector, }); requestMock.mockImplementation(() => ({ @@ -506,7 +506,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/sn_si_incident/1', method: 'get', - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -552,7 +552,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/incident?sysparm_query=ORDERBYDESCsys_created_on^correlation_id=custom_correlation_id', method: 'get', - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -577,7 +577,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], table: 'sn_si_incident' }, axiosInstance: axios, - connectorMetricsCollector, + connectorUsageCollector, }); requestMock.mockImplementation(() => ({ @@ -591,7 +591,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/sn_si_incident?sysparm_query=ORDERBYDESCsys_created_on^correlation_id=custom_correlation_id', method: 'get', - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -645,7 +645,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow-sir'], axiosInstance: axios, - connectorMetricsCollector, + connectorUsageCollector, }); const res = await createIncident(service); @@ -656,7 +656,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/x_elas2_sir_int/elastic_api/health', method: 'get', - connectorMetricsCollector, + connectorUsageCollector, }); expect(requestMock).toHaveBeenNthCalledWith(2, { @@ -666,7 +666,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/import/x_elas2_sir_int_elastic_si_incident', method: 'post', data: { u_short_description: 'title', u_description: 'desc' }, - connectorMetricsCollector, + connectorUsageCollector, }); expect(requestMock).toHaveBeenNthCalledWith(3, { @@ -675,7 +675,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/sn_si_incident/1', method: 'get', - connectorMetricsCollector, + connectorUsageCollector, }); expect(res.url).toEqual('https://example.com/nav_to.do?uri=sn_si_incident.do?sys_id=1'); @@ -731,7 +731,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/import/x_elas2_inc_int_elastic_incident', method: 'post', data: { u_short_description: 'title', u_description: 'desc', foo: 'test' }, - connectorMetricsCollector, + connectorUsageCollector, }); }); }); @@ -748,7 +748,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], useImportAPI: false }, axiosInstance: axios, - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -775,7 +775,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/v2/table/incident', method: 'post', data: { short_description: 'title', description: 'desc' }, - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -789,7 +789,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow-sir'], useImportAPI: false }, axiosInstance: axios, - connectorMetricsCollector, + connectorUsageCollector, }); mockIncidentResponse(false); @@ -806,7 +806,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/v2/table/sn_si_incident', method: 'post', data: { short_description: 'title', description: 'desc' }, - connectorMetricsCollector, + connectorUsageCollector, }); expect(res.url).toEqual('https://example.com/nav_to.do?uri=sn_si_incident.do?sys_id=1'); @@ -855,7 +855,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow-sir'], axiosInstance: axios, - connectorMetricsCollector, + connectorUsageCollector, }); const res = await updateIncident(service); @@ -865,7 +865,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/x_elas2_sir_int/elastic_api/health', method: 'get', - connectorMetricsCollector, + connectorUsageCollector, }); expect(requestMock).toHaveBeenNthCalledWith(2, { @@ -875,7 +875,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/import/x_elas2_sir_int_elastic_si_incident', method: 'post', data: { u_short_description: 'title', u_description: 'desc', elastic_incident_id: '1' }, - connectorMetricsCollector, + connectorUsageCollector, }); expect(requestMock).toHaveBeenNthCalledWith(3, { @@ -884,7 +884,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/sn_si_incident/1', method: 'get', - connectorMetricsCollector, + connectorUsageCollector, }); expect(res.url).toEqual('https://example.com/nav_to.do?uri=sn_si_incident.do?sys_id=1'); @@ -948,7 +948,7 @@ describe('ServiceNow service', () => { elastic_incident_id: '1', foo: 'test', }, - connectorMetricsCollector, + connectorUsageCollector, }); }); }); @@ -965,7 +965,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], useImportAPI: false }, axiosInstance: axios, - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -993,7 +993,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/v2/table/incident/1', method: 'patch', data: { short_description: 'title', description: 'desc' }, - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -1007,7 +1007,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow-sir'], useImportAPI: false }, axiosInstance: axios, - connectorMetricsCollector, + connectorUsageCollector, }); mockIncidentResponse(false); @@ -1025,7 +1025,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/v2/table/sn_si_incident/1', method: 'patch', data: { short_description: 'title', description: 'desc' }, - connectorMetricsCollector, + connectorUsageCollector, }); expect(res.url).toEqual('https://example.com/nav_to.do?uri=sn_si_incident.do?sys_id=1'); @@ -1070,7 +1070,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/incident/1', method: 'get', - connectorMetricsCollector, + connectorUsageCollector, }); expect(requestMock).toHaveBeenNthCalledWith(2, { @@ -1079,7 +1079,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/x_elas2_inc_int/elastic_api/health', method: 'get', - connectorMetricsCollector, + connectorUsageCollector, }); expect(requestMock).toHaveBeenNthCalledWith(3, { @@ -1094,7 +1094,7 @@ describe('ServiceNow service', () => { u_state: '7', u_close_notes: 'Closed by Caller', }, - connectorMetricsCollector, + connectorUsageCollector, }); expect(requestMock).toHaveBeenNthCalledWith(4, { @@ -1103,7 +1103,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/incident/1', method: 'get', - connectorMetricsCollector, + connectorUsageCollector, }); expect(res?.url).toEqual('https://example.com/nav_to.do?uri=incident.do?sys_id=1'); @@ -1139,7 +1139,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/incident?sysparm_query=ORDERBYDESCsys_created_on^correlation_id=custom_correlation_id', method: 'get', - connectorMetricsCollector, + connectorUsageCollector, }); expect(requestMock).toHaveBeenNthCalledWith(2, { @@ -1148,7 +1148,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/x_elas2_inc_int/elastic_api/health', method: 'get', - connectorMetricsCollector, + connectorUsageCollector, }); expect(requestMock).toHaveBeenNthCalledWith(3, { @@ -1163,7 +1163,7 @@ describe('ServiceNow service', () => { u_state: '7', u_close_notes: 'Closed by Caller', }, - connectorMetricsCollector, + connectorUsageCollector, }); expect(requestMock).toHaveBeenNthCalledWith(4, { @@ -1172,7 +1172,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/incident/1', method: 'get', - connectorMetricsCollector, + connectorUsageCollector, }); expect(res?.url).toEqual('https://example.com/nav_to.do?uri=incident.do?sys_id=1'); @@ -1283,7 +1283,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], useImportAPI: false }, axiosInstance: axios, - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -1315,7 +1315,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow-sir'], useImportAPI: false }, axiosInstance: axios, - connectorMetricsCollector, + connectorUsageCollector, }); mockIncidentResponse(false); @@ -1333,7 +1333,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/sn_si_incident/1', method: 'get', - connectorMetricsCollector, + connectorUsageCollector, }); expect(requestMock).toHaveBeenNthCalledWith(2, { @@ -1347,7 +1347,7 @@ describe('ServiceNow service', () => { state: '7', close_notes: 'Closed by Caller', }, - connectorMetricsCollector, + connectorUsageCollector, }); expect(requestMock).toHaveBeenNthCalledWith(3, { @@ -1356,7 +1356,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/sn_si_incident/1', method: 'get', - connectorMetricsCollector, + connectorUsageCollector, }); expect(res?.url).toEqual('https://example.com/nav_to.do?uri=sn_si_incident.do?sys_id=1'); @@ -1376,7 +1376,7 @@ describe('ServiceNow service', () => { logger, configurationUtilities, url: 'https://example.com/api/now/table/sys_dictionary?sysparm_query=name=task^ORname=incident^internal_type=string&active=true&array=false&read_only=false&sysparm_fields=max_length,element,column_label,mandatory', - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -1398,7 +1398,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], table: 'sn_si_incident' }, axiosInstance: axios, - connectorMetricsCollector, + connectorUsageCollector, }); requestMock.mockImplementation(() => ({ @@ -1411,7 +1411,7 @@ describe('ServiceNow service', () => { logger, configurationUtilities, url: 'https://example.com/api/now/table/sys_dictionary?sysparm_query=name=task^ORname=sn_si_incident^internal_type=string&active=true&array=false&read_only=false&sysparm_fields=max_length,element,column_label,mandatory', - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -1448,7 +1448,7 @@ describe('ServiceNow service', () => { logger, configurationUtilities, url: 'https://example.com/api/now/table/sys_choice?sysparm_query=name=task^ORname=incident^element=priority^ORelement=category^language=en&sysparm_fields=label,value,dependent_value,element', - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -1470,7 +1470,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], table: 'sn_si_incident' }, axiosInstance: axios, - connectorMetricsCollector, + connectorUsageCollector, }); requestMock.mockImplementation(() => ({ @@ -1484,7 +1484,7 @@ describe('ServiceNow service', () => { logger, configurationUtilities, url: 'https://example.com/api/now/table/sys_choice?sysparm_query=name=task^ORname=sn_si_incident^element=priority^ORelement=category^language=en&sysparm_fields=label,value,dependent_value,element', - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -1577,7 +1577,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], useImportAPI: false }, axiosInstance: axios, - connectorMetricsCollector, + connectorUsageCollector, }); await service.checkIfApplicationIsInstalled(); expect(requestMock).not.toHaveBeenCalled(); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.ts index a8e4f66263379..84a8592aaa832 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.ts @@ -37,7 +37,7 @@ export const createExternalService: ServiceFactory = ({ configurationUtilities, serviceConfig, axiosInstance, - connectorMetricsCollector, + connectorUsageCollector, }): ExternalService => { const { config, secrets } = credentials; const { table, importSetTable, useImportAPI, appScope } = serviceConfig; @@ -133,7 +133,7 @@ export const createExternalService: ServiceFactory = ({ logger, configurationUtilities, method: 'get', - connectorMetricsCollector, // TODO check if this is internal + connectorUsageCollector, // TODO check if this is internal }); checkInstance(res); @@ -162,7 +162,7 @@ export const createExternalService: ServiceFactory = ({ logger, configurationUtilities, method: 'get', - connectorMetricsCollector, + connectorUsageCollector, }); checkInstance(res); @@ -181,7 +181,7 @@ export const createExternalService: ServiceFactory = ({ logger, params, configurationUtilities, - connectorMetricsCollector, + connectorUsageCollector, }); checkInstance(res); @@ -205,7 +205,7 @@ export const createExternalService: ServiceFactory = ({ method: 'post', data: prepareIncident(useTableApi, incident), configurationUtilities, - connectorMetricsCollector, + connectorUsageCollector, }); checkInstance(res); @@ -245,7 +245,7 @@ export const createExternalService: ServiceFactory = ({ ...(useTableApi ? {} : { elastic_incident_id: incidentId }), }, configurationUtilities, - connectorMetricsCollector, + connectorUsageCollector, }); checkInstance(res); @@ -278,7 +278,7 @@ export const createExternalService: ServiceFactory = ({ method: 'get', logger, configurationUtilities, - connectorMetricsCollector, + connectorUsageCollector, }); checkInstance(res); @@ -357,7 +357,7 @@ export const createExternalService: ServiceFactory = ({ url: fieldsUrl, logger, configurationUtilities, - connectorMetricsCollector, + connectorUsageCollector, }); checkInstance(res); @@ -375,7 +375,7 @@ export const createExternalService: ServiceFactory = ({ url: getChoicesURL(fields), logger, configurationUtilities, - connectorMetricsCollector, + connectorUsageCollector, }); checkInstance(res); return res.data.result; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/types.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/types.ts index 93462e2811826..7cecf0bcddb46 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/types.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/types.ts @@ -11,7 +11,7 @@ import { AxiosError, AxiosInstance, AxiosResponse } from 'axios'; import { TypeOf } from '@kbn/config-schema'; import { Logger } from '@kbn/core/server'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; -import { ConnectorMetricsCollector, ValidatorServices } from '@kbn/actions-plugin/server/types'; +import { ConnectorUsageCollector, ValidatorServices } from '@kbn/actions-plugin/server/types'; import { ExecutorParamsSchemaITSM, ExecutorSubActionCommonFieldsParamsSchema, @@ -305,7 +305,7 @@ interface ServiceFactoryOpts { configurationUtilities: ActionsConfigurationUtilities; serviceConfig: SNProductsConfigValue; axiosInstance: AxiosInstance; - connectorMetricsCollector: ConnectorMetricsCollector; + connectorUsageCollector: ConnectorUsageCollector; } export type ServiceFactory = ({ @@ -314,7 +314,7 @@ export type ServiceFactory = ({ configurationUtilities, serviceConfig, axiosInstance, - connectorMetricsCollector, + connectorUsageCollector, }: ServiceFactoryOpts) => T; /** diff --git a/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.test.ts index 79ffa4bce0c1f..87dacaf4e6f17 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.test.ts @@ -19,7 +19,7 @@ import { actionsMock } from '@kbn/actions-plugin/server/mocks'; import { RunActionResponseSchema, StreamingResponseSchema } from '../../../common/openai/schema'; import { initDashboard } from '../lib/gen_ai/create_gen_ai_dashboard'; import { PassThrough, Transform } from 'stream'; -import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; jest.mock('../lib/gen_ai/create_gen_ai_dashboard'); const mockTee = jest.fn(); @@ -47,7 +47,7 @@ jest.mock('openai', () => ({ describe('OpenAIConnector', () => { let mockRequest: jest.Mock; let mockError: jest.Mock; - let connectorMetricsCollector: ConnectorMetricsCollector; + let connectorUsageCollector: ConnectorUsageCollector; const logger = loggingSystemMock.createLogger(); const mockResponseString = 'Hello! How can I assist you today?'; @@ -76,7 +76,7 @@ describe('OpenAIConnector', () => { }, }; beforeEach(() => { - connectorMetricsCollector = new ConnectorMetricsCollector({ + connectorUsageCollector = new ConnectorUsageCollector({ logger, connectorId: 'test-connector-id', }); @@ -123,7 +123,7 @@ describe('OpenAIConnector', () => { it('uses the default model if none is supplied', async () => { const response = await connector.runApi( { body: JSON.stringify(sampleOpenAiBody) }, - connectorMetricsCollector + connectorUsageCollector ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( @@ -140,7 +140,7 @@ describe('OpenAIConnector', () => { 'content-type': 'application/json', }, }, - connectorMetricsCollector + connectorUsageCollector ); expect(response).toEqual(mockResponse.data); }); @@ -149,7 +149,7 @@ describe('OpenAIConnector', () => { const requestBody = { model: 'gpt-3.5-turbo', ...sampleOpenAiBody }; const response = await connector.runApi( { body: JSON.stringify(requestBody) }, - connectorMetricsCollector + connectorUsageCollector ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( @@ -162,7 +162,7 @@ describe('OpenAIConnector', () => { 'content-type': 'application/json', }, }, - connectorMetricsCollector + connectorUsageCollector ); expect(response).toEqual(mockResponse.data); }); @@ -170,7 +170,7 @@ describe('OpenAIConnector', () => { it('the OpenAI API call is successful with correct parameters', async () => { const response = await connector.runApi( { body: JSON.stringify(sampleOpenAiBody) }, - connectorMetricsCollector + connectorUsageCollector ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( @@ -187,7 +187,7 @@ describe('OpenAIConnector', () => { 'content-type': 'application/json', }, }, - connectorMetricsCollector + connectorUsageCollector ); expect(response).toEqual(mockResponse.data); }); @@ -209,7 +209,7 @@ describe('OpenAIConnector', () => { stream: true, }), }, - connectorMetricsCollector + connectorUsageCollector ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( @@ -225,7 +225,7 @@ describe('OpenAIConnector', () => { 'content-type': 'application/json', }, }, - connectorMetricsCollector + connectorUsageCollector ); expect(response).toEqual(mockResponse.data); }); @@ -235,7 +235,7 @@ describe('OpenAIConnector', () => { connector.request = mockError; await expect( - connector.runApi({ body: JSON.stringify(sampleOpenAiBody) }, connectorMetricsCollector) + connector.runApi({ body: JSON.stringify(sampleOpenAiBody) }, connectorUsageCollector) ).rejects.toThrow('API Error'); }); }); @@ -247,7 +247,7 @@ describe('OpenAIConnector', () => { body: JSON.stringify(sampleOpenAiBody), stream: false, }, - connectorMetricsCollector + connectorUsageCollector ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( @@ -266,7 +266,7 @@ describe('OpenAIConnector', () => { 'content-type': 'application/json', }, }, - connectorMetricsCollector + connectorUsageCollector ); expect(response).toEqual(mockResponse.data); }); @@ -277,7 +277,7 @@ describe('OpenAIConnector', () => { body: JSON.stringify(sampleOpenAiBody), stream: true, }, - connectorMetricsCollector + connectorUsageCollector ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( @@ -297,7 +297,7 @@ describe('OpenAIConnector', () => { 'content-type': 'application/json', }, }, - connectorMetricsCollector + connectorUsageCollector ); expect(response).toEqual({ headers: { 'Content-Type': 'dont-compress-this' }, @@ -323,7 +323,7 @@ describe('OpenAIConnector', () => { }), stream: true, }, - connectorMetricsCollector + connectorUsageCollector ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( @@ -342,7 +342,7 @@ describe('OpenAIConnector', () => { 'content-type': 'application/json', }, }, - connectorMetricsCollector + connectorUsageCollector ); expect(response).toEqual({ headers: { 'Content-Type': 'dont-compress-this' }, @@ -357,7 +357,7 @@ describe('OpenAIConnector', () => { await expect( connector.streamApi( { body: JSON.stringify(sampleOpenAiBody), stream: true }, - connectorMetricsCollector + connectorUsageCollector ) ).rejects.toThrow('API Error'); }); @@ -383,7 +383,7 @@ describe('OpenAIConnector', () => { }); it('the API call is successful with correct request parameters', async () => { - await connector.invokeStream(sampleOpenAiBody, connectorMetricsCollector); + await connector.invokeStream(sampleOpenAiBody, connectorUsageCollector); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( { @@ -402,13 +402,13 @@ describe('OpenAIConnector', () => { 'content-type': 'application/json', }, }, - connectorMetricsCollector + connectorUsageCollector ); }); it('signal is properly passed to streamApi', async () => { const signal = jest.fn(); - await connector.invokeStream({ ...sampleOpenAiBody, signal }, connectorMetricsCollector); + await connector.invokeStream({ ...sampleOpenAiBody, signal }, connectorUsageCollector); expect(mockRequest).toHaveBeenCalledWith( { @@ -428,13 +428,13 @@ describe('OpenAIConnector', () => { }, signal, }, - connectorMetricsCollector + connectorUsageCollector ); }); it('timeout is properly passed to streamApi', async () => { const timeout = 180000; - await connector.invokeStream({ ...sampleOpenAiBody, timeout }, connectorMetricsCollector); + await connector.invokeStream({ ...sampleOpenAiBody, timeout }, connectorUsageCollector); expect(mockRequest).toHaveBeenCalledWith( { @@ -454,7 +454,7 @@ describe('OpenAIConnector', () => { }, timeout, }, - connectorMetricsCollector + connectorUsageCollector ); }); @@ -463,21 +463,21 @@ describe('OpenAIConnector', () => { connector.request = mockError; await expect( - connector.invokeStream(sampleOpenAiBody, connectorMetricsCollector) + connector.invokeStream(sampleOpenAiBody, connectorUsageCollector) ).rejects.toThrow('API Error'); }); it('responds with a readable stream', async () => { // @ts-ignore connector.request = mockStream(); - const response = await connector.invokeStream(sampleOpenAiBody, connectorMetricsCollector); + const response = await connector.invokeStream(sampleOpenAiBody, connectorUsageCollector); expect(response instanceof PassThrough).toEqual(true); }); }); describe('invokeAI', () => { it('the API call is successful with correct parameters', async () => { - const response = await connector.invokeAI(sampleOpenAiBody, connectorMetricsCollector); + const response = await connector.invokeAI(sampleOpenAiBody, connectorUsageCollector); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( { @@ -493,7 +493,7 @@ describe('OpenAIConnector', () => { 'content-type': 'application/json', }, }, - connectorMetricsCollector + connectorUsageCollector ); expect(response.message).toEqual(mockResponseString); expect(response.usage.total_tokens).toEqual(9); @@ -501,7 +501,7 @@ describe('OpenAIConnector', () => { it('signal is properly passed to runApi', async () => { const signal = jest.fn(); - await connector.invokeAI({ ...sampleOpenAiBody, signal }, connectorMetricsCollector); + await connector.invokeAI({ ...sampleOpenAiBody, signal }, connectorUsageCollector); expect(mockRequest).toHaveBeenCalledWith( { @@ -518,13 +518,13 @@ describe('OpenAIConnector', () => { }, signal, }, - connectorMetricsCollector + connectorUsageCollector ); }); it('timeout is properly passed to runApi', async () => { const timeout = 180000; - await connector.invokeAI({ ...sampleOpenAiBody, timeout }, connectorMetricsCollector); + await connector.invokeAI({ ...sampleOpenAiBody, timeout }, connectorUsageCollector); expect(mockRequest).toHaveBeenCalledWith( { @@ -541,7 +541,7 @@ describe('OpenAIConnector', () => { }, timeout, }, - connectorMetricsCollector + connectorUsageCollector ); }); @@ -549,15 +549,15 @@ describe('OpenAIConnector', () => { // @ts-ignore connector.request = mockError; - await expect( - connector.invokeAI(sampleOpenAiBody, connectorMetricsCollector) - ).rejects.toThrow('API Error'); + await expect(connector.invokeAI(sampleOpenAiBody, connectorUsageCollector)).rejects.toThrow( + 'API Error' + ); }); }); describe('invokeAsyncIterator', () => { it('the API call is successful with correct request parameters', async () => { - await connector.invokeAsyncIterator(sampleOpenAiBody, connectorMetricsCollector); + await connector.invokeAsyncIterator(sampleOpenAiBody, connectorUsageCollector); expect(mockRequest).toBeCalledTimes(0); expect(mockCreate).toHaveBeenCalledWith( { @@ -574,7 +574,7 @@ describe('OpenAIConnector', () => { const signal = jest.fn(); await connector.invokeAsyncIterator( { ...sampleOpenAiBody, signal, timeout }, - connectorMetricsCollector + connectorUsageCollector ); expect(mockRequest).toBeCalledTimes(0); expect(mockCreate).toHaveBeenCalledWith( @@ -597,7 +597,7 @@ describe('OpenAIConnector', () => { }); await expect( - connector.invokeAsyncIterator(sampleOpenAiBody, connectorMetricsCollector) + connector.invokeAsyncIterator(sampleOpenAiBody, connectorUsageCollector) ).rejects.toThrow('API Error'); }); }); @@ -690,7 +690,7 @@ describe('OpenAIConnector', () => { it('uses the default model if none is supplied', async () => { const response = await connector.runApi( { body: JSON.stringify(sampleOpenAiBody) }, - connectorMetricsCollector + connectorUsageCollector ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( @@ -706,7 +706,7 @@ describe('OpenAIConnector', () => { 'content-type': 'application/json', }, }, - connectorMetricsCollector + connectorUsageCollector ); expect(response).toEqual(mockResponse.data); }); @@ -746,7 +746,7 @@ describe('OpenAIConnector', () => { it('test the AzureAI API call is successful with correct parameters', async () => { const response = await connector.runApi( { body: JSON.stringify(sampleAzureAiBody) }, - connectorMetricsCollector + connectorUsageCollector ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( @@ -759,7 +759,7 @@ describe('OpenAIConnector', () => { 'content-type': 'application/json', }, }, - connectorMetricsCollector + connectorUsageCollector ); expect(response).toEqual(mockResponse.data); }); @@ -777,7 +777,7 @@ describe('OpenAIConnector', () => { { body: JSON.stringify({ ...body, stream: true }), }, - connectorMetricsCollector + connectorUsageCollector ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( @@ -790,7 +790,7 @@ describe('OpenAIConnector', () => { 'content-type': 'application/json', }, }, - connectorMetricsCollector + connectorUsageCollector ); expect(response).toEqual(mockResponse.data); }); @@ -800,7 +800,7 @@ describe('OpenAIConnector', () => { connector.request = mockError; await expect( - connector.runApi({ body: JSON.stringify(sampleAzureAiBody) }, connectorMetricsCollector) + connector.runApi({ body: JSON.stringify(sampleAzureAiBody) }, connectorUsageCollector) ).rejects.toThrow('API Error'); }); }); @@ -812,7 +812,7 @@ describe('OpenAIConnector', () => { body: JSON.stringify(sampleAzureAiBody), stream: false, }, - connectorMetricsCollector + connectorUsageCollector ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( @@ -826,7 +826,7 @@ describe('OpenAIConnector', () => { 'content-type': 'application/json', }, }, - connectorMetricsCollector + connectorUsageCollector ); expect(response).toEqual(mockResponse.data); }); @@ -837,7 +837,7 @@ describe('OpenAIConnector', () => { body: JSON.stringify(sampleAzureAiBody), stream: true, }, - connectorMetricsCollector + connectorUsageCollector ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( @@ -852,7 +852,7 @@ describe('OpenAIConnector', () => { 'content-type': 'application/json', }, }, - connectorMetricsCollector + connectorUsageCollector ); expect(response).toEqual({ headers: { 'Content-Type': 'dont-compress-this' }, @@ -874,7 +874,7 @@ describe('OpenAIConnector', () => { body: JSON.stringify({ ...body, stream: false }), stream: true, }, - connectorMetricsCollector + connectorUsageCollector ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( @@ -892,7 +892,7 @@ describe('OpenAIConnector', () => { 'content-type': 'application/json', }, }, - connectorMetricsCollector + connectorUsageCollector ); expect(response).toEqual({ headers: { 'Content-Type': 'dont-compress-this' }, @@ -907,7 +907,7 @@ describe('OpenAIConnector', () => { await expect( connector.streamApi( { body: JSON.stringify(sampleAzureAiBody), stream: true }, - connectorMetricsCollector + connectorUsageCollector ) ).rejects.toThrow('API Error'); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.ts b/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.ts index 191bfb3693538..6cadc322a3d78 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.ts @@ -16,7 +16,7 @@ import { ChatCompletionMessageParam, } from 'openai/resources/chat/completions'; import { Stream } from 'openai/streaming'; -import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { removeEndpointFromUrl } from './lib/openai_utils'; import { RunActionParamsSchema, @@ -160,7 +160,7 @@ export class OpenAIConnector extends SubActionConnector { public async runApi( { body, signal, timeout }: RunActionParams, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { const sanitizedBody = sanitizeRequest( this.provider, @@ -184,7 +184,7 @@ export class OpenAIConnector extends SubActionConnector { ...axiosOptions.headers, }, }, - connectorMetricsCollector + connectorUsageCollector ); return response.data; } @@ -199,7 +199,7 @@ export class OpenAIConnector extends SubActionConnector { */ public async streamApi( { body, stream, signal, timeout }: StreamActionParams, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { const executeBody = getRequestWithStreamOption( this.provider, @@ -225,7 +225,7 @@ export class OpenAIConnector extends SubActionConnector { }, timeout, }, - connectorMetricsCollector + connectorUsageCollector ); return stream ? pipeStreamingResponse(response) : response.data; } @@ -275,7 +275,7 @@ export class OpenAIConnector extends SubActionConnector { */ public async invokeStream( body: InvokeAIActionParams, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { const { signal, timeout, ...rest } = body; @@ -286,7 +286,7 @@ export class OpenAIConnector extends SubActionConnector { signal, timeout, // do not default if not provided }, - connectorMetricsCollector + connectorUsageCollector )) as unknown as IncomingMessage; return res.pipe(new PassThrough()); @@ -303,7 +303,7 @@ export class OpenAIConnector extends SubActionConnector { */ public async invokeAsyncIterator( body: InvokeAIActionParams, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise<{ consumerStream: Stream; tokenCountStream: Stream; @@ -320,7 +320,7 @@ export class OpenAIConnector extends SubActionConnector { ('defaultModel' in this.config ? this.config.defaultModel : DEFAULT_OPENAI_MODEL), }; - connectorMetricsCollector.addRequestBodyBytes(undefined, requestBody); + connectorUsageCollector.addRequestBodyBytes(undefined, requestBody); const stream = await this.openAI.chat.completions.create(requestBody, { signal, timeout, // do not default if not provided @@ -345,12 +345,12 @@ export class OpenAIConnector extends SubActionConnector { */ public async invokeAI( body: InvokeAIActionParams, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { const { signal, timeout, ...rest } = body; const res = await this.runApi( { body: JSON.stringify(rest), signal, timeout }, - connectorMetricsCollector + connectorUsageCollector ); if (res.choices && res.choices.length > 0 && res.choices[0].message?.content) { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.test.ts index 1c47d11192fd3..821f2b3032661 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.test.ts @@ -15,7 +15,7 @@ import { MockedLogger } from '@kbn/logging-mocks'; import { OpsgenieConnectorTypeId } from '../../../common'; import { OpsgenieConnector } from './connector'; import * as utils from '@kbn/actions-plugin/server/lib/axios_utils'; -import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; jest.mock('axios'); @@ -37,7 +37,7 @@ describe('OpsgenieConnector', () => { let mockedActionsConfig: jest.Mocked; let logger: MockedLogger; let services: ReturnType; - let connectorMetricsCollector: ConnectorMetricsCollector; + let connectorUsageCollector: ConnectorUsageCollector; const defaultCreateAlertExpect = { method: 'post', @@ -77,43 +77,43 @@ describe('OpsgenieConnector', () => { logger, services, }); - connectorMetricsCollector = new ConnectorMetricsCollector({ + connectorUsageCollector = new ConnectorUsageCollector({ logger, connectorId: 'test-connector-id', }); }); it('calls request with the correct arguments for creating an alert', async () => { - await connector.createAlert({ message: 'hello' }, connectorMetricsCollector); + await connector.createAlert({ message: 'hello' }, connectorUsageCollector); expect(requestMock.mock.calls[0][0]).toEqual({ data: { message: 'hello' }, ...ignoredRequestFields, ...defaultCreateAlertExpect, - connectorMetricsCollector, + connectorUsageCollector, }); }); it('calls request without modifying the alias when it is less than 512 characters when creating an alert', async () => { - await connector.createAlert({ message: 'hello', alias: '111' }, connectorMetricsCollector); + await connector.createAlert({ message: 'hello', alias: '111' }, connectorUsageCollector); expect(requestMock.mock.calls[0][0]).toEqual({ ...ignoredRequestFields, ...defaultCreateAlertExpect, data: { message: 'hello', alias: '111' }, - connectorMetricsCollector, + connectorUsageCollector, }); }); it('calls request without modifying the alias when it is equal to 512 characters when creating an alert', async () => { const alias = 'a'.repeat(512); - await connector.createAlert({ message: 'hello', alias }, connectorMetricsCollector); + await connector.createAlert({ message: 'hello', alias }, connectorUsageCollector); expect(requestMock.mock.calls[0][0]).toEqual({ ...ignoredRequestFields, ...defaultCreateAlertExpect, data: { message: 'hello', alias }, - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -123,13 +123,13 @@ describe('OpsgenieConnector', () => { const hasher = crypto.createHash('sha256'); const sha256Hash = hasher.update(alias); - await connector.createAlert({ message: 'hello', alias }, connectorMetricsCollector); + await connector.createAlert({ message: 'hello', alias }, connectorUsageCollector); expect(requestMock.mock.calls[0][0]).toEqual({ ...ignoredRequestFields, ...defaultCreateAlertExpect, data: { message: 'hello', alias: `sha-${sha256Hash.digest('hex')}` }, - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -139,24 +139,24 @@ describe('OpsgenieConnector', () => { const hasher = crypto.createHash('sha256'); const sha256Hash = hasher.update(alias); - await connector.closeAlert({ alias }, connectorMetricsCollector); + await connector.closeAlert({ alias }, connectorUsageCollector); expect(requestMock.mock.calls[0][0]).toEqual({ ...ignoredRequestFields, ...createCloseAlertExpect(`sha-${sha256Hash.digest('hex')}`), data: {}, - connectorMetricsCollector, + connectorUsageCollector, }); }); it('calls request with the correct arguments for closing an alert', async () => { - await connector.closeAlert({ user: 'sam', alias: '111' }, connectorMetricsCollector); + await connector.closeAlert({ user: 'sam', alias: '111' }, connectorUsageCollector); expect(requestMock.mock.calls[0][0]).toEqual({ ...ignoredRequestFields, ...createCloseAlertExpect('111'), data: { user: 'sam' }, - connectorMetricsCollector, + connectorUsageCollector, }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.ts b/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.ts index 16b91e2256284..0963ac720c80a 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.ts @@ -9,7 +9,7 @@ import crypto from 'crypto'; import { ServiceParams, SubActionConnector } from '@kbn/actions-plugin/server'; import { AxiosError } from 'axios'; import { isEmpty } from 'lodash'; -import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { OpsgenieSubActions } from '../../../common'; import { CreateAlertParamsSchema, CloseAlertParamsSchema, Response } from './schema'; import { CloseAlertParams, Config, CreateAlertParams, FailureResponseType, Secrets } from './types'; @@ -70,7 +70,7 @@ export class OpsgenieConnector extends SubActionConnector { public async createAlert( params: CreateAlertParams, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ) { const res = await this.request( { @@ -80,7 +80,7 @@ export class OpsgenieConnector extends SubActionConnector { headers: this.createHeaders(), responseSchema: Response, }, - connectorMetricsCollector + connectorUsageCollector ); return res.data; @@ -116,7 +116,7 @@ export class OpsgenieConnector extends SubActionConnector { public async closeAlert( params: CloseAlertParams, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ) { const newAlias = OpsgenieConnector.createAlias(params.alias); @@ -133,7 +133,7 @@ export class OpsgenieConnector extends SubActionConnector { headers: this.createHeaders(), responseSchema: Response, }, - connectorMetricsCollector + connectorUsageCollector ); return res.data; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.test.ts index f9f9492eb7981..38446eefe44f1 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.test.ts @@ -10,7 +10,7 @@ import moment from 'moment'; jest.mock('./post_pagerduty', () => ({ postPagerduty: jest.fn(), })); -import { ConnectorMetricsCollector, Services } from '@kbn/actions-plugin/server/types'; +import { ConnectorUsageCollector, Services } from '@kbn/actions-plugin/server/types'; import { validateConfig, validateSecrets, validateParams } from '@kbn/actions-plugin/server/lib'; import { postPagerduty } from './post_pagerduty'; import { Logger } from '@kbn/core/server'; @@ -31,12 +31,12 @@ const mockedLogger: jest.Mocked = loggerMock.create(); let connectorType: PagerDutyConnectorType; let configurationUtilities: jest.Mocked; -let connectorMetricsCollector: ConnectorMetricsCollector; +let connectorUsageCollector: ConnectorUsageCollector; beforeEach(() => { configurationUtilities = actionsConfigMock.create(); connectorType = getConnectorType(); - connectorMetricsCollector = new ConnectorMetricsCollector({ + connectorUsageCollector = new ConnectorUsageCollector({ logger: mockedLogger, connectorId: 'test-connector-id', }); @@ -274,7 +274,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }; const actionResponse = await connectorType.executor(executorOptions); const { apiUrl, data, headers } = postPagerdutyMock.mock.calls[0][0]; @@ -356,7 +356,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }; const actionResponse = await connectorType.executor(executorOptions); const { apiUrl, data, headers } = postPagerdutyMock.mock.calls[0][0]; @@ -465,7 +465,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }; const actionResponse = await connectorType.executor(executorOptions); const { apiUrl, data, headers } = postPagerdutyMock.mock.calls[0][0]; @@ -543,7 +543,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }; const actionResponse = await connectorType.executor(executorOptions); const { apiUrl, data, headers } = postPagerdutyMock.mock.calls[0][0]; @@ -587,7 +587,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }; const actionResponse = await connectorType.executor(executorOptions); expect(actionResponse).toMatchInlineSnapshot(` @@ -618,7 +618,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }; const actionResponse = await connectorType.executor(executorOptions); expect(actionResponse).toMatchInlineSnapshot(` @@ -649,7 +649,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }; const actionResponse = await connectorType.executor(executorOptions); expect(actionResponse).toMatchInlineSnapshot(` @@ -680,7 +680,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }; const actionResponse = await connectorType.executor(executorOptions); expect(actionResponse).toMatchInlineSnapshot(` @@ -721,7 +721,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }; const actionResponse = await connectorType.executor(executorOptions); const { apiUrl, data, headers } = postPagerdutyMock.mock.calls[0][0]; @@ -785,7 +785,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }; const actionResponse = await connectorType.executor(executorOptions); const { apiUrl, data, headers } = postPagerdutyMock.mock.calls[0][0]; @@ -852,7 +852,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }; const actionResponse = await connectorType.executor(executorOptions); const { apiUrl, data, headers } = postPagerdutyMock.mock.calls[0][0]; @@ -918,7 +918,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }; const actionResponse = await connectorType.executor(executorOptions); const { apiUrl, data, headers } = postPagerdutyMock.mock.calls[0][0]; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.ts index ee56b9e2d58d8..c4d2444540cad 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.ts @@ -206,7 +206,7 @@ async function executor( services, configurationUtilities, logger, - connectorMetricsCollector, + connectorUsageCollector, } = execOptions; const apiUrl = getPagerDutyApiUrl(config); @@ -222,7 +222,7 @@ async function executor( { apiUrl, data, headers, services }, logger, configurationUtilities, - connectorMetricsCollector + connectorUsageCollector ); } catch (err) { const message = i18n.translate('xpack.stackConnectors.pagerduty.postingErrorMessage', { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/post_pagerduty.ts b/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/post_pagerduty.ts index b93cc81f74492..8b0937f9d857b 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/post_pagerduty.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/post_pagerduty.ts @@ -7,7 +7,7 @@ import axios, { AxiosResponse } from 'axios'; import { Logger } from '@kbn/core/server'; -import { ConnectorMetricsCollector, Services } from '@kbn/actions-plugin/server/types'; +import { ConnectorUsageCollector, Services } from '@kbn/actions-plugin/server/types'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; import { request } from '@kbn/actions-plugin/server/lib/axios_utils'; @@ -23,7 +23,7 @@ export async function postPagerduty( options: PostPagerdutyOptions, logger: Logger, configurationUtilities: ActionsConfigurationUtilities, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { const { apiUrl, data, headers } = options; const axiosInstance = axios.create(); @@ -37,6 +37,6 @@ export async function postPagerduty( headers, configurationUtilities, validateStatus: () => true, - connectorMetricsCollector, + connectorUsageCollector, }); } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.test.ts index 68c05db76512a..6f3999dc70df7 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.test.ts @@ -13,7 +13,7 @@ import { ResilientConnector } from './resilient'; import { actionsMock } from '@kbn/actions-plugin/server/mocks'; import { RESILIENT_CONNECTOR_ID } from './constants'; import { PushToServiceIncidentSchema } from './schema'; -import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; jest.mock('axios'); jest.mock('@kbn/actions-plugin/server/lib/axios_utils', () => { @@ -84,7 +84,7 @@ const mockIncidentUpdate = (withUpdateError = false) => { }) ); }; -let connectorMetricsCollector: ConnectorMetricsCollector; +let connectorUsageCollector: ConnectorUsageCollector; describe('IBM Resilient connector', () => { const logger = loggingSystemMock.createLogger(); @@ -110,7 +110,7 @@ describe('IBM Resilient connector', () => { beforeEach(() => { jest.resetAllMocks(); jest.setSystemTime(TIMESTAMP); - connectorMetricsCollector = new ConnectorMetricsCollector({ + connectorUsageCollector = new ConnectorUsageCollector({ logger, connectorId: 'test-connector-id', }); @@ -136,12 +136,12 @@ describe('IBM Resilient connector', () => { }); it('returns the incident correctly', async () => { - const res = await connector.getIncident({ id: '1' }, connectorMetricsCollector); + const res = await connector.getIncident({ id: '1' }, connectorUsageCollector); expect(res).toEqual(incidentMock); }); it('should call request with correct arguments', async () => { - await connector.getIncident({ id: '1' }, connectorMetricsCollector); + await connector.getIncident({ id: '1' }, connectorUsageCollector); expect(requestMock).toHaveBeenCalledWith({ ...ignoredRequestFields, method: 'GET', @@ -154,7 +154,7 @@ describe('IBM Resilient connector', () => { params: { text_content_output_format: 'objects_convert', }, - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -162,7 +162,7 @@ describe('IBM Resilient connector', () => { requestMock.mockImplementation(() => { throw new Error('An error has occurred'); }); - await expect(connector.getIncident({ id: '1' }, connectorMetricsCollector)).rejects.toThrow( + await expect(connector.getIncident({ id: '1' }, connectorUsageCollector)).rejects.toThrow( 'Unable to get incident with id 1. Error: An error has occurred' ); }); @@ -191,7 +191,7 @@ describe('IBM Resilient connector', () => { }); it('creates the incident correctly', async () => { - const res = await connector.createIncident(incidentMock, connectorMetricsCollector); + const res = await connector.createIncident(incidentMock, connectorUsageCollector); expect(res).toEqual({ title: '1', @@ -202,7 +202,7 @@ describe('IBM Resilient connector', () => { }); it('should call request with correct arguments', async () => { - await connector.createIncident(incidentMock, connectorMetricsCollector); + await connector.createIncident(incidentMock, connectorUsageCollector); expect(requestMock).toHaveBeenCalledWith({ ...ignoredRequestFields, @@ -222,7 +222,7 @@ describe('IBM Resilient connector', () => { Authorization: `Basic ${token}`, 'Content-Type': 'application/json', }, - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -239,7 +239,7 @@ describe('IBM Resilient connector', () => { incidentTypes: [1001], severityCode: 6, }, - connectorMetricsCollector + connectorUsageCollector ) ).rejects.toThrow( '[Action][IBM Resilient]: Unable to create incident. Error: An error has occurred' @@ -249,9 +249,7 @@ describe('IBM Resilient connector', () => { it('should throw if the required attributes are not received in response', async () => { requestMock.mockImplementation(() => createAxiosResponse({ data: { notRequired: 'test' } })); - await expect( - connector.createIncident(incidentMock, connectorMetricsCollector) - ).rejects.toThrow( + await expect(connector.createIncident(incidentMock, connectorUsageCollector)).rejects.toThrow( '[Action][IBM Resilient]: Unable to create incident. Error: Response validation failed (Error: [id]: expected value of type [number] but got [undefined]).' ); }); @@ -269,7 +267,7 @@ describe('IBM Resilient connector', () => { }; it('updates the incident correctly', async () => { mockIncidentUpdate(); - const res = await connector.updateIncident(req, connectorMetricsCollector); + const res = await connector.updateIncident(req, connectorUsageCollector); expect(res).toEqual({ title: '1', @@ -292,7 +290,7 @@ describe('IBM Resilient connector', () => { severityCode: 5, }, }, - connectorMetricsCollector + connectorUsageCollector ); expect(requestMock.mock.calls[1][0]).toEqual({ @@ -349,14 +347,14 @@ describe('IBM Resilient connector', () => { }, ], }, - connectorMetricsCollector, + connectorUsageCollector, }); }); it('it should throw an error', async () => { mockIncidentUpdate(true); - await expect(connector.updateIncident(req, connectorMetricsCollector)).rejects.toThrow( + await expect(connector.updateIncident(req, connectorUsageCollector)).rejects.toThrow( '[Action][IBM Resilient]: Unable to update incident with id 1. Error: An error has occurred' ); }); @@ -379,7 +377,7 @@ describe('IBM Resilient connector', () => { ); requestMock.mockImplementation(() => createAxiosResponse({ data: { notRequired: 'test' } })); - await expect(connector.updateIncident(req, connectorMetricsCollector)).rejects.toThrow( + await expect(connector.updateIncident(req, connectorUsageCollector)).rejects.toThrow( '[Action][IBM Resilient]: Unable to update incident with id 1. Error: Response validation failed (Error: [success]: expected value of type [boolean] but got [undefined]).' ); }); @@ -406,7 +404,7 @@ describe('IBM Resilient connector', () => { }); it('should call request with correct arguments', async () => { - await connector.addComment(req, connectorMetricsCollector); + await connector.addComment(req, connectorUsageCollector); expect(requestMock).toHaveBeenCalledWith({ ...ignoredRequestFields, @@ -422,7 +420,7 @@ describe('IBM Resilient connector', () => { format: 'text', }, }, - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -431,7 +429,7 @@ describe('IBM Resilient connector', () => { throw new Error('An error has occurred'); }); - await expect(connector.addComment(req, connectorMetricsCollector)).rejects.toThrow( + await expect(connector.addComment(req, connectorUsageCollector)).rejects.toThrow( '[Action][IBM Resilient]: Unable to create comment at incident with id 1. Error: An error has occurred.' ); }); @@ -447,7 +445,7 @@ describe('IBM Resilient connector', () => { }); it('should call request with correct arguments', async () => { - await connector.getIncidentTypes(undefined, connectorMetricsCollector); + await connector.getIncidentTypes(undefined, connectorUsageCollector); expect(requestMock).toBeCalledTimes(1); expect(requestMock).toHaveBeenCalledWith({ ...ignoredRequestFields, @@ -458,12 +456,12 @@ describe('IBM Resilient connector', () => { Authorization: `Basic ${token}`, 'Content-Type': 'application/json', }, - connectorMetricsCollector, + connectorUsageCollector, }); }); it('returns incident types correctly', async () => { - const res = await connector.getIncidentTypes(undefined, connectorMetricsCollector); + const res = await connector.getIncidentTypes(undefined, connectorUsageCollector); expect(res).toEqual([ { id: '17', name: 'Communication error (fax; email)' }, @@ -476,9 +474,7 @@ describe('IBM Resilient connector', () => { throw new Error('An error has occurred'); }); - await expect( - connector.getIncidentTypes(undefined, connectorMetricsCollector) - ).rejects.toThrow( + await expect(connector.getIncidentTypes(undefined, connectorUsageCollector)).rejects.toThrow( '[Action][IBM Resilient]: Unable to get incident types. Error: An error has occurred.' ); }); @@ -488,9 +484,7 @@ describe('IBM Resilient connector', () => { createAxiosResponse({ data: { id: '1001', name: 'Custom type' } }) ); - await expect( - connector.getIncidentTypes(undefined, connectorMetricsCollector) - ).rejects.toThrow( + await expect(connector.getIncidentTypes(undefined, connectorUsageCollector)).rejects.toThrow( '[Action][IBM Resilient]: Unable to get incident types. Error: Response validation failed (Error: [values]: expected value of type [array] but got [undefined]).' ); }); @@ -508,7 +502,7 @@ describe('IBM Resilient connector', () => { }); it('should call request with correct arguments', async () => { - await connector.getSeverity(undefined, connectorMetricsCollector); + await connector.getSeverity(undefined, connectorUsageCollector); expect(requestMock).toBeCalledTimes(1); expect(requestMock).toHaveBeenCalledWith({ ...ignoredRequestFields, @@ -519,12 +513,12 @@ describe('IBM Resilient connector', () => { Authorization: `Basic ${token}`, 'Content-Type': 'application/json', }, - connectorMetricsCollector, + connectorUsageCollector, }); }); it('returns severity correctly', async () => { - const res = await connector.getSeverity(undefined, connectorMetricsCollector); + const res = await connector.getSeverity(undefined, connectorUsageCollector); expect(res).toEqual([ { @@ -547,7 +541,7 @@ describe('IBM Resilient connector', () => { throw new Error('An error has occurred'); }); - await expect(connector.getSeverity(undefined, connectorMetricsCollector)).rejects.toThrow( + await expect(connector.getSeverity(undefined, connectorUsageCollector)).rejects.toThrow( '[Action][IBM Resilient]: Unable to get severity. Error: An error has occurred.' ); }); @@ -557,7 +551,7 @@ describe('IBM Resilient connector', () => { createAxiosResponse({ data: { id: '10', name: 'Critical' } }) ); - await expect(connector.getSeverity(undefined, connectorMetricsCollector)).rejects.toThrow( + await expect(connector.getSeverity(undefined, connectorUsageCollector)).rejects.toThrow( '[Action][IBM Resilient]: Unable to get severity. Error: Response validation failed (Error: [values]: expected value of type [array] but got [undefined]).' ); }); @@ -572,7 +566,7 @@ describe('IBM Resilient connector', () => { ); }); it('should call request with correct arguments', async () => { - await connector.getFields(undefined, connectorMetricsCollector); + await connector.getFields(undefined, connectorUsageCollector); expect(requestMock).toBeCalledTimes(1); expect(requestMock).toHaveBeenCalledWith({ @@ -584,12 +578,12 @@ describe('IBM Resilient connector', () => { Authorization: `Basic ${token}`, 'Content-Type': 'application/json', }, - connectorMetricsCollector, + connectorUsageCollector, }); }); it('returns common fields correctly', async () => { - const res = await connector.getFields(undefined, connectorMetricsCollector); + const res = await connector.getFields(undefined, connectorUsageCollector); expect(res).toEqual(resilientFields); }); @@ -597,7 +591,7 @@ describe('IBM Resilient connector', () => { requestMock.mockImplementation(() => { throw new Error('An error has occurred'); }); - await expect(connector.getFields(undefined, connectorMetricsCollector)).rejects.toThrow( + await expect(connector.getFields(undefined, connectorUsageCollector)).rejects.toThrow( 'Unable to get fields. Error: An error has occurred' ); }); @@ -605,7 +599,7 @@ describe('IBM Resilient connector', () => { it('should throw if the required attributes are not received in response', async () => { requestMock.mockImplementation(() => createAxiosResponse({ data: { someField: 'test' } })); - await expect(connector.getFields(undefined, connectorMetricsCollector)).rejects.toThrow( + await expect(connector.getFields(undefined, connectorUsageCollector)).rejects.toThrow( '[Action][IBM Resilient]: Unable to get fields. Error: Response validation failed (Error: expected value of type [array] but got [Object]).' ); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.ts b/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.ts index 6a5b9f36a20ea..da297369ae024 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.ts @@ -10,7 +10,7 @@ import { omitBy, isNil } from 'lodash/fp'; import { CaseConnector, getBasicAuthHeader, ServiceParams } from '@kbn/actions-plugin/server'; import { schema, Type } from '@kbn/config-schema'; import { getErrorMessage } from '@kbn/actions-plugin/server/lib/axios_utils'; -import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { CreateIncidentData, ExternalServiceIncidentResponse, @@ -120,7 +120,7 @@ export class ResilientConnector extends CaseConnector< public async createIncident( incident: Incident, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { try { let data: CreateIncidentData = { @@ -168,7 +168,7 @@ export class ResilientConnector extends CaseConnector< { unknowns: 'allow' } ), }, - connectorMetricsCollector + connectorUsageCollector ); const { id, create_date: createDate } = res.data; @@ -188,10 +188,10 @@ export class ResilientConnector extends CaseConnector< public async updateIncident( { incidentId, incident }: UpdateIncidentParams, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { try { - const latestIncident = await this.getIncident({ id: incidentId }, connectorMetricsCollector); + const latestIncident = await this.getIncident({ id: incidentId }, connectorUsageCollector); // Remove null or undefined values. Allowing null values sets the field in IBM Resilient to empty. const newIncident = omitBy(isNil, incident); @@ -205,14 +205,14 @@ export class ResilientConnector extends CaseConnector< headers: this.getAuthHeaders(), responseSchema: schema.object({ success: schema.boolean() }, { unknowns: 'allow' }), }, - connectorMetricsCollector + connectorUsageCollector ); if (!res.data.success) { throw new Error('Error while updating incident'); } - const updatedIncident = await this.getIncident({ id: incidentId }, connectorMetricsCollector); + const updatedIncident = await this.getIncident({ id: incidentId }, connectorUsageCollector); return { title: `${updatedIncident.id}`, @@ -232,7 +232,7 @@ export class ResilientConnector extends CaseConnector< public async addComment( { incidentId, comment }: { incidentId: string; comment: string }, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ) { try { await this.request( @@ -243,7 +243,7 @@ export class ResilientConnector extends CaseConnector< headers: this.getAuthHeaders(), responseSchema: schema.object({}, { unknowns: 'allow' }), }, - connectorMetricsCollector + connectorUsageCollector ); } catch (error) { throw new Error( @@ -257,7 +257,7 @@ export class ResilientConnector extends CaseConnector< public async getIncident( { id }: { id: string }, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { try { const res = await this.request( @@ -270,7 +270,7 @@ export class ResilientConnector extends CaseConnector< headers: this.getAuthHeaders(), responseSchema: GetIncidentResponseSchema, }, - connectorMetricsCollector + connectorUsageCollector ); return res.data; @@ -283,7 +283,7 @@ export class ResilientConnector extends CaseConnector< public async getIncidentTypes( params: unknown, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { try { const res = await this.request( @@ -293,7 +293,7 @@ export class ResilientConnector extends CaseConnector< headers: this.getAuthHeaders(), responseSchema: GetIncidentTypesResponseSchema, }, - connectorMetricsCollector + connectorUsageCollector ); const incidentTypes = res.data?.values ?? []; @@ -311,7 +311,7 @@ export class ResilientConnector extends CaseConnector< public async getSeverity( params: unknown, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { try { const res = await this.request( @@ -321,7 +321,7 @@ export class ResilientConnector extends CaseConnector< headers: this.getAuthHeaders(), responseSchema: GetSeverityResponseSchema, }, - connectorMetricsCollector + connectorUsageCollector ); const severities = res.data?.values ?? []; @@ -336,7 +336,7 @@ export class ResilientConnector extends CaseConnector< } } - public async getFields(params: unknown, connectorMetricsCollector: ConnectorMetricsCollector) { + public async getFields(params: unknown, connectorUsageCollector: ConnectorUsageCollector) { try { const res = await this.request( { @@ -345,7 +345,7 @@ export class ResilientConnector extends CaseConnector< headers: this.getAuthHeaders(), responseSchema: GetCommonFieldsResponseSchema, }, - connectorMetricsCollector + connectorUsageCollector ); const fields = res.data.map((field) => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.test.ts index fe198c54cf212..8a13a48e47be1 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.test.ts @@ -13,17 +13,17 @@ import { } from '../../../common/sentinelone/types'; import { API_PATH } from './sentinelone'; import { SentinelOneGetActivitiesResponseSchema } from '../../../common/sentinelone/schema'; -import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; describe('SentinelOne Connector', () => { let connectorInstance: ReturnType; - let connectorMetricsCollector: ConnectorMetricsCollector; + let connectorUsageCollector: ConnectorUsageCollector; const logger = loggingSystemMock.createLogger(); beforeEach(() => { connectorInstance = sentinelOneConnectorMocks.create(); - connectorMetricsCollector = new ConnectorMetricsCollector({ + connectorUsageCollector = new ConnectorUsageCollector({ logger, connectorId: 'test-connector-id', }); @@ -44,7 +44,7 @@ describe('SentinelOne Connector', () => { fetchAgentFilesParams.agentId = ''; await expect( - connectorInstance.fetchAgentFiles(fetchAgentFilesParams, connectorMetricsCollector) + connectorInstance.fetchAgentFiles(fetchAgentFilesParams, connectorUsageCollector) ).rejects.toHaveProperty('message', "'agentId' parameter is required"); }); @@ -52,7 +52,7 @@ describe('SentinelOne Connector', () => { const fetchFilesUrl = `${connectorInstance.constructorParams.config.url}${API_PATH}/agents/${fetchAgentFilesParams.agentId}/actions/fetch-files`; const response = await connectorInstance.fetchAgentFiles( fetchAgentFilesParams, - connectorMetricsCollector + connectorUsageCollector ); expect(response).toEqual({ data: { success: true }, errors: null }); @@ -86,13 +86,13 @@ describe('SentinelOne Connector', () => { it('should error if called with invalid agent id', async () => { downloadAgentFileParams.agentId = ''; await expect( - connectorInstance.downloadAgentFile(downloadAgentFileParams, connectorMetricsCollector) + connectorInstance.downloadAgentFile(downloadAgentFileParams, connectorUsageCollector) ).rejects.toHaveProperty('message', "'agentId' parameter is required"); }); it('should call SentinelOne api with expected url', async () => { await expect( - connectorInstance.downloadAgentFile(downloadAgentFileParams, connectorMetricsCollector) + connectorInstance.downloadAgentFile(downloadAgentFileParams, connectorUsageCollector) ).resolves.toEqual(connectorInstance.mockResponses.downloadAgentFileApiResponse); }); }); @@ -134,7 +134,7 @@ describe('SentinelOne Connector', () => { it('should call SentinelOne api to retrieve task results', async () => { await connectorInstance.downloadRemoteScriptResults( { taskId: 'task-123' }, - connectorMetricsCollector + connectorUsageCollector ); expect(connectorInstance.requestSpy).toHaveBeenCalledWith( @@ -151,7 +151,7 @@ describe('SentinelOne Connector', () => { await expect( connectorInstance.downloadRemoteScriptResults( { taskId: 'task-123' }, - connectorMetricsCollector + connectorUsageCollector ) ).rejects.toThrow('Download URL for script results of task id [task-123] not found'); }); @@ -160,7 +160,7 @@ describe('SentinelOne Connector', () => { await expect( connectorInstance.downloadRemoteScriptResults( { taskId: 'task-123' }, - connectorMetricsCollector + connectorUsageCollector ) ).resolves.toEqual(connectorInstance.mockResponses.downloadRemoteScriptResults); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.ts b/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.ts index 2f1729466b76e..dd73bafae8d2f 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.ts @@ -8,7 +8,7 @@ import { ServiceParams, SubActionConnector } from '@kbn/actions-plugin/server'; import type { AxiosError } from 'axios'; import { SubActionRequestParams } from '@kbn/actions-plugin/server/sub_action_framework/types'; -import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { Stream } from 'stream'; import type { SentinelOneConfig, @@ -160,7 +160,7 @@ export class SentinelOneConnector extends SubActionConnector< public async fetchAgentFiles( { files, agentId, zipPassCode }: SentinelOneFetchAgentFilesParams, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ) { if (!agentId) { throw new Error(`'agentId' parameter is required`); @@ -178,13 +178,13 @@ export class SentinelOneConnector extends SubActionConnector< }, responseSchema: SentinelOneFetchAgentFilesResponseSchema, }, - connectorMetricsCollector + connectorUsageCollector ); } public async downloadAgentFile( { agentId, activityId }: SentinelOneDownloadAgentFileParams, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ) { if (!agentId) { throw new Error(`'agentId' parameter is required`); @@ -197,13 +197,13 @@ export class SentinelOneConnector extends SubActionConnector< responseType: 'stream', responseSchema: SentinelOneDownloadAgentFileResponseSchema, }, - connectorMetricsCollector + connectorUsageCollector ); } public async getActivities( queryParams?: SentinelOneGetActivitiesParams, - connectorMetricsCollector?: ConnectorMetricsCollector + connectorUsageCollector?: ConnectorUsageCollector ) { return this.sentinelOneApiRequest( { @@ -212,13 +212,13 @@ export class SentinelOneConnector extends SubActionConnector< params: queryParams, responseSchema: SentinelOneGetActivitiesResponseSchema, }, - connectorMetricsCollector! + connectorUsageCollector! ); } public async executeScript( { filter, script }: SentinelOneExecuteScriptParams, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ) { if (!filter.ids && !filter.uuids) { throw new Error(`A filter must be defined; either 'ids' or 'uuids'`); @@ -237,15 +237,15 @@ export class SentinelOneConnector extends SubActionConnector< }, responseSchema: SentinelOneExecuteScriptResponseSchema, }, - connectorMetricsCollector + connectorUsageCollector ); } public async isolateHost( { alertIds, ...payload }: SentinelOneIsolateHostParams, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ) { - const response = await this.getAgents(payload, connectorMetricsCollector); + const response = await this.getAgents(payload, connectorUsageCollector); if (response.data.length === 0) { const errorMessage = 'No agents found'; @@ -272,15 +272,15 @@ export class SentinelOneConnector extends SubActionConnector< }, responseSchema: SentinelOneIsolateHostResponseSchema, }, - connectorMetricsCollector + connectorUsageCollector ); } public async releaseHost( { alertIds, ...payload }: SentinelOneIsolateHostParams, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ) { - const response = await this.getAgents(payload, connectorMetricsCollector); + const response = await this.getAgents(payload, connectorUsageCollector); if (response.data.length === 0) { throw new Error('No agents found'); @@ -303,13 +303,13 @@ export class SentinelOneConnector extends SubActionConnector< }, responseSchema: SentinelOneIsolateHostResponseSchema, }, - connectorMetricsCollector + connectorUsageCollector ); } public async getAgents( payload: SentinelOneGetAgentsParams, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { return this.sentinelOneApiRequest( { @@ -319,13 +319,13 @@ export class SentinelOneConnector extends SubActionConnector< }, responseSchema: SentinelOneGetAgentsResponseSchema, }, - connectorMetricsCollector + connectorUsageCollector ); } public async getRemoteScriptStatus( payload: SentinelOneGetRemoteScriptStatusParams, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { return this.sentinelOneApiRequest( { @@ -335,13 +335,13 @@ export class SentinelOneConnector extends SubActionConnector< }, responseSchema: SentinelOneGetRemoteScriptStatusResponseSchema, }, - connectorMetricsCollector + connectorUsageCollector ) as unknown as SentinelOneGetRemoteScriptStatusApiResponse; } public async getRemoteScriptResults( { taskIds }: SentinelOneGetRemoteScriptResultsParams, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { return this.sentinelOneApiRequest( { @@ -350,17 +350,17 @@ export class SentinelOneConnector extends SubActionConnector< data: { data: { taskIds } }, responseSchema: SentinelOneGetRemoteScriptResultsResponseSchema, }, - connectorMetricsCollector + connectorUsageCollector ) as unknown as SentinelOneGetRemoteScriptResultsApiResponse; } public async downloadRemoteScriptResults( { taskId }: SentinelOneDownloadRemoteScriptResultsParams, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { const scriptResultsInfo = await this.getRemoteScriptResults( { taskIds: [taskId] }, - connectorMetricsCollector + connectorUsageCollector ); this.logger.debug( @@ -387,7 +387,7 @@ export class SentinelOneConnector extends SubActionConnector< responseType: 'stream', responseSchema: SentinelOneDownloadRemoteScriptResultsResponseSchema, }, - connectorMetricsCollector + connectorUsageCollector ); return downloadConnection.data; @@ -395,7 +395,7 @@ export class SentinelOneConnector extends SubActionConnector< private async sentinelOneApiRequest( req: SubActionRequestParams, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { const response = await this.request( { @@ -405,7 +405,7 @@ export class SentinelOneConnector extends SubActionConnector< APIToken: this.secrets.token, }, }, - connectorMetricsCollector + connectorUsageCollector ); return response.data; @@ -435,7 +435,7 @@ export class SentinelOneConnector extends SubActionConnector< public async getRemoteScripts( payload: SentinelOneGetRemoteScriptsParams, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { return this.sentinelOneApiRequest( { @@ -446,7 +446,7 @@ export class SentinelOneConnector extends SubActionConnector< }, responseSchema: SentinelOneGetRemoteScriptsResponseSchema, }, - connectorMetricsCollector + connectorUsageCollector ); } } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/server_log/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/server_log/index.test.ts index 85fb63bd28cfe..29fd5d41adc26 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/server_log/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/server_log/index.test.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { ConnectorMetricsCollector, validateParams } from '@kbn/actions-plugin/server/lib'; +import { validateParams } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { Logger } from '@kbn/core/server'; import { actionsMock } from '@kbn/actions-plugin/server/mocks'; import { getConnectorType, ServerLogConnectorType, ServerLogConnectorTypeExecutorOptions } from '.'; @@ -107,7 +108,7 @@ describe('execute()', () => { secrets: {}, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector: new ConnectorMetricsCollector({ + connectorUsageCollector: new ConnectorUsageCollector({ logger: mockedLogger, connectorId: 'test-connector-id', }), diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/index.ts index 236589545dd36..d32f52cd698ee 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/index.ts @@ -109,7 +109,7 @@ async function executorITOM( secrets, configurationUtilities, logger, - connectorMetricsCollector, + connectorUsageCollector, } = execOptions; const { subAction, subActionParams } = params; const connectorTokenClient = execOptions.services.connectorTokenClient; @@ -127,7 +127,7 @@ async function executorITOM( serviceConfig: externalServiceConfig, connectorTokenClient, createServiceFn: createService, - connectorMetricsCollector, + connectorUsageCollector, }); const apiAsRecord = api as unknown as Record; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.test.ts index 57ae7f16fdd0f..951c2731b526d 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.test.ts @@ -15,7 +15,7 @@ import { loggingSystemMock } from '@kbn/core/server/mocks'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { snExternalServiceConfig } from '../lib/servicenow/config'; import { itomEventParams, serviceNowChoices } from '../lib/servicenow/mocks'; -import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; const logger = loggingSystemMock.create().get() as jest.Mocked; @@ -34,10 +34,10 @@ const configurationUtilities = actionsConfigMock.create(); describe('ServiceNow SIR service', () => { let service: ExternalServiceITOM; - let connectorMetricsCollector: ConnectorMetricsCollector; + let connectorUsageCollector: ConnectorUsageCollector; beforeEach(() => { - connectorMetricsCollector = new ConnectorMetricsCollector({ + connectorUsageCollector = new ConnectorUsageCollector({ logger, connectorId: 'test-connector-id', }); @@ -50,7 +50,7 @@ describe('ServiceNow SIR service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow-itom'], axiosInstance: axios, - connectorMetricsCollector, + connectorUsageCollector, }) as ExternalServiceITOM; }); @@ -76,7 +76,7 @@ describe('ServiceNow SIR service', () => { url: 'https://example.com/api/global/em/jsonv2', method: 'post', data: { records: [itomEventParams] }, - connectorMetricsCollector, + connectorUsageCollector, }); }); }); @@ -93,7 +93,7 @@ describe('ServiceNow SIR service', () => { logger, configurationUtilities, url: 'https://example.com/api/now/table/sys_choice?sysparm_query=name=task^ORname=em_event^element=severity^language=en&sysparm_fields=label,value,dependent_value,element', - connectorMetricsCollector, + connectorUsageCollector, }); }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.ts index ba99737c4f75d..a6ed020461194 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.ts @@ -23,7 +23,7 @@ export const createExternalService: ServiceFactory = ({ configurationUtilities, serviceConfig, axiosInstance, - connectorMetricsCollector, + connectorUsageCollector, }): ExternalServiceITOM => { const snService = createExternalServiceCommon({ credentials, @@ -31,7 +31,7 @@ export const createExternalService: ServiceFactory = ({ configurationUtilities, serviceConfig, axiosInstance, - connectorMetricsCollector, + connectorUsageCollector, }); const addEvent = async (params: ExecutorSubActionAddEventParams) => { @@ -43,7 +43,7 @@ export const createExternalService: ServiceFactory = ({ method: 'post', data: { records: [params] }, configurationUtilities, - connectorMetricsCollector, + connectorUsageCollector, }); snService.checkInstance(res); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/index.ts index 4e20e027a2481..6ab6bc389ac7a 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/index.ts @@ -133,7 +133,7 @@ async function executor( services, configurationUtilities, logger, - connectorMetricsCollector, + connectorUsageCollector, } = execOptions; const { subAction, subActionParams } = params; const connectorTokenClient = services.connectorTokenClient; @@ -151,7 +151,7 @@ async function executor( serviceConfig: externalServiceConfig, connectorTokenClient, createServiceFn: createService, - connectorMetricsCollector, + connectorUsageCollector, }); const apiAsRecord = api as unknown as Record; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/service.test.ts index 529b2bc18f073..5590da4cbfbd6 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/service.test.ts @@ -15,7 +15,7 @@ import { loggingSystemMock } from '@kbn/core/server/mocks'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { serviceNowCommonFields, serviceNowChoices } from '../lib/servicenow/mocks'; import { snExternalServiceConfig } from '../lib/servicenow/config'; -import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; const logger = loggingSystemMock.create().get() as jest.Mocked; jest.mock('axios', () => ({ @@ -123,7 +123,7 @@ const expectImportedIncident = (update: boolean) => { configurationUtilities, url: 'https://example.com/api/x_elas2_inc_int/elastic_api/health', method: 'get', - connectorMetricsCollector: expect.any(ConnectorMetricsCollector), + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); expect(requestMock).toHaveBeenNthCalledWith(2, { @@ -137,7 +137,7 @@ const expectImportedIncident = (update: boolean) => { u_description: 'desc', ...(update ? { elastic_incident_id: '1' } : {}), }, - connectorMetricsCollector: expect.any(ConnectorMetricsCollector), + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); expect(requestMock).toHaveBeenNthCalledWith(3, { @@ -146,17 +146,17 @@ const expectImportedIncident = (update: boolean) => { configurationUtilities, url: 'https://example.com/api/now/v2/table/incident/1', method: 'get', - connectorMetricsCollector: expect.any(ConnectorMetricsCollector), + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); }; describe('ServiceNow service', () => { let service: ExternalService; - let connectorMetricsCollector: ConnectorMetricsCollector; + let connectorUsageCollector: ConnectorUsageCollector; beforeEach(() => { jest.clearAllMocks(); - connectorMetricsCollector = new ConnectorMetricsCollector({ + connectorUsageCollector = new ConnectorUsageCollector({ logger, connectorId: 'test-connector-id', }); @@ -171,7 +171,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow'], axiosInstance: axios, - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -187,7 +187,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow'], axiosInstance: axios, - connectorMetricsCollector, + connectorUsageCollector, }) ).toThrow(); }); @@ -228,7 +228,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow'], axiosInstance: axios, - connectorMetricsCollector, + connectorUsageCollector, }) ).toThrow(); }); @@ -393,7 +393,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow'], axiosInstance: axios, - connectorMetricsCollector, + connectorUsageCollector, }) ).toThrow(); }); @@ -421,7 +421,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/incident/1', method: 'get', - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -435,7 +435,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], table: 'sn_si_incident' }, axiosInstance: axios, - connectorMetricsCollector, + connectorUsageCollector, }); requestMock.mockImplementation(() => ({ @@ -449,7 +449,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/sn_si_incident/1', method: 'get', - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -503,7 +503,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow-sir'], axiosInstance: axios, - connectorMetricsCollector, + connectorUsageCollector, }); const res = await createIncident(service); @@ -514,7 +514,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/x_elas2_sir_int/elastic_api/health', method: 'get', - connectorMetricsCollector, + connectorUsageCollector, }); expect(requestMock).toHaveBeenNthCalledWith(2, { @@ -524,7 +524,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/import/x_elas2_sir_int_elastic_si_incident', method: 'post', data: { u_short_description: 'title', u_description: 'desc' }, - connectorMetricsCollector, + connectorUsageCollector, }); expect(requestMock).toHaveBeenNthCalledWith(3, { @@ -533,7 +533,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/sn_si_incident/1', method: 'get', - connectorMetricsCollector, + connectorUsageCollector, }); expect(res.url).toEqual('https://example.com/nav_to.do?uri=sn_si_incident.do?sys_id=1'); @@ -592,7 +592,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], useImportAPI: false }, axiosInstance: axios, - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -617,7 +617,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/v2/table/incident', method: 'post', data: { short_description: 'title', description: 'desc' }, - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -631,7 +631,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow-sir'], useImportAPI: false }, axiosInstance: axios, - connectorMetricsCollector, + connectorUsageCollector, }); mockIncidentResponse(false); @@ -647,7 +647,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/v2/table/sn_si_incident', method: 'post', data: { short_description: 'title', description: 'desc' }, - connectorMetricsCollector, + connectorUsageCollector, }); expect(res.url).toEqual('https://example.com/nav_to.do?uri=sn_si_incident.do?sys_id=1'); @@ -684,7 +684,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow-sir'], axiosInstance: axios, - connectorMetricsCollector, + connectorUsageCollector, }); const res = await updateIncident(service); @@ -694,7 +694,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/x_elas2_sir_int/elastic_api/health', method: 'get', - connectorMetricsCollector, + connectorUsageCollector, }); expect(requestMock).toHaveBeenNthCalledWith(2, { @@ -704,7 +704,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/import/x_elas2_sir_int_elastic_si_incident', method: 'post', data: { u_short_description: 'title', u_description: 'desc', elastic_incident_id: '1' }, - connectorMetricsCollector, + connectorUsageCollector, }); expect(requestMock).toHaveBeenNthCalledWith(3, { @@ -713,7 +713,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/sn_si_incident/1', method: 'get', - connectorMetricsCollector, + connectorUsageCollector, }); expect(res.url).toEqual('https://example.com/nav_to.do?uri=sn_si_incident.do?sys_id=1'); @@ -775,7 +775,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], useImportAPI: false }, axiosInstance: axios, - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -801,7 +801,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/v2/table/incident/1', method: 'patch', data: { short_description: 'title', description: 'desc' }, - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -815,7 +815,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow-sir'], useImportAPI: false }, axiosInstance: axios, - connectorMetricsCollector, + connectorUsageCollector, }); mockIncidentResponse(false); @@ -832,7 +832,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/v2/table/sn_si_incident/1', method: 'patch', data: { short_description: 'title', description: 'desc' }, - connectorMetricsCollector, + connectorUsageCollector, }); expect(res.url).toEqual('https://example.com/nav_to.do?uri=sn_si_incident.do?sys_id=1'); @@ -852,7 +852,7 @@ describe('ServiceNow service', () => { logger, configurationUtilities, url: 'https://example.com/api/now/table/sys_dictionary?sysparm_query=name=task^ORname=incident^internal_type=string&active=true&array=false&read_only=false&sysparm_fields=max_length,element,column_label,mandatory', - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -874,7 +874,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], table: 'sn_si_incident' }, axiosInstance: axios, - connectorMetricsCollector, + connectorUsageCollector, }); requestMock.mockImplementation(() => ({ @@ -887,7 +887,7 @@ describe('ServiceNow service', () => { logger, configurationUtilities, url: 'https://example.com/api/now/table/sys_dictionary?sysparm_query=name=task^ORname=sn_si_incident^internal_type=string&active=true&array=false&read_only=false&sysparm_fields=max_length,element,column_label,mandatory', - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -924,7 +924,7 @@ describe('ServiceNow service', () => { logger, configurationUtilities, url: 'https://example.com/api/now/table/sys_choice?sysparm_query=name=task^ORname=incident^element=priority^ORelement=category^language=en&sysparm_fields=label,value,dependent_value,element', - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -946,7 +946,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], table: 'sn_si_incident' }, axiosInstance: axios, - connectorMetricsCollector, + connectorUsageCollector, }); requestMock.mockImplementation(() => ({ @@ -960,7 +960,7 @@ describe('ServiceNow service', () => { logger, configurationUtilities, url: 'https://example.com/api/now/table/sys_choice?sysparm_query=name=task^ORname=sn_si_incident^element=priority^ORelement=category^language=en&sysparm_fields=label,value,dependent_value,element', - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -1053,7 +1053,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], useImportAPI: false }, axiosInstance: axios, - connectorMetricsCollector, + connectorUsageCollector, }); await service.checkIfApplicationIsInstalled(); expect(requestMock).not.toHaveBeenCalled(); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/index.ts index c880848d0667c..8d842c6e6fccf 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/index.ts @@ -124,7 +124,7 @@ async function executor( services, configurationUtilities, logger, - connectorMetricsCollector, + connectorUsageCollector, } = execOptions; const { subAction, subActionParams } = params; const connectorTokenClient = services.connectorTokenClient; @@ -142,7 +142,7 @@ async function executor( serviceConfig: externalServiceConfig, connectorTokenClient, createServiceFn: createService, - connectorMetricsCollector, + connectorUsageCollector, }); const apiAsRecord = api as unknown as Record; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.test.ts index 17a211458351f..91eb7e4dcd7af 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.test.ts @@ -15,7 +15,7 @@ import { loggingSystemMock } from '@kbn/core/server/mocks'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { observables } from '../lib/servicenow/mocks'; import { snExternalServiceConfig } from '../lib/servicenow/config'; -import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; const logger = loggingSystemMock.create().get() as jest.Mocked; @@ -32,7 +32,7 @@ jest.mock('@kbn/actions-plugin/server/lib/axios_utils', () => { axios.create = jest.fn(() => axios); const requestMock = utils.request as jest.Mock; const configurationUtilities = actionsConfigMock.create(); -let connectorMetricsCollector: ConnectorMetricsCollector; +let connectorUsageCollector: ConnectorUsageCollector; const mockApplicationVersion = () => requestMock.mockImplementationOnce(() => ({ @@ -72,7 +72,7 @@ const expectAddObservables = (single: boolean) => { configurationUtilities, url: 'https://example.com/api/x_elas2_sir_int/elastic_api/health', method: 'get', - connectorMetricsCollector: expect.any(ConnectorMetricsCollector), + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); const url = single @@ -88,7 +88,7 @@ const expectAddObservables = (single: boolean) => { url, method: 'post', data, - connectorMetricsCollector: expect.any(ConnectorMetricsCollector), + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); }; @@ -96,7 +96,7 @@ describe('ServiceNow SIR service', () => { let service: ExternalServiceSIR; beforeEach(() => { - connectorMetricsCollector = new ConnectorMetricsCollector({ + connectorUsageCollector = new ConnectorUsageCollector({ logger, connectorId: 'test-connector-id', }); @@ -109,7 +109,7 @@ describe('ServiceNow SIR service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow-sir'], axiosInstance: axios, - connectorMetricsCollector, + connectorUsageCollector, }) as ExternalServiceSIR; }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.ts index b8ba4826d6838..8fc7249c1d6a1 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.ts @@ -28,7 +28,7 @@ export const createExternalService: ServiceFactory = ({ configurationUtilities, serviceConfig, axiosInstance, - connectorMetricsCollector, + connectorUsageCollector, }): ExternalServiceSIR => { const snService = createExternalServiceCommon({ credentials, @@ -36,7 +36,7 @@ export const createExternalService: ServiceFactory = ({ configurationUtilities, serviceConfig, axiosInstance, - connectorMetricsCollector, + connectorUsageCollector, }); const _addObservable = async (data: Observable | Observable[], url: string) => { @@ -49,7 +49,7 @@ export const createExternalService: ServiceFactory = ({ method: 'post', data, configurationUtilities, - connectorMetricsCollector, + connectorUsageCollector, }); snService.checkInstance(res); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack/index.test.ts index 25fc03895fcdb..7d897ce5a3b77 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack/index.test.ts @@ -9,7 +9,7 @@ import { Logger } from '@kbn/core/server'; import { Services, ActionTypeExecutorResult as ConnectorTypeExecutorResult, - ConnectorMetricsCollector, + ConnectorUsageCollector, } from '@kbn/actions-plugin/server/types'; import { validateParams, validateSecrets } from '@kbn/actions-plugin/server/lib'; import { @@ -36,7 +36,7 @@ const mockedLogger: jest.Mocked = loggerMock.create(); let connectorType: SlackConnectorType; let configurationUtilities: jest.Mocked; -let connectorMetricsCollector: ConnectorMetricsCollector; +let connectorUsageCollector: ConnectorUsageCollector; beforeEach(() => { configurationUtilities = actionsConfigMock.create(); @@ -45,7 +45,7 @@ beforeEach(() => { return { status: 'ok', actionId: options.actionId }; }, }); - connectorMetricsCollector = new ConnectorMetricsCollector({ + connectorUsageCollector = new ConnectorUsageCollector({ logger: mockedLogger, connectorId: 'test-connector-id', }); @@ -187,7 +187,7 @@ describe('execute()', () => { params: { message: 'this invocation should succeed' }, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }); expect(response).toMatchInlineSnapshot(` Object { @@ -208,7 +208,7 @@ describe('execute()', () => { params: { message: 'failure: this invocation should fail' }, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }) ).rejects.toThrowErrorMatchingInlineSnapshot( `"slack mockExecutor failure: this invocation should fail"` @@ -234,7 +234,7 @@ describe('execute()', () => { params: { message: 'this invocation should succeed' }, configurationUtilities: configUtils, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }); expect(mockedLogger.debug).toHaveBeenCalledWith( 'IncomingWebhook was called with proxyUrl https://someproxyhost' @@ -261,7 +261,7 @@ describe('execute()', () => { params: { message: 'this invocation should succeed' }, configurationUtilities: configUtils, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }); expect(mockedLogger.debug).not.toHaveBeenCalledWith( 'IncomingWebhook was called with proxyUrl https://someproxyhost' @@ -288,7 +288,7 @@ describe('execute()', () => { params: { message: 'this invocation should succeed' }, configurationUtilities: configUtils, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }); expect(mockedLogger.debug).toHaveBeenCalledWith( 'IncomingWebhook was called with proxyUrl https://someproxyhost' @@ -315,7 +315,7 @@ describe('execute()', () => { params: { message: 'this invocation should succeed' }, configurationUtilities: configUtils, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }); expect(mockedLogger.debug).toHaveBeenCalledWith( 'IncomingWebhook was called with proxyUrl https://someproxyhost' @@ -342,7 +342,7 @@ describe('execute()', () => { params: { message: 'this invocation should succeed' }, configurationUtilities: configUtils, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }); expect(mockedLogger.debug).not.toHaveBeenCalledWith( 'IncomingWebhook was called with proxyUrl https://someproxyhost' diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack/index.ts index 173f309072bb5..489d7c22b0286 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack/index.ts @@ -139,7 +139,7 @@ function validateConnectorTypeConfig( async function slackExecutor( execOptions: SlackConnectorTypeExecutorOptions ): Promise> { - const { actionId, secrets, params, configurationUtilities, logger, connectorMetricsCollector } = + const { actionId, secrets, params, configurationUtilities, logger, connectorUsageCollector } = execOptions; let result: IncomingWebhookResult; @@ -164,7 +164,7 @@ async function slackExecutor( const webhook = new IncomingWebhook(webhookUrl, { agent, }); - connectorMetricsCollector.addRequestBodyBytes(undefined, { text: message }); + connectorUsageCollector.addRequestBodyBytes(undefined, { text: message }); result = await webhook.send(message); } catch (err) { if (err.original == null || err.original.response == null) { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.test.ts index ca0e24dc4e11d..84e5b68a41c7e 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.test.ts @@ -7,7 +7,7 @@ import axios from 'axios'; import { Logger } from '@kbn/core/server'; -import { ConnectorMetricsCollector, Services } from '@kbn/actions-plugin/server/types'; +import { ConnectorUsageCollector, Services } from '@kbn/actions-plugin/server/types'; import { validateConfig, validateParams, validateSecrets } from '@kbn/actions-plugin/server/lib'; import { getConnectorType } from '.'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; @@ -39,12 +39,12 @@ const headers = { let connectorType: SlackApiConnectorType; let configurationUtilities: jest.Mocked; -let connectorMetricsCollector: ConnectorMetricsCollector; +let connectorUsageCollector: ConnectorUsageCollector; beforeEach(() => { configurationUtilities = actionsConfigMock.create(); connectorType = getConnectorType(); - connectorMetricsCollector = new ConnectorMetricsCollector({ + connectorUsageCollector = new ConnectorUsageCollector({ logger: mockedLogger, connectorId: 'test-connector-id', }); @@ -203,7 +203,7 @@ describe('execute', () => { params: {} as PostMessageParams, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }) ).rejects.toThrowErrorMatchingInlineSnapshot( `"[Action][ExternalService] -> [Slack API] Unsupported subAction type undefined."` @@ -302,7 +302,7 @@ describe('execute', () => { }, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }); expect(requestMock).toHaveBeenCalledWith({ @@ -313,7 +313,7 @@ describe('execute', () => { method: 'post', url: 'https://slack.com/api/chat.postMessage', data: { channel: 'general', text: 'some text' }, - connectorMetricsCollector, + connectorUsageCollector, }); expect(response).toEqual({ @@ -394,7 +394,7 @@ describe('execute', () => { }, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }); expect(requestMock).toHaveBeenCalledWith({ @@ -405,7 +405,7 @@ describe('execute', () => { method: 'post', url: 'https://slack.com/api/chat.postMessage', data: { channel: 'LKJHGF345', text: 'some text' }, - connectorMetricsCollector, + connectorUsageCollector, }); expect(response).toEqual({ @@ -486,7 +486,7 @@ describe('execute', () => { }, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }); expect(requestMock).toHaveBeenCalledWith({ @@ -497,7 +497,7 @@ describe('execute', () => { method: 'post', url: 'https://slack.com/api/chat.postMessage', data: { channel: 'LKJHGF345', blocks: testBlock.blocks }, - connectorMetricsCollector, + connectorUsageCollector, }); expect(response).toEqual({ @@ -537,7 +537,7 @@ describe('execute', () => { }, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }); expect(requestMock).toHaveBeenCalledWith({ @@ -547,7 +547,7 @@ describe('execute', () => { logger: mockedLogger, method: 'get', url: 'https://slack.com/api/conversations.info?channel=ZXCVBNM567', - connectorMetricsCollector, + connectorUsageCollector, }); expect(response).toEqual({ diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.ts index d70085805db0f..b816a1b014678 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.ts @@ -107,7 +107,7 @@ const slackApiExecutor = async ({ secrets, configurationUtilities, logger, - connectorMetricsCollector, + connectorUsageCollector, }: SlackApiExecutorOptions): Promise> => { const subAction = params.subAction; @@ -130,7 +130,7 @@ const slackApiExecutor = async ({ }, logger, configurationUtilities, - connectorMetricsCollector + connectorUsageCollector ); if (subAction === 'validChannelId') { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.test.ts index 2e398fa4017c4..936d4006006d1 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.test.ts @@ -13,7 +13,7 @@ import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.moc import { createExternalService } from './service'; import { SlackApiService } from '../../../common/slack_api/types'; import { SLACK_API_CONNECTOR_ID } from '../../../common/slack_api/constants'; -import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; const logger = loggingSystemMock.create().get() as jest.Mocked; @@ -29,7 +29,7 @@ jest.mock('@kbn/actions-plugin/server/lib/axios_utils', () => { axios.create = jest.fn(() => axios); const requestMock = request as jest.Mock; const configurationUtilities = actionsConfigMock.create(); -let connectorMetricsCollector: ConnectorMetricsCollector; +let connectorUsageCollector: ConnectorUsageCollector; const channel = { id: 'channel_id_1', @@ -119,7 +119,7 @@ describe('Slack API service', () => { let service: SlackApiService; beforeAll(() => { - connectorMetricsCollector = new ConnectorMetricsCollector({ + connectorUsageCollector = new ConnectorUsageCollector({ logger, connectorId: 'test-connector-id', }); @@ -129,7 +129,7 @@ describe('Slack API service', () => { }, logger, configurationUtilities, - connectorMetricsCollector + connectorUsageCollector ); }); @@ -146,7 +146,7 @@ describe('Slack API service', () => { }, logger, configurationUtilities, - connectorMetricsCollector + connectorUsageCollector ) ).toThrowErrorMatchingInlineSnapshot(`"[Action][Slack API]: Wrong configuration."`); }); @@ -180,7 +180,7 @@ describe('Slack API service', () => { configurationUtilities, method: 'get', url: 'https://slack.com/api/conversations.info?channel=channel_id_1', - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -216,7 +216,7 @@ describe('Slack API service', () => { method: 'post', url: 'https://slack.com/api/chat.postMessage', data: { channel: 'general', text: 'a message' }, - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -241,7 +241,7 @@ describe('Slack API service', () => { method: 'post', url: 'https://slack.com/api/chat.postMessage', data: { channel: 'QWEERTYU987', text: 'a message' }, - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -262,7 +262,7 @@ describe('Slack API service', () => { method: 'post', url: 'https://slack.com/api/chat.postMessage', data: { channel: 'QWEERTYU987', text: 'a message' }, - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -303,7 +303,7 @@ describe('Slack API service', () => { method: 'post', url: 'https://slack.com/api/chat.postMessage', data: { channel: 'general', blocks: testBlock.blocks }, - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -328,7 +328,7 @@ describe('Slack API service', () => { method: 'post', url: 'https://slack.com/api/chat.postMessage', data: { channel: 'QWEERTYU987', blocks: testBlock.blocks }, - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -352,7 +352,7 @@ describe('Slack API service', () => { method: 'post', url: 'https://slack.com/api/chat.postMessage', data: { channel: 'QWEERTYU987', blocks: testBlock.blocks }, - connectorMetricsCollector, + connectorUsageCollector, }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.ts index a21c07ccef45b..7180b0982d92c 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.ts @@ -13,7 +13,7 @@ import { request } from '@kbn/actions-plugin/server/lib/axios_utils'; import { pipe } from 'fp-ts/lib/pipeable'; import { map, getOrElse } from 'fp-ts/lib/Option'; import type { ActionTypeExecutorResult as ConnectorTypeExecutorResult } from '@kbn/actions-plugin/server/types'; -import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/types'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { SLACK_CONNECTOR_NAME } from './translations'; import type { PostMessageSubActionParams, @@ -113,7 +113,7 @@ export const createExternalService = ( }, logger: Logger, configurationUtilities: ActionsConfigurationUtilities, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): SlackApiService => { const { token } = secrets; const { allowedChannels } = config || { allowedChannels: [] }; @@ -141,7 +141,7 @@ export const createExternalService = ( method: 'get', headers, url: `${SLACK_URL}conversations.info?channel=${channelId}`, - connectorMetricsCollector, + connectorUsageCollector, }); }; if (channelId.length === 0) { @@ -210,7 +210,7 @@ export const createExternalService = ( data: { channel: channelToUse, text }, headers, configurationUtilities, - connectorMetricsCollector, + connectorUsageCollector, }); return buildSlackExecutorSuccessResponse({ slackApiResponseData: result.data }); @@ -236,7 +236,7 @@ export const createExternalService = ( data: { channel: channelToUse, blocks: blockJson.blocks }, headers, configurationUtilities, - connectorMetricsCollector, + connectorUsageCollector, }); return buildSlackExecutorSuccessResponse({ slackApiResponseData: result.data }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/swimlane/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/swimlane/index.ts index edf0a4a0edf2b..bbe53e86e068e 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/swimlane/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/swimlane/index.ts @@ -83,7 +83,7 @@ async function executor( secrets, configurationUtilities, logger, - connectorMetricsCollector, + connectorUsageCollector, } = execOptions; const { subAction, subActionParams } = params as ExecutorParams; let data: SwimlaneExecutorResultData | null = null; @@ -95,7 +95,7 @@ async function executor( }, logger, configurationUtilities, - connectorMetricsCollector + connectorUsageCollector ); if (!api[subAction]) { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.test.ts index 11bbcbd4e30d8..5c04d60bed9c1 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.test.ts @@ -14,7 +14,7 @@ import { request, createAxiosResponse } from '@kbn/actions-plugin/server/lib/axi import { createExternalService } from './service'; import { mappings } from './mocks'; import { ExternalService } from './types'; -import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; const logger = loggingSystemMock.create().get() as jest.Mocked; @@ -57,10 +57,10 @@ describe('Swimlane Service', () => { }; const url = config.apiUrl.slice(0, -1); - let connectorMetricsCollector: ConnectorMetricsCollector; + let connectorUsageCollector: ConnectorUsageCollector; beforeAll(() => { - connectorMetricsCollector = new ConnectorMetricsCollector({ + connectorUsageCollector = new ConnectorUsageCollector({ logger, connectorId: 'test-connector-id', }); @@ -73,7 +73,7 @@ describe('Swimlane Service', () => { }, logger, configurationUtilities, - connectorMetricsCollector + connectorUsageCollector ); }); beforeEach(() => { @@ -95,7 +95,7 @@ describe('Swimlane Service', () => { }, logger, configurationUtilities, - connectorMetricsCollector + connectorUsageCollector ) ).toThrow(); }); @@ -113,7 +113,7 @@ describe('Swimlane Service', () => { }, logger, configurationUtilities, - connectorMetricsCollector + connectorUsageCollector ) ).toThrow(); }); @@ -132,7 +132,7 @@ describe('Swimlane Service', () => { }, logger, configurationUtilities, - connectorMetricsCollector + connectorUsageCollector ) ).toThrow(); }); @@ -149,7 +149,7 @@ describe('Swimlane Service', () => { }, logger, configurationUtilities, - connectorMetricsCollector + connectorUsageCollector ); }).toThrow(); }); @@ -202,7 +202,7 @@ describe('Swimlane Service', () => { url: `${url}/api/app/${config.appId}/record`, method: 'post', configurationUtilities, - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -286,7 +286,7 @@ describe('Swimlane Service', () => { url: `${url}/api/app/${config.appId}/record/${incidentId}`, method: 'patch', configurationUtilities, - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -366,7 +366,7 @@ describe('Swimlane Service', () => { url: `${url}/api/app/${config.appId}/record/${incidentId}/${mappings.commentsConfig.id}/comment`, method: 'post', configurationUtilities, - connectorMetricsCollector, + connectorUsageCollector, }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.ts b/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.ts index bd0f4367e1313..4abe7f08de5c5 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.ts @@ -14,7 +14,7 @@ import { throwIfResponseIsNotValid, } from '@kbn/actions-plugin/server/lib/axios_utils'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; -import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { getBodyForEventAction } from './helpers'; import { CreateCommentParams, @@ -44,7 +44,7 @@ export const createExternalService = ( { config, secrets }: ExternalServiceCredentials, logger: Logger, configurationUtilities: ActionsConfigurationUtilities, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): ExternalService => { const { apiUrl: url, appId, mappings } = config as SwimlanePublicConfigurationType; const { apiToken } = secrets as SwimlaneSecretConfigurationType; @@ -94,7 +94,7 @@ export const createExternalService = ( logger, method: 'post', url: getPostRecordUrl(appId), - connectorMetricsCollector, + connectorUsageCollector, }); throwIfResponseIsNotValid({ @@ -135,7 +135,7 @@ export const createExternalService = ( logger, method: 'patch', url: getPostRecordIdUrl(appId, params.incidentId), - connectorMetricsCollector, + connectorUsageCollector, }); throwIfResponseIsNotValid({ @@ -185,7 +185,7 @@ export const createExternalService = ( logger, method: 'post', url: getPostCommentUrl(appId, incidentId, fieldId), - connectorMetricsCollector, + connectorUsageCollector, }); /** diff --git a/x-pack/plugins/stack_connectors/server/connector_types/teams/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/teams/index.test.ts index f31ae33af68bf..6b1b0cf105d9d 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/teams/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/teams/index.test.ts @@ -6,7 +6,7 @@ */ import { Logger } from '@kbn/core/server'; -import { ConnectorMetricsCollector, Services } from '@kbn/actions-plugin/server/types'; +import { ConnectorUsageCollector, Services } from '@kbn/actions-plugin/server/types'; import { validateParams, validateSecrets } from '@kbn/actions-plugin/server/lib'; import axios from 'axios'; import { getConnectorType, TeamsConnectorType, ConnectorTypeId } from '.'; @@ -34,12 +34,12 @@ const mockedLogger: jest.Mocked = loggerMock.create(); let connectorType: TeamsConnectorType; let configurationUtilities: jest.Mocked; -let connectorMetricsCollector: ConnectorMetricsCollector; +let connectorUsageCollector: ConnectorUsageCollector; beforeEach(() => { configurationUtilities = actionsConfigMock.create(); connectorType = getConnectorType(); - connectorMetricsCollector = new ConnectorMetricsCollector({ + connectorUsageCollector = new ConnectorUsageCollector({ logger: mockedLogger, connectorId: 'test-connector-id', }); @@ -172,13 +172,13 @@ describe('execute()', () => { params: { message: 'this invocation should succeed' }, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }); delete requestMock.mock.calls[0][0].configurationUtilities; expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "axios": undefined, - "connectorMetricsCollector": ConnectorMetricsCollector { + "connectorUsageCollector": ConnectorUsageCollector { "connectorId": "test-connector-id", "logger": Object { "context": Array [], @@ -204,7 +204,7 @@ describe('execute()', () => { "trace": [MockFunction], "warn": [MockFunction], }, - "metrics": Object { + "usage": Object { "requestBodyBytes": 0, }, }, @@ -259,13 +259,13 @@ describe('execute()', () => { params: { message: 'this invocation should succeed' }, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }); delete requestMock.mock.calls[0][0].configurationUtilities; expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "axios": undefined, - "connectorMetricsCollector": ConnectorMetricsCollector { + "connectorUsageCollector": ConnectorUsageCollector { "connectorId": "test-connector-id", "logger": Object { "context": Array [], @@ -291,7 +291,7 @@ describe('execute()', () => { "trace": [MockFunction], "warn": [MockFunction], }, - "metrics": Object { + "usage": Object { "requestBodyBytes": 0, }, }, diff --git a/x-pack/plugins/stack_connectors/server/connector_types/teams/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/teams/index.ts index a4a89501773d1..9ab0fe4d428d7 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/teams/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/teams/index.ts @@ -119,7 +119,7 @@ function validateConnectorTypeConfig( async function teamsExecutor( execOptions: TeamsConnectorTypeExecutorOptions ): Promise> { - const { actionId, secrets, params, configurationUtilities, logger, connectorMetricsCollector } = + const { actionId, secrets, params, configurationUtilities, logger, connectorUsageCollector } = execOptions; const { webhookUrl } = secrets; const { message } = params; @@ -135,7 +135,7 @@ async function teamsExecutor( logger, data, configurationUtilities, - connectorMetricsCollector, + connectorUsageCollector, }) ); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/thehive/thehive.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/thehive/thehive.test.ts index 6015588c2bb4e..5972d5da570ef 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/thehive/thehive.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/thehive/thehive.test.ts @@ -18,7 +18,7 @@ import { PushToServiceIncidentSchema, } from '../../../common/thehive/schema'; import type { ExecutorSubActionCreateAlertParams, Incident } from '../../../common/thehive/types'; -import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; const mockTime = new Date('2024-04-03T09:10:30.000'); @@ -39,7 +39,7 @@ describe('TheHiveConnector', () => { let mockRequest: jest.Mock; let mockError: jest.Mock; - let connectorMetricsCollector: ConnectorMetricsCollector; + let connectorUsageCollector: ConnectorUsageCollector; beforeAll(() => { jest.useFakeTimers(); @@ -55,7 +55,7 @@ describe('TheHiveConnector', () => { throw new Error('API Error'); }); jest.clearAllMocks(); - connectorMetricsCollector = new ConnectorMetricsCollector({ + connectorUsageCollector = new ConnectorUsageCollector({ logger, connectorId: 'test-connector-id', }); @@ -132,7 +132,7 @@ describe('TheHiveConnector', () => { }; it('TheHive API call is successful with correct parameters', async () => { - const response = await connector.createIncident(incident, connectorMetricsCollector); + const response = await connector.createIncident(incident, connectorUsageCollector); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( { @@ -145,7 +145,7 @@ describe('TheHiveConnector', () => { 'X-Organisation': null, }, }, - connectorMetricsCollector + connectorUsageCollector ); expect(response).toEqual({ id: '~172064', @@ -159,7 +159,7 @@ describe('TheHiveConnector', () => { // @ts-ignore connector.request = mockError; - await expect(connector.createIncident(incident, connectorMetricsCollector)).rejects.toThrow( + await expect(connector.createIncident(incident, connectorUsageCollector)).rejects.toThrow( 'API Error' ); }); @@ -188,7 +188,7 @@ describe('TheHiveConnector', () => { it('TheHive API call is successful with correct parameters', async () => { const response = await connector.updateIncident( { incidentId: '~172064', incident }, - connectorMetricsCollector + connectorUsageCollector ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( @@ -202,7 +202,7 @@ describe('TheHiveConnector', () => { 'X-Organisation': null, }, }, - connectorMetricsCollector + connectorUsageCollector ); expect(response).toEqual({ id: '~172064', @@ -217,7 +217,7 @@ describe('TheHiveConnector', () => { connector.request = mockError; await expect( - connector.updateIncident({ incidentId: '~172064', incident }, connectorMetricsCollector) + connector.updateIncident({ incidentId: '~172064', incident }, connectorUsageCollector) ).rejects.toThrow('API Error'); }); }); @@ -248,7 +248,7 @@ describe('TheHiveConnector', () => { incidentId: '~172064', comment: 'test comment', }, - connectorMetricsCollector + connectorUsageCollector ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( @@ -262,7 +262,7 @@ describe('TheHiveConnector', () => { 'X-Organisation': null, }, }, - connectorMetricsCollector + connectorUsageCollector ); }); @@ -273,7 +273,7 @@ describe('TheHiveConnector', () => { await expect( connector.addComment( { incidentId: '~172064', comment: 'test comment' }, - connectorMetricsCollector + connectorUsageCollector ) ).rejects.toThrow('API Error'); }); @@ -342,7 +342,7 @@ describe('TheHiveConnector', () => { }); it('TheHive API call is successful with correct parameters', async () => { - const response = await connector.getIncident({ id: '~172064' }, connectorMetricsCollector); + const response = await connector.getIncident({ id: '~172064' }, connectorUsageCollector); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( { @@ -353,7 +353,7 @@ describe('TheHiveConnector', () => { 'X-Organisation': null, }, }, - connectorMetricsCollector + connectorUsageCollector ); expect(response).toEqual(mockResponse.data); }); @@ -363,7 +363,7 @@ describe('TheHiveConnector', () => { connector.request = mockError; await expect( - connector.getIncident({ id: '~172064' }, connectorMetricsCollector) + connector.getIncident({ id: '~172064' }, connectorUsageCollector) ).rejects.toThrow('API Error'); }); }); @@ -418,7 +418,7 @@ describe('TheHiveConnector', () => { }; it('TheHive API call is successful with correct parameters', async () => { - await connector.createAlert(alert, connectorMetricsCollector); + await connector.createAlert(alert, connectorUsageCollector); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith( { @@ -431,7 +431,7 @@ describe('TheHiveConnector', () => { 'X-Organisation': null, }, }, - connectorMetricsCollector + connectorUsageCollector ); }); @@ -439,7 +439,7 @@ describe('TheHiveConnector', () => { // @ts-ignore connector.request = mockError; - await expect(connector.createAlert(alert, connectorMetricsCollector)).rejects.toThrow( + await expect(connector.createAlert(alert, connectorUsageCollector)).rejects.toThrow( 'API Error' ); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/thehive/thehive.ts b/x-pack/plugins/stack_connectors/server/connector_types/thehive/thehive.ts index 887ba24d16ca4..623a9b8ee73d7 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/thehive/thehive.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/thehive/thehive.ts @@ -8,7 +8,7 @@ import { ServiceParams, CaseConnector } from '@kbn/actions-plugin/server'; import type { AxiosError } from 'axios'; import { Type } from '@kbn/config-schema'; -import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { SUB_ACTION } from '../../../common/thehive/constants'; import { TheHiveIncidentResponseSchema, @@ -71,7 +71,7 @@ export class TheHiveConnector extends CaseConnector< public async createIncident( incident: Incident, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { const res = await this.request( { @@ -81,7 +81,7 @@ export class TheHiveConnector extends CaseConnector< headers: this.getAuthHeaders(), responseSchema: TheHiveIncidentResponseSchema, }, - connectorMetricsCollector + connectorUsageCollector ); return { @@ -94,7 +94,7 @@ export class TheHiveConnector extends CaseConnector< public async addComment( { incidentId, comment }: { incidentId: string; comment: string }, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ) { await this.request( { @@ -104,7 +104,7 @@ export class TheHiveConnector extends CaseConnector< headers: this.getAuthHeaders(), responseSchema: TheHiveAddCommentResponseSchema, }, - connectorMetricsCollector + connectorUsageCollector ); } @@ -116,7 +116,7 @@ export class TheHiveConnector extends CaseConnector< incidentId: string; incident: Incident; }, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { await this.request( { @@ -126,7 +126,7 @@ export class TheHiveConnector extends CaseConnector< headers: this.getAuthHeaders(), responseSchema: TheHiveUpdateIncidentResponseSchema, }, - connectorMetricsCollector + connectorUsageCollector ); return { @@ -139,7 +139,7 @@ export class TheHiveConnector extends CaseConnector< public async getIncident( { id }: { id: string }, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { const res = await this.request( { @@ -147,7 +147,7 @@ export class TheHiveConnector extends CaseConnector< headers: this.getAuthHeaders(), responseSchema: TheHiveIncidentResponseSchema, }, - connectorMetricsCollector + connectorUsageCollector ); return res.data; @@ -155,7 +155,7 @@ export class TheHiveConnector extends CaseConnector< public async createAlert( alert: ExecutorSubActionCreateAlertParams, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ) { await this.request( { @@ -165,7 +165,7 @@ export class TheHiveConnector extends CaseConnector< headers: this.getAuthHeaders(), responseSchema: TheHiveCreateAlertResponseSchema, }, - connectorMetricsCollector + connectorUsageCollector ); } } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.test.ts index b24564a3f3419..6bbaad9b86a0c 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.test.ts @@ -12,7 +12,7 @@ import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; import { TinesConnector } from './tines'; import { request } from '@kbn/actions-plugin/server/lib/axios_utils'; import { API_MAX_RESULTS, TINES_CONNECTOR_ID } from '../../../common/tines/constants'; -import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; jest.mock('axios'); (axios as jest.Mocked).create.mockImplementation( @@ -79,7 +79,7 @@ const storiesGetRequestExpected = { 'Content-Type': 'application/json', }, params: { per_page: API_MAX_RESULTS }, - connectorMetricsCollector: expect.any(ConnectorMetricsCollector), + connectorUsageCollector: expect.any(ConnectorUsageCollector), }; const agentsGetRequestExpected = { @@ -93,10 +93,10 @@ const agentsGetRequestExpected = { 'Content-Type': 'application/json', }, params: { story_id: story.id, per_page: API_MAX_RESULTS }, - connectorMetricsCollector: expect.any(ConnectorMetricsCollector), + connectorUsageCollector: expect.any(ConnectorUsageCollector), }; -let connectorMetricsCollector: ConnectorMetricsCollector; +let connectorUsageCollector: ConnectorUsageCollector; describe('TinesConnector', () => { const logger = loggingSystemMock.createLogger(); @@ -111,7 +111,7 @@ describe('TinesConnector', () => { beforeEach(() => { jest.clearAllMocks(); - connectorMetricsCollector = new ConnectorMetricsCollector({ + connectorUsageCollector = new ConnectorUsageCollector({ logger, connectorId: 'test-connector-id', }); @@ -123,13 +123,13 @@ describe('TinesConnector', () => { }); it('should request Tines stories', async () => { - await connector.getStories(undefined, connectorMetricsCollector); + await connector.getStories(undefined, connectorUsageCollector); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith(storiesGetRequestExpected); }); it('should return the Tines stories reduced array', async () => { - const { stories } = await connector.getStories(undefined, connectorMetricsCollector); + const { stories } = await connector.getStories(undefined, connectorUsageCollector); expect(stories).toEqual([storyResult]); }); @@ -137,7 +137,7 @@ describe('TinesConnector', () => { mockRequest.mockReturnValueOnce({ data: { stories: [story], meta: { pages: 1 } }, }); - const response = await connector.getStories(undefined, connectorMetricsCollector); + const response = await connector.getStories(undefined, connectorUsageCollector); expect(response.incompleteResponse).toEqual(false); }); @@ -145,7 +145,7 @@ describe('TinesConnector', () => { mockRequest.mockReturnValueOnce({ data: { stories: [story], meta: { pages: 2 } }, }); - const response = await connector.getStories(undefined, connectorMetricsCollector); + const response = await connector.getStories(undefined, connectorUsageCollector); expect(response.incompleteResponse).toEqual(true); }); }); @@ -156,7 +156,7 @@ describe('TinesConnector', () => { }); it('should request Tines webhook actions', async () => { - await connector.getWebhooks({ storyId: story.id }, connectorMetricsCollector); + await connector.getWebhooks({ storyId: story.id }, connectorUsageCollector); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith(agentsGetRequestExpected); @@ -165,7 +165,7 @@ describe('TinesConnector', () => { it('should return the Tines webhooks reduced array', async () => { const { webhooks } = await connector.getWebhooks( { storyId: story.id }, - connectorMetricsCollector + connectorUsageCollector ); expect(webhooks).toEqual([webhookResult]); }); @@ -174,10 +174,7 @@ describe('TinesConnector', () => { mockRequest.mockReturnValueOnce({ data: { agents: [webhookAgent], meta: { pages: 1 } }, }); - const response = await connector.getWebhooks( - { storyId: story.id }, - connectorMetricsCollector - ); + const response = await connector.getWebhooks({ storyId: story.id }, connectorUsageCollector); expect(response.incompleteResponse).toEqual(false); }); @@ -185,10 +182,7 @@ describe('TinesConnector', () => { mockRequest.mockReturnValueOnce({ data: { agents: [webhookAgent], meta: { pages: 2 } }, }); - const response = await connector.getWebhooks( - { storyId: story.id }, - connectorMetricsCollector - ); + const response = await connector.getWebhooks({ storyId: story.id }, connectorUsageCollector); expect(response.incompleteResponse).toEqual(true); }); }); @@ -204,7 +198,7 @@ describe('TinesConnector', () => { webhook: webhookResult, body: '[]', }, - connectorMetricsCollector + connectorUsageCollector ); expect(mockRequest).toBeCalledTimes(1); @@ -216,7 +210,7 @@ describe('TinesConnector', () => { headers: { 'Content-Type': 'application/json', }, - connectorMetricsCollector, + connectorUsageCollector, }); }); @@ -226,7 +220,7 @@ describe('TinesConnector', () => { webhookUrl, body: '[]', }, - connectorMetricsCollector + connectorUsageCollector ); expect(mockRequest).toBeCalledTimes(1); @@ -238,7 +232,7 @@ describe('TinesConnector', () => { headers: { 'Content-Type': 'application/json', }, - connectorMetricsCollector, + connectorUsageCollector, }); }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.ts b/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.ts index 0a1f3964731d6..ed98ec382af86 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.ts @@ -6,9 +6,9 @@ */ import { ServiceParams, SubActionConnector } from '@kbn/actions-plugin/server'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import type { AxiosError } from 'axios'; import { SubActionRequestParams } from '@kbn/actions-plugin/server/sub_action_framework/types'; -import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; import { TinesStoriesActionParamsSchema, TinesWebhooksActionParamsSchema, @@ -110,14 +110,14 @@ export class TinesConnector extends SubActionConnector( req: SubActionRequestParams, reducer: (response: R) => T, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { const response = await this.request( { ...req, params: { ...req.params, per_page: API_MAX_RESULTS }, }, - connectorMetricsCollector + connectorUsageCollector ); return { ...reducer(response.data), @@ -137,7 +137,7 @@ export class TinesConnector extends SubActionConnector { return this.tinesApiRequest( { @@ -146,13 +146,13 @@ export class TinesConnector extends SubActionConnector { return this.tinesApiRequest( { @@ -162,13 +162,13 @@ export class TinesConnector extends SubActionConnector { if (!webhook && !webhookUrl) { throw Error('Invalid subActionsParams: [webhook] or [webhookUrl] expected but got none'); @@ -180,7 +180,7 @@ export class TinesConnector extends SubActionConnector, - "connectorMetricsCollector": Object { + "connectorUsageCollector": Object { "connectorId": "test-connector-id", "logger": Object { "context": Array [], @@ -29,7 +29,7 @@ Object { "trace": [MockFunction], "warn": [MockFunction], }, - "metrics": Object { + "usage": Object { "requestBodyBytes": 0, }, }, diff --git a/x-pack/plugins/stack_connectors/server/connector_types/torq/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/torq/index.test.ts index 0841502f1f195..39bbdd44a918d 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/torq/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/torq/index.test.ts @@ -11,12 +11,8 @@ import axios from 'axios'; import { ActionTypeConfigType, getActionType, TorqActionType } from '.'; import * as utils from '@kbn/actions-plugin/server/lib/axios_utils'; -import { - ConnectorMetricsCollector, - validateConfig, - validateParams, - validateSecrets, -} from '@kbn/actions-plugin/server/lib'; +import { validateConfig, validateParams, validateSecrets } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { actionsMock } from '@kbn/actions-plugin/server/mocks'; import { Services } from '@kbn/actions-plugin/server/types'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; @@ -42,12 +38,12 @@ const services: Services = actionsMock.createServices(); let actionType: TorqActionType; const mockedLogger: jest.Mocked = loggerMock.create(); let configurationUtilities: jest.Mocked; -let connectorMetricsCollector: ConnectorMetricsCollector; +let connectorUsageCollector: ConnectorUsageCollector; beforeAll(() => { actionType = getActionType(); configurationUtilities = actionsConfigMock.create(); - connectorMetricsCollector = new ConnectorMetricsCollector({ + connectorUsageCollector = new ConnectorUsageCollector({ logger: mockedLogger, connectorId: 'test-connector-id', }); @@ -181,14 +177,14 @@ describe('execute Torq action', () => { params: { body: '{"msg": "some data"}' }, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }); delete requestMock.mock.calls[0][0].configurationUtilities; expect(requestMock.mock.calls[0][0]).toMatchSnapshot({ axios: expect.any(Function), - connectorMetricsCollector: { - metrics: { + connectorUsageCollector: { + usage: { requestBodyBytes: 0, }, }, diff --git a/x-pack/plugins/stack_connectors/server/connector_types/torq/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/torq/index.ts index af03b10667dea..b60237dd7991e 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/torq/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/torq/index.ts @@ -146,7 +146,7 @@ export async function executor( const { webhookIntegrationUrl } = execOptions.config; const { body: data } = execOptions.params; const configurationUtilities = execOptions.configurationUtilities; - const connectorMetricsCollector = execOptions.connectorMetricsCollector; + const connectorUsageCollector = execOptions.connectorUsageCollector; const secrets: ActionTypeSecretsType = execOptions.secrets; const token = secrets.token; @@ -172,7 +172,7 @@ export async function executor( configurationUtilities, logger: execOptions.logger, validateStatus: (status: number) => status >= 200 && status < 300, - connectorMetricsCollector, + connectorUsageCollector, }) ); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/webhook/__snapshots__/index.test.ts.snap b/x-pack/plugins/stack_connectors/server/connector_types/webhook/__snapshots__/index.test.ts.snap index 17304a2e94cea..f52e34d90dbf0 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/webhook/__snapshots__/index.test.ts.snap +++ b/x-pack/plugins/stack_connectors/server/connector_types/webhook/__snapshots__/index.test.ts.snap @@ -3,7 +3,7 @@ exports[`execute() execute with username/password sends request with basic auth 1`] = ` Object { "axios": undefined, - "connectorMetricsCollector": Object { + "connectorUsageCollector": Object { "connectorId": "test-connector-id", "logger": Object { "context": Array [], @@ -29,7 +29,7 @@ Object { "trace": [MockFunction], "warn": [MockFunction], }, - "metrics": Object { + "usage": Object { "requestBodyBytes": 0, }, }, diff --git a/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.test.ts index 8e10ba515ad99..724daa852019f 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { ConnectorMetricsCollector, Services } from '@kbn/actions-plugin/server/types'; +import { ConnectorUsageCollector, Services } from '@kbn/actions-plugin/server/types'; import { validateConfig, validateParams, validateSecrets } from '@kbn/actions-plugin/server/lib'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; @@ -41,12 +41,12 @@ const mockedLogger: jest.Mocked = loggerMock.create(); let connectorType: WebhookConnectorType; let configurationUtilities: jest.Mocked; -let connectorMetricsCollector: ConnectorMetricsCollector; +let connectorUsageCollector: ConnectorUsageCollector; beforeEach(() => { configurationUtilities = actionsConfigMock.create(); connectorType = getConnectorType(); - connectorMetricsCollector = new ConnectorMetricsCollector({ + connectorUsageCollector = new ConnectorUsageCollector({ logger: mockedLogger, connectorId: 'test-connector-id', }); @@ -344,14 +344,14 @@ describe('execute()', () => { params: { body: 'some data' }, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }); delete requestMock.mock.calls[0][0].configurationUtilities; expect(requestMock.mock.calls[0][0]).toMatchSnapshot({ axios: undefined, - connectorMetricsCollector: { - metrics: { + connectorUsageCollector: { + usage: { requestBodyBytes: 0, }, }, @@ -386,7 +386,7 @@ describe('execute()', () => { params: { body: 'some data' }, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }); delete requestMock.mock.calls[0][0].configurationUtilities; @@ -394,7 +394,7 @@ describe('execute()', () => { expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "axios": undefined, - "connectorMetricsCollector": ConnectorMetricsCollector { + "connectorUsageCollector": ConnectorUsageCollector { "connectorId": "test-connector-id", "logger": Object { "context": Array [], @@ -420,7 +420,7 @@ describe('execute()', () => { "trace": [MockFunction], "warn": [MockFunction], }, - "metrics": Object { + "usage": Object { "requestBodyBytes": 0, }, }, @@ -605,7 +605,7 @@ describe('execute()', () => { params: { body: 'some data' }, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }); expect(mockedLogger.error).toBeCalledWith( 'error on some-id webhook event: maxContentLength size of 1000000 exceeded' @@ -636,14 +636,14 @@ describe('execute()', () => { params: { body: 'some data' }, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }); delete requestMock.mock.calls[0][0].configurationUtilities; expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "axios": undefined, - "connectorMetricsCollector": ConnectorMetricsCollector { + "connectorUsageCollector": ConnectorUsageCollector { "connectorId": "test-connector-id", "logger": Object { "context": Array [], @@ -669,7 +669,7 @@ describe('execute()', () => { "trace": [MockFunction], "warn": [MockFunction], }, - "metrics": Object { + "usage": Object { "requestBodyBytes": 0, }, }, diff --git a/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.ts index a3cb8172b2237..f7c7fd4f6d61e 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.ts @@ -128,7 +128,7 @@ function validateConnectorTypeConfig( export async function executor( execOptions: WebhookConnectorTypeExecutorOptions ): Promise> { - const { actionId, config, params, configurationUtilities, logger, connectorMetricsCollector } = + const { actionId, config, params, configurationUtilities, logger, connectorUsageCollector } = execOptions; const { method, url, headers = {}, hasAuth, authType, ca, verificationMode } = config; const { body: data } = params; @@ -160,7 +160,7 @@ export async function executor( data, configurationUtilities, sslOverrides, - connectorMetricsCollector, + connectorUsageCollector, }) ); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.test.ts index e6ae05810a1f2..b357faffc8a0b 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.test.ts @@ -14,7 +14,7 @@ import { XmattersConnectorType, } from '.'; import { actionsMock } from '@kbn/actions-plugin/server/mocks'; -import { ConnectorMetricsCollector, Services } from '@kbn/actions-plugin/server/types'; +import { ConnectorUsageCollector, Services } from '@kbn/actions-plugin/server/types'; import { validateConfig, validateConnector, @@ -45,12 +45,12 @@ const mockedLogger: jest.Mocked = loggerMock.create(); let connectorType: XmattersConnectorType; let configurationUtilities: jest.Mocked; -let connectorMetricsCollector: ConnectorMetricsCollector; +let connectorUsageCollector: ConnectorUsageCollector; beforeEach(() => { configurationUtilities = actionsConfigMock.create(); connectorType = getConnectorType(); - connectorMetricsCollector = new ConnectorMetricsCollector({ + connectorUsageCollector = new ConnectorUsageCollector({ logger: mockedLogger, connectorId: 'test-connector-id', }); @@ -428,7 +428,7 @@ describe('execute()', () => { }, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }); const { method, url, headers, data } = requestMock.mock.calls[0][0]; @@ -478,7 +478,7 @@ describe('execute()', () => { }, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }); expect(mockedLogger.warn).toBeCalledWith( 'Error thrown triggering xMatters workflow: maxContentLength size of 1000000 exceeded' @@ -511,7 +511,7 @@ describe('execute()', () => { }, configurationUtilities, logger: mockedLogger, - connectorMetricsCollector, + connectorUsageCollector, }); const { method, url, headers, data } = requestMock.mock.calls[0][0]; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.ts index 034a884573f9e..ad189bda9defb 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.ts @@ -247,7 +247,7 @@ function validateConnectorTypeSecrets( export async function executor( execOptions: XmattersConnectorTypeExecutorOptions ): Promise> { - const { actionId, configurationUtilities, config, params, logger, connectorMetricsCollector } = + const { actionId, configurationUtilities, config, params, logger, connectorUsageCollector } = execOptions; const { configUrl, usesBasic } = config; const data = getPayloadForRequest(params); @@ -268,7 +268,7 @@ export async function executor( { url, data, basicAuth }, logger, configurationUtilities, - connectorMetricsCollector + connectorUsageCollector ); } catch (err) { const message = i18n.translate('xpack.stackConnectors.xmatters.postingErrorMessage', { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/xmatters/post_xmatters.ts b/x-pack/plugins/stack_connectors/server/connector_types/xmatters/post_xmatters.ts index d0dbba93e2fde..215d1942c6e8a 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/xmatters/post_xmatters.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/xmatters/post_xmatters.ts @@ -9,10 +9,8 @@ import axios, { AxiosResponse } from 'axios'; import { Logger } from '@kbn/core/server'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; import { request } from '@kbn/actions-plugin/server/lib/axios_utils'; -import { - combineHeadersWithBasicAuthHeader, - ConnectorMetricsCollector, -} from '@kbn/actions-plugin/server/lib'; +import { combineHeadersWithBasicAuthHeader } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; interface PostXmattersOptions { url: string; @@ -38,7 +36,7 @@ export async function postXmatters( options: PostXmattersOptions, logger: Logger, configurationUtilities: ActionsConfigurationUtilities, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ): Promise { const { url, data, basicAuth } = options; const axiosInstance = axios.create(); @@ -54,6 +52,6 @@ export async function postXmatters( data, configurationUtilities, validateStatus: () => true, - connectorMetricsCollector, + connectorUsageCollector, }); } diff --git a/x-pack/test/alerting_api_integration/common/plugins/alerts/server/sub_action_connector.ts b/x-pack/test/alerting_api_integration/common/plugins/alerts/server/sub_action_connector.ts index 1dd361ebb814b..302bbf2b06668 100644 --- a/x-pack/test/alerting_api_integration/common/plugins/alerts/server/sub_action_connector.ts +++ b/x-pack/test/alerting_api_integration/common/plugins/alerts/server/sub_action_connector.ts @@ -11,7 +11,7 @@ import type { ServiceParams } from '@kbn/actions-plugin/server'; import { PluginSetupContract as ActionsPluginSetup } from '@kbn/actions-plugin/server/plugin'; import { schema, TypeOf } from '@kbn/config-schema'; import { SubActionConnectorType } from '@kbn/actions-plugin/server/sub_action_framework/types'; -import { ConnectorMetricsCollector } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; const TestConfigSchema = schema.object({ url: schema.string() }); const TestSecretsSchema = schema.object({ @@ -72,9 +72,9 @@ export const getTestSubActionConnector = ( public async subActionWithParams( { id }: { id: string }, - connectorMetricsCollector: ConnectorMetricsCollector + connectorUsageCollector: ConnectorUsageCollector ) { - connectorMetricsCollector.addRequestBodyBytes(undefined, { id }); + connectorUsageCollector.addRequestBodyBytes(undefined, { id }); return { id }; } diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/bedrock.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/bedrock.ts index f613d56eab507..d3994050bcbc5 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/bedrock.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/bedrock.ts @@ -361,7 +361,7 @@ export default function bedrockTest({ getService }: FtrProviderContext) { }); const executeEvent = events[1]; - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(145); + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(145); }); it('should overwrite the model when a model argument is provided', async () => { @@ -408,7 +408,7 @@ export default function bedrockTest({ getService }: FtrProviderContext) { }); const executeEvent = events[3]; - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(145); + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(145); }); it('should invoke AI with assistant AI body argument formatted to bedrock expectations', async () => { @@ -474,7 +474,7 @@ export default function bedrockTest({ getService }: FtrProviderContext) { }); const executeEvent = events[5]; - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(256); + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(256); }); describe('Token tracking dashboard', () => { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/cases_webhook.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/cases_webhook.ts index 71198328160b5..1ef7b170a4f0d 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/cases_webhook.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/cases_webhook.ts @@ -416,7 +416,7 @@ export default function casesWebhookTest({ getService }: FtrProviderContext) { }); const executeEvent = events[1]; - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(125); + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(125); expect(body).to.eql({ status: 'ok', diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/d3security.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/d3security.ts index 0c47f176efc42..72cea764d0165 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/d3security.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/d3security.ts @@ -267,7 +267,7 @@ export default function d3SecurityTest({ getService }: FtrProviderContext) { }); const executeEvent = events[1]; - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(99); + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(99); expect(body).to.eql({ status: 'ok', diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/email.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/email.ts index 21d0f8f5ee0f3..6ed2c89e094f9 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/email.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/email.ts @@ -150,7 +150,7 @@ export default function emailTest({ getService }: FtrProviderContext) { }); const executeEvent = events[1]; - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(350); + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(350); }); }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/es_index.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/es_index.ts index 0ffe702a50143..8d867aea49685 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/es_index.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/es_index.ts @@ -233,7 +233,7 @@ export default function indexTest({ getService }: FtrProviderContext) { }); const executeEvent = events[1]; - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(0); + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(0); }); it('should execute successly with refresh false', async () => { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/jira.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/jira.ts index f355e6793fecf..2268e379f441a 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/jira.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/jira.ts @@ -536,7 +536,7 @@ export default function jiraTest({ getService }: FtrProviderContext) { }); const executeEvent = events[1]; - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(124); + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(124); }); it('should handle creating an incident with other fields', async () => { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/openai.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/openai.ts index e2fdf58704da4..652859003e01c 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/openai.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/openai.ts @@ -333,7 +333,7 @@ export default function genAiTest({ getService }: FtrProviderContext) { }); const executeEvent = events[1]; - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(78); + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(78); }); describe('Token tracking dashboard', () => { const dashboardId = 'specific-dashboard-id-default'; diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/opsgenie.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/opsgenie.ts index 4625364e9bb7a..75913a4182bbd 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/opsgenie.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/opsgenie.ts @@ -554,7 +554,7 @@ export default function opsgenieTest({ getService }: FtrProviderContext) { }); const executeEvent = events[1]; - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(21); + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(21); }); it('should preserve the alias when it is 512 characters when creating an alert', async () => { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/pagerduty.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/pagerduty.ts index 940ef8f89467f..2871066b6456a 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/pagerduty.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/pagerduty.ts @@ -192,7 +192,7 @@ export default function pagerdutyTest({ getService }: FtrProviderContext) { }); const executeEvent = events[1]; - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(142); + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(142); }); it('should execute successfully with links and customDetails', async () => { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/resilient.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/resilient.ts index fd69794863164..6dfb420463e9f 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/resilient.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/resilient.ts @@ -428,7 +428,7 @@ export default function resilientTest({ getService }: FtrProviderContext) { }); const executeEvent = events[1]; - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(167); + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(167); }); }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/server_log.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/server_log.ts index 0fd72a2b8ec7a..a3fedba5d1f69 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/server_log.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/server_log.ts @@ -88,7 +88,7 @@ export default function serverLogTest({ getService }: FtrProviderContext) { }); const executeEvent = events[1]; - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(0); + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(0); }); }); } diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_itom.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_itom.ts index c150003339f0d..0f1748db4f5ef 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_itom.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_itom.ts @@ -519,7 +519,7 @@ export default function serviceNowITOMTest({ getService }: FtrProviderContext) { }); const executeEvent = events[1]; - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(317); + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(317); }); }); @@ -584,7 +584,7 @@ export default function serviceNowITOMTest({ getService }: FtrProviderContext) { }); const executeEvent = events[3]; - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(0); + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(0); }); }); }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_itsm.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_itsm.ts index ee470a85101ab..bc0f48f15caf5 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_itsm.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_itsm.ts @@ -727,7 +727,7 @@ export default function serviceNowITSMTest({ getService }: FtrProviderContext) { }); const executeEvent = events[1]; - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(261); + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(261); }); }); @@ -791,7 +791,7 @@ export default function serviceNowITSMTest({ getService }: FtrProviderContext) { }); const executeEvent = events[1]; - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(239); + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(239); }); }); @@ -856,7 +856,7 @@ export default function serviceNowITSMTest({ getService }: FtrProviderContext) { }); const executeEvent = events[3]; - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(0); + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(0); }); }); @@ -898,7 +898,7 @@ export default function serviceNowITSMTest({ getService }: FtrProviderContext) { }); const executeEvent = events[5]; - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(0); + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(0); }); }); }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_sir.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_sir.ts index f5246766b744c..717a44a406712 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_sir.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_sir.ts @@ -740,7 +740,7 @@ export default function serviceNowSIRTest({ getService }: FtrProviderContext) { }); const executeEvent = events[1]; - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(645); + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(645); }); }); @@ -803,7 +803,7 @@ export default function serviceNowSIRTest({ getService }: FtrProviderContext) { }); const executeEvent = events[1]; - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(429); + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(429); }); }); @@ -868,7 +868,7 @@ export default function serviceNowSIRTest({ getService }: FtrProviderContext) { }); const executeEvent = events[3]; - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(0); + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(0); }); }); }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/slack_webhook.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/slack_webhook.ts index ff574fd0aea31..457f9edbed2fc 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/slack_webhook.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/slack_webhook.ts @@ -195,7 +195,7 @@ export default function slackTest({ getService }: FtrProviderContext) { }); const executeEvent = events[1]; - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(18); + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(18); }); it('should handle an empty message error', async () => { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/swimlane.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/swimlane.ts index 75cfc23bca764..4d91fdddf80dd 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/swimlane.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/swimlane.ts @@ -478,7 +478,7 @@ export default function swimlaneTest({ getService }: FtrProviderContext) { }); const executeEvent = events[1]; - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(175); + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(175); }); it('should handle updating an incident', async () => { @@ -526,7 +526,7 @@ export default function swimlaneTest({ getService }: FtrProviderContext) { }); const executeEvent = events[3]; - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(193); + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(193); }); }); }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/tines.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/tines.ts index 7eeb2712cc81d..04971990f879e 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/tines.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/tines.ts @@ -411,7 +411,7 @@ export default function tinesTest({ getService }: FtrProviderContext) { }); const executeEvent = events[1]; - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(2); + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(2); }); it('should get webhooks', async () => { @@ -457,7 +457,7 @@ export default function tinesTest({ getService }: FtrProviderContext) { }); const executeEvent = events[3]; - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(2); + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(2); }); it('should run the webhook', async () => { @@ -491,7 +491,7 @@ export default function tinesTest({ getService }: FtrProviderContext) { }); const executeEvent = events[5]; - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(8); + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(8); }); it('should run the webhook url', async () => { @@ -531,7 +531,7 @@ export default function tinesTest({ getService }: FtrProviderContext) { }); const executeEvent = events[5]; - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(8); + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(8); }); }); @@ -589,7 +589,7 @@ export default function tinesTest({ getService }: FtrProviderContext) { }); const executeEvent = events[1]; - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(2); + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(2); }); it('should return a failure when attempting to get webhooks', async () => { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/torq.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/torq.ts index e5857443a0afd..b709ef837ad03 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/torq.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/torq.ts @@ -177,7 +177,7 @@ export default function torqTest({ getService }: FtrProviderContext) { }); const executeEvent = events[1]; - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(14); + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(14); }); it('should handle a 400 Torq error', async () => { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/webhook.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/webhook.ts index 5e0298ac3b944..f05db95254c1c 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/webhook.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/webhook.ts @@ -278,7 +278,7 @@ export default function webhookTest({ getService }: FtrProviderContext) { }); const executeEvent = events[1]; - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(19); + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(19); }); it('should support the PUT method against webhook target', async () => { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/xmatters.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/xmatters.ts index 00dd7137fdf8f..7cf2320c97933 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/xmatters.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/xmatters.ts @@ -199,7 +199,7 @@ export default function xmattersTest({ getService }: FtrProviderContext) { }); const executeEvent = events[1]; - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.be(130); + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(130); }); it('should handle a 40x xmatters error', async () => { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/execute.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/execute.ts index 6ce3261fe7790..f7b62d51d635f 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/execute.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/execute.ts @@ -652,7 +652,7 @@ export default function ({ getService }: FtrProviderContext) { expect(executeEvent?.message).to.eql(message); expect(startExecuteEvent?.message).to.eql(message.replace('executed', 'started')); - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.eql(0); + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.eql(0); if (source) { expect(executeEvent?.kibana?.action?.execution?.source).to.eql(source.toLowerCase()); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/sub_action_framework/index.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/sub_action_framework/index.ts index 8582509722719..b504f8204c4aa 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/sub_action_framework/index.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/sub_action_framework/index.ts @@ -167,7 +167,7 @@ export default function createActionTests({ getService }: FtrProviderContext) { }); const executeEvent = events[1]; - expect(executeEvent?.kibana?.action?.execution?.metrics?.request_body_bytes).to.eql( + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.eql( Buffer.byteLength(JSON.stringify(subActionParams)) ); From e77bb10a36adafcff9e52004fd2245e7d209dd0b Mon Sep 17 00:00:00 2001 From: Ersin Erdal Date: Tue, 13 Aug 2024 15:57:19 +0300 Subject: [PATCH 19/25] revert eslint changes --- .../server/routes/index.mock.ts | 2 +- .../server/routes/index.ts | 2 +- .../views/overview/gated_form.tsx | 40 +++-------------- .../fleet/sections/agents/index.test.tsx | 3 +- .../app/diagnostics/index_templates_tab.tsx | 45 +++---------------- .../opentelemetry_instructions.tsx | 15 ++----- 6 files changed, 18 insertions(+), 89 deletions(-) diff --git a/x-pack/plugins/encrypted_saved_objects/server/routes/index.mock.ts b/x-pack/plugins/encrypted_saved_objects/server/routes/index.mock.ts index 4d453f64b6954..e6263521f690d 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/routes/index.mock.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/routes/index.mock.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { BuildFlavor } from '@kbn/config'; +import { BuildFlavor } from '@kbn/config'; import { httpServiceMock, loggingSystemMock } from '@kbn/core/server/mocks'; import type { ConfigType } from '../config'; diff --git a/x-pack/plugins/encrypted_saved_objects/server/routes/index.ts b/x-pack/plugins/encrypted_saved_objects/server/routes/index.ts index aa3499ee46055..14d1933e8b765 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/routes/index.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/routes/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { BuildFlavor } from '@kbn/config'; +import { BuildFlavor } from '@kbn/config'; import type { IRouter, Logger } from '@kbn/core/server'; import type { PublicMethodsOf } from '@kbn/utility-types'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/gated_form.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/gated_form.tsx index ff6730223a9de..8f05aa57cca7a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/gated_form.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/gated_form.tsx @@ -257,23 +257,14 @@ const EducationPanel: React.FC<{ featureContent: string }> = ({ featureContent } {feature.actionLink !== undefined && feature.actionLabel !== undefined && ( - + {feature.actionLabel} )} - + {i18n.translate( 'xpack.enterpriseSearch.workplaceSearch.gateForm.educationalPanel.learnMore', { @@ -286,13 +277,7 @@ const EducationPanel: React.FC<{ featureContent: string }> = ({ featureContent } {feature.addOnLearnMoreLabel !== undefined && feature.addOnLearnMoreUrl !== undefined && ( - + {feature.addOnLearnMoreLabel} @@ -315,7 +300,6 @@ const EducationPanel: React.FC<{ featureContent: string }> = ({ featureContent } )} > { setFeaturesOther(e.target.value); }} @@ -598,7 +582,6 @@ export const WorkplaceSearchGate: React.FC = () => { { setAdditionalFeedback(e.target.value); }} @@ -613,10 +596,7 @@ export const WorkplaceSearchGate: React.FC = () => { details or to opt-out at any time." values={{ contact: ( - + { ), privacyStatementLink: ( - + { ), termsOfService: ( - + { )} > { ({ ...jest.requireActual('../../../../hooks/use_fleet_status'), diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/diagnostics/index_templates_tab.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/diagnostics/index_templates_tab.tsx index 60faae291d005..c2a4c47fde86e 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/diagnostics/index_templates_tab.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/diagnostics/index_templates_tab.tsx @@ -8,7 +8,6 @@ import { EuiCallOut, EuiLoadingElastic } from '@elastic/eui'; import { EuiBadge, EuiBasicTable, EuiBasicTableColumn, EuiSpacer, EuiText } from '@elastic/eui'; import React from 'react'; -import { i18n } from '@kbn/i18n'; import { APIReturnType } from '../../../services/rest/create_call_apm_api'; import { FETCH_STATUS } from '../../../hooks/use_fetcher'; import { useDiagnosticsContext } from './context/use_diagnostics'; @@ -35,30 +34,14 @@ export function DiagnosticsIndexTemplates() { field: 'status', render: (_, { exists, isNonStandard }) => { if (isNonStandard) { - return ( - - {i18n.translate('xpack.apm.columns.nonStandardBadgeLabel', { - defaultMessage: 'Non standard', - })} - - ); + return Non standard; } if (!exists) { - return ( - - {i18n.translate('xpack.apm.columns.notFoundBadgeLabel', { - defaultMessage: 'Not found', - })} - - ); + return Not found; } - return ( - - {i18n.translate('xpack.apm.columns.okBadgeLabel', { defaultMessage: 'OK' })} - - ); + return OK; }, truncateText: true, }, @@ -68,10 +51,7 @@ export function DiagnosticsIndexTemplates() { <> - {i18n.translate('xpack.apm.diagnosticsIndexTemplates.thisSectionListsTheTextLabel', { - defaultMessage: - 'This section lists the names of the default APM Index Templates and whether it exists or not', - })} + This section lists the names of the default APM Index Templates and whether it exists or not @@ -101,21 +81,8 @@ function NonStandardIndexTemplateCalout({ return ( <> - - {i18n.translate( - 'xpack.apm.nonStandardIndexTemplateCalout.theFollowingIndexTemplatesCallOutLabel', - { - defaultMessage: - 'The following index templates do not follow the recommended naming scheme:', - } - )}{' '} + + The following index templates do not follow the recommended naming scheme:{' '} {nonStandardIndexTemplates.map(({ name }) => ( {name} ))} diff --git a/x-pack/plugins/observability_solution/apm/public/tutorial/config_agent/opentelemetry_instructions.tsx b/x-pack/plugins/observability_solution/apm/public/tutorial/config_agent/opentelemetry_instructions.tsx index ad20e82d54058..4584326f2f3f2 100644 --- a/x-pack/plugins/observability_solution/apm/public/tutorial/config_agent/opentelemetry_instructions.tsx +++ b/x-pack/plugins/observability_solution/apm/public/tutorial/config_agent/opentelemetry_instructions.tsx @@ -110,10 +110,7 @@ export function OpenTelemetryInstructions({ apmServerUrl, secretToken }: Props) target="_blank" href="https://github.com/open-telemetry/opentelemetry-specification/blob/v1.10.0/specification/protocol/exporter.md" > - {i18n.translate( - 'xpack.apm.openTelemetryInstructions.otelexporterotlpendpointLinkLabel', - { defaultMessage: 'OTEL_EXPORTER_OTLP_ENDPOINT' } - )} + OTEL_EXPORTER_OTLP_ENDPOINT ), otelExporterOtlpHeaders: ( @@ -122,10 +119,7 @@ export function OpenTelemetryInstructions({ apmServerUrl, secretToken }: Props) target="_blank" href="https://github.com/open-telemetry/opentelemetry-specification/blob/v1.10.0/specification/protocol/exporter.md" > - {i18n.translate( - 'xpack.apm.openTelemetryInstructions.otelexporterotlpheadersLinkLabel', - { defaultMessage: 'OTEL_EXPORTER_OTLP_HEADERS' } - )} + OTEL_EXPORTER_OTLP_HEADERS ), otelResourceAttributes: ( @@ -134,10 +128,7 @@ export function OpenTelemetryInstructions({ apmServerUrl, secretToken }: Props) target="_blank" href="https://github.com/open-telemetry/opentelemetry-specification/blob/v1.10.0/specification/resource/sdk.md" > - {i18n.translate( - 'xpack.apm.openTelemetryInstructions.otelresourceattributesLinkLabel', - { defaultMessage: 'OTEL_RESOURCE_ATTRIBUTES' } - )} + OTEL_RESOURCE_ATTRIBUTES ), }} From 9af645e249cc80bfd6a720a6e2da54e19c488053 Mon Sep 17 00:00:00 2001 From: Ersin Erdal Date: Tue, 13 Aug 2024 17:57:46 +0300 Subject: [PATCH 20/25] fix snapshot --- .../__snapshots__/service.test.ts.snap | 322 ++++++++++++++++++ 1 file changed, 322 insertions(+) diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/__snapshots__/service.test.ts.snap b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/__snapshots__/service.test.ts.snap index 12a4e93def576..cbcf2aac8f6f0 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/__snapshots__/service.test.ts.snap +++ b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/__snapshots__/service.test.ts.snap @@ -321,3 +321,325 @@ Object { "url": "https://coolsite.net/issue/1/comment", } `; + +exports[`Cases webhook service createComment it should call request with correct arguments when authType=SSL: + Object { + "axios": [Function], + "connectorUsageCollector": ConnectorUsageCollector { + "connectorId": "test-connector-id", + "logger": Object { + "context": Array [], + "debug": [MockFunction], + "error": [MockFunction], + "fatal": [MockFunction], + "get": [MockFunction], + "info": [MockFunction], + "isLevelEnabled": [MockFunction], + "log": [MockFunction], + "trace": [MockFunction], + "warn": [MockFunction], + }, + "usage": Object { + "requestBodyBytes": 0, + }, + }, + "data": "{\\"body\\":\\"comment\\"}", + "logger": Object { + "context": Array [], + "debug": [MockFunction], + "error": [MockFunction], + "fatal": [MockFunction], + "get": [MockFunction], + "info": [MockFunction], + "isLevelEnabled": [MockFunction], + "log": [MockFunction], + "trace": [MockFunction], + "warn": [MockFunction], + }, + "method": "post", + "sslOverrides": Object { + "cert": Object { + "data": Array [ + 10, + 45, + 45, + 45, + 45, + 45, + 66, + 69, + 71, + 73, + 78, + 32, + 67, + 69, + 82, + 84, + 73, + 70, + 73, + 67, + 65, + 84, + 69, + 45, + 45, + 45, + 45, + 45, + 10, + 45, + 45, + 45, + 45, + 45, + 69, + 78, + 68, + 32, + 67, + 69, + 82, + 84, + 73, + 70, + 73, + 67, + 65, + 84, + 69, + 45, + 45, + 45, + 45, + 45, + 10, + ], + "type": "Buffer", + }, + "key": Object { + "data": Array [ + 10, + 45, + 45, + 45, + 45, + 45, + 66, + 69, + 71, + 73, + 78, + 32, + 80, + 82, + 73, + 86, + 65, + 84, + 69, + 32, + 75, + 69, + 89, + 45, + 45, + 45, + 45, + 45, + 10, + 45, + 45, + 45, + 45, + 45, + 69, + 78, + 68, + 32, + 80, + 82, + 73, + 86, + 65, + 84, + 69, + 32, + 75, + 69, + 89, + 45, + 45, + 45, + 45, + 45, + 10, + ], + "type": "Buffer", + }, + "passphrase": "foobar", + }, + "url": "https://coolsite.net/issue/1/comment", + } + 1`] = ` +Object { + "axios": [Function], + "connectorUsageCollector": ConnectorUsageCollector { + "connectorId": "test-connector-id", + "logger": Object { + "context": Array [], + "debug": [MockFunction], + "error": [MockFunction], + "fatal": [MockFunction], + "get": [MockFunction], + "info": [MockFunction], + "isLevelEnabled": [MockFunction], + "log": [MockFunction], + "trace": [MockFunction], + "warn": [MockFunction], + }, + "usage": Object { + "requestBodyBytes": 0, + }, + }, + "data": "{\\"body\\":\\"comment\\"}", + "logger": Object { + "context": Array [], + "debug": [MockFunction], + "error": [MockFunction], + "fatal": [MockFunction], + "get": [MockFunction], + "info": [MockFunction], + "isLevelEnabled": [MockFunction], + "log": [MockFunction], + "trace": [MockFunction], + "warn": [MockFunction], + }, + "method": "post", + "sslOverrides": Object { + "cert": Object { + "data": Array [ + 10, + 45, + 45, + 45, + 45, + 45, + 66, + 69, + 71, + 73, + 78, + 32, + 67, + 69, + 82, + 84, + 73, + 70, + 73, + 67, + 65, + 84, + 69, + 45, + 45, + 45, + 45, + 45, + 10, + 45, + 45, + 45, + 45, + 45, + 69, + 78, + 68, + 32, + 67, + 69, + 82, + 84, + 73, + 70, + 73, + 67, + 65, + 84, + 69, + 45, + 45, + 45, + 45, + 45, + 10, + ], + "type": "Buffer", + }, + "key": Object { + "data": Array [ + 10, + 45, + 45, + 45, + 45, + 45, + 66, + 69, + 71, + 73, + 78, + 32, + 80, + 82, + 73, + 86, + 65, + 84, + 69, + 32, + 75, + 69, + 89, + 45, + 45, + 45, + 45, + 45, + 10, + 45, + 45, + 45, + 45, + 45, + 69, + 78, + 68, + 32, + 80, + 82, + 73, + 86, + 65, + 84, + 69, + 32, + 75, + 69, + 89, + 45, + 45, + 45, + 45, + 45, + 10, + ], + "type": "Buffer", + }, + "passphrase": "foobar", + }, + "url": "https://coolsite.net/issue/1/comment", +} +`; From 5a4a1e5cb6e58af8ae3e6987af9146c55d4fe61b Mon Sep 17 00:00:00 2001 From: Ersin Erdal Date: Wed, 14 Aug 2024 11:29:57 +0300 Subject: [PATCH 21/25] fix snapshot --- .../__snapshots__/service.test.ts.snap | 322 ------------------ 1 file changed, 322 deletions(-) diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/__snapshots__/service.test.ts.snap b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/__snapshots__/service.test.ts.snap index cbcf2aac8f6f0..12a4e93def576 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/__snapshots__/service.test.ts.snap +++ b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/__snapshots__/service.test.ts.snap @@ -321,325 +321,3 @@ Object { "url": "https://coolsite.net/issue/1/comment", } `; - -exports[`Cases webhook service createComment it should call request with correct arguments when authType=SSL: - Object { - "axios": [Function], - "connectorUsageCollector": ConnectorUsageCollector { - "connectorId": "test-connector-id", - "logger": Object { - "context": Array [], - "debug": [MockFunction], - "error": [MockFunction], - "fatal": [MockFunction], - "get": [MockFunction], - "info": [MockFunction], - "isLevelEnabled": [MockFunction], - "log": [MockFunction], - "trace": [MockFunction], - "warn": [MockFunction], - }, - "usage": Object { - "requestBodyBytes": 0, - }, - }, - "data": "{\\"body\\":\\"comment\\"}", - "logger": Object { - "context": Array [], - "debug": [MockFunction], - "error": [MockFunction], - "fatal": [MockFunction], - "get": [MockFunction], - "info": [MockFunction], - "isLevelEnabled": [MockFunction], - "log": [MockFunction], - "trace": [MockFunction], - "warn": [MockFunction], - }, - "method": "post", - "sslOverrides": Object { - "cert": Object { - "data": Array [ - 10, - 45, - 45, - 45, - 45, - 45, - 66, - 69, - 71, - 73, - 78, - 32, - 67, - 69, - 82, - 84, - 73, - 70, - 73, - 67, - 65, - 84, - 69, - 45, - 45, - 45, - 45, - 45, - 10, - 45, - 45, - 45, - 45, - 45, - 69, - 78, - 68, - 32, - 67, - 69, - 82, - 84, - 73, - 70, - 73, - 67, - 65, - 84, - 69, - 45, - 45, - 45, - 45, - 45, - 10, - ], - "type": "Buffer", - }, - "key": Object { - "data": Array [ - 10, - 45, - 45, - 45, - 45, - 45, - 66, - 69, - 71, - 73, - 78, - 32, - 80, - 82, - 73, - 86, - 65, - 84, - 69, - 32, - 75, - 69, - 89, - 45, - 45, - 45, - 45, - 45, - 10, - 45, - 45, - 45, - 45, - 45, - 69, - 78, - 68, - 32, - 80, - 82, - 73, - 86, - 65, - 84, - 69, - 32, - 75, - 69, - 89, - 45, - 45, - 45, - 45, - 45, - 10, - ], - "type": "Buffer", - }, - "passphrase": "foobar", - }, - "url": "https://coolsite.net/issue/1/comment", - } - 1`] = ` -Object { - "axios": [Function], - "connectorUsageCollector": ConnectorUsageCollector { - "connectorId": "test-connector-id", - "logger": Object { - "context": Array [], - "debug": [MockFunction], - "error": [MockFunction], - "fatal": [MockFunction], - "get": [MockFunction], - "info": [MockFunction], - "isLevelEnabled": [MockFunction], - "log": [MockFunction], - "trace": [MockFunction], - "warn": [MockFunction], - }, - "usage": Object { - "requestBodyBytes": 0, - }, - }, - "data": "{\\"body\\":\\"comment\\"}", - "logger": Object { - "context": Array [], - "debug": [MockFunction], - "error": [MockFunction], - "fatal": [MockFunction], - "get": [MockFunction], - "info": [MockFunction], - "isLevelEnabled": [MockFunction], - "log": [MockFunction], - "trace": [MockFunction], - "warn": [MockFunction], - }, - "method": "post", - "sslOverrides": Object { - "cert": Object { - "data": Array [ - 10, - 45, - 45, - 45, - 45, - 45, - 66, - 69, - 71, - 73, - 78, - 32, - 67, - 69, - 82, - 84, - 73, - 70, - 73, - 67, - 65, - 84, - 69, - 45, - 45, - 45, - 45, - 45, - 10, - 45, - 45, - 45, - 45, - 45, - 69, - 78, - 68, - 32, - 67, - 69, - 82, - 84, - 73, - 70, - 73, - 67, - 65, - 84, - 69, - 45, - 45, - 45, - 45, - 45, - 10, - ], - "type": "Buffer", - }, - "key": Object { - "data": Array [ - 10, - 45, - 45, - 45, - 45, - 45, - 66, - 69, - 71, - 73, - 78, - 32, - 80, - 82, - 73, - 86, - 65, - 84, - 69, - 32, - 75, - 69, - 89, - 45, - 45, - 45, - 45, - 45, - 10, - 45, - 45, - 45, - 45, - 45, - 69, - 78, - 68, - 32, - 80, - 82, - 73, - 86, - 65, - 84, - 69, - 32, - 75, - 69, - 89, - 45, - 45, - 45, - 45, - 45, - 10, - ], - "type": "Buffer", - }, - "passphrase": "foobar", - }, - "url": "https://coolsite.net/issue/1/comment", -} -`; From 702322931caaaa5946b5b1c17dff0dbce4b5e04c Mon Sep 17 00:00:00 2001 From: Ersin Erdal Date: Wed, 14 Aug 2024 16:18:10 +0300 Subject: [PATCH 22/25] remove snapshot --- .../__snapshots__/service.test.ts.snap | 323 ------------------ .../cases_webhook/service.test.ts | 2 +- 2 files changed, 1 insertion(+), 324 deletions(-) delete mode 100644 x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/__snapshots__/service.test.ts.snap diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/__snapshots__/service.test.ts.snap b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/__snapshots__/service.test.ts.snap deleted file mode 100644 index 12a4e93def576..0000000000000 --- a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/__snapshots__/service.test.ts.snap +++ /dev/null @@ -1,323 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Cases webhook service createComment it should call request with correct arguments when authType=SSL: - Object { - "axios": [Function], - "connectorUsageCollector": ConnectorUsageCollector { - "connectorId": "test-connector-id", - "logger": Object { - "context": Array [], - "debug": [MockFunction], - "error": [MockFunction], - "fatal": [MockFunction], - "get": [MockFunction], - "info": [MockFunction], - "isLevelEnabled": [MockFunction], - "log": [MockFunction], - "trace": [MockFunction], - "warn": [MockFunction], - }, - "usage": Object { - "requestBodyBytes": 0, - }, - }, - "data": "{\\"body\\":\\"comment\\"}", - "logger": Object { - "context": Array [], - "debug": [MockFunction], - "error": [MockFunction], - "fatal": [MockFunction], - "get": [MockFunction], - "info": [MockFunction], - "isLevelEnabled": [MockFunction], - "log": [MockFunction], - "trace": [MockFunction], - "warn": [MockFunction], - }, - "method": "post", - "sslOverrides": Object { - "cert": Object { - "data": Array [ - 10, - 45, - 45, - 45, - 45, - 45, - 66, - 69, - 71, - 73, - 78, - 32, - 67, - 69, - 82, - 84, - 73, - 70, - 73, - 67, - 65, - 84, - 69, - 45, - 45, - 45, - 45, - 45, - 10, - 45, - 45, - 45, - 45, - 45, - 69, - 78, - 68, - 32, - 67, - 69, - 82, - 84, - 73, - 70, - 73, - 67, - 65, - 84, - 69, - 45, - 45, - 45, - 45, - 45, - 10, - ], - "type": "Buffer", - }, - "key": Object { - "data": Array [ - 10, - 45, - 45, - 45, - 45, - 45, - 66, - 69, - 71, - 73, - 78, - 32, - 80, - 82, - 73, - 86, - 65, - 84, - 69, - 32, - 75, - 69, - 89, - 45, - 45, - 45, - 45, - 45, - 10, - 45, - 45, - 45, - 45, - 45, - 69, - 78, - 68, - 32, - 80, - 82, - 73, - 86, - 65, - 84, - 69, - 32, - 75, - 69, - 89, - 45, - 45, - 45, - 45, - 45, - 10, - ], - "type": "Buffer", - }, - "passphrase": "foobar", - }, - "url": "https://coolsite.net/issue/1/comment", - } - 1`] = ` -Object { - "axios": [Function], - "connectorUsageCollector": ConnectorUsageCollector { - "connectorId": "test-connector-id", - "logger": Object { - "context": Array [], - "debug": [MockFunction], - "error": [MockFunction], - "fatal": [MockFunction], - "get": [MockFunction], - "info": [MockFunction], - "isLevelEnabled": [MockFunction], - "log": [MockFunction], - "trace": [MockFunction], - "warn": [MockFunction], - }, - "usage": Object { - "requestBodyBytes": 0, - }, - }, - "data": "{\\"body\\":\\"comment\\"}", - "logger": Object { - "context": Array [], - "debug": [MockFunction], - "error": [MockFunction], - "fatal": [MockFunction], - "get": [MockFunction], - "info": [MockFunction], - "isLevelEnabled": [MockFunction], - "log": [MockFunction], - "trace": [MockFunction], - "warn": [MockFunction], - }, - "method": "post", - "sslOverrides": Object { - "cert": Object { - "data": Array [ - 10, - 45, - 45, - 45, - 45, - 45, - 66, - 69, - 71, - 73, - 78, - 32, - 67, - 69, - 82, - 84, - 73, - 70, - 73, - 67, - 65, - 84, - 69, - 45, - 45, - 45, - 45, - 45, - 10, - 45, - 45, - 45, - 45, - 45, - 69, - 78, - 68, - 32, - 67, - 69, - 82, - 84, - 73, - 70, - 73, - 67, - 65, - 84, - 69, - 45, - 45, - 45, - 45, - 45, - 10, - ], - "type": "Buffer", - }, - "key": Object { - "data": Array [ - 10, - 45, - 45, - 45, - 45, - 45, - 66, - 69, - 71, - 73, - 78, - 32, - 80, - 82, - 73, - 86, - 65, - 84, - 69, - 32, - 75, - 69, - 89, - 45, - 45, - 45, - 45, - 45, - 10, - 45, - 45, - 45, - 45, - 45, - 69, - 78, - 68, - 32, - 80, - 82, - 73, - 86, - 65, - 84, - 69, - 32, - 75, - 69, - 89, - 45, - 45, - 45, - 45, - 45, - 10, - ], - "type": "Buffer", - }, - "passphrase": "foobar", - }, - "url": "https://coolsite.net/issue/1/comment", -} -`; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts index 27cce1d9f6a35..a44b34bf88fce 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts @@ -1084,7 +1084,7 @@ describe('Cases webhook service', () => { // irrelevant snapshot content delete requestMock.mock.calls[0][0].configurationUtilities; - expect(requestMock.mock.calls[0][0]).toMatchSnapshot(` + expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "axios": [Function], "connectorUsageCollector": ConnectorUsageCollector { From f1ab8c8c500ea624d79026a85894aef85b168c98 Mon Sep 17 00:00:00 2001 From: Ersin Erdal Date: Wed, 21 Aug 2024 14:20:19 +0300 Subject: [PATCH 23/25] revert change on security solutions --- x-pack/plugins/security_solution_serverless/server/plugin.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/security_solution_serverless/server/plugin.ts b/x-pack/plugins/security_solution_serverless/server/plugin.ts index f81a8e013e290..7161c5b684505 100644 --- a/x-pack/plugins/security_solution_serverless/server/plugin.ts +++ b/x-pack/plugins/security_solution_serverless/server/plugin.ts @@ -63,6 +63,7 @@ export class SecuritySolutionServerlessPlugin // Register product features const enabledProductFeatures = getProductProductFeatures(this.config.productTypes); + registerProductFeatures(pluginsSetup, enabledProductFeatures, this.config); // Register telemetry events From a1152cf59417ebb344c37fd51ee730d8de450c52 Mon Sep 17 00:00:00 2001 From: Ersin Erdal Date: Tue, 27 Aug 2024 00:50:14 +0300 Subject: [PATCH 24/25] remove temporary comments --- .../actions/clients/crowdstrike/crowdstrike_actions_client.ts | 2 -- .../actions/clients/sentinelone/sentinel_one_actions_client.ts | 2 -- 2 files changed, 4 deletions(-) diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/crowdstrike/crowdstrike_actions_client.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/crowdstrike/crowdstrike_actions_client.ts index 6103bff35ab3e..f4ad7f981ab9d 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/crowdstrike/crowdstrike_actions_client.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/crowdstrike/crowdstrike_actions_client.ts @@ -46,8 +46,6 @@ export type CrowdstrikeActionsClientOptions = ResponseActionsClientOptions & { connectorActions: NormalizedExternalConnectorClient; }; -// Temporary comment to trigger unit tests - export class CrowdstrikeActionsClient extends ResponseActionsClientImpl { protected readonly agentType: ResponseActionAgentType = 'crowdstrike'; private readonly connectorActionsClient: NormalizedExternalConnectorClient; diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/sentinel_one_actions_client.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/sentinel_one_actions_client.ts index f983b61d79b6d..ba017ea9db1c9 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/sentinel_one_actions_client.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/sentinel_one_actions_client.ts @@ -114,8 +114,6 @@ interface FetchScriptInfoResponse< buildScriptArgs: (options: TScriptOptions) => string; } -// Temporary comment to trigger unit tests - export class SentinelOneActionsClient extends ResponseActionsClientImpl { protected readonly agentType: ResponseActionAgentType = 'sentinel_one'; private readonly connectorActionsClient: NormalizedExternalConnectorClient; From 23b4921310d98723222e7fdee7b8a02e04618e41 Mon Sep 17 00:00:00 2001 From: Ersin Erdal Date: Tue, 27 Aug 2024 01:52:18 +0300 Subject: [PATCH 25/25] fix executor test --- x-pack/plugins/actions/server/lib/action_executor.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/actions/server/lib/action_executor.test.ts b/x-pack/plugins/actions/server/lib/action_executor.test.ts index 9c6313964ac02..560d5dc3ecea5 100644 --- a/x-pack/plugins/actions/server/lib/action_executor.test.ts +++ b/x-pack/plugins/actions/server/lib/action_executor.test.ts @@ -4,7 +4,6 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - import { KibanaRequest } from '@kbn/core/server'; import { schema } from '@kbn/config-schema'; import { ActionExecutor } from './action_executor'; @@ -229,9 +228,12 @@ const getBaseExecuteEventLogDoc = ( }; }; +const mockGetRequestBodyByte = jest.spyOn(ConnectorUsageCollector.prototype, 'getRequestBodyByte'); + beforeEach(() => { jest.resetAllMocks(); jest.clearAllMocks(); + mockGetRequestBodyByte.mockReturnValue(0); spacesMock.getSpaceId.mockReturnValue('some-namespace'); loggerMock.get.mockImplementation(() => loggerMock); const mockRealm = { name: 'default_native', type: 'native' }; @@ -250,8 +252,6 @@ beforeEach(() => { getActionsAuthorizationWithRequest.mockReturnValue(authorizationMock); }); -const mockGetRequestBodyByte = jest.spyOn(ConnectorUsageCollector.prototype, 'getRequestBodyByte'); - describe('Action Executor', () => { for (const executeUnsecure of [false, true]) { const label = executeUnsecure ? 'executes unsecured' : 'executes';