From c84047bd36f265992fc5645494aa658ae3036559 Mon Sep 17 00:00:00 2001 From: Dima Arnautov Date: Wed, 17 Feb 2021 19:26:23 +0100 Subject: [PATCH 01/17] [ML] Prevent duplicate notifications about the same anomaly result (#91485) * [ML] check kibana even logs for existing alert instance * [ML] create alert instance key, add check for alert id * [ML] use anomaly_utils, check interval gap * [ML] add detector index * [ML] fix unit test * [ML] include detector_index into source --- x-pack/plugins/ml/common/types/alerts.ts | 13 +- .../plugins/ml/common/util/anomaly_utils.ts | 4 - .../lib/alerts/alerting_service.test.ts | 4 +- .../ml/server/lib/alerts/alerting_service.ts | 143 +++++++++++++++--- .../register_anomaly_detection_alert_type.ts | 10 +- .../server/lib/alerts/register_ml_alerts.ts | 2 + x-pack/plugins/ml/server/plugin.ts | 1 + x-pack/plugins/ml/server/routes/alerting.ts | 4 +- .../providers/alerting_service.ts | 8 +- 9 files changed, 150 insertions(+), 39 deletions(-) diff --git a/x-pack/plugins/ml/common/types/alerts.ts b/x-pack/plugins/ml/common/types/alerts.ts index 51d06b99062300..7e6e9d89c5a651 100644 --- a/x-pack/plugins/ml/common/types/alerts.ts +++ b/x-pack/plugins/ml/common/types/alerts.ts @@ -15,7 +15,7 @@ export type TopHitsResultsKeys = 'top_record_hits' | 'top_bucket_hits' | 'top_in export interface AlertExecutionResult { count: number; key: number; - key_as_string: string; + alertInstanceKey: string; isInterim: boolean; jobIds: string[]; timestamp: number; @@ -47,10 +47,13 @@ interface BaseAnomalyAlertDoc { export interface RecordAnomalyAlertDoc extends BaseAnomalyAlertDoc { result_type: typeof ANOMALY_RESULT_TYPE.RECORD; function: string; - field_name: string; - by_field_value: string | number; - over_field_value: string | number; - partition_field_value: string | number; + field_name?: string; + by_field_name?: string; + by_field_value?: string | number; + over_field_name?: string; + over_field_value?: string | number; + partition_field_name?: string; + partition_field_value?: string | number; } export interface BucketAnomalyAlertDoc extends BaseAnomalyAlertDoc { diff --git a/x-pack/plugins/ml/common/util/anomaly_utils.ts b/x-pack/plugins/ml/common/util/anomaly_utils.ts index 028afee2524c93..68605f29c7be96 100644 --- a/x-pack/plugins/ml/common/util/anomaly_utils.ts +++ b/x-pack/plugins/ml/common/util/anomaly_utils.ts @@ -230,8 +230,6 @@ export function getEntityFieldName(record: AnomalyRecordDoc): string | undefined if (record.partition_field_name !== undefined) { return record.partition_field_name; } - - return undefined; } // Returns the value of the field to use as the entity value from the source record @@ -249,8 +247,6 @@ export function getEntityFieldValue(record: AnomalyRecordDoc): string | number | if (record.partition_field_value !== undefined) { return record.partition_field_value; } - - return undefined; } // Returns the list of partitioning entity fields for the source record as a list diff --git a/x-pack/plugins/ml/server/lib/alerts/alerting_service.test.ts b/x-pack/plugins/ml/server/lib/alerts/alerting_service.test.ts index 261fac7b620ba9..f029fa24f96078 100644 --- a/x-pack/plugins/ml/server/lib/alerts/alerting_service.test.ts +++ b/x-pack/plugins/ml/server/lib/alerts/alerting_service.test.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { resolveTimeInterval } from './alerting_service'; +import { resolveBucketSpanInSeconds } from './alerting_service'; describe('Alerting Service', () => { test('should resolve maximum bucket interval', () => { - expect(resolveTimeInterval(['15m', '1h', '6h', '90s'])).toBe('43200s'); + expect(resolveBucketSpanInSeconds(['15m', '1h', '6h', '90s'])).toBe(43200); }); }); diff --git a/x-pack/plugins/ml/server/lib/alerts/alerting_service.ts b/x-pack/plugins/ml/server/lib/alerts/alerting_service.ts index 5ef883cc50fbb3..6e7cd77e450bcc 100644 --- a/x-pack/plugins/ml/server/lib/alerts/alerting_service.ts +++ b/x-pack/plugins/ml/server/lib/alerts/alerting_service.ts @@ -7,6 +7,9 @@ import Boom from '@hapi/boom'; import rison from 'rison-node'; +import { ElasticsearchClient } from 'kibana/server'; +import moment from 'moment'; +import { Duration } from 'moment/moment'; import { MlClient } from '../ml_client'; import { MlAnomalyDetectionAlertParams, @@ -25,6 +28,8 @@ import { import { parseInterval } from '../../../common/util/parse_interval'; import { AnomalyDetectionAlertContext } from './register_anomaly_detection_alert_type'; import { MlJobsResponse } from '../../../common/types/job_service'; +import { ANOMALY_SCORE_MATCH_GROUP_ID } from '../../../common/constants/alerts'; +import { getEntityFieldName, getEntityFieldValue } from '../../../common/util/anomaly_utils'; function isDefined(argument: T | undefined | null): argument is T { return argument !== undefined && argument !== null; @@ -34,22 +39,23 @@ function isDefined(argument: T | undefined | null): argument is T { * Resolves the longest bucket span from the list and multiply it by 2. * @param bucketSpans Collection of bucket spans */ -export function resolveTimeInterval(bucketSpans: string[]): string { - return `${ +export function resolveBucketSpanInSeconds(bucketSpans: string[]): number { + return ( Math.max( ...bucketSpans .map((b) => parseInterval(b)) .filter(isDefined) .map((v) => v.asSeconds()) ) * 2 - }s`; + ); } /** * Alerting related server-side methods * @param mlClient + * @param esClient */ -export function alertingServiceProvider(mlClient: MlClient) { +export function alertingServiceProvider(mlClient: MlClient, esClient: ElasticsearchClient) { const getAggResultsLabel = (resultType: AnomalyResultType) => { return { aggGroupLabel: `${resultType}_results` as PreviewResultsKeys, @@ -177,10 +183,14 @@ export function alertingServiceProvider(mlClient: MlClient) { 'is_interim', 'function', 'field_name', + 'by_field_name', 'by_field_value', + 'over_field_name', 'over_field_value', + 'partition_field_name', 'partition_field_value', 'job_id', + 'detector_index', ], }, size: 3, @@ -257,14 +267,31 @@ export function alertingServiceProvider(mlClient: MlClient) { }; }; + /** + * Provides unique key for the anomaly result. + */ + const getAlertInstanceKey = (source: any): string => { + let alertInstanceKey = `${source.job_id}_${source.timestamp}`; + if (source.result_type === ANOMALY_RESULT_TYPE.INFLUENCER) { + alertInstanceKey += `_${source.influencer_field_name}_${source.influencer_field_value}`; + } else if (source.result_type === ANOMALY_RESULT_TYPE.RECORD) { + const fieldName = getEntityFieldName(source); + const fieldValue = getEntityFieldValue(source); + alertInstanceKey += `_${source.detector_index}_${source.function}_${fieldName}_${fieldValue}`; + } + return alertInstanceKey; + }; + /** * Builds a request body - * @param params - * @param previewTimeInterval + * @param params - Alert params + * @param previewTimeInterval - Relative time interval to test the alert condition + * @param checkIntervalGap - Interval between alert executions */ const fetchAnomalies = async ( params: MlAnomalyDetectionAlertParams, - previewTimeInterval?: string + previewTimeInterval?: string, + checkIntervalGap?: Duration ): Promise => { const jobAndGroupIds = [ ...(params.jobSelection.jobIds ?? []), @@ -281,9 +308,14 @@ export function alertingServiceProvider(mlClient: MlClient) { return; } - const lookBackTimeInterval = resolveTimeInterval( - jobsResponse.map((v) => v.analysis_config.bucket_span) - ); + /** + * The check interval might be bigger than the 2x bucket span. + * We need to check the biggest time range to make sure anomalies are not missed. + */ + const lookBackTimeInterval = `${Math.max( + resolveBucketSpanInSeconds(jobsResponse.map((v) => v.analysis_config.bucket_span)), + checkIntervalGap ? checkIntervalGap.asSeconds() : 0 + )}s`; const jobIds = jobsResponse.map((v) => v.job_id); @@ -370,19 +402,22 @@ export function alertingServiceProvider(mlClient: MlClient) { const aggTypeResults = v[resultsLabel.aggGroupLabel]; const requestedAnomalies = aggTypeResults[resultsLabel.topHitsLabel].hits.hits; + const topAnomaly = requestedAnomalies[0]; + const alertInstanceKey = getAlertInstanceKey(topAnomaly._source); + return { count: aggTypeResults.doc_count, key: v.key, - key_as_string: v.key_as_string, + alertInstanceKey, jobIds: [...new Set(requestedAnomalies.map((h) => h._source.job_id))], isInterim: requestedAnomalies.some((h) => h._source.is_interim), - timestamp: requestedAnomalies[0]._source.timestamp, - timestampIso8601: requestedAnomalies[0].fields.timestamp_iso8601[0], - timestampEpoch: requestedAnomalies[0].fields.timestamp_epoch[0], - score: requestedAnomalies[0].fields.score[0], + timestamp: topAnomaly._source.timestamp, + timestampIso8601: topAnomaly.fields.timestamp_iso8601[0], + timestampEpoch: topAnomaly.fields.timestamp_epoch[0], + score: topAnomaly.fields.score[0], bucketRange: { - start: requestedAnomalies[0].fields.start[0], - end: requestedAnomalies[0].fields.end[0], + start: topAnomaly.fields.start[0], + end: topAnomaly.fields.end[0], }, topRecords: v.record_results.top_record_hits.hits.hits.map((h) => ({ ...h._source, @@ -479,13 +514,24 @@ export function alertingServiceProvider(mlClient: MlClient) { /** * Return the result of an alert condition execution. * - * @param params + * @param params - Alert params + * @param publicBaseUrl + * @param alertId - Alert ID + * @param startedAt + * @param previousStartedAt */ execute: async ( params: MlAnomalyDetectionAlertParams, - publicBaseUrl: string | undefined + publicBaseUrl: string | undefined, + alertId: string, + startedAt: Date, + previousStartedAt: Date | null ): Promise => { - const res = await fetchAnomalies(params); + const checkIntervalGap = previousStartedAt + ? moment.duration(moment(startedAt).diff(previousStartedAt)) + : undefined; + + const res = await fetchAnomalies(params, undefined, checkIntervalGap); if (!res) { throw new Error('No results found'); @@ -496,12 +542,65 @@ export function alertingServiceProvider(mlClient: MlClient) { const anomalyExplorerUrl = buildExplorerUrl(result, params.resultType as AnomalyResultType); - return { + const executionResult = { ...result, - name: result.key_as_string, + name: result.alertInstanceKey, anomalyExplorerUrl, kibanaBaseUrl: publicBaseUrl!, }; + + let kibanaEventLogCount = 0; + try { + // Check kibana-event-logs for presence of this alert instance + const kibanaLogResults = await esClient.count({ + index: '.kibana-event-log-*', + body: { + query: { + bool: { + must: [ + { + term: { + 'kibana.alerting.action_group_id': { + value: ANOMALY_SCORE_MATCH_GROUP_ID, + }, + }, + }, + { + term: { + 'kibana.alerting.instance_id': { + value: executionResult.name, + }, + }, + }, + { + nested: { + path: 'kibana.saved_objects', + query: { + term: { + 'kibana.saved_objects.id': { + value: alertId, + }, + }, + }, + }, + }, + ], + }, + }, + }, + }); + + kibanaEventLogCount = kibanaLogResults.body.count; + } catch (e) { + // eslint-disable-next-line no-console + console.log('Unable to check kibana event logs', e); + } + + if (kibanaEventLogCount > 0) { + return; + } + + return executionResult; }, /** * Checks how often the alert condition will fire an alert instance diff --git a/x-pack/plugins/ml/server/lib/alerts/register_anomaly_detection_alert_type.ts b/x-pack/plugins/ml/server/lib/alerts/register_anomaly_detection_alert_type.ts index 6f8fa59aa231e7..30a92c02cefc3a 100644 --- a/x-pack/plugins/ml/server/lib/alerts/register_anomaly_detection_alert_type.ts +++ b/x-pack/plugins/ml/server/lib/alerts/register_anomaly_detection_alert_type.ts @@ -123,13 +123,19 @@ export function registerAnomalyDetectionAlertType({ }, producer: PLUGIN_ID, minimumLicenseRequired: MINIMUM_FULL_LICENSE, - async executor({ services, params }) { + async executor({ services, params, alertId, state, previousStartedAt, startedAt }) { const fakeRequest = {} as KibanaRequest; const { execute } = mlSharedServices.alertingServiceProvider( services.savedObjectsClient, fakeRequest ); - const executionResult = await execute(params, publicBaseUrl); + const executionResult = await execute( + params, + publicBaseUrl, + alertId, + startedAt, + previousStartedAt + ); if (executionResult) { const alertInstanceName = executionResult.name; diff --git a/x-pack/plugins/ml/server/lib/alerts/register_ml_alerts.ts b/x-pack/plugins/ml/server/lib/alerts/register_ml_alerts.ts index 5c9106d78595fc..371c5435f91de9 100644 --- a/x-pack/plugins/ml/server/lib/alerts/register_ml_alerts.ts +++ b/x-pack/plugins/ml/server/lib/alerts/register_ml_alerts.ts @@ -5,12 +5,14 @@ * 2.0. */ +import { Logger } from 'kibana/server'; import { AlertingPlugin } from '../../../../alerts/server'; import { registerAnomalyDetectionAlertType } from './register_anomaly_detection_alert_type'; import { SharedServices } from '../../shared_services'; export interface RegisterAlertParams { alerts: AlertingPlugin['setup']; + logger: Logger; mlSharedServices: SharedServices; publicBaseUrl: string | undefined; } diff --git a/x-pack/plugins/ml/server/plugin.ts b/x-pack/plugins/ml/server/plugin.ts index 10ed70d7f73969..24fac9184cc27c 100644 --- a/x-pack/plugins/ml/server/plugin.ts +++ b/x-pack/plugins/ml/server/plugin.ts @@ -211,6 +211,7 @@ export class MlServerPlugin if (plugins.alerts) { registerMlAlerts({ alerts: plugins.alerts, + logger: this.log, mlSharedServices: sharedServices, publicBaseUrl: coreSetup.http.basePath.publicBaseUrl, }); diff --git a/x-pack/plugins/ml/server/routes/alerting.ts b/x-pack/plugins/ml/server/routes/alerting.ts index 7b7f3a7db9723a..a268a5200b35e7 100644 --- a/x-pack/plugins/ml/server/routes/alerting.ts +++ b/x-pack/plugins/ml/server/routes/alerting.ts @@ -30,9 +30,9 @@ export function alertingRoutes({ router, routeGuard }: RouteInitialization) { tags: ['access:ml:canGetJobs'], }, }, - routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => { + routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response, client }) => { try { - const alertingService = alertingServiceProvider(mlClient); + const alertingService = alertingServiceProvider(mlClient, client.asInternalUser); const result = await alertingService.preview(request.body); diff --git a/x-pack/plugins/ml/server/shared_services/providers/alerting_service.ts b/x-pack/plugins/ml/server/shared_services/providers/alerting_service.ts index 318dac200a8772..cbe22478e12d6c 100644 --- a/x-pack/plugins/ml/server/shared_services/providers/alerting_service.ts +++ b/x-pack/plugins/ml/server/shared_services/providers/alerting_service.ts @@ -20,7 +20,9 @@ export function getAlertingServiceProvider(getGuards: GetGuards) { return await getGuards(request, savedObjectsClient) .isFullLicense() .hasMlCapabilities(['canGetJobs']) - .ok(({ mlClient }) => alertingServiceProvider(mlClient).preview(...args)); + .ok(({ mlClient, scopedClient }) => + alertingServiceProvider(mlClient, scopedClient.asInternalUser).preview(...args) + ); }, execute: async ( ...args: Parameters @@ -28,7 +30,9 @@ export function getAlertingServiceProvider(getGuards: GetGuards) { return await getGuards(request, savedObjectsClient) .isFullLicense() .hasMlCapabilities(['canGetJobs']) - .ok(({ mlClient }) => alertingServiceProvider(mlClient).execute(...args)); + .ok(({ mlClient, scopedClient }) => + alertingServiceProvider(mlClient, scopedClient.asInternalUser).execute(...args) + ); }, }; }, From 88ac3bf541a2437dd207f32374b0c66e52a3d29c Mon Sep 17 00:00:00 2001 From: ymao1 Date: Wed, 17 Feb 2021 13:43:25 -0500 Subject: [PATCH 02/17] [Actions][Docs] Actions and Connectors API Docs (#90974) * Stubbing out asciidocs * wip * Finishing connector API docs * Cleanup * Removing experimental label * PR fixes * PR fixes * PR fixes --- docs/api/actions-and-connectors.asciidoc | 30 +++++++ .../actions-and-connectors/create.asciidoc | 68 +++++++++++++++ .../actions-and-connectors/delete.asciidoc | 35 ++++++++ .../actions-and-connectors/execute.asciidoc | 83 +++++++++++++++++++ docs/api/actions-and-connectors/get.asciidoc | 50 +++++++++++ .../actions-and-connectors/get_all.asciidoc | 52 ++++++++++++ docs/api/actions-and-connectors/list.asciidoc | 59 +++++++++++++ .../actions-and-connectors/update.asciidoc | 68 +++++++++++++++ .../user/alerting/action-types/email.asciidoc | 1 + .../user/alerting/action-types/index.asciidoc | 1 + docs/user/alerting/action-types/jira.asciidoc | 1 + .../alerting/action-types/pagerduty.asciidoc | 1 + .../alerting/action-types/resilient.asciidoc | 1 + .../alerting/action-types/servicenow.asciidoc | 1 + .../user/alerting/action-types/slack.asciidoc | 1 + .../user/alerting/action-types/teams.asciidoc | 1 + .../alerting/action-types/webhook.asciidoc | 1 + docs/user/api.asciidoc | 1 + 18 files changed, 455 insertions(+) create mode 100644 docs/api/actions-and-connectors.asciidoc create mode 100644 docs/api/actions-and-connectors/create.asciidoc create mode 100644 docs/api/actions-and-connectors/delete.asciidoc create mode 100644 docs/api/actions-and-connectors/execute.asciidoc create mode 100644 docs/api/actions-and-connectors/get.asciidoc create mode 100644 docs/api/actions-and-connectors/get_all.asciidoc create mode 100644 docs/api/actions-and-connectors/list.asciidoc create mode 100644 docs/api/actions-and-connectors/update.asciidoc diff --git a/docs/api/actions-and-connectors.asciidoc b/docs/api/actions-and-connectors.asciidoc new file mode 100644 index 00000000000000..17e7ea1b7672a3 --- /dev/null +++ b/docs/api/actions-and-connectors.asciidoc @@ -0,0 +1,30 @@ +[[actions-and-connectors-api]] +== Action and connector APIs + +Manage Actions and Connectors. + +The following action APIs are available: + +* <> to retrieve a single action by ID + +* <> to retrieve all actions + +* <> to retrieve a list of all action types + +* <> to create actions + +* <> to update the attributes for an existing action + +* <> to execute an action by ID + +* <> to delete an action by ID + +For information about the actions and connectors that {kib} supports, refer to <>. + +include::actions-and-connectors/get.asciidoc[] +include::actions-and-connectors/get_all.asciidoc[] +include::actions-and-connectors/list.asciidoc[] +include::actions-and-connectors/create.asciidoc[] +include::actions-and-connectors/update.asciidoc[] +include::actions-and-connectors/execute.asciidoc[] +include::actions-and-connectors/delete.asciidoc[] diff --git a/docs/api/actions-and-connectors/create.asciidoc b/docs/api/actions-and-connectors/create.asciidoc new file mode 100644 index 00000000000000..af5ddd050e40ec --- /dev/null +++ b/docs/api/actions-and-connectors/create.asciidoc @@ -0,0 +1,68 @@ +[[actions-and-connectors-api-create]] +=== Create action API +++++ +Create action API +++++ + +Creates an action. + +[[actions-and-connectors-api-create-request]] +==== Request + +`POST :/api/actions/action` + +[[actions-and-connectors-api-create-request-body]] +==== Request body + +`name`:: + (Required, string) The display name for the action. + +`actionTypeId`:: + (Required, string) The action type ID for the action. + +`config`:: + (Required, object) The configuration for the action. Configuration properties vary depending on + the action type. For information about the configuration properties, refer to <>. + +`secrets`:: + (Required, object) The secrets configuration for the action. Secrets configuration properties vary + depending on the action type. For information about the secrets configuration properties, refer to <>. + +[[actions-and-connectors-api-create-request-codes]] +==== Response code + +`200`:: + Indicates a successful call. + +[[actions-and-connectors-api-create-example]] +==== Example + +[source,sh] +-------------------------------------------------- +$ curl -X POST api/actions/action -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d ' +{ + "name": "my-action", + "actionTypeId": ".index", + "config": { + "index": "test-index" + } +}' +-------------------------------------------------- +// KIBANA + +The API returns the following: + +[source,sh] +-------------------------------------------------- +{ + "id": "c55b6eb0-6bad-11eb-9f3b-611eebc6c3ad", + "actionTypeId": ".index", + "name": "my-action", + "config": { + "index": "test-index", + "refresh": false, + "executionTimeField": null + }, + "isPreconfigured": false +} +-------------------------------------------------- \ No newline at end of file diff --git a/docs/api/actions-and-connectors/delete.asciidoc b/docs/api/actions-and-connectors/delete.asciidoc new file mode 100644 index 00000000000000..e90b9ae44c5bd3 --- /dev/null +++ b/docs/api/actions-and-connectors/delete.asciidoc @@ -0,0 +1,35 @@ +[[actions-and-connectors-api-delete]] +=== Delete action API +++++ +Delete action API +++++ + +Deletes an action by ID. + +WARNING: When you delete an action, _it cannot be recovered_. + +[[actions-and-connectors-api-delete-request]] +==== Request + +`DELETE :/api/actions/action/` + +[[actions-and-connectors-api-delete-path-params]] +==== Path parameters + +`id`:: + (Required, string) The ID of the action. + +[[actions-and-connectors-api-delete-response-codes]] +==== Response code + +`200`:: + Indicates a successful call. + +==== Example + +[source,sh] +-------------------------------------------------- +$ curl -X DELETE api/actions/action/c55b6eb0-6bad-11eb-9f3b-611eebc6c3ad +-------------------------------------------------- +// KIBANA + diff --git a/docs/api/actions-and-connectors/execute.asciidoc b/docs/api/actions-and-connectors/execute.asciidoc new file mode 100644 index 00000000000000..12f1405eb44560 --- /dev/null +++ b/docs/api/actions-and-connectors/execute.asciidoc @@ -0,0 +1,83 @@ +[[actions-and-connectors-api-execute]] +=== Execute action API +++++ +Execute action API +++++ + +Executes an action by ID. + +[[actions-and-connectors-api-execute-request]] +==== Request + +`POST :/api/actions/action//_execute` + +[[actions-and-connectors-api-execute-params]] +==== Path parameters + +`id`:: + (Required, string) The ID of the action. + +[[actions-and-connectors-api-execute-request-body]] +==== Request body + +`params`:: + (Required, object) The parameters of the action. Parameter properties vary depending on + the action type. For information about the parameter properties, refer to <>. + +[[actions-and-connectors-api-execute-codes]] +==== Response code + +`200`:: + Indicates a successful call. + +[[actions-and-connectors-api-execute-example]] +==== Example + +[source,sh] +-------------------------------------------------- +$ curl -X POST api/actions/action/c55b6eb0-6bad-11eb-9f3b-611eebc6c3ad/_execute -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d ' +{ + "params": { + "documents": [ + { + "id": "test_doc_id", + "name": "test_doc_name", + "message": "hello, world" + } + ] + } +}' +-------------------------------------------------- +// KIBANA + +The API returns the following: + +[source,sh] +-------------------------------------------------- +{ + "status": "ok", + "data": { + "took": 197, + "errors": false, + "items": [ + { + "index": { + "_index": "updated-index", + "_id": "iKyijHcBKCsmXNFrQe3T", + "_version": 1, + "result": "created", + "_shards": { + "total": 2, + "successful": 1, + "failed": 0 + }, + "_seq_no": 0, + "_primary_term": 1, + "status": 201 + } + } + ] + }, + "actionId": "c55b6eb0-6bad-11eb-9f3b-611eebc6c3ad" +} +-------------------------------------------------- \ No newline at end of file diff --git a/docs/api/actions-and-connectors/get.asciidoc b/docs/api/actions-and-connectors/get.asciidoc new file mode 100644 index 00000000000000..6be554e65db049 --- /dev/null +++ b/docs/api/actions-and-connectors/get.asciidoc @@ -0,0 +1,50 @@ +[[actions-and-connectors-api-get]] +=== Get action API +++++ +Get action API +++++ + +Retrieves an action by ID. + +[[actions-and-connectors-api-get-request]] +==== Request + +`GET :/api/actions/action/` + +[[actions-and-connectors-api-get-params]] +==== Path parameters + +`id`:: + (Required, string) The ID of the action. + +[[actions-and-connectors-api-get-codes]] +==== Response code + +`200`:: + Indicates a successful call. + +[[actions-and-connectors-api-get-example]] +==== Example + +[source,sh] +-------------------------------------------------- +$ curl -X GET api/actions/action/c55b6eb0-6bad-11eb-9f3b-611eebc6c3ad +-------------------------------------------------- +// KIBANA + +The API returns the following: + +[source,sh] +-------------------------------------------------- +{ + "id": "c55b6eb0-6bad-11eb-9f3b-611eebc6c3ad", + "actionTypeId": ".index", + "name": "my-action", + "config": { + "index": "test-index", + "refresh": false, + "executionTimeField": null + }, + "isPreconfigured": false +} +-------------------------------------------------- diff --git a/docs/api/actions-and-connectors/get_all.asciidoc b/docs/api/actions-and-connectors/get_all.asciidoc new file mode 100644 index 00000000000000..9863963c8395e6 --- /dev/null +++ b/docs/api/actions-and-connectors/get_all.asciidoc @@ -0,0 +1,52 @@ +[[actions-and-connectors-api-get-all]] +=== Get all actions API +++++ +Get all actions API +++++ + +Retrieves all actions. + +[[actions-and-connectors-api-get-all-request]] +==== Request + +`GET :/api/actions` + +[[actions-and-connectors-api-get-all-codes]] +==== Response code + +`200`:: + Indicates a successful call. + +[[actions-and-connectors-api-get-all-example]] +==== Example + +[source,sh] +-------------------------------------------------- +$ curl -X GET api/actions +-------------------------------------------------- +// KIBANA + +The API returns the following: + +[source,sh] +-------------------------------------------------- +[ + { + "id": "preconfigured-mail-action", + "actionTypeId": ".email", + "name": "email: preconfigured-mail-action", + "isPreconfigured": true + }, + { + "id": "c55b6eb0-6bad-11eb-9f3b-611eebc6c3ad", + "actionTypeId": ".index", + "name": "my-action", + "config": { + "index": "test-index", + "refresh": false, + "executionTimeField": null + }, + "isPreconfigured": false + } +] +-------------------------------------------------- diff --git a/docs/api/actions-and-connectors/list.asciidoc b/docs/api/actions-and-connectors/list.asciidoc new file mode 100644 index 00000000000000..b800b7ff3b4f2f --- /dev/null +++ b/docs/api/actions-and-connectors/list.asciidoc @@ -0,0 +1,59 @@ +[[actions-and-connectors-api-list]] +=== List action types API +++++ +List all action types API +++++ + +Retrieves a list of all action types. + +[[actions-and-connectors-api-list-request]] +==== Request + +`GET :/api/actions/list_action_types` + +[[actions-and-connectors-api-list-codes]] +==== Response code + +`200`:: + Indicates a successful call. + +[[actions-and-connectors-api-list-example]] +==== Example + +[source,sh] +-------------------------------------------------- +$ curl -X GET api/actions/list_action_types +-------------------------------------------------- +// KIBANA + +The API returns the following: + +[source,sh] +-------------------------------------------------- +[ + { + "id": ".email", <1> + "name": "Email", <2> + "minimumLicenseRequired": "gold", <3> + "enabled": false, <4> + "enabledInConfig": true, <5> + "enabledInLicense": false <6> + }, + { + "id": ".index", + "name": "Index", + "minimumLicenseRequired": "basic", + "enabled": true, + "enabledInConfig": true, + "enabledInLicense": true + } +] +-------------------------------------------------- + + +<1> `id` - The unique ID of the action type. +<2> `name` - The name of the action type. +<3> `minimumLicenseRequired` - The license required to use the action type. +<4> `enabled` - Specifies if the action type is enabled or disabled in {kib}. +<5> `enabledInConfig` - Specifies if the action type is enabled or enabled in the {kib} .yml file. +<6> `enabledInLicense` - Specifies if the action type is enabled or disabled in the license. diff --git a/docs/api/actions-and-connectors/update.asciidoc b/docs/api/actions-and-connectors/update.asciidoc new file mode 100644 index 00000000000000..e08ec2f8da1b67 --- /dev/null +++ b/docs/api/actions-and-connectors/update.asciidoc @@ -0,0 +1,68 @@ +[[actions-and-connectors-api-update]] +=== Update action API +++++ +Update action API +++++ + +Updates the attributes for an existing action. + +[[actions-and-connectors-api-update-request]] +==== Request + +`PUT :/api/actions/action/` + +[[actions-and-connectors-api-update-params]] +==== Path parameters + +`id`:: + (Required, string) The ID of the action. + +[[actions-and-connectors-api-update-request-body]] +==== Request body + +`name`:: + (Required, string) The new name of the action. + +`config`:: + (Required, object) The new action configuration. Configuration properties vary depending on the action type. For information about the configuration properties, refer to <>. + +`secrets`:: + (Required, object) The updated secrets configuration for the action. Secrets properties vary depending on the action type. For information about the secrets configuration properties, refer to <>. + +[[actions-and-connectors-api-update-codes]] +==== Response code + +`200`:: + Indicates a successful call. + +[[actions-and-connectors-api-update-example]] +==== Example + +[source,sh] +-------------------------------------------------- +$ curl -X PUT api/actions/action/c55b6eb0-6bad-11eb-9f3b-611eebc6c3ad -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d ' +{ + "name": "updated-action", + "config": { + "index": "updated-index" + } +}' +-------------------------------------------------- +// KIBANA + +The API returns the following: + +[source,sh] +-------------------------------------------------- +{ + "id": "c55b6eb0-6bad-11eb-9f3b-611eebc6c3ad", + "actionTypeId": ".index", + "name": "updated-action", + "config": { + "index": "updated-index", + "refresh": false, + "executionTimeField": null + }, + "isPreconfigured": false +} +-------------------------------------------------- diff --git a/docs/user/alerting/action-types/email.asciidoc b/docs/user/alerting/action-types/email.asciidoc index d7a9373a6e2a99..3562be1e405f6f 100644 --- a/docs/user/alerting/action-types/email.asciidoc +++ b/docs/user/alerting/action-types/email.asciidoc @@ -37,6 +37,7 @@ Password:: password for 'login' type authentication. password: passwordkeystorevalue -- +[[email-connector-config-properties]] `config` defines the action type specific to the configuration and contains the following properties: [cols="2*<"] diff --git a/docs/user/alerting/action-types/index.asciidoc b/docs/user/alerting/action-types/index.asciidoc index 2c6da7c7c3026b..2f459edea28f14 100644 --- a/docs/user/alerting/action-types/index.asciidoc +++ b/docs/user/alerting/action-types/index.asciidoc @@ -30,6 +30,7 @@ Execution time field:: This field will be automatically set to the time the ale executionTimeField: somedate -- +[[index-connector-config-properties]] `config` defines the action type specific to the configuration and contains the following properties: [cols="2*<"] diff --git a/docs/user/alerting/action-types/jira.asciidoc b/docs/user/alerting/action-types/jira.asciidoc index 65e5ee4fc4a013..6e47d5618d5982 100644 --- a/docs/user/alerting/action-types/jira.asciidoc +++ b/docs/user/alerting/action-types/jira.asciidoc @@ -33,6 +33,7 @@ API token (or password):: Jira API authentication token (or password) for HTTP apiToken: tokenkeystorevalue -- +[[jira-connector-config-properties]] `config` defines the action type specific to the configuration and contains the following properties: [cols="2*<"] diff --git a/docs/user/alerting/action-types/pagerduty.asciidoc b/docs/user/alerting/action-types/pagerduty.asciidoc index aad192dbddb30f..e1078a55ddd0d5 100644 --- a/docs/user/alerting/action-types/pagerduty.asciidoc +++ b/docs/user/alerting/action-types/pagerduty.asciidoc @@ -150,6 +150,7 @@ Integration Key:: A 32 character PagerDuty Integration Key for an integration routingKey: testroutingkey -- +[[pagerduty-connector-config-properties]] `config` defines the action type specific to the configuration. `config` contains `apiURL`, a string that corresponds to *API URL*. diff --git a/docs/user/alerting/action-types/resilient.asciidoc b/docs/user/alerting/action-types/resilient.asciidoc index b5ddb76d49b0cd..112246ab91162e 100644 --- a/docs/user/alerting/action-types/resilient.asciidoc +++ b/docs/user/alerting/action-types/resilient.asciidoc @@ -33,6 +33,7 @@ API key secret:: The authentication key secret for HTTP Basic authentication. apiKeySecret: tokenkeystorevalue -- +[[resilient-connector-config-properties]] `config` defines the action type specific to the configuration and contains the following properties: [cols="2*<"] diff --git a/docs/user/alerting/action-types/servicenow.asciidoc b/docs/user/alerting/action-types/servicenow.asciidoc index 0acb92bcdb5ee5..5d8782c14e5815 100644 --- a/docs/user/alerting/action-types/servicenow.asciidoc +++ b/docs/user/alerting/action-types/servicenow.asciidoc @@ -31,6 +31,7 @@ Password:: Password for HTTP Basic authentication. password: passwordkeystorevalue -- +[[servicenow-connector-config-properties]] `config` defines the action type specific to the configuration and contains the following properties: [cols="2*<"] diff --git a/docs/user/alerting/action-types/slack.asciidoc b/docs/user/alerting/action-types/slack.asciidoc index a1fe7a2521b22a..6a38e5c827ab28 100644 --- a/docs/user/alerting/action-types/slack.asciidoc +++ b/docs/user/alerting/action-types/slack.asciidoc @@ -26,6 +26,7 @@ Webhook URL:: The URL of the incoming webhook. See https://api.slack.com/messa webhookUrl: 'https://hooks.slack.com/services/abcd/efgh/ijklmnopqrstuvwxyz' -- +[[slack-connector-config-properties]] `config` defines the action type specific to the configuration. `config` contains `webhookUrl`, a string that corresponds to *Webhook URL*. diff --git a/docs/user/alerting/action-types/teams.asciidoc b/docs/user/alerting/action-types/teams.asciidoc index 6706dd2e5643fd..e1ce91fc0c1231 100644 --- a/docs/user/alerting/action-types/teams.asciidoc +++ b/docs/user/alerting/action-types/teams.asciidoc @@ -26,6 +26,7 @@ Webhook URL:: The URL of the incoming webhook. See https://docs.microsoft.com/ webhookUrl: 'https://outlook.office.com/webhook/abcd@0123456/IncomingWebhook/abcdefgh/ijklmnopqrstuvwxyz' -- +[[teams-connector-config-properties]] `config` defines the action type specific to the configuration. `config` contains `webhookUrl`, a string that corresponds to *Webhook URL*. diff --git a/docs/user/alerting/action-types/webhook.asciidoc b/docs/user/alerting/action-types/webhook.asciidoc index fff6814325ea45..2d626d53d1c77e 100644 --- a/docs/user/alerting/action-types/webhook.asciidoc +++ b/docs/user/alerting/action-types/webhook.asciidoc @@ -36,6 +36,7 @@ Password:: An optional password. If set, HTTP basic authentication is used. Cur password: passwordkeystorevalue -- +[[webhook-connector-config-properties]] `config` defines the action type specific to the configuration and contains the following properties: [cols="2*<"] diff --git a/docs/user/api.asciidoc b/docs/user/api.asciidoc index 20f1fc89367f29..2ae83bee1e06c7 100644 --- a/docs/user/api.asciidoc +++ b/docs/user/api.asciidoc @@ -36,6 +36,7 @@ include::{kib-repo-dir}/api/features.asciidoc[] include::{kib-repo-dir}/api/spaces-management.asciidoc[] include::{kib-repo-dir}/api/role-management.asciidoc[] include::{kib-repo-dir}/api/saved-objects.asciidoc[] +include::{kib-repo-dir}/api/actions-and-connectors.asciidoc[] include::{kib-repo-dir}/api/dashboard-api.asciidoc[] include::{kib-repo-dir}/api/logstash-configuration-management.asciidoc[] include::{kib-repo-dir}/api/url-shortening.asciidoc[] From 119199ef41c11df2d0fc4cd4dc55d2db6c500f3a Mon Sep 17 00:00:00 2001 From: Dmitry Date: Wed, 17 Feb 2021 19:45:06 +0100 Subject: [PATCH 03/17] [coverage] change worker, save json files in original path (#91683) * [coverage] write data to original path * [coverage] change worker size --- .ci/Jenkinsfile_coverage | 2 +- test/functional/services/remote/remote.ts | 15 +++++++++++---- test/scripts/jenkins_ci_group.sh | 8 -------- test/scripts/jenkins_unit.sh | 2 +- test/scripts/jenkins_xpack_ci_group.sh | 8 -------- 5 files changed, 13 insertions(+), 22 deletions(-) diff --git a/.ci/Jenkinsfile_coverage b/.ci/Jenkinsfile_coverage index b804e3071448e7..0aa962a58f53cc 100644 --- a/.ci/Jenkinsfile_coverage +++ b/.ci/Jenkinsfile_coverage @@ -10,7 +10,7 @@ kibanaPipeline(timeoutMinutes: 300) { "TIME_STAMP=${timestamp}", 'CODE_COVERAGE=1', // Enables coverage. Needed for multiple ci scripts, such as remote.ts, test/scripts/*.sh, schema.js, etc. ]) { - workers.base(name: 'coverage-worker', size: 'l', ramDisk: false, bootstrapped: false) { + workers.base(name: 'coverage-worker', size: 'xl', ramDisk: false, bootstrapped: false) { catchError { kibanaPipeline.bash(""" diff --git a/test/functional/services/remote/remote.ts b/test/functional/services/remote/remote.ts index f731ffade6efc7..5bf99b4bf1136b 100644 --- a/test/functional/services/remote/remote.ts +++ b/test/functional/services/remote/remote.ts @@ -37,14 +37,21 @@ export async function RemoteProvider({ getService }: FtrProviderContext) { }; const writeCoverage = (coverageJson: string) => { - if (!Fs.existsSync(coverageDir)) { - Fs.mkdirSync(coverageDir, { recursive: true }); + // on CI we make hard link clone and run tests from kibana${process.env.CI_GROUP} root path + const re = new RegExp(`kibana${process.env.CI_GROUP}`, 'g'); + const dir = process.env.CI ? coverageDir.replace(re, 'kibana') : coverageDir; + + if (!Fs.existsSync(dir)) { + Fs.mkdirSync(dir, { recursive: true }); } + const id = coverageCounter++; const timestamp = Date.now(); - const path = resolve(coverageDir, `${id}.${timestamp}.coverage.json`); + const path = resolve(dir, `${id}.${timestamp}.coverage.json`); log.info('writing coverage to', path); - Fs.writeFileSync(path, JSON.stringify(JSON.parse(coverageJson), null, 2)); + + const jsonString = process.env.CI ? coverageJson.replace(re, 'kibana') : coverageJson; + Fs.writeFileSync(path, JSON.stringify(JSON.parse(jsonString), null, 2)); }; const browserConfig: BrowserConfig = { diff --git a/test/scripts/jenkins_ci_group.sh b/test/scripts/jenkins_ci_group.sh index 4faf645975c778..58dcc9f52c0893 100755 --- a/test/scripts/jenkins_ci_group.sh +++ b/test/scripts/jenkins_ci_group.sh @@ -29,14 +29,6 @@ else echo " -> running tests from the clone folder" node scripts/functional_tests --debug --include-tag "ciGroup$CI_GROUP" --exclude-tag "skipCoverage" || true; - if [[ -d target/kibana-coverage/functional ]]; then - echo " -> replacing kibana${CI_GROUP} with kibana in json files" - sed -i "s|kibana${CI_GROUP}|kibana|g" target/kibana-coverage/functional/*.json - echo " -> copying coverage to the original folder" - mkdir -p ../kibana/target/kibana-coverage/functional - mv target/kibana-coverage/functional/* ../kibana/target/kibana-coverage/functional/ - fi - echo " -> moving junit output, silently fail in case of no report" mkdir -p ../kibana/target/junit mv target/junit/* ../kibana/target/junit/ || echo "copying junit failed" diff --git a/test/scripts/jenkins_unit.sh b/test/scripts/jenkins_unit.sh index a483f8378b8b41..3300ed2d0884f9 100755 --- a/test/scripts/jenkins_unit.sh +++ b/test/scripts/jenkins_unit.sh @@ -28,7 +28,7 @@ if [[ -z "$CODE_COVERAGE" ]] ; then ./test/scripts/checks/test_hardening.sh else echo " -> Running jest tests with coverage" - node scripts/jest --ci --verbose --maxWorkers=6 --coverage || true; + node scripts/jest --ci --verbose --maxWorkers=8 --coverage || true; echo " -> Running jest integration tests with coverage" node scripts/jest_integration --ci --verbose --coverage || true; diff --git a/test/scripts/jenkins_xpack_ci_group.sh b/test/scripts/jenkins_xpack_ci_group.sh index 648605135b3595..0198a5d0ac5fac 100755 --- a/test/scripts/jenkins_xpack_ci_group.sh +++ b/test/scripts/jenkins_xpack_ci_group.sh @@ -25,14 +25,6 @@ else echo " -> running tests from the clone folder" node scripts/functional_tests --debug --include-tag "ciGroup$CI_GROUP" --exclude-tag "skipCoverage" || true; - if [[ -d ../target/kibana-coverage/functional ]]; then - echo " -> replacing kibana${CI_GROUP} with kibana in json files" - sed -i "s|kibana${CI_GROUP}|kibana|g" ../target/kibana-coverage/functional/*.json - echo " -> copying coverage to the original folder" - mkdir -p ../../kibana/target/kibana-coverage/functional - mv ../target/kibana-coverage/functional/* ../../kibana/target/kibana-coverage/functional/ - fi - echo " -> moving junit output, silently fail in case of no report" mkdir -p ../../kibana/target/junit mv ../target/junit/* ../../kibana/target/junit/ || echo "copying junit failed" From 03c423f11d9d02c84e8499ed07323013d537c494 Mon Sep 17 00:00:00 2001 From: Dario Gieselaar Date: Wed, 17 Feb 2021 20:11:54 +0100 Subject: [PATCH 04/17] [APM] use top_metrics aggregation where appropriate (#91479) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Søren Louv-Jansen --- .../lib/environments/get_all_environments.ts | 4 ++-- .../__snapshots__/queries.test.ts.snap | 18 +++++++------- .../get_destination_map.ts | 21 ++++++++-------- .../get_service_transaction_stats.ts | 16 +++++++------ .../__snapshots__/queries.test.ts.snap | 24 +++++++++++-------- .../get_transaction_group_stats.ts | 18 +++++++------- .../distribution/get_buckets/index.ts | 13 ++++++---- x-pack/plugins/apm/server/routes/services.ts | 1 + .../traces/__snapshots__/top_traces.snap | 2 +- .../tests/transactions/distribution.ts | 8 +++---- 10 files changed, 69 insertions(+), 56 deletions(-) diff --git a/x-pack/plugins/apm/server/lib/environments/get_all_environments.ts b/x-pack/plugins/apm/server/lib/environments/get_all_environments.ts index 8fedcf6224e3c9..1bf01c24776fb0 100644 --- a/x-pack/plugins/apm/server/lib/environments/get_all_environments.ts +++ b/x-pack/plugins/apm/server/lib/environments/get_all_environments.ts @@ -31,8 +31,8 @@ export async function getAllEnvironments({ includeMissing?: boolean; }) { const spanName = serviceName - ? 'get_all_environments_for_all_services' - : 'get_all_environments_for_service'; + ? 'get_all_environments_for_service' + : 'get_all_environments_for_all_services'; return withApmSpan(spanName, async () => { const { apmEventClient, config } = setup; const maxServiceEnvironments = config['xpack.apm.maxServiceEnvironments']; diff --git a/x-pack/plugins/apm/server/lib/services/__snapshots__/queries.test.ts.snap b/x-pack/plugins/apm/server/lib/services/__snapshots__/queries.test.ts.snap index 606ce870351564..3e68831ee7cba7 100644 --- a/x-pack/plugins/apm/server/lib/services/__snapshots__/queries.test.ts.snap +++ b/x-pack/plugins/apm/server/lib/services/__snapshots__/queries.test.ts.snap @@ -101,14 +101,6 @@ Array [ "aggs": Object { "transactionType": Object { "aggs": Object { - "agentName": Object { - "top_hits": Object { - "docvalue_fields": Array [ - "agent.name", - ], - "size": 1, - }, - }, "avg_duration": Object { "avg": Object { "field": "transaction.duration.us", @@ -129,6 +121,16 @@ Array [ ], }, }, + "sample": Object { + "top_metrics": Object { + "metrics": Object { + "field": "agent.name", + }, + "sort": Object { + "@timestamp": "desc", + }, + }, + }, "timeseries": Object { "aggs": Object { "avg_duration": Object { diff --git a/x-pack/plugins/apm/server/lib/services/get_service_dependencies/get_destination_map.ts b/x-pack/plugins/apm/server/lib/services/get_service_dependencies/get_destination_map.ts index ef2b50cbdbedfe..aa53e8da6cad05 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_dependencies/get_destination_map.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_dependencies/get_destination_map.ts @@ -71,14 +71,13 @@ export const getDestinationMap = ({ ], }, aggs: { - docs: { - top_hits: { - docvalue_fields: [ - SPAN_TYPE, - SPAN_SUBTYPE, - SPAN_ID, + sample: { + top_metrics: { + metrics: [ + { field: SPAN_TYPE }, + { field: SPAN_SUBTYPE }, + { field: SPAN_ID }, ] as const, - _source: false, sort: { '@timestamp': 'desc', }, @@ -93,15 +92,15 @@ export const getDestinationMap = ({ const outgoingConnections = response.aggregations?.connections.buckets.map((bucket) => { - const doc = bucket.docs.hits.hits[0]; + const fieldValues = bucket.sample.top[0].metrics; return { [SPAN_DESTINATION_SERVICE_RESOURCE]: String( bucket.key[SPAN_DESTINATION_SERVICE_RESOURCE] ), - [SPAN_ID]: String(doc.fields[SPAN_ID]?.[0]), - [SPAN_TYPE]: String(doc.fields[SPAN_TYPE]?.[0] ?? ''), - [SPAN_SUBTYPE]: String(doc.fields[SPAN_SUBTYPE]?.[0] ?? ''), + [SPAN_ID]: (fieldValues[SPAN_ID] ?? '') as string, + [SPAN_TYPE]: (fieldValues[SPAN_TYPE] ?? '') as string, + [SPAN_SUBTYPE]: (fieldValues[SPAN_SUBTYPE] ?? '') as string, }; }) ?? []; diff --git a/x-pack/plugins/apm/server/lib/services/get_services/get_service_transaction_stats.ts b/x-pack/plugins/apm/server/lib/services/get_services/get_service_transaction_stats.ts index 36540b01a07cc9..acfdc1d8c1710a 100644 --- a/x-pack/plugins/apm/server/lib/services/get_services/get_service_transaction_stats.ts +++ b/x-pack/plugins/apm/server/lib/services/get_services/get_service_transaction_stats.ts @@ -98,10 +98,12 @@ export async function getServiceTransactionStats({ missing: '', }, }, - agentName: { - top_hits: { - docvalue_fields: [AGENT_NAME] as const, - size: 1, + sample: { + top_metrics: { + metrics: { field: AGENT_NAME } as const, + sort: { + '@timestamp': 'desc', + }, }, }, timeseries: { @@ -139,9 +141,9 @@ export async function getServiceTransactionStats({ environments: topTransactionTypeBucket.environments.buckets .map((environmentBucket) => environmentBucket.key as string) .filter(Boolean), - agentName: topTransactionTypeBucket.agentName.hits.hits[0].fields[ - 'agent.name' - ]?.[0] as AgentName, + agentName: topTransactionTypeBucket.sample.top[0].metrics[ + AGENT_NAME + ] as AgentName, avgResponseTime: { value: topTransactionTypeBucket.avg_duration.value, timeseries: topTransactionTypeBucket.timeseries.buckets.map( diff --git a/x-pack/plugins/apm/server/lib/transaction_groups/__snapshots__/queries.test.ts.snap b/x-pack/plugins/apm/server/lib/transaction_groups/__snapshots__/queries.test.ts.snap index 89069d74bacf8b..443159611883fc 100644 --- a/x-pack/plugins/apm/server/lib/transaction_groups/__snapshots__/queries.test.ts.snap +++ b/x-pack/plugins/apm/server/lib/transaction_groups/__snapshots__/queries.test.ts.snap @@ -13,11 +13,13 @@ Array [ "transaction_groups": Object { "aggs": Object { "transaction_type": Object { - "top_hits": Object { - "_source": Array [ - "transaction.type", - ], - "size": 1, + "top_metrics": Object { + "metrics": Object { + "field": "transaction.type", + }, + "sort": Object { + "@timestamp": "desc", + }, }, }, }, @@ -222,11 +224,13 @@ Array [ "transaction_groups": Object { "aggs": Object { "transaction_type": Object { - "top_hits": Object { - "_source": Array [ - "transaction.type", - ], - "size": 1, + "top_metrics": Object { + "metrics": Object { + "field": "transaction.type", + }, + "sort": Object { + "@timestamp": "desc", + }, }, }, }, diff --git a/x-pack/plugins/apm/server/lib/transaction_groups/get_transaction_group_stats.ts b/x-pack/plugins/apm/server/lib/transaction_groups/get_transaction_group_stats.ts index ee19a6a8d15918..5ee46bf1a5918a 100644 --- a/x-pack/plugins/apm/server/lib/transaction_groups/get_transaction_group_stats.ts +++ b/x-pack/plugins/apm/server/lib/transaction_groups/get_transaction_group_stats.ts @@ -69,9 +69,13 @@ export function getCounts({ request, setup }: MetricParams) { return withApmSpan('get_transaction_group_transaction_count', async () => { const params = mergeRequestWithAggs(request, { transaction_type: { - top_hits: { - size: 1, - _source: [TRANSACTION_TYPE], + top_metrics: { + sort: { + '@timestamp': 'desc', + }, + metrics: { + field: TRANSACTION_TYPE, + } as const, }, }, }); @@ -81,14 +85,12 @@ export function getCounts({ request, setup }: MetricParams) { return arrayUnionToCallable( response.aggregations?.transaction_groups.buckets ?? [] ).map((bucket) => { - // type is Transaction | APMBaseDoc because it could be a metric document - const source = (bucket.transaction_type.hits.hits[0] - ._source as unknown) as { transaction: { type: string } }; - return { key: bucket.key as BucketKey, count: bucket.doc_count, - transactionType: source.transaction.type, + transactionType: bucket.transaction_type.top[0].metrics[ + TRANSACTION_TYPE + ] as string, }; }); }); diff --git a/x-pack/plugins/apm/server/lib/transactions/distribution/get_buckets/index.ts b/x-pack/plugins/apm/server/lib/transactions/distribution/get_buckets/index.ts index 22a34ded4c20d5..d1d23f538e96b0 100644 --- a/x-pack/plugins/apm/server/lib/transactions/distribution/get_buckets/index.ts +++ b/x-pack/plugins/apm/server/lib/transactions/distribution/get_buckets/index.ts @@ -109,8 +109,11 @@ export async function getBuckets({ }), aggs: { samples: { - top_hits: { - _source: [TRANSACTION_ID, TRACE_ID], + top_metrics: { + metrics: [ + { field: TRANSACTION_ID }, + { field: TRACE_ID }, + ] as const, size: 10, sort: { _score: 'desc', @@ -128,9 +131,9 @@ export async function getBuckets({ response.aggregations?.distribution.buckets.map((bucket) => { return { key: bucket.key, - samples: bucket.samples.hits.hits.map((hit) => ({ - traceId: hit._source.trace.id, - transactionId: hit._source.transaction.id, + samples: bucket.samples.top.map((sample) => ({ + traceId: sample.metrics[TRACE_ID] as string, + transactionId: sample.metrics[TRANSACTION_ID] as string, })), }; }) ?? [] diff --git a/x-pack/plugins/apm/server/routes/services.ts b/x-pack/plugins/apm/server/routes/services.ts index ff064e0571d138..84ccb4b06c2e6a 100644 --- a/x-pack/plugins/apm/server/routes/services.ts +++ b/x-pack/plugins/apm/server/routes/services.ts @@ -304,6 +304,7 @@ export const serviceErrorGroupsRoute = createRoute({ transactionType, }, } = context.params; + return getServiceErrorGroups({ serviceName, setup, diff --git a/x-pack/test/apm_api_integration/tests/traces/__snapshots__/top_traces.snap b/x-pack/test/apm_api_integration/tests/traces/__snapshots__/top_traces.snap index c8104b9858027c..ad9eca1cc0900c 100644 --- a/x-pack/test/apm_api_integration/tests/traces/__snapshots__/top_traces.snap +++ b/x-pack/test/apm_api_integration/tests/traces/__snapshots__/top_traces.snap @@ -995,7 +995,7 @@ Array [ }, "serviceName": "kibana-frontend", "transactionName": "/app/dev_tools", - "transactionType": "page-load", + "transactionType": "route-change", "transactionsPerMinute": 0.0666666666666667, }, Object { diff --git a/x-pack/test/apm_api_integration/tests/transactions/distribution.ts b/x-pack/test/apm_api_integration/tests/transactions/distribution.ts index e46ec7a181fc00..56d5e217068a4b 100644 --- a/x-pack/test/apm_api_integration/tests/transactions/distribution.ts +++ b/x-pack/test/apm_api_integration/tests/transactions/distribution.ts @@ -83,16 +83,16 @@ export default function ApiTest({ getService }: FtrProviderContext) { .toMatchInline(` Array [ Object { - "traceId": "af0f18dc0841cfc1f567e7e1d55cfda7", - "transactionId": "925f02e5ac122897", + "traceId": "a4eb3781a21dc11d289293076fd1a1b3", + "transactionId": "21892bde4ff1364d", }, Object { "traceId": "ccd327537120e857bdfa407434dfb9a4", "transactionId": "c5f923159cc1b8a6", }, Object { - "traceId": "a4eb3781a21dc11d289293076fd1a1b3", - "transactionId": "21892bde4ff1364d", + "traceId": "af0f18dc0841cfc1f567e7e1d55cfda7", + "transactionId": "925f02e5ac122897", }, ] `); From a3dfecb03f2f2a17c29c0f89064b6dad201afda7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 17 Feb 2021 13:23:51 -0600 Subject: [PATCH 05/17] Update dependency @elastic/charts to v25 (#91557) --- package.json | 2 +- .../public/static/utils/transform_click_event.ts | 7 ++----- .../public/components/detailed_tooltip.tsx | 7 ++----- .../public/utils/get_legend_actions.tsx | 2 +- .../public/utils/use_color_picker.tsx | 2 +- src/plugins/vis_type_xy/public/vis_component.tsx | 16 +++------------- .../components/common/charts/duration_chart.tsx | 4 ++-- yarn.lock | 8 ++++---- 8 files changed, 16 insertions(+), 32 deletions(-) diff --git a/package.json b/package.json index cc8ab44c51c96a..a7959f047ab5c0 100644 --- a/package.json +++ b/package.json @@ -351,7 +351,7 @@ "@cypress/webpack-preprocessor": "^5.5.0", "@elastic/apm-rum": "^5.6.1", "@elastic/apm-rum-react": "^1.2.5", - "@elastic/charts": "24.6.0", + "@elastic/charts": "25.0.1", "@elastic/eslint-config-kibana": "link:packages/elastic-eslint-config-kibana", "@elastic/eslint-plugin-eui": "0.0.2", "@elastic/github-checks-reporter": "0.0.20b3", diff --git a/src/plugins/charts/public/static/utils/transform_click_event.ts b/src/plugins/charts/public/static/utils/transform_click_event.ts index e875967616bbdb..0c303b92bf1a1c 100644 --- a/src/plugins/charts/public/static/utils/transform_click_event.ts +++ b/src/plugins/charts/public/static/utils/transform_click_event.ts @@ -30,9 +30,6 @@ export interface BrushTriggerEvent { type AllSeriesAccessors = Array<[accessor: Accessor | AccessorFn, value: string | number]>; -// TODO: replace when exported from elastic/charts -const DEFAULT_SINGLE_PANEL_SM_VALUE = '__ECH_DEFAULT_SINGLE_PANEL_SM_VALUE__'; - /** * returns accessor value from string or function accessor * @param datum @@ -97,11 +94,11 @@ function getSplitChartValue({ | string | number | undefined { - if (smHorizontalAccessorValue !== DEFAULT_SINGLE_PANEL_SM_VALUE) { + if (smHorizontalAccessorValue !== undefined) { return smHorizontalAccessorValue; } - if (smVerticalAccessorValue !== DEFAULT_SINGLE_PANEL_SM_VALUE) { + if (smVerticalAccessorValue !== undefined) { return smVerticalAccessorValue; } diff --git a/src/plugins/vis_type_xy/public/components/detailed_tooltip.tsx b/src/plugins/vis_type_xy/public/components/detailed_tooltip.tsx index 0c1ab262755a73..c9ed82fcf58e55 100644 --- a/src/plugins/vis_type_xy/public/components/detailed_tooltip.tsx +++ b/src/plugins/vis_type_xy/public/components/detailed_tooltip.tsx @@ -27,9 +27,6 @@ interface TooltipData { value: string; } -// TODO: replace when exported from elastic/charts -const DEFAULT_SINGLE_PANEL_SM_VALUE = '__ECH_DEFAULT_SINGLE_PANEL_SM_VALUE__'; - export const getTooltipData = ( aspects: Aspects, header: TooltipValue | null, @@ -81,7 +78,7 @@ export const getTooltipData = ( if ( aspects.splitColumn && valueSeries.smHorizontalAccessorValue !== undefined && - valueSeries.smHorizontalAccessorValue !== DEFAULT_SINGLE_PANEL_SM_VALUE + valueSeries.smHorizontalAccessorValue !== undefined ) { data.push({ label: aspects.splitColumn.title, @@ -92,7 +89,7 @@ export const getTooltipData = ( if ( aspects.splitRow && valueSeries.smVerticalAccessorValue !== undefined && - valueSeries.smVerticalAccessorValue !== DEFAULT_SINGLE_PANEL_SM_VALUE + valueSeries.smVerticalAccessorValue !== undefined ) { data.push({ label: aspects.splitRow.title, diff --git a/src/plugins/vis_type_xy/public/utils/get_legend_actions.tsx b/src/plugins/vis_type_xy/public/utils/get_legend_actions.tsx index 9f557806cf1427..5c28ca77da0c4a 100644 --- a/src/plugins/vis_type_xy/public/utils/get_legend_actions.tsx +++ b/src/plugins/vis_type_xy/public/utils/get_legend_actions.tsx @@ -20,7 +20,7 @@ export const getLegendActions = ( onFilter: (data: ClickTriggerEvent, negate?: any) => void, getSeriesName: (series: XYChartSeriesIdentifier) => SeriesName ): LegendAction => { - return ({ series: xySeries }) => { + return ({ series: [xySeries] }) => { const [popoverOpen, setPopoverOpen] = useState(false); const [isfilterable, setIsfilterable] = useState(false); const series = xySeries as XYChartSeriesIdentifier; diff --git a/src/plugins/vis_type_xy/public/utils/use_color_picker.tsx b/src/plugins/vis_type_xy/public/utils/use_color_picker.tsx index 80e7e12adf799d..5028bc379c375d 100644 --- a/src/plugins/vis_type_xy/public/utils/use_color_picker.tsx +++ b/src/plugins/vis_type_xy/public/utils/use_color_picker.tsx @@ -36,7 +36,7 @@ export const useColorPicker = ( getSeriesName: (series: XYChartSeriesIdentifier) => SeriesName ): LegendColorPicker => useMemo( - () => ({ anchor, color, onClose, onChange, seriesIdentifier }) => { + () => ({ anchor, color, onClose, onChange, seriesIdentifiers: [seriesIdentifier] }) => { const seriesName = getSeriesName(seriesIdentifier as XYChartSeriesIdentifier); const handlChange = (newColor: string | null, event: BaseSyntheticEvent) => { if (!seriesName) { diff --git a/src/plugins/vis_type_xy/public/vis_component.tsx b/src/plugins/vis_type_xy/public/vis_component.tsx index c7ba5021196ff7..ab398101bac9d6 100644 --- a/src/plugins/vis_type_xy/public/vis_component.tsx +++ b/src/plugins/vis_type_xy/public/vis_component.tsx @@ -157,17 +157,12 @@ const VisComponent = (props: VisComponentProps) => { ( visData: Datatable, xAccessor: Accessor | AccessorFn, - splitSeriesAccessors: Array, - splitChartAccessor?: Accessor | AccessorFn + splitSeriesAccessors: Array ) => { const splitSeriesAccessorFnMap = getSplitSeriesAccessorFnMap(splitSeriesAccessors); return (series: XYChartSeriesIdentifier): ClickTriggerEvent | null => { if (xAccessor !== null) { - return getFilterFromSeriesFn(visData)( - series, - splitSeriesAccessorFnMap, - splitChartAccessor - ); + return getFilterFromSeriesFn(visData)(series, splitSeriesAccessorFnMap); } return null; @@ -373,12 +368,7 @@ const VisComponent = (props: VisComponentProps) => { config.aspects.series && (config.aspects.series?.length ?? 0) > 0 ? getLegendActions( canFilter, - getFilterEventData( - visData, - xAccessor, - splitSeriesAccessors, - splitChartColumnAccessor ?? splitChartRowAccessor - ), + getFilterEventData(visData, xAccessor, splitSeriesAccessors), handleFilterAction, getSeriesName ) diff --git a/x-pack/plugins/uptime/public/components/common/charts/duration_chart.tsx b/x-pack/plugins/uptime/public/components/common/charts/duration_chart.tsx index b91b50666cf07b..68b9ab0435aaac 100644 --- a/x-pack/plugins/uptime/public/components/common/charts/duration_chart.tsx +++ b/x-pack/plugins/uptime/public/components/common/charts/duration_chart.tsx @@ -15,8 +15,8 @@ import { Position, timeFormatter, Settings, - SeriesIdentifier, BrushEndListener, + LegendItemListener, } from '@elastic/charts'; import { getChartDateLabel } from '../../../lib/helper'; import { LocationDurationLine } from '../../../../common/types'; @@ -75,7 +75,7 @@ export const DurationChartComponent = ({ }); }; - const legendToggleVisibility = (legendItem: SeriesIdentifier | null) => { + const legendToggleVisibility: LegendItemListener = ([legendItem]) => { if (legendItem) { setHiddenLegends((prevState) => { if (prevState.includes(legendItem.specId)) { diff --git a/yarn.lock b/yarn.lock index 1a939e3dddf579..6cb2a6864eb752 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2138,10 +2138,10 @@ dependencies: object-hash "^1.3.0" -"@elastic/charts@24.6.0": - version "24.6.0" - resolved "https://registry.yarnpkg.com/@elastic/charts/-/charts-24.6.0.tgz#2123c72e69e1e4557be41ae55c085a5a9f75d3b6" - integrity sha512-fL0301EcHxJEYRzdlD4JIA3VXY4qwRPSkRrk8hvJNryTlQWEdyXZF3HNczk0IrgST5cfCOGAWG8IVtO59HxUJw== +"@elastic/charts@25.0.1": + version "25.0.1" + resolved "https://registry.yarnpkg.com/@elastic/charts/-/charts-25.0.1.tgz#7c61fc22887b7b1feba3e52fc1b44f21a9c1d0bc" + integrity sha512-UYGO9Yg2+cdJOOs9DjlYeB2Oy/3UMXTtF6/yWZt2iXh7mmW9jI5DqfjgG/9BFSCwQZHUKBZ58d5ZCQfe72maGA== dependencies: "@popperjs/core" "^2.4.0" chroma-js "^2.1.0" From f650c38e12ae09caa1e5bd76dc39f66639a0b9ba Mon Sep 17 00:00:00 2001 From: Nathan L Smith Date: Wed, 17 Feb 2021 14:28:50 -0600 Subject: [PATCH 06/17] Remove environment from uiFilters (#89647) --- .../plugins/apm/common/utils/queries.test.ts | 33 +++++ .../utils/queries.ts} | 30 +++- .../plugins/apm/common/utils/range_filter.ts | 16 -- .../app/ErrorGroupDetails/index.tsx | 5 +- .../app/correlations/error_correlations.tsx | 10 +- .../app/correlations/latency_correlations.tsx | 10 +- .../app/error_group_overview/index.tsx | 5 +- .../app/service_inventory/index.tsx | 11 +- .../index.tsx | 7 +- .../service_overview_errors_table/index.tsx | 4 +- ...ice_overview_instances_chart_and_table.tsx | 5 +- .../service_overview_throughput_chart.tsx | 5 +- .../index.tsx | 5 +- .../components/app/trace_overview/index.tsx | 5 +- .../use_transaction_list.ts | 5 +- .../shared/EnvironmentFilter/index.tsx | 5 +- .../use_transaction_breakdown.ts | 13 +- .../transaction_error_rate_chart/index.tsx | 13 +- .../url_params_context/resolve_url_params.ts | 3 +- .../url_params_context/url_params_context.tsx | 2 - .../use_error_group_distribution_fetcher.tsx | 5 +- .../use_service_metric_charts_fetcher.ts | 13 +- .../use_transaction_distribution_fetcher.ts | 12 +- .../use_transaction_latency_chart_fetcher.ts | 10 +- ...se_transaction_throughput_chart_fetcher.ts | 13 +- .../plugins/apm/public/utils/testHelpers.tsx | 4 +- .../chart_preview/get_transaction_duration.ts | 7 +- .../get_transaction_error_count.ts | 7 +- .../get_transaction_error_rate.ts | 7 +- .../alerts/register_error_count_alert_type.ts | 4 +- ...egister_transaction_duration_alert_type.ts | 4 +- ...ister_transaction_error_rate_alert_type.ts | 4 +- .../create_anomaly_detection_jobs.ts | 6 +- .../index.ts | 9 +- .../index.ts | 9 +- .../lib/environments/get_environments.ts | 5 +- .../errors/distribution/get_buckets.test.ts | 11 +- .../lib/errors/distribution/get_buckets.ts | 7 +- .../errors/distribution/get_distribution.ts | 3 + .../lib/errors/get_error_group_sample.ts | 7 +- .../apm/server/lib/errors/get_error_groups.ts | 8 +- .../helpers/aggregated_transactions/index.ts | 4 +- .../get_environment_ui_filter_es.test.ts | 32 ---- .../convert_ui_filters/get_es_filter.ts | 6 +- .../__snapshots__/queries.test.ts.snap | 140 +++++++++--------- .../server/lib/metrics/by_agent/default.ts | 17 ++- .../java/gc/fetch_and_transform_gc_metrics.ts | 3 + .../by_agent/java/gc/get_gc_rate_chart.ts | 3 + .../by_agent/java/gc/get_gc_time_chart.ts | 3 + .../by_agent/java/heap_memory/index.ts | 3 + .../server/lib/metrics/by_agent/java/index.ts | 21 ++- .../by_agent/java/non_heap_memory/index.ts | 3 + .../by_agent/java/thread_count/index.ts | 3 + .../lib/metrics/by_agent/shared/cpu/index.ts | 3 + .../metrics/by_agent/shared/memory/index.ts | 4 + .../metrics/fetch_and_transform_metrics.ts | 3 + .../get_metrics_chart_data_by_agent.ts | 11 +- .../get_service_count.ts | 4 +- .../get_transaction_coordinates.ts | 4 +- .../apm/server/lib/rum_client/has_rum_data.ts | 6 +- .../fetch_service_paths_from_trace_ids.ts | 4 +- .../lib/service_map/get_service_anomalies.ts | 16 +- .../server/lib/service_map/get_service_map.ts | 13 +- .../get_service_map_from_trace_ids.ts | 9 +- .../get_service_map_service_node_info.test.ts | 4 +- .../get_service_map_service_node_info.ts | 17 +-- .../lib/service_map/get_trace_sample_ids.ts | 9 +- .../__snapshots__/queries.test.ts.snap | 28 ++-- .../get_derived_service_annotations.ts | 7 +- .../annotations/get_stored_annotations.ts | 13 +- .../lib/services/get_service_agent_name.ts | 4 +- .../get_destination_map.ts | 11 +- .../get_service_dependencies/get_metrics.ts | 9 +- .../get_service_dependencies/index.ts | 2 +- .../get_service_error_groups/index.ts | 10 +- ...et_service_instance_system_metric_stats.ts | 6 +- .../get_service_instance_transaction_stats.ts | 6 +- .../services/get_service_instances/index.ts | 1 + .../services/get_service_metadata_details.ts | 4 +- .../services/get_service_metadata_icons.ts | 4 +- ...transaction_group_comparison_statistics.ts | 7 +- .../get_service_transaction_groups.ts | 7 +- .../services/get_service_transaction_types.ts | 4 +- .../get_services/get_health_statuses.ts | 17 +-- .../get_service_transaction_stats.ts | 9 +- .../get_services/get_services_items.ts | 6 +- .../server/lib/services/get_services/index.ts | 3 + .../apm/server/lib/services/get_throughput.ts | 11 +- .../apm/server/lib/traces/get_trace_items.ts | 6 +- .../__snapshots__/queries.test.ts.snap | 64 ++++---- .../server/lib/transaction_groups/fetcher.ts | 2 + .../lib/transaction_groups/get_error_rate.ts | 11 +- .../lib/transactions/breakdown/index.ts | 7 +- .../distribution/get_buckets/index.ts | 10 +- .../distribution/get_distribution_max.ts | 14 +- .../lib/transactions/distribution/index.ts | 4 + .../transactions/get_anomaly_data/fetcher.ts | 11 +- .../transactions/get_anomaly_data/index.ts | 20 +-- .../transactions/get_latency_charts/index.ts | 14 +- .../get_throughput_charts/index.ts | 16 +- .../lib/transactions/get_transaction/index.ts | 4 +- .../plugins/apm/server/projections/errors.ts | 7 +- .../plugins/apm/server/projections/metrics.ts | 7 +- .../projections/rum_page_load_transactions.ts | 6 +- .../apm/server/projections/services.ts | 4 +- .../apm/server/projections/transactions.ts | 11 +- .../plugins/apm/server/routes/correlations.ts | 9 +- .../apm/server/routes/create_apm_api.ts | 8 +- .../apm/server/routes/default_api_types.ts | 2 + x-pack/plugins/apm/server/routes/errors.ts | 17 ++- x-pack/plugins/apm/server/routes/metrics.ts | 6 +- .../plugins/apm/server/routes/service_map.ts | 4 +- x-pack/plugins/apm/server/routes/services.ts | 25 +++- x-pack/plugins/apm/server/routes/traces.ts | 8 +- .../plugins/apm/server/routes/transactions.ts | 56 ++++--- .../plugins/apm/server/utils/test_helpers.tsx | 2 +- .../tests/csm/has_rum_data.ts | 2 +- .../tests/feature_controls.ts | 8 +- .../tests/services/top_services.ts | 4 +- .../transactions/__snapshots__/latency.snap | 4 +- .../tests/transactions/latency.ts | 47 +++--- .../tests/transactions/throughput.ts | 4 +- 122 files changed, 757 insertions(+), 528 deletions(-) create mode 100644 x-pack/plugins/apm/common/utils/queries.test.ts rename x-pack/plugins/apm/{server/lib/helpers/convert_ui_filters/get_environment_ui_filter_es.ts => common/utils/queries.ts} (52%) delete mode 100644 x-pack/plugins/apm/common/utils/range_filter.ts delete mode 100644 x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_environment_ui_filter_es.test.ts diff --git a/x-pack/plugins/apm/common/utils/queries.test.ts b/x-pack/plugins/apm/common/utils/queries.test.ts new file mode 100644 index 00000000000000..546c8627def69c --- /dev/null +++ b/x-pack/plugins/apm/common/utils/queries.test.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { SERVICE_ENVIRONMENT } from '../elasticsearch_fieldnames'; +import { ENVIRONMENT_NOT_DEFINED } from '../environment_filter_values'; +import { environmentQuery } from './queries'; + +describe('environmentQuery', () => { + describe('when environment is undefined', () => { + it('returns an empty query', () => { + expect(environmentQuery()).toEqual([]); + }); + }); + + it('creates a query for a service environment', () => { + expect(environmentQuery('test')).toEqual([ + { + term: { [SERVICE_ENVIRONMENT]: 'test' }, + }, + ]); + }); + + it('creates a query for missing service environments', () => { + expect(environmentQuery(ENVIRONMENT_NOT_DEFINED.value)[0]).toHaveProperty( + ['bool', 'must_not', 'exists', 'field'], + SERVICE_ENVIRONMENT + ); + }); +}); diff --git a/x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_environment_ui_filter_es.ts b/x-pack/plugins/apm/common/utils/queries.ts similarity index 52% rename from x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_environment_ui_filter_es.ts rename to x-pack/plugins/apm/common/utils/queries.ts index 3dea3344085c92..dbbbf324b964a9 100644 --- a/x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_environment_ui_filter_es.ts +++ b/x-pack/plugins/apm/common/utils/queries.ts @@ -5,19 +5,41 @@ * 2.0. */ -import { ESFilter } from '../../../../../../typings/elasticsearch'; +import { ESFilter } from '../../../../typings/elasticsearch'; import { ENVIRONMENT_NOT_DEFINED, ENVIRONMENT_ALL, -} from '../../../../common/environment_filter_values'; -import { SERVICE_ENVIRONMENT } from '../../../../common/elasticsearch_fieldnames'; +} from '../environment_filter_values'; +import { SERVICE_ENVIRONMENT } from '../elasticsearch_fieldnames'; -export function getEnvironmentUiFilterES(environment?: string): ESFilter[] { +type QueryContainer = ESFilter; + +export function environmentQuery(environment?: string): QueryContainer[] { if (!environment || environment === ENVIRONMENT_ALL.value) { return []; } + if (environment === ENVIRONMENT_NOT_DEFINED.value) { return [{ bool: { must_not: { exists: { field: SERVICE_ENVIRONMENT } } } }]; } + return [{ term: { [SERVICE_ENVIRONMENT]: environment } }]; } + +export function rangeQuery( + start: number, + end: number, + field = '@timestamp' +): QueryContainer[] { + return [ + { + range: { + [field]: { + gte: start, + lte: end, + format: 'epoch_millis', + }, + }, + }, + ]; +} diff --git a/x-pack/plugins/apm/common/utils/range_filter.ts b/x-pack/plugins/apm/common/utils/range_filter.ts deleted file mode 100644 index 8d5b7d5e1beb1e..00000000000000 --- a/x-pack/plugins/apm/common/utils/range_filter.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * 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. - */ - -export function rangeFilter(start: number, end: number) { - return { - '@timestamp': { - gte: start, - lte: end, - format: 'epoch_millis', - }, - }; -} diff --git a/x-pack/plugins/apm/public/components/app/ErrorGroupDetails/index.tsx b/x-pack/plugins/apm/public/components/app/ErrorGroupDetails/index.tsx index 3edf21eae7279f..4cd2db43621a8f 100644 --- a/x-pack/plugins/apm/public/components/app/ErrorGroupDetails/index.tsx +++ b/x-pack/plugins/apm/public/components/app/ErrorGroupDetails/index.tsx @@ -68,7 +68,7 @@ type ErrorGroupDetailsProps = RouteComponentProps<{ export function ErrorGroupDetails({ location, match }: ErrorGroupDetailsProps) { const { serviceName, groupId } = match.params; const { urlParams, uiFilters } = useUrlParams(); - const { start, end } = urlParams; + const { environment, start, end } = urlParams; const { data: errorGroupData } = useFetcher( (callApmApi) => { @@ -81,6 +81,7 @@ export function ErrorGroupDetails({ location, match }: ErrorGroupDetailsProps) { groupId, }, query: { + environment, start, end, uiFilters: JSON.stringify(uiFilters), @@ -89,7 +90,7 @@ export function ErrorGroupDetails({ location, match }: ErrorGroupDetailsProps) { }); } }, - [serviceName, start, end, groupId, uiFilters] + [environment, serviceName, start, end, groupId, uiFilters] ); const { errorDistributionData } = useErrorGroupDistributionFetcher({ diff --git a/x-pack/plugins/apm/public/components/app/correlations/error_correlations.tsx b/x-pack/plugins/apm/public/components/app/correlations/error_correlations.tsx index 7386209310c1fb..9b80ee6fc31b85 100644 --- a/x-pack/plugins/apm/public/components/app/correlations/error_correlations.tsx +++ b/x-pack/plugins/apm/public/components/app/correlations/error_correlations.tsx @@ -51,7 +51,13 @@ export function ErrorCorrelations({ onClose }: Props) { const { serviceName } = useParams<{ serviceName?: string }>(); const { urlParams, uiFilters } = useUrlParams(); - const { transactionName, transactionType, start, end } = urlParams; + const { + environment, + transactionName, + transactionType, + start, + end, + } = urlParams; const { defaultFieldNames } = useFieldNames(); const [fieldNames, setFieldNames] = useLocalStorage( `apm.correlations.errors.fields:${serviceName}`, @@ -65,6 +71,7 @@ export function ErrorCorrelations({ onClose }: Props) { endpoint: 'GET /api/apm/correlations/failed_transactions', params: { query: { + environment, serviceName, transactionName, transactionType, @@ -78,6 +85,7 @@ export function ErrorCorrelations({ onClose }: Props) { } }, [ + environment, serviceName, start, end, diff --git a/x-pack/plugins/apm/public/components/app/correlations/latency_correlations.tsx b/x-pack/plugins/apm/public/components/app/correlations/latency_correlations.tsx index c88aaa85bb856f..459df99a62f5a2 100644 --- a/x-pack/plugins/apm/public/components/app/correlations/latency_correlations.tsx +++ b/x-pack/plugins/apm/public/components/app/correlations/latency_correlations.tsx @@ -49,7 +49,13 @@ export function LatencyCorrelations({ onClose }: Props) { const { serviceName } = useParams<{ serviceName?: string }>(); const { urlParams, uiFilters } = useUrlParams(); - const { transactionName, transactionType, start, end } = urlParams; + const { + environment, + transactionName, + transactionType, + start, + end, + } = urlParams; const { defaultFieldNames } = useFieldNames(); const [fieldNames, setFieldNames] = useLocalStorage( `apm.correlations.latency.fields:${serviceName}`, @@ -70,6 +76,7 @@ export function LatencyCorrelations({ onClose }: Props) { endpoint: 'GET /api/apm/correlations/slow_transactions', params: { query: { + environment, serviceName, transactionName, transactionType, @@ -84,6 +91,7 @@ export function LatencyCorrelations({ onClose }: Props) { } }, [ + environment, serviceName, start, end, diff --git a/x-pack/plugins/apm/public/components/app/error_group_overview/index.tsx b/x-pack/plugins/apm/public/components/app/error_group_overview/index.tsx index 29bdf6467e5447..bde23eddaa44fa 100644 --- a/x-pack/plugins/apm/public/components/app/error_group_overview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/error_group_overview/index.tsx @@ -28,7 +28,7 @@ interface ErrorGroupOverviewProps { export function ErrorGroupOverview({ serviceName }: ErrorGroupOverviewProps) { const { urlParams, uiFilters } = useUrlParams(); - const { start, end, sortField, sortDirection } = urlParams; + const { environment, start, end, sortField, sortDirection } = urlParams; const { errorDistributionData } = useErrorGroupDistributionFetcher({ serviceName, groupId: undefined, @@ -46,6 +46,7 @@ export function ErrorGroupOverview({ serviceName }: ErrorGroupOverviewProps) { serviceName, }, query: { + environment, start, end, sortField, @@ -56,7 +57,7 @@ export function ErrorGroupOverview({ serviceName }: ErrorGroupOverviewProps) { }); } }, - [serviceName, start, end, sortField, sortDirection, uiFilters] + [environment, serviceName, start, end, sortField, sortDirection, uiFilters] ); useTrackPageview({ diff --git a/x-pack/plugins/apm/public/components/app/service_inventory/index.tsx b/x-pack/plugins/apm/public/components/app/service_inventory/index.tsx index 32bc907f624fbd..cd17ca0ce023d2 100644 --- a/x-pack/plugins/apm/public/components/app/service_inventory/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_inventory/index.tsx @@ -39,19 +39,24 @@ function useServicesFetcher() { const { urlParams, uiFilters } = useUrlParams(); const { core } = useApmPluginContext(); const upgradeAssistantHref = useUpgradeAssistantHref(); - const { start, end } = urlParams; + const { environment, start, end } = urlParams; const { data = initialData, status } = useFetcher( (callApmApi) => { if (start && end) { return callApmApi({ endpoint: 'GET /api/apm/services', params: { - query: { start, end, uiFilters: JSON.stringify(uiFilters) }, + query: { + environment, + start, + end, + uiFilters: JSON.stringify(uiFilters), + }, }, }); } }, - [start, end, uiFilters] + [environment, start, end, uiFilters] ); useEffect(() => { diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_dependencies_table/index.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_dependencies_table/index.tsx index baae683e2eba95..2f37e8e4238d8b 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_dependencies_table/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_dependencies_table/index.tsx @@ -14,10 +14,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; -import { - ENVIRONMENT_ALL, - getNextEnvironmentUrlParam, -} from '../../../../../common/environment_filter_values'; +import { getNextEnvironmentUrlParam } from '../../../../../common/environment_filter_values'; import { asMillisecondDuration, asPercent, @@ -182,7 +179,7 @@ export function ServiceOverviewDependenciesTable({ serviceName }: Props) { query: { start, end, - environment: environment || ENVIRONMENT_ALL.value, + environment, numBuckets: 20, }, }, diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_errors_table/index.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_errors_table/index.tsx index 7f4823c13d593a..f7f5db32e986cc 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_errors_table/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_errors_table/index.tsx @@ -52,7 +52,7 @@ const DEFAULT_SORT = { export function ServiceOverviewErrorsTable({ serviceName }: Props) { const { - urlParams: { start, end }, + urlParams: { environment, start, end }, uiFilters, } = useUrlParams(); const { transactionType } = useApmServiceContext(); @@ -152,6 +152,7 @@ export function ServiceOverviewErrorsTable({ serviceName }: Props) { params: { path: { serviceName }, query: { + environment, start, end, uiFilters: JSON.stringify(uiFilters), @@ -178,6 +179,7 @@ export function ServiceOverviewErrorsTable({ serviceName }: Props) { }); }, [ + environment, start, end, serviceName, diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_chart_and_table.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_chart_and_table.tsx index e7c1d4442e3b7c..819d65a5d9415e 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_chart_and_table.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_chart_and_table.tsx @@ -25,7 +25,7 @@ export function ServiceOverviewInstancesChartAndTable({ const { transactionType } = useApmServiceContext(); const { - urlParams: { start, end }, + urlParams: { environment, start, end }, uiFilters, } = useUrlParams(); @@ -43,6 +43,7 @@ export function ServiceOverviewInstancesChartAndTable({ serviceName, }, query: { + environment, start, end, transactionType, @@ -52,7 +53,7 @@ export function ServiceOverviewInstancesChartAndTable({ }, }); }, - [start, end, serviceName, transactionType, uiFilters] + [environment, start, end, serviceName, transactionType, uiFilters] ); return ( diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_throughput_chart.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_throughput_chart.tsx index 1d0074da6005ff..2d38ce2c23ca7c 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_throughput_chart.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_throughput_chart.tsx @@ -30,7 +30,7 @@ export function ServiceOverviewThroughputChart({ const { serviceName } = useParams<{ serviceName?: string }>(); const { urlParams, uiFilters } = useUrlParams(); const { transactionType } = useApmServiceContext(); - const { start, end } = urlParams; + const { environment, start, end } = urlParams; const { data = INITIAL_STATE, status } = useFetcher( (callApmApi) => { @@ -42,6 +42,7 @@ export function ServiceOverviewThroughputChart({ serviceName, }, query: { + environment, start, end, transactionType, @@ -51,7 +52,7 @@ export function ServiceOverviewThroughputChart({ }); } }, - [serviceName, start, end, uiFilters, transactionType] + [environment, serviceName, start, end, uiFilters, transactionType] ); return ( diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/index.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/index.tsx index a0facb2ddbedf6..5529f9028b9dda 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/index.tsx @@ -58,7 +58,7 @@ export function ServiceOverviewTransactionsTable({ serviceName }: Props) { const { transactionType } = useApmServiceContext(); const { uiFilters, - urlParams: { start, end, latencyAggregationType }, + urlParams: { environment, start, end, latencyAggregationType }, } = useUrlParams(); const { data = INITIAL_STATE, status } = useFetcher( @@ -72,6 +72,7 @@ export function ServiceOverviewTransactionsTable({ serviceName }: Props) { params: { path: { serviceName }, query: { + environment, start, end, uiFilters: JSON.stringify(uiFilters), @@ -87,6 +88,7 @@ export function ServiceOverviewTransactionsTable({ serviceName }: Props) { }); }, [ + environment, serviceName, start, end, @@ -125,6 +127,7 @@ export function ServiceOverviewTransactionsTable({ serviceName }: Props) { params: { path: { serviceName }, query: { + environment, start, end, uiFilters: JSON.stringify(uiFilters), diff --git a/x-pack/plugins/apm/public/components/app/trace_overview/index.tsx b/x-pack/plugins/apm/public/components/app/trace_overview/index.tsx index cae0ef2de2ad1b..8fc9ac12824baa 100644 --- a/x-pack/plugins/apm/public/components/app/trace_overview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/trace_overview/index.tsx @@ -23,7 +23,7 @@ const DEFAULT_RESPONSE: TracesAPIResponse = { export function TraceOverview() { const { urlParams, uiFilters } = useUrlParams(); - const { start, end } = urlParams; + const { environment, start, end } = urlParams; const { status, data = DEFAULT_RESPONSE } = useFetcher( (callApmApi) => { if (start && end) { @@ -31,6 +31,7 @@ export function TraceOverview() { endpoint: 'GET /api/apm/traces', params: { query: { + environment, start, end, uiFilters: JSON.stringify(uiFilters), @@ -39,7 +40,7 @@ export function TraceOverview() { }); } }, - [start, end, uiFilters] + [environment, start, end, uiFilters] ); useTrackPageview({ app: 'apm', path: 'traces_overview' }); diff --git a/x-pack/plugins/apm/public/components/app/transaction_overview/use_transaction_list.ts b/x-pack/plugins/apm/public/components/app/transaction_overview/use_transaction_list.ts index 406ba98b79e256..a63788457b8b5d 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_overview/use_transaction_list.ts +++ b/x-pack/plugins/apm/public/components/app/transaction_overview/use_transaction_list.ts @@ -21,7 +21,7 @@ const DEFAULT_RESPONSE: Partial = { export function useTransactionListFetcher() { const { urlParams, uiFilters } = useUrlParams(); const { serviceName } = useParams<{ serviceName?: string }>(); - const { transactionType, start, end } = urlParams; + const { environment, transactionType, start, end } = urlParams; const { data = DEFAULT_RESPONSE, error, status } = useFetcher( (callApmApi) => { if (serviceName && start && end && transactionType) { @@ -30,6 +30,7 @@ export function useTransactionListFetcher() { params: { path: { serviceName }, query: { + environment, start, end, transactionType, @@ -39,7 +40,7 @@ export function useTransactionListFetcher() { }); } }, - [serviceName, start, end, transactionType, uiFilters] + [environment, serviceName, start, end, transactionType, uiFilters] ); return { diff --git a/x-pack/plugins/apm/public/components/shared/EnvironmentFilter/index.tsx b/x-pack/plugins/apm/public/components/shared/EnvironmentFilter/index.tsx index 714645fd749612..59c99463144cbe 100644 --- a/x-pack/plugins/apm/public/components/shared/EnvironmentFilter/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/EnvironmentFilter/index.tsx @@ -64,10 +64,9 @@ export function EnvironmentFilter() { const history = useHistory(); const location = useLocation(); const { serviceName } = useParams<{ serviceName?: string }>(); - const { uiFilters, urlParams } = useUrlParams(); + const { urlParams } = useUrlParams(); - const { environment } = uiFilters; - const { start, end } = urlParams; + const { environment, start, end } = urlParams; const { environments, status = 'loading' } = useEnvironmentsFetcher({ serviceName, start, diff --git a/x-pack/plugins/apm/public/components/shared/charts/transaction_breakdown_chart/use_transaction_breakdown.ts b/x-pack/plugins/apm/public/components/shared/charts/transaction_breakdown_chart/use_transaction_breakdown.ts index 466f201ab3398e..293a1929ca6069 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/transaction_breakdown_chart/use_transaction_breakdown.ts +++ b/x-pack/plugins/apm/public/components/shared/charts/transaction_breakdown_chart/use_transaction_breakdown.ts @@ -13,7 +13,7 @@ import { useApmServiceContext } from '../../../../context/apm_service/use_apm_se export function useTransactionBreakdown() { const { serviceName } = useParams<{ serviceName?: string }>(); const { urlParams, uiFilters } = useUrlParams(); - const { start, end, transactionName } = urlParams; + const { environment, start, end, transactionName } = urlParams; const { transactionType } = useApmServiceContext(); const { data = { timeseries: undefined }, error, status } = useFetcher( @@ -25,6 +25,7 @@ export function useTransactionBreakdown() { params: { path: { serviceName }, query: { + environment, start, end, transactionName, @@ -35,7 +36,15 @@ export function useTransactionBreakdown() { }); } }, - [serviceName, start, end, transactionType, transactionName, uiFilters] + [ + environment, + serviceName, + start, + end, + transactionType, + transactionName, + uiFilters, + ] ); return { diff --git a/x-pack/plugins/apm/public/components/shared/charts/transaction_error_rate_chart/index.tsx b/x-pack/plugins/apm/public/components/shared/charts/transaction_error_rate_chart/index.tsx index df18e7627faedb..a3da8812966f18 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/transaction_error_rate_chart/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/transaction_error_rate_chart/index.tsx @@ -33,7 +33,7 @@ export function TransactionErrorRateChart({ const { serviceName } = useParams<{ serviceName?: string }>(); const { urlParams, uiFilters } = useUrlParams(); const { transactionType } = useApmServiceContext(); - const { start, end, transactionName } = urlParams; + const { environment, start, end, transactionName } = urlParams; const { data, status } = useFetcher( (callApmApi) => { @@ -46,6 +46,7 @@ export function TransactionErrorRateChart({ serviceName, }, query: { + environment, start, end, transactionType, @@ -56,7 +57,15 @@ export function TransactionErrorRateChart({ }); } }, - [serviceName, start, end, uiFilters, transactionType, transactionName] + [ + environment, + serviceName, + start, + end, + uiFilters, + transactionType, + transactionName, + ] ); const errorRates = data?.transactionErrorRate || []; diff --git a/x-pack/plugins/apm/public/context/url_params_context/resolve_url_params.ts b/x-pack/plugins/apm/public/context/url_params_context/resolve_url_params.ts index 63d719205c2ade..b6e7330be30cbd 100644 --- a/x-pack/plugins/apm/public/context/url_params_context/resolve_url_params.ts +++ b/x-pack/plugins/apm/public/context/url_params_context/resolve_url_params.ts @@ -6,6 +6,7 @@ */ import { Location } from 'history'; +import { ENVIRONMENT_ALL } from '../../../common/environment_filter_values'; import { LatencyAggregationType } from '../../../common/latency_aggregation_types'; import { pickKeys } from '../../../common/utils/pick_keys'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths @@ -66,6 +67,7 @@ export function resolveUrlParams(location: Location, state: TimeUrlParams) { refreshInterval: refreshInterval ? toNumber(refreshInterval) : undefined, // query params + environment: toString(environment) || ENVIRONMENT_ALL.value, sortDirection, sortField, page: toNumber(page) || 0, @@ -87,7 +89,6 @@ export function resolveUrlParams(location: Location, state: TimeUrlParams) { : undefined, comparisonType: comparisonType as TimeRangeComparisonType | undefined, // ui filters - environment, ...localUIFilters, }); } diff --git a/x-pack/plugins/apm/public/context/url_params_context/url_params_context.tsx b/x-pack/plugins/apm/public/context/url_params_context/url_params_context.tsx index 8312fedc7eb039..90245b9843b013 100644 --- a/x-pack/plugins/apm/public/context/url_params_context/url_params_context.tsx +++ b/x-pack/plugins/apm/public/context/url_params_context/url_params_context.tsx @@ -14,7 +14,6 @@ import React, { useState, } from 'react'; import { withRouter } from 'react-router-dom'; -import { ENVIRONMENT_ALL } from '../../../common/environment_filter_values'; import { LocalUIFilterName } from '../../../common/ui_filter'; import { pickKeys } from '../../../common/utils/pick_keys'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths @@ -39,7 +38,6 @@ function useUiFilters(params: IUrlParams): UIFilters { return useDeepObjectIdentity({ kuery, - environment: environment || ENVIRONMENT_ALL.value, ...localUiFilters, }); } diff --git a/x-pack/plugins/apm/public/hooks/use_error_group_distribution_fetcher.tsx b/x-pack/plugins/apm/public/hooks/use_error_group_distribution_fetcher.tsx index 834b0cc0527897..9ff179e6af6a06 100644 --- a/x-pack/plugins/apm/public/hooks/use_error_group_distribution_fetcher.tsx +++ b/x-pack/plugins/apm/public/hooks/use_error_group_distribution_fetcher.tsx @@ -16,7 +16,7 @@ export function useErrorGroupDistributionFetcher({ groupId: string | undefined; }) { const { urlParams, uiFilters } = useUrlParams(); - const { start, end } = urlParams; + const { environment, start, end } = urlParams; const { data } = useFetcher( (callApmApi) => { if (start && end) { @@ -25,6 +25,7 @@ export function useErrorGroupDistributionFetcher({ params: { path: { serviceName }, query: { + environment, start, end, groupId, @@ -34,7 +35,7 @@ export function useErrorGroupDistributionFetcher({ }); } }, - [serviceName, start, end, groupId, uiFilters] + [environment, serviceName, start, end, groupId, uiFilters] ); return { errorDistributionData: data }; diff --git a/x-pack/plugins/apm/public/hooks/use_service_metric_charts_fetcher.ts b/x-pack/plugins/apm/public/hooks/use_service_metric_charts_fetcher.ts index ecfa5471189d20..87e10f1e8937b0 100644 --- a/x-pack/plugins/apm/public/hooks/use_service_metric_charts_fetcher.ts +++ b/x-pack/plugins/apm/public/hooks/use_service_metric_charts_fetcher.ts @@ -24,7 +24,7 @@ export function useServiceMetricChartsFetcher({ const { urlParams, uiFilters } = useUrlParams(); const { agentName } = useApmServiceContext(); const { serviceName } = useParams<{ serviceName?: string }>(); - const { start, end } = urlParams; + const { environment, start, end } = urlParams; const { data = INITIAL_DATA, error, status } = useFetcher( (callApmApi) => { if (serviceName && start && end && agentName) { @@ -33,6 +33,7 @@ export function useServiceMetricChartsFetcher({ params: { path: { serviceName }, query: { + environment, serviceNodeName, start, end, @@ -43,7 +44,15 @@ export function useServiceMetricChartsFetcher({ }); } }, - [serviceName, start, end, agentName, serviceNodeName, uiFilters] + [ + environment, + serviceName, + start, + end, + agentName, + serviceNodeName, + uiFilters, + ] ); return { diff --git a/x-pack/plugins/apm/public/hooks/use_transaction_distribution_fetcher.ts b/x-pack/plugins/apm/public/hooks/use_transaction_distribution_fetcher.ts index 66446bf0dfebad..c493a30716aa5e 100644 --- a/x-pack/plugins/apm/public/hooks/use_transaction_distribution_fetcher.ts +++ b/x-pack/plugins/apm/public/hooks/use_transaction_distribution_fetcher.ts @@ -25,6 +25,7 @@ export function useTransactionDistributionFetcher() { const { serviceName } = useParams<{ serviceName?: string }>(); const { urlParams, uiFilters } = useUrlParams(); const { + environment, start, end, transactionType, @@ -45,6 +46,7 @@ export function useTransactionDistributionFetcher() { serviceName, }, query: { + environment, start, end, transactionType, @@ -92,7 +94,15 @@ export function useTransactionDistributionFetcher() { }, // the histogram should not be refetched if the transactionId or traceId changes // eslint-disable-next-line react-hooks/exhaustive-deps - [serviceName, start, end, transactionType, transactionName, uiFilters] + [ + environment, + serviceName, + start, + end, + transactionType, + transactionName, + uiFilters, + ] ); return { diff --git a/x-pack/plugins/apm/public/hooks/use_transaction_latency_chart_fetcher.ts b/x-pack/plugins/apm/public/hooks/use_transaction_latency_chart_fetcher.ts index d5974ee3543a7e..cca2e99d84dfdf 100644 --- a/x-pack/plugins/apm/public/hooks/use_transaction_latency_chart_fetcher.ts +++ b/x-pack/plugins/apm/public/hooks/use_transaction_latency_chart_fetcher.ts @@ -18,7 +18,13 @@ export function useTransactionLatencyChartsFetcher() { const { transactionType } = useApmServiceContext(); const theme = useTheme(); const { - urlParams: { start, end, transactionName, latencyAggregationType }, + urlParams: { + environment, + start, + end, + transactionName, + latencyAggregationType, + }, uiFilters, } = useUrlParams(); @@ -37,6 +43,7 @@ export function useTransactionLatencyChartsFetcher() { params: { path: { serviceName }, query: { + environment, start, end, transactionType, @@ -49,6 +56,7 @@ export function useTransactionLatencyChartsFetcher() { } }, [ + environment, serviceName, start, end, diff --git a/x-pack/plugins/apm/public/hooks/use_transaction_throughput_chart_fetcher.ts b/x-pack/plugins/apm/public/hooks/use_transaction_throughput_chart_fetcher.ts index af9a5fee24877a..55765cd40c04eb 100644 --- a/x-pack/plugins/apm/public/hooks/use_transaction_throughput_chart_fetcher.ts +++ b/x-pack/plugins/apm/public/hooks/use_transaction_throughput_chart_fetcher.ts @@ -18,7 +18,7 @@ export function useTransactionThroughputChartsFetcher() { const { transactionType } = useApmServiceContext(); const theme = useTheme(); const { - urlParams: { start, end, transactionName }, + urlParams: { environment, start, end, transactionName }, uiFilters, } = useUrlParams(); @@ -31,6 +31,7 @@ export function useTransactionThroughputChartsFetcher() { params: { path: { serviceName }, query: { + environment, start, end, transactionType, @@ -41,7 +42,15 @@ export function useTransactionThroughputChartsFetcher() { }); } }, - [serviceName, start, end, transactionName, transactionType, uiFilters] + [ + environment, + serviceName, + start, + end, + transactionName, + transactionType, + uiFilters, + ] ); const memoizedData = useMemo( diff --git a/x-pack/plugins/apm/public/utils/testHelpers.tsx b/x-pack/plugins/apm/public/utils/testHelpers.tsx index aac6196c4253c5..f7f6f7486091b7 100644 --- a/x-pack/plugins/apm/public/utils/testHelpers.tsx +++ b/x-pack/plugins/apm/public/utils/testHelpers.tsx @@ -182,8 +182,8 @@ export async function inspectSearchParams( }, } ) as APMConfig, - uiFilters: { environment: 'test' }, - esFilter: [{ term: { 'service.environment': 'test' } }], + uiFilters: {}, + esFilter: [], indices: { /* eslint-disable @typescript-eslint/naming-convention */ 'apm_oss.sourcemapIndices': 'myIndex', diff --git a/x-pack/plugins/apm/server/lib/alerts/chart_preview/get_transaction_duration.ts b/x-pack/plugins/apm/server/lib/alerts/chart_preview/get_transaction_duration.ts index e487684909633e..3457207eeee3c4 100644 --- a/x-pack/plugins/apm/server/lib/alerts/chart_preview/get_transaction_duration.ts +++ b/x-pack/plugins/apm/server/lib/alerts/chart_preview/get_transaction_duration.ts @@ -13,10 +13,9 @@ import { TRANSACTION_TYPE, } from '../../../../common/elasticsearch_fieldnames'; import { ProcessorEvent } from '../../../../common/processor_event'; -import { rangeFilter } from '../../../../common/utils/range_filter'; +import { environmentQuery, rangeQuery } from '../../../../common/utils/queries'; import { AlertParams } from '../../../routes/alerts/chart_preview'; import { withApmSpan } from '../../../utils/with_apm_span'; -import { getEnvironmentUiFilterES } from '../../helpers/convert_ui_filters/get_environment_ui_filter_es'; import { getBucketSize } from '../../helpers/get_bucket_size'; import { Setup, SetupTimeRange } from '../../helpers/setup_request'; @@ -39,13 +38,13 @@ export function getTransactionDurationChartPreview({ const query = { bool: { filter: [ - { range: rangeFilter(start, end) }, { term: { [PROCESSOR_EVENT]: ProcessorEvent.transaction } }, ...(serviceName ? [{ term: { [SERVICE_NAME]: serviceName } }] : []), ...(transactionType ? [{ term: { [TRANSACTION_TYPE]: transactionType } }] : []), - ...getEnvironmentUiFilterES(environment), + ...rangeQuery(start, end), + ...environmentQuery(environment), ], }, }; diff --git a/x-pack/plugins/apm/server/lib/alerts/chart_preview/get_transaction_error_count.ts b/x-pack/plugins/apm/server/lib/alerts/chart_preview/get_transaction_error_count.ts index 05ad743af0997b..aa85c44284d9d4 100644 --- a/x-pack/plugins/apm/server/lib/alerts/chart_preview/get_transaction_error_count.ts +++ b/x-pack/plugins/apm/server/lib/alerts/chart_preview/get_transaction_error_count.ts @@ -7,10 +7,9 @@ import { SERVICE_NAME } from '../../../../common/elasticsearch_fieldnames'; import { ProcessorEvent } from '../../../../common/processor_event'; -import { rangeFilter } from '../../../../common/utils/range_filter'; import { AlertParams } from '../../../routes/alerts/chart_preview'; +import { environmentQuery, rangeQuery } from '../../../../common/utils/queries'; import { withApmSpan } from '../../../utils/with_apm_span'; -import { getEnvironmentUiFilterES } from '../../helpers/convert_ui_filters/get_environment_ui_filter_es'; import { getBucketSize } from '../../helpers/get_bucket_size'; import { Setup, SetupTimeRange } from '../../helpers/setup_request'; @@ -28,9 +27,9 @@ export function getTransactionErrorCountChartPreview({ const query = { bool: { filter: [ - { range: rangeFilter(start, end) }, ...(serviceName ? [{ term: { [SERVICE_NAME]: serviceName } }] : []), - ...getEnvironmentUiFilterES(environment), + ...rangeQuery(start, end), + ...environmentQuery(environment), ], }, }; diff --git a/x-pack/plugins/apm/server/lib/alerts/chart_preview/get_transaction_error_rate.ts b/x-pack/plugins/apm/server/lib/alerts/chart_preview/get_transaction_error_rate.ts index fa01773c780703..88e249a71a81f0 100644 --- a/x-pack/plugins/apm/server/lib/alerts/chart_preview/get_transaction_error_rate.ts +++ b/x-pack/plugins/apm/server/lib/alerts/chart_preview/get_transaction_error_rate.ts @@ -11,9 +11,8 @@ import { TRANSACTION_TYPE, } from '../../../../common/elasticsearch_fieldnames'; import { ProcessorEvent } from '../../../../common/processor_event'; -import { rangeFilter } from '../../../../common/utils/range_filter'; import { AlertParams } from '../../../routes/alerts/chart_preview'; -import { getEnvironmentUiFilterES } from '../../helpers/convert_ui_filters/get_environment_ui_filter_es'; +import { environmentQuery, rangeQuery } from '../../../../common/utils/queries'; import { getBucketSize } from '../../helpers/get_bucket_size'; import { Setup, SetupTimeRange } from '../../helpers/setup_request'; import { @@ -34,13 +33,13 @@ export async function getTransactionErrorRateChartPreview({ const query = { bool: { filter: [ - { range: rangeFilter(start, end) }, { term: { [PROCESSOR_EVENT]: ProcessorEvent.transaction } }, ...(serviceName ? [{ term: { [SERVICE_NAME]: serviceName } }] : []), ...(transactionType ? [{ term: { [TRANSACTION_TYPE]: transactionType } }] : []), - ...getEnvironmentUiFilterES(environment), + ...rangeQuery(start, end), + ...environmentQuery(environment), ], }, }; diff --git a/x-pack/plugins/apm/server/lib/alerts/register_error_count_alert_type.ts b/x-pack/plugins/apm/server/lib/alerts/register_error_count_alert_type.ts index e9e2e078ec344e..c7861eaa819aed 100644 --- a/x-pack/plugins/apm/server/lib/alerts/register_error_count_alert_type.ts +++ b/x-pack/plugins/apm/server/lib/alerts/register_error_count_alert_type.ts @@ -27,7 +27,7 @@ import { SERVICE_NAME, } from '../../../common/elasticsearch_fieldnames'; import { ProcessorEvent } from '../../../common/processor_event'; -import { getEnvironmentUiFilterES } from '../helpers/convert_ui_filters/get_environment_ui_filter_es'; +import { environmentQuery } from '../../../common/utils/queries'; import { getApmIndices } from '../settings/apm_indices/get_apm_indices'; import { apmActionVariables } from './action_variables'; import { alertingEsClient } from './alerting_es_client'; @@ -104,7 +104,7 @@ export function registerErrorCountAlertType({ ...(alertParams.serviceName ? [{ term: { [SERVICE_NAME]: alertParams.serviceName } }] : []), - ...getEnvironmentUiFilterES(alertParams.environment), + ...environmentQuery(alertParams.environment), ], }, }, diff --git a/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_alert_type.ts b/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_alert_type.ts index 480efd8d4c7ad0..704aee932a604f 100644 --- a/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_alert_type.ts +++ b/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_alert_type.ts @@ -20,7 +20,7 @@ import { } from '../../../common/elasticsearch_fieldnames'; import { ProcessorEvent } from '../../../common/processor_event'; import { getDurationFormatter } from '../../../common/utils/formatters'; -import { getEnvironmentUiFilterES } from '../helpers/convert_ui_filters/get_environment_ui_filter_es'; +import { environmentQuery } from '../../../common/utils/queries'; import { getApmIndices } from '../settings/apm_indices/get_apm_indices'; import { apmActionVariables } from './action_variables'; import { alertingEsClient } from './alerting_es_client'; @@ -96,7 +96,7 @@ export function registerTransactionDurationAlertType({ { term: { [PROCESSOR_EVENT]: ProcessorEvent.transaction } }, { term: { [SERVICE_NAME]: alertParams.serviceName } }, { term: { [TRANSACTION_TYPE]: alertParams.transactionType } }, - ...getEnvironmentUiFilterES(alertParams.environment), + ...environmentQuery(alertParams.environment), ], }, }, diff --git a/x-pack/plugins/apm/server/lib/alerts/register_transaction_error_rate_alert_type.ts b/x-pack/plugins/apm/server/lib/alerts/register_transaction_error_rate_alert_type.ts index 882bde87927615..6f58b7714d8324 100644 --- a/x-pack/plugins/apm/server/lib/alerts/register_transaction_error_rate_alert_type.ts +++ b/x-pack/plugins/apm/server/lib/alerts/register_transaction_error_rate_alert_type.ts @@ -22,7 +22,7 @@ import { import { EventOutcome } from '../../../common/event_outcome'; import { ProcessorEvent } from '../../../common/processor_event'; import { asDecimalOrInteger } from '../../../common/utils/formatters'; -import { getEnvironmentUiFilterES } from '../helpers/convert_ui_filters/get_environment_ui_filter_es'; +import { environmentQuery } from '../../../common/utils/queries'; import { getApmIndices } from '../settings/apm_indices/get_apm_indices'; import { apmActionVariables } from './action_variables'; import { alertingEsClient } from './alerting_es_client'; @@ -103,7 +103,7 @@ export function registerTransactionErrorRateAlertType({ }, ] : []), - ...getEnvironmentUiFilterES(alertParams.environment), + ...environmentQuery(alertParams.environment), ], }, }, diff --git a/x-pack/plugins/apm/server/lib/anomaly_detection/create_anomaly_detection_jobs.ts b/x-pack/plugins/apm/server/lib/anomaly_detection/create_anomaly_detection_jobs.ts index a560f011b186bb..d70e19bf4a5f52 100644 --- a/x-pack/plugins/apm/server/lib/anomaly_detection/create_anomaly_detection_jobs.ts +++ b/x-pack/plugins/apm/server/lib/anomaly_detection/create_anomaly_detection_jobs.ts @@ -9,15 +9,15 @@ import { Logger } from 'kibana/server'; import uuid from 'uuid/v4'; import { snakeCase } from 'lodash'; import Boom from '@hapi/boom'; -import { ProcessorEvent } from '../../../common/processor_event'; import { ML_ERRORS } from '../../../common/anomaly_detection'; +import { ProcessorEvent } from '../../../common/processor_event'; +import { environmentQuery } from '../../../common/utils/queries'; import { Setup } from '../helpers/setup_request'; import { TRANSACTION_DURATION, PROCESSOR_EVENT, } from '../../../common/elasticsearch_fieldnames'; import { APM_ML_JOB_GROUP, ML_MODULE_ID_APM_TRANSACTION } from './constants'; -import { getEnvironmentUiFilterES } from '../helpers/convert_ui_filters/get_environment_ui_filter_es'; import { withApmSpan } from '../../utils/with_apm_span'; export async function createAnomalyDetectionJobs( @@ -86,7 +86,7 @@ async function createAnomalyDetectionJob({ filter: [ { term: { [PROCESSOR_EVENT]: ProcessorEvent.transaction } }, { exists: { field: TRANSACTION_DURATION } }, - ...getEnvironmentUiFilterES(environment), + ...environmentQuery(environment), ], }, }, diff --git a/x-pack/plugins/apm/server/lib/correlations/get_correlations_for_failed_transactions/index.ts b/x-pack/plugins/apm/server/lib/correlations/get_correlations_for_failed_transactions/index.ts index 721e35e2ef60d0..ecefdfc2b3d9b2 100644 --- a/x-pack/plugins/apm/server/lib/correlations/get_correlations_for_failed_transactions/index.ts +++ b/x-pack/plugins/apm/server/lib/correlations/get_correlations_for_failed_transactions/index.ts @@ -13,7 +13,7 @@ import { } from '../process_significant_term_aggs'; import { AggregationOptionsByType } from '../../../../../../typings/elasticsearch/aggregations'; import { ESFilter } from '../../../../../../typings/elasticsearch'; -import { rangeFilter } from '../../../../common/utils/range_filter'; +import { environmentQuery, rangeQuery } from '../../../../common/utils/queries'; import { EVENT_OUTCOME, SERVICE_NAME, @@ -31,12 +31,14 @@ import { import { withApmSpan } from '../../../utils/with_apm_span'; export async function getCorrelationsForFailedTransactions({ + environment, serviceName, transactionType, transactionName, fieldNames, setup, }: { + environment?: string; serviceName: string | undefined; transactionType: string | undefined; transactionName: string | undefined; @@ -47,9 +49,10 @@ export async function getCorrelationsForFailedTransactions({ const { start, end, esFilter, apmEventClient } = setup; const backgroundFilters: ESFilter[] = [ - ...esFilter, - { range: rangeFilter(start, end) }, { term: { [PROCESSOR_EVENT]: ProcessorEvent.transaction } }, + ...rangeQuery(start, end), + ...environmentQuery(environment), + ...esFilter, ]; if (serviceName) { diff --git a/x-pack/plugins/apm/server/lib/correlations/get_correlations_for_slow_transactions/index.ts b/x-pack/plugins/apm/server/lib/correlations/get_correlations_for_slow_transactions/index.ts index 816061da5cfc17..832b89a18d1028 100644 --- a/x-pack/plugins/apm/server/lib/correlations/get_correlations_for_slow_transactions/index.ts +++ b/x-pack/plugins/apm/server/lib/correlations/get_correlations_for_slow_transactions/index.ts @@ -7,7 +7,7 @@ import { AggregationOptionsByType } from '../../../../../../typings/elasticsearch/aggregations'; import { ESFilter } from '../../../../../../typings/elasticsearch'; -import { rangeFilter } from '../../../../common/utils/range_filter'; +import { environmentQuery, rangeQuery } from '../../../../common/utils/queries'; import { SERVICE_NAME, TRANSACTION_DURATION, @@ -23,6 +23,7 @@ import { getLatencyDistribution } from './get_latency_distribution'; import { withApmSpan } from '../../../utils/with_apm_span'; export async function getCorrelationsForSlowTransactions({ + environment, serviceName, transactionType, transactionName, @@ -30,6 +31,7 @@ export async function getCorrelationsForSlowTransactions({ fieldNames, setup, }: { + environment?: string; serviceName: string | undefined; transactionType: string | undefined; transactionName: string | undefined; @@ -41,9 +43,10 @@ export async function getCorrelationsForSlowTransactions({ const { start, end, esFilter, apmEventClient } = setup; const backgroundFilters: ESFilter[] = [ - ...esFilter, - { range: rangeFilter(start, end) }, { term: { [PROCESSOR_EVENT]: ProcessorEvent.transaction } }, + ...rangeQuery(start, end), + ...environmentQuery(environment), + ...esFilter, ]; if (serviceName) { diff --git a/x-pack/plugins/apm/server/lib/environments/get_environments.ts b/x-pack/plugins/apm/server/lib/environments/get_environments.ts index 56f0a03910c1a4..af88493c148ce1 100644 --- a/x-pack/plugins/apm/server/lib/environments/get_environments.ts +++ b/x-pack/plugins/apm/server/lib/environments/get_environments.ts @@ -5,14 +5,13 @@ * 2.0. */ -import { ESFilter } from '../../../../../typings/elasticsearch'; import { SERVICE_ENVIRONMENT, SERVICE_NAME, } from '../../../common/elasticsearch_fieldnames'; import { ENVIRONMENT_NOT_DEFINED } from '../../../common/environment_filter_values'; import { ProcessorEvent } from '../../../common/processor_event'; -import { rangeFilter } from '../../../common/utils/range_filter'; +import { rangeQuery } from '../../../common/utils/queries'; import { withApmSpan } from '../../utils/with_apm_span'; import { getProcessorEventForAggregatedTransactions } from '../helpers/aggregated_transactions'; import { Setup, SetupTimeRange } from '../helpers/setup_request'; @@ -37,7 +36,7 @@ export async function getEnvironments({ return withApmSpan(spanName, async () => { const { start, end, apmEventClient, config } = setup; - const filter: ESFilter[] = [{ range: rangeFilter(start, end) }]; + const filter = rangeQuery(start, end); if (serviceName) { filter.push({ diff --git a/x-pack/plugins/apm/server/lib/errors/distribution/get_buckets.test.ts b/x-pack/plugins/apm/server/lib/errors/distribution/get_buckets.test.ts index db8414864f5771..1712699162b73c 100644 --- a/x-pack/plugins/apm/server/lib/errors/distribution/get_buckets.test.ts +++ b/x-pack/plugins/apm/server/lib/errors/distribution/get_buckets.test.ts @@ -25,6 +25,7 @@ describe('get buckets', () => { }); await getBuckets({ + environment: 'prod', serviceName: 'myServiceName', bucketSize: 10, setup: { @@ -42,14 +43,8 @@ describe('get buckets', () => { get: () => 'myIndex', } ) as APMConfig, - uiFilters: { - environment: 'prod', - }, - esFilter: [ - { - term: { 'service.environment': 'prod' }, - }, - ], + uiFilters: {}, + esFilter: [], indices: { /* eslint-disable @typescript-eslint/naming-convention */ 'apm_oss.sourcemapIndices': 'apm-*', diff --git a/x-pack/plugins/apm/server/lib/errors/distribution/get_buckets.ts b/x-pack/plugins/apm/server/lib/errors/distribution/get_buckets.ts index 383fcbb2f5ce72..fbe406d8d1a9d2 100644 --- a/x-pack/plugins/apm/server/lib/errors/distribution/get_buckets.ts +++ b/x-pack/plugins/apm/server/lib/errors/distribution/get_buckets.ts @@ -11,16 +11,18 @@ import { SERVICE_NAME, } from '../../../../common/elasticsearch_fieldnames'; import { ProcessorEvent } from '../../../../common/processor_event'; -import { rangeFilter } from '../../../../common/utils/range_filter'; +import { environmentQuery, rangeQuery } from '../../../../common/utils/queries'; import { withApmSpan } from '../../../utils/with_apm_span'; import { Setup, SetupTimeRange } from '../../helpers/setup_request'; export async function getBuckets({ + environment, serviceName, groupId, bucketSize, setup, }: { + environment?: string; serviceName: string; groupId?: string; bucketSize: number; @@ -30,7 +32,8 @@ export async function getBuckets({ const { start, end, esFilter, apmEventClient } = setup; const filter: ESFilter[] = [ { term: { [SERVICE_NAME]: serviceName } }, - { range: rangeFilter(start, end) }, + ...rangeQuery(start, end), + ...environmentQuery(environment), ...esFilter, ]; diff --git a/x-pack/plugins/apm/server/lib/errors/distribution/get_distribution.ts b/x-pack/plugins/apm/server/lib/errors/distribution/get_distribution.ts index be3a29780a5b65..1fb0cbad4a5f09 100644 --- a/x-pack/plugins/apm/server/lib/errors/distribution/get_distribution.ts +++ b/x-pack/plugins/apm/server/lib/errors/distribution/get_distribution.ts @@ -14,16 +14,19 @@ function getBucketSize({ start, end }: SetupTimeRange) { } export async function getErrorDistribution({ + environment, serviceName, groupId, setup, }: { + environment?: string; serviceName: string; groupId?: string; setup: Setup & SetupTimeRange; }) { const bucketSize = getBucketSize({ start: setup.start, end: setup.end }); const { buckets, noHits } = await getBuckets({ + environment, serviceName, groupId, bucketSize, diff --git a/x-pack/plugins/apm/server/lib/errors/get_error_group_sample.ts b/x-pack/plugins/apm/server/lib/errors/get_error_group_sample.ts index 121b9b3d0c46fb..0ab26f3c6e969d 100644 --- a/x-pack/plugins/apm/server/lib/errors/get_error_group_sample.ts +++ b/x-pack/plugins/apm/server/lib/errors/get_error_group_sample.ts @@ -11,16 +11,18 @@ import { TRANSACTION_SAMPLED, } from '../../../common/elasticsearch_fieldnames'; import { ProcessorEvent } from '../../../common/processor_event'; -import { rangeFilter } from '../../../common/utils/range_filter'; +import { environmentQuery, rangeQuery } from '../../../common/utils/queries'; import { withApmSpan } from '../../utils/with_apm_span'; import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { getTransaction } from '../transactions/get_transaction'; export function getErrorGroupSample({ + environment, serviceName, groupId, setup, }: { + environment?: string; serviceName: string; groupId: string; setup: Setup & SetupTimeRange; @@ -39,7 +41,8 @@ export function getErrorGroupSample({ filter: [ { term: { [SERVICE_NAME]: serviceName } }, { term: { [ERROR_GROUP_ID]: groupId } }, - { range: rangeFilter(start, end) }, + ...rangeQuery(start, end), + ...environmentQuery(environment), ...esFilter, ], should: [{ term: { [TRANSACTION_SAMPLED]: true } }], diff --git a/x-pack/plugins/apm/server/lib/errors/get_error_groups.ts b/x-pack/plugins/apm/server/lib/errors/get_error_groups.ts index 6e91f8fe7cdd28..28d89eb0574709 100644 --- a/x-pack/plugins/apm/server/lib/errors/get_error_groups.ts +++ b/x-pack/plugins/apm/server/lib/errors/get_error_groups.ts @@ -21,11 +21,13 @@ import { getErrorName } from '../helpers/get_error_name'; import { Setup, SetupTimeRange } from '../helpers/setup_request'; export function getErrorGroups({ + environment, serviceName, sortField, sortDirection = 'desc', setup, }: { + environment?: string; serviceName: string; sortField?: string; sortDirection?: 'asc' | 'desc'; @@ -37,7 +39,11 @@ export function getErrorGroups({ // sort buckets by last occurrence of error const sortByLatestOccurrence = sortField === 'latestOccurrenceAt'; - const projection = getErrorGroupsProjection({ setup, serviceName }); + const projection = getErrorGroupsProjection({ + environment, + setup, + serviceName, + }); const order: SortOptions = sortByLatestOccurrence ? { diff --git a/x-pack/plugins/apm/server/lib/helpers/aggregated_transactions/index.ts b/x-pack/plugins/apm/server/lib/helpers/aggregated_transactions/index.ts index 424c85d55a36e1..71744c3e590929 100644 --- a/x-pack/plugins/apm/server/lib/helpers/aggregated_transactions/index.ts +++ b/x-pack/plugins/apm/server/lib/helpers/aggregated_transactions/index.ts @@ -6,7 +6,7 @@ */ import { SearchAggregatedTransactionSetting } from '../../../../common/aggregated_transactions'; -import { rangeFilter } from '../../../../common/utils/range_filter'; +import { rangeQuery } from '../../../../common/utils/queries'; import { ProcessorEvent } from '../../../../common/processor_event'; import { TRANSACTION_DURATION, @@ -35,7 +35,7 @@ export async function getHasAggregatedTransactions({ bool: { filter: [ { exists: { field: TRANSACTION_DURATION_HISTOGRAM } }, - ...(start && end ? [{ range: rangeFilter(start, end) }] : []), + ...(start && end ? rangeQuery(start, end) : []), ], }, }, diff --git a/x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_environment_ui_filter_es.test.ts b/x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_environment_ui_filter_es.test.ts deleted file mode 100644 index 57bf511f459428..00000000000000 --- a/x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_environment_ui_filter_es.test.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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 { getEnvironmentUiFilterES } from './get_environment_ui_filter_es'; -import { ENVIRONMENT_NOT_DEFINED } from '../../../../common/environment_filter_values'; -import { SERVICE_ENVIRONMENT } from '../../../../common/elasticsearch_fieldnames'; - -describe('getEnvironmentUiFilterES', () => { - it('should return empty array, when environment is undefined', () => { - const uiFilterES = getEnvironmentUiFilterES(); - expect(uiFilterES).toHaveLength(0); - }); - - it('should create a filter for a service environment', () => { - const uiFilterES = getEnvironmentUiFilterES('test'); - expect(uiFilterES).toHaveLength(1); - expect(uiFilterES[0]).toHaveProperty(['term', SERVICE_ENVIRONMENT], 'test'); - }); - - it('should create a filter for missing service environments', () => { - const uiFilterES = getEnvironmentUiFilterES(ENVIRONMENT_NOT_DEFINED.value); - expect(uiFilterES).toHaveLength(1); - expect(uiFilterES[0]).toHaveProperty( - ['bool', 'must_not', 'exists', 'field'], - SERVICE_ENVIRONMENT - ); - }); -}); diff --git a/x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_es_filter.ts b/x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_es_filter.ts index 63e0edd6097bf4..e91c9b52deecf1 100644 --- a/x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_es_filter.ts +++ b/x-pack/plugins/apm/server/lib/helpers/convert_ui_filters/get_es_filter.ts @@ -7,7 +7,6 @@ import { ESFilter } from '../../../../../../typings/elasticsearch'; import { UIFilters } from '../../../../typings/ui_filters'; -import { getEnvironmentUiFilterES } from './get_environment_ui_filter_es'; import { localUIFilters, localUIFilterNames, @@ -28,10 +27,7 @@ export function getEsFilter(uiFilters: UIFilters) { }; }) as ESFilter[]; - const esFilters = [ - ...getKueryUiFilterES(uiFilters.kuery), - ...getEnvironmentUiFilterES(uiFilters.environment), - ].concat(mappedFilters) as ESFilter[]; + const esFilters = [...getKueryUiFilterES(uiFilters.kuery), ...mappedFilters]; return esFilters; } diff --git a/x-pack/plugins/apm/server/lib/metrics/__snapshots__/queries.test.ts.snap b/x-pack/plugins/apm/server/lib/metrics/__snapshots__/queries.test.ts.snap index 961a1eee61d1d5..4eed09f3e5c28b 100644 --- a/x-pack/plugins/apm/server/lib/metrics/__snapshots__/queries.test.ts.snap +++ b/x-pack/plugins/apm/server/lib/metrics/__snapshots__/queries.test.ts.snap @@ -71,6 +71,11 @@ Object { "service.name": "foo", }, }, + Object { + "term": Object { + "service.node.name": "bar", + }, + }, Object { "range": Object { "@timestamp": Object { @@ -80,11 +85,6 @@ Object { }, }, }, - Object { - "term": Object { - "service.node.name": "bar", - }, - }, Object { "term": Object { "service.environment": "test", @@ -159,6 +159,11 @@ Object { "service.name": "foo", }, }, + Object { + "term": Object { + "service.node.name": "bar", + }, + }, Object { "range": Object { "@timestamp": Object { @@ -168,11 +173,6 @@ Object { }, }, }, - Object { - "term": Object { - "service.node.name": "bar", - }, - }, Object { "term": Object { "service.environment": "test", @@ -322,6 +322,11 @@ Object { "service.name": "foo", }, }, + Object { + "term": Object { + "service.node.name": "bar", + }, + }, Object { "range": Object { "@timestamp": Object { @@ -331,11 +336,6 @@ Object { }, }, }, - Object { - "term": Object { - "service.node.name": "bar", - }, - }, Object { "term": Object { "service.environment": "test", @@ -415,6 +415,11 @@ Object { "service.name": "foo", }, }, + Object { + "term": Object { + "service.node.name": "bar", + }, + }, Object { "range": Object { "@timestamp": Object { @@ -424,11 +429,6 @@ Object { }, }, }, - Object { - "term": Object { - "service.node.name": "bar", - }, - }, Object { "term": Object { "service.environment": "test", @@ -498,6 +498,11 @@ Object { "service.name": "foo", }, }, + Object { + "term": Object { + "service.node.name": "bar", + }, + }, Object { "range": Object { "@timestamp": Object { @@ -507,11 +512,6 @@ Object { }, }, }, - Object { - "term": Object { - "service.node.name": "bar", - }, - }, Object { "term": Object { "service.environment": "test", @@ -601,15 +601,6 @@ Object { "service.name": "foo", }, }, - Object { - "range": Object { - "@timestamp": Object { - "format": "epoch_millis", - "gte": 1528113600000, - "lte": 1528977600000, - }, - }, - }, Object { "bool": Object { "must_not": Array [ @@ -621,6 +612,15 @@ Object { ], }, }, + Object { + "range": Object { + "@timestamp": Object { + "format": "epoch_millis", + "gte": 1528113600000, + "lte": 1528977600000, + }, + }, + }, Object { "term": Object { "service.environment": "test", @@ -695,15 +695,6 @@ Object { "service.name": "foo", }, }, - Object { - "range": Object { - "@timestamp": Object { - "format": "epoch_millis", - "gte": 1528113600000, - "lte": 1528977600000, - }, - }, - }, Object { "bool": Object { "must_not": Array [ @@ -715,6 +706,15 @@ Object { ], }, }, + Object { + "range": Object { + "@timestamp": Object { + "format": "epoch_millis", + "gte": 1528113600000, + "lte": 1528977600000, + }, + }, + }, Object { "term": Object { "service.environment": "test", @@ -864,15 +864,6 @@ Object { "service.name": "foo", }, }, - Object { - "range": Object { - "@timestamp": Object { - "format": "epoch_millis", - "gte": 1528113600000, - "lte": 1528977600000, - }, - }, - }, Object { "bool": Object { "must_not": Array [ @@ -884,6 +875,15 @@ Object { ], }, }, + Object { + "range": Object { + "@timestamp": Object { + "format": "epoch_millis", + "gte": 1528113600000, + "lte": 1528977600000, + }, + }, + }, Object { "term": Object { "service.environment": "test", @@ -963,15 +963,6 @@ Object { "service.name": "foo", }, }, - Object { - "range": Object { - "@timestamp": Object { - "format": "epoch_millis", - "gte": 1528113600000, - "lte": 1528977600000, - }, - }, - }, Object { "bool": Object { "must_not": Array [ @@ -983,6 +974,15 @@ Object { ], }, }, + Object { + "range": Object { + "@timestamp": Object { + "format": "epoch_millis", + "gte": 1528113600000, + "lte": 1528977600000, + }, + }, + }, Object { "term": Object { "service.environment": "test", @@ -1052,15 +1052,6 @@ Object { "service.name": "foo", }, }, - Object { - "range": Object { - "@timestamp": Object { - "format": "epoch_millis", - "gte": 1528113600000, - "lte": 1528977600000, - }, - }, - }, Object { "bool": Object { "must_not": Array [ @@ -1072,6 +1063,15 @@ Object { ], }, }, + Object { + "range": Object { + "@timestamp": Object { + "format": "epoch_millis", + "gte": 1528113600000, + "lte": 1528977600000, + }, + }, + }, Object { "term": Object { "service.environment": "test", diff --git a/x-pack/plugins/apm/server/lib/metrics/by_agent/default.ts b/x-pack/plugins/apm/server/lib/metrics/by_agent/default.ts index e03be2391597d4..c5e80600b69d43 100644 --- a/x-pack/plugins/apm/server/lib/metrics/by_agent/default.ts +++ b/x-pack/plugins/apm/server/lib/metrics/by_agent/default.ts @@ -9,13 +9,18 @@ import { Setup, SetupTimeRange } from '../../helpers/setup_request'; import { getCPUChartData } from './shared/cpu'; import { getMemoryChartData } from './shared/memory'; -export async function getDefaultMetricsCharts( - setup: Setup & SetupTimeRange, - serviceName: string -) { +export async function getDefaultMetricsCharts({ + environment, + serviceName, + setup, +}: { + environment?: string; + serviceName: string; + setup: Setup & SetupTimeRange; +}) { const charts = await Promise.all([ - getCPUChartData({ setup, serviceName }), - getMemoryChartData({ setup, serviceName }), + getCPUChartData({ environment, setup, serviceName }), + getMemoryChartData({ environment, setup, serviceName }), ]); return { charts }; diff --git a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/fetch_and_transform_gc_metrics.ts b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/fetch_and_transform_gc_metrics.ts index e76ad10b535b09..d7c9294c8ec7a1 100644 --- a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/fetch_and_transform_gc_metrics.ts +++ b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/fetch_and_transform_gc_metrics.ts @@ -22,12 +22,14 @@ import { getBucketSize } from '../../../../helpers/get_bucket_size'; import { getVizColorForIndex } from '../../../../../../common/viz_colors'; export async function fetchAndTransformGcMetrics({ + environment, setup, serviceName, serviceNodeName, chartBase, fieldName, }: { + environment?: string; setup: Setup & SetupTimeRange; serviceName: string; serviceNodeName?: string; @@ -39,6 +41,7 @@ export async function fetchAndTransformGcMetrics({ const { bucketSize } = getBucketSize({ start, end }); const projection = getMetricsProjection({ + environment, setup, serviceName, serviceNodeName, diff --git a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/get_gc_rate_chart.ts b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/get_gc_rate_chart.ts index 7989f57046ae78..8c5b9fb3db9221 100644 --- a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/get_gc_rate_chart.ts +++ b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/get_gc_rate_chart.ts @@ -33,16 +33,19 @@ const chartBase: ChartBase = { }; function getGcRateChart({ + environment, setup, serviceName, serviceNodeName, }: { + environment?: string; setup: Setup & SetupTimeRange; serviceName: string; serviceNodeName?: string; }) { return withApmSpan('get_gc_rate_charts', () => fetchAndTransformGcMetrics({ + environment, setup, serviceName, serviceNodeName, diff --git a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/get_gc_time_chart.ts b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/get_gc_time_chart.ts index 446894f82b75e3..98f31f06c1b644 100644 --- a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/get_gc_time_chart.ts +++ b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/get_gc_time_chart.ts @@ -33,16 +33,19 @@ const chartBase: ChartBase = { }; function getGcTimeChart({ + environment, setup, serviceName, serviceNodeName, }: { + environment?: string; setup: Setup & SetupTimeRange; serviceName: string; serviceNodeName?: string; }) { return withApmSpan('get_gc_time_charts', () => fetchAndTransformGcMetrics({ + environment, setup, serviceName, serviceNodeName, diff --git a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/heap_memory/index.ts b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/heap_memory/index.ts index 2b7bb9ea8da6ed..d6cbc4a07e8f9b 100644 --- a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/heap_memory/index.ts +++ b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/heap_memory/index.ts @@ -53,16 +53,19 @@ const chartBase: ChartBase = { }; export function getHeapMemoryChart({ + environment, setup, serviceName, serviceNodeName, }: { + environment?: string; setup: Setup & SetupTimeRange; serviceName: string; serviceNodeName?: string; }) { return withApmSpan('get_heap_memory_charts', () => fetchAndTransformMetrics({ + environment, setup, serviceName, serviceNodeName, diff --git a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/index.ts b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/index.ts index e137720000262a..970b4d3499b798 100644 --- a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/index.ts +++ b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/index.ts @@ -16,23 +16,30 @@ import { getGcRateChart } from './gc/get_gc_rate_chart'; import { getGcTimeChart } from './gc/get_gc_time_chart'; export function getJavaMetricsCharts({ + environment, setup, serviceName, serviceNodeName, }: { + environment?: string; setup: Setup & SetupTimeRange; serviceName: string; serviceNodeName?: string; }) { return withApmSpan('get_java_system_metric_charts', async () => { const charts = await Promise.all([ - getCPUChartData({ setup, serviceName, serviceNodeName }), - getMemoryChartData({ setup, serviceName, serviceNodeName }), - getHeapMemoryChart({ setup, serviceName, serviceNodeName }), - getNonHeapMemoryChart({ setup, serviceName, serviceNodeName }), - getThreadCountChart({ setup, serviceName, serviceNodeName }), - getGcRateChart({ setup, serviceName, serviceNodeName }), - getGcTimeChart({ setup, serviceName, serviceNodeName }), + getCPUChartData({ environment, setup, serviceName, serviceNodeName }), + getMemoryChartData({ environment, setup, serviceName, serviceNodeName }), + getHeapMemoryChart({ environment, setup, serviceName, serviceNodeName }), + getNonHeapMemoryChart({ + environment, + setup, + serviceName, + serviceNodeName, + }), + getThreadCountChart({ environment, setup, serviceName, serviceNodeName }), + getGcRateChart({ environment, setup, serviceName, serviceNodeName }), + getGcTimeChart({ environment, setup, serviceName, serviceNodeName }), ]); return { charts }; diff --git a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/non_heap_memory/index.ts b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/non_heap_memory/index.ts index a3e253d2c81d67..25abd2c34c83a9 100644 --- a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/non_heap_memory/index.ts +++ b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/non_heap_memory/index.ts @@ -50,16 +50,19 @@ const chartBase: ChartBase = { }; export async function getNonHeapMemoryChart({ + environment, setup, serviceName, serviceNodeName, }: { + environment?: string; setup: Setup & SetupTimeRange; serviceName: string; serviceNodeName?: string; }) { return withApmSpan('get_non_heap_memory_charts', () => fetchAndTransformMetrics({ + environment, setup, serviceName, serviceNodeName, diff --git a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/thread_count/index.ts b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/thread_count/index.ts index e176c156ad05a5..c8a209fee701a1 100644 --- a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/thread_count/index.ts +++ b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/thread_count/index.ts @@ -42,16 +42,19 @@ const chartBase: ChartBase = { }; export async function getThreadCountChart({ + environment, setup, serviceName, serviceNodeName, }: { + environment?: string; setup: Setup & SetupTimeRange; serviceName: string; serviceNodeName?: string; }) { return withApmSpan('get_thread_count_charts', () => fetchAndTransformMetrics({ + environment, setup, serviceName, serviceNodeName, diff --git a/x-pack/plugins/apm/server/lib/metrics/by_agent/shared/cpu/index.ts b/x-pack/plugins/apm/server/lib/metrics/by_agent/shared/cpu/index.ts index e7f576b73c5aef..ebfe504e5269b7 100644 --- a/x-pack/plugins/apm/server/lib/metrics/by_agent/shared/cpu/index.ts +++ b/x-pack/plugins/apm/server/lib/metrics/by_agent/shared/cpu/index.ts @@ -54,16 +54,19 @@ const chartBase: ChartBase = { }; export function getCPUChartData({ + environment, setup, serviceName, serviceNodeName, }: { + environment?: string; setup: Setup & SetupTimeRange; serviceName: string; serviceNodeName?: string; }) { return withApmSpan('get_cpu_metric_charts', () => fetchAndTransformMetrics({ + environment, setup, serviceName, serviceNodeName, diff --git a/x-pack/plugins/apm/server/lib/metrics/by_agent/shared/memory/index.ts b/x-pack/plugins/apm/server/lib/metrics/by_agent/shared/memory/index.ts index 0f7954d86d3e2c..55b3328bcd2a9b 100644 --- a/x-pack/plugins/apm/server/lib/metrics/by_agent/shared/memory/index.ts +++ b/x-pack/plugins/apm/server/lib/metrics/by_agent/shared/memory/index.ts @@ -71,10 +71,12 @@ export const percentCgroupMemoryUsedScript = { }; export async function getMemoryChartData({ + environment, setup, serviceName, serviceNodeName, }: { + environment?: string; setup: Setup & SetupTimeRange; serviceName: string; serviceNodeName?: string; @@ -84,6 +86,7 @@ export async function getMemoryChartData({ 'get_cgroup_memory_metrics_charts', () => fetchAndTransformMetrics({ + environment, setup, serviceName, serviceNodeName, @@ -101,6 +104,7 @@ export async function getMemoryChartData({ if (cgroupResponse.noHits) { return await withApmSpan('get_system_memory_metrics_charts', () => fetchAndTransformMetrics({ + environment, setup, serviceName, serviceNodeName, diff --git a/x-pack/plugins/apm/server/lib/metrics/fetch_and_transform_metrics.ts b/x-pack/plugins/apm/server/lib/metrics/fetch_and_transform_metrics.ts index 7a52806601e0e8..17e9aef29ba82d 100644 --- a/x-pack/plugins/apm/server/lib/metrics/fetch_and_transform_metrics.ts +++ b/x-pack/plugins/apm/server/lib/metrics/fetch_and_transform_metrics.ts @@ -48,6 +48,7 @@ interface Filter { } export async function fetchAndTransformMetrics({ + environment, setup, serviceName, serviceNodeName, @@ -55,6 +56,7 @@ export async function fetchAndTransformMetrics({ aggs, additionalFilters = [], }: { + environment?: string; setup: Setup & SetupTimeRange; serviceName: string; serviceNodeName?: string; @@ -65,6 +67,7 @@ export async function fetchAndTransformMetrics({ const { start, end, apmEventClient, config } = setup; const projection = getMetricsProjection({ + environment, setup, serviceName, serviceNodeName, diff --git a/x-pack/plugins/apm/server/lib/metrics/get_metrics_chart_data_by_agent.ts b/x-pack/plugins/apm/server/lib/metrics/get_metrics_chart_data_by_agent.ts index 5083982f1cb9cb..eda71ef380ee9c 100644 --- a/x-pack/plugins/apm/server/lib/metrics/get_metrics_chart_data_by_agent.ts +++ b/x-pack/plugins/apm/server/lib/metrics/get_metrics_chart_data_by_agent.ts @@ -15,11 +15,13 @@ export interface MetricsChartsByAgentAPIResponse { } export async function getMetricsChartDataByAgent({ + environment, setup, serviceName, serviceNodeName, agentName, }: { + environment?: string; setup: Setup & SetupTimeRange; serviceName: string; serviceNodeName?: string; @@ -27,11 +29,16 @@ export async function getMetricsChartDataByAgent({ }): Promise { switch (agentName) { case 'java': { - return getJavaMetricsCharts({ setup, serviceName, serviceNodeName }); + return getJavaMetricsCharts({ + environment, + setup, + serviceName, + serviceNodeName, + }); } default: { - return getDefaultMetricsCharts(setup, serviceName); + return getDefaultMetricsCharts({ environment, setup, serviceName }); } } } diff --git a/x-pack/plugins/apm/server/lib/observability_overview/get_service_count.ts b/x-pack/plugins/apm/server/lib/observability_overview/get_service_count.ts index 4af57a685bf839..c7ac678899b58c 100644 --- a/x-pack/plugins/apm/server/lib/observability_overview/get_service_count.ts +++ b/x-pack/plugins/apm/server/lib/observability_overview/get_service_count.ts @@ -6,7 +6,7 @@ */ import { ProcessorEvent } from '../../../common/processor_event'; -import { rangeFilter } from '../../../common/utils/range_filter'; +import { rangeQuery } from '../../../common/utils/queries'; import { SERVICE_NAME } from '../../../common/elasticsearch_fieldnames'; import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { getProcessorEventForAggregatedTransactions } from '../helpers/aggregated_transactions'; @@ -36,7 +36,7 @@ export function getServiceCount({ size: 0, query: { bool: { - filter: [{ range: rangeFilter(start, end) }], + filter: rangeQuery(start, end), }, }, aggs: { serviceCount: { cardinality: { field: SERVICE_NAME } } }, diff --git a/x-pack/plugins/apm/server/lib/observability_overview/get_transaction_coordinates.ts b/x-pack/plugins/apm/server/lib/observability_overview/get_transaction_coordinates.ts index 87394567afc50b..2da4b0f8de3632 100644 --- a/x-pack/plugins/apm/server/lib/observability_overview/get_transaction_coordinates.ts +++ b/x-pack/plugins/apm/server/lib/observability_overview/get_transaction_coordinates.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { rangeFilter } from '../../../common/utils/range_filter'; +import { rangeQuery } from '../../../common/utils/queries'; import { Coordinates } from '../../../../observability/typings/common'; import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { getProcessorEventForAggregatedTransactions } from '../helpers/aggregated_transactions'; @@ -38,7 +38,7 @@ export function getTransactionCoordinates({ size: 0, query: { bool: { - filter: [{ range: rangeFilter(start, end) }], + filter: rangeQuery(start, end), }, }, aggs: { diff --git a/x-pack/plugins/apm/server/lib/rum_client/has_rum_data.ts b/x-pack/plugins/apm/server/lib/rum_client/has_rum_data.ts index 368c5ec5463592..9626019347e5bb 100644 --- a/x-pack/plugins/apm/server/lib/rum_client/has_rum_data.ts +++ b/x-pack/plugins/apm/server/lib/rum_client/has_rum_data.ts @@ -11,7 +11,7 @@ import { TRANSACTION_TYPE, } from '../../../common/elasticsearch_fieldnames'; import { ProcessorEvent } from '../../../common/processor_event'; -import { rangeFilter } from '../../../common/utils/range_filter'; +import { rangeQuery } from '../../../common/utils/queries'; import { TRANSACTION_PAGE_LOAD } from '../../../common/transaction_types'; export async function hasRumData({ setup }: { setup: Setup & SetupTimeRange }) { @@ -31,9 +31,7 @@ export async function hasRumData({ setup }: { setup: Setup & SetupTimeRange }) { }, aggs: { services: { - filter: { - range: rangeFilter(start, end), - }, + filter: rangeQuery(start, end)[0], aggs: { mostTraffic: { terms: { diff --git a/x-pack/plugins/apm/server/lib/service_map/fetch_service_paths_from_trace_ids.ts b/x-pack/plugins/apm/server/lib/service_map/fetch_service_paths_from_trace_ids.ts index 939ebbb1f79419..259a0e6daea6fc 100644 --- a/x-pack/plugins/apm/server/lib/service_map/fetch_service_paths_from_trace_ids.ts +++ b/x-pack/plugins/apm/server/lib/service_map/fetch_service_paths_from_trace_ids.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { rangeFilter } from '../../../common/utils/range_filter'; +import { rangeQuery } from '../../../common/utils/queries'; import { ProcessorEvent } from '../../../common/processor_event'; import { TRACE_ID } from '../../../common/elasticsearch_fieldnames'; import { @@ -42,7 +42,7 @@ export async function fetchServicePathsFromTraceIds( [TRACE_ID]: traceIds, }, }, - { range: rangeFilter(start, end) }, + ...rangeQuery(start, end), ], }, }, diff --git a/x-pack/plugins/apm/server/lib/service_map/get_service_anomalies.ts b/x-pack/plugins/apm/server/lib/service_map/get_service_anomalies.ts index 2c64678eb082ec..ab221e30ea4897 100644 --- a/x-pack/plugins/apm/server/lib/service_map/get_service_anomalies.ts +++ b/x-pack/plugins/apm/server/lib/service_map/get_service_anomalies.ts @@ -17,6 +17,7 @@ import { TRANSACTION_PAGE_LOAD, TRANSACTION_REQUEST, } from '../../../common/transaction_types'; +import { rangeQuery } from '../../../common/utils/queries'; import { withApmSpan } from '../../utils/with_apm_span'; import { getMlJobsWithAPMGroup } from '../anomaly_detection/get_ml_jobs_with_apm_group'; import { Setup, SetupTimeRange } from '../helpers/setup_request'; @@ -51,16 +52,11 @@ export async function getServiceAnomalies({ bool: { filter: [ { terms: { result_type: ['model_plot', 'record'] } }, - { - range: { - timestamp: { - // fetch data for at least 30 minutes - gte: Math.min(end - 30 * 60 * 1000, start), - lte: end, - format: 'epoch_millis', - }, - }, - }, + ...rangeQuery( + Math.min(end - 30 * 60 * 1000, start), + end, + 'timestamp' + ), { terms: { // Only retrieving anomalies for transaction types "request" and "page-load" diff --git a/x-pack/plugins/apm/server/lib/service_map/get_service_map.ts b/x-pack/plugins/apm/server/lib/service_map/get_service_map.ts index 951484308db195..1aee1bb5b242af 100644 --- a/x-pack/plugins/apm/server/lib/service_map/get_service_map.ts +++ b/x-pack/plugins/apm/server/lib/service_map/get_service_map.ts @@ -15,8 +15,8 @@ import { } from '../../../common/elasticsearch_fieldnames'; import { getServicesProjection } from '../../projections/services'; import { mergeProjection } from '../../projections/util/merge_projection'; +import { environmentQuery } from '../../../common/utils/queries'; import { withApmSpan } from '../../utils/with_apm_span'; -import { getEnvironmentUiFilterES } from '../helpers/convert_ui_filters/get_environment_ui_filter_es'; import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { DEFAULT_ANOMALIES, @@ -88,14 +88,17 @@ async function getConnectionData({ async function getServicesData(options: IEnvOptions) { return withApmSpan('get_service_stats_for_service_map', async () => { - const { setup, searchAggregatedTransactions } = options; + const { environment, setup, searchAggregatedTransactions } = options; const projection = getServicesProjection({ setup: { ...setup, esFilter: [] }, searchAggregatedTransactions, }); - let { filter } = projection.body.query.bool; + let filter = [ + ...projection.body.query.bool.filter, + ...environmentQuery(environment), + ]; if (options.serviceName) { filter = filter.concat({ @@ -105,10 +108,6 @@ async function getServicesData(options: IEnvOptions) { }); } - if (options.environment) { - filter = filter.concat(getEnvironmentUiFilterES(options.environment)); - } - const params = mergeProjection(projection, { body: { size: 0, diff --git a/x-pack/plugins/apm/server/lib/service_map/get_service_map_from_trace_ids.ts b/x-pack/plugins/apm/server/lib/service_map/get_service_map_from_trace_ids.ts index ef4faf94063461..6e9225041b199c 100644 --- a/x-pack/plugins/apm/server/lib/service_map/get_service_map_from_trace_ids.ts +++ b/x-pack/plugins/apm/server/lib/service_map/get_service_map_from_trace_ids.ts @@ -6,7 +6,10 @@ */ import { find, uniqBy } from 'lodash'; -import { ENVIRONMENT_NOT_DEFINED } from '../../../common/environment_filter_values'; +import { + ENVIRONMENT_ALL, + ENVIRONMENT_NOT_DEFINED, +} from '../../../common/environment_filter_values'; import { SERVICE_ENVIRONMENT, SERVICE_NAME, @@ -27,8 +30,10 @@ export function getConnections({ if (!paths) { return []; } + const isEnvironmentSelected = + environment && environment !== ENVIRONMENT_ALL.value; - if (serviceName || environment) { + if (serviceName || isEnvironmentSelected) { paths = paths.filter((path) => { return ( path diff --git a/x-pack/plugins/apm/server/lib/service_map/get_service_map_service_node_info.test.ts b/x-pack/plugins/apm/server/lib/service_map/get_service_map_service_node_info.test.ts index 63f28abab8f3aa..b161345e729d35 100644 --- a/x-pack/plugins/apm/server/lib/service_map/get_service_map_service_node_info.test.ts +++ b/x-pack/plugins/apm/server/lib/service_map/get_service_map_service_node_info.test.ts @@ -19,11 +19,13 @@ describe('getServiceMapServiceNodeInfo', () => { hits: { total: { value: 0 } }, }), }, + esFilter: [], indices: {}, - uiFilters: { environment: 'test environment' }, + uiFilters: {}, } as unknown) as Setup & SetupTimeRange; const serviceName = 'test service name'; const result = await getServiceMapServiceNodeInfo({ + environment: 'test environment', setup, serviceName, searchAggregatedTransactions: false, diff --git a/x-pack/plugins/apm/server/lib/service_map/get_service_map_service_node_info.ts b/x-pack/plugins/apm/server/lib/service_map/get_service_map_service_node_info.ts index 213702bf06f4ce..e384b15685dad4 100644 --- a/x-pack/plugins/apm/server/lib/service_map/get_service_map_service_node_info.ts +++ b/x-pack/plugins/apm/server/lib/service_map/get_service_map_service_node_info.ts @@ -19,14 +19,13 @@ import { TRANSACTION_PAGE_LOAD, TRANSACTION_REQUEST, } from '../../../common/transaction_types'; -import { rangeFilter } from '../../../common/utils/range_filter'; +import { environmentQuery, rangeQuery } from '../../../common/utils/queries'; import { withApmSpan } from '../../utils/with_apm_span'; import { getDocumentTypeFilterForAggregatedTransactions, getProcessorEventForAggregatedTransactions, getTransactionDurationFieldForAggregatedTransactions, } from '../helpers/aggregated_transactions'; -import { getEnvironmentUiFilterES } from '../helpers/convert_ui_filters/get_environment_ui_filter_es'; import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { percentCgroupMemoryUsedScript, @@ -51,6 +50,7 @@ interface TaskParameters { } export function getServiceMapServiceNodeInfo({ + environment, serviceName, setup, searchAggregatedTransactions, @@ -59,9 +59,9 @@ export function getServiceMapServiceNodeInfo({ const { start, end, uiFilters } = setup; const filter: ESFilter[] = [ - { range: rangeFilter(start, end) }, { term: { [SERVICE_NAME]: serviceName } }, - ...getEnvironmentUiFilterES(uiFilters.environment), + ...rangeQuery(start, end), + ...environmentQuery(environment), ]; const minutes = Math.abs((end - start) / (1000 * 60)); @@ -106,16 +106,13 @@ async function getErrorStats({ searchAggregatedTransactions: boolean; }) { return withApmSpan('get_error_rate_for_service_map_node', async () => { - const setupWithBlankUiFilters = { - ...setup, - uiFilters: { environment }, - esFilter: getEnvironmentUiFilterES(environment), - }; const { noHits, average } = await getErrorRate({ - setup: setupWithBlankUiFilters, + environment, + setup, serviceName, searchAggregatedTransactions, }); + return { avgErrorRate: noHits ? null : average }; }); } diff --git a/x-pack/plugins/apm/server/lib/service_map/get_trace_sample_ids.ts b/x-pack/plugins/apm/server/lib/service_map/get_trace_sample_ids.ts index deb9104a839051..e8dcb28baa9a38 100644 --- a/x-pack/plugins/apm/server/lib/service_map/get_trace_sample_ids.ts +++ b/x-pack/plugins/apm/server/lib/service_map/get_trace_sample_ids.ts @@ -16,9 +16,8 @@ import { } from '../../../common/elasticsearch_fieldnames'; import { ProcessorEvent } from '../../../common/processor_event'; import { SERVICE_MAP_TIMEOUT_ERROR } from '../../../common/service_map'; -import { rangeFilter } from '../../../common/utils/range_filter'; +import { environmentQuery, rangeQuery } from '../../../common/utils/queries'; import { withApmSpan } from '../../utils/with_apm_span'; -import { getEnvironmentUiFilterES } from '../helpers/convert_ui_filters/get_environment_ui_filter_es'; import { Setup, SetupTimeRange } from '../helpers/setup_request'; const MAX_TRACES_TO_INSPECT = 1000; @@ -35,8 +34,6 @@ export function getTraceSampleIds({ return withApmSpan('get_trace_sample_ids', async () => { const { start, end, apmEventClient, config } = setup; - const rangeQuery = { range: rangeFilter(start, end) }; - const query = { bool: { filter: [ @@ -45,7 +42,7 @@ export function getTraceSampleIds({ field: SPAN_DESTINATION_SERVICE_RESOURCE, }, }, - rangeQuery, + ...rangeQuery(start, end), ] as ESFilter[], }, } as { bool: { filter: ESFilter[]; must_not?: ESFilter[] | ESFilter } }; @@ -54,7 +51,7 @@ export function getTraceSampleIds({ query.bool.filter.push({ term: { [SERVICE_NAME]: serviceName } }); } - query.bool.filter.push(...getEnvironmentUiFilterES(environment)); + query.bool.filter.push(...environmentQuery(environment)); const fingerprintBucketSize = serviceName ? config['xpack.apm.serviceMapFingerprintBucketSize'] diff --git a/x-pack/plugins/apm/server/lib/service_nodes/__snapshots__/queries.test.ts.snap b/x-pack/plugins/apm/server/lib/service_nodes/__snapshots__/queries.test.ts.snap index d83e558775be40..e6d702cc03c0b1 100644 --- a/x-pack/plugins/apm/server/lib/service_nodes/__snapshots__/queries.test.ts.snap +++ b/x-pack/plugins/apm/server/lib/service_nodes/__snapshots__/queries.test.ts.snap @@ -35,6 +35,11 @@ Object { "service.name": "foo", }, }, + Object { + "term": Object { + "service.node.name": "bar", + }, + }, Object { "range": Object { "@timestamp": Object { @@ -44,11 +49,6 @@ Object { }, }, }, - Object { - "term": Object { - "service.node.name": "bar", - }, - }, Object { "term": Object { "service.environment": "test", @@ -97,15 +97,6 @@ Object { "service.name": "foo", }, }, - Object { - "range": Object { - "@timestamp": Object { - "format": "epoch_millis", - "gte": 1528113600000, - "lte": 1528977600000, - }, - }, - }, Object { "bool": Object { "must_not": Array [ @@ -117,6 +108,15 @@ Object { ], }, }, + Object { + "range": Object { + "@timestamp": Object { + "format": "epoch_millis", + "gte": 1528113600000, + "lte": 1528977600000, + }, + }, + }, Object { "term": Object { "service.environment": "test", diff --git a/x-pack/plugins/apm/server/lib/services/annotations/get_derived_service_annotations.ts b/x-pack/plugins/apm/server/lib/services/annotations/get_derived_service_annotations.ts index 7c746aac29af92..67aa9d7fcd8707 100644 --- a/x-pack/plugins/apm/server/lib/services/annotations/get_derived_service_annotations.ts +++ b/x-pack/plugins/apm/server/lib/services/annotations/get_derived_service_annotations.ts @@ -12,13 +12,12 @@ import { SERVICE_NAME, SERVICE_VERSION, } from '../../../../common/elasticsearch_fieldnames'; -import { rangeFilter } from '../../../../common/utils/range_filter'; +import { environmentQuery, rangeQuery } from '../../../../common/utils/queries'; import { withApmSpan } from '../../../utils/with_apm_span'; import { getDocumentTypeFilterForAggregatedTransactions, getProcessorEventForAggregatedTransactions, } from '../../helpers/aggregated_transactions'; -import { getEnvironmentUiFilterES } from '../../helpers/convert_ui_filters/get_environment_ui_filter_es'; import { Setup, SetupTimeRange } from '../../helpers/setup_request'; export async function getDerivedServiceAnnotations({ @@ -40,7 +39,7 @@ export async function getDerivedServiceAnnotations({ ...getDocumentTypeFilterForAggregatedTransactions( searchAggregatedTransactions ), - ...getEnvironmentUiFilterES(environment), + ...environmentQuery(environment), ]; const versions = @@ -57,7 +56,7 @@ export async function getDerivedServiceAnnotations({ size: 0, query: { bool: { - filter: [...filter, { range: rangeFilter(start, end) }], + filter: [...filter, ...rangeQuery(start, end)], }, }, aggs: { diff --git a/x-pack/plugins/apm/server/lib/services/annotations/get_stored_annotations.ts b/x-pack/plugins/apm/server/lib/services/annotations/get_stored_annotations.ts index fc53f763dac0ff..6c7cbc26ea6536 100644 --- a/x-pack/plugins/apm/server/lib/services/annotations/get_stored_annotations.ts +++ b/x-pack/plugins/apm/server/lib/services/annotations/get_stored_annotations.ts @@ -5,19 +5,18 @@ * 2.0. */ -import { ElasticsearchClient, Logger } from 'kibana/server'; import { ResponseError } from '@elastic/elasticsearch/lib/errors'; +import { ElasticsearchClient, Logger } from 'kibana/server'; +import { environmentQuery, rangeQuery } from '../../../../common/utils/queries'; import { unwrapEsResponse, WrappedElasticsearchClientError, } from '../../../../../observability/server'; -import { rangeFilter } from '../../../../common/utils/range_filter'; import { ESSearchResponse } from '../../../../../../typings/elasticsearch'; import { Annotation as ESAnnotation } from '../../../../../observability/common/annotations'; import { ScopedAnnotationsClient } from '../../../../../observability/server'; import { Annotation, AnnotationType } from '../../../../common/annotations'; import { SERVICE_NAME } from '../../../../common/elasticsearch_fieldnames'; -import { getEnvironmentUiFilterES } from '../../helpers/convert_ui_filters/get_environment_ui_filter_es'; import { Setup, SetupTimeRange } from '../../helpers/setup_request'; import { withApmSpan } from '../../../utils/with_apm_span'; @@ -37,18 +36,18 @@ export function getStoredAnnotations({ logger: Logger; }): Promise { return withApmSpan('get_stored_annotations', async () => { + const { start, end } = setup; + const body = { size: 50, query: { bool: { filter: [ - { - range: rangeFilter(setup.start, setup.end), - }, { term: { 'annotation.type': 'deployment' } }, { term: { tags: 'apm' } }, { term: { [SERVICE_NAME]: serviceName } }, - ...getEnvironmentUiFilterES(environment), + ...rangeQuery(start, end), + ...environmentQuery(environment), ], }, }, diff --git a/x-pack/plugins/apm/server/lib/services/get_service_agent_name.ts b/x-pack/plugins/apm/server/lib/services/get_service_agent_name.ts index 29c77da6e4075f..3683a069342a9b 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_agent_name.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_agent_name.ts @@ -10,7 +10,7 @@ import { AGENT_NAME, SERVICE_NAME, } from '../../../common/elasticsearch_fieldnames'; -import { rangeFilter } from '../../../common/utils/range_filter'; +import { rangeQuery } from '../../../common/utils/queries'; import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { getProcessorEventForAggregatedTransactions } from '../helpers/aggregated_transactions'; import { withApmSpan } from '../../utils/with_apm_span'; @@ -44,7 +44,7 @@ export function getServiceAgentName({ bool: { filter: [ { term: { [SERVICE_NAME]: serviceName } }, - { range: rangeFilter(start, end) }, + ...rangeQuery(start, end), ], }, }, diff --git a/x-pack/plugins/apm/server/lib/services/get_service_dependencies/get_destination_map.ts b/x-pack/plugins/apm/server/lib/services/get_service_dependencies/get_destination_map.ts index aa53e8da6cad05..558d6ae22f00f5 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_dependencies/get_destination_map.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_dependencies/get_destination_map.ts @@ -19,9 +19,8 @@ import { SPAN_SUBTYPE, SPAN_TYPE, } from '../../../../common/elasticsearch_fieldnames'; -import { rangeFilter } from '../../../../common/utils/range_filter'; import { ProcessorEvent } from '../../../../common/processor_event'; -import { getEnvironmentUiFilterES } from '../../helpers/convert_ui_filters/get_environment_ui_filter_es'; +import { environmentQuery, rangeQuery } from '../../../../common/utils/queries'; import { joinByKey } from '../../../../common/utils/join_by_key'; import { Setup, SetupTimeRange } from '../../helpers/setup_request'; import { withApmSpan } from '../../../utils/with_apm_span'; @@ -33,7 +32,7 @@ export const getDestinationMap = ({ }: { setup: Setup & SetupTimeRange; serviceName: string; - environment: string; + environment?: string; }) => { return withApmSpan('get_service_destination_map', async () => { const { start, end, apmEventClient } = setup; @@ -50,8 +49,8 @@ export const getDestinationMap = ({ filter: [ { term: { [SERVICE_NAME]: serviceName } }, { exists: { field: SPAN_DESTINATION_SERVICE_RESOURCE } }, - { range: rangeFilter(start, end) }, - ...getEnvironmentUiFilterES(environment), + ...rangeQuery(start, end), + ...environmentQuery(environment), ], }, }, @@ -122,7 +121,7 @@ export const getDestinationMap = ({ ), }, }, - { range: rangeFilter(start, end) }, + ...rangeQuery(start, end), ], }, }, diff --git a/x-pack/plugins/apm/server/lib/services/get_service_dependencies/get_metrics.ts b/x-pack/plugins/apm/server/lib/services/get_service_dependencies/get_metrics.ts index 9a020daa7e095d..dfbdfb3f504e8c 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_dependencies/get_metrics.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_dependencies/get_metrics.ts @@ -13,9 +13,8 @@ import { SPAN_DESTINATION_SERVICE_RESPONSE_TIME_COUNT, SPAN_DESTINATION_SERVICE_RESPONSE_TIME_SUM, } from '../../../../common/elasticsearch_fieldnames'; -import { rangeFilter } from '../../../../common/utils/range_filter'; import { ProcessorEvent } from '../../../../common/processor_event'; -import { getEnvironmentUiFilterES } from '../../helpers/convert_ui_filters/get_environment_ui_filter_es'; +import { environmentQuery, rangeQuery } from '../../../../common/utils/queries'; import { getBucketSize } from '../../helpers/get_bucket_size'; import { EventOutcome } from '../../../../common/event_outcome'; import { Setup, SetupTimeRange } from '../../helpers/setup_request'; @@ -29,7 +28,7 @@ export const getMetrics = ({ }: { setup: Setup & SetupTimeRange; serviceName: string; - environment: string; + environment?: string; numBuckets: number; }) => { return withApmSpan('get_service_destination_metrics', async () => { @@ -49,8 +48,8 @@ export const getMetrics = ({ { exists: { field: SPAN_DESTINATION_SERVICE_RESPONSE_TIME_COUNT }, }, - { range: rangeFilter(start, end) }, - ...getEnvironmentUiFilterES(environment), + ...rangeQuery(start, end), + ...environmentQuery(environment), ], }, }, diff --git a/x-pack/plugins/apm/server/lib/services/get_service_dependencies/index.ts b/x-pack/plugins/apm/server/lib/services/get_service_dependencies/index.ts index 19f306f5cb8035..724b5278d7edfc 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_dependencies/index.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_dependencies/index.ts @@ -51,7 +51,7 @@ export function getServiceDependencies({ }: { serviceName: string; setup: Setup & SetupTimeRange; - environment: string; + environment?: string; numBuckets: number; }): Promise { return withApmSpan('get_service_dependencies', async () => { diff --git a/x-pack/plugins/apm/server/lib/services/get_service_error_groups/index.ts b/x-pack/plugins/apm/server/lib/services/get_service_error_groups/index.ts index f5aa01e1dfa58a..a17fb6da2007fa 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_error_groups/index.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_error_groups/index.ts @@ -9,7 +9,7 @@ import { ValuesType } from 'utility-types'; import { orderBy } from 'lodash'; import { NOT_AVAILABLE_LABEL } from '../../../../common/i18n'; import { PromiseReturnType } from '../../../../../observability/typings/common'; -import { rangeFilter } from '../../../../common/utils/range_filter'; +import { environmentQuery, rangeQuery } from '../../../../common/utils/queries'; import { ProcessorEvent } from '../../../../common/processor_event'; import { ERROR_EXC_MESSAGE, @@ -28,6 +28,7 @@ export type ServiceErrorGroupItem = ValuesType< >; export async function getServiceErrorGroups({ + environment, serviceName, setup, size, @@ -37,6 +38,7 @@ export async function getServiceErrorGroups({ sortField, transactionType, }: { + environment?: string; serviceName: string; setup: Setup & SetupTimeRange; size: number; @@ -63,7 +65,8 @@ export async function getServiceErrorGroups({ filter: [ { term: { [SERVICE_NAME]: serviceName } }, { term: { [TRANSACTION_TYPE]: transactionType } }, - { range: rangeFilter(start, end) }, + ...rangeQuery(start, end), + ...environmentQuery(environment), ...esFilter, ], }, @@ -145,7 +148,8 @@ export async function getServiceErrorGroups({ { terms: { [ERROR_GROUP_ID]: sortedErrorGroupIds } }, { term: { [SERVICE_NAME]: serviceName } }, { term: { [TRANSACTION_TYPE]: transactionType } }, - { range: rangeFilter(start, end) }, + ...rangeQuery(start, end), + ...environmentQuery(environment), ...esFilter, ], }, diff --git a/x-pack/plugins/apm/server/lib/services/get_service_instances/get_service_instance_system_metric_stats.ts b/x-pack/plugins/apm/server/lib/services/get_service_instances/get_service_instance_system_metric_stats.ts index 4f8088352d0ae2..ef90e5197229b9 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_instances/get_service_instance_system_metric_stats.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_instances/get_service_instance_system_metric_stats.ts @@ -6,7 +6,7 @@ */ import { AggregationOptionsByType } from '../../../../../../typings/elasticsearch'; -import { rangeFilter } from '../../../../common/utils/range_filter'; +import { environmentQuery, rangeQuery } from '../../../../common/utils/queries'; import { SERVICE_NODE_NAME_MISSING } from '../../../../common/service_nodes'; import { METRIC_CGROUP_MEMORY_USAGE_BYTES, @@ -26,6 +26,7 @@ import { import { withApmSpan } from '../../../utils/with_apm_span'; export async function getServiceInstanceSystemMetricStats({ + environment, setup, serviceName, size, @@ -95,8 +96,9 @@ export async function getServiceInstanceSystemMetricStats({ query: { bool: { filter: [ - { range: rangeFilter(start, end) }, { term: { [SERVICE_NAME]: serviceName } }, + ...rangeQuery(start, end), + ...environmentQuery(environment), ...esFilter, ], should: [cgroupMemoryFilter, systemMemoryFilter, cpuUsageFilter], diff --git a/x-pack/plugins/apm/server/lib/services/get_service_instances/get_service_instance_transaction_stats.ts b/x-pack/plugins/apm/server/lib/services/get_service_instances/get_service_instance_transaction_stats.ts index 2cbe5a42206d18..b56625bcebc998 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_instances/get_service_instance_transaction_stats.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_instances/get_service_instance_transaction_stats.ts @@ -6,7 +6,7 @@ */ import { EventOutcome } from '../../../../common/event_outcome'; -import { rangeFilter } from '../../../../common/utils/range_filter'; +import { environmentQuery, rangeQuery } from '../../../../common/utils/queries'; import { SERVICE_NODE_NAME_MISSING } from '../../../../common/service_nodes'; import { EVENT_OUTCOME, @@ -24,6 +24,7 @@ import { calculateThroughput } from '../../helpers/calculate_throughput'; import { withApmSpan } from '../../../utils/with_apm_span'; export async function getServiceInstanceTransactionStats({ + environment, setup, transactionType, serviceName, @@ -72,9 +73,10 @@ export async function getServiceInstanceTransactionStats({ query: { bool: { filter: [ - { range: rangeFilter(start, end) }, { term: { [SERVICE_NAME]: serviceName } }, { term: { [TRANSACTION_TYPE]: transactionType } }, + ...rangeQuery(start, end), + ...environmentQuery(environment), ...esFilter, ], }, diff --git a/x-pack/plugins/apm/server/lib/services/get_service_instances/index.ts b/x-pack/plugins/apm/server/lib/services/get_service_instances/index.ts index 021774f9522c1b..4c16940e6d2538 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_instances/index.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_instances/index.ts @@ -12,6 +12,7 @@ import { getServiceInstanceSystemMetricStats } from './get_service_instance_syst import { getServiceInstanceTransactionStats } from './get_service_instance_transaction_stats'; export interface ServiceInstanceParams { + environment?: string; setup: Setup & SetupTimeRange; serviceName: string; transactionType: string; diff --git a/x-pack/plugins/apm/server/lib/services/get_service_metadata_details.ts b/x-pack/plugins/apm/server/lib/services/get_service_metadata_details.ts index f1198a4d858fda..5c43191cf588c2 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_metadata_details.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_metadata_details.ts @@ -21,7 +21,7 @@ import { SERVICE_VERSION, } from '../../../common/elasticsearch_fieldnames'; import { ContainerType } from '../../../common/service_metadata'; -import { rangeFilter } from '../../../common/utils/range_filter'; +import { rangeQuery } from '../../../common/utils/queries'; import { TransactionRaw } from '../../../typings/es_schemas/raw/transaction_raw'; import { getProcessorEventForAggregatedTransactions } from '../helpers/aggregated_transactions'; import { Setup, SetupTimeRange } from '../helpers/setup_request'; @@ -74,7 +74,7 @@ export function getServiceMetadataDetails({ const filter = [ { term: { [SERVICE_NAME]: serviceName } }, - { range: rangeFilter(start, end) }, + ...rangeQuery(start, end), ]; const params = { diff --git a/x-pack/plugins/apm/server/lib/services/get_service_metadata_icons.ts b/x-pack/plugins/apm/server/lib/services/get_service_metadata_icons.ts index 0ea95a08abaa98..b342ffea02464e 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_metadata_icons.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_metadata_icons.ts @@ -16,7 +16,7 @@ import { HOST_OS_PLATFORM, } from '../../../common/elasticsearch_fieldnames'; import { ContainerType } from '../../../common/service_metadata'; -import { rangeFilter } from '../../../common/utils/range_filter'; +import { rangeQuery } from '../../../common/utils/queries'; import { TransactionRaw } from '../../../typings/es_schemas/raw/transaction_raw'; import { getProcessorEventForAggregatedTransactions } from '../helpers/aggregated_transactions'; import { Setup, SetupTimeRange } from '../helpers/setup_request'; @@ -55,7 +55,7 @@ export function getServiceMetadataIcons({ const filter = [ { term: { [SERVICE_NAME]: serviceName } }, - { range: rangeFilter(start, end) }, + ...rangeQuery(start, end), ]; const params = { diff --git a/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_comparison_statistics.ts b/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_comparison_statistics.ts index 54cf89d6125b6e..ce36db3e82babe 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_comparison_statistics.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_transaction_group_comparison_statistics.ts @@ -14,7 +14,7 @@ import { } from '../../../common/elasticsearch_fieldnames'; import { EventOutcome } from '../../../common/event_outcome'; import { LatencyAggregationType } from '../../../common/latency_aggregation_types'; -import { rangeFilter } from '../../../common/utils/range_filter'; +import { environmentQuery, rangeQuery } from '../../../common/utils/queries'; import { Coordinate } from '../../../typings/timeseries'; import { withApmSpan } from '../../utils/with_apm_span'; import { @@ -31,6 +31,7 @@ import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { calculateTransactionErrorPercentage } from '../helpers/transaction_error_rate'; export async function getServiceTransactionGroupComparisonStatistics({ + environment, serviceName, transactionNames, setup, @@ -39,6 +40,7 @@ export async function getServiceTransactionGroupComparisonStatistics({ transactionType, latencyAggregationType, }: { + environment?: string; serviceName: string; transactionNames: string[]; setup: Setup & SetupTimeRange; @@ -82,10 +84,11 @@ export async function getServiceTransactionGroupComparisonStatistics({ filter: [ { term: { [SERVICE_NAME]: serviceName } }, { term: { [TRANSACTION_TYPE]: transactionType } }, - { range: rangeFilter(start, end) }, ...getDocumentTypeFilterForAggregatedTransactions( searchAggregatedTransactions ), + ...rangeQuery(start, end), + ...environmentQuery(environment), ...esFilter, ], }, diff --git a/x-pack/plugins/apm/server/lib/services/get_service_transaction_groups.ts b/x-pack/plugins/apm/server/lib/services/get_service_transaction_groups.ts index 168eed8e38374c..ddbfd617faf65b 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_transaction_groups.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_transaction_groups.ts @@ -13,7 +13,7 @@ import { } from '../../../common/elasticsearch_fieldnames'; import { EventOutcome } from '../../../common/event_outcome'; import { LatencyAggregationType } from '../../../common/latency_aggregation_types'; -import { rangeFilter } from '../../../common/utils/range_filter'; +import { environmentQuery, rangeQuery } from '../../../common/utils/queries'; import { withApmSpan } from '../../utils/with_apm_span'; import { getDocumentTypeFilterForAggregatedTransactions, @@ -36,12 +36,14 @@ export type ServiceOverviewTransactionGroupSortField = | 'impact'; export async function getServiceTransactionGroups({ + environment, serviceName, setup, searchAggregatedTransactions, transactionType, latencyAggregationType, }: { + environment?: string; serviceName: string; setup: Setup & SetupTimeRange; searchAggregatedTransactions: boolean; @@ -70,10 +72,11 @@ export async function getServiceTransactionGroups({ filter: [ { term: { [SERVICE_NAME]: serviceName } }, { term: { [TRANSACTION_TYPE]: transactionType } }, - { range: rangeFilter(start, end) }, ...getDocumentTypeFilterForAggregatedTransactions( searchAggregatedTransactions ), + ...rangeQuery(start, end), + ...environmentQuery(environment), ...esFilter, ], }, diff --git a/x-pack/plugins/apm/server/lib/services/get_service_transaction_types.ts b/x-pack/plugins/apm/server/lib/services/get_service_transaction_types.ts index bc4660e2c01a5e..3d77bf5bd6baf3 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_transaction_types.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_transaction_types.ts @@ -9,7 +9,7 @@ import { SERVICE_NAME, TRANSACTION_TYPE, } from '../../../common/elasticsearch_fieldnames'; -import { rangeFilter } from '../../../common/utils/range_filter'; +import { rangeQuery } from '../../../common/utils/queries'; import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { getDocumentTypeFilterForAggregatedTransactions, @@ -46,7 +46,7 @@ export function getServiceTransactionTypes({ searchAggregatedTransactions ), { term: { [SERVICE_NAME]: serviceName } }, - { range: rangeFilter(start, end) }, + ...rangeQuery(start, end), ], }, }, diff --git a/x-pack/plugins/apm/server/lib/services/get_services/get_health_statuses.ts b/x-pack/plugins/apm/server/lib/services/get_services/get_health_statuses.ts index e88fafb061912d..6fc868b0f0a4ec 100644 --- a/x-pack/plugins/apm/server/lib/services/get_services/get_health_statuses.ts +++ b/x-pack/plugins/apm/server/lib/services/get_services/get_health_statuses.ts @@ -8,28 +8,25 @@ import { getSeverity } from '../../../../common/anomaly_detection'; import { getServiceHealthStatus } from '../../../../common/service_health_status'; import { getServiceAnomalies } from '../../service_map/get_service_anomalies'; -import { - ServicesItemsProjection, - ServicesItemsSetup, -} from './get_services_items'; +import { ServicesItemsSetup } from './get_services_items'; interface AggregationParams { + environment?: string; setup: ServicesItemsSetup; - projection: ServicesItemsProjection; searchAggregatedTransactions: boolean; } -export const getHealthStatuses = async ( - { setup }: AggregationParams, - mlAnomaliesEnvironment?: string -) => { +export const getHealthStatuses = async ({ + environment, + setup, +}: AggregationParams) => { if (!setup.ml) { return []; } const anomalies = await getServiceAnomalies({ setup, - environment: mlAnomaliesEnvironment, + environment, }); return anomalies.serviceAnomalies.map((anomalyStats) => { diff --git a/x-pack/plugins/apm/server/lib/services/get_services/get_service_transaction_stats.ts b/x-pack/plugins/apm/server/lib/services/get_services/get_service_transaction_stats.ts index acfdc1d8c1710a..e1f8bca83829cc 100644 --- a/x-pack/plugins/apm/server/lib/services/get_services/get_service_transaction_stats.ts +++ b/x-pack/plugins/apm/server/lib/services/get_services/get_service_transaction_stats.ts @@ -15,7 +15,7 @@ import { TRANSACTION_PAGE_LOAD, TRANSACTION_REQUEST, } from '../../../../common/transaction_types'; -import { rangeFilter } from '../../../../common/utils/range_filter'; +import { environmentQuery, rangeQuery } from '../../../../common/utils/queries'; import { AgentName } from '../../../../typings/es_schemas/ui/fields/agent'; import { getDocumentTypeFilterForAggregatedTransactions, @@ -32,6 +32,7 @@ import { ServicesItemsSetup } from './get_services_items'; import { withApmSpan } from '../../../utils/with_apm_span'; interface AggregationParams { + environment?: string; setup: ServicesItemsSetup; searchAggregatedTransactions: boolean; } @@ -39,6 +40,7 @@ interface AggregationParams { const MAX_NUMBER_OF_SERVICES = 500; export async function getServiceTransactionStats({ + environment, setup, searchAggregatedTransactions, }: AggregationParams) { @@ -71,11 +73,12 @@ export async function getServiceTransactionStats({ query: { bool: { filter: [ - { range: rangeFilter(start, end) }, - ...esFilter, ...getDocumentTypeFilterForAggregatedTransactions( searchAggregatedTransactions ), + ...rangeQuery(start, end), + ...environmentQuery(environment), + ...esFilter, ], }, }, diff --git a/x-pack/plugins/apm/server/lib/services/get_services/get_services_items.ts b/x-pack/plugins/apm/server/lib/services/get_services/get_services_items.ts index 1ba9aaf980201f..c2677af038486b 100644 --- a/x-pack/plugins/apm/server/lib/services/get_services/get_services_items.ts +++ b/x-pack/plugins/apm/server/lib/services/get_services/get_services_items.ts @@ -14,19 +14,21 @@ import { getHealthStatuses } from './get_health_statuses'; import { getServiceTransactionStats } from './get_service_transaction_stats'; export type ServicesItemsSetup = Setup & SetupTimeRange; -export type ServicesItemsProjection = ReturnType; export async function getServicesItems({ + environment, setup, searchAggregatedTransactions, logger, }: { + environment?: string; setup: ServicesItemsSetup; searchAggregatedTransactions: boolean; logger: Logger; }) { return withApmSpan('get_services_items', async () => { const params = { + environment, projection: getServicesProjection({ setup, searchAggregatedTransactions, @@ -37,7 +39,7 @@ export async function getServicesItems({ const [transactionStats, healthStatuses] = await Promise.all([ getServiceTransactionStats(params), - getHealthStatuses(params, setup.uiFilters.environment).catch((err) => { + getHealthStatuses(params).catch((err) => { logger.error(err); return []; }), diff --git a/x-pack/plugins/apm/server/lib/services/get_services/index.ts b/x-pack/plugins/apm/server/lib/services/get_services/index.ts index 45efd80c45a980..1a0ddeda11651b 100644 --- a/x-pack/plugins/apm/server/lib/services/get_services/index.ts +++ b/x-pack/plugins/apm/server/lib/services/get_services/index.ts @@ -14,10 +14,12 @@ import { getServicesItems } from './get_services_items'; import { hasHistoricalAgentData } from './has_historical_agent_data'; export async function getServices({ + environment, setup, searchAggregatedTransactions, logger, }: { + environment?: string; setup: Setup & SetupTimeRange; searchAggregatedTransactions: boolean; logger: Logger; @@ -25,6 +27,7 @@ export async function getServices({ return withApmSpan('get_services', async () => { const [items, hasLegacyData] = await Promise.all([ getServicesItems({ + environment, setup, searchAggregatedTransactions, logger, diff --git a/x-pack/plugins/apm/server/lib/services/get_throughput.ts b/x-pack/plugins/apm/server/lib/services/get_throughput.ts index 33268e9b3332d7..f7cd23b0e37a7b 100644 --- a/x-pack/plugins/apm/server/lib/services/get_throughput.ts +++ b/x-pack/plugins/apm/server/lib/services/get_throughput.ts @@ -10,7 +10,7 @@ import { SERVICE_NAME, TRANSACTION_TYPE, } from '../../../common/elasticsearch_fieldnames'; -import { rangeFilter } from '../../../common/utils/range_filter'; +import { environmentQuery, rangeQuery } from '../../../common/utils/queries'; import { getDocumentTypeFilterForAggregatedTransactions, getProcessorEventForAggregatedTransactions, @@ -20,6 +20,7 @@ import { Setup } from '../helpers/setup_request'; import { withApmSpan } from '../../utils/with_apm_span'; interface Options { + environment?: string; searchAggregatedTransactions: boolean; serviceName: string; setup: Setup; @@ -29,6 +30,7 @@ interface Options { } function fetcher({ + environment, searchAggregatedTransactions, serviceName, setup, @@ -36,16 +38,17 @@ function fetcher({ start, end, }: Options) { - const { apmEventClient } = setup; + const { esFilter, apmEventClient } = setup; const { intervalString } = getBucketSize({ start, end }); const filter: ESFilter[] = [ { term: { [SERVICE_NAME]: serviceName } }, { term: { [TRANSACTION_TYPE]: transactionType } }, - { range: rangeFilter(start, end) }, ...getDocumentTypeFilterForAggregatedTransactions( searchAggregatedTransactions ), - ...setup.esFilter, + ...rangeQuery(start, end), + ...environmentQuery(environment), + ...esFilter, ]; const params = { diff --git a/x-pack/plugins/apm/server/lib/traces/get_trace_items.ts b/x-pack/plugins/apm/server/lib/traces/get_trace_items.ts index bd3ecf1e0f862d..f631657f872761 100644 --- a/x-pack/plugins/apm/server/lib/traces/get_trace_items.ts +++ b/x-pack/plugins/apm/server/lib/traces/get_trace_items.ts @@ -15,7 +15,7 @@ import { ERROR_LOG_LEVEL, } from '../../../common/elasticsearch_fieldnames'; import { APMError } from '../../../typings/es_schemas/ui/apm_error'; -import { rangeFilter } from '../../../common/utils/range_filter'; +import { rangeQuery } from '../../../common/utils/queries'; import { Setup, SetupTimeRange } from '../helpers/setup_request'; import { PromiseValueType } from '../../../typings/common'; import { withApmSpan } from '../../utils/with_apm_span'; @@ -44,7 +44,7 @@ export async function getTraceItems( bool: { filter: [ { term: { [TRACE_ID]: traceId } }, - { range: rangeFilter(start, end) }, + ...rangeQuery(start, end), ], must_not: { terms: { [ERROR_LOG_LEVEL]: excludedLogLevels } }, }, @@ -74,7 +74,7 @@ export async function getTraceItems( bool: { filter: [ { term: { [TRACE_ID]: traceId } }, - { range: rangeFilter(start, end) }, + ...rangeQuery(start, end), ], should: { exists: { field: PARENT_ID }, diff --git a/x-pack/plugins/apm/server/lib/transaction_groups/__snapshots__/queries.test.ts.snap b/x-pack/plugins/apm/server/lib/transaction_groups/__snapshots__/queries.test.ts.snap index 443159611883fc..7fb2bb2fcbeeb1 100644 --- a/x-pack/plugins/apm/server/lib/transaction_groups/__snapshots__/queries.test.ts.snap +++ b/x-pack/plugins/apm/server/lib/transaction_groups/__snapshots__/queries.test.ts.snap @@ -244,12 +244,8 @@ Array [ "bool": Object { "filter": Array [ Object { - "range": Object { - "@timestamp": Object { - "format": "epoch_millis", - "gte": 1528113600000, - "lte": 1528977600000, - }, + "term": Object { + "service.name": "foo", }, }, Object { @@ -258,8 +254,12 @@ Array [ }, }, Object { - "term": Object { - "service.name": "foo", + "range": Object { + "@timestamp": Object { + "format": "epoch_millis", + "gte": 1528113600000, + "lte": 1528977600000, + }, }, }, Object { @@ -299,12 +299,8 @@ Array [ "bool": Object { "filter": Array [ Object { - "range": Object { - "@timestamp": Object { - "format": "epoch_millis", - "gte": 1528113600000, - "lte": 1528977600000, - }, + "term": Object { + "service.name": "foo", }, }, Object { @@ -313,8 +309,12 @@ Array [ }, }, Object { - "term": Object { - "service.name": "foo", + "range": Object { + "@timestamp": Object { + "format": "epoch_millis", + "gte": 1528113600000, + "lte": 1528977600000, + }, }, }, Object { @@ -354,12 +354,8 @@ Array [ "bool": Object { "filter": Array [ Object { - "range": Object { - "@timestamp": Object { - "format": "epoch_millis", - "gte": 1528113600000, - "lte": 1528977600000, - }, + "term": Object { + "service.name": "foo", }, }, Object { @@ -368,8 +364,12 @@ Array [ }, }, Object { - "term": Object { - "service.name": "foo", + "range": Object { + "@timestamp": Object { + "format": "epoch_millis", + "gte": 1528113600000, + "lte": 1528977600000, + }, }, }, Object { @@ -415,12 +415,8 @@ Array [ "bool": Object { "filter": Array [ Object { - "range": Object { - "@timestamp": Object { - "format": "epoch_millis", - "gte": 1528113600000, - "lte": 1528977600000, - }, + "term": Object { + "service.name": "foo", }, }, Object { @@ -429,8 +425,12 @@ Array [ }, }, Object { - "term": Object { - "service.name": "foo", + "range": Object { + "@timestamp": Object { + "format": "epoch_millis", + "gte": 1528113600000, + "lte": 1528977600000, + }, }, }, Object { diff --git a/x-pack/plugins/apm/server/lib/transaction_groups/fetcher.ts b/x-pack/plugins/apm/server/lib/transaction_groups/fetcher.ts index 0fad948edde19b..09e5e358a1b7c1 100644 --- a/x-pack/plugins/apm/server/lib/transaction_groups/fetcher.ts +++ b/x-pack/plugins/apm/server/lib/transaction_groups/fetcher.ts @@ -27,6 +27,7 @@ import { } from './get_transaction_group_stats'; interface TopTransactionOptions { + environment?: string; type: 'top_transactions'; serviceName: string; transactionType: string; @@ -35,6 +36,7 @@ interface TopTransactionOptions { } interface TopTraceOptions { + environment?: string; type: 'top_traces'; transactionName?: string; searchAggregatedTransactions: boolean; diff --git a/x-pack/plugins/apm/server/lib/transaction_groups/get_error_rate.ts b/x-pack/plugins/apm/server/lib/transaction_groups/get_error_rate.ts index 839efc9009c389..d1a056002db078 100644 --- a/x-pack/plugins/apm/server/lib/transaction_groups/get_error_rate.ts +++ b/x-pack/plugins/apm/server/lib/transaction_groups/get_error_rate.ts @@ -14,7 +14,7 @@ import { TRANSACTION_TYPE, } from '../../../common/elasticsearch_fieldnames'; import { EventOutcome } from '../../../common/event_outcome'; -import { rangeFilter } from '../../../common/utils/range_filter'; +import { environmentQuery, rangeQuery } from '../../../common/utils/queries'; import { getDocumentTypeFilterForAggregatedTransactions, getProcessorEventForAggregatedTransactions, @@ -29,12 +29,14 @@ import { import { withApmSpan } from '../../utils/with_apm_span'; export async function getErrorRate({ + environment, serviceName, transactionType, transactionName, setup, searchAggregatedTransactions, }: { + environment?: string; serviceName: string; transactionType?: string; transactionName?: string; @@ -57,17 +59,18 @@ export async function getErrorRate({ const filter = [ { term: { [SERVICE_NAME]: serviceName } }, - { range: rangeFilter(start, end) }, { terms: { [EVENT_OUTCOME]: [EventOutcome.failure, EventOutcome.success], }, }, + ...transactionNamefilter, + ...transactionTypefilter, ...getDocumentTypeFilterForAggregatedTransactions( searchAggregatedTransactions ), - ...transactionNamefilter, - ...transactionTypefilter, + ...rangeQuery(start, end), + ...environmentQuery(environment), ...esFilter, ]; diff --git a/x-pack/plugins/apm/server/lib/transactions/breakdown/index.ts b/x-pack/plugins/apm/server/lib/transactions/breakdown/index.ts index 8a2579b4a2b875..c3741184c807db 100644 --- a/x-pack/plugins/apm/server/lib/transactions/breakdown/index.ts +++ b/x-pack/plugins/apm/server/lib/transactions/breakdown/index.ts @@ -18,18 +18,20 @@ import { TRANSACTION_BREAKDOWN_COUNT, } from '../../../../common/elasticsearch_fieldnames'; import { Setup, SetupTimeRange } from '../../helpers/setup_request'; -import { rangeFilter } from '../../../../common/utils/range_filter'; +import { environmentQuery, rangeQuery } from '../../../../common/utils/queries'; import { getMetricsDateHistogramParams } from '../../helpers/metrics'; import { MAX_KPIS } from './constants'; import { getVizColorForIndex } from '../../../../common/viz_colors'; import { withApmSpan } from '../../../utils/with_apm_span'; export function getTransactionBreakdown({ + environment, setup, serviceName, transactionName, transactionType, }: { + environment?: string; setup: Setup & SetupTimeRange; serviceName: string; transactionName?: string; @@ -82,7 +84,8 @@ export function getTransactionBreakdown({ const filters = [ { term: { [SERVICE_NAME]: serviceName } }, { term: { [TRANSACTION_TYPE]: transactionType } }, - { range: rangeFilter(start, end) }, + ...rangeQuery(start, end), + ...environmentQuery(environment), ...esFilter, ]; diff --git a/x-pack/plugins/apm/server/lib/transactions/distribution/get_buckets/index.ts b/x-pack/plugins/apm/server/lib/transactions/distribution/get_buckets/index.ts index d1d23f538e96b0..7ed016cd4b4c61 100644 --- a/x-pack/plugins/apm/server/lib/transactions/distribution/get_buckets/index.ts +++ b/x-pack/plugins/apm/server/lib/transactions/distribution/get_buckets/index.ts @@ -17,7 +17,10 @@ import { } from '../../../../../common/elasticsearch_fieldnames'; import { ProcessorEvent } from '../../../../../common/processor_event'; import { joinByKey } from '../../../../../common/utils/join_by_key'; -import { rangeFilter } from '../../../../../common/utils/range_filter'; +import { + environmentQuery, + rangeQuery, +} from '../../../../../common/utils/queries'; import { getDocumentTypeFilterForAggregatedTransactions, getProcessorEventForAggregatedTransactions, @@ -46,6 +49,7 @@ function getHistogramAggOptions({ } export async function getBuckets({ + environment, serviceName, transactionName, transactionType, @@ -56,6 +60,7 @@ export async function getBuckets({ setup, searchAggregatedTransactions, }: { + environment?: string; serviceName: string; transactionName: string; transactionType: string; @@ -75,7 +80,8 @@ export async function getBuckets({ { term: { [SERVICE_NAME]: serviceName } }, { term: { [TRANSACTION_TYPE]: transactionType } }, { term: { [TRANSACTION_NAME]: transactionName } }, - { range: rangeFilter(start, end) }, + ...rangeQuery(start, end), + ...environmentQuery(environment), ...esFilter, ]; diff --git a/x-pack/plugins/apm/server/lib/transactions/distribution/get_distribution_max.ts b/x-pack/plugins/apm/server/lib/transactions/distribution/get_distribution_max.ts index ed54dae32704e3..f8061ea9894698 100644 --- a/x-pack/plugins/apm/server/lib/transactions/distribution/get_distribution_max.ts +++ b/x-pack/plugins/apm/server/lib/transactions/distribution/get_distribution_max.ts @@ -15,15 +15,18 @@ import { getProcessorEventForAggregatedTransactions, getTransactionDurationFieldForAggregatedTransactions, } from '../../helpers/aggregated_transactions'; +import { environmentQuery, rangeQuery } from '../../../../common/utils/queries'; import { withApmSpan } from '../../../utils/with_apm_span'; export async function getDistributionMax({ + environment, serviceName, transactionName, transactionType, setup, searchAggregatedTransactions, }: { + environment?: string; serviceName: string; transactionName: string; transactionType: string; @@ -49,15 +52,8 @@ export async function getDistributionMax({ { term: { [SERVICE_NAME]: serviceName } }, { term: { [TRANSACTION_TYPE]: transactionType } }, { term: { [TRANSACTION_NAME]: transactionName } }, - { - range: { - '@timestamp': { - gte: start, - lte: end, - format: 'epoch_millis', - }, - }, - }, + ...rangeQuery(start, end), + ...environmentQuery(environment), ...esFilter, ], }, diff --git a/x-pack/plugins/apm/server/lib/transactions/distribution/index.ts b/x-pack/plugins/apm/server/lib/transactions/distribution/index.ts index 22436cac40183d..92d1d96b4a8e3a 100644 --- a/x-pack/plugins/apm/server/lib/transactions/distribution/index.ts +++ b/x-pack/plugins/apm/server/lib/transactions/distribution/index.ts @@ -20,6 +20,7 @@ function getBucketSize(max: number) { } export async function getTransactionDistribution({ + environment, serviceName, transactionName, transactionType, @@ -28,6 +29,7 @@ export async function getTransactionDistribution({ setup, searchAggregatedTransactions, }: { + environment?: string; serviceName: string; transactionName: string; transactionType: string; @@ -38,6 +40,7 @@ export async function getTransactionDistribution({ }) { return withApmSpan('get_transaction_latency_distribution', async () => { const distributionMax = await getDistributionMax({ + environment, serviceName, transactionName, transactionType, @@ -52,6 +55,7 @@ export async function getTransactionDistribution({ const bucketSize = getBucketSize(distributionMax); const { buckets, noHits } = await getBuckets({ + environment, serviceName, transactionName, transactionType, diff --git a/x-pack/plugins/apm/server/lib/transactions/get_anomaly_data/fetcher.ts b/x-pack/plugins/apm/server/lib/transactions/get_anomaly_data/fetcher.ts index 002ddd1ec35f04..d566f3a169e78a 100644 --- a/x-pack/plugins/apm/server/lib/transactions/get_anomaly_data/fetcher.ts +++ b/x-pack/plugins/apm/server/lib/transactions/get_anomaly_data/fetcher.ts @@ -7,6 +7,7 @@ import { ESSearchResponse } from '../../../../../../typings/elasticsearch'; import { PromiseReturnType } from '../../../../../observability/typings/common'; +import { rangeQuery } from '../../../../common/utils/queries'; import { withApmSpan } from '../../../utils/with_apm_span'; import { Setup } from '../../helpers/setup_request'; @@ -40,15 +41,7 @@ export function anomalySeriesFetcher({ { terms: { result_type: ['model_plot', 'record'] } }, { term: { partition_field_value: serviceName } }, { term: { by_field_value: transactionType } }, - { - range: { - timestamp: { - gte: start, - lte: end, - format: 'epoch_millis', - }, - }, - }, + ...rangeQuery(start, end, 'timestamp'), ], }, }, diff --git a/x-pack/plugins/apm/server/lib/transactions/get_anomaly_data/index.ts b/x-pack/plugins/apm/server/lib/transactions/get_anomaly_data/index.ts index 29dd562330cc15..a03b1ac82e90a6 100644 --- a/x-pack/plugins/apm/server/lib/transactions/get_anomaly_data/index.ts +++ b/x-pack/plugins/apm/server/lib/transactions/get_anomaly_data/index.ts @@ -18,20 +18,21 @@ import { ANOMALY_THRESHOLD } from '../../../../../ml/common'; import { withApmSpan } from '../../../utils/with_apm_span'; export async function getAnomalySeries({ + environment, serviceName, transactionType, transactionName, setup, logger, }: { + environment?: string; serviceName: string; transactionType: string; transactionName?: string; setup: Setup & SetupTimeRange; logger: Logger; }) { - const { uiFilters, start, end, ml } = setup; - const { environment } = uiFilters; + const { start, end, ml } = setup; // don't fetch anomalies if the ML plugin is not setup if (!ml) { @@ -45,18 +46,17 @@ export async function getAnomalySeries({ } // don't fetch anomalies when no specific environment is selected - if (environment === ENVIRONMENT_ALL.value) { + if (!environment || environment === ENVIRONMENT_ALL.value) { return undefined; } - // don't fetch anomalies if unknown uiFilters are applied - const knownFilters = ['environment', 'serviceName']; - const hasUnknownFiltersApplied = Object.entries(setup.uiFilters) - .filter(([key, value]) => !!value) - .map(([key]) => key) - .some((uiFilterName) => !knownFilters.includes(uiFilterName)); + // Don't fetch anomalies if uiFilters are applied. This filters out anything + // with empty values so `kuery: ''` returns false but `kuery: 'x:y'` returns true. + const hasUiFiltersApplied = + Object.entries(setup.uiFilters).filter(([_key, value]) => !!value).length > + 0; - if (hasUnknownFiltersApplied) { + if (hasUiFiltersApplied) { return undefined; } diff --git a/x-pack/plugins/apm/server/lib/transactions/get_latency_charts/index.ts b/x-pack/plugins/apm/server/lib/transactions/get_latency_charts/index.ts index ee27d00fdc0d4d..e1d3921d298c77 100644 --- a/x-pack/plugins/apm/server/lib/transactions/get_latency_charts/index.ts +++ b/x-pack/plugins/apm/server/lib/transactions/get_latency_charts/index.ts @@ -13,7 +13,7 @@ import { TRANSACTION_TYPE, } from '../../../../common/elasticsearch_fieldnames'; import { LatencyAggregationType } from '../../../../common/latency_aggregation_types'; -import { rangeFilter } from '../../../../common/utils/range_filter'; +import { environmentQuery, rangeQuery } from '../../../../common/utils/queries'; import { getDocumentTypeFilterForAggregatedTransactions, getProcessorEventForAggregatedTransactions, @@ -31,6 +31,7 @@ export type LatencyChartsSearchResponse = PromiseReturnType< >; function searchLatency({ + environment, serviceName, transactionType, transactionName, @@ -38,6 +39,7 @@ function searchLatency({ searchAggregatedTransactions, latencyAggregationType, }: { + environment?: string; serviceName: string; transactionType: string | undefined; transactionName: string | undefined; @@ -45,16 +47,17 @@ function searchLatency({ searchAggregatedTransactions: boolean; latencyAggregationType: LatencyAggregationType; }) { - const { start, end, apmEventClient } = setup; + const { esFilter, start, end, apmEventClient } = setup; const { intervalString } = getBucketSize({ start, end }); const filter: ESFilter[] = [ { term: { [SERVICE_NAME]: serviceName } }, - { range: rangeFilter(start, end) }, ...getDocumentTypeFilterForAggregatedTransactions( searchAggregatedTransactions ), - ...setup.esFilter, + ...rangeQuery(start, end), + ...environmentQuery(environment), + ...esFilter, ]; if (transactionName) { @@ -102,6 +105,7 @@ function searchLatency({ } export function getLatencyTimeseries({ + environment, serviceName, transactionType, transactionName, @@ -109,6 +113,7 @@ export function getLatencyTimeseries({ searchAggregatedTransactions, latencyAggregationType, }: { + environment?: string; serviceName: string; transactionType: string | undefined; transactionName: string | undefined; @@ -118,6 +123,7 @@ export function getLatencyTimeseries({ }) { return withApmSpan('get_latency_charts', async () => { const response = await searchLatency({ + environment, serviceName, transactionType, transactionName, diff --git a/x-pack/plugins/apm/server/lib/transactions/get_throughput_charts/index.ts b/x-pack/plugins/apm/server/lib/transactions/get_throughput_charts/index.ts index 7c1fa9c3a2368e..ec5dbf0eab3e9e 100644 --- a/x-pack/plugins/apm/server/lib/transactions/get_throughput_charts/index.ts +++ b/x-pack/plugins/apm/server/lib/transactions/get_throughput_charts/index.ts @@ -13,7 +13,7 @@ import { TRANSACTION_RESULT, TRANSACTION_TYPE, } from '../../../../common/elasticsearch_fieldnames'; -import { rangeFilter } from '../../../../common/utils/range_filter'; +import { environmentQuery, rangeQuery } from '../../../../common/utils/queries'; import { getDocumentTypeFilterForAggregatedTransactions, getProcessorEventForAggregatedTransactions, @@ -28,6 +28,7 @@ export type ThroughputChartsResponse = PromiseReturnType< >; function searchThroughput({ + environment, serviceName, transactionType, transactionName, @@ -35,6 +36,7 @@ function searchThroughput({ searchAggregatedTransactions, intervalString, }: { + environment?: string; serviceName: string; transactionType: string; transactionName: string | undefined; @@ -42,16 +44,17 @@ function searchThroughput({ searchAggregatedTransactions: boolean; intervalString: string; }) { - const { start, end, apmEventClient } = setup; + const { esFilter, start, end, apmEventClient } = setup; const filter: ESFilter[] = [ { term: { [SERVICE_NAME]: serviceName } }, - { range: rangeFilter(start, end) }, + { term: { [TRANSACTION_TYPE]: transactionType } }, ...getDocumentTypeFilterForAggregatedTransactions( searchAggregatedTransactions ), - { term: { [TRANSACTION_TYPE]: transactionType } }, - ...setup.esFilter, + ...rangeQuery(start, end), + ...environmentQuery(environment), + ...esFilter, ]; if (transactionName) { @@ -91,12 +94,14 @@ function searchThroughput({ } export async function getThroughputCharts({ + environment, serviceName, transactionType, transactionName, setup, searchAggregatedTransactions, }: { + environment?: string; serviceName: string; transactionType: string; transactionName: string | undefined; @@ -107,6 +112,7 @@ export async function getThroughputCharts({ const { bucketSize, intervalString } = getBucketSize(setup); const response = await searchThroughput({ + environment, serviceName, transactionType, transactionName, diff --git a/x-pack/plugins/apm/server/lib/transactions/get_transaction/index.ts b/x-pack/plugins/apm/server/lib/transactions/get_transaction/index.ts index 2fdb8e25fd9962..38d6b593dc72dc 100644 --- a/x-pack/plugins/apm/server/lib/transactions/get_transaction/index.ts +++ b/x-pack/plugins/apm/server/lib/transactions/get_transaction/index.ts @@ -9,7 +9,7 @@ import { TRACE_ID, TRANSACTION_ID, } from '../../../../common/elasticsearch_fieldnames'; -import { rangeFilter } from '../../../../common/utils/range_filter'; +import { rangeQuery } from '../../../../common/utils/queries'; import { Setup, SetupTimeRange } from '../../helpers/setup_request'; import { ProcessorEvent } from '../../../../common/processor_event'; import { withApmSpan } from '../../../utils/with_apm_span'; @@ -37,7 +37,7 @@ export function getTransaction({ filter: [ { term: { [TRANSACTION_ID]: transactionId } }, { term: { [TRACE_ID]: traceId } }, - { range: rangeFilter(start, end) }, + ...rangeQuery(start, end), ], }, }, diff --git a/x-pack/plugins/apm/server/projections/errors.ts b/x-pack/plugins/apm/server/projections/errors.ts index 082fd53a0ca93d..342d78608efbf6 100644 --- a/x-pack/plugins/apm/server/projections/errors.ts +++ b/x-pack/plugins/apm/server/projections/errors.ts @@ -10,13 +10,15 @@ import { SERVICE_NAME, ERROR_GROUP_ID, } from '../../common/elasticsearch_fieldnames'; -import { rangeFilter } from '../../common/utils/range_filter'; +import { environmentQuery, rangeQuery } from '../../common/utils/queries'; import { ProcessorEvent } from '../../common/processor_event'; export function getErrorGroupsProjection({ + environment, setup, serviceName, }: { + environment?: string; setup: Setup & SetupTimeRange; serviceName: string; }) { @@ -31,7 +33,8 @@ export function getErrorGroupsProjection({ bool: { filter: [ { term: { [SERVICE_NAME]: serviceName } }, - { range: rangeFilter(start, end) }, + ...rangeQuery(start, end), + ...environmentQuery(environment), ...esFilter, ], }, diff --git a/x-pack/plugins/apm/server/projections/metrics.ts b/x-pack/plugins/apm/server/projections/metrics.ts index f6c3f85ed48075..a32c2ae46c870b 100644 --- a/x-pack/plugins/apm/server/projections/metrics.ts +++ b/x-pack/plugins/apm/server/projections/metrics.ts @@ -10,7 +10,7 @@ import { SERVICE_NAME, SERVICE_NODE_NAME, } from '../../common/elasticsearch_fieldnames'; -import { rangeFilter } from '../../common/utils/range_filter'; +import { environmentQuery, rangeQuery } from '../../common/utils/queries'; import { SERVICE_NODE_NAME_MISSING } from '../../common/service_nodes'; import { ProcessorEvent } from '../../common/processor_event'; @@ -27,10 +27,12 @@ function getServiceNodeNameFilters(serviceNodeName?: string) { } export function getMetricsProjection({ + environment, setup, serviceName, serviceNodeName, }: { + environment?: string; setup: Setup & SetupTimeRange; serviceName: string; serviceNodeName?: string; @@ -39,8 +41,9 @@ export function getMetricsProjection({ const filter = [ { term: { [SERVICE_NAME]: serviceName } }, - { range: rangeFilter(start, end) }, ...getServiceNodeNameFilters(serviceNodeName), + ...rangeQuery(start, end), + ...environmentQuery(environment), ...esFilter, ]; diff --git a/x-pack/plugins/apm/server/projections/rum_page_load_transactions.ts b/x-pack/plugins/apm/server/projections/rum_page_load_transactions.ts index ff8d868bc4abe5..1d5f7316b69ad6 100644 --- a/x-pack/plugins/apm/server/projections/rum_page_load_transactions.ts +++ b/x-pack/plugins/apm/server/projections/rum_page_load_transactions.ts @@ -11,7 +11,7 @@ import { TRANSACTION_TYPE, SERVICE_LANGUAGE_NAME, } from '../../common/elasticsearch_fieldnames'; -import { rangeFilter } from '../../common/utils/range_filter'; +import { rangeQuery } from '../../common/utils/queries'; import { ProcessorEvent } from '../../common/processor_event'; import { TRANSACTION_PAGE_LOAD } from '../../common/transaction_types'; @@ -28,7 +28,7 @@ export function getRumPageLoadTransactionsProjection({ const bool = { filter: [ - { range: rangeFilter(start, end) }, + ...rangeQuery(start, end), { term: { [TRANSACTION_TYPE]: TRANSACTION_PAGE_LOAD } }, ...(checkFetchStartFieldExists ? [ @@ -79,7 +79,7 @@ export function getRumErrorsProjection({ const bool = { filter: [ - { range: rangeFilter(start, end) }, + ...rangeQuery(start, end), { term: { [AGENT_NAME]: 'rum-js' } }, { term: { diff --git a/x-pack/plugins/apm/server/projections/services.ts b/x-pack/plugins/apm/server/projections/services.ts index 33ffb45a006378..a9f5a7efd0e67e 100644 --- a/x-pack/plugins/apm/server/projections/services.ts +++ b/x-pack/plugins/apm/server/projections/services.ts @@ -7,7 +7,7 @@ import { Setup, SetupTimeRange } from '../../server/lib/helpers/setup_request'; import { SERVICE_NAME } from '../../common/elasticsearch_fieldnames'; -import { rangeFilter } from '../../common/utils/range_filter'; +import { rangeQuery } from '../../common/utils/queries'; import { ProcessorEvent } from '../../common/processor_event'; import { getProcessorEventForAggregatedTransactions } from '../lib/helpers/aggregated_transactions'; @@ -34,7 +34,7 @@ export function getServicesProjection({ size: 0, query: { bool: { - filter: [{ range: rangeFilter(start, end) }, ...esFilter], + filter: [...rangeQuery(start, end), ...esFilter], }, }, aggs: { diff --git a/x-pack/plugins/apm/server/projections/transactions.ts b/x-pack/plugins/apm/server/projections/transactions.ts index 76f2fc164e3fd2..45ed5d2865a67e 100644 --- a/x-pack/plugins/apm/server/projections/transactions.ts +++ b/x-pack/plugins/apm/server/projections/transactions.ts @@ -11,19 +11,21 @@ import { TRANSACTION_TYPE, TRANSACTION_NAME, } from '../../common/elasticsearch_fieldnames'; -import { rangeFilter } from '../../common/utils/range_filter'; +import { environmentQuery, rangeQuery } from '../../common/utils/queries'; import { getProcessorEventForAggregatedTransactions, getDocumentTypeFilterForAggregatedTransactions, } from '../lib/helpers/aggregated_transactions'; export function getTransactionsProjection({ + environment, setup, serviceName, transactionName, transactionType, searchAggregatedTransactions, }: { + environment?: string; setup: Setup & SetupTimeRange; serviceName?: string; transactionName?: string; @@ -44,14 +46,15 @@ export function getTransactionsProjection({ const bool = { filter: [ - { range: rangeFilter(start, end) }, + ...serviceNameFilter, ...transactionNameFilter, ...transactionTypeFilter, - ...serviceNameFilter, - ...esFilter, ...getDocumentTypeFilterForAggregatedTransactions( searchAggregatedTransactions ), + ...rangeQuery(start, end), + ...environmentQuery(environment), + ...esFilter, ], }; diff --git a/x-pack/plugins/apm/server/routes/correlations.ts b/x-pack/plugins/apm/server/routes/correlations.ts index 3c2ff00153ce79..d4a0db3c0d6c7b 100644 --- a/x-pack/plugins/apm/server/routes/correlations.ts +++ b/x-pack/plugins/apm/server/routes/correlations.ts @@ -13,7 +13,7 @@ import { getCorrelationsForFailedTransactions } from '../lib/correlations/get_co import { getCorrelationsForSlowTransactions } from '../lib/correlations/get_correlations_for_slow_transactions'; import { setupRequest } from '../lib/helpers/setup_request'; import { createRoute } from './create_route'; -import { rangeRt } from './default_api_types'; +import { environmentRt, rangeRt } from './default_api_types'; const INVALID_LICENSE = i18n.translate( 'xpack.apm.significanTerms.license.text', @@ -37,6 +37,7 @@ export const correlationsForSlowTransactionsRoute = createRoute({ fieldNames: t.string, }), t.partial({ uiFilters: t.string }), + environmentRt, rangeRt, ]), }), @@ -47,6 +48,7 @@ export const correlationsForSlowTransactionsRoute = createRoute({ } const setup = await setupRequest(context, request); const { + environment, serviceName, transactionType, transactionName, @@ -55,6 +57,7 @@ export const correlationsForSlowTransactionsRoute = createRoute({ } = context.params.query; return getCorrelationsForSlowTransactions({ + environment, serviceName, transactionType, transactionName, @@ -78,6 +81,7 @@ export const correlationsForFailedTransactionsRoute = createRoute({ fieldNames: t.string, }), t.partial({ uiFilters: t.string }), + environmentRt, rangeRt, ]), }), @@ -88,14 +92,15 @@ export const correlationsForFailedTransactionsRoute = createRoute({ } const setup = await setupRequest(context, request); const { + environment, serviceName, transactionType, transactionName, - fieldNames, } = context.params.query; return getCorrelationsForFailedTransactions({ + environment, serviceName, transactionType, transactionName, diff --git a/x-pack/plugins/apm/server/routes/create_apm_api.ts b/x-pack/plugins/apm/server/routes/create_apm_api.ts index fc5d6a3dd0bcdb..822a45fca269fd 100644 --- a/x-pack/plugins/apm/server/routes/create_apm_api.ts +++ b/x-pack/plugins/apm/server/routes/create_apm_api.ts @@ -63,8 +63,8 @@ import { transactionChartsErrorRateRoute, transactionGroupsRoute, transactionGroupsPrimaryStatisticsRoute, - transactionLatencyChatsRoute, - transactionThroughputChatsRoute, + transactionLatencyChartsRoute, + transactionThroughputChartsRoute, transactionGroupsComparisonStatisticsRoute, } from './transactions'; import { serviceMapRoute, serviceMapServiceNodeRoute } from './service_map'; @@ -167,8 +167,8 @@ const createApmApi = () => { .add(transactionChartsErrorRateRoute) .add(transactionGroupsRoute) .add(transactionGroupsPrimaryStatisticsRoute) - .add(transactionLatencyChatsRoute) - .add(transactionThroughputChatsRoute) + .add(transactionLatencyChartsRoute) + .add(transactionThroughputChartsRoute) .add(transactionGroupsComparisonStatisticsRoute) // Service map diff --git a/x-pack/plugins/apm/server/routes/default_api_types.ts b/x-pack/plugins/apm/server/routes/default_api_types.ts index fdc1e8ebe5a55f..990b462a520d23 100644 --- a/x-pack/plugins/apm/server/routes/default_api_types.ts +++ b/x-pack/plugins/apm/server/routes/default_api_types.ts @@ -18,4 +18,6 @@ export const comparisonRangeRt = t.partial({ comparisonEnd: isoToEpochRt, }); +export const environmentRt = t.partial({ environment: t.string }); + export const uiFiltersRt = t.type({ uiFilters: t.string }); diff --git a/x-pack/plugins/apm/server/routes/errors.ts b/x-pack/plugins/apm/server/routes/errors.ts index cc9db2e6a48551..073a91bfe15487 100644 --- a/x-pack/plugins/apm/server/routes/errors.ts +++ b/x-pack/plugins/apm/server/routes/errors.ts @@ -11,7 +11,7 @@ import { getErrorDistribution } from '../lib/errors/distribution/get_distributio import { getErrorGroupSample } from '../lib/errors/get_error_group_sample'; import { getErrorGroups } from '../lib/errors/get_error_groups'; import { setupRequest } from '../lib/helpers/setup_request'; -import { uiFiltersRt, rangeRt } from './default_api_types'; +import { environmentRt, uiFiltersRt, rangeRt } from './default_api_types'; export const errorsRoute = createRoute({ endpoint: 'GET /api/apm/services/{serviceName}/errors', @@ -24,6 +24,7 @@ export const errorsRoute = createRoute({ sortField: t.string, sortDirection: t.union([t.literal('asc'), t.literal('desc')]), }), + environmentRt, uiFiltersRt, rangeRt, ]), @@ -33,9 +34,10 @@ export const errorsRoute = createRoute({ const setup = await setupRequest(context, request); const { params } = context; const { serviceName } = params.path; - const { sortField, sortDirection } = params.query; + const { environment, sortField, sortDirection } = params.query; return getErrorGroups({ + environment, serviceName, sortField, sortDirection, @@ -51,13 +53,15 @@ export const errorGroupsRoute = createRoute({ serviceName: t.string, groupId: t.string, }), - query: t.intersection([uiFiltersRt, rangeRt]), + query: t.intersection([environmentRt, uiFiltersRt, rangeRt]), }), options: { tags: ['access:apm'] }, handler: async ({ context, request }) => { const setup = await setupRequest(context, request); const { serviceName, groupId } = context.params.path; - return getErrorGroupSample({ serviceName, groupId, setup }); + const { environment } = context.params.query; + + return getErrorGroupSample({ environment, serviceName, groupId, setup }); }, }); @@ -71,6 +75,7 @@ export const errorDistributionRoute = createRoute({ t.partial({ groupId: t.string, }), + environmentRt, uiFiltersRt, rangeRt, ]), @@ -80,7 +85,7 @@ export const errorDistributionRoute = createRoute({ const setup = await setupRequest(context, request); const { params } = context; const { serviceName } = params.path; - const { groupId } = params.query; - return getErrorDistribution({ serviceName, groupId, setup }); + const { environment, groupId } = params.query; + return getErrorDistribution({ environment, serviceName, groupId, setup }); }, }); diff --git a/x-pack/plugins/apm/server/routes/metrics.ts b/x-pack/plugins/apm/server/routes/metrics.ts index d07504a1046ee5..08376ed0e37ffb 100644 --- a/x-pack/plugins/apm/server/routes/metrics.ts +++ b/x-pack/plugins/apm/server/routes/metrics.ts @@ -9,7 +9,7 @@ import * as t from 'io-ts'; import { setupRequest } from '../lib/helpers/setup_request'; import { getMetricsChartDataByAgent } from '../lib/metrics/get_metrics_chart_data_by_agent'; import { createRoute } from './create_route'; -import { uiFiltersRt, rangeRt } from './default_api_types'; +import { environmentRt, uiFiltersRt, rangeRt } from './default_api_types'; export const metricsChartsRoute = createRoute({ endpoint: `GET /api/apm/services/{serviceName}/metrics/charts`, @@ -24,6 +24,7 @@ export const metricsChartsRoute = createRoute({ t.partial({ serviceNodeName: t.string, }), + environmentRt, uiFiltersRt, rangeRt, ]), @@ -33,8 +34,9 @@ export const metricsChartsRoute = createRoute({ const setup = await setupRequest(context, request); const { params } = context; const { serviceName } = params.path; - const { agentName, serviceNodeName } = params.query; + const { agentName, environment, serviceNodeName } = params.query; return await getMetricsChartDataByAgent({ + environment, setup, serviceName, agentName, diff --git a/x-pack/plugins/apm/server/routes/service_map.ts b/x-pack/plugins/apm/server/routes/service_map.ts index 7cca6cd0a19430..65c7b245958f32 100644 --- a/x-pack/plugins/apm/server/routes/service_map.ts +++ b/x-pack/plugins/apm/server/routes/service_map.ts @@ -12,7 +12,7 @@ import { setupRequest } from '../lib/helpers/setup_request'; import { getServiceMap } from '../lib/service_map/get_service_map'; import { getServiceMapServiceNodeInfo } from '../lib/service_map/get_service_map_service_node_info'; import { createRoute } from './create_route'; -import { rangeRt, uiFiltersRt } from './default_api_types'; +import { environmentRt, rangeRt, uiFiltersRt } from './default_api_types'; import { notifyFeatureUsage } from '../feature'; import { getSearchAggregatedTransactions } from '../lib/helpers/aggregated_transactions'; import { isActivePlatinumLicense } from '../../common/license_check'; @@ -22,9 +22,9 @@ export const serviceMapRoute = createRoute({ params: t.type({ query: t.intersection([ t.partial({ - environment: t.string, serviceName: t.string, }), + environmentRt, rangeRt, ]), }), diff --git a/x-pack/plugins/apm/server/routes/services.ts b/x-pack/plugins/apm/server/routes/services.ts index 84ccb4b06c2e6a..e59b438305b349 100644 --- a/x-pack/plugins/apm/server/routes/services.ts +++ b/x-pack/plugins/apm/server/routes/services.ts @@ -25,23 +25,29 @@ import { getServiceTransactionTypes } from '../lib/services/get_service_transact import { getThroughput } from '../lib/services/get_throughput'; import { offsetPreviousPeriodCoordinates } from '../utils/offset_previous_period_coordinate'; import { createRoute } from './create_route'; -import { comparisonRangeRt, rangeRt, uiFiltersRt } from './default_api_types'; +import { + comparisonRangeRt, + environmentRt, + rangeRt, + uiFiltersRt, +} from './default_api_types'; import { withApmSpan } from '../utils/with_apm_span'; export const servicesRoute = createRoute({ endpoint: 'GET /api/apm/services', params: t.type({ - query: t.intersection([uiFiltersRt, rangeRt]), + query: t.intersection([environmentRt, uiFiltersRt, rangeRt]), }), options: { tags: ['access:apm'] }, handler: async ({ context, request }) => { const setup = await setupRequest(context, request); - + const { environment } = context.params.query; const searchAggregatedTransactions = await getSearchAggregatedTransactions( setup ); const services = await getServices({ + environment, setup, searchAggregatedTransactions, logger: context.logger, @@ -273,6 +279,7 @@ export const serviceErrorGroupsRoute = createRoute({ serviceName: t.string, }), query: t.intersection([ + environmentRt, rangeRt, uiFiltersRt, t.type({ @@ -296,6 +303,7 @@ export const serviceErrorGroupsRoute = createRoute({ const { path: { serviceName }, query: { + environment, numBuckets, pageIndex, size, @@ -306,6 +314,7 @@ export const serviceErrorGroupsRoute = createRoute({ } = context.params; return getServiceErrorGroups({ + environment, serviceName, setup, size, @@ -326,6 +335,7 @@ export const serviceThroughputRoute = createRoute({ }), query: t.intersection([ t.type({ transactionType: t.string }), + environmentRt, uiFiltersRt, rangeRt, comparisonRangeRt, @@ -336,6 +346,7 @@ export const serviceThroughputRoute = createRoute({ const setup = await setupRequest(context, request); const { serviceName } = context.params.path; const { + environment, transactionType, comparisonStart, comparisonEnd, @@ -356,12 +367,14 @@ export const serviceThroughputRoute = createRoute({ const [currentPeriod, previousPeriod] = await Promise.all([ getThroughput({ ...commonProps, + environment, start, end, }), comparisonStart && comparisonEnd ? getThroughput({ ...commonProps, + environment, start: comparisonStart, end: comparisonEnd, }).then((coordinates) => @@ -389,6 +402,7 @@ export const serviceInstancesRoute = createRoute({ }), query: t.intersection([ t.type({ transactionType: t.string, numBuckets: toNumberRt }), + environmentRt, uiFiltersRt, rangeRt, ]), @@ -397,13 +411,14 @@ export const serviceInstancesRoute = createRoute({ handler: async ({ context, request }) => { const setup = await setupRequest(context, request); const { serviceName } = context.params.path; - const { transactionType, numBuckets } = context.params.query; + const { environment, transactionType, numBuckets } = context.params.query; const searchAggregatedTransactions = await getSearchAggregatedTransactions( setup ); return getServiceInstances({ + environment, serviceName, setup, transactionType, @@ -421,9 +436,9 @@ export const serviceDependenciesRoute = createRoute({ }), query: t.intersection([ t.type({ - environment: t.string, numBuckets: toNumberRt, }), + environmentRt, rangeRt, ]), }), diff --git a/x-pack/plugins/apm/server/routes/traces.ts b/x-pack/plugins/apm/server/routes/traces.ts index 722675906487ce..5d3f99be7af344 100644 --- a/x-pack/plugins/apm/server/routes/traces.ts +++ b/x-pack/plugins/apm/server/routes/traces.ts @@ -10,23 +10,25 @@ import { setupRequest } from '../lib/helpers/setup_request'; import { getTrace } from '../lib/traces/get_trace'; import { getTransactionGroupList } from '../lib/transaction_groups'; import { createRoute } from './create_route'; -import { rangeRt, uiFiltersRt } from './default_api_types'; +import { environmentRt, rangeRt, uiFiltersRt } from './default_api_types'; import { getSearchAggregatedTransactions } from '../lib/helpers/aggregated_transactions'; import { getRootTransactionByTraceId } from '../lib/transactions/get_transaction_by_trace'; export const tracesRoute = createRoute({ endpoint: 'GET /api/apm/traces', params: t.type({ - query: t.intersection([rangeRt, uiFiltersRt]), + query: t.intersection([environmentRt, rangeRt, uiFiltersRt]), }), options: { tags: ['access:apm'] }, handler: async ({ context, request }) => { const setup = await setupRequest(context, request); + const { environment } = context.params.query; const searchAggregatedTransactions = await getSearchAggregatedTransactions( setup ); + return getTransactionGroupList( - { type: 'top_traces', searchAggregatedTransactions }, + { environment, type: 'top_traces', searchAggregatedTransactions }, setup ); }, diff --git a/x-pack/plugins/apm/server/routes/transactions.ts b/x-pack/plugins/apm/server/routes/transactions.ts index bef96cb7f0767e..5a4be216a817c2 100644 --- a/x-pack/plugins/apm/server/routes/transactions.ts +++ b/x-pack/plugins/apm/server/routes/transactions.ts @@ -5,7 +5,6 @@ * 2.0. */ -import Boom from '@hapi/boom'; import * as t from 'io-ts'; import { LatencyAggregationType, @@ -25,7 +24,7 @@ import { getThroughputCharts } from '../lib/transactions/get_throughput_charts'; import { getTransactionGroupList } from '../lib/transaction_groups'; import { getErrorRate } from '../lib/transaction_groups/get_error_rate'; import { createRoute } from './create_route'; -import { rangeRt, uiFiltersRt } from './default_api_types'; +import { environmentRt, rangeRt, uiFiltersRt } from './default_api_types'; /** * Returns a list of transactions grouped by name @@ -39,6 +38,7 @@ export const transactionGroupsRoute = createRoute({ }), query: t.intersection([ t.type({ transactionType: t.string }), + environmentRt, uiFiltersRt, rangeRt, ]), @@ -47,7 +47,7 @@ export const transactionGroupsRoute = createRoute({ handler: async ({ context, request }) => { const setup = await setupRequest(context, request); const { serviceName } = context.params.path; - const { transactionType } = context.params.query; + const { environment, transactionType } = context.params.query; const searchAggregatedTransactions = await getSearchAggregatedTransactions( setup @@ -55,6 +55,7 @@ export const transactionGroupsRoute = createRoute({ return getTransactionGroupList( { + environment, type: 'top_transactions', serviceName, transactionType, @@ -71,6 +72,7 @@ export const transactionGroupsPrimaryStatisticsRoute = createRoute({ params: t.type({ path: t.type({ serviceName: t.string }), query: t.intersection([ + environmentRt, rangeRt, uiFiltersRt, t.type({ @@ -91,10 +93,11 @@ export const transactionGroupsPrimaryStatisticsRoute = createRoute({ const { path: { serviceName }, - query: { latencyAggregationType, transactionType }, + query: { environment, latencyAggregationType, transactionType }, } = context.params; return getServiceTransactionGroups({ + environment, setup, serviceName, searchAggregatedTransactions, @@ -110,6 +113,7 @@ export const transactionGroupsComparisonStatisticsRoute = createRoute({ params: t.type({ path: t.type({ serviceName: t.string }), query: t.intersection([ + environmentRt, rangeRt, uiFiltersRt, t.type({ @@ -133,6 +137,7 @@ export const transactionGroupsComparisonStatisticsRoute = createRoute({ const { path: { serviceName }, query: { + environment, transactionNames, latencyAggregationType, numBuckets, @@ -141,6 +146,7 @@ export const transactionGroupsComparisonStatisticsRoute = createRoute({ } = context.params; return getServiceTransactionGroupComparisonStatistics({ + environment, setup, serviceName, transactionNames, @@ -152,7 +158,7 @@ export const transactionGroupsComparisonStatisticsRoute = createRoute({ }, }); -export const transactionLatencyChatsRoute = createRoute({ +export const transactionLatencyChartsRoute = createRoute({ endpoint: 'GET /api/apm/services/{serviceName}/transactions/charts/latency', params: t.type({ path: t.type({ @@ -166,6 +172,7 @@ export const transactionLatencyChatsRoute = createRoute({ transactionType: t.string, latencyAggregationType: latencyAggregationTypeRt, }), + environmentRt, uiFiltersRt, rangeRt, ]), @@ -176,22 +183,18 @@ export const transactionLatencyChatsRoute = createRoute({ const logger = context.logger; const { serviceName } = context.params.path; const { + environment, transactionType, transactionName, latencyAggregationType, } = context.params.query; - if (!setup.uiFilters.environment) { - throw Boom.badRequest( - `environment is a required property of the ?uiFilters JSON for transaction_groups/charts.` - ); - } - const searchAggregatedTransactions = await getSearchAggregatedTransactions( setup ); const options = { + environment, serviceName, transactionType, transactionName, @@ -222,7 +225,7 @@ export const transactionLatencyChatsRoute = createRoute({ }, }); -export const transactionThroughputChatsRoute = createRoute({ +export const transactionThroughputChartsRoute = createRoute({ endpoint: 'GET /api/apm/services/{serviceName}/transactions/charts/throughput', params: t.type({ @@ -234,25 +237,25 @@ export const transactionThroughputChatsRoute = createRoute({ t.partial({ transactionName: t.string }), uiFiltersRt, rangeRt, + environmentRt, ]), }), options: { tags: ['access:apm'] }, handler: async ({ context, request }) => { const setup = await setupRequest(context, request); const { serviceName } = context.params.path; - const { transactionType, transactionName } = context.params.query; - - if (!setup.uiFilters.environment) { - throw Boom.badRequest( - `environment is a required property of the ?uiFilters JSON for transaction_groups/charts.` - ); - } + const { + environment, + transactionType, + transactionName, + } = context.params.query; const searchAggregatedTransactions = await getSearchAggregatedTransactions( setup ); return await getThroughputCharts({ + environment, serviceName, transactionType, transactionName, @@ -278,6 +281,7 @@ export const transactionChartsDistributionRoute = createRoute({ transactionId: t.string, traceId: t.string, }), + environmentRt, uiFiltersRt, rangeRt, ]), @@ -287,6 +291,7 @@ export const transactionChartsDistributionRoute = createRoute({ const setup = await setupRequest(context, request); const { serviceName } = context.params.path; const { + environment, transactionType, transactionName, transactionId = '', @@ -298,6 +303,7 @@ export const transactionChartsDistributionRoute = createRoute({ ); return getTransactionDistribution({ + environment, serviceName, transactionType, transactionName, @@ -318,6 +324,7 @@ export const transactionChartsBreakdownRoute = createRoute({ query: t.intersection([ t.type({ transactionType: t.string }), t.partial({ transactionName: t.string }), + environmentRt, uiFiltersRt, rangeRt, ]), @@ -326,9 +333,14 @@ export const transactionChartsBreakdownRoute = createRoute({ handler: async ({ context, request }) => { const setup = await setupRequest(context, request); const { serviceName } = context.params.path; - const { transactionName, transactionType } = context.params.query; + const { + environment, + transactionName, + transactionType, + } = context.params.query; return getTransactionBreakdown({ + environment, serviceName, transactionName, transactionType, @@ -345,6 +357,7 @@ export const transactionChartsErrorRateRoute = createRoute({ serviceName: t.string, }), query: t.intersection([ + environmentRt, uiFiltersRt, rangeRt, t.type({ transactionType: t.string }), @@ -356,13 +369,14 @@ export const transactionChartsErrorRateRoute = createRoute({ const setup = await setupRequest(context, request); const { params } = context; const { serviceName } = params.path; - const { transactionType, transactionName } = params.query; + const { environment, transactionType, transactionName } = params.query; const searchAggregatedTransactions = await getSearchAggregatedTransactions( setup ); return getErrorRate({ + environment, serviceName, transactionType, transactionName, diff --git a/x-pack/plugins/apm/server/utils/test_helpers.tsx b/x-pack/plugins/apm/server/utils/test_helpers.tsx index 19ac562121d9dc..4df638cc2c5df2 100644 --- a/x-pack/plugins/apm/server/utils/test_helpers.tsx +++ b/x-pack/plugins/apm/server/utils/test_helpers.tsx @@ -88,7 +88,7 @@ export async function inspectSearchParams( }, } ) as APMConfig, - uiFilters: { environment: 'test' }, + uiFilters: {}, esFilter: [{ term: { 'service.environment': 'test' } }], indices: { /* eslint-disable @typescript-eslint/naming-convention */ diff --git a/x-pack/test/apm_api_integration/tests/csm/has_rum_data.ts b/x-pack/test/apm_api_integration/tests/csm/has_rum_data.ts index 1d00d54a3997bf..4474d0996175bb 100644 --- a/x-pack/test/apm_api_integration/tests/csm/has_rum_data.ts +++ b/x-pack/test/apm_api_integration/tests/csm/has_rum_data.ts @@ -31,7 +31,7 @@ export default function rumHasDataApiTests({ getService }: FtrProviderContext) { 'has RUM data with data', { config: 'trial', archives: ['8.0.0', 'rum_8.0.0'] }, () => { - it('returns that it has data and service name with most traffice', async () => { + it('returns that it has data and service name with most traffic', async () => { const response = await supertest.get( '/api/apm/observability_overview/has_rum_data?start=2020-09-07T20%3A35%3A54.654Z&end=2020-09-16T20%3A35%3A54.654Z&uiFilters=' ); diff --git a/x-pack/test/apm_api_integration/tests/feature_controls.ts b/x-pack/test/apm_api_integration/tests/feature_controls.ts index db2b42323c4f64..45114dd506716d 100644 --- a/x-pack/test/apm_api_integration/tests/feature_controls.ts +++ b/x-pack/test/apm_api_integration/tests/feature_controls.ts @@ -109,28 +109,28 @@ export default function featureControlsTests({ getService }: FtrProviderContext) }, { req: { - url: `/api/apm/services/foo/transactions/charts/latency?start=${start}&end=${end}&transactionType=bar&latencyAggregationType=avg&uiFilters=%7B%22environment%22%3A%22testing%22%7D`, + url: `/api/apm/services/foo/transactions/charts/latency?environment=testing&start=${start}&end=${end}&transactionType=bar&latencyAggregationType=avg&uiFilters=%7B%7D`, }, expectForbidden: expect403, expectResponse: expect200, }, { req: { - url: `/api/apm/services/foo/transactions/charts/latency?start=${start}&end=${end}&transactionType=bar&latencyAggregationType=avg&transactionName=baz&uiFilters=%7B%22environment%22%3A%22testing%22%7D`, + url: `/api/apm/services/foo/transactions/charts/latency?environment=testing&start=${start}&end=${end}&transactionType=bar&latencyAggregationType=avg&transactionName=baz&uiFilters=%7B%7D`, }, expectForbidden: expect403, expectResponse: expect200, }, { req: { - url: `/api/apm/services/foo/transactions/charts/throughput?start=${start}&end=${end}&transactionType=bar&uiFilters=%7B%22environment%22%3A%22testing%22%7D`, + url: `/api/apm/services/foo/transactions/charts/throughput?environment=testing&start=${start}&end=${end}&transactionType=bar&uiFilters=%7B%7D`, }, expectForbidden: expect403, expectResponse: expect200, }, { req: { - url: `/api/apm/services/foo/transactions/charts/throughput?start=${start}&end=${end}&transactionType=bar&transactionName=baz&uiFilters=%7B%22environment%22%3A%22testing%22%7D`, + url: `/api/apm/services/foo/transactions/charts/throughput?environment=testing&start=${start}&end=${end}&transactionType=bar&transactionName=baz&uiFilters=%7B%7D`, }, expectForbidden: expect403, expectResponse: expect200, diff --git a/x-pack/test/apm_api_integration/tests/services/top_services.ts b/x-pack/test/apm_api_integration/tests/services/top_services.ts index efd0b410cf8aaa..3afaec653fcb35 100644 --- a/x-pack/test/apm_api_integration/tests/services/top_services.ts +++ b/x-pack/test/apm_api_integration/tests/services/top_services.ts @@ -346,8 +346,8 @@ export default function ApiTest({ getService }: FtrProviderContext) { let response: PromiseReturnType; before(async () => { response = await supertest.get( - `/api/apm/services?start=${start}&end=${end}&uiFilters=${encodeURIComponent( - `{"kuery":"service.name:opbeans-java","environment":"ENVIRONMENT_ALL"}` + `/api/apm/services?environment=ENVIRONMENT_ALL&start=${start}&end=${end}&uiFilters=${encodeURIComponent( + `{"kuery":"service.name:opbeans-java"}` )}` ); }); diff --git a/x-pack/test/apm_api_integration/tests/transactions/__snapshots__/latency.snap b/x-pack/test/apm_api_integration/tests/transactions/__snapshots__/latency.snap index a384ca2c9364e8..11c557fd02e381 100644 --- a/x-pack/test/apm_api_integration/tests/transactions/__snapshots__/latency.snap +++ b/x-pack/test/apm_api_integration/tests/transactions/__snapshots__/latency.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`APM API tests trial apm_8.0.0 Transaction latency with a trial license when data is loaded when not defined environments seleted should return the correct anomaly boundaries 1`] = ` +exports[`APM API tests trial apm_8.0.0 Transaction latency with a trial license when data is loaded when not defined environment is selected should return the correct anomaly boundaries 1`] = ` Array [ Object { "x": 1607436000000, @@ -30,7 +30,7 @@ Array [ ] `; -exports[`APM API tests trial apm_8.0.0 Transaction latency with a trial license when data is loaded with environment selected in uiFilters should return a non-empty anomaly series 1`] = ` +exports[`APM API tests trial apm_8.0.0 Transaction latency with a trial license when data is loaded with environment selected should return a non-empty anomaly series 1`] = ` Array [ Object { "x": 1607436000000, diff --git a/x-pack/test/apm_api_integration/tests/transactions/latency.ts b/x-pack/test/apm_api_integration/tests/transactions/latency.ts index 3003c6f902f39e..523139717b309e 100644 --- a/x-pack/test/apm_api_integration/tests/transactions/latency.ts +++ b/x-pack/test/apm_api_integration/tests/transactions/latency.ts @@ -26,10 +26,10 @@ export default function ApiTest({ getService }: FtrProviderContext) { 'Latency with a basic license when data is not loaded ', { config: 'basic', archives: [] }, () => { - const uiFilters = encodeURIComponent(JSON.stringify({ environment: 'testing' })); + const uiFilters = encodeURIComponent(JSON.stringify({})); it('returns 400 when latencyAggregationType is not informed', async () => { const response = await supertest.get( - `/api/apm/services/opbeans-node/transactions/charts/latency?start=${start}&end=${end}&uiFilters=${uiFilters}&transactionType=request` + `/api/apm/services/opbeans-node/transactions/charts/latency?environment=testing&start=${start}&end=${end}&uiFilters=${uiFilters}&transactionType=request` ); expect(response.status).to.be(400); @@ -37,7 +37,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('returns 400 when transactionType is not informed', async () => { const response = await supertest.get( - `/api/apm/services/opbeans-node/transactions/charts/latency?start=${start}&end=${end}&uiFilters=${uiFilters}&latencyAggregationType=avg` + `/api/apm/services/opbeans-node/transactions/charts/latency?environment=testing&start=${start}&end=${end}&uiFilters=${uiFilters}&latencyAggregationType=avg` ); expect(response.status).to.be(400); @@ -45,7 +45,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('handles the empty state', async () => { const response = await supertest.get( - `/api/apm/services/opbeans-node/transactions/charts/latency?start=${start}&end=${end}&uiFilters=${uiFilters}&latencyAggregationType=avg&transactionType=request` + `/api/apm/services/opbeans-node/transactions/charts/latency?environment=testing&start=${start}&end=${end}&uiFilters=${uiFilters}&latencyAggregationType=avg&transactionType=request` ); expect(response.status).to.be(200); @@ -62,12 +62,12 @@ export default function ApiTest({ getService }: FtrProviderContext) { () => { let response: PromiseReturnType; - const uiFilters = encodeURIComponent(JSON.stringify({ environment: 'testing' })); + const uiFilters = encodeURIComponent(JSON.stringify({})); describe('average latency type', () => { before(async () => { response = await supertest.get( - `/api/apm/services/opbeans-node/transactions/charts/latency?start=${start}&end=${end}&uiFilters=${uiFilters}&transactionType=request&latencyAggregationType=avg` + `/api/apm/services/opbeans-node/transactions/charts/latency?environment=testing&start=${start}&end=${end}&uiFilters=${uiFilters}&transactionType=request&latencyAggregationType=avg` ); }); @@ -81,7 +81,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { describe('95th percentile latency type', () => { before(async () => { response = await supertest.get( - `/api/apm/services/opbeans-node/transactions/charts/latency?start=${start}&end=${end}&uiFilters=${uiFilters}&transactionType=request&latencyAggregationType=p95` + `/api/apm/services/opbeans-node/transactions/charts/latency?environment=testing&start=${start}&end=${end}&uiFilters=${uiFilters}&transactionType=request&latencyAggregationType=p95` ); }); @@ -95,7 +95,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { describe('99th percentile latency type', () => { before(async () => { response = await supertest.get( - `/api/apm/services/opbeans-node/transactions/charts/latency?start=${start}&end=${end}&uiFilters=${uiFilters}&transactionType=request&latencyAggregationType=p99` + `/api/apm/services/opbeans-node/transactions/charts/latency?environment=testing&start=${start}&end=${end}&uiFilters=${uiFilters}&transactionType=request&latencyAggregationType=p99` ); }); @@ -116,15 +116,16 @@ export default function ApiTest({ getService }: FtrProviderContext) { const transactionType = 'request'; - describe('without environment', () => { + describe('without an environment', () => { const uiFilters = encodeURIComponent(JSON.stringify({})); before(async () => { response = await supertest.get( `/api/apm/services/opbeans-java/transactions/charts/latency?start=${start}&end=${end}&transactionType=${transactionType}&uiFilters=${uiFilters}&latencyAggregationType=avg` ); }); - it('should return an error response', () => { - expect(response.status).to.eql(400); + + it('returns an ok response', () => { + expect(response.status).to.eql(200); }); }); @@ -139,11 +140,11 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); }); - describe('with environment selected in uiFilters', () => { - const uiFilters = encodeURIComponent(JSON.stringify({ environment: 'production' })); + describe('with environment selected', () => { + const uiFilters = encodeURIComponent(JSON.stringify({})); before(async () => { response = await supertest.get( - `/api/apm/services/opbeans-java/transactions/charts/latency?start=${start}&end=${end}&transactionType=${transactionType}&uiFilters=${uiFilters}&latencyAggregationType=avg` + `/api/apm/services/opbeans-java/transactions/charts/latency?environment=production&start=${start}&end=${end}&transactionType=${transactionType}&uiFilters=${uiFilters}&latencyAggregationType=avg` ); }); @@ -166,13 +167,11 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); }); - describe('when not defined environments seleted', () => { - const uiFilters = encodeURIComponent( - JSON.stringify({ environment: 'ENVIRONMENT_NOT_DEFINED' }) - ); + describe('when not defined environment is selected', () => { + const uiFilters = encodeURIComponent(JSON.stringify({})); before(async () => { response = await supertest.get( - `/api/apm/services/opbeans-python/transactions/charts/latency?start=${start}&end=${end}&transactionType=${transactionType}&uiFilters=${uiFilters}&latencyAggregationType=avg` + `/api/apm/services/opbeans-python/transactions/charts/latency?environment=ENVIRONMENT_NOT_DEFINED&start=${start}&end=${end}&transactionType=${transactionType}&uiFilters=${uiFilters}&latencyAggregationType=avg` ); }); @@ -195,10 +194,10 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); describe('with all environments selected', () => { - const uiFilters = encodeURIComponent(JSON.stringify({ environment: 'ENVIRONMENT_ALL' })); + const uiFilters = encodeURIComponent(JSON.stringify({})); before(async () => { response = await supertest.get( - `/api/apm/services/opbeans-java/transactions/charts/latency?start=${start}&end=${end}&transactionType=${transactionType}&uiFilters=${uiFilters}&latencyAggregationType=avg` + `/api/apm/services/opbeans-java/transactions/charts/latency?environment=ENVIRONMENT_ALL&start=${start}&end=${end}&transactionType=${transactionType}&uiFilters=${uiFilters}&latencyAggregationType=avg` ); }); @@ -212,12 +211,10 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); describe('with environment selected and empty kuery filter', () => { - const uiFilters = encodeURIComponent( - JSON.stringify({ kuery: '', environment: 'production' }) - ); + const uiFilters = encodeURIComponent(JSON.stringify({ kuery: '' })); before(async () => { response = await supertest.get( - `/api/apm/services/opbeans-java/transactions/charts/latency?start=${start}&end=${end}&transactionType=${transactionType}&uiFilters=${uiFilters}&latencyAggregationType=avg` + `/api/apm/services/opbeans-java/transactions/charts/latency?environment=production&start=${start}&end=${end}&transactionType=${transactionType}&uiFilters=${uiFilters}&latencyAggregationType=avg` ); }); diff --git a/x-pack/test/apm_api_integration/tests/transactions/throughput.ts b/x-pack/test/apm_api_integration/tests/transactions/throughput.ts index 040e280e3157f2..430392a32bfb82 100644 --- a/x-pack/test/apm_api_integration/tests/transactions/throughput.ts +++ b/x-pack/test/apm_api_integration/tests/transactions/throughput.ts @@ -20,7 +20,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { // url parameters const { start, end } = metadata; - const uiFilters = JSON.stringify({ environment: 'testing' }); + const uiFilters = JSON.stringify({}); registry.when('Throughput when data is not loaded', { config: 'basic', archives: [] }, () => { it('handles the empty state', async () => { @@ -28,6 +28,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { url.format({ pathname: `/api/apm/services/opbeans-node/transactions/charts/throughput`, query: { + environment: 'testing', start, end, uiFilters, @@ -53,6 +54,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { url.format({ pathname: `/api/apm/services/opbeans-node/transactions/charts/throughput`, query: { + environment: 'testing', start, end, uiFilters, From 481c92296e9114ac0b3297016c3f7df902ccd862 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Wed, 17 Feb 2021 12:53:33 -0800 Subject: [PATCH 07/17] [Alerts][Docs] Cleanup alerts README.md to remove duplication from docs (#91074) * Cleanup alerts README.md to remove duplication from docs * fixed due to comments * fixed due to comments Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- x-pack/plugins/alerts/README.md | 290 +++++--------------------------- 1 file changed, 46 insertions(+), 244 deletions(-) diff --git a/x-pack/plugins/alerts/README.md b/x-pack/plugins/alerts/README.md index 2191b23eec11ee..aab848d4555d2d 100644 --- a/x-pack/plugins/alerts/README.md +++ b/x-pack/plugins/alerts/README.md @@ -20,26 +20,13 @@ Table of Contents - [Example](#example) - [Role Based Access-Control](#role-based-access-control) - [Alert Navigation](#alert-navigation) - - [RESTful API](#restful-api) - - [`POST /api/alerts/alert`: Create alert](#post-apialert-create-alert) - - [`DELETE /api/alerts/alert/{id}`: Delete alert](#delete-apialertid-delete-alert) - - [`GET /api/alerts/_find`: Find alerts](#get-apialertfind-find-alerts) - - [`GET /api/alerts/alert/{id}`: Get alert](#get-apialertid-get-alert) + - [Experimental RESTful API](#restful-api) - [`GET /api/alerts/alert/{id}/state`: Get alert state](#get-apialertidstate-get-alert-state) - [`GET /api/alerts/alert/{id}/_instance_summary`: Get alert instance summary](#get-apialertidstate-get-alert-instance-summary) - - [`GET /api/alerts/list_alert_types`: List alert types](#get-apialerttypes-list-alert-types) - - [`PUT /api/alerts/alert/{id}`: Update alert](#put-apialertid-update-alert) - - [`POST /api/alerts/alert/{id}/_enable`: Enable an alert](#post-apialertidenable-enable-an-alert) - - [`POST /api/alerts/alert/{id}/_disable`: Disable an alert](#post-apialertiddisable-disable-an-alert) - - [`POST /api/alerts/alert/{id}/_mute_all`: Mute all alert instances](#post-apialertidmuteall-mute-all-alert-instances) - - [`POST /api/alerts/alert/{alert_id}/alert_instance/{alert_instance_id}/_mute`: Mute alert instance](#post-apialertalertidalertinstancealertinstanceidmute-mute-alert-instance) - - [`POST /api/alerts/alert/{id}/_unmute_all`: Unmute all alert instances](#post-apialertidunmuteall-unmute-all-alert-instances) - - [`POST /api/alerts/alert/{alertId}/alert_instance/{alertInstanceId}/_unmute`: Unmute an alert instance](#post-apialertalertidalertinstancealertinstanceidunmute-unmute-an-alert-instance) - [`POST /api/alerts/alert/{id}/_update_api_key`: Update alert API key](#post-apialertidupdateapikey-update-alert-api-key) - - [Schedule Formats](#schedule-formats) - [Alert instance factory](#alert-instance-factory) - [Templating actions](#templating-actions) - - [Examples](#examples) + - [Examples](#examples) ## Terminology @@ -61,7 +48,7 @@ A Kibana alert detects a condition and executes one or more actions when that co 1. Develop and register an alert type (see alert types -> example). 2. Configure feature level privileges using RBAC -3. Create an alert using the RESTful API (see alerts -> create). +3. Create an alert using the RESTful API [Documentation](https://www.elastic.co/guide/en/kibana/master/alerts-api-update.html) (see alerts -> create). ## Limitations @@ -96,6 +83,7 @@ The following table describes the properties of the `options` object. |validate.params|When developing an alert type, you can choose to accept a series of parameters. You may also have the parameters validated before they are passed to the `executor` function or created as an alert saved object. In order to do this, provide a `@kbn/config-schema` schema that we will use to validate the `params` attribute.|@kbn/config-schema| |executor|This is where the code of the alert type lives. This is a function to be called when executing an alert on an interval basis. For full details, see executor section below.|Function| |producer|The id of the application producing this alert type.|string| +|minimumLicenseRequired|The value of a minimum license. Most of the alerts are licensed as "basic".|string| ### Executor @@ -142,13 +130,13 @@ This example receives server and threshold as parameters. It will read the CPU u ```typescript import { schema } from '@kbn/config-schema'; +import { AlertType, AlertExecutorOptions } from '../../../alerts/server'; import { - Alert, - AlertTypeParams, - AlertTypeState, - AlertInstanceState, - AlertInstanceContext -} from 'x-pack/plugins/alerts/common'; + AlertTypeParams, + AlertTypeState, + AlertInstanceState, + AlertInstanceContext, +} from '../../../alerts/common'; ... interface MyAlertTypeParams extends AlertTypeParams { server: string; @@ -156,7 +144,7 @@ interface MyAlertTypeParams extends AlertTypeParams { } interface MyAlertTypeState extends AlertTypeState { - lastChecked: number; + lastChecked: Date; } interface MyAlertTypeInstanceState extends AlertInstanceState { @@ -257,83 +245,6 @@ const myAlertType: AlertType< server.newPlatform.setup.plugins.alerts.registerType(myAlertType); ``` -This example only receives threshold as a parameter. It will read the CPU usage of all the servers and schedule individual actions if the reading for a server is greater than the threshold. This is a better implementation than above as only one query is performed for all the servers instead of one query per server. - -```typescript -server.newPlatform.setup.plugins.alerts.registerType({ - id: 'my-alert-type', - name: 'My alert type', - validate: { - params: schema.object({ - threshold: schema.number({ min: 0, max: 1 }), - }), - }, - actionGroups: [ - { - id: 'default', - name: 'Default', - }, - ], - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - actionVariables: { - context: [ - { name: 'server', description: 'the server' }, - { name: 'hasCpuUsageIncreased', description: 'boolean indicating if the cpu usage has increased' }, - ], - state: [ - { name: 'cpuUsage', description: 'CPU usage' }, - ], - }, - async executor({ - alertId, - startedAt, - previousStartedAt, - services, - params, - state, - }: AlertExecutorOptions) { - const { threshold } = params; // Let's assume params is { threshold: 0.8 } - - // Call a function to get the CPU readings on all the servers. The result will be - // an array of { server, cpuUsage }. - const cpuUsageByServer = await getCpuUsageByServer(); - - for (const { server, cpuUsage: currentCpuUsage } of cpuUsageByServer) { - // Only execute if CPU usage is greater than threshold - if (currentCpuUsage > threshold) { - // The first argument is a unique identifier the alert instance is about. In this scenario - // the provided server will be used. Also, this id will be used to make `getState()` return - // previous state, if any, on matching identifiers. - const alertInstance = services.alertInstanceFactory(server); - - // State from last execution. This will exist if an alert instance was created and executed - // in the previous execution - const { cpuUsage: previousCpuUsage } = alertInstance.getState(); - - // Replace state entirely with new values - alertInstance.replaceState({ - cpuUsage: currentCpuUsage, - }); - - // 'default' refers to the id of a group of actions to be scheduled for execution, see 'actions' in create alert section - alertInstance.scheduleActions('default', { - server, - hasCpuUsageIncreased: currentCpuUsage > previousCpuUsage, - }); - } - } - - // Single object containing state that isn't specific to a server, this will become available - // within the `state` function parameter at the next execution - return { - lastChecked: new Date(), - }; - }, - producer: 'alerting', -}); -``` - ## Role Based Access-Control Once you have registered your AlertType, you need to grant your users privileges to use it. When registering a feature in Kibana you can specify multiple types of privileges which are granted to users when they're assigned certain roles. @@ -387,29 +298,37 @@ It's important to note that any role can be granted a mix of `all` and `read` pr ```typescript features.registerKibanaFeature({ - id: 'my-application-id', - name: 'My Application', - app: [], - privileges: { - all: { - alerting: { - all: [ - 'my-application-id.my-alert-type', - 'my-application-id.my-restricted-alert-type' - ], - }, - }, - read: { - alerting: { - all: [ - 'my-application-id.my-alert-type' - ] - read: [ - 'my-application-id.my-restricted-alert-type' - ], - }, - }, - }, + id: 'my-application-id', + name: 'My Application', + app: [], + privileges: { + all: { + app: ['my-application-id', 'kibana'], + savedObject: { + all: [], + read: [], + }, + ui: [], + api: [], + }, + read: { + app: ['lens', 'kibana'], + alerting: { + all: [ + 'my-application-id.my-alert-type' + ], + read: [ + 'my-application-id.my-restricted-alert-type' + ], + }, + savedObject: { + all: [], + read: [], + }, + ui: [], + api: [], + }, + }, }); ``` @@ -494,46 +413,10 @@ The only case in which this handler will not be used to evaluate the navigation You can use the `registerNavigation` api to specify as many AlertType specific handlers as you like, but you can only use it once per AlertType as we wouldn't know which handler to use if you specified two for the same AlertType. For the same reason, you can only use `registerDefaultNavigation` once per plugin, as it covers all cases for your specific plugin. -## RESTful API - -Using an alert type requires you to create an alert that will contain parameters and actions for a given alert type. See below for CRUD operations using the API. +## Experimental RESTful API -### `POST /api/alerts/alert`: Create alert - -Payload: - -|Property|Description|Type| -|---|---|---| -|enabled|Indicate if you want the alert to start executing on an interval basis after it has been created.|boolean| -|name|A name to reference and search in the future.|string| -|tags|A list of keywords to reference and search in the future.|string[]| -|alertTypeId|The id value of the alert type you want to call when the alert is scheduled to execute.|string| -|schedule|The schedule specifying when this alert should be run, using one of the available schedule formats specified under _Schedule Formats_ below|object| -|throttle|A Duration specifying how often this alert should fire the same actions. This will prevent the alert from sending out the same notification over and over. For example, if an alert with a `schedule` of 1 minute stays in a triggered state for 90 minutes, setting a `throttle` of `10m` or `1h` will prevent it from sending 90 notifications over this period.|string| -|params|The parameters to pass in to the alert type executor `params` value. This will also validate against the alert type params validator if defined.|object| -|actions|Array of the following:
- `group` (string): We support grouping actions in the scenario of escalations or different types of alert instances. If you don't need this, feel free to use `default` as a value.
- `id` (string): The id of the action saved object to execute.
- `params` (object): The map to the `params` the action type will receive. In order to help apply context to strings, we handle them as mustache templates and pass in a default set of context. (see templating actions).|array| - -### `DELETE /api/alerts/alert/{id}`: Delete alert - -Params: - -|Property|Description|Type| -|---|---|---| -|id|The id of the alert you're trying to delete.|string| - -### `GET /api/alerts/_find`: Find alerts - -Params: - -See the saved objects API documentation for find. All the properties are the same except you cannot pass in `type`. - -### `GET /api/alerts/alert/{id}`: Get alert - -Params: - -|Property|Description|Type| -|---|---|---| -|id|The id of the alert you're trying to get.|string| +Using of the alert type requires you to create an alert that will contain parameters and actions for a given alert type. API description for CRUD operations is a part of the [user documentation](https://www.elastic.co/guide/en/kibana/master/alerts-api-update.html). +API listed below is experimental and could be changed or removed in the future. ### `GET /api/alerts/alert/{id}/state`: Get alert state @@ -560,93 +443,12 @@ Query: |---|---|---| |dateStart|The date to start looking for alert events in the event log. Either an ISO date string, or a duration string indicating time since now.|string| -### `GET /api/alerts/list_alert_types`: List alert types - -No parameters. - -### `PUT /api/alerts/alert/{id}`: Update alert - -Params: - -|Property|Description|Type| -|---|---|---| -|id|The id of the alert you're trying to update.|string| - -Payload: - -|Property|Description|Type| -|---|---|---| -|schedule|The schedule specifying when this alert should be run, using one of the available schedule formats specified under _Schedule Formats_ below|object| -|throttle|A Duration specifying how often this alert should fire the same actions. This will prevent the alert from sending out the same notification over and over. For example, if an alert with a `schedule` of 1 minute stays in a triggered state for 90 minutes, setting a `throttle` of `10m` or `1h` will prevent it from sending 90 notifications over this period.|string| -|name|A name to reference and search in the future.|string| -|tags|A list of keywords to reference and search in the future.|string[]| -|params|The parameters to pass in to the alert type executor `params` value. This will also validate against the alert type params validator if defined.|object| -|actions|Array of the following:
- `group` (string): We support grouping actions in the scenario of escalations or different types of alert instances. If you don't need this, feel free to use `default` as a value.
- `id` (string): The id of the action saved object to execute.
- `params` (object): There map to the `params` the action type will receive. In order to help apply context to strings, we handle them as mustache templates and pass in a default set of context. (see templating actions).|array| - -### `POST /api/alerts/alert/{id}/_enable`: Enable an alert - -Params: - -|Property|Description|Type| -|---|---|---| -|id|The id of the alert you're trying to enable.|string| - -### `POST /api/alerts/alert/{id}/_disable`: Disable an alert - -Params: - -|Property|Description|Type| -|---|---|---| -|id|The id of the alert you're trying to disable.|string| - -### `POST /api/alerts/alert/{id}/_mute_all`: Mute all alert instances - -Params: - -|Property|Description|Type| -|---|---|---| -|id|The id of the alert you're trying to mute all alert instances for.|string| - -### `POST /api/alerts/alert/{alert_id}/alert_instance/{alert_instance_id}/_mute`: Mute alert instance - -Params: - -|Property|Description|Type| -|---|---|---| -|alertId|The id of the alert you're trying to mute an instance for.|string| -|alertInstanceId|The instance id of the alert instance you're trying to mute.|string| - -### `POST /api/alerts/alert/{id}/_unmute_all`: Unmute all alert instances - -Params: - -|Property|Description|Type| -|---|---|---| -|id|The id of the alert you're trying to unmute all alert instances for.|string| - -### `POST /api/alerts/alert/{alertId}/alert_instance/{alertInstanceId}/_unmute`: Unmute an alert instance - -Params: - -|Property|Description|Type| -|---|---|---| -|alertId|The id of the alert you're trying to unmute an instance for.|string| -|alertInstanceId|The instance id of the alert instance you're trying to unmute.|string| - ### `POST /api/alerts/alert/{id}/_update_api_key`: Update alert API key |Property|Description|Type| |---|---|---| |id|The id of the alert you're trying to update the API key for. System will use user in request context to generate an API key for.|string| -## Schedule Formats -A schedule is structured such that the key specifies the format you wish to use and its value specifies the schedule. - -We currently support the _Interval format_ which specifies the interval in seconds, minutes, hours or days at which the alert should execute. -Example: `{ interval: "10s" }`, `{ interval: "5m" }`, `{ interval: "1h" }`, `{ interval: "1d" }`. - -There are plans to support multiple other schedule formats in the near future. - ## Alert instance factory **alertInstanceFactory(id)** @@ -694,7 +496,7 @@ When an alert instance executes, the first argument is the `group` of actions to The templating engine is [mustache]. General definition for the [mustache variable] is a double-brace {{}}. All variables are HTML-escaped by default and if there is a requirement to render unescaped HTML, it should be applied the triple mustache: `{{{name}}}`. Also, can be used `&` to unescape a variable. -## Examples +### Examples The following code would be within an alert type. As you can see `cpuUsage ` will replace the state of the alert instance and `server` is the context for the alert instance to execute. The difference between the two is `cpuUsage ` will be accessible at the next execution. From 5eeae3dff4041686129edb3e186059901e3633e7 Mon Sep 17 00:00:00 2001 From: Kevin Qualters <56408403+kqualters-elastic@users.noreply.github.com> Date: Wed, 17 Feb 2021 15:57:34 -0500 Subject: [PATCH 08/17] Update entity route schema, use more indices on detections page (#91718) --- .../common/endpoint/schema/resolver.ts | 2 +- .../components/graph_overlay/index.tsx | 17 +++++++---------- .../components/timeline/body/helpers.tsx | 2 +- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/x-pack/plugins/security_solution/common/endpoint/schema/resolver.ts b/x-pack/plugins/security_solution/common/endpoint/schema/resolver.ts index b38cabf33a3db0..3bfe2a7410c080 100644 --- a/x-pack/plugins/security_solution/common/endpoint/schema/resolver.ts +++ b/x-pack/plugins/security_solution/common/endpoint/schema/resolver.ts @@ -76,6 +76,6 @@ export const validateEntities = { /** * Indices to search in. */ - indices: schema.arrayOf(schema.string()), + indices: schema.oneOf([schema.arrayOf(schema.string()), schema.string()]), }), }; diff --git a/x-pack/plugins/security_solution/public/timelines/components/graph_overlay/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/graph_overlay/index.tsx index 9c9c56461609d9..a8cfea1de8e74c 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/graph_overlay/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/graph_overlay/index.tsx @@ -30,8 +30,7 @@ import { TimelineId } from '../../../../common/types/timeline'; import { timelineSelectors } from '../../store/timeline'; import { timelineDefaults } from '../../store/timeline/defaults'; import { isFullScreen } from '../timeline/body/column_headers'; -import { useSourcererScope } from '../../../common/containers/sourcerer'; -import { SourcererScopeName } from '../../../common/store/sourcerer/model'; +import { sourcererSelectors } from '../../../common/store'; import { updateTimelineGraphEventId } from '../../../timelines/store/timeline/actions'; import { Resolver } from '../../../resolver/view'; import { @@ -169,14 +168,12 @@ const GraphOverlayComponent: React.FC = ({ isEventViewer, timelineId } globalFullScreen, ]); - let sourcereScope = SourcererScopeName.default; - if ([TimelineId.detectionsRulesDetailsPage, TimelineId.detectionsPage].includes(timelineId)) { - sourcereScope = SourcererScopeName.detections; - } else if (timelineId === TimelineId.active) { - sourcereScope = SourcererScopeName.timeline; - } + const existingIndexNamesSelector = useMemo( + () => sourcererSelectors.getAllExistingIndexNamesSelector(), + [] + ); + const existingIndexNames = useDeepEqualSelector(existingIndexNamesSelector); - const { selectedPatterns } = useSourcererScope(sourcereScope); return ( = ({ isEventViewer, timelineId } diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/helpers.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/helpers.tsx index 32a01654bf9aff..dd701aa284997e 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/helpers.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/helpers.tsx @@ -151,7 +151,7 @@ const InvestigateInResolverActionComponent: React.FC !isInvestigateInResolverActionEnabled(ecsData), [ecsData]); const handleClick = useCallback(() => { dispatch(updateTimelineGraphEventId({ id: timelineId, graphEventId: ecsData._id })); - if (TimelineId.active) { + if (timelineId === TimelineId.active) { dispatch(setActiveTabTimeline({ id: timelineId, activeTab: TimelineTabs.graph })); } }, [dispatch, ecsData._id, timelineId]); From 3e5497484d8c3a034e834a56128c93829b764ad9 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Wed, 17 Feb 2021 14:02:20 -0700 Subject: [PATCH 09/17] [Maps] use stored map buffer to generate queries for search sessions (#91148) * [Maps] use stored map buffer to generate queries for search sessions * getDataFilters unit test * tslint * update setQuery unit tests * only set searchSessionMapBuffer when search session isRestore * tslint Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../maps/public/actions/map_actions.test.js | 3 + .../maps/public/actions/map_actions.ts | 5 ++ .../maps/public/embeddable/map_embeddable.tsx | 50 ++++++---------- .../plugins/maps/public/embeddable/types.ts | 3 +- x-pack/plugins/maps/public/reducers/map.d.ts | 1 + x-pack/plugins/maps/public/reducers/map.js | 3 +- .../public/selectors/map_selectors.test.ts | 60 ++++++++++++++++++- .../maps/public/selectors/map_selectors.ts | 9 ++- 8 files changed, 96 insertions(+), 38 deletions(-) diff --git a/x-pack/plugins/maps/public/actions/map_actions.test.js b/x-pack/plugins/maps/public/actions/map_actions.test.js index c0ad934c232e22..fafafa6b6a0711 100644 --- a/x-pack/plugins/maps/public/actions/map_actions.test.js +++ b/x-pack/plugins/maps/public/actions/map_actions.test.js @@ -277,6 +277,9 @@ describe('map_actions', () => { require('../selectors/map_selectors').getSearchSessionId = () => { return searchSessionId; }; + require('../selectors/map_selectors').getSearchSessionMapBuffer = () => { + return undefined; + }; require('../selectors/map_selectors').getMapSettings = () => { return { autoFitToDataBounds: false, diff --git a/x-pack/plugins/maps/public/actions/map_actions.ts b/x-pack/plugins/maps/public/actions/map_actions.ts index 33c79c793974b4..9682306852ba92 100644 --- a/x-pack/plugins/maps/public/actions/map_actions.ts +++ b/x-pack/plugins/maps/public/actions/map_actions.ts @@ -22,6 +22,7 @@ import { getTimeFilters, getLayerList, getSearchSessionId, + getSearchSessionMapBuffer, } from '../selectors/map_selectors'; import { CLEAR_GOTO, @@ -229,12 +230,14 @@ export function setQuery({ filters = [], forceRefresh = false, searchSessionId, + searchSessionMapBuffer, }: { filters?: Filter[]; query?: Query; timeFilters?: TimeRange; forceRefresh?: boolean; searchSessionId?: string; + searchSessionMapBuffer?: MapExtent; }) { return async ( dispatch: ThunkDispatch, @@ -255,6 +258,7 @@ export function setQuery({ }, filters: filters ? filters : getFilters(getState()), searchSessionId, + searchSessionMapBuffer, }; const prevQueryContext = { @@ -262,6 +266,7 @@ export function setQuery({ query: getQuery(getState()), filters: getFilters(getState()), searchSessionId: getSearchSessionId(getState()), + searchSessionMapBuffer: getSearchSessionMapBuffer(getState()), }; if (_.isEqual(nextQueryContext, prevQueryContext)) { diff --git a/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx b/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx index f42a055b24d0a2..b7e50815fd1f71 100644 --- a/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx +++ b/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx @@ -44,6 +44,7 @@ import { } from '../reducers/non_serializable_instances'; import { getMapCenter, + getMapBuffer, getMapZoom, getHiddenLayerIds, getQueryableUniqueIndexPatternIds, @@ -151,11 +152,7 @@ export class MapEmbeddable store.dispatch(disableScrollZoom()); this._dispatchSetQuery({ - query: this.input.query, - timeRange: this.input.timeRange, - filters: this.input.filters, forceRefresh: false, - searchSessionId: this.input.searchSessionId, }); if (this.input.refreshConfig) { this._dispatchSetRefreshConfig(this.input.refreshConfig); @@ -230,11 +227,7 @@ export class MapEmbeddable this.input.searchSessionId !== this._prevSearchSessionId ) { this._dispatchSetQuery({ - query: this.input.query, - timeRange: this.input.timeRange, - filters: this.input.filters, forceRefresh: false, - searchSessionId: this.input.searchSessionId, }); } @@ -258,30 +251,24 @@ export class MapEmbeddable } } - _dispatchSetQuery({ - query, - timeRange, - filters = [], - forceRefresh, - searchSessionId, - }: { - query?: Query; - timeRange?: TimeRange; - filters?: Filter[]; - forceRefresh: boolean; - searchSessionId?: string; - }) { - this._prevTimeRange = timeRange; - this._prevQuery = query; - this._prevFilters = filters; - this._prevSearchSessionId = searchSessionId; + _dispatchSetQuery({ forceRefresh }: { forceRefresh: boolean }) { + this._prevTimeRange = this.input.timeRange; + this._prevQuery = this.input.query; + this._prevFilters = this.input.filters; + this._prevSearchSessionId = this.input.searchSessionId; + const enabledFilters = this.input.filters + ? this.input.filters.filter((filter) => !filter.meta.disabled) + : []; this._savedMap.getStore().dispatch( setQuery({ - filters: filters.filter((filter) => !filter.meta.disabled), - query, - timeFilters: timeRange, + filters: enabledFilters, + query: this.input.query, + timeFilters: this.input.timeRange, forceRefresh, - searchSessionId, + searchSessionId: this.input.searchSessionId, + searchSessionMapBuffer: getIsRestore(this.input.searchSessionId) + ? this.input.mapBuffer + : undefined, }) ); } @@ -432,11 +419,7 @@ export class MapEmbeddable reload() { this._dispatchSetQuery({ - query: this.input.query, - timeRange: this.input.timeRange, - filters: this.input.filters, forceRefresh: true, - searchSessionId: this.input.searchSessionId, }); } @@ -457,6 +440,7 @@ export class MapEmbeddable lon: center.lon, zoom, }, + mapBuffer: getMapBuffer(this._savedMap.getStore().getState()), }); } diff --git a/x-pack/plugins/maps/public/embeddable/types.ts b/x-pack/plugins/maps/public/embeddable/types.ts index 67489802bc31d1..7cd4fa8e1253bd 100644 --- a/x-pack/plugins/maps/public/embeddable/types.ts +++ b/x-pack/plugins/maps/public/embeddable/types.ts @@ -12,7 +12,7 @@ import { SavedObjectEmbeddableInput, } from '../../../../../src/plugins/embeddable/public'; import { RefreshInterval, Query, Filter, TimeRange } from '../../../../../src/plugins/data/common'; -import { MapCenterAndZoom } from '../../common/descriptor_types'; +import { MapCenterAndZoom, MapExtent } from '../../common/descriptor_types'; import { MapSavedObjectAttributes } from '../../common/map_saved_object_type'; import { MapSettings } from '../reducers/map'; @@ -25,6 +25,7 @@ interface MapEmbeddableState { isLayerTOCOpen?: boolean; openTOCDetails?: string[]; mapCenter?: MapCenterAndZoom; + mapBuffer?: MapExtent; mapSettings?: Partial; hiddenLayers?: string[]; hideFilterActions?: boolean; diff --git a/x-pack/plugins/maps/public/reducers/map.d.ts b/x-pack/plugins/maps/public/reducers/map.d.ts index 6a51d4feeb9dfe..1cf37561609640 100644 --- a/x-pack/plugins/maps/public/reducers/map.d.ts +++ b/x-pack/plugins/maps/public/reducers/map.d.ts @@ -37,6 +37,7 @@ export type MapContext = { refreshTimerLastTriggeredAt?: string; drawState?: DrawState; searchSessionId?: string; + searchSessionMapBuffer?: MapExtent; }; export type MapSettings = { diff --git a/x-pack/plugins/maps/public/reducers/map.js b/x-pack/plugins/maps/public/reducers/map.js index fa7e1308bac4f4..9bf0df612bac40 100644 --- a/x-pack/plugins/maps/public/reducers/map.js +++ b/x-pack/plugins/maps/public/reducers/map.js @@ -241,7 +241,7 @@ export function map(state = DEFAULT_MAP_STATE, action) { }; return { ...state, mapState: { ...state.mapState, ...newMapState } }; case SET_QUERY: - const { query, timeFilters, filters, searchSessionId } = action; + const { query, timeFilters, filters, searchSessionId, searchSessionMapBuffer } = action; return { ...state, mapState: { @@ -250,6 +250,7 @@ export function map(state = DEFAULT_MAP_STATE, action) { timeFilters, filters, searchSessionId, + searchSessionMapBuffer, }, }; case SET_REFRESH_CONFIG: diff --git a/x-pack/plugins/maps/public/selectors/map_selectors.test.ts b/x-pack/plugins/maps/public/selectors/map_selectors.test.ts index 89cd80f4daab50..fff33ae246b319 100644 --- a/x-pack/plugins/maps/public/selectors/map_selectors.test.ts +++ b/x-pack/plugins/maps/public/selectors/map_selectors.test.ts @@ -26,9 +26,67 @@ jest.mock('../kibana_services', () => ({ })); import { DEFAULT_MAP_STORE_STATE } from '../reducers/store'; -import { areLayersLoaded, getTimeFilters } from './map_selectors'; +import { areLayersLoaded, getDataFilters, getTimeFilters } from './map_selectors'; import { LayerDescriptor } from '../../common/descriptor_types'; import { ILayer } from '../classes/layers/layer'; +import { Filter } from '../../../../../src/plugins/data/public'; + +describe('getDataFilters', () => { + const mapExtent = { + maxLat: 1, + maxLon: 1, + minLat: 0, + minLon: 0, + }; + const mapBuffer = { + maxLat: 1.5, + maxLon: 1.5, + minLat: -0.5, + minLon: -0.5, + }; + const mapZoom = 4; + const timeFilters = { to: '2001-01-01', from: '2001-12-31' }; + const refreshTimerLastTriggeredAt = '2001-01-01T00:00:00'; + const query = undefined; + const filters: Filter[] = []; + const searchSessionId = '12345'; + const searchSessionMapBuffer = { + maxLat: 1.25, + maxLon: 1.25, + minLat: -0.25, + minLon: -0.25, + }; + + test('should set buffer as searchSessionMapBuffer when using searchSessionId', () => { + const dataFilters = getDataFilters.resultFunc( + mapExtent, + mapBuffer, + mapZoom, + timeFilters, + refreshTimerLastTriggeredAt, + query, + filters, + searchSessionId, + searchSessionMapBuffer + ); + expect(dataFilters.buffer).toEqual(searchSessionMapBuffer); + }); + + test('should fall back to screen buffer when using searchSessionId and searchSessionMapBuffer is not provided', () => { + const dataFilters = getDataFilters.resultFunc( + mapExtent, + mapBuffer, + mapZoom, + timeFilters, + refreshTimerLastTriggeredAt, + query, + filters, + searchSessionId, + undefined + ); + expect(dataFilters.buffer).toEqual(mapBuffer); + }); +}); describe('getTimeFilters', () => { test('should return timeFilters when contained in state', () => { diff --git a/x-pack/plugins/maps/public/selectors/map_selectors.ts b/x-pack/plugins/maps/public/selectors/map_selectors.ts index b16ac704c3715b..ffaff3263cf484 100644 --- a/x-pack/plugins/maps/public/selectors/map_selectors.ts +++ b/x-pack/plugins/maps/public/selectors/map_selectors.ts @@ -183,6 +183,9 @@ export const getFilters = ({ map }: MapStoreState): Filter[] => map.mapState.fil export const getSearchSessionId = ({ map }: MapStoreState): string | undefined => map.mapState.searchSessionId; +export const getSearchSessionMapBuffer = ({ map }: MapStoreState): MapExtent | undefined => + map.mapState.searchSessionMapBuffer; + export const isUsingSearch = (state: MapStoreState): boolean => { const filters = getFilters(state).filter((filter) => !filter.meta.disabled); const queryString = _.get(getQuery(state), 'query', ''); @@ -235,6 +238,7 @@ export const getDataFilters = createSelector( getQuery, getFilters, getSearchSessionId, + getSearchSessionMapBuffer, ( mapExtent, mapBuffer, @@ -243,11 +247,12 @@ export const getDataFilters = createSelector( refreshTimerLastTriggeredAt, query, filters, - searchSessionId + searchSessionId, + searchSessionMapBuffer ) => { return { extent: mapExtent, - buffer: mapBuffer, + buffer: searchSessionId && searchSessionMapBuffer ? searchSessionMapBuffer : mapBuffer, zoom: mapZoom, timeFilters, refreshTimerLastTriggeredAt, From 5bbbcb358f77754f6ee0dfc2db3b9c5ccd978364 Mon Sep 17 00:00:00 2001 From: Diana Derevyankina <54894989+DziyanaDzeraviankina@users.noreply.github.com> Date: Thu, 18 Feb 2021 00:04:38 +0300 Subject: [PATCH 10/17] Replace EuiCodeBlock with Monaco editor in Discover (#90781) * Update version of react-monaco-editor and monaco-editor libraries * Fix yarn lock file * Fix CI * Fix unit tests * Fix CI * Fix comment * move monaco instance in window.MonacoEnvironment * Replace EuiCodeBlock with Monaco editor in Discover expanded document * Replace EuiCodeBlock with EuiErrorBoundary * Revert changes done by mistake * Remove unused translations * Fix doc_viewer test and snapshots * Add comment and rename the function related to editor height calculation * Remove "value" from JSON tree and fix resizing * Update json_code_editor.test.tsx.snap * Fix JsonCodeEditor props * Fix json_code_editor test * Delete JsonCodeBlock and remove inline style in JsonCodeEditor * Rename jsonCodeEditor CSS class name to dscJsonCodeEditor Co-authored-by: Uladzislau Lasitsa Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../components/doc_viewer/doc_viewer.test.tsx | 5 ++ .../doc_viewer/doc_viewer_render_error.tsx | 20 ++--- .../components/doc_viewer/doc_viewer_tab.tsx | 6 +- .../json_code_block.test.tsx.snap | 20 ----- .../json_code_block/json_code_block.tsx | 23 ----- .../json_code_editor.test.tsx.snap | 71 ++++++++++++++++ .../json_code_editor/json_code_editor.scss | 3 + .../json_code_editor.test.tsx} | 18 ++-- .../json_code_editor/json_code_editor.tsx | 84 +++++++++++++++++++ src/plugins/discover/public/plugin.ts | 4 +- .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - 12 files changed, 187 insertions(+), 69 deletions(-) delete mode 100644 src/plugins/discover/public/application/components/json_code_block/__snapshots__/json_code_block.test.tsx.snap delete mode 100644 src/plugins/discover/public/application/components/json_code_block/json_code_block.tsx create mode 100644 src/plugins/discover/public/application/components/json_code_editor/__snapshots__/json_code_editor.test.tsx.snap create mode 100644 src/plugins/discover/public/application/components/json_code_editor/json_code_editor.scss rename src/plugins/discover/public/application/components/{json_code_block/json_code_block.test.tsx => json_code_editor/json_code_editor.test.tsx} (53%) create mode 100644 src/plugins/discover/public/application/components/json_code_editor/json_code_editor.tsx diff --git a/src/plugins/discover/public/application/components/doc_viewer/doc_viewer.test.tsx b/src/plugins/discover/public/application/components/doc_viewer/doc_viewer.test.tsx index 62e19b83b016e4..6afa7f89371f98 100644 --- a/src/plugins/discover/public/application/components/doc_viewer/doc_viewer.test.tsx +++ b/src/plugins/discover/public/application/components/doc_viewer/doc_viewer.test.tsx @@ -16,6 +16,11 @@ import { DocViewRenderProps } from '../../doc_views/doc_views_types'; jest.mock('../../../kibana_services', () => { let registry: any[] = []; return { + getServices: () => ({ + uiSettings: { + get: jest.fn(), + }, + }), getDocViewsRegistry: () => ({ addDocView(view: any) { registry.push(view); diff --git a/src/plugins/discover/public/application/components/doc_viewer/doc_viewer_render_error.tsx b/src/plugins/discover/public/application/components/doc_viewer/doc_viewer_render_error.tsx index 571af94f293728..b9b068ce4bd073 100644 --- a/src/plugins/discover/public/application/components/doc_viewer/doc_viewer_render_error.tsx +++ b/src/plugins/discover/public/application/components/doc_viewer/doc_viewer_render_error.tsx @@ -7,20 +7,18 @@ */ import React from 'react'; -import { EuiCallOut, EuiCodeBlock } from '@elastic/eui'; -import { formatMsg, formatStack } from '../../../../../kibana_legacy/public'; +import { EuiErrorBoundary } from '@elastic/eui'; interface Props { error: Error | string; } -export function DocViewerError({ error }: Props) { - const errMsg = formatMsg(error); - const errStack = typeof error === 'object' ? formatStack(error) : ''; +const DocViewerErrorWrapper = ({ error }: Props) => { + throw error; +}; - return ( - - {errStack && {errStack}} - - ); -} +export const DocViewerError = ({ error }: Props) => ( + + + +); diff --git a/src/plugins/discover/public/application/components/doc_viewer/doc_viewer_tab.tsx b/src/plugins/discover/public/application/components/doc_viewer/doc_viewer_tab.tsx index 1da75b45239105..25454a3bad38ab 100644 --- a/src/plugins/discover/public/application/components/doc_viewer/doc_viewer_tab.tsx +++ b/src/plugins/discover/public/application/components/doc_viewer/doc_viewer_tab.tsx @@ -11,6 +11,8 @@ import { I18nProvider } from '@kbn/i18n/react'; import { DocViewRenderTab } from './doc_viewer_render_tab'; import { DocViewerError } from './doc_viewer_render_error'; import { DocViewRenderFn, DocViewRenderProps } from '../../doc_views/doc_views_types'; +import { getServices } from '../../../kibana_services'; +import { KibanaContextProvider } from '../../../../../kibana_react/public'; interface Props { component?: React.ComponentType; @@ -72,7 +74,9 @@ export class DocViewerTab extends React.Component { const Component = component as any; return ( - + + + ); } diff --git a/src/plugins/discover/public/application/components/json_code_block/__snapshots__/json_code_block.test.tsx.snap b/src/plugins/discover/public/application/components/json_code_block/__snapshots__/json_code_block.test.tsx.snap deleted file mode 100644 index d6f48a9b3c7745..00000000000000 --- a/src/plugins/discover/public/application/components/json_code_block/__snapshots__/json_code_block.test.tsx.snap +++ /dev/null @@ -1,20 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`returns the \`JsonCodeEditor\` component 1`] = ` - - { - "_index": "test", - "_type": "doc", - "_id": "foo", - "_score": 1, - "_source": { - "test": 123 - } -} - -`; diff --git a/src/plugins/discover/public/application/components/json_code_block/json_code_block.tsx b/src/plugins/discover/public/application/components/json_code_block/json_code_block.tsx deleted file mode 100644 index 7dab2b199b018f..00000000000000 --- a/src/plugins/discover/public/application/components/json_code_block/json_code_block.tsx +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import React from 'react'; -import { EuiCodeBlock } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { DocViewRenderProps } from '../../doc_views/doc_views_types'; - -export function JsonCodeBlock({ hit }: DocViewRenderProps) { - const label = i18n.translate('discover.docViews.json.codeEditorAriaLabel', { - defaultMessage: 'Read only JSON view of an elasticsearch document', - }); - return ( - - {JSON.stringify(hit, null, 2)} - - ); -} diff --git a/src/plugins/discover/public/application/components/json_code_editor/__snapshots__/json_code_editor.test.tsx.snap b/src/plugins/discover/public/application/components/json_code_editor/__snapshots__/json_code_editor.test.tsx.snap new file mode 100644 index 00000000000000..4f27158eee04f1 --- /dev/null +++ b/src/plugins/discover/public/application/components/json_code_editor/__snapshots__/json_code_editor.test.tsx.snap @@ -0,0 +1,71 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`returns the \`JsonCodeEditor\` component 1`] = ` + + + +
+ + + +
+
+ + + +
+`; diff --git a/src/plugins/discover/public/application/components/json_code_editor/json_code_editor.scss b/src/plugins/discover/public/application/components/json_code_editor/json_code_editor.scss new file mode 100644 index 00000000000000..5521df5b363acd --- /dev/null +++ b/src/plugins/discover/public/application/components/json_code_editor/json_code_editor.scss @@ -0,0 +1,3 @@ +.dscJsonCodeEditor { + width: 100% +} diff --git a/src/plugins/discover/public/application/components/json_code_block/json_code_block.test.tsx b/src/plugins/discover/public/application/components/json_code_editor/json_code_editor.test.tsx similarity index 53% rename from src/plugins/discover/public/application/components/json_code_block/json_code_block.test.tsx rename to src/plugins/discover/public/application/components/json_code_editor/json_code_editor.test.tsx index dd56a1077f1ac6..4ccb3010d5a2b9 100644 --- a/src/plugins/discover/public/application/components/json_code_block/json_code_block.test.tsx +++ b/src/plugins/discover/public/application/components/json_code_editor/json_code_editor.test.tsx @@ -8,17 +8,15 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { JsonCodeBlock } from './json_code_block'; -import { IndexPattern } from '../../../../../data/public'; +import { JsonCodeEditor } from './json_code_editor'; it('returns the `JsonCodeEditor` component', () => { - const props = { - hit: { _index: 'test', _type: 'doc', _id: 'foo', _score: 1, _source: { test: 123 } }, - columns: [], - indexPattern: {} as IndexPattern, - filter: jest.fn(), - onAddColumn: jest.fn(), - onRemoveColumn: jest.fn(), + const value = { + _index: 'test', + _type: 'doc', + _id: 'foo', + _score: 1, + _source: { test: 123 }, }; - expect(shallow()).toMatchSnapshot(); + expect(shallow()).toMatchSnapshot(); }); diff --git a/src/plugins/discover/public/application/components/json_code_editor/json_code_editor.tsx b/src/plugins/discover/public/application/components/json_code_editor/json_code_editor.tsx new file mode 100644 index 00000000000000..85d6aad7552502 --- /dev/null +++ b/src/plugins/discover/public/application/components/json_code_editor/json_code_editor.tsx @@ -0,0 +1,84 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import './json_code_editor.scss'; + +import React, { useCallback } from 'react'; +import { i18n } from '@kbn/i18n'; +import { monaco, XJsonLang } from '@kbn/monaco'; +import { EuiButtonEmpty, EuiCopy, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; +import { CodeEditor } from '../../../../../kibana_react/public'; +import { DocViewRenderProps } from '../../../application/doc_views/doc_views_types'; + +const codeEditorAriaLabel = i18n.translate('discover.json.codeEditorAriaLabel', { + defaultMessage: 'Read only JSON view of an elasticsearch document', +}); +const copyToClipboardLabel = i18n.translate('discover.json.copyToClipboardLabel', { + defaultMessage: 'Copy to clipboard', +}); + +export const JsonCodeEditor = ({ hit }: DocViewRenderProps) => { + const jsonValue = JSON.stringify(hit, null, 2); + + // setting editor height based on lines height and count to stretch and fit its content + const setEditorCalculatedHeight = useCallback((editor) => { + const editorElement = editor.getDomNode(); + + if (!editorElement) { + return; + } + + const lineHeight = editor.getOption(monaco.editor.EditorOption.lineHeight); + const lineCount = editor.getModel()?.getLineCount() || 1; + const height = editor.getTopForLineNumber(lineCount + 1) + lineHeight; + + editorElement.style.height = `${height}px`; + editor.layout(); + }, []); + + return ( + + + +
+ + {(copy) => ( + + {copyToClipboardLabel} + + )} + +
+
+ + {}} + editorDidMount={setEditorCalculatedHeight} + aria-label={codeEditorAriaLabel} + options={{ + automaticLayout: true, + fontSize: 12, + minimap: { + enabled: false, + }, + overviewRulerBorder: false, + readOnly: true, + scrollbar: { + alwaysConsumeMouseWheel: false, + }, + scrollBeyondLastLine: false, + wordWrap: 'on', + wrappingIndent: 'indent', + }} + /> + +
+ ); +}; diff --git a/src/plugins/discover/public/plugin.ts b/src/plugins/discover/public/plugin.ts index c53dfaff24112f..47161c2b8298e1 100644 --- a/src/plugins/discover/public/plugin.ts +++ b/src/plugins/discover/public/plugin.ts @@ -36,7 +36,7 @@ import { UrlGeneratorState } from '../../share/public'; import { DocViewInput, DocViewInputFn } from './application/doc_views/doc_views_types'; import { DocViewsRegistry } from './application/doc_views/doc_views_registry'; import { DocViewTable } from './application/components/table/table'; -import { JsonCodeBlock } from './application/components/json_code_block/json_code_block'; +import { JsonCodeEditor } from './application/components/json_code_editor/json_code_editor'; import { setDocViewsRegistry, setUrlTracker, @@ -187,7 +187,7 @@ export class DiscoverPlugin defaultMessage: 'JSON', }), order: 20, - component: JsonCodeBlock, + component: JsonCodeEditor, }); const { diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 3196bcc6031c9e..3a07e303eb7d81 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -1479,7 +1479,6 @@ "discover.docTable.tableRow.viewSingleDocumentLinkText": "単一のドキュメントを表示", "discover.docTable.tableRow.viewSurroundingDocumentsLinkText": "周りのドキュメントを表示", "discover.documentsAriaLabel": "ドキュメント", - "discover.docViews.json.codeEditorAriaLabel": "Elasticsearch ドキュメントの JSON ビューのみを読み込む", "discover.docViews.json.jsonTitle": "JSON", "discover.docViews.table.fieldNamesBeginningWithUnderscoreUnsupportedAriaLabel": "警告", "discover.docViews.table.fieldNamesBeginningWithUnderscoreUnsupportedTooltip": "{underscoreSign} で始まるフィールド名はサポートされません", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 7292769cdbd0fa..71a2fd83be9680 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -1479,7 +1479,6 @@ "discover.docTable.tableRow.viewSingleDocumentLinkText": "查看单个文档", "discover.docTable.tableRow.viewSurroundingDocumentsLinkText": "查看周围文档", "discover.documentsAriaLabel": "文档", - "discover.docViews.json.codeEditorAriaLabel": "Elasticsearch 文档的只读 JSON 视图", "discover.docViews.json.jsonTitle": "JSON", "discover.docViews.table.fieldNamesBeginningWithUnderscoreUnsupportedAriaLabel": "警告", "discover.docViews.table.fieldNamesBeginningWithUnderscoreUnsupportedTooltip": "不支持以 {underscoreSign} 开头的字段名称", From a2cd3662b20937b04666b2f48a58abaea9e7a3d8 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Wed, 17 Feb 2021 16:23:30 -0500 Subject: [PATCH 11/17] [Maps] rename data load method for clarity (#91547) --- .../maps/public/classes/layers/layer.tsx | 4 ++-- .../layers/vector_layer/vector_layer.tsx | 2 +- .../public/selectors/map_selectors.test.ts | 20 ++++++++++--------- .../maps/public/selectors/map_selectors.ts | 2 +- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/x-pack/plugins/maps/public/classes/layers/layer.tsx b/x-pack/plugins/maps/public/classes/layers/layer.tsx index 89c6d70a217c95..e3a21b596afe14 100644 --- a/x-pack/plugins/maps/public/classes/layers/layer.tsx +++ b/x-pack/plugins/maps/public/classes/layers/layer.tsx @@ -77,7 +77,7 @@ export interface ILayer { canShowTooltip(): boolean; syncLayerWithMB(mbMap: MbMap): void; getLayerTypeIconName(): string; - isDataLoaded(): boolean; + isInitialDataLoadComplete(): boolean; getIndexPatternIds(): string[]; getQueryableIndexPatternIds(): string[]; getType(): string | undefined; @@ -446,7 +446,7 @@ export class AbstractLayer implements ILayer { throw new Error('should implement Layer#getLayerTypeIconName'); } - isDataLoaded(): boolean { + isInitialDataLoadComplete(): boolean { const sourceDataRequest = this.getSourceDataRequest(); return sourceDataRequest ? sourceDataRequest.hasData() : false; } diff --git a/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx b/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx index 7e87d99fd4f93f..2373ed3ba2062f 100644 --- a/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx @@ -174,7 +174,7 @@ export class VectorLayer extends AbstractLayer implements IVectorLayer { return this.getValidJoins().length > 0; } - isDataLoaded() { + isInitialDataLoadComplete() { const sourceDataRequest = this.getSourceDataRequest(); if (!sourceDataRequest || !sourceDataRequest.hasData()) { return false; diff --git a/x-pack/plugins/maps/public/selectors/map_selectors.test.ts b/x-pack/plugins/maps/public/selectors/map_selectors.test.ts index fff33ae246b319..58268b6ea9d82c 100644 --- a/x-pack/plugins/maps/public/selectors/map_selectors.test.ts +++ b/x-pack/plugins/maps/public/selectors/map_selectors.test.ts @@ -124,12 +124,12 @@ describe('getTimeFilters', () => { describe('areLayersLoaded', () => { function createLayerMock({ hasErrors = false, - isDataLoaded = false, + isInitialDataLoadComplete = false, isVisible = true, showAtZoomLevel = true, }: { hasErrors?: boolean; - isDataLoaded?: boolean; + isInitialDataLoadComplete?: boolean; isVisible?: boolean; showAtZoomLevel?: boolean; }) { @@ -137,8 +137,8 @@ describe('areLayersLoaded', () => { hasErrors: () => { return hasErrors; }, - isDataLoaded: () => { - return isDataLoaded; + isInitialDataLoadComplete: () => { + return isInitialDataLoadComplete; }, isVisible: () => { return isVisible; @@ -157,35 +157,37 @@ describe('areLayersLoaded', () => { }); test('layer should not be counted as loaded if it has not loaded', () => { - const layerList = [createLayerMock({ isDataLoaded: false })]; + const layerList = [createLayerMock({ isInitialDataLoadComplete: false })]; const waitingForMapReadyLayerList: LayerDescriptor[] = []; const zoom = 4; expect(areLayersLoaded.resultFunc(layerList, waitingForMapReadyLayerList, zoom)).toBe(false); }); test('layer should be counted as loaded if its not visible', () => { - const layerList = [createLayerMock({ isVisible: false, isDataLoaded: false })]; + const layerList = [createLayerMock({ isVisible: false, isInitialDataLoadComplete: false })]; const waitingForMapReadyLayerList: LayerDescriptor[] = []; const zoom = 4; expect(areLayersLoaded.resultFunc(layerList, waitingForMapReadyLayerList, zoom)).toBe(true); }); test('layer should be counted as loaded if its not shown at zoom level', () => { - const layerList = [createLayerMock({ showAtZoomLevel: false, isDataLoaded: false })]; + const layerList = [ + createLayerMock({ showAtZoomLevel: false, isInitialDataLoadComplete: false }), + ]; const waitingForMapReadyLayerList: LayerDescriptor[] = []; const zoom = 4; expect(areLayersLoaded.resultFunc(layerList, waitingForMapReadyLayerList, zoom)).toBe(true); }); test('layer should be counted as loaded if it has a loading error', () => { - const layerList = [createLayerMock({ hasErrors: true, isDataLoaded: false })]; + const layerList = [createLayerMock({ hasErrors: true, isInitialDataLoadComplete: false })]; const waitingForMapReadyLayerList: LayerDescriptor[] = []; const zoom = 4; expect(areLayersLoaded.resultFunc(layerList, waitingForMapReadyLayerList, zoom)).toBe(true); }); test('layer should be counted as loaded if its loaded', () => { - const layerList = [createLayerMock({ isDataLoaded: true })]; + const layerList = [createLayerMock({ isInitialDataLoadComplete: true })]; const waitingForMapReadyLayerList: LayerDescriptor[] = []; const zoom = 4; expect(areLayersLoaded.resultFunc(layerList, waitingForMapReadyLayerList, zoom)).toBe(true); diff --git a/x-pack/plugins/maps/public/selectors/map_selectors.ts b/x-pack/plugins/maps/public/selectors/map_selectors.ts index ffaff3263cf484..35c73a2bd2f1c7 100644 --- a/x-pack/plugins/maps/public/selectors/map_selectors.ts +++ b/x-pack/plugins/maps/public/selectors/map_selectors.ts @@ -437,7 +437,7 @@ export const areLayersLoaded = createSelector( layer.isVisible() && layer.showAtZoomLevel(zoom) && !layer.hasErrors() && - !layer.isDataLoaded() + !layer.isInitialDataLoadComplete() ) { return false; } From e095a6abf2ed3c7d49322643382b2056c89090d4 Mon Sep 17 00:00:00 2001 From: Michael Olorunnisola Date: Wed, 17 Feb 2021 16:26:40 -0500 Subject: [PATCH 12/17] [Security Solution][Timeline] Minor side panel fixes (#91691) --- .../host_overview/endpoint_overview/translations.ts | 4 ++-- .../side_panel/host_details/expandable_host.tsx | 11 +++++++++-- .../network_details/expandable_network.tsx | 11 +++++++++-- .../timeline/body/events/stateful_event.tsx | 12 +++++++++--- x-pack/plugins/translations/translations/ja-JP.json | 2 -- x-pack/plugins/translations/translations/zh-CN.json | 2 -- 6 files changed, 29 insertions(+), 13 deletions(-) diff --git a/x-pack/plugins/security_solution/public/overview/components/host_overview/endpoint_overview/translations.ts b/x-pack/plugins/security_solution/public/overview/components/host_overview/endpoint_overview/translations.ts index 3e18c7a01c808e..1a007cd7f0f56d 100644 --- a/x-pack/plugins/security_solution/public/overview/components/host_overview/endpoint_overview/translations.ts +++ b/x-pack/plugins/security_solution/public/overview/components/host_overview/endpoint_overview/translations.ts @@ -17,13 +17,13 @@ export const ENDPOINT_POLICY = i18n.translate( export const POLICY_STATUS = i18n.translate( 'xpack.securitySolution.host.details.endpoint.policyStatus', { - defaultMessage: 'Configuration Status', + defaultMessage: 'Policy Status', } ); export const SENSORVERSION = i18n.translate( 'xpack.securitySolution.host.details.endpoint.sensorversion', { - defaultMessage: 'Sensorversion', + defaultMessage: 'Sensor Version', } ); diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/host_details/expandable_host.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/host_details/expandable_host.tsx index 4e101e29bb4841..8fce9a186bbd46 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/host_details/expandable_host.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/host_details/expandable_host.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; +import styled from 'styled-components'; import { i18n } from '@kbn/i18n'; import { EuiTitle } from '@elastic/eui'; import { HostDetailsLink } from '../../../../common/components/links'; @@ -23,14 +24,20 @@ interface ExpandableHostProps { hostName: string; } +const StyledTitle = styled.h4` + word-break: break-all; + word-wrap: break-word; + white-space: pre-wrap; +`; + export const ExpandableHostDetailsTitle = ({ hostName }: ExpandableHostProps) => ( -

+ {i18n.translate('xpack.securitySolution.timeline.sidePanel.hostDetails.title', { defaultMessage: 'Host details', })} {`: ${hostName}`} -

+
); diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/network_details/expandable_network.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/network_details/expandable_network.tsx index b12b575681acf2..19f6e2c9652f92 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/network_details/expandable_network.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/network_details/expandable_network.tsx @@ -7,6 +7,7 @@ import { EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import styled from 'styled-components'; import React, { useCallback, useMemo } from 'react'; import { useDispatch } from 'react-redux'; import { FlowTarget } from '../../../../../common/search_strategy'; @@ -31,14 +32,20 @@ interface ExpandableNetworkProps { expandedNetwork: { ip: string; flowTarget: FlowTarget }; } +const StyledTitle = styled.h4` + word-break: break-all; + word-wrap: break-word; + white-space: pre-wrap; +`; + export const ExpandableNetworkDetailsTitle = ({ ip }: { ip: string }) => ( -

+ {i18n.translate('xpack.securitySolution.timeline.sidePanel.networkDetails.title', { defaultMessage: 'Network details', })} {`: ${ip}`} -

+
); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/stateful_event.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/stateful_event.tsx index 45b10d635195bb..4191badd6b03fb 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/stateful_event.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/stateful_event.tsx @@ -109,8 +109,14 @@ const StatefulEventComponent: React.FC = ({ }, [event?.data]); const hostIPAddresses = useMemo(() => { - const ipList = getMappedNonEcsValue({ data: event?.data, fieldName: 'host.ip' }); - return ipList; + const hostIpList = getMappedNonEcsValue({ data: event?.data, fieldName: 'host.ip' }) ?? []; + const sourceIpList = getMappedNonEcsValue({ data: event?.data, fieldName: 'source.ip' }) ?? []; + const destinationIpList = + getMappedNonEcsValue({ + data: event?.data, + fieldName: 'destination.ip', + }) ?? []; + return new Set([...hostIpList, ...sourceIpList, ...destinationIpList]); }, [event?.data]); const activeTab = tabType ?? TimelineTabs.query; @@ -123,7 +129,7 @@ const StatefulEventComponent: React.FC = ({ activeExpandedDetail?.params?.hostName === hostName) || (activeExpandedDetail?.panelView === 'networkDetail' && activeExpandedDetail?.params?.ip && - hostIPAddresses?.includes(activeExpandedDetail?.params?.ip)) || + hostIPAddresses?.has(activeExpandedDetail?.params?.ip)) || false; const getNotesByIds = useMemo(() => appSelectors.notesByIdsSelector(), []); diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 3a07e303eb7d81..344a07e53e3edb 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -18875,8 +18875,6 @@ "xpack.securitySolution.hooks.useAddToTimeline.addedFieldMessage": "{fieldOrValue}をタイムラインに追加しました", "xpack.securitySolution.host.details.architectureLabel": "アーキテクチャー", "xpack.securitySolution.host.details.endpoint.endpointPolicy": "統合", - "xpack.securitySolution.host.details.endpoint.policyStatus": "構成ステータス", - "xpack.securitySolution.host.details.endpoint.sensorversion": "センサーバージョン", "xpack.securitySolution.host.details.firstSeenTitle": "初回の認識", "xpack.securitySolution.host.details.lastSeenTitle": "前回の認識", "xpack.securitySolution.host.details.overview.cloudProviderTitle": "クラウドプロバイダー", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 71a2fd83be9680..579a06d44e6595 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -18921,8 +18921,6 @@ "xpack.securitySolution.hooks.useAddToTimeline.addedFieldMessage": "已将 {fieldOrValue} 添加到时间线", "xpack.securitySolution.host.details.architectureLabel": "架构", "xpack.securitySolution.host.details.endpoint.endpointPolicy": "集成", - "xpack.securitySolution.host.details.endpoint.policyStatus": "配置状态", - "xpack.securitySolution.host.details.endpoint.sensorversion": "感应器版本", "xpack.securitySolution.host.details.firstSeenTitle": "首次看到时间", "xpack.securitySolution.host.details.lastSeenTitle": "最后看到时间", "xpack.securitySolution.host.details.overview.cloudProviderTitle": "云服务提供商", From e6ecc9fe255b69f6f950ba54153d707bbfdd1e0a Mon Sep 17 00:00:00 2001 From: "Devin W. Hurley" Date: Wed, 17 Feb 2021 17:08:41 -0500 Subject: [PATCH 13/17] [Security Solution] [Detections] Prevent early ejection from big loop when index pattern is missing the given timestamp override field (#91597) * fix for when search response yields 400 with missing timestamp override field * prefer includes over strict equality * adds integration test to check for this case * adds a unit test and util function to ensure unit test executes properly and waits for rule to complete running * remove comments from rebase --- .../signals/single_search_after.ts | 28 ++++++++++++++++ .../lib/detection_engine/signals/utils.ts | 12 ++++--- .../security_and_spaces/tests/create_rules.ts | 32 +++++++++++++++++++ .../detection_engine_api_integration/utils.ts | 13 ++++++++ 4 files changed, 81 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_search_after.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_search_after.ts index fbea610428bd0f..9c58bba296ad35 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_search_after.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_search_after.ts @@ -87,6 +87,34 @@ export const singleSearchAfter = async ({ }; } catch (exc) { logger.error(buildRuleMessage(`[-] nextSearchAfter threw an error ${exc}`)); + if ( + exc.message.includes('No mapping found for [@timestamp] in order to sort on') || + exc.message.includes(`No mapping found for [${timestampOverride}] in order to sort on`) + ) { + logger.error(buildRuleMessage(`[-] failure reason: ${exc.message}`)); + + const searchRes: SignalSearchResponse = { + took: 0, + timed_out: false, + _shards: { + total: 1, + successful: 1, + failed: 0, + skipped: 0, + }, + hits: { + total: 0, + max_score: 0, + hits: [], + }, + }; + return { + searchResult: searchRes, + searchDuration: '-1.0', + searchErrors: exc.message, + }; + } + throw exc; } }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts index f6bd5c8a325be1..323986e6ffecbc 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts @@ -134,9 +134,10 @@ export const hasTimestampFields = async ( ? 'timestamp field "@timestamp"' : `timestamp override field "${timestampField}"` }: ${JSON.stringify( - isEmpty(timestampFieldCapsResponse.body.fields) + isEmpty(timestampFieldCapsResponse.body.fields) || + isEmpty(timestampFieldCapsResponse.body.fields[timestampField]) ? timestampFieldCapsResponse.body.indices - : timestampFieldCapsResponse.body.fields[timestampField].unmapped.indices + : timestampFieldCapsResponse.body.fields[timestampField]?.unmapped?.indices )}`; logger.error(buildRuleMessage(errorString)); await ruleStatusService.warning(errorString); @@ -698,9 +699,12 @@ export const createSearchAfterReturnTypeFromResponse = ({ searchResult._shards.failed === 0 || searchResult._shards.failures?.every((failure) => { return ( - failure.reason?.reason === 'No mapping found for [@timestamp] in order to sort on' || - failure.reason?.reason === + failure.reason?.reason?.includes( + 'No mapping found for [@timestamp] in order to sort on' + ) || + failure.reason?.reason?.includes( `No mapping found for [${timestampOverride}] in order to sort on` + ) ); }), lastLookBackDate: lastValidDate({ searchResult, timestampOverride }), diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_rules.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_rules.ts index a9120bde274f24..8d494724d9f766 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_rules.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_rules.ts @@ -27,11 +27,13 @@ import { getSimpleMlRuleOutput, waitForRuleSuccessOrStatus, waitForSignalsToBePresent, + waitForAlertToComplete, getRuleForSignalTesting, getRuleForSignalTestingWithTimestampOverride, } from '../../utils'; import { ROLES } from '../../../../plugins/security_solution/common/test'; import { createUserAndRole, deleteUserAndRole } from '../roles_users_utils'; +import { RuleStatusResponse } from '../../../../plugins/security_solution/server/lib/detection_engine/rules/types'; // eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext) => { @@ -287,6 +289,36 @@ export default ({ getService }: FtrProviderContext) => { await deleteAllAlerts(supertest); await esArchiver.unload('security_solution/timestamp_override'); }); + + it('should create a single rule which has a timestamp override for an index pattern that does not exist and write a warning status', async () => { + // defaults to event.ingested timestamp override. + // event.ingested is one of the timestamp fields set on the es archive data + // inside of x-pack/test/functional/es_archives/security_solution/timestamp_override/data.json.gz + const simpleRule = getRuleForSignalTestingWithTimestampOverride(['myfakeindex-1']); + const { body } = await supertest + .post(DETECTION_ENGINE_RULES_URL) + .set('kbn-xsrf', 'true') + .send(simpleRule) + .expect(200); + const bodyId = body.id; + + await waitForAlertToComplete(supertest, bodyId); + await waitForRuleSuccessOrStatus(supertest, bodyId, 'warning'); + + const { body: statusBody } = await supertest + .post(DETECTION_ENGINE_RULES_STATUS_URL) + .set('kbn-xsrf', 'true') + .send({ ids: [bodyId] }) + .expect(200); + + expect((statusBody as RuleStatusResponse)[bodyId].current_status?.status).to.eql('warning'); + expect( + (statusBody as RuleStatusResponse)[bodyId].current_status?.last_success_message + ).to.eql( + 'The following indices are missing the timestamp override field "event.ingested": ["myfakeindex-1"]' + ); + }); + it('should create a single rule which has a timestamp override and generates two signals with a "warning" status', async () => { // defaults to event.ingested timestamp override. // event.ingested is one of the timestamp fields set on the es archive data diff --git a/x-pack/test/detection_engine_api_integration/utils.ts b/x-pack/test/detection_engine_api_integration/utils.ts index 4875e837556fcc..684cbb6368ad90 100644 --- a/x-pack/test/detection_engine_api_integration/utils.ts +++ b/x-pack/test/detection_engine_api_integration/utils.ts @@ -964,6 +964,19 @@ export const getRule = async ( return body; }; +export const waitForAlertToComplete = async ( + supertest: SuperTest, + id: string +): Promise => { + await waitFor(async () => { + const { body: alertBody } = await supertest + .get(`/api/alerts/alert/${id}/state`) + .set('kbn-xsrf', 'true') + .expect(200); + return alertBody.previousStartedAt != null; + }, 'waitForAlertToComplete'); +}; + /** * Waits for the rule in find status to be 'succeeded' * or the provided status, before continuing From 4ef4b0511b7bb074bafb8ce930b1b8442d1c2b28 Mon Sep 17 00:00:00 2001 From: "Devin W. Hurley" Date: Wed, 17 Feb 2021 17:08:53 -0500 Subject: [PATCH 14/17] [Security Solution] [Detections] Update error banner when refreshing rule status on rule details page (#91051) * refresh error banner on rule details page when refreshing status * remove unused test --- .../rules/rule_status/index.test.tsx | 19 --- .../components/rules/rule_status/index.tsx | 110 +++--------------- .../detection_engine/rules/details/index.tsx | 76 ++++++++++-- 3 files changed, 83 insertions(+), 122 deletions(-) delete mode 100644 x-pack/plugins/security_solution/public/detections/components/rules/rule_status/index.test.tsx diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_status/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_status/index.test.tsx deleted file mode 100644 index f3669e128ac6ed..00000000000000 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_status/index.test.tsx +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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 React from 'react'; -import { shallow } from 'enzyme'; - -import { RuleStatus } from './index'; - -describe('RuleStatus', () => { - it('renders loader correctly', () => { - const wrapper = shallow(); - - expect(wrapper.dive().find('[data-test-subj="rule-status-loader"]')).toHaveLength(1); - }); -}); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_status/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_status/index.tsx index 677e6de0ff485d..42a6cb8bed1d7d 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_status/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_status/index.tsx @@ -5,115 +5,43 @@ * 2.0. */ -import { - EuiButtonIcon, - EuiFlexGroup, - EuiFlexItem, - EuiHealth, - EuiLoadingSpinner, - EuiText, -} from '@elastic/eui'; -import React, { memo, useCallback, useEffect, useState } from 'react'; -import deepEqual from 'fast-deep-equal'; +import { EuiFlexItem, EuiHealth, EuiText } from '@elastic/eui'; +import React, { memo } from 'react'; -import { - useRuleStatus, - RuleInfoStatus, - RuleStatusType, -} from '../../../containers/detection_engine/rules'; +import { RuleStatusType } from '../../../containers/detection_engine/rules'; import { FormattedDate } from '../../../../common/components/formatted_date'; import { getEmptyTagValue } from '../../../../common/components/empty_value'; import { getStatusColor } from './helpers'; import * as i18n from './translations'; interface RuleStatusProps { - ruleId: string | null; - ruleEnabled?: boolean | null; + children: React.ReactNode | null | undefined; + statusDate: string | null | undefined; + status: RuleStatusType | null | undefined; } -const RuleStatusComponent: React.FC = ({ ruleId, ruleEnabled }) => { - const [loading, ruleStatus, fetchRuleStatus] = useRuleStatus(ruleId); - const [myRuleEnabled, setMyRuleEnabled] = useState(ruleEnabled ?? null); - const [currentStatus, setCurrentStatus] = useState( - ruleStatus?.current_status ?? null - ); - - useEffect(() => { - if (myRuleEnabled !== ruleEnabled && fetchRuleStatus != null && ruleId != null) { - fetchRuleStatus(ruleId); - if (myRuleEnabled !== ruleEnabled) { - setMyRuleEnabled(ruleEnabled ?? null); - } - } - }, [fetchRuleStatus, myRuleEnabled, ruleId, ruleEnabled, setMyRuleEnabled]); - - useEffect(() => { - if (!deepEqual(currentStatus, ruleStatus?.current_status)) { - setCurrentStatus(ruleStatus?.current_status ?? null); - } - }, [currentStatus, ruleStatus, setCurrentStatus]); - - const handleRefresh = useCallback(() => { - if (fetchRuleStatus != null && ruleId != null) { - fetchRuleStatus(ruleId); - } - }, [fetchRuleStatus, ruleId]); - - const getStatus = useCallback((status: RuleStatusType | null | undefined) => { - if (status == null) { - return getEmptyTagValue(); - } else if (status != null && status === 'partial failure') { - // Temporary fix if on upgrade a rule has a status of 'partial failure' we want to display that text as 'warning' - // On the next subsequent rule run, that 'partial failure' status will be re-written as a 'warning' status - // and this code will no longer be necessary - // TODO: remove this code in 8.0.0 - return 'warning'; - } - return status; - }, []); - +const RuleStatusComponent: React.FC = ({ children, statusDate, status }) => { return ( - + <> - {i18n.STATUS} - {':'} + + + {status ?? getEmptyTagValue()} + + - {loading && ( - - - - )} - {!loading && ( + {statusDate != null && status != null && ( <> - - - {getStatus(currentStatus?.status)} - - + <>{i18n.STATUS_AT} - {currentStatus?.status_date != null && currentStatus?.status != null && ( - <> - - <>{i18n.STATUS_AT} - - - - - - )} - - + + )} - + {children} + ); }; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx index c4dc9b62c74cd5..4e225917f076df 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx @@ -9,6 +9,7 @@ // TODO: Disabling complexity is temporary till this component is refactored as part of lists UI integration import { + EuiButtonIcon, EuiLoadingSpinner, EuiFlexGroup, EuiFlexItem, @@ -24,6 +25,7 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useParams, useHistory } from 'react-router-dom'; import { useDispatch } from 'react-redux'; import styled from 'styled-components'; +import deepEqual from 'fast-deep-equal'; import { useDeepEqualSelector, @@ -41,7 +43,7 @@ import { } from '../../../../../common/components/link_to/redirect_to_detection_engine'; import { SiemSearchBar } from '../../../../../common/components/search_bar'; import { WrapperPage } from '../../../../../common/components/wrapper_page'; -import { Rule } from '../../../../containers/detection_engine/rules'; +import { Rule, useRuleStatus, RuleInfoStatus } from '../../../../containers/detection_engine/rules'; import { useListsConfig } from '../../../../containers/detection_engine/lists/use_lists_config'; import { SpyRoute } from '../../../../../common/utils/route/spy_routes'; import { StepAboutRuleToggleDetails } from '../../../../components/rules/step_about_rule_details'; @@ -101,6 +103,7 @@ import { import * as detectionI18n from '../../translations'; import * as ruleI18n from '../translations'; +import * as statusI18n from '../../../../components/rules/rule_status/translations'; import * as i18n from './translations'; import { isTab } from '../../../../../common/components/accessibility/helpers'; import { NeedAdminForUpdateRulesCallOut } from '../../../../components/callouts/need_admin_for_update_callout'; @@ -179,6 +182,15 @@ const RuleDetailsPageComponent = () => { const loading = userInfoLoading || listsConfigLoading; const { detailName: ruleId } = useParams<{ detailName: string }>(); const { rule: maybeRule, refresh: refreshRule, loading: ruleLoading } = useRuleAsync(ruleId); + const [loadingStatus, ruleStatus, fetchRuleStatus] = useRuleStatus(ruleId); + const [currentStatus, setCurrentStatus] = useState( + ruleStatus?.current_status ?? null + ); + useEffect(() => { + if (!deepEqual(currentStatus, ruleStatus?.current_status)) { + setCurrentStatus(ruleStatus?.current_status ?? null); + } + }, [currentStatus, ruleStatus, setCurrentStatus]); const [rule, setRule] = useState(null); const isLoading = ruleLoading && rule == null; // This is used to re-trigger api rule status when user de/activate rule @@ -302,33 +314,65 @@ const RuleDetailsPageComponent = () => { ), [ruleDetailTabs, ruleDetailTab, setRuleDetailTab] ); + + const handleRefresh = useCallback(() => { + if (fetchRuleStatus != null && ruleId != null) { + fetchRuleStatus(ruleId); + } + }, [fetchRuleStatus, ruleId]); + + const ruleStatusInfo = useMemo(() => { + return loadingStatus ? ( + + + + ) : ( + <> + + + + + ); + }, [currentStatus, loadingStatus, handleRefresh]); const ruleError = useMemo(() => { - if ( - rule?.status === 'failed' && + if (loadingStatus) { + return ( + + + + ); + } else if ( + currentStatus?.status === 'failed' && ruleDetailTab === RuleDetailTabs.alerts && - rule?.last_failure_at != null + currentStatus?.last_failure_at != null ) { return ( ); } else if ( - (rule?.status === 'warning' || rule?.status === 'partial failure') && + (currentStatus?.status === 'warning' || currentStatus?.status === 'partial failure') && ruleDetailTab === RuleDetailTabs.alerts && - rule?.last_success_at != null + currentStatus?.last_success_at != null ) { return ( ); } return null; - }, [rule, ruleDetailTab]); + }, [ruleDetailTab, currentStatus, loadingStatus]); const updateDateRangeCallback = useCallback( ({ x }) => { @@ -500,7 +544,15 @@ const RuleDetailsPageComponent = () => { , ] : []), - , + <> + + + {statusI18n.STATUS} + {':'} + + {ruleStatusInfo} + + , ]} title={title} > From 9ca41438f1375e257687c027a406f7747b5e2a25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Louv-Jansen?= Date: Wed, 17 Feb 2021 23:15:16 +0100 Subject: [PATCH 15/17] Update backport to 5.6.6 (#91703) --- package.json | 2 +- yarn.lock | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index a7959f047ab5c0..96db1977237d1c 100644 --- a/package.json +++ b/package.json @@ -592,7 +592,7 @@ "babel-plugin-require-context-hook": "^1.0.0", "babel-plugin-styled-components": "^1.10.7", "babel-plugin-transform-react-remove-prop-types": "^0.4.24", - "backport": "^5.6.4", + "backport": "^5.6.6", "base64-js": "^1.3.1", "base64url": "^3.0.1", "broadcast-channel": "^3.0.3", diff --git a/yarn.lock b/yarn.lock index 6cb2a6864eb752..836c067c73324a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9020,10 +9020,10 @@ bach@^1.0.0: async-settle "^1.0.0" now-and-later "^2.0.0" -backport@^5.6.4: - version "5.6.4" - resolved "https://registry.yarnpkg.com/backport/-/backport-5.6.4.tgz#8cf4bc750b26d27161306858ee9069218ad7cdfd" - integrity sha512-ZhuZcGxOBHBXFBCwweVf02b+KhWe0tdgg71jPSl583YYxlru+JBRH+TFM8S0J6/6YUuTWO81M9funjehJ18jqg== +backport@^5.6.6: + version "5.6.6" + resolved "https://registry.yarnpkg.com/backport/-/backport-5.6.6.tgz#cb03f948a36386734fa491343b93f4ca280e00f3" + integrity sha512-8O7z0q6m5DfQgrhLDUOLcH2y/rXwSgqv5WIWSSoZpPyRdPpmd3xApIfohlJ3oBX9W0TdbO3aKzaV00qg3H9P7w== dependencies: "@octokit/rest" "^18.0.12" "@types/lodash.difference" "^4.5.6" @@ -9040,7 +9040,7 @@ backport@^5.6.4: lodash.isstring "^4.0.1" lodash.uniq "^4.5.0" make-dir "^3.1.0" - ora "^5.2.0" + ora "^5.3.0" safe-json-stringify "^1.2.0" strip-json-comments "^3.1.1" winston "^3.3.3" @@ -22186,10 +22186,10 @@ ora@^4.0.3, ora@^4.0.4: strip-ansi "^6.0.0" wcwidth "^1.0.1" -ora@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/ora/-/ora-5.2.0.tgz#de10bfd2d15514384af45f3fa9d9b1aaf344fda1" - integrity sha512-+wG2v8TUU8EgzPHun1k/n45pXquQ9fHnbXVetl9rRgO6kjZszGGbraF3XPTIdgeA+s1lbRjSEftAnyT0w8ZMvQ== +ora@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/ora/-/ora-5.3.0.tgz#fb832899d3a1372fe71c8b2c534bbfe74961bb6f" + integrity sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g== dependencies: bl "^4.0.3" chalk "^4.1.0" From da780f5671b06203c3dc5aeb4026377078a888ec Mon Sep 17 00:00:00 2001 From: Ryland Herrick Date: Wed, 17 Feb 2021 16:52:48 -0600 Subject: [PATCH 16/17] [Security Solution][Detections] Indicator path followup (#91747) * Remove eslint issue by not permuting our input We instead return a new object from our enrich function. * Fixes editing of non-indicator rules If the user edits a rule without visiting the About tab, they will receive a value of threatIndicatorPath: '' which we'll then try to send to the backend, but it gets rejected. By removing this defaulting logic we get the correct behavior: existing rules default to threatIndicatorPath: undefined, which gets stripped before being sent to the backend. If the rule is an indicator rule, the value will be persisted as expected. * Move default indicator path to common constant --- .../security_solution/common/constants.ts | 5 +++ .../schemas/request/rule_schemas.mock.ts | 3 +- .../schemas/response/rules_schema.mocks.ts | 3 +- .../rules/step_about_rule/default_value.ts | 1 - .../rules/step_about_rule/index.tsx | 3 +- .../detection_engine/rules/helpers.test.tsx | 1 - .../pages/detection_engine/rules/helpers.tsx | 2 +- .../threat_mapping/build_threat_enrichment.ts | 3 +- .../enrich_signal_threat_matches.test.ts | 45 ++++++++++--------- .../enrich_signal_threat_matches.ts | 22 ++++----- 10 files changed, 48 insertions(+), 40 deletions(-) diff --git a/x-pack/plugins/security_solution/common/constants.ts b/x-pack/plugins/security_solution/common/constants.ts index 34fcfa5f0befdb..bc71df5d9e0084 100644 --- a/x-pack/plugins/security_solution/common/constants.ts +++ b/x-pack/plugins/security_solution/common/constants.ts @@ -45,6 +45,11 @@ export const DEFAULT_RULE_REFRESH_INTERVAL_VALUE = 60000; // ms export const DEFAULT_RULE_REFRESH_IDLE_VALUE = 2700000; // ms export const DEFAULT_RULE_NOTIFICATION_QUERY_SIZE = 100; +// Document path where threat indicator fields are expected. Used as +// both the source of enrichment fields and the destination for enrichment in +// the generated detection alert +export const DEFAULT_INDICATOR_PATH = 'threat.indicator'; + export enum SecurityPageName { detections = 'detections', overview = 'overview', diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/rule_schemas.mock.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/rule_schemas.mock.ts index fb29e37a53fdbe..3bae9551f4df79 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/rule_schemas.mock.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/rule_schemas.mock.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { DEFAULT_INDICATOR_PATH } from '../../../constants'; import { MachineLearningCreateSchema, MachineLearningUpdateSchema, @@ -56,7 +57,7 @@ export const getCreateThreatMatchRulesSchemaMock = ( rule_id: ruleId, threat_query: '*:*', threat_index: ['list-index'], - threat_indicator_path: 'threat.indicator', + threat_indicator_path: DEFAULT_INDICATOR_PATH, threat_mapping: [ { entries: [ diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.mocks.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.mocks.ts index cf07389e207b34..8dc7427ed09331 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.mocks.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.mocks.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { DEFAULT_INDICATOR_PATH } from '../../../constants'; import { getListArrayMock } from '../types/lists.mock'; import { RulesSchema } from './rules_schema'; @@ -150,7 +151,7 @@ export const getThreatMatchingSchemaPartialMock = (enabled = false): Partial = ({ euiFieldProps: { fullWidth: true, disabled: isLoading, - placeholder: 'threat.indicator', + placeholder: DEFAULT_INDICATOR_PATH, }, }} /> diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.test.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.test.tsx index 111eb8a5594a8d..f0511602bd67f7 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.test.tsx @@ -116,7 +116,6 @@ describe('rule helpers', () => { severity: { value: 'low', mapping: fillEmptySeverityMappings([]), isMappingChecked: false }, tags: ['tag1', 'tag2'], threat: getThreatMock(), - threatIndicatorPath: '', timestampOverride: 'event.ingested', }; const scheduleRuleStepData = { from: '0s', interval: '5m' }; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx index d37c2d9141f5d4..c862d484b282b3 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx @@ -180,7 +180,7 @@ export const getAboutStepsData = (rule: Rule, detailsView: boolean): AboutStepRu }, falsePositives, threat: threat as Threats, - threatIndicatorPath: threatIndicatorPath ?? '', + threatIndicatorPath, }; }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/build_threat_enrichment.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/build_threat_enrichment.ts index 4f38f2db9230a9..cdbafe692c6305 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/build_threat_enrichment.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/build_threat_enrichment.ts @@ -5,13 +5,12 @@ * 2.0. */ +import { DEFAULT_INDICATOR_PATH } from '../../../../../common/constants'; import { SignalSearchResponse, SignalsEnrichment } from '../types'; import { enrichSignalThreatMatches } from './enrich_signal_threat_matches'; import { getThreatList } from './get_threat_list'; import { BuildThreatEnrichmentOptions, GetMatchedThreats } from './types'; -const DEFAULT_INDICATOR_PATH = 'threat.indicator'; - export const buildThreatEnrichment = ({ buildRuleMessage, exceptionItems, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/enrich_signal_threat_matches.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/enrich_signal_threat_matches.test.ts index fada3141168711..f98f0c88a2dfae 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/enrich_signal_threat_matches.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/enrich_signal_threat_matches.test.ts @@ -6,6 +6,7 @@ */ import { get } from 'lodash'; +import { DEFAULT_INDICATOR_PATH } from '../../../../../common/constants'; import { getThreatListItemMock } from './build_threat_mapping_filter.mock'; import { @@ -93,7 +94,7 @@ describe('buildMatchedIndicator', () => { const indicators = buildMatchedIndicator({ queries: [], threats, - indicatorPath: 'threat.indicator', + indicatorPath: DEFAULT_INDICATOR_PATH, }); expect(indicators).toEqual([]); @@ -103,7 +104,7 @@ describe('buildMatchedIndicator', () => { const [indicator] = buildMatchedIndicator({ queries, threats, - indicatorPath: 'threat.indicator', + indicatorPath: DEFAULT_INDICATOR_PATH, }); expect(get(indicator, 'matched.atomic')).toEqual('domain_1'); @@ -113,7 +114,7 @@ describe('buildMatchedIndicator', () => { const [indicator] = buildMatchedIndicator({ queries, threats, - indicatorPath: 'threat.indicator', + indicatorPath: DEFAULT_INDICATOR_PATH, }); expect(get(indicator, 'matched.field')).toEqual('event.field'); @@ -123,7 +124,7 @@ describe('buildMatchedIndicator', () => { const [indicator] = buildMatchedIndicator({ queries, threats, - indicatorPath: 'threat.indicator', + indicatorPath: DEFAULT_INDICATOR_PATH, }); expect(get(indicator, 'matched.type')).toEqual('type_1'); @@ -152,7 +153,7 @@ describe('buildMatchedIndicator', () => { const indicators = buildMatchedIndicator({ queries, threats, - indicatorPath: 'threat.indicator', + indicatorPath: DEFAULT_INDICATOR_PATH, }); expect(indicators).toHaveLength(queries.length); @@ -162,7 +163,7 @@ describe('buildMatchedIndicator', () => { const indicators = buildMatchedIndicator({ queries, threats, - indicatorPath: 'threat.indicator', + indicatorPath: DEFAULT_INDICATOR_PATH, }); expect(indicators).toEqual([ @@ -227,7 +228,7 @@ describe('buildMatchedIndicator', () => { const indicators = buildMatchedIndicator({ queries, threats, - indicatorPath: 'threat.indicator', + indicatorPath: DEFAULT_INDICATOR_PATH, }); expect(indicators).toEqual([ @@ -252,7 +253,7 @@ describe('buildMatchedIndicator', () => { const indicators = buildMatchedIndicator({ queries, threats, - indicatorPath: 'threat.indicator', + indicatorPath: DEFAULT_INDICATOR_PATH, }); expect(indicators).toEqual([ @@ -284,7 +285,7 @@ describe('buildMatchedIndicator', () => { const indicators = buildMatchedIndicator({ queries, threats, - indicatorPath: 'threat.indicator', + indicatorPath: DEFAULT_INDICATOR_PATH, }); expect(indicators).toEqual([ @@ -316,7 +317,7 @@ describe('buildMatchedIndicator', () => { buildMatchedIndicator({ queries, threats, - indicatorPath: 'threat.indicator', + indicatorPath: DEFAULT_INDICATOR_PATH, }) ).toThrowError('Expected indicator field to be an object, but found: not an object'); }); @@ -337,7 +338,7 @@ describe('buildMatchedIndicator', () => { buildMatchedIndicator({ queries, threats, - indicatorPath: 'threat.indicator', + indicatorPath: DEFAULT_INDICATOR_PATH, }) ).toThrowError('Expected indicator field to be an object, but found: not an object'); }); @@ -366,7 +367,7 @@ describe('enrichSignalThreatMatches', () => { const enrichedSignals = await enrichSignalThreatMatches( signals, getMatchedThreats, - 'threat.indicator' + DEFAULT_INDICATOR_PATH ); expect(enrichedSignals.hits.hits).toEqual([]); @@ -381,10 +382,10 @@ describe('enrichSignalThreatMatches', () => { const enrichedSignals = await enrichSignalThreatMatches( signals, getMatchedThreats, - 'threat.indicator' + DEFAULT_INDICATOR_PATH ); const [enrichedHit] = enrichedSignals.hits.hits; - const indicators = get(enrichedHit._source, 'threat.indicator'); + const indicators = get(enrichedHit._source, DEFAULT_INDICATOR_PATH); expect(indicators).toEqual([ { existing: 'indicator' }, @@ -406,10 +407,10 @@ describe('enrichSignalThreatMatches', () => { const enrichedSignals = await enrichSignalThreatMatches( signals, getMatchedThreats, - 'threat.indicator' + DEFAULT_INDICATOR_PATH ); const [enrichedHit] = enrichedSignals.hits.hits; - const indicators = get(enrichedHit._source, 'threat.indicator'); + const indicators = get(enrichedHit._source, DEFAULT_INDICATOR_PATH); expect(indicators).toEqual([ { @@ -427,10 +428,10 @@ describe('enrichSignalThreatMatches', () => { const enrichedSignals = await enrichSignalThreatMatches( signals, getMatchedThreats, - 'threat.indicator' + DEFAULT_INDICATOR_PATH ); const [enrichedHit] = enrichedSignals.hits.hits; - const indicators = get(enrichedHit._source, 'threat.indicator'); + const indicators = get(enrichedHit._source, DEFAULT_INDICATOR_PATH); expect(indicators).toEqual([ { existing: 'indicator' }, @@ -450,7 +451,7 @@ describe('enrichSignalThreatMatches', () => { }); const signals = getSignalsResponseMock([signalHit]); await expect(() => - enrichSignalThreatMatches(signals, getMatchedThreats, 'threat.indicator') + enrichSignalThreatMatches(signals, getMatchedThreats, DEFAULT_INDICATOR_PATH) ).rejects.toThrowError('Expected threat field to be an object, but found: whoops'); }); @@ -486,7 +487,7 @@ describe('enrichSignalThreatMatches', () => { 'custom_threat.custom_indicator' ); const [enrichedHit] = enrichedSignals.hits.hits; - const indicators = get(enrichedHit._source, 'threat.indicator'); + const indicators = get(enrichedHit._source, DEFAULT_INDICATOR_PATH); expect(indicators).toEqual([ { @@ -529,13 +530,13 @@ describe('enrichSignalThreatMatches', () => { const enrichedSignals = await enrichSignalThreatMatches( signals, getMatchedThreats, - 'threat.indicator' + DEFAULT_INDICATOR_PATH ); expect(enrichedSignals.hits.total).toEqual(expect.objectContaining({ value: 1 })); expect(enrichedSignals.hits.hits).toHaveLength(1); const [enrichedHit] = enrichedSignals.hits.hits; - const indicators = get(enrichedHit._source, 'threat.indicator'); + const indicators = get(enrichedHit._source, DEFAULT_INDICATOR_PATH); expect(indicators).toEqual([ { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/enrich_signal_threat_matches.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/enrich_signal_threat_matches.ts index c5b032207f1c5a..761a58224fac58 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/enrich_signal_threat_matches.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/enrich_signal_threat_matches.ts @@ -6,6 +6,7 @@ */ import { get, isObject } from 'lodash'; +import { DEFAULT_INDICATOR_PATH } from '../../../../../common/constants'; import type { SignalSearchResponse, SignalSourceHit } from '../types'; import type { @@ -91,7 +92,7 @@ export const enrichSignalThreatMatches = async ( if (!isObject(threat)) { throw new Error(`Expected threat field to be an object, but found: ${threat}`); } - const existingIndicatorValue = get(signalHit._source, 'threat.indicator') ?? []; + const existingIndicatorValue = get(signalHit._source, DEFAULT_INDICATOR_PATH) ?? []; const existingIndicators = [existingIndicatorValue].flat(); // ensure indicators is an array return { @@ -105,14 +106,15 @@ export const enrichSignalThreatMatches = async ( }, }; }); - /* eslint-disable require-atomic-updates */ - signals.hits.hits = enrichedSignals; - if (isObject(signals.hits.total)) { - signals.hits.total.value = enrichedSignals.length; - } else { - signals.hits.total = enrichedSignals.length; - } - /* eslint-enable require-atomic-updates */ - return signals; + return { + ...signals, + hits: { + ...signals.hits, + hits: enrichedSignals, + total: isObject(signals.hits.total) + ? { ...signals.hits.total, value: enrichedSignals.length } + : enrichedSignals.length, + }, + }; }; From 31810c65566ce58acef283062d3f286444cd3da8 Mon Sep 17 00:00:00 2001 From: igoristic Date: Wed, 17 Feb 2021 18:09:58 -0500 Subject: [PATCH 17/17] Added flag to change the alerts app context requirment (#91726) --- x-pack/plugins/monitoring/common/constants.ts | 5 +++++ .../public/alerts/ccr_read_exceptions_alert/index.tsx | 8 ++++++-- .../public/alerts/cpu_usage_alert/cpu_usage_alert.tsx | 8 ++++++-- .../monitoring/public/alerts/disk_usage_alert/index.tsx | 8 ++++++-- .../public/alerts/large_shard_size_alert/index.tsx | 8 ++++++-- .../public/alerts/legacy_alert/legacy_alert.tsx | 8 ++++++-- .../monitoring/public/alerts/memory_usage_alert/index.tsx | 8 ++++++-- .../missing_monitoring_data_alert.tsx | 8 ++++++-- .../public/alerts/thread_pool_rejections_alert/index.tsx | 3 ++- 9 files changed, 49 insertions(+), 15 deletions(-) diff --git a/x-pack/plugins/monitoring/common/constants.ts b/x-pack/plugins/monitoring/common/constants.ts index 8b1e91e2caf67e..18c96106566486 100644 --- a/x-pack/plugins/monitoring/common/constants.ts +++ b/x-pack/plugins/monitoring/common/constants.ts @@ -580,6 +580,11 @@ export const ALERT_ACTION_TYPE_EMAIL = '.email'; */ export const ALERT_ACTION_TYPE_LOG = '.server-log'; +/** + * To enable modifing of alerts in under actions + */ +export const ALERT_REQUIRES_APP_CONTEXT = false; + export const ALERT_EMAIL_SERVICES = ['gmail', 'hotmail', 'icloud', 'outlook365', 'ses', 'yahoo']; /** diff --git a/x-pack/plugins/monitoring/public/alerts/ccr_read_exceptions_alert/index.tsx b/x-pack/plugins/monitoring/public/alerts/ccr_read_exceptions_alert/index.tsx index f0b58b41015052..3088e2a75c3492 100644 --- a/x-pack/plugins/monitoring/public/alerts/ccr_read_exceptions_alert/index.tsx +++ b/x-pack/plugins/monitoring/public/alerts/ccr_read_exceptions_alert/index.tsx @@ -9,7 +9,11 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { Expression, Props } from '../components/param_details_form/expression'; import { AlertTypeModel, ValidationResult } from '../../../../triggers_actions_ui/public'; -import { ALERT_CCR_READ_EXCEPTIONS, ALERT_DETAILS } from '../../../common/constants'; +import { + ALERT_CCR_READ_EXCEPTIONS, + ALERT_DETAILS, + ALERT_REQUIRES_APP_CONTEXT, +} from '../../../common/constants'; import { AlertTypeParams } from '../../../../alerts/common'; interface ValidateOptions extends AlertTypeParams { @@ -45,6 +49,6 @@ export function createCCRReadExceptionsAlertType(): AlertTypeModel { return { @@ -26,6 +30,6 @@ export function createDiskUsageAlertType(): AlertTypeModel ), validate, defaultActionMessage: '{{context.internalFullMessage}}', - requiresAppContext: true, + requiresAppContext: ALERT_REQUIRES_APP_CONTEXT, }; } diff --git a/x-pack/plugins/monitoring/public/alerts/legacy_alert/legacy_alert.tsx b/x-pack/plugins/monitoring/public/alerts/legacy_alert/legacy_alert.tsx index 3f23035f526496..87850f893797a2 100644 --- a/x-pack/plugins/monitoring/public/alerts/legacy_alert/legacy_alert.tsx +++ b/x-pack/plugins/monitoring/public/alerts/legacy_alert/legacy_alert.tsx @@ -10,7 +10,11 @@ import { i18n } from '@kbn/i18n'; import { EuiTextColor, EuiSpacer } from '@elastic/eui'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { AlertTypeModel } from '../../../../triggers_actions_ui/public/types'; -import { LEGACY_ALERTS, LEGACY_ALERT_DETAILS } from '../../../common/constants'; +import { + LEGACY_ALERTS, + LEGACY_ALERT_DETAILS, + ALERT_REQUIRES_APP_CONTEXT, +} from '../../../common/constants'; export function createLegacyAlertTypes(): AlertTypeModel[] { return LEGACY_ALERTS.map((legacyAlert) => { @@ -34,7 +38,7 @@ export function createLegacyAlertTypes(): AlertTypeModel[] { ), defaultActionMessage: '{{context.internalFullMessage}}', validate: () => ({ errors: {} }), - requiresAppContext: true, + requiresAppContext: ALERT_REQUIRES_APP_CONTEXT, }; }); } diff --git a/x-pack/plugins/monitoring/public/alerts/memory_usage_alert/index.tsx b/x-pack/plugins/monitoring/public/alerts/memory_usage_alert/index.tsx index 8437faf2258b97..6639b4f2f6a489 100644 --- a/x-pack/plugins/monitoring/public/alerts/memory_usage_alert/index.tsx +++ b/x-pack/plugins/monitoring/public/alerts/memory_usage_alert/index.tsx @@ -11,7 +11,11 @@ import { Expression, Props } from '../components/param_details_form/expression'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { AlertTypeModel } from '../../../../triggers_actions_ui/public/types'; -import { ALERT_MEMORY_USAGE, ALERT_DETAILS } from '../../../common/constants'; +import { + ALERT_MEMORY_USAGE, + ALERT_DETAILS, + ALERT_REQUIRES_APP_CONTEXT, +} from '../../../common/constants'; export function createMemoryUsageAlertType(): AlertTypeModel { return { @@ -26,6 +30,6 @@ export function createMemoryUsageAlertType(): AlertTypeModel