From 317e1e41d449bd043f71fafa710697f8b7353cbf Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 5 Apr 2021 11:34:42 -0400 Subject: [PATCH] [Observability] Exploratory View initial skeleton (#94426) (#96215) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Shahzad --- tsconfig.json | 1 + x-pack/plugins/observability/kibana.json | 2 +- .../public/assets/kibana_dashboard_dark.svg | 116 ++++++ .../public/assets/kibana_dashboard_light.svg | 116 ++++++ .../public/components/app/header/index.tsx | 4 +- .../components/empty_view.tsx | 32 ++ .../components/filter_label.test.tsx | 138 +++++++ .../components/filter_label.tsx | 90 ++++ .../configurations/constants.ts | 73 ++++ .../configurations/cpu_usage_config.ts | 42 ++ .../data/elasticsearch_fieldnames.ts | 144 +++++++ .../configurations/data/sample_attribute.ts | 74 ++++ .../data/test_index_pattern.json | 11 + .../configurations/default_configs.ts | 52 +++ .../configurations/kpi_trends_config.ts | 73 ++++ .../configurations/lens_attributes.test.ts | 387 ++++++++++++++++++ .../configurations/lens_attributes.ts | 273 ++++++++++++ .../configurations/logs_frequency_config.ts | 39 ++ .../configurations/memory_usage_config.ts | 42 ++ .../configurations/monitor_duration_config.ts | 48 +++ .../configurations/monitor_pings_config.ts | 43 ++ .../configurations/network_activity_config.ts | 41 ++ .../configurations/performance_dist_config.ts | 86 ++++ .../configurations/service_latency_config.ts | 52 +++ .../service_throughput_config.ts | 55 +++ .../configurations/url_constants.ts | 15 + .../exploratory_view/configurations/utils.ts | 54 +++ .../exploratory_view.test.tsx | 93 +++++ .../exploratory_view/exploratory_view.tsx | 87 ++++ .../exploratory_view/header/header.test.tsx | 53 +++ .../shared/exploratory_view/header/header.tsx | 63 +++ .../hooks/use_default_index_pattern.tsx | 61 +++ .../hooks/use_init_exploratory_view.ts | 44 ++ .../hooks/use_lens_attributes.ts | 88 ++++ .../hooks/use_series_filters.ts | 100 +++++ .../hooks/use_url_strorage.tsx | 103 +++++ .../shared/exploratory_view/index.tsx | 64 +++ .../shared/exploratory_view/rtl_helpers.tsx | 318 ++++++++++++++ .../columns/data_types_col.test.tsx | 59 +++ .../series_builder/columns/data_types_col.tsx | 56 +++ .../columns/report_breakdowns.test.tsx | 75 ++++ .../columns/report_breakdowns.tsx | 15 + .../columns/report_definition_col.test.tsx | 75 ++++ .../columns/report_definition_col.tsx | 95 +++++ .../columns/report_filters.test.tsx | 28 ++ .../series_builder/columns/report_filters.tsx | 22 + .../columns/report_types_col.test.tsx | 65 +++ .../columns/report_types_col.tsx | 61 +++ .../series_builder/custom_report_field.tsx | 47 +++ .../series_builder/series_builder.tsx | 201 +++++++++ .../series_date_picker/index.tsx | 55 +++ .../series_date_picker.test.tsx | 76 ++++ .../series_editor/columns/actions_col.tsx | 31 ++ .../series_editor/columns/breakdowns.test.tsx | 49 +++ .../series_editor/columns/breakdowns.tsx | 65 +++ .../columns/chart_types.test.tsx | 56 +++ .../series_editor/columns/chart_types.tsx | 149 +++++++ .../series_editor/columns/date_picker_col.tsx | 20 + .../columns/filter_expanded.test.tsx | 93 +++++ .../series_editor/columns/filter_expanded.tsx | 100 +++++ .../columns/filter_value_btn.test.tsx | 238 +++++++++++ .../columns/filter_value_btn.tsx | 117 ++++++ .../columns/metric_selection.test.tsx | 112 +++++ .../columns/metric_selection.tsx | 86 ++++ .../series_editor/columns/remove_series.tsx | 35 ++ .../series_editor/columns/series_filter.tsx | 139 +++++++ .../series_editor/selected_filters.test.tsx | 33 ++ .../series_editor/selected_filters.tsx | 96 +++++ .../series_editor/series_editor.tsx | 139 +++++++ .../shared/exploratory_view/types.ts | 89 ++++ .../field_value_selection.tsx | 19 +- .../shared/field_value_suggestions/index.tsx | 24 +- .../public/context/has_data_context.test.tsx | 9 +- .../public/context/has_data_context.tsx | 46 ++- .../public/hooks/use_breadcrumbs.ts | 71 ++++ .../public/hooks/use_quick_time_ranges.tsx | 22 + .../public/hooks/use_values_list.ts | 46 ++- x-pack/plugins/observability/public/index.ts | 1 + .../observability/public/routes/index.tsx | 21 + .../utils/observability_index_patterns.ts | 64 +++ x-pack/plugins/observability/tsconfig.json | 9 +- x-pack/plugins/uptime/public/apps/plugin.ts | 27 +- 82 files changed, 6058 insertions(+), 55 deletions(-) create mode 100644 x-pack/plugins/observability/public/assets/kibana_dashboard_dark.svg create mode 100644 x-pack/plugins/observability/public/assets/kibana_dashboard_light.svg create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/components/empty_view.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/components/filter_label.test.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/components/filter_label.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants.ts create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/cpu_usage_config.ts create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/data/elasticsearch_fieldnames.ts create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/data/sample_attribute.ts create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/data/test_index_pattern.json create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/default_configs.ts create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/kpi_trends_config.ts create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.test.ts create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.ts create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/logs_frequency_config.ts create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/memory_usage_config.ts create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/monitor_duration_config.ts create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/monitor_pings_config.ts create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/network_activity_config.ts create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/performance_dist_config.ts create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/service_latency_config.ts create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/service_throughput_config.ts create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/url_constants.ts create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.test.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/header/header.test.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/header/header.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_default_index_pattern.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_init_exploratory_view.ts create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_lens_attributes.ts create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_series_filters.ts create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_url_strorage.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/index.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/rtl_helpers.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/data_types_col.test.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/data_types_col.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_breakdowns.test.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_breakdowns.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_definition_col.test.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_definition_col.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_filters.test.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_filters.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_types_col.test.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_types_col.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/custom_report_field.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/series_builder.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/series_date_picker/index.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/series_date_picker/series_date_picker.test.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/actions_col.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/breakdowns.test.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/breakdowns.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/chart_types.test.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/chart_types.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/date_picker_col.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/filter_expanded.test.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/filter_expanded.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/filter_value_btn.test.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/filter_value_btn.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/metric_selection.test.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/metric_selection.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/remove_series.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/series_filter.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/selected_filters.test.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/selected_filters.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/series_editor.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts create mode 100644 x-pack/plugins/observability/public/hooks/use_breadcrumbs.ts create mode 100644 x-pack/plugins/observability/public/hooks/use_quick_time_ranges.tsx create mode 100644 x-pack/plugins/observability/public/utils/observability_index_patterns.ts diff --git a/tsconfig.json b/tsconfig.json index 03597114333cac..30944ac71fcc8a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -83,6 +83,7 @@ "x-pack/plugins/uptime/server/lib/requests/helper.ts", "x-pack/plugins/uptime/public/lib/helper/rtl_helpers.tsx", "x-pack/plugins/uptime/public/lib/helper/enzyme_helpers.tsx", + "x-pack/plugins/observability/public/components/shared/exploratory_view/rtl_helpers.tsx", "x-pack/plugins/apm/server/utils/test_helpers.tsx", "x-pack/plugins/apm/public/utils/testHelpers.tsx", diff --git a/x-pack/plugins/observability/kibana.json b/x-pack/plugins/observability/kibana.json index 84aa1be9a8d870..5c47d0376581a0 100644 --- a/x-pack/plugins/observability/kibana.json +++ b/x-pack/plugins/observability/kibana.json @@ -3,7 +3,7 @@ "version": "8.0.0", "kibanaVersion": "kibana", "configPath": ["xpack", "observability"], - "optionalPlugins": ["licensing", "home", "usageCollection"], + "optionalPlugins": ["licensing", "home", "usageCollection","lens"], "requiredPlugins": ["data"], "ui": true, "server": true, diff --git a/x-pack/plugins/observability/public/assets/kibana_dashboard_dark.svg b/x-pack/plugins/observability/public/assets/kibana_dashboard_dark.svg new file mode 100644 index 00000000000000..834dd98d60e4c6 --- /dev/null +++ b/x-pack/plugins/observability/public/assets/kibana_dashboard_dark.svg @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/x-pack/plugins/observability/public/assets/kibana_dashboard_light.svg b/x-pack/plugins/observability/public/assets/kibana_dashboard_light.svg new file mode 100644 index 00000000000000..958d25362c4393 --- /dev/null +++ b/x-pack/plugins/observability/public/assets/kibana_dashboard_light.svg @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/x-pack/plugins/observability/public/components/app/header/index.tsx b/x-pack/plugins/observability/public/components/app/header/index.tsx index a41e3364d22b6e..8b86e0b25379b8 100644 --- a/x-pack/plugins/observability/public/components/app/header/index.tsx +++ b/x-pack/plugins/observability/public/components/app/header/index.tsx @@ -59,13 +59,13 @@ export function Header({ color, datePicker = null, restrictWidth }: Props) { - + - +

{i18n.translate('xpack.observability.home.title', { diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/components/empty_view.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/components/empty_view.tsx new file mode 100644 index 00000000000000..17f1b039667d0b --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/components/empty_view.tsx @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiImage } from '@elastic/eui'; +import styled from 'styled-components'; +import { useKibana } from '../../../../../../../../src/plugins/kibana_react/public'; + +export function EmptyView() { + const { + services: { http }, + } = useKibana(); + + return ( + + + + ); +} + +const Wrapper = styled.div` + text-align: center; + opacity: 0.4; + height: 550px; +`; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/components/filter_label.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/components/filter_label.test.tsx new file mode 100644 index 00000000000000..37597e0ce513f2 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/components/filter_label.test.tsx @@ -0,0 +1,138 @@ +/* + * 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 { fireEvent, screen, waitFor } from '@testing-library/react'; +import { mockIndexPattern, render } from '../rtl_helpers'; +import { buildFilterLabel, FilterLabel } from './filter_label'; +import * as useSeriesHook from '../hooks/use_series_filters'; + +describe('FilterLabel', function () { + const invertFilter = jest.fn(); + jest.spyOn(useSeriesHook, 'useSeriesFilters').mockReturnValue({ + invertFilter, + } as any); + + it('should render properly', async function () { + render( + + ); + + await waitFor(() => { + screen.getByText('elastic-co'); + screen.getByText(/web application:/i); + screen.getByTitle('Delete Web Application: elastic-co'); + screen.getByRole('button', { + name: /delete web application: elastic-co/i, + }); + }); + }); + + it.skip('should delete filter', async function () { + const removeFilter = jest.fn(); + render( + + ); + + await waitFor(() => { + fireEvent.click(screen.getByLabelText('Filter actions')); + }); + + fireEvent.click(screen.getByTestId('deleteFilter')); + expect(removeFilter).toHaveBeenCalledTimes(1); + expect(removeFilter).toHaveBeenCalledWith('service.name', 'elastic-co', false); + }); + + it.skip('should invert filter', async function () { + const removeFilter = jest.fn(); + render( + + ); + + await waitFor(() => { + fireEvent.click(screen.getByLabelText('Filter actions')); + }); + + fireEvent.click(screen.getByTestId('negateFilter')); + expect(invertFilter).toHaveBeenCalledTimes(1); + expect(invertFilter).toHaveBeenCalledWith({ + field: 'service.name', + negate: false, + value: 'elastic-co', + }); + }); + + it('should display invert filter', async function () { + render( + + ); + + await waitFor(() => { + screen.getByText('elastic-co'); + screen.getByText(/web application:/i); + screen.getByTitle('Delete NOT Web Application: elastic-co'); + screen.getByRole('button', { + name: /delete not web application: elastic-co/i, + }); + }); + }); + + it('should build filter meta', function () { + expect( + buildFilterLabel({ + field: 'user_agent.name', + label: 'Browser family', + indexPattern: mockIndexPattern, + value: 'Firefox', + negate: false, + }) + ).toEqual({ + meta: { + alias: null, + disabled: false, + index: 'apm-*', + key: 'Browser family', + negate: false, + type: 'phrase', + value: 'Firefox', + }, + query: { + match_phrase: { + 'user_agent.name': 'Firefox', + }, + }, + }); + }); +}); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/components/filter_label.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/components/filter_label.tsx new file mode 100644 index 00000000000000..3d6dc5b3f2bf51 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/components/filter_label.tsx @@ -0,0 +1,90 @@ +/* + * 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 { injectI18n } from '@kbn/i18n/react'; +import { esFilters, Filter, IndexPattern } from '../../../../../../../../src/plugins/data/public'; +import { useIndexPatternContext } from '../hooks/use_default_index_pattern'; +import { useKibana } from '../../../../../../../../src/plugins/kibana_react/public'; +import { useSeriesFilters } from '../hooks/use_series_filters'; + +interface Props { + field: string; + label: string; + value: string; + seriesId: string; + negate: boolean; + definitionFilter?: boolean; + removeFilter: (field: string, value: string, notVal: boolean) => void; +} +export function buildFilterLabel({ + field, + value, + label, + indexPattern, + negate, +}: { + label: string; + value: string; + negate: boolean; + field: string; + indexPattern: IndexPattern; +}) { + const indexField = indexPattern.getFieldByName(field)!; + + const filter = esFilters.buildPhraseFilter(indexField, value, indexPattern); + + filter.meta.value = value; + filter.meta.key = label; + filter.meta.alias = null; + filter.meta.negate = negate; + filter.meta.disabled = false; + filter.meta.type = 'phrase'; + + return filter; +} +export function FilterLabel({ + label, + seriesId, + field, + value, + negate, + removeFilter, + definitionFilter, +}: Props) { + const FilterItem = injectI18n(esFilters.FilterItem); + + const { indexPattern } = useIndexPatternContext(); + + const filter = buildFilterLabel({ field, value, label, indexPattern, negate }); + + const { invertFilter } = useSeriesFilters({ seriesId }); + + const { + services: { uiSettings }, + } = useKibana(); + + return indexPattern ? ( + { + removeFilter(field, value, false); + }} + onUpdate={(filterN: Filter) => { + if (definitionFilter) { + // FIXME handle this use case + } else if (filterN.meta.negate !== negate) { + invertFilter({ field, value, negate }); + } + }} + uiSettings={uiSettings!} + hiddenPanelOptions={['pinFilter', 'editFilter', 'disableFilter']} + /> + ) : null; +} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants.ts new file mode 100644 index 00000000000000..aa3ac2fa64317b --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants.ts @@ -0,0 +1,73 @@ +/* + * 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 { AppDataType, ReportViewTypeId } from '../types'; +import { + CLS_FIELD, + FCP_FIELD, + FID_FIELD, + LCP_FIELD, + TBT_FIELD, +} from './data/elasticsearch_fieldnames'; + +export const FieldLabels: Record = { + 'user_agent.name': 'Browser family', + 'user_agent.version': 'Browser version', + 'user_agent.os.name': 'Operating system', + 'client.geo.country_name': 'Location', + 'user_agent.device.name': 'Device', + 'observer.geo.name': 'Observer location', + 'service.name': 'Service Name', + 'service.environment': 'Environment', + + [LCP_FIELD]: 'Largest contentful paint', + [FCP_FIELD]: 'First contentful paint', + [TBT_FIELD]: 'Total blocking time', + [FID_FIELD]: 'First input delay', + [CLS_FIELD]: 'Cumulative layout shift', + + 'monitor.id': 'Monitor Id', + 'monitor.status': 'Monitor Status', + + 'agent.hostname': 'Agent host', + 'host.hostname': 'Host name', + 'monitor.name': 'Monitor name', + 'monitor.type': 'Monitor Type', + 'url.port': 'Port', + tags: 'Tags', + + // custom + + 'performance.metric': 'Metric', + 'Business.KPI': 'KPI', +}; + +export const DataViewLabels: Record = { + pld: 'Performance Distribution', + upd: 'Uptime monitor duration', + upp: 'Uptime pings', + svl: 'APM Service latency', + kpi: 'KPI over time', + tpt: 'APM Service throughput', + cpu: 'System CPU Usage', + logs: 'Logs Frequency', + mem: 'System Memory Usage', + nwk: 'Network Activity', +}; + +export const ReportToDataTypeMap: Record = { + upd: 'synthetics', + upp: 'synthetics', + tpt: 'apm', + svl: 'apm', + kpi: 'rum', + pld: 'rum', + nwk: 'metrics', + mem: 'metrics', + logs: 'logs', + cpu: 'metrics', +}; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/cpu_usage_config.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/cpu_usage_config.ts new file mode 100644 index 00000000000000..5a4fb2aa3a6a59 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/cpu_usage_config.ts @@ -0,0 +1,42 @@ +/* + * 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 { DataSeries } from '../types'; +import { FieldLabels } from './constants'; +import { OperationType } from '../../../../../../lens/public'; + +interface Props { + seriesId: string; +} + +export function getCPUUsageLensConfig({ seriesId }: Props): DataSeries { + return { + id: seriesId, + reportType: 'cpu-usage', + defaultSeriesType: 'line', + seriesTypes: ['line', 'bar'], + xAxisColumn: { + sourceField: '@timestamp', + }, + yAxisColumn: { + operationType: 'avg' as OperationType, + sourceField: 'system.cpu.user.pct', + label: 'CPU Usage %', + }, + hasMetricType: true, + defaultFilters: [], + breakdowns: ['host.hostname'], + filters: [], + labels: { ...FieldLabels, 'host.hostname': 'Host name' }, + reportDefinitions: [ + { + field: 'agent.hostname', + required: true, + }, + ], + }; +} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/data/elasticsearch_fieldnames.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/data/elasticsearch_fieldnames.ts new file mode 100644 index 00000000000000..3faf54fff31404 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/data/elasticsearch_fieldnames.ts @@ -0,0 +1,144 @@ +/* + * 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 const CLOUD = 'cloud'; +export const CLOUD_AVAILABILITY_ZONE = 'cloud.availability_zone'; +export const CLOUD_PROVIDER = 'cloud.provider'; +export const CLOUD_REGION = 'cloud.region'; +export const CLOUD_MACHINE_TYPE = 'cloud.machine.type'; + +export const SERVICE = 'service'; +export const SERVICE_NAME = 'service.name'; +export const SERVICE_ENVIRONMENT = 'service.environment'; +export const SERVICE_FRAMEWORK_NAME = 'service.framework.name'; +export const SERVICE_FRAMEWORK_VERSION = 'service.framework.version'; +export const SERVICE_LANGUAGE_NAME = 'service.language.name'; +export const SERVICE_LANGUAGE_VERSION = 'service.language.version'; +export const SERVICE_RUNTIME_NAME = 'service.runtime.name'; +export const SERVICE_RUNTIME_VERSION = 'service.runtime.version'; +export const SERVICE_NODE_NAME = 'service.node.name'; +export const SERVICE_VERSION = 'service.version'; + +export const AGENT = 'agent'; +export const AGENT_NAME = 'agent.name'; +export const AGENT_VERSION = 'agent.version'; + +export const URL_FULL = 'url.full'; +export const HTTP_REQUEST_METHOD = 'http.request.method'; +export const HTTP_RESPONSE_STATUS_CODE = 'http.response.status_code'; +export const USER_ID = 'user.id'; +export const USER_AGENT_ORIGINAL = 'user_agent.original'; +export const USER_AGENT_NAME = 'user_agent.name'; +export const USER_AGENT_VERSION = 'user_agent.version'; + +export const DESTINATION_ADDRESS = 'destination.address'; + +export const OBSERVER_HOSTNAME = 'observer.hostname'; +export const OBSERVER_VERSION_MAJOR = 'observer.version_major'; +export const OBSERVER_LISTENING = 'observer.listening'; +export const PROCESSOR_EVENT = 'processor.event'; + +export const TRANSACTION_DURATION = 'transaction.duration.us'; +export const TRANSACTION_DURATION_HISTOGRAM = 'transaction.duration.histogram'; +export const TRANSACTION_TYPE = 'transaction.type'; +export const TRANSACTION_RESULT = 'transaction.result'; +export const TRANSACTION_NAME = 'transaction.name'; +export const TRANSACTION_ID = 'transaction.id'; +export const TRANSACTION_SAMPLED = 'transaction.sampled'; +export const TRANSACTION_BREAKDOWN_COUNT = 'transaction.breakdown.count'; +export const TRANSACTION_PAGE_URL = 'transaction.page.url'; +// for transaction metrics +export const TRANSACTION_ROOT = 'transaction.root'; + +export const EVENT_OUTCOME = 'event.outcome'; + +export const TRACE_ID = 'trace.id'; + +export const SPAN_DURATION = 'span.duration.us'; +export const SPAN_TYPE = 'span.type'; +export const SPAN_SUBTYPE = 'span.subtype'; +export const SPAN_SELF_TIME_SUM = 'span.self_time.sum.us'; +export const SPAN_ACTION = 'span.action'; +export const SPAN_NAME = 'span.name'; +export const SPAN_ID = 'span.id'; +export const SPAN_DESTINATION_SERVICE_RESOURCE = 'span.destination.service.resource'; +export const SPAN_DESTINATION_SERVICE_RESPONSE_TIME_COUNT = + 'span.destination.service.response_time.count'; + +export const SPAN_DESTINATION_SERVICE_RESPONSE_TIME_SUM = + 'span.destination.service.response_time.sum.us'; + +// Parent ID for a transaction or span +export const PARENT_ID = 'parent.id'; + +export const ERROR_GROUP_ID = 'error.grouping_key'; +export const ERROR_CULPRIT = 'error.culprit'; +export const ERROR_LOG_LEVEL = 'error.log.level'; +export const ERROR_LOG_MESSAGE = 'error.log.message'; +export const ERROR_EXC_MESSAGE = 'error.exception.message'; // only to be used in es queries, since error.exception is now an array +export const ERROR_EXC_HANDLED = 'error.exception.handled'; // only to be used in es queries, since error.exception is now an array +export const ERROR_EXC_TYPE = 'error.exception.type'; +export const ERROR_PAGE_URL = 'error.page.url'; + +// METRICS +export const METRIC_SYSTEM_FREE_MEMORY = 'system.memory.actual.free'; +export const METRIC_SYSTEM_TOTAL_MEMORY = 'system.memory.total'; +export const METRIC_SYSTEM_CPU_PERCENT = 'system.cpu.total.norm.pct'; +export const METRIC_PROCESS_CPU_PERCENT = 'system.process.cpu.total.norm.pct'; +export const METRIC_CGROUP_MEMORY_LIMIT_BYTES = 'system.process.cgroup.memory.mem.limit.bytes'; +export const METRIC_CGROUP_MEMORY_USAGE_BYTES = 'system.process.cgroup.memory.mem.usage.bytes'; + +export const METRIC_JAVA_HEAP_MEMORY_MAX = 'jvm.memory.heap.max'; +export const METRIC_JAVA_HEAP_MEMORY_COMMITTED = 'jvm.memory.heap.committed'; +export const METRIC_JAVA_HEAP_MEMORY_USED = 'jvm.memory.heap.used'; +export const METRIC_JAVA_NON_HEAP_MEMORY_MAX = 'jvm.memory.non_heap.max'; +export const METRIC_JAVA_NON_HEAP_MEMORY_COMMITTED = 'jvm.memory.non_heap.committed'; +export const METRIC_JAVA_NON_HEAP_MEMORY_USED = 'jvm.memory.non_heap.used'; +export const METRIC_JAVA_THREAD_COUNT = 'jvm.thread.count'; +export const METRIC_JAVA_GC_COUNT = 'jvm.gc.count'; +export const METRIC_JAVA_GC_TIME = 'jvm.gc.time'; + +export const LABEL_NAME = 'labels.name'; + +export const HOST = 'host'; +export const HOST_NAME = 'host.hostname'; +export const HOST_OS_PLATFORM = 'host.os.platform'; +export const CONTAINER_ID = 'container.id'; +export const KUBERNETES = 'kubernetes'; +export const POD_NAME = 'kubernetes.pod.name'; + +export const CLIENT_GEO_COUNTRY_ISO_CODE = 'client.geo.country_iso_code'; +export const CLIENT_GEO_COUNTRY_NAME = 'client.geo.country_name'; + +// RUM Labels +export const TRANSACTION_URL = 'url.full'; +export const CLIENT_GEO = 'client.geo'; +export const USER_AGENT_DEVICE = 'user_agent.device.name'; +export const USER_AGENT_OS = 'user_agent.os.name'; + +export const TRANSACTION_TIME_TO_FIRST_BYTE = 'transaction.marks.agent.timeToFirstByte'; +export const TRANSACTION_DOM_INTERACTIVE = 'transaction.marks.agent.domInteractive'; + +export const FCP_FIELD = 'transaction.marks.agent.firstContentfulPaint'; +export const LCP_FIELD = 'transaction.marks.agent.largestContentfulPaint'; +export const TBT_FIELD = 'transaction.experience.tbt'; +export const FID_FIELD = 'transaction.experience.fid'; +export const CLS_FIELD = 'transaction.experience.cls'; + +export const PROFILE_ID = 'profile.id'; +export const PROFILE_DURATION = 'profile.duration'; +export const PROFILE_TOP_ID = 'profile.top.id'; +export const PROFILE_STACK = 'profile.stack'; + +export const PROFILE_SAMPLES_COUNT = 'profile.samples.count'; +export const PROFILE_CPU_NS = 'profile.cpu.ns'; +export const PROFILE_WALL_US = 'profile.wall.us'; + +export const PROFILE_ALLOC_OBJECTS = 'profile.alloc_objects.count'; +export const PROFILE_ALLOC_SPACE = 'profile.alloc_space.bytes'; +export const PROFILE_INUSE_OBJECTS = 'profile.inuse_objects.count'; +export const PROFILE_INUSE_SPACE = 'profile.inuse_space.bytes'; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/data/sample_attribute.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/data/sample_attribute.ts new file mode 100644 index 00000000000000..9b299e7d70bcc4 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/data/sample_attribute.ts @@ -0,0 +1,74 @@ +/* + * 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 const sampleAttribute = { + title: 'Prefilled from exploratory view app', + description: '', + visualizationType: 'lnsXY', + references: [ + { id: 'apm-*', name: 'indexpattern-datasource-current-indexpattern', type: 'index-pattern' }, + { id: 'apm-*', name: 'indexpattern-datasource-layer-layer1', type: 'index-pattern' }, + ], + state: { + datasourceStates: { + indexpattern: { + layers: { + layer1: { + columnOrder: ['x-axis-column', 'y-axis-column'], + columns: { + 'x-axis-column': { + sourceField: 'transaction.duration.us', + label: 'Page load time', + dataType: 'number', + operationType: 'range', + isBucketed: true, + scale: 'interval', + params: { + type: 'histogram', + ranges: [{ from: 0, to: 1000, label: '' }], + maxBars: 'auto', + }, + }, + 'y-axis-column': { + dataType: 'number', + isBucketed: false, + label: 'Pages loaded', + operationType: 'count', + scale: 'ratio', + sourceField: 'Records', + }, + }, + incompleteColumns: {}, + }, + }, + }, + }, + visualization: { + legend: { isVisible: true, position: 'right' }, + valueLabels: 'hide', + fittingFunction: 'Linear', + curveType: 'CURVE_MONOTONE_X', + axisTitlesVisibilitySettings: { x: true, yLeft: true, yRight: true }, + tickLabelsVisibilitySettings: { x: true, yLeft: true, yRight: true }, + gridlinesVisibilitySettings: { x: true, yLeft: true, yRight: true }, + preferredSeriesType: 'line', + layers: [ + { + accessors: ['y-axis-column'], + layerId: 'layer1', + seriesType: 'line', + yConfig: [{ forAccessor: 'y-axis-column', color: 'green' }], + xAccessor: 'x-axis-column', + }, + ], + }, + query: { query: '', language: 'kuery' }, + filters: [ + { meta: { index: 'apm-*' }, query: { match_phrase: { 'transaction.type': 'page-load' } } }, + { meta: { index: 'apm-*' }, query: { match_phrase: { 'processor.event': 'transaction' } } }, + ], + }, +}; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/data/test_index_pattern.json b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/data/test_index_pattern.json new file mode 100644 index 00000000000000..31fec1fe8d4f46 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/data/test_index_pattern.json @@ -0,0 +1,11 @@ +{ + "attributes": { + "fieldFormatMap": "{\"client.bytes\":{\"id\":\"bytes\"},\"client.nat.port\":{\"id\":\"string\"},\"client.port\":{\"id\":\"string\"},\"destination.bytes\":{\"id\":\"bytes\"},\"destination.nat.port\":{\"id\":\"string\"},\"destination.port\":{\"id\":\"string\"},\"event.duration\":{\"id\":\"duration\",\"params\":{\"inputFormat\":\"nanoseconds\",\"outputFormat\":\"asMilliseconds\",\"outputPrecision\":1}},\"event.sequence\":{\"id\":\"string\"},\"event.severity\":{\"id\":\"string\"},\"http.request.body.bytes\":{\"id\":\"bytes\"},\"http.request.bytes\":{\"id\":\"bytes\"},\"http.response.body.bytes\":{\"id\":\"bytes\"},\"http.response.bytes\":{\"id\":\"bytes\"},\"http.response.status_code\":{\"id\":\"string\"},\"log.syslog.facility.code\":{\"id\":\"string\"},\"log.syslog.priority\":{\"id\":\"string\"},\"network.bytes\":{\"id\":\"bytes\"},\"package.size\":{\"id\":\"string\"},\"process.parent.pgid\":{\"id\":\"string\"},\"process.parent.pid\":{\"id\":\"string\"},\"process.parent.ppid\":{\"id\":\"string\"},\"process.parent.thread.id\":{\"id\":\"string\"},\"process.pgid\":{\"id\":\"string\"},\"process.pid\":{\"id\":\"string\"},\"process.ppid\":{\"id\":\"string\"},\"process.thread.id\":{\"id\":\"string\"},\"server.bytes\":{\"id\":\"bytes\"},\"server.nat.port\":{\"id\":\"string\"},\"server.port\":{\"id\":\"string\"},\"source.bytes\":{\"id\":\"bytes\"},\"source.nat.port\":{\"id\":\"string\"},\"source.port\":{\"id\":\"string\"},\"system.cpu.total.norm.pct\":{\"id\":\"percent\"},\"system.memory.actual.free\":{\"id\":\"bytes\"},\"system.memory.total\":{\"id\":\"bytes\"},\"system.process.cgroup.memory.mem.limit.bytes\":{\"id\":\"bytes\"},\"system.process.cgroup.memory.mem.usage.bytes\":{\"id\":\"bytes\"},\"system.process.cpu.total.norm.pct\":{\"id\":\"percent\"},\"system.process.memory.rss.bytes\":{\"id\":\"bytes\"},\"system.process.memory.size\":{\"id\":\"bytes\"},\"url.port\":{\"id\":\"string\"}}", + "fields": "[{\"name\":\"@timestamp\",\"type\":\"date\",\"esTypes\":[\"date\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"_id\",\"type\":\"string\",\"esTypes\":[\"_id\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_index\",\"type\":\"string\",\"esTypes\":[\"_index\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_score\",\"type\":\"number\",\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_source\",\"type\":\"_source\",\"esTypes\":[\"_source\"],\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_type\",\"type\":\"string\",\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"agent.build.original\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"agent.ephemeral_id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"agent.hostname\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"agent.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"agent.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"agent.type\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"agent.version\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"as.number\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"as.organization.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"as.organization.name.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"as.organization.name\"}}},{\"name\":\"child.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.address\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.as.number\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.as.organization.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.as.organization.name.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"client.as.organization.name\"}}},{\"name\":\"client.bytes\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.domain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.geo.city_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.geo.continent_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.geo.country_iso_code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.geo.country_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.geo.location\",\"type\":\"geo_point\",\"esTypes\":[\"geo_point\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.geo.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.geo.region_iso_code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.geo.region_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.ip\",\"type\":\"ip\",\"esTypes\":[\"ip\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.mac\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.nat.ip\",\"type\":\"ip\",\"esTypes\":[\"ip\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.nat.port\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.packets\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.port\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.registered_domain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.subdomain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.top_level_domain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.user.domain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.user.email\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.user.full_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.user.full_name.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"client.user.full_name\"}}},{\"name\":\"client.user.group.domain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.user.group.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.user.group.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.user.hash\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.user.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.user.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client.user.name.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"client.user.name\"}}},{\"name\":\"client.user.roles\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"cloud.account.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"cloud.account.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"cloud.availability_zone\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"cloud.image.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"cloud.instance.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"cloud.instance.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"cloud.machine.type\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"cloud.project.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"cloud.project.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"cloud.provider\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"cloud.region\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"cloud.service.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"clr.gc.count\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"clr.gc.gen0size\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"clr.gc.gen1size\",\"type\":\"number\",\"esTypes\":[\"float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"clr.gc.gen2size\",\"type\":\"number\",\"esTypes\":[\"float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"clr.gc.gen3size\",\"type\":\"number\",\"esTypes\":[\"float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"code_signature.exists\",\"type\":\"boolean\",\"esTypes\":[\"boolean\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"code_signature.status\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"code_signature.subject_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"code_signature.trusted\",\"type\":\"boolean\",\"esTypes\":[\"boolean\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"code_signature.valid\",\"type\":\"boolean\",\"esTypes\":[\"boolean\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"container.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"container.image.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"container.image.tag\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"container.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"container.runtime\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.address\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.as.number\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.as.organization.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.as.organization.name.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"destination.as.organization.name\"}}},{\"name\":\"destination.bytes\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.domain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.geo.city_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.geo.continent_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.geo.country_iso_code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.geo.country_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.geo.location\",\"type\":\"geo_point\",\"esTypes\":[\"geo_point\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.geo.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.geo.region_iso_code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.geo.region_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.ip\",\"type\":\"ip\",\"esTypes\":[\"ip\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.mac\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.nat.ip\",\"type\":\"ip\",\"esTypes\":[\"ip\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.nat.port\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.packets\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.port\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.registered_domain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.subdomain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.top_level_domain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.user.domain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.user.email\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.user.full_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.user.full_name.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"destination.user.full_name\"}}},{\"name\":\"destination.user.group.domain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.user.group.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.user.group.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.user.hash\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.user.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.user.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination.user.name.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"destination.user.name\"}}},{\"name\":\"destination.user.roles\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.code_signature.exists\",\"type\":\"boolean\",\"esTypes\":[\"boolean\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.code_signature.status\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.code_signature.subject_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.code_signature.trusted\",\"type\":\"boolean\",\"esTypes\":[\"boolean\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.code_signature.valid\",\"type\":\"boolean\",\"esTypes\":[\"boolean\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.hash.md5\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.hash.sha1\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.hash.sha256\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.hash.sha512\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.path\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.pe.architecture\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.pe.company\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.pe.description\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.pe.file_version\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.pe.imphash\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.pe.original_file_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dll.pe.product\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dns.answers.class\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dns.answers.data\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dns.answers.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dns.answers.ttl\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dns.answers.type\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dns.header_flags\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dns.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dns.op_code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dns.question.class\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dns.question.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dns.question.registered_domain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dns.question.subdomain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dns.question.top_level_domain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dns.question.type\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dns.resolved_ip\",\"type\":\"ip\",\"esTypes\":[\"ip\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dns.response_code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dns.type\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ecs.version\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"error.code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"error.culprit\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"error.exception.code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"error.exception.handled\",\"type\":\"boolean\",\"esTypes\":[\"boolean\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"error.exception.message\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"error.exception.module\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"error.exception.type\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"error.grouping_key\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"error.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"error.log.level\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"error.log.logger_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"error.log.message\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"error.log.param_message\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"error.message\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"error.stack_trace\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":false,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"error.stack_trace.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"error.stack_trace\"}}},{\"name\":\"error.type\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.action\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.category\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.created\",\"type\":\"date\",\"esTypes\":[\"date\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.dataset\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.duration\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.end\",\"type\":\"date\",\"esTypes\":[\"date\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.hash\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.ingested\",\"type\":\"date\",\"esTypes\":[\"date\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.kind\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.module\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.original\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":false,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.outcome\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.provider\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.reason\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.reference\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.risk_score\",\"type\":\"number\",\"esTypes\":[\"float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.risk_score_norm\",\"type\":\"number\",\"esTypes\":[\"float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.sequence\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.severity\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.start\",\"type\":\"date\",\"esTypes\":[\"date\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.timezone\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.type\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event.url\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.accessed\",\"type\":\"date\",\"esTypes\":[\"date\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.attributes\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.code_signature.exists\",\"type\":\"boolean\",\"esTypes\":[\"boolean\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.code_signature.status\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.code_signature.subject_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.code_signature.trusted\",\"type\":\"boolean\",\"esTypes\":[\"boolean\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.code_signature.valid\",\"type\":\"boolean\",\"esTypes\":[\"boolean\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.created\",\"type\":\"date\",\"esTypes\":[\"date\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.ctime\",\"type\":\"date\",\"esTypes\":[\"date\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.device\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.directory\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.drive_letter\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.extension\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.gid\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.group\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.hash.md5\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.hash.sha1\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.hash.sha256\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.hash.sha512\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.inode\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.mime_type\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.mode\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.mtime\",\"type\":\"date\",\"esTypes\":[\"date\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.owner\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.path\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.path.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"file.path\"}}},{\"name\":\"file.pe.architecture\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.pe.company\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.pe.description\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.pe.file_version\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.pe.imphash\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.pe.original_file_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.pe.product\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.size\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.target_path\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.target_path.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"file.target_path\"}}},{\"name\":\"file.type\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.uid\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.x509.alternative_names\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.x509.issuer.common_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.x509.issuer.country\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.x509.issuer.distinguished_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.x509.issuer.locality\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.x509.issuer.organization\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.x509.issuer.organizational_unit\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.x509.issuer.state_or_province\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.x509.not_after\",\"type\":\"date\",\"esTypes\":[\"date\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.x509.not_before\",\"type\":\"date\",\"esTypes\":[\"date\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.x509.public_key_algorithm\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.x509.public_key_curve\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.x509.public_key_exponent\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":false,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.x509.public_key_size\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.x509.serial_number\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.x509.signature_algorithm\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.x509.subject.common_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.x509.subject.country\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.x509.subject.distinguished_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.x509.subject.locality\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.x509.subject.organization\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.x509.subject.organizational_unit\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.x509.subject.state_or_province\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file.x509.version_number\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geo.city_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geo.continent_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geo.country_iso_code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geo.country_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geo.location\",\"type\":\"geo_point\",\"esTypes\":[\"geo_point\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geo.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geo.region_iso_code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geo.region_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"golang.goroutines\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"golang.heap.allocations.active\",\"type\":\"number\",\"esTypes\":[\"float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"golang.heap.allocations.allocated\",\"type\":\"number\",\"esTypes\":[\"float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"golang.heap.allocations.frees\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"golang.heap.allocations.idle\",\"type\":\"number\",\"esTypes\":[\"float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"golang.heap.allocations.mallocs\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"golang.heap.allocations.objects\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"golang.heap.allocations.total\",\"type\":\"number\",\"esTypes\":[\"float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"golang.heap.gc.cpu_fraction\",\"type\":\"number\",\"esTypes\":[\"float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"golang.heap.gc.next_gc_limit\",\"type\":\"number\",\"esTypes\":[\"float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"golang.heap.gc.total_count\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"golang.heap.gc.total_pause.ns\",\"type\":\"number\",\"esTypes\":[\"float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"golang.heap.system.obtained\",\"type\":\"number\",\"esTypes\":[\"float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"golang.heap.system.released\",\"type\":\"number\",\"esTypes\":[\"float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"golang.heap.system.stack\",\"type\":\"number\",\"esTypes\":[\"float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"golang.heap.system.total\",\"type\":\"number\",\"esTypes\":[\"float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"group.domain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"group.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"group.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"hash.md5\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"hash.sha1\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"hash.sha256\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"hash.sha512\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.architecture\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.containerized\",\"type\":\"boolean\",\"esTypes\":[\"boolean\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.domain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.geo.city_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.geo.continent_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.geo.country_iso_code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.geo.country_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.geo.location\",\"type\":\"geo_point\",\"esTypes\":[\"geo_point\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.geo.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.geo.region_iso_code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.geo.region_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.hostname\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.ip\",\"type\":\"ip\",\"esTypes\":[\"ip\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.mac\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.os.build\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.os.codename\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.os.family\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.os.full\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.os.full.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"host.os.full\"}}},{\"name\":\"host.os.kernel\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.os.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.os.name.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"host.os.name\"}}},{\"name\":\"host.os.platform\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.os.version\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.type\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.uptime\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.user.domain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.user.email\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.user.full_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.user.full_name.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"host.user.full_name\"}}},{\"name\":\"host.user.group.domain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.user.group.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.user.group.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.user.hash\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.user.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.user.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host.user.name.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"host.user.name\"}}},{\"name\":\"host.user.roles\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.request.body.bytes\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.request.body.content\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.request.body.content.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"http.request.body.content\"}}},{\"name\":\"http.request.bytes\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.request.method\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.request.mime_type\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.request.referrer\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.response.body.bytes\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.response.body.content\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.response.body.content.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"http.response.body.content\"}}},{\"name\":\"http.response.bytes\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.response.finished\",\"type\":\"boolean\",\"esTypes\":[\"boolean\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.response.mime_type\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.response.status_code\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"http.version\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"interface.alias\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"interface.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"interface.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"jvm.gc.alloc\",\"type\":\"number\",\"esTypes\":[\"float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"jvm.gc.count\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"jvm.gc.time\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"jvm.memory.heap.committed\",\"type\":\"number\",\"esTypes\":[\"float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"jvm.memory.heap.max\",\"type\":\"number\",\"esTypes\":[\"float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"jvm.memory.heap.pool.committed\",\"type\":\"number\",\"esTypes\":[\"float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"jvm.memory.heap.pool.max\",\"type\":\"number\",\"esTypes\":[\"float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"jvm.memory.heap.pool.used\",\"type\":\"number\",\"esTypes\":[\"float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"jvm.memory.heap.used\",\"type\":\"number\",\"esTypes\":[\"float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"jvm.memory.non_heap.committed\",\"type\":\"number\",\"esTypes\":[\"float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"jvm.memory.non_heap.max\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"jvm.memory.non_heap.used\",\"type\":\"number\",\"esTypes\":[\"float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"jvm.thread.count\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"kubernetes.container.image\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"kubernetes.container.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"kubernetes.deployment.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"kubernetes.namespace\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"kubernetes.node.hostname\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"kubernetes.node.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"kubernetes.pod.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"kubernetes.pod.uid\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"kubernetes.replicaset.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"kubernetes.statefulset.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"labels.city\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"labels.company\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"labels.country_code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"labels.customer_email\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"labels.customer_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"labels.customer_tier\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"labels.env\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"labels.events_encoded\",\"type\":\"number\",\"esTypes\":[\"scaled_float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"labels.events_failed\",\"type\":\"number\",\"esTypes\":[\"scaled_float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"labels.events_original\",\"type\":\"number\",\"esTypes\":[\"scaled_float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"labels.events_published\",\"type\":\"number\",\"esTypes\":[\"scaled_float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"labels.foo\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"labels.git_rev\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"labels.hostname\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"labels.in_eu\",\"type\":\"boolean\",\"esTypes\":[\"boolean\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"labels.ip\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"labels.kibana_uuid\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"labels.lang\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"labels.lorem\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"labels.multi-line\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"labels.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"labels.plugin\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"labels.productId\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"labels.request_id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"labels.served_from_cache\",\"type\":\"conflict\",\"esTypes\":[\"boolean\",\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false,\"conflictDescriptions\":{\"boolean\":[\"apm-8.0.0-transaction-000001\"],\"keyword\":[\"apm-8.0.0-transaction-000002\"]}},{\"name\":\"labels.taskType\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"labels.this-is-a-very-long-tag-name-without-any-spaces\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"labels.u\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"labels.worker\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"log.file.path\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"log.level\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"log.logger\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"log.origin.file.line\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"log.origin.file.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"log.origin.function\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"log.original\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":false,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"log.syslog.facility.code\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"log.syslog.facility.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"log.syslog.priority\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"log.syslog.severity.code\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"log.syslog.severity.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"message\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"metricset.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"metricset.period\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"network.application\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"network.bytes\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"network.community_id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"network.direction\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"network.forwarded_ip\",\"type\":\"ip\",\"esTypes\":[\"ip\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"network.iana_number\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"network.inner.vlan.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"network.inner.vlan.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"network.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"network.packets\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"network.protocol\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"network.transport\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"network.type\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"network.vlan.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"network.vlan.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"nodejs.eventloop.delay.avg.ms\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"nodejs.eventloop.delay.ns\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"nodejs.handles.active\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"nodejs.memory.arrayBuffers.bytes\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"nodejs.memory.external.bytes\",\"type\":\"number\",\"esTypes\":[\"float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"nodejs.memory.heap.allocated.bytes\",\"type\":\"number\",\"esTypes\":[\"float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"nodejs.memory.heap.used.bytes\",\"type\":\"number\",\"esTypes\":[\"float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"nodejs.requests.active\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.egress.interface.alias\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.egress.interface.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.egress.interface.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.egress.vlan.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.egress.vlan.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.egress.zone\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.geo.city_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.geo.continent_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.geo.country_iso_code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.geo.country_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.geo.location\",\"type\":\"geo_point\",\"esTypes\":[\"geo_point\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.geo.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.geo.region_iso_code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.geo.region_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.hostname\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.ingress.interface.alias\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.ingress.interface.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.ingress.interface.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.ingress.vlan.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.ingress.vlan.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.ingress.zone\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.ip\",\"type\":\"ip\",\"esTypes\":[\"ip\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.listening\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.mac\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.os.family\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.os.full\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.os.full.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"observer.os.full\"}}},{\"name\":\"observer.os.kernel\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.os.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.os.name.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"observer.os.name\"}}},{\"name\":\"observer.os.platform\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.os.version\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.product\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.serial_number\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.type\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.vendor\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.version\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"observer.version_major\",\"type\":\"number\",\"esTypes\":[\"byte\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"organization.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"organization.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"organization.name.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"organization.name\"}}},{\"name\":\"os.family\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"os.full\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"os.full.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"os.full\"}}},{\"name\":\"os.kernel\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"os.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"os.name.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"os.name\"}}},{\"name\":\"os.platform\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"os.version\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"package.architecture\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"package.build_version\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"package.checksum\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"package.description\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"package.install_scope\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"package.installed\",\"type\":\"date\",\"esTypes\":[\"date\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"package.license\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"package.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"package.path\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"package.reference\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"package.size\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"package.type\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"package.version\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"parent.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"pe.architecture\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"pe.company\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"pe.description\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"pe.file_version\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"pe.imphash\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"pe.original_file_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"pe.product\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.args\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.args_count\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.code_signature.exists\",\"type\":\"boolean\",\"esTypes\":[\"boolean\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.code_signature.status\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.code_signature.subject_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.code_signature.trusted\",\"type\":\"boolean\",\"esTypes\":[\"boolean\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.code_signature.valid\",\"type\":\"boolean\",\"esTypes\":[\"boolean\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.command_line\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.command_line.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"process.command_line\"}}},{\"name\":\"process.entity_id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.executable\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.executable.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"process.executable\"}}},{\"name\":\"process.exit_code\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.hash.md5\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.hash.sha1\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.hash.sha256\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.hash.sha512\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.name.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"process.name\"}}},{\"name\":\"process.parent.args\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.args_count\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.code_signature.exists\",\"type\":\"boolean\",\"esTypes\":[\"boolean\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.code_signature.status\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.code_signature.subject_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.code_signature.trusted\",\"type\":\"boolean\",\"esTypes\":[\"boolean\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.code_signature.valid\",\"type\":\"boolean\",\"esTypes\":[\"boolean\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.command_line\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.command_line.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"process.parent.command_line\"}}},{\"name\":\"process.parent.entity_id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.executable\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.executable.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"process.parent.executable\"}}},{\"name\":\"process.parent.exit_code\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.hash.md5\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.hash.sha1\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.hash.sha256\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.hash.sha512\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.name.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"process.parent.name\"}}},{\"name\":\"process.parent.pe.architecture\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.pe.company\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.pe.description\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.pe.file_version\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.pe.imphash\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.pe.original_file_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.pe.product\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.pgid\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.pid\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.ppid\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.start\",\"type\":\"date\",\"esTypes\":[\"date\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.thread.id\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.thread.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.title\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.title.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"process.parent.title\"}}},{\"name\":\"process.parent.uptime\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.working_directory\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.parent.working_directory.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"process.parent.working_directory\"}}},{\"name\":\"process.pe.architecture\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.pe.company\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.pe.description\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.pe.file_version\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.pe.imphash\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.pe.original_file_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.pe.product\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.pgid\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.pid\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.ppid\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.start\",\"type\":\"date\",\"esTypes\":[\"date\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.id\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.thread.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.title\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.uptime\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.working_directory\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process.working_directory.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"process.working_directory\"}}},{\"name\":\"processor.event\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"processor.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"profile.alloc_objects.count\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"profile.alloc_space.bytes\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"profile.cpu.ns\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"profile.duration\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"profile.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"profile.inuse_objects.count\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"profile.inuse_space.bytes\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"profile.samples.count\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"profile.stack.filename\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"profile.stack.function\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"profile.stack.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"profile.stack.line\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"profile.top.filename\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"profile.top.function\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"profile.top.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"profile.top.line\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"registry.data.bytes\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"registry.data.strings\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"registry.data.type\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"registry.hive\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"registry.key\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"registry.path\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"registry.value\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"related.hash\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"related.hosts\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"related.ip\",\"type\":\"ip\",\"esTypes\":[\"ip\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"related.user\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ruby.gc.count\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ruby.heap.allocations.total\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ruby.heap.slots.free\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ruby.heap.slots.live\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ruby.threads\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"rule.author\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"rule.category\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"rule.description\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"rule.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"rule.license\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"rule.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"rule.reference\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"rule.ruleset\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"rule.uuid\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"rule.version\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.address\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.as.number\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.as.organization.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.as.organization.name.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"server.as.organization.name\"}}},{\"name\":\"server.bytes\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.domain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.geo.city_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.geo.continent_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.geo.country_iso_code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.geo.country_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.geo.location\",\"type\":\"geo_point\",\"esTypes\":[\"geo_point\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.geo.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.geo.region_iso_code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.geo.region_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.ip\",\"type\":\"ip\",\"esTypes\":[\"ip\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.mac\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.nat.ip\",\"type\":\"ip\",\"esTypes\":[\"ip\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.nat.port\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.packets\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.port\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.registered_domain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.subdomain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.top_level_domain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.user.domain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.user.email\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.user.full_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.user.full_name.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"server.user.full_name\"}}},{\"name\":\"server.user.group.domain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.user.group.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.user.group.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.user.hash\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.user.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.user.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server.user.name.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"server.user.name\"}}},{\"name\":\"server.user.roles\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"service.environment\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"service.ephemeral_id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"service.framework.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"service.framework.version\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"service.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"service.language.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"service.language.version\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"service.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"service.node.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"service.runtime.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"service.runtime.version\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"service.state\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"service.type\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"service.version\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.address\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.as.number\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.as.organization.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.as.organization.name.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"source.as.organization.name\"}}},{\"name\":\"source.bytes\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.domain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.geo.city_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.geo.continent_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.geo.country_iso_code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.geo.country_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.geo.location\",\"type\":\"geo_point\",\"esTypes\":[\"geo_point\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.geo.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.geo.region_iso_code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.geo.region_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.ip\",\"type\":\"ip\",\"esTypes\":[\"ip\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.mac\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.nat.ip\",\"type\":\"ip\",\"esTypes\":[\"ip\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.nat.port\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.packets\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.port\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.registered_domain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.subdomain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.top_level_domain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.user.domain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.user.email\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.user.full_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.user.full_name.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"source.user.full_name\"}}},{\"name\":\"source.user.group.domain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.user.group.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.user.group.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.user.hash\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.user.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.user.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.user.name.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"source.user.name\"}}},{\"name\":\"source.user.roles\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"sourcemap.bundle_filepath\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"sourcemap.service.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"sourcemap.service.version\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"span.action\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"span.db.link\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"span.db.rows_affected\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"span.destination.service.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"span.destination.service.resource\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"span.destination.service.response_time.count\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"span.destination.service.response_time.sum.us\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"span.destination.service.type\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"span.duration.us\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"span.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"span.message.age.ms\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"span.message.queue.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"span.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"span.self_time.count\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"span.self_time.sum.us\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"span.start.us\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"span.subtype\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"span.sync\",\"type\":\"boolean\",\"esTypes\":[\"boolean\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"span.type\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.cpu.total.norm.pct\",\"type\":\"number\",\"esTypes\":[\"scaled_float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.memory.actual.free\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.memory.total\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.process.cgroup.memory.mem.limit.bytes\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.process.cgroup.memory.mem.usage.bytes\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.process.cgroup.memory.stats.inactive_file.bytes\",\"type\":\"number\",\"esTypes\":[\"float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.process.cpu.system.norm.pct\",\"type\":\"number\",\"esTypes\":[\"float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.process.cpu.total.norm.pct\",\"type\":\"number\",\"esTypes\":[\"scaled_float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.process.cpu.user.norm.pct\",\"type\":\"number\",\"esTypes\":[\"float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.process.memory.rss.bytes\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.process.memory.size\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tags\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"threat.framework\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"threat.tactic.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"threat.tactic.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"threat.tactic.reference\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"threat.technique.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"threat.technique.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"threat.technique.name.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"threat.technique.name\"}}},{\"name\":\"threat.technique.reference\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"threat.technique.subtechnique.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"threat.technique.subtechnique.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"threat.technique.subtechnique.name.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"threat.technique.subtechnique.name\"}}},{\"name\":\"threat.technique.subtechnique.reference\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"timeseries.instance\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"timestamp.us\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.cipher\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.client.certificate\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.client.certificate_chain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.client.hash.md5\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.client.hash.sha1\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.client.hash.sha256\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.client.issuer\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.client.ja3\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.client.not_after\",\"type\":\"date\",\"esTypes\":[\"date\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.client.not_before\",\"type\":\"date\",\"esTypes\":[\"date\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.client.server_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.client.subject\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.client.supported_ciphers\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.client.x509.alternative_names\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.client.x509.issuer.common_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.client.x509.issuer.country\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.client.x509.issuer.distinguished_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.client.x509.issuer.locality\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.client.x509.issuer.organization\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.client.x509.issuer.organizational_unit\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.client.x509.issuer.state_or_province\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.client.x509.not_after\",\"type\":\"date\",\"esTypes\":[\"date\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.client.x509.not_before\",\"type\":\"date\",\"esTypes\":[\"date\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.client.x509.public_key_algorithm\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.client.x509.public_key_curve\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.client.x509.public_key_exponent\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":false,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.client.x509.public_key_size\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.client.x509.serial_number\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.client.x509.signature_algorithm\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.client.x509.subject.common_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.client.x509.subject.country\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.client.x509.subject.distinguished_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.client.x509.subject.locality\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.client.x509.subject.organization\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.client.x509.subject.organizational_unit\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.client.x509.subject.state_or_province\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.client.x509.version_number\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.curve\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.established\",\"type\":\"boolean\",\"esTypes\":[\"boolean\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.next_protocol\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.resumed\",\"type\":\"boolean\",\"esTypes\":[\"boolean\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.server.certificate\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.server.certificate_chain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.server.hash.md5\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.server.hash.sha1\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.server.hash.sha256\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.server.issuer\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.server.ja3s\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.server.not_after\",\"type\":\"date\",\"esTypes\":[\"date\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.server.not_before\",\"type\":\"date\",\"esTypes\":[\"date\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.server.subject\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.server.x509.alternative_names\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.server.x509.issuer.common_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.server.x509.issuer.country\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.server.x509.issuer.distinguished_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.server.x509.issuer.locality\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.server.x509.issuer.organization\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.server.x509.issuer.organizational_unit\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.server.x509.issuer.state_or_province\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.server.x509.not_after\",\"type\":\"date\",\"esTypes\":[\"date\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.server.x509.not_before\",\"type\":\"date\",\"esTypes\":[\"date\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.server.x509.public_key_algorithm\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.server.x509.public_key_curve\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.server.x509.public_key_exponent\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":false,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.server.x509.public_key_size\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.server.x509.serial_number\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.server.x509.signature_algorithm\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.server.x509.subject.common_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.server.x509.subject.country\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.server.x509.subject.distinguished_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.server.x509.subject.locality\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.server.x509.subject.organization\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.server.x509.subject.organizational_unit\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.server.x509.subject.state_or_province\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.server.x509.version_number\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.version\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls.version_protocol\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"trace.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.breakdown.count\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.duration.count\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.duration.histogram\",\"type\":\"histogram\",\"esTypes\":[\"histogram\"],\"searchable\":false,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.duration.sum.us\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.duration.us\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.experience.cls\",\"type\":\"number\",\"esTypes\":[\"scaled_float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.experience.fid\",\"type\":\"number\",\"esTypes\":[\"scaled_float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.experience.longtask.count\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.experience.longtask.max\",\"type\":\"number\",\"esTypes\":[\"scaled_float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.experience.longtask.sum\",\"type\":\"number\",\"esTypes\":[\"scaled_float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.experience.tbt\",\"type\":\"number\",\"esTypes\":[\"scaled_float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.marks.agent.domComplete\",\"type\":\"number\",\"esTypes\":[\"scaled_float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.marks.agent.domInteractive\",\"type\":\"number\",\"esTypes\":[\"scaled_float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.marks.agent.firstContentfulPaint\",\"type\":\"number\",\"esTypes\":[\"scaled_float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.marks.agent.largestContentfulPaint\",\"type\":\"number\",\"esTypes\":[\"scaled_float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.marks.agent.timeToFirstByte\",\"type\":\"number\",\"esTypes\":[\"scaled_float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.marks.navigationTiming.connectEnd\",\"type\":\"number\",\"esTypes\":[\"scaled_float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.marks.navigationTiming.connectStart\",\"type\":\"number\",\"esTypes\":[\"scaled_float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.marks.navigationTiming.domComplete\",\"type\":\"number\",\"esTypes\":[\"scaled_float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.marks.navigationTiming.domContentLoadedEventEnd\",\"type\":\"number\",\"esTypes\":[\"scaled_float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.marks.navigationTiming.domContentLoadedEventStart\",\"type\":\"number\",\"esTypes\":[\"scaled_float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.marks.navigationTiming.domInteractive\",\"type\":\"number\",\"esTypes\":[\"scaled_float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.marks.navigationTiming.domLoading\",\"type\":\"number\",\"esTypes\":[\"scaled_float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.marks.navigationTiming.domainLookupEnd\",\"type\":\"number\",\"esTypes\":[\"scaled_float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.marks.navigationTiming.domainLookupStart\",\"type\":\"number\",\"esTypes\":[\"scaled_float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.marks.navigationTiming.fetchStart\",\"type\":\"number\",\"esTypes\":[\"scaled_float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.marks.navigationTiming.loadEventEnd\",\"type\":\"number\",\"esTypes\":[\"scaled_float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.marks.navigationTiming.loadEventStart\",\"type\":\"number\",\"esTypes\":[\"scaled_float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.marks.navigationTiming.requestStart\",\"type\":\"number\",\"esTypes\":[\"scaled_float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.marks.navigationTiming.responseEnd\",\"type\":\"number\",\"esTypes\":[\"scaled_float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.marks.navigationTiming.responseStart\",\"type\":\"number\",\"esTypes\":[\"scaled_float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.message.age.ms\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.message.queue.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.name.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"transaction.name\"}}},{\"name\":\"transaction.result\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.root\",\"type\":\"boolean\",\"esTypes\":[\"boolean\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.sampled\",\"type\":\"boolean\",\"esTypes\":[\"boolean\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.self_time.count\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.self_time.sum.us\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.span_count.dropped\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction.type\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"url.domain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"url.extension\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"url.fragment\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"url.full\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"url.original\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"url.original.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"url.original\"}}},{\"name\":\"url.password\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"url.path\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"url.port\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"url.query\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"url.registered_domain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"url.scheme\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"url.subdomain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"url.top_level_domain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"url.username\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.domain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.email\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.full_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.full_name.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"user.full_name\"}}},{\"name\":\"user.group.domain\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.group.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.group.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.hash\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.roles\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user_agent.device.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user_agent.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user_agent.original\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user_agent.original.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"user_agent.original\"}}},{\"name\":\"user_agent.os.family\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user_agent.os.full\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user_agent.os.kernel\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user_agent.os.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user_agent.os.platform\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user_agent.os.version\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user_agent.version\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"vlan.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"vlan.name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"vulnerability.category\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"vulnerability.classification\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"vulnerability.description\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"vulnerability.description.text\",\"type\":\"string\",\"esTypes\":[\"text\"],\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false,\"subType\":{\"multi\":{\"parent\":\"vulnerability.description\"}}},{\"name\":\"vulnerability.enumeration\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"vulnerability.id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"vulnerability.reference\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"vulnerability.report_id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"vulnerability.scanner.vendor\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"vulnerability.score.base\",\"type\":\"number\",\"esTypes\":[\"float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"vulnerability.score.environmental\",\"type\":\"number\",\"esTypes\":[\"float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"vulnerability.score.temporal\",\"type\":\"number\",\"esTypes\":[\"float\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"vulnerability.score.version\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"vulnerability.severity\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"x509.alternative_names\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"x509.issuer.common_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"x509.issuer.country\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"x509.issuer.distinguished_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"x509.issuer.locality\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"x509.issuer.organization\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"x509.issuer.organizational_unit\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"x509.issuer.state_or_province\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"x509.not_after\",\"type\":\"date\",\"esTypes\":[\"date\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"x509.not_before\",\"type\":\"date\",\"esTypes\":[\"date\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"x509.public_key_algorithm\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"x509.public_key_curve\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"x509.public_key_exponent\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":false,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"x509.public_key_size\",\"type\":\"number\",\"esTypes\":[\"long\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"x509.serial_number\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"x509.signature_algorithm\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"x509.subject.common_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"x509.subject.country\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"x509.subject.distinguished_name\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"x509.subject.locality\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"x509.subject.organization\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"x509.subject.organizational_unit\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"x509.subject.state_or_province\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"x509.version_number\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true}]", + "sourceFilters": "[{\"value\":\"sourcemap.sourcemap\"}]", + "timeFieldName": "@timestamp" + }, + "id": "apm-*", + "type": "index-pattern", + "version": "1" +} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/default_configs.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/default_configs.ts new file mode 100644 index 00000000000000..85d48ef638d448 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/default_configs.ts @@ -0,0 +1,52 @@ +/* + * 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 { ReportViewTypes } from '../types'; +import { getPerformanceDistLensConfig } from './performance_dist_config'; +import { getMonitorDurationConfig } from './monitor_duration_config'; +import { getServiceLatencyLensConfig } from './service_latency_config'; +import { getMonitorPingsConfig } from './monitor_pings_config'; +import { getServiceThroughputLensConfig } from './service_throughput_config'; +import { getKPITrendsLensConfig } from './kpi_trends_config'; +import { getCPUUsageLensConfig } from './cpu_usage_config'; +import { getMemoryUsageLensConfig } from './memory_usage_config'; +import { getNetworkActivityLensConfig } from './network_activity_config'; +import { getLogsFrequencyLensConfig } from './logs_frequency_config'; +import { IIndexPattern } from '../../../../../../../../src/plugins/data/common/index_patterns'; + +interface Props { + reportType: keyof typeof ReportViewTypes; + seriesId: string; + indexPattern: IIndexPattern; +} + +export const getDefaultConfigs = ({ reportType, seriesId, indexPattern }: Props) => { + switch (ReportViewTypes[reportType]) { + case 'page-load-dist': + return getPerformanceDistLensConfig({ seriesId, indexPattern }); + case 'kpi-trends': + return getKPITrendsLensConfig({ seriesId, indexPattern }); + case 'uptime-duration': + return getMonitorDurationConfig({ seriesId }); + case 'uptime-pings': + return getMonitorPingsConfig({ seriesId }); + case 'service-latency': + return getServiceLatencyLensConfig({ seriesId, indexPattern }); + case 'service-throughput': + return getServiceThroughputLensConfig({ seriesId, indexPattern }); + case 'cpu-usage': + return getCPUUsageLensConfig({ seriesId }); + case 'memory-usage': + return getMemoryUsageLensConfig({ seriesId }); + case 'network-activity': + return getNetworkActivityLensConfig({ seriesId }); + case 'logs-frequency': + return getLogsFrequencyLensConfig({ seriesId }); + default: + return getKPITrendsLensConfig({ seriesId, indexPattern }); + } +}; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/kpi_trends_config.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/kpi_trends_config.ts new file mode 100644 index 00000000000000..a967a8824bca7b --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/kpi_trends_config.ts @@ -0,0 +1,73 @@ +/* + * 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 { ConfigProps, DataSeries } from '../types'; +import { FieldLabels } from './constants'; +import { buildPhraseFilter } from './utils'; +import { + CLIENT_GEO_COUNTRY_NAME, + PROCESSOR_EVENT, + SERVICE_ENVIRONMENT, + SERVICE_NAME, + TRANSACTION_TYPE, + USER_AGENT_DEVICE, + USER_AGENT_NAME, + USER_AGENT_OS, + USER_AGENT_VERSION, +} from './data/elasticsearch_fieldnames'; + +export function getKPITrendsLensConfig({ seriesId, indexPattern }: ConfigProps): DataSeries { + return { + id: seriesId, + defaultSeriesType: 'bar_stacked', + reportType: 'kpi-trends', + seriesTypes: ['bar', 'bar_stacked'], + xAxisColumn: { + sourceField: '@timestamp', + }, + yAxisColumn: { + operationType: 'count', + label: 'Page views', + }, + hasMetricType: false, + defaultFilters: [ + USER_AGENT_OS, + CLIENT_GEO_COUNTRY_NAME, + USER_AGENT_DEVICE, + { + field: USER_AGENT_NAME, + nested: USER_AGENT_VERSION, + }, + ], + breakdowns: [USER_AGENT_NAME, USER_AGENT_OS, CLIENT_GEO_COUNTRY_NAME, USER_AGENT_DEVICE], + filters: [ + buildPhraseFilter(TRANSACTION_TYPE, 'page-load', indexPattern), + buildPhraseFilter(PROCESSOR_EVENT, 'transaction', indexPattern), + ], + labels: { ...FieldLabels, SERVICE_NAME: 'Web Application' }, + reportDefinitions: [ + { + field: SERVICE_NAME, + required: true, + }, + { + field: SERVICE_ENVIRONMENT, + }, + { + field: 'Business.KPI', + custom: true, + defaultValue: 'Records', + options: [ + { + field: 'Records', + label: 'Page views', + }, + ], + }, + ], + }; +} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.test.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.test.ts new file mode 100644 index 00000000000000..dcfaed938cc0f7 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.test.ts @@ -0,0 +1,387 @@ +/* + * 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 { LensAttributes } from './lens_attributes'; +import { mockIndexPattern } from '../rtl_helpers'; +import { getDefaultConfigs } from './default_configs'; +import { sampleAttribute } from './data/sample_attribute'; +import { LCP_FIELD, SERVICE_NAME } from './data/elasticsearch_fieldnames'; +import { USER_AGENT_NAME } from './data/elasticsearch_fieldnames'; + +describe('Lens Attribute', () => { + const reportViewConfig = getDefaultConfigs({ + reportType: 'pld', + indexPattern: mockIndexPattern, + seriesId: 'series-id', + }); + + let lnsAttr: LensAttributes; + + beforeEach(() => { + lnsAttr = new LensAttributes(mockIndexPattern, reportViewConfig, 'line', [], 'count', {}); + }); + + it('should return expected json', function () { + expect(lnsAttr.getJSON()).toEqual(sampleAttribute); + }); + + it('should return main y axis', function () { + expect(lnsAttr.getMainYAxis()).toEqual({ + dataType: 'number', + isBucketed: false, + label: 'Pages loaded', + operationType: 'count', + scale: 'ratio', + sourceField: 'Records', + }); + }); + + it('should return expected field type', function () { + expect(JSON.stringify(lnsAttr.getFieldMeta('transaction.type'))).toEqual( + JSON.stringify({ + count: 0, + name: 'transaction.type', + type: 'string', + esTypes: ['keyword'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }) + ); + }); + + it('should return expected field type for custom field with default value', function () { + expect(JSON.stringify(lnsAttr.getFieldMeta('performance.metric'))).toEqual( + JSON.stringify({ + count: 0, + name: 'transaction.duration.us', + type: 'number', + esTypes: ['long'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }) + ); + }); + + it('should return expected field type for custom field with passed value', function () { + lnsAttr = new LensAttributes(mockIndexPattern, reportViewConfig, 'line', [], 'count', { + 'performance.metric': LCP_FIELD, + }); + + expect(JSON.stringify(lnsAttr.getFieldMeta('performance.metric'))).toEqual( + JSON.stringify({ + count: 0, + name: LCP_FIELD, + type: 'number', + esTypes: ['scaled_float'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }) + ); + }); + + it('should return expected number column', function () { + expect(lnsAttr.getNumberColumn('transaction.duration.us')).toEqual({ + dataType: 'number', + isBucketed: true, + label: 'Page load time', + operationType: 'range', + params: { + maxBars: 'auto', + ranges: [ + { + from: 0, + label: '', + to: 1000, + }, + ], + type: 'histogram', + }, + scale: 'interval', + sourceField: 'transaction.duration.us', + }); + }); + + it('should return expected date histogram column', function () { + expect(lnsAttr.getDateHistogramColumn('@timestamp')).toEqual({ + dataType: 'date', + isBucketed: true, + label: '@timestamp', + operationType: 'date_histogram', + params: { + interval: 'auto', + }, + scale: 'interval', + sourceField: '@timestamp', + }); + }); + + it('should return main x axis', function () { + expect(lnsAttr.getXAxis()).toEqual({ + dataType: 'number', + isBucketed: true, + label: 'Page load time', + operationType: 'range', + params: { + maxBars: 'auto', + ranges: [ + { + from: 0, + label: '', + to: 1000, + }, + ], + type: 'histogram', + }, + scale: 'interval', + sourceField: 'transaction.duration.us', + }); + }); + + it('should return first layer', function () { + expect(lnsAttr.getLayer()).toEqual({ + columnOrder: ['x-axis-column', 'y-axis-column'], + columns: { + 'x-axis-column': { + dataType: 'number', + isBucketed: true, + label: 'Page load time', + operationType: 'range', + params: { + maxBars: 'auto', + ranges: [ + { + from: 0, + label: '', + to: 1000, + }, + ], + type: 'histogram', + }, + scale: 'interval', + sourceField: 'transaction.duration.us', + }, + 'y-axis-column': { + dataType: 'number', + isBucketed: false, + label: 'Pages loaded', + operationType: 'count', + scale: 'ratio', + sourceField: 'Records', + }, + }, + incompleteColumns: {}, + }); + }); + + it('should return expected XYState', function () { + expect(lnsAttr.getXyState()).toEqual({ + axisTitlesVisibilitySettings: { x: true, yLeft: true, yRight: true }, + curveType: 'CURVE_MONOTONE_X', + fittingFunction: 'Linear', + gridlinesVisibilitySettings: { x: true, yLeft: true, yRight: true }, + layers: [ + { + accessors: ['y-axis-column'], + layerId: 'layer1', + palette: undefined, + seriesType: 'line', + xAccessor: 'x-axis-column', + yConfig: [{ color: 'green', forAccessor: 'y-axis-column' }], + }, + ], + legend: { isVisible: true, position: 'right' }, + preferredSeriesType: 'line', + tickLabelsVisibilitySettings: { x: true, yLeft: true, yRight: true }, + valueLabels: 'hide', + }); + }); + + describe('ParseFilters function', function () { + it('should parse default filters', function () { + expect(lnsAttr.parseFilters()).toEqual([ + { meta: { index: 'apm-*' }, query: { match_phrase: { 'transaction.type': 'page-load' } } }, + { meta: { index: 'apm-*' }, query: { match_phrase: { 'processor.event': 'transaction' } } }, + ]); + }); + + it('should parse default and ui filters', function () { + lnsAttr = new LensAttributes( + mockIndexPattern, + reportViewConfig, + 'line', + [ + { field: SERVICE_NAME, values: ['elastic-co', 'kibana-front'] }, + { field: USER_AGENT_NAME, values: ['Firefox'], notValues: ['Chrome'] }, + ], + 'count', + {} + ); + + expect(lnsAttr.parseFilters()).toEqual([ + { meta: { index: 'apm-*' }, query: { match_phrase: { 'transaction.type': 'page-load' } } }, + { meta: { index: 'apm-*' }, query: { match_phrase: { 'processor.event': 'transaction' } } }, + { + meta: { + index: 'apm-*', + key: 'service.name', + params: ['elastic-co', 'kibana-front'], + type: 'phrases', + value: 'elastic-co, kibana-front', + }, + query: { + bool: { + minimum_should_match: 1, + should: [ + { + match_phrase: { + 'service.name': 'elastic-co', + }, + }, + { + match_phrase: { + 'service.name': 'kibana-front', + }, + }, + ], + }, + }, + }, + { + meta: { + index: 'apm-*', + }, + query: { + match_phrase: { + 'user_agent.name': 'Firefox', + }, + }, + }, + { + meta: { + index: 'apm-*', + negate: true, + }, + query: { + match_phrase: { + 'user_agent.name': 'Chrome', + }, + }, + }, + ]); + }); + }); + + describe('Layer breakdowns', function () { + it('should add breakdown column', function () { + lnsAttr.addBreakdown(USER_AGENT_NAME); + + expect(lnsAttr.visualization.layers).toEqual([ + { + accessors: ['y-axis-column'], + layerId: 'layer1', + palette: undefined, + seriesType: 'line', + splitAccessor: 'break-down-column', + xAccessor: 'x-axis-column', + yConfig: [{ color: 'green', forAccessor: 'y-axis-column' }], + }, + ]); + + expect(lnsAttr.layers.layer1).toEqual({ + columnOrder: ['x-axis-column', 'break-down-column', 'y-axis-column'], + columns: { + 'break-down-column': { + dataType: 'string', + isBucketed: true, + label: 'Top values of Browser family', + operationType: 'terms', + params: { + missingBucket: false, + orderBy: { columnId: 'y-axis-column', type: 'column' }, + orderDirection: 'desc', + otherBucket: true, + size: 3, + }, + scale: 'ordinal', + sourceField: 'user_agent.name', + }, + 'x-axis-column': { + dataType: 'number', + isBucketed: true, + label: 'Page load time', + operationType: 'range', + params: { + maxBars: 'auto', + ranges: [{ from: 0, label: '', to: 1000 }], + type: 'histogram', + }, + scale: 'interval', + sourceField: 'transaction.duration.us', + }, + 'y-axis-column': { + dataType: 'number', + isBucketed: false, + label: 'Pages loaded', + operationType: 'count', + scale: 'ratio', + sourceField: 'Records', + }, + }, + incompleteColumns: {}, + }); + }); + + it('should remove breakdown column', function () { + lnsAttr.addBreakdown(USER_AGENT_NAME); + + lnsAttr.removeBreakdown(); + + expect(lnsAttr.visualization.layers).toEqual([ + { + accessors: ['y-axis-column'], + layerId: 'layer1', + palette: undefined, + seriesType: 'line', + xAccessor: 'x-axis-column', + yConfig: [{ color: 'green', forAccessor: 'y-axis-column' }], + }, + ]); + + expect(lnsAttr.layers.layer1.columnOrder).toEqual(['x-axis-column', 'y-axis-column']); + + expect(lnsAttr.layers.layer1.columns).toEqual({ + 'x-axis-column': { + dataType: 'number', + isBucketed: true, + label: 'Page load time', + operationType: 'range', + params: { + maxBars: 'auto', + ranges: [{ from: 0, label: '', to: 1000 }], + type: 'histogram', + }, + scale: 'interval', + sourceField: 'transaction.duration.us', + }, + 'y-axis-column': { + dataType: 'number', + isBucketed: false, + label: 'Pages loaded', + operationType: 'count', + scale: 'ratio', + sourceField: 'Records', + }, + }); + }); + }); +}); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.ts new file mode 100644 index 00000000000000..589a93d1600686 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.ts @@ -0,0 +1,273 @@ +/* + * 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 { + CountIndexPatternColumn, + DateHistogramIndexPatternColumn, + LastValueIndexPatternColumn, + OperationType, + PersistedIndexPatternLayer, + RangeIndexPatternColumn, + SeriesType, + TypedLensByValueInput, + XYState, + XYCurveType, + DataType, +} from '../../../../../../lens/public'; +import { + buildPhraseFilter, + buildPhrasesFilter, + IndexPattern, +} from '../../../../../../../../src/plugins/data/common'; +import { FieldLabels } from './constants'; +import { DataSeries, UrlFilter } from '../types'; + +function getLayerReferenceName(layerId: string) { + return `indexpattern-datasource-layer-${layerId}`; +} + +export class LensAttributes { + indexPattern: IndexPattern; + layers: Record; + visualization: XYState; + filters: UrlFilter[]; + seriesType: SeriesType; + reportViewConfig: DataSeries; + reportDefinitions: Record; + + constructor( + indexPattern: IndexPattern, + reportViewConfig: DataSeries, + seriesType?: SeriesType, + filters?: UrlFilter[], + metricType?: OperationType, + reportDefinitions?: Record + ) { + this.indexPattern = indexPattern; + this.layers = {}; + this.filters = filters ?? []; + this.reportDefinitions = reportDefinitions ?? {}; + + if (typeof reportViewConfig.yAxisColumn.operationType !== undefined && metricType) { + reportViewConfig.yAxisColumn.operationType = metricType; + } + this.seriesType = seriesType ?? reportViewConfig.defaultSeriesType; + this.reportViewConfig = reportViewConfig; + this.layers.layer1 = this.getLayer(); + this.visualization = this.getXyState(); + } + + addBreakdown(sourceField: string) { + const fieldMeta = this.indexPattern.getFieldByName(sourceField); + + this.layers.layer1.columns['break-down-column'] = { + sourceField, + label: `Top values of ${FieldLabels[sourceField]}`, + dataType: fieldMeta?.type as DataType, + operationType: 'terms', + scale: 'ordinal', + isBucketed: true, + params: { + size: 3, + orderBy: { type: 'column', columnId: 'y-axis-column' }, + orderDirection: 'desc', + otherBucket: true, + missingBucket: false, + }, + }; + + this.layers.layer1.columnOrder = ['x-axis-column', 'break-down-column', 'y-axis-column']; + + this.visualization.layers[0].splitAccessor = 'break-down-column'; + } + + removeBreakdown() { + delete this.layers.layer1.columns['break-down-column']; + + this.layers.layer1.columnOrder = ['x-axis-column', 'y-axis-column']; + + this.visualization.layers[0].splitAccessor = undefined; + } + + getNumberColumn(sourceField: string): RangeIndexPatternColumn { + return { + sourceField, + label: this.reportViewConfig.labels[sourceField], + dataType: 'number', + operationType: 'range', + isBucketed: true, + scale: 'interval', + params: { + type: 'histogram', + ranges: [{ from: 0, to: 1000, label: '' }], + maxBars: 'auto', + }, + }; + } + + getDateHistogramColumn(sourceField: string): DateHistogramIndexPatternColumn { + return { + sourceField, + dataType: 'date', + isBucketed: true, + label: '@timestamp', + operationType: 'date_histogram', + params: { interval: 'auto' }, + scale: 'interval', + }; + } + + getXAxis(): + | LastValueIndexPatternColumn + | DateHistogramIndexPatternColumn + | RangeIndexPatternColumn { + const { xAxisColumn } = this.reportViewConfig; + + const { type: fieldType, name: fieldName } = this.getFieldMeta(xAxisColumn.sourceField)!; + + if (fieldType === 'date') { + return this.getDateHistogramColumn(fieldName); + } + if (fieldType === 'number') { + return this.getNumberColumn(fieldName); + } + + // FIXME review my approach again + return this.getDateHistogramColumn(fieldName); + } + + getFieldMeta(sourceField?: string) { + let xAxisField = sourceField; + + if (xAxisField) { + const rdf = this.reportViewConfig.reportDefinitions ?? []; + + const customField = rdf.find(({ field }) => field === xAxisField); + + if (customField) { + if (this.reportDefinitions[xAxisField]) { + xAxisField = this.reportDefinitions[xAxisField]; + } else if (customField.defaultValue) { + xAxisField = customField.defaultValue; + } else if (customField.options?.[0].field) { + xAxisField = customField.options?.[0].field; + } + } + + return this.indexPattern.getFieldByName(xAxisField); + } + } + + getMainYAxis() { + return { + dataType: 'number', + isBucketed: false, + label: 'Count of records', + operationType: 'count', + scale: 'ratio', + sourceField: 'Records', + ...this.reportViewConfig.yAxisColumn, + } as CountIndexPatternColumn; + } + + getLayer() { + return { + columnOrder: ['x-axis-column', 'y-axis-column'], + columns: { + 'x-axis-column': this.getXAxis(), + 'y-axis-column': this.getMainYAxis(), + }, + incompleteColumns: {}, + }; + } + + getXyState(): XYState { + return { + legend: { isVisible: true, position: 'right' }, + valueLabels: 'hide', + fittingFunction: 'Linear', + curveType: 'CURVE_MONOTONE_X' as XYCurveType, + axisTitlesVisibilitySettings: { x: true, yLeft: true, yRight: true }, + tickLabelsVisibilitySettings: { x: true, yLeft: true, yRight: true }, + gridlinesVisibilitySettings: { x: true, yLeft: true, yRight: true }, + preferredSeriesType: 'line', + layers: [ + { + accessors: ['y-axis-column'], + layerId: 'layer1', + seriesType: this.seriesType ?? 'line', + palette: this.reportViewConfig.palette, + yConfig: [{ forAccessor: 'y-axis-column', color: 'green' }], + xAccessor: 'x-axis-column', + }, + ], + }; + } + + parseFilters() { + const defaultFilters = this.reportViewConfig.filters ?? []; + const parsedFilters = this.reportViewConfig.filters ? [...defaultFilters] : []; + + this.filters.forEach(({ field, values = [], notValues = [] }) => { + const fieldMeta = this.indexPattern.fields.find((fieldT) => fieldT.name === field)!; + + if (values?.length > 0) { + if (values?.length > 1) { + const multiFilter = buildPhrasesFilter(fieldMeta, values, this.indexPattern); + parsedFilters.push(multiFilter); + } else { + const filter = buildPhraseFilter(fieldMeta, values[0], this.indexPattern); + parsedFilters.push(filter); + } + } + + if (notValues?.length > 0) { + if (notValues?.length > 1) { + const multiFilter = buildPhrasesFilter(fieldMeta, notValues, this.indexPattern); + multiFilter.meta.negate = true; + parsedFilters.push(multiFilter); + } else { + const filter = buildPhraseFilter(fieldMeta, notValues[0], this.indexPattern); + filter.meta.negate = true; + parsedFilters.push(filter); + } + } + }); + + return parsedFilters; + } + + getJSON(): TypedLensByValueInput['attributes'] { + return { + title: 'Prefilled from exploratory view app', + description: '', + visualizationType: 'lnsXY', + references: [ + { + id: this.indexPattern.id!, + name: 'indexpattern-datasource-current-indexpattern', + type: 'index-pattern', + }, + { + id: this.indexPattern.id!, + name: getLayerReferenceName('layer1'), + type: 'index-pattern', + }, + ], + state: { + datasourceStates: { + indexpattern: { + layers: this.layers, + }, + }, + visualization: this.visualization, + query: { query: '', language: 'kuery' }, + filters: this.parseFilters(), + }, + }; + } +} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/logs_frequency_config.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/logs_frequency_config.ts new file mode 100644 index 00000000000000..68e5e697d2f9d1 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/logs_frequency_config.ts @@ -0,0 +1,39 @@ +/* + * 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 { DataSeries } from '../types'; +import { FieldLabels } from './constants'; + +interface Props { + seriesId: string; +} + +export function getLogsFrequencyLensConfig({ seriesId }: Props): DataSeries { + return { + id: seriesId, + reportType: 'logs-frequency', + defaultSeriesType: 'line', + seriesTypes: ['line', 'bar'], + xAxisColumn: { + sourceField: '@timestamp', + }, + yAxisColumn: { + operationType: 'count', + }, + hasMetricType: false, + defaultFilters: [], + breakdowns: ['agent.hostname'], + filters: [], + labels: { ...FieldLabels }, + reportDefinitions: [ + { + field: 'agent.hostname', + required: true, + }, + ], + }; +} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/memory_usage_config.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/memory_usage_config.ts new file mode 100644 index 00000000000000..579372ed86fa74 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/memory_usage_config.ts @@ -0,0 +1,42 @@ +/* + * 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 { DataSeries } from '../types'; +import { FieldLabels } from './constants'; +import { OperationType } from '../../../../../../lens/public'; + +interface Props { + seriesId: string; +} + +export function getMemoryUsageLensConfig({ seriesId }: Props): DataSeries { + return { + id: seriesId, + reportType: 'memory-usage', + defaultSeriesType: 'line', + seriesTypes: ['line', 'bar'], + xAxisColumn: { + sourceField: '@timestamp', + }, + yAxisColumn: { + operationType: 'avg' as OperationType, + sourceField: 'system.memory.used.pct', + label: 'Memory Usage %', + }, + hasMetricType: true, + defaultFilters: [], + breakdowns: ['host.hostname'], + filters: [], + labels: { ...FieldLabels, 'host.hostname': 'Host name' }, + reportDefinitions: [ + { + field: 'host.hostname', + required: true, + }, + ], + }; +} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/monitor_duration_config.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/monitor_duration_config.ts new file mode 100644 index 00000000000000..aa9b8b94c6d862 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/monitor_duration_config.ts @@ -0,0 +1,48 @@ +/* + * 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 { DataSeries } from '../types'; +import { FieldLabels } from './constants'; +import { OperationType } from '../../../../../../lens/public'; + +interface Props { + seriesId: string; +} + +export function getMonitorDurationConfig({ seriesId }: Props): DataSeries { + return { + id: seriesId, + reportType: 'uptime-duration', + defaultSeriesType: 'line', + seriesTypes: ['line', 'bar_stacked'], + xAxisColumn: { + sourceField: '@timestamp', + }, + yAxisColumn: { + operationType: 'avg' as OperationType, + sourceField: 'monitor.duration.us', + label: 'Monitor duration (ms)', + }, + hasMetricType: true, + defaultFilters: ['monitor.type', 'observer.geo.name', 'tags'], + breakdowns: [ + 'observer.geo.name', + 'monitor.name', + 'monitor.id', + 'monitor.type', + 'tags', + 'url.port', + ], + filters: [], + reportDefinitions: [ + { + field: 'monitor.id', + }, + ], + labels: { ...FieldLabels }, + }; +} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/monitor_pings_config.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/monitor_pings_config.ts new file mode 100644 index 00000000000000..72968626e934bf --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/monitor_pings_config.ts @@ -0,0 +1,43 @@ +/* + * 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 { DataSeries } from '../types'; +import { FieldLabels } from './constants'; + +interface Props { + seriesId: string; +} + +export function getMonitorPingsConfig({ seriesId }: Props): DataSeries { + return { + id: seriesId, + reportType: 'uptime-pings', + defaultSeriesType: 'bar_stacked', + seriesTypes: ['bar_stacked', 'bar'], + xAxisColumn: { + sourceField: '@timestamp', + }, + yAxisColumn: { + operationType: 'count', + label: 'Monitor pings', + }, + hasMetricType: false, + defaultFilters: ['observer.geo.name'], + breakdowns: ['monitor.status', 'observer.geo.name', 'monitor.type'], + filters: [], + palette: { type: 'palette', name: 'status' }, + reportDefinitions: [ + { + field: 'monitor.id', + }, + { + field: 'url.full', + }, + ], + labels: { ...FieldLabels }, + }; +} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/network_activity_config.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/network_activity_config.ts new file mode 100644 index 00000000000000..63cdd0ec8bd605 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/network_activity_config.ts @@ -0,0 +1,41 @@ +/* + * 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 { DataSeries } from '../types'; +import { FieldLabels } from './constants'; +import { OperationType } from '../../../../../../lens/public'; + +interface Props { + seriesId: string; +} + +export function getNetworkActivityLensConfig({ seriesId }: Props): DataSeries { + return { + id: seriesId, + reportType: 'network-activity', + defaultSeriesType: 'line', + seriesTypes: ['line', 'bar'], + xAxisColumn: { + sourceField: '@timestamp', + }, + yAxisColumn: { + operationType: 'avg' as OperationType, + sourceField: 'system.memory.used.pct', + }, + hasMetricType: true, + defaultFilters: [], + breakdowns: ['host.hostname'], + filters: [], + labels: { ...FieldLabels, 'host.hostname': 'Host name' }, + reportDefinitions: [ + { + field: 'host.hostname', + required: true, + }, + ], + }; +} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/performance_dist_config.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/performance_dist_config.ts new file mode 100644 index 00000000000000..41617304c9f3df --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/performance_dist_config.ts @@ -0,0 +1,86 @@ +/* + * 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 { ConfigProps, DataSeries } from '../types'; +import { FieldLabels } from './constants'; +import { buildPhraseFilter } from './utils'; +import { + CLIENT_GEO_COUNTRY_NAME, + CLS_FIELD, + FCP_FIELD, + FID_FIELD, + LCP_FIELD, + PROCESSOR_EVENT, + SERVICE_ENVIRONMENT, + SERVICE_NAME, + TBT_FIELD, + TRANSACTION_DURATION, + TRANSACTION_TYPE, + USER_AGENT_DEVICE, + USER_AGENT_NAME, + USER_AGENT_OS, + USER_AGENT_VERSION, +} from './data/elasticsearch_fieldnames'; + +export function getPerformanceDistLensConfig({ seriesId, indexPattern }: ConfigProps): DataSeries { + return { + id: seriesId ?? 'unique-key', + reportType: 'page-load-dist', + defaultSeriesType: 'line', + seriesTypes: ['line', 'bar'], + xAxisColumn: { + sourceField: 'performance.metric', + }, + yAxisColumn: { + operationType: 'count', + label: 'Pages loaded', + }, + hasMetricType: false, + defaultFilters: [ + USER_AGENT_OS, + CLIENT_GEO_COUNTRY_NAME, + USER_AGENT_DEVICE, + { + field: USER_AGENT_NAME, + nested: USER_AGENT_VERSION, + }, + ], + breakdowns: [USER_AGENT_NAME, USER_AGENT_OS, CLIENT_GEO_COUNTRY_NAME, USER_AGENT_DEVICE], + reportDefinitions: [ + { + field: SERVICE_NAME, + required: true, + }, + { + field: SERVICE_ENVIRONMENT, + }, + { + field: 'performance.metric', + custom: true, + defaultValue: TRANSACTION_DURATION, + options: [ + { label: 'Page load time', field: TRANSACTION_DURATION }, + { label: 'First contentful paint', field: FCP_FIELD }, + { label: 'Total blocking time', field: TBT_FIELD }, + // FIXME, review if we need these descriptions + { label: 'Largest contentful paint', field: LCP_FIELD, description: 'Core web vital' }, + { label: 'First input delay', field: FID_FIELD, description: 'Core web vital' }, + { label: 'Cumulative layout shift', field: CLS_FIELD, description: 'Core web vital' }, + ], + }, + ], + filters: [ + buildPhraseFilter(TRANSACTION_TYPE, 'page-load', indexPattern), + buildPhraseFilter(PROCESSOR_EVENT, 'transaction', indexPattern), + ], + labels: { + ...FieldLabels, + [SERVICE_NAME]: 'Web Application', + [TRANSACTION_DURATION]: 'Page load time', + }, + }; +} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/service_latency_config.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/service_latency_config.ts new file mode 100644 index 00000000000000..a31679c61a4aba --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/service_latency_config.ts @@ -0,0 +1,52 @@ +/* + * 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 { ConfigProps, DataSeries } from '../types'; +import { FieldLabels } from './constants'; +import { buildPhraseFilter } from './utils'; +import { OperationType } from '../../../../../../lens/public'; + +export function getServiceLatencyLensConfig({ seriesId, indexPattern }: ConfigProps): DataSeries { + return { + id: seriesId, + reportType: 'service-latency', + defaultSeriesType: 'line', + seriesTypes: ['line', 'bar'], + xAxisColumn: { + sourceField: '@timestamp', + }, + yAxisColumn: { + operationType: 'avg' as OperationType, + sourceField: 'transaction.duration.us', + label: 'Latency', + }, + hasMetricType: true, + defaultFilters: [ + 'user_agent.name', + 'user_agent.os.name', + 'client.geo.country_name', + 'user_agent.device.name', + ], + breakdowns: [ + 'user_agent.name', + 'user_agent.os.name', + 'client.geo.country_name', + 'user_agent.device.name', + ], + filters: [buildPhraseFilter('transaction.type', 'request', indexPattern)], + labels: { ...FieldLabels }, + reportDefinitions: [ + { + field: 'service.name', + required: true, + }, + { + field: 'service.environment', + }, + ], + }; +} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/service_throughput_config.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/service_throughput_config.ts new file mode 100644 index 00000000000000..32cae2167ddf02 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/service_throughput_config.ts @@ -0,0 +1,55 @@ +/* + * 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 { ConfigProps, DataSeries } from '../types'; +import { FieldLabels } from './constants'; +import { buildPhraseFilter } from './utils'; +import { OperationType } from '../../../../../../lens/public'; + +export function getServiceThroughputLensConfig({ + seriesId, + indexPattern, +}: ConfigProps): DataSeries { + return { + id: seriesId, + reportType: 'service-latency', + defaultSeriesType: 'line', + seriesTypes: ['line', 'bar'], + xAxisColumn: { + sourceField: '@timestamp', + }, + yAxisColumn: { + operationType: 'avg' as OperationType, + sourceField: 'transaction.duration.us', + label: 'Throughput', + }, + hasMetricType: true, + defaultFilters: [ + 'user_agent.name', + 'user_agent.os.name', + 'client.geo.country_name', + 'user_agent.device.name', + ], + breakdowns: [ + 'user_agent.name', + 'user_agent.os.name', + 'client.geo.country_name', + 'user_agent.device.name', + ], + filters: [buildPhraseFilter('transaction.type', 'request', indexPattern)], + labels: { ...FieldLabels }, + reportDefinitions: [ + { + field: 'service.name', + required: true, + }, + { + field: 'service.environment', + }, + ], + }; +} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/url_constants.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/url_constants.ts new file mode 100644 index 00000000000000..5b99c19dbabb7d --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/url_constants.ts @@ -0,0 +1,15 @@ +/* + * 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 enum URL_KEYS { + METRIC_TYPE = 'mt', + REPORT_TYPE = 'rt', + SERIES_TYPE = 'st', + BREAK_DOWN = 'bd', + FILTERS = 'ft', + REPORT_DEFINITIONS = 'rdf', +} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts new file mode 100644 index 00000000000000..38b8ce81b2acd6 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/utils.ts @@ -0,0 +1,54 @@ +/* + * 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 rison, { RisonValue } from 'rison-node'; +import type { AllSeries, AllShortSeries } from '../hooks/use_url_strorage'; +import type { SeriesUrl } from '../types'; +import { IIndexPattern } from '../../../../../../../../src/plugins/data/common/index_patterns'; +import { esFilters } from '../../../../../../../../src/plugins/data/public'; +import { URL_KEYS } from './url_constants'; + +export function convertToShortUrl(series: SeriesUrl) { + const { + metric, + seriesType, + reportType, + breakdown, + filters, + reportDefinitions, + ...restSeries + } = series; + + return { + [URL_KEYS.METRIC_TYPE]: metric, + [URL_KEYS.REPORT_TYPE]: reportType, + [URL_KEYS.SERIES_TYPE]: seriesType, + [URL_KEYS.BREAK_DOWN]: breakdown, + [URL_KEYS.FILTERS]: filters, + [URL_KEYS.REPORT_DEFINITIONS]: reportDefinitions, + ...restSeries, + }; +} + +export function createExploratoryViewUrl(allSeries: AllSeries, baseHref = '') { + const allSeriesIds = Object.keys(allSeries); + + const allShortSeries: AllShortSeries = {}; + + allSeriesIds.forEach((seriesKey) => { + allShortSeries[seriesKey] = convertToShortUrl(allSeries[seriesKey]); + }); + + return ( + baseHref + + `/app/observability/exploratory-view#?sr=${rison.encode(allShortSeries as RisonValue)}` + ); +} + +export function buildPhraseFilter(field: string, value: any, indexPattern: IIndexPattern) { + const fieldMeta = indexPattern.fields.find((fieldT) => fieldT.name === field)!; + return esFilters.buildPhraseFilter(fieldMeta, value, indexPattern); +} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.test.tsx new file mode 100644 index 00000000000000..7e99874f557b30 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.test.tsx @@ -0,0 +1,93 @@ +/* + * 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 { within } from '@testing-library/react'; +import { fireEvent, screen, waitFor } from '@testing-library/dom'; +import { render, mockUrlStorage, mockCore } from './rtl_helpers'; +import { ExploratoryView } from './exploratory_view'; +import { getStubIndexPattern } from '../../../../../../../src/plugins/data/public/test_utils'; +import * as obsvInd from '../../../utils/observability_index_patterns'; + +describe('ExploratoryView', () => { + beforeEach(() => { + const indexPattern = getStubIndexPattern( + 'apm-*', + () => {}, + '@timestamp', + [ + { + name: '@timestamp', + type: 'date', + esTypes: ['date'], + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + ], + mockCore() as any + ); + + jest.spyOn(obsvInd, 'ObservabilityIndexPatterns').mockReturnValue({ + getIndexPattern: jest.fn().mockReturnValue(indexPattern), + } as any); + }); + + it('renders exploratory view', async () => { + render(); + + await waitFor(() => { + screen.getByText(/open in lens/i); + screen.getByRole('heading', { name: /exploratory view/i }); + screen.getByRole('img', { name: /visulization/i }); + screen.getByText(/add series/i); + screen.getByText(/no series found, please add a series\./i); + }); + }); + + it('can add, cancel new series', async () => { + render(); + + await fireEvent.click(screen.getByText(/add series/i)); + + await waitFor(() => { + screen.getByText(/open in lens/i); + screen.getByText(/select a data type to start building a series\./i); + screen.getByRole('table', { name: /this table contains 1 rows\./i }); + const button = screen.getByRole('button', { name: /add/i }); + within(button).getByText(/add/i); + }); + + await fireEvent.click(screen.getByText(/cancel/i)); + + await waitFor(() => { + screen.getByText(/add series/i); + }); + }); + + it('renders lens component when there is series', async () => { + mockUrlStorage({ + data: { + 'uptime-pings-histogram': { + reportType: 'upp', + breakdown: 'monitor.status', + time: { from: 'now-15m', to: 'now' }, + }, + }, + }); + + render(); + + await waitFor(() => { + screen.getByText(/open in lens/i); + screen.getByRole('heading', { name: /uptime pings/i }); + screen.getByText(/uptime-pings-histogram/i); + screen.getByText(/Lens Embeddable Component/i); + screen.getByRole('table', { name: /this table contains 1 rows\./i }); + }); + }); +}); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.tsx new file mode 100644 index 00000000000000..b3ad107bbe0e2f --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.tsx @@ -0,0 +1,87 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import React, { useEffect, useState } from 'react'; +import styled from 'styled-components'; +import { EuiLoadingSpinner, EuiPanel, EuiTitle } from '@elastic/eui'; +import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; +import { ObservabilityPublicPluginsStart } from '../../../plugin'; +import { ExploratoryViewHeader } from './header/header'; +import { SeriesEditor } from './series_editor/series_editor'; +import { useUrlStorage } from './hooks/use_url_strorage'; +import { useLensAttributes } from './hooks/use_lens_attributes'; +import { EmptyView } from './components/empty_view'; +import { useIndexPatternContext } from './hooks/use_default_index_pattern'; +import { TypedLensByValueInput } from '../../../../../lens/public'; + +export function ExploratoryView() { + const { + services: { lens }, + } = useKibana(); + + const [lensAttributes, setLensAttributes] = useState( + null + ); + + const { indexPattern } = useIndexPatternContext(); + + const LensComponent = lens?.EmbeddableComponent; + + const { firstSeriesId: seriesId, firstSeries: series } = useUrlStorage(); + + const lensAttributesT = useLensAttributes({ + seriesId, + indexPattern, + }); + + useEffect(() => { + setLensAttributes(lensAttributesT); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [JSON.stringify(lensAttributesT ?? {}), series?.reportType, series?.time?.from]); + + return ( + + {lens ? ( + <> + + {!indexPattern && ( + + + + )} + {lensAttributes && seriesId && series?.reportType && series?.time ? ( + + ) : ( + + )} + + + ) : ( + +

+ {i18n.translate('xpack.observability.overview.exploratoryView.lensDisabled', { + defaultMessage: + 'Lens app is not available, please enable Lens to use exploratory view.', + })} +

+
+ )} +
+ ); +} + +const SpinnerWrap = styled.div` + height: 100vh; + display: flex; + justify-content: center; + align-items: center; +`; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/header/header.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/header/header.test.tsx new file mode 100644 index 00000000000000..de6912f256be7c --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/header/header.test.tsx @@ -0,0 +1,53 @@ +/* + * 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 { mockUrlStorage, render } from '../rtl_helpers'; +import { ExploratoryViewHeader } from './header'; +import { fireEvent } from '@testing-library/dom'; + +describe('ExploratoryViewHeader', function () { + it('should render properly', function () { + const { getByText } = render( + + ); + getByText('Open in Lens'); + }); + + it('should be able to click open in lens', function () { + mockUrlStorage({ + data: { + 'uptime-pings-histogram': { + reportType: 'upp', + breakdown: 'monitor.status', + time: { from: 'now-15m', to: 'now' }, + }, + }, + }); + + const { getByText, core } = render( + + ); + fireEvent.click(getByText('Open in Lens')); + + expect(core?.lens?.navigateToPrefilledEditor).toHaveBeenCalledTimes(1); + expect(core?.lens?.navigateToPrefilledEditor).toHaveBeenCalledWith({ + attributes: { title: 'Performance distribution' }, + id: '', + timeRange: { + from: 'now-15m', + to: 'now', + }, + }); + }); +}); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/header/header.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/header/header.tsx new file mode 100644 index 00000000000000..bda3566c766021 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/header/header.tsx @@ -0,0 +1,63 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; +import { TypedLensByValueInput } from '../../../../../../lens/public'; +import { useKibana } from '../../../../../../../../src/plugins/kibana_react/public'; +import { ObservabilityPublicPluginsStart } from '../../../../plugin'; +import { DataViewLabels } from '../configurations/constants'; +import { useUrlStorage } from '../hooks/use_url_strorage'; + +interface Props { + seriesId: string; + lensAttributes: TypedLensByValueInput['attributes'] | null; +} + +export function ExploratoryViewHeader({ seriesId, lensAttributes }: Props) { + const { + services: { lens }, + } = useKibana(); + + const { series } = useUrlStorage(seriesId); + + return ( + + + +

+ {DataViewLabels[series.reportType] ?? + i18n.translate('xpack.observability.expView.heading.label', { + defaultMessage: 'Exploratory view', + })} +

+
+
+ + { + if (lensAttributes) { + lens.navigateToPrefilledEditor({ + id: '', + timeRange: series.time, + attributes: lensAttributes, + }); + } + }} + > + {i18n.translate('xpack.observability.expView.heading.openInLens', { + defaultMessage: 'Open in Lens', + })} + + +
+ ); +} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_default_index_pattern.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_default_index_pattern.tsx new file mode 100644 index 00000000000000..04cbb4a4ddb18d --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_default_index_pattern.tsx @@ -0,0 +1,61 @@ +/* + * 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, { createContext, useContext, Context, useState, useEffect } from 'react'; +import { IndexPattern } from '../../../../../../../../src/plugins/data/common'; +import { AppDataType } from '../types'; +import { useKibana } from '../../../../../../../../src/plugins/kibana_react/public'; +import { ObservabilityPublicPluginsStart } from '../../../../plugin'; +import { ObservabilityIndexPatterns } from '../../../../utils/observability_index_patterns'; + +export interface IIndexPatternContext { + indexPattern: IndexPattern; + loadIndexPattern: (dataType: AppDataType) => void; +} + +export const IndexPatternContext = createContext>({}); + +interface ProviderProps { + indexPattern?: IndexPattern; + children: JSX.Element; +} + +export function IndexPatternContextProvider({ + children, + indexPattern: initialIndexPattern, +}: ProviderProps) { + const [indexPattern, setIndexPattern] = useState(initialIndexPattern); + + useEffect(() => { + setIndexPattern(initialIndexPattern); + }, [initialIndexPattern]); + + const { + services: { data }, + } = useKibana(); + + const loadIndexPattern = async (dataType: AppDataType) => { + const obsvIndexP = new ObservabilityIndexPatterns(data); + const indPattern = await obsvIndexP.getIndexPattern(dataType); + setIndexPattern(indPattern!); + }; + + return ( + + {children} + + ); +} + +export const useIndexPatternContext = () => { + return useContext((IndexPatternContext as unknown) as Context); +}; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_init_exploratory_view.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_init_exploratory_view.ts new file mode 100644 index 00000000000000..9f462790e8d37f --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_init_exploratory_view.ts @@ -0,0 +1,44 @@ +/* + * 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 { useFetcher } from '../../../..'; +import { IKbnUrlStateStorage } from '../../../../../../../../src/plugins/kibana_utils/public'; +import { useKibana } from '../../../../../../../../src/plugins/kibana_react/public'; +import { ObservabilityPublicPluginsStart } from '../../../../plugin'; +import { AllShortSeries } from './use_url_strorage'; +import { ReportToDataTypeMap } from '../configurations/constants'; +import { + DataType, + ObservabilityIndexPatterns, +} from '../../../../utils/observability_index_patterns'; + +export const useInitExploratoryView = (storage: IKbnUrlStateStorage) => { + const { + services: { data }, + } = useKibana(); + + const allSeriesKey = 'sr'; + + const allSeries = storage.get(allSeriesKey) ?? {}; + + const allSeriesIds = Object.keys(allSeries); + + const firstSeriesId = allSeriesIds?.[0]; + + const firstSeries = allSeries[firstSeriesId]; + + const { data: indexPattern } = useFetcher(() => { + const obsvIndexP = new ObservabilityIndexPatterns(data); + let reportType: DataType = 'apm'; + if (firstSeries?.rt) { + reportType = ReportToDataTypeMap[firstSeries?.rt]; + } + + return obsvIndexP.getIndexPattern(reportType); + }, [firstSeries?.rt, data]); + + return indexPattern; +}; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_lens_attributes.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_lens_attributes.ts new file mode 100644 index 00000000000000..1c735009f66f9d --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_lens_attributes.ts @@ -0,0 +1,88 @@ +/* + * 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 { useMemo } from 'react'; +import { TypedLensByValueInput } from '../../../../../../lens/public'; +import { LensAttributes } from '../configurations/lens_attributes'; +import { useUrlStorage } from './use_url_strorage'; +import { getDefaultConfigs } from '../configurations/default_configs'; + +import { IndexPattern } from '../../../../../../../../src/plugins/data/common'; +import { DataSeries, SeriesUrl, UrlFilter } from '../types'; + +interface Props { + seriesId: string; + indexPattern?: IndexPattern | null; +} + +export const getFiltersFromDefs = ( + reportDefinitions: SeriesUrl['reportDefinitions'], + dataViewConfig: DataSeries +) => { + const rdfFilters = Object.entries(reportDefinitions ?? {}).map(([field, value]) => { + return { + field, + values: [value], + }; + }) as UrlFilter[]; + + // let's filter out custom fields + return rdfFilters.filter(({ field }) => { + const rdf = dataViewConfig.reportDefinitions.find(({ field: fd }) => field === fd); + return !rdf?.custom; + }); +}; + +export const useLensAttributes = ({ + seriesId, + indexPattern, +}: Props): TypedLensByValueInput['attributes'] | null => { + const { series } = useUrlStorage(seriesId); + + const { breakdown, seriesType, metric: metricType, reportType, reportDefinitions = {} } = + series ?? {}; + + return useMemo(() => { + if (!indexPattern || !reportType) { + return null; + } + + const dataViewConfig = getDefaultConfigs({ + seriesId, + reportType, + indexPattern, + }); + + const filters: UrlFilter[] = (series.filters ?? []).concat( + getFiltersFromDefs(reportDefinitions, dataViewConfig) + ); + + const lensAttributes = new LensAttributes( + indexPattern, + dataViewConfig, + seriesType, + filters, + metricType, + reportDefinitions + ); + + if (breakdown) { + lensAttributes.addBreakdown(breakdown); + } + + return lensAttributes.getJSON(); + }, [ + indexPattern, + breakdown, + seriesType, + metricType, + reportType, + reportDefinitions, + seriesId, + series.filters, + ]); +}; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_series_filters.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_series_filters.ts new file mode 100644 index 00000000000000..35247180c2ee5b --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_series_filters.ts @@ -0,0 +1,100 @@ +/* + * 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 { useUrlStorage } from './use_url_strorage'; +import { UrlFilter } from '../types'; + +export interface UpdateFilter { + field: string; + value: string; + negate?: boolean; +} + +export const useSeriesFilters = ({ seriesId }: { seriesId: string }) => { + const { series, setSeries } = useUrlStorage(seriesId); + + const filters = series.filters ?? []; + + const removeFilter = ({ field, value, negate }: UpdateFilter) => { + const filtersN = filters.map((filter) => { + if (filter.field === field) { + if (negate) { + const notValuesN = filter.notValues?.filter((val) => val !== value); + return { ...filter, notValues: notValuesN }; + } else { + const valuesN = filter.values?.filter((val) => val !== value); + return { ...filter, values: valuesN }; + } + } + + return filter; + }); + setSeries(seriesId, { ...series, filters: filtersN }); + }; + + const addFilter = ({ field, value, negate }: UpdateFilter) => { + const currFilter: UrlFilter = { field }; + if (negate) { + currFilter.notValues = [value]; + } else { + currFilter.values = [value]; + } + if (filters.length === 0) { + setSeries(seriesId, { ...series, filters: [currFilter] }); + } else { + setSeries(seriesId, { + ...series, + filters: [currFilter, ...filters.filter((ft) => ft.field !== field)], + }); + } + }; + + const updateFilter = ({ field, value, negate }: UpdateFilter) => { + const currFilter: UrlFilter | undefined = filters.find(({ field: fd }) => field === fd) ?? { + field, + }; + + const currNotValues = currFilter.notValues ?? []; + const currValues = currFilter.values ?? []; + + const notValues = currNotValues.filter((val) => val !== value); + const values = currValues.filter((val) => val !== value); + + if (negate) { + notValues.push(value); + } else { + values.push(value); + } + + currFilter.notValues = notValues.length > 0 ? notValues : undefined; + currFilter.values = values.length > 0 ? values : undefined; + + const otherFilters = filters.filter(({ field: fd }) => fd !== field); + + if (notValues.length > 0 || values.length > 0) { + setSeries(seriesId, { ...series, filters: [...otherFilters, currFilter] }); + } else { + setSeries(seriesId, { ...series, filters: otherFilters }); + } + }; + + const setFilter = ({ field, value, negate }: UpdateFilter) => { + const currFilter: UrlFilter | undefined = filters.find(({ field: fd }) => field === fd); + + if (!currFilter) { + addFilter({ field, value, negate }); + } else { + updateFilter({ field, value, negate }); + } + }; + + const invertFilter = ({ field, value, negate }: UpdateFilter) => { + updateFilter({ field, value, negate: !negate }); + }; + + return { invertFilter, setFilter, removeFilter }; +}; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_url_strorage.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_url_strorage.tsx new file mode 100644 index 00000000000000..d38429703b7099 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_url_strorage.tsx @@ -0,0 +1,103 @@ +/* + * 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, { createContext, useContext, Context } from 'react'; +import { IKbnUrlStateStorage } from '../../../../../../../../src/plugins/kibana_utils/public'; +import type { AppDataType, ReportViewTypeId, SeriesUrl, UrlFilter } from '../types'; +import { convertToShortUrl } from '../configurations/utils'; +import { OperationType, SeriesType } from '../../../../../../lens/public'; +import { URL_KEYS } from '../configurations/url_constants'; + +export const UrlStorageContext = createContext(null); + +interface ProviderProps { + storage: IKbnUrlStateStorage; +} + +export function UrlStorageContextProvider({ + children, + storage, +}: ProviderProps & { children: JSX.Element }) { + return {children}; +} + +function convertFromShortUrl(newValue: ShortUrlSeries): SeriesUrl { + const { mt, st, rt, bd, ft, time, rdf, ...restSeries } = newValue; + return { + metric: mt, + reportType: rt!, + seriesType: st, + breakdown: bd, + filters: ft!, + time: time!, + reportDefinitions: rdf, + ...restSeries, + }; +} + +interface ShortUrlSeries { + [URL_KEYS.METRIC_TYPE]?: OperationType; + [URL_KEYS.REPORT_TYPE]?: ReportViewTypeId; + [URL_KEYS.SERIES_TYPE]?: SeriesType; + [URL_KEYS.BREAK_DOWN]?: string; + [URL_KEYS.FILTERS]?: UrlFilter[]; + [URL_KEYS.REPORT_DEFINITIONS]?: Record; + time?: { + to: string; + from: string; + }; + dataType?: AppDataType; +} + +export type AllShortSeries = Record; +export type AllSeries = Record; + +export const NEW_SERIES_KEY = 'newSeriesKey'; + +export function useUrlStorage(seriesId?: string) { + const allSeriesKey = 'sr'; + const storage = useContext((UrlStorageContext as unknown) as Context); + let series: SeriesUrl = {} as SeriesUrl; + const allShortSeries = storage.get(allSeriesKey) ?? {}; + + const allSeriesIds = Object.keys(allShortSeries); + + const allSeries: AllSeries = {}; + + allSeriesIds.forEach((seriesKey) => { + allSeries[seriesKey] = convertFromShortUrl(allShortSeries[seriesKey]); + }); + + if (seriesId) { + series = allSeries?.[seriesId] ?? ({} as SeriesUrl); + } + + const setSeries = async (seriesIdN: string, newValue: SeriesUrl) => { + allShortSeries[seriesIdN] = convertToShortUrl(newValue); + allSeries[seriesIdN] = newValue; + return storage.set(allSeriesKey, allShortSeries); + }; + + const removeSeries = (seriesIdN: string) => { + delete allShortSeries[seriesIdN]; + delete allSeries[seriesIdN]; + storage.set(allSeriesKey, allShortSeries); + }; + + const firstSeriesId = allSeriesIds?.[0]; + + return { + storage, + setSeries, + removeSeries, + series, + firstSeriesId, + allSeries, + allSeriesIds, + firstSeries: allSeries?.[firstSeriesId], + }; +} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/index.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/index.tsx new file mode 100644 index 00000000000000..dc47a0f075fe69 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/index.tsx @@ -0,0 +1,64 @@ +/* + * 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, { useContext } from 'react'; +import { i18n } from '@kbn/i18n'; +import { useHistory } from 'react-router-dom'; +import { ThemeContext } from 'styled-components'; +import { ExploratoryView } from './exploratory_view'; +import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; +import { ObservabilityPublicPluginsStart } from '../../../plugin'; +import { useBreadcrumbs } from '../../../hooks/use_breadcrumbs'; +import { IndexPatternContextProvider } from './hooks/use_default_index_pattern'; +import { + createKbnUrlStateStorage, + withNotifyOnErrors, +} from '../../../../../../../src/plugins/kibana_utils/public/'; +import { UrlStorageContextProvider } from './hooks/use_url_strorage'; +import { useInitExploratoryView } from './hooks/use_init_exploratory_view'; +import { WithHeaderLayout } from '../../app/layout/with_header'; + +export function ExploratoryViewPage() { + useBreadcrumbs([ + { + text: i18n.translate('xpack.observability.overview.exploratoryView', { + defaultMessage: 'Exploratory view', + }), + }, + ]); + + const theme = useContext(ThemeContext); + + const { + services: { uiSettings, notifications }, + } = useKibana(); + + const history = useHistory(); + + const kbnUrlStateStorage = createKbnUrlStateStorage({ + history, + useHash: uiSettings!.get('state:storeInSessionStorage'), + ...withNotifyOnErrors(notifications!.toasts), + }); + + const indexPattern = useInitExploratoryView(kbnUrlStateStorage); + + return ( + + {indexPattern ? ( + + + + + + ) : null} + + ); +} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/rtl_helpers.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/rtl_helpers.tsx new file mode 100644 index 00000000000000..112bfcc3ccb580 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/rtl_helpers.tsx @@ -0,0 +1,318 @@ +/* + * 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 { of } from 'rxjs'; +import React, { ReactElement } from 'react'; +import { stringify } from 'query-string'; +// eslint-disable-next-line import/no-extraneous-dependencies +import { render as reactTestLibRender, RenderOptions } from '@testing-library/react'; +import { Router } from 'react-router-dom'; +import { createMemoryHistory, History } from 'history'; +import { CoreStart } from 'kibana/public'; +import { I18nProvider } from '@kbn/i18n/react'; +import { coreMock } from 'src/core/public/mocks'; +import { + KibanaServices, + KibanaContextProvider, +} from '../../../../../../../src/plugins/kibana_react/public'; +import { ObservabilityPublicPluginsStart } from '../../../plugin'; +import { EuiThemeProvider } from '../../../../../../../src/plugins/kibana_react/common'; +import { lensPluginMock } from '../../../../../lens/public/mocks'; +import { IndexPatternContextProvider } from './hooks/use_default_index_pattern'; +import { AllSeries, UrlStorageContextProvider } from './hooks/use_url_strorage'; +import { + withNotifyOnErrors, + createKbnUrlStateStorage, +} from '../../../../../../../src/plugins/kibana_utils/public'; +import * as fetcherHook from '../../../hooks/use_fetcher'; +import * as useUrlHook from './hooks/use_url_strorage'; +import * as useSeriesFilterHook from './hooks/use_series_filters'; +import * as useHasDataHook from '../../../hooks/use_has_data'; +import * as useValuesListHook from '../../../hooks/use_values_list'; + +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { getStubIndexPattern } from '../../../../../../../src/plugins/data/public/index_patterns/index_pattern.stub'; +import indexPatternData from './configurations/data/test_index_pattern.json'; + +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { setIndexPatterns } from '../../../../../../../src/plugins/data/public/services'; +import { IndexPatternsContract } from '../../../../../../../src/plugins/data/common/index_patterns/index_patterns'; +import { UrlFilter } from './types'; +import { dataPluginMock } from '../../../../../../../src/plugins/data/public/mocks'; + +interface KibanaProps { + services?: KibanaServices; +} + +export interface KibanaProviderOptions { + core?: ExtraCore & Partial; + kibanaProps?: KibanaProps; +} + +interface MockKibanaProviderProps> + extends KibanaProviderOptions { + children: ReactElement; + history: History; +} + +type MockRouterProps> = MockKibanaProviderProps; + +type Url = + | string + | { + path: string; + queryParams: Record; + }; + +interface RenderRouterOptions extends KibanaProviderOptions { + history?: History; + renderOptions?: Omit; + url?: Url; +} + +function getSetting(key: string): T { + if (key === 'timepicker:quickRanges') { + return ([ + { + display: 'Today', + from: 'now/d', + to: 'now/d', + }, + ] as unknown) as T; + } + return ('MMM D, YYYY @ HH:mm:ss.SSS' as unknown) as T; +} + +function setSetting$(key: string): T { + return (of('MMM D, YYYY @ HH:mm:ss.SSS') as unknown) as T; +} + +/* default mock core */ +const defaultCore = coreMock.createStart(); +export const mockCore: () => Partial = () => { + const core: Partial = { + ...defaultCore, + application: { + ...defaultCore.application, + getUrlForApp: () => '/app/observability', + navigateToUrl: jest.fn(), + capabilities: { + ...defaultCore.application.capabilities, + observability: { + 'alerting:save': true, + configureSettings: true, + save: true, + show: true, + }, + }, + }, + uiSettings: { + ...defaultCore.uiSettings, + get: getSetting, + get$: setSetting$, + }, + lens: lensPluginMock.createStartContract(), + data: dataPluginMock.createStartContract(), + }; + + return core; +}; + +/* Mock Provider Components */ +export function MockKibanaProvider>({ + children, + core, + history, + kibanaProps, +}: MockKibanaProviderProps) { + const { notifications } = core!; + + const kbnUrlStateStorage = createKbnUrlStateStorage({ + history, + useHash: false, + ...withNotifyOnErrors(notifications!.toasts), + }); + + const indexPattern = mockIndexPattern; + + setIndexPatterns(({ + ...[indexPattern], + get: async () => indexPattern, + } as unknown) as IndexPatternsContract); + + return ( + + + + + + {children} + + + + + + ); +} + +export function MockRouter({ + children, + core, + history = createMemoryHistory(), + kibanaProps, +}: MockRouterProps) { + return ( + + + {children} + + + ); +} + +/* Custom react testing library render */ +export function render( + ui: ReactElement, + { + history = createMemoryHistory(), + core: customCore, + kibanaProps, + renderOptions, + url, + }: RenderRouterOptions = {} +) { + if (url) { + history = getHistoryFromUrl(url); + } + + const core = { + ...mockCore(), + ...customCore, + }; + + return { + ...reactTestLibRender( + + {ui} + , + renderOptions + ), + history, + core, + }; +} + +const getHistoryFromUrl = (url: Url) => { + if (typeof url === 'string') { + return createMemoryHistory({ + initialEntries: [url], + }); + } + + return createMemoryHistory({ + initialEntries: [url.path + stringify(url.queryParams)], + }); +}; + +export const mockFetcher = (data: any) => { + return jest.spyOn(fetcherHook, 'useFetcher').mockReturnValue({ + data, + status: fetcherHook.FETCH_STATUS.SUCCESS, + refetch: jest.fn(), + }); +}; + +export const mockUseHasData = () => { + const onRefreshTimeRange = jest.fn(); + const spy = jest.spyOn(useHasDataHook, 'useHasData').mockReturnValue({ + onRefreshTimeRange, + } as any); + return { spy, onRefreshTimeRange }; +}; + +export const mockUseValuesList = (values?: string[]) => { + const onRefreshTimeRange = jest.fn(); + const spy = jest.spyOn(useValuesListHook, 'useValuesList').mockReturnValue({ + values: values ?? [], + } as any); + return { spy, onRefreshTimeRange }; +}; + +export const mockUrlStorage = ({ + data, + filters, + breakdown, +}: { + data?: AllSeries; + filters?: UrlFilter[]; + breakdown?: string; +}) => { + const mockDataSeries = data || { + 'performance-distribution': { + reportType: 'pld', + breakdown: breakdown || 'user_agent.name', + time: { from: 'now-15m', to: 'now' }, + ...(filters ? { filters } : {}), + }, + }; + const allSeriesIds = Object.keys(mockDataSeries); + const firstSeriesId = allSeriesIds?.[0]; + + const series = mockDataSeries[firstSeriesId]; + + const removeSeries = jest.fn(); + const setSeries = jest.fn(); + + const spy = jest.spyOn(useUrlHook, 'useUrlStorage').mockReturnValue({ + firstSeriesId, + allSeriesIds, + removeSeries, + setSeries, + series, + firstSeries: mockDataSeries[firstSeriesId], + allSeries: mockDataSeries, + } as any); + + return { spy, removeSeries, setSeries }; +}; + +export function mockUseSeriesFilter() { + const removeFilter = jest.fn(); + const invertFilter = jest.fn(); + const setFilter = jest.fn(); + const spy = jest.spyOn(useSeriesFilterHook, 'useSeriesFilters').mockReturnValue({ + removeFilter, + invertFilter, + setFilter, + }); + + return { + spy, + removeFilter, + invertFilter, + setFilter, + }; +} + +const hist = createMemoryHistory(); +export const mockHistory = { + ...hist, + createHref: jest.fn(({ pathname }) => `/observability${pathname}`), + push: jest.fn(), + location: { + ...hist.location, + pathname: '/current-path', + }, +}; + +export const mockIndexPattern = getStubIndexPattern( + 'apm-*', + () => {}, + '@timestamp', + JSON.parse(indexPatternData.attributes.fields), + mockCore() as any +); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/data_types_col.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/data_types_col.test.tsx new file mode 100644 index 00000000000000..d33d8515d3bee0 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/data_types_col.test.tsx @@ -0,0 +1,59 @@ +/* + * 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 { fireEvent, screen } from '@testing-library/react'; +import { mockUrlStorage, render } from '../../rtl_helpers'; +import { dataTypes, DataTypesCol } from './data_types_col'; +import { NEW_SERIES_KEY } from '../../hooks/use_url_strorage'; + +describe('DataTypesCol', function () { + it('should render properly', function () { + const { getByText } = render(); + + dataTypes.forEach(({ label }) => { + getByText(label); + }); + }); + + it('should set series on change', function () { + const { setSeries } = mockUrlStorage({}); + + render(); + + fireEvent.click(screen.getByText(/user experience\(rum\)/i)); + + expect(setSeries).toHaveBeenCalledTimes(1); + expect(setSeries).toHaveBeenCalledWith('newSeriesKey', { dataType: 'rum' }); + }); + + it('should set series on change on already selected', function () { + const { setSeries } = mockUrlStorage({ + data: { + [NEW_SERIES_KEY]: { + dataType: 'synthetics', + reportType: 'upp', + breakdown: 'monitor.status', + time: { from: 'now-15m', to: 'now' }, + }, + }, + }); + + render(); + + const button = screen.getByRole('button', { + name: /Synthetic Monitoring/i, + }); + + expect(button.classList).toContain('euiButton--fill'); + + fireEvent.click(button); + + // undefined on click selected + expect(setSeries).toHaveBeenCalledWith('newSeriesKey', { dataType: undefined }); + }); +}); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/data_types_col.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/data_types_col.tsx new file mode 100644 index 00000000000000..7ea44e66a721af --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/data_types_col.tsx @@ -0,0 +1,56 @@ +/* + * 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 { EuiButton, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { AppDataType } from '../../types'; +import { useIndexPatternContext } from '../../hooks/use_default_index_pattern'; +import { NEW_SERIES_KEY, useUrlStorage } from '../../hooks/use_url_strorage'; + +export const dataTypes: Array<{ id: AppDataType; label: string }> = [ + { id: 'synthetics', label: 'Synthetic Monitoring' }, + { id: 'rum', label: 'User Experience(RUM)' }, + { id: 'logs', label: 'Logs' }, + { id: 'metrics', label: 'Metrics' }, + { id: 'apm', label: 'APM' }, +]; + +export function DataTypesCol() { + const { series, setSeries } = useUrlStorage(NEW_SERIES_KEY); + + const { loadIndexPattern } = useIndexPatternContext(); + + const onDataTypeChange = (dataType?: AppDataType) => { + if (dataType) { + loadIndexPattern(dataType); + } + setSeries(NEW_SERIES_KEY, { dataType } as any); + }; + + const selectedDataType = series.dataType; + + return ( + + {dataTypes.map(({ id: dataTypeId, label }) => ( + + { + onDataTypeChange(dataTypeId === selectedDataType ? undefined : dataTypeId); + }} + > + {label} + + + ))} + + ); +} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_breakdowns.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_breakdowns.test.tsx new file mode 100644 index 00000000000000..dba660fff9c363 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_breakdowns.test.tsx @@ -0,0 +1,75 @@ +/* + * 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 { fireEvent, screen } from '@testing-library/react'; +import { render } from '../../../../../utils/test_helper'; +import { getDefaultConfigs } from '../../configurations/default_configs'; +import { mockIndexPattern, mockUrlStorage } from '../../rtl_helpers'; +import { NEW_SERIES_KEY } from '../../hooks/use_url_strorage'; +import { ReportBreakdowns } from './report_breakdowns'; +import { USER_AGENT_OS } from '../../configurations/data/elasticsearch_fieldnames'; + +describe('Series Builder ReportBreakdowns', function () { + const dataViewSeries = getDefaultConfigs({ + reportType: 'pld', + indexPattern: mockIndexPattern, + seriesId: NEW_SERIES_KEY, + }); + + it('should render properly', function () { + mockUrlStorage({}); + + render(); + + screen.getByText('Select an option: , is selected'); + screen.getAllByText('Browser family'); + }); + + it('should set new series breakdown on change', function () { + const { setSeries } = mockUrlStorage({}); + + render(); + + const btn = screen.getByRole('button', { + name: /select an option: Browser family , is selected/i, + hidden: true, + }); + + fireEvent.click(btn); + + fireEvent.click(screen.getByText(/operating system/i)); + + expect(setSeries).toHaveBeenCalledTimes(1); + expect(setSeries).toHaveBeenCalledWith('newSeriesKey', { + breakdown: USER_AGENT_OS, + reportType: 'pld', + time: { from: 'now-15m', to: 'now' }, + }); + }); + it('should set undefined on new series on no select breakdown', function () { + const { setSeries } = mockUrlStorage({}); + + render(); + + const btn = screen.getByRole('button', { + name: /select an option: Browser family , is selected/i, + hidden: true, + }); + + fireEvent.click(btn); + + fireEvent.click(screen.getByText(/no breakdown/i)); + + expect(setSeries).toHaveBeenCalledTimes(1); + expect(setSeries).toHaveBeenCalledWith('newSeriesKey', { + breakdown: undefined, + reportType: 'pld', + time: { from: 'now-15m', to: 'now' }, + }); + }); +}); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_breakdowns.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_breakdowns.tsx new file mode 100644 index 00000000000000..7667cea417a52a --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_breakdowns.tsx @@ -0,0 +1,15 @@ +/* + * 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 { Breakdowns } from '../../series_editor/columns/breakdowns'; +import { NEW_SERIES_KEY } from '../../hooks/use_url_strorage'; +import { DataSeries } from '../../types'; + +export function ReportBreakdowns({ dataViewSeries }: { dataViewSeries: DataSeries }) { + return ; +} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_definition_col.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_definition_col.test.tsx new file mode 100644 index 00000000000000..2fda5811541660 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_definition_col.test.tsx @@ -0,0 +1,75 @@ +/* + * 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 { fireEvent, screen } from '@testing-library/react'; +import { getDefaultConfigs } from '../../configurations/default_configs'; +import { mockIndexPattern, mockUrlStorage, mockUseValuesList, render } from '../../rtl_helpers'; +import { NEW_SERIES_KEY } from '../../hooks/use_url_strorage'; +import { ReportDefinitionCol } from './report_definition_col'; +import { SERVICE_NAME } from '../../configurations/data/elasticsearch_fieldnames'; + +describe('Series Builder ReportDefinitionCol', function () { + const dataViewSeries = getDefaultConfigs({ + reportType: 'pld', + indexPattern: mockIndexPattern, + seriesId: NEW_SERIES_KEY, + }); + + const { setSeries } = mockUrlStorage({ + data: { + 'performance-dist': { + dataType: 'rum', + reportType: 'pld', + time: { from: 'now-30d', to: 'now' }, + reportDefinitions: { [SERVICE_NAME]: 'elastic-co' }, + }, + }, + }); + + it('should render properly', async function () { + render(); + + screen.getByText('Web Application'); + screen.getByText('Environment'); + screen.getByText('Select an option: Page load time, is selected'); + screen.getByText('Page load time'); + }); + + it('should render selected report definitions', function () { + render(); + + screen.getByText('elastic-co'); + }); + + it('should be able to remove selected definition', function () { + render(); + + const removeBtn = screen.getByText(/elastic-co/i); + + fireEvent.click(removeBtn); + + expect(setSeries).toHaveBeenCalledTimes(1); + expect(setSeries).toHaveBeenCalledWith('newSeriesKey', { + dataType: 'rum', + reportDefinitions: {}, + reportType: 'pld', + time: { from: 'now-30d', to: 'now' }, + }); + }); + + it('should be able to unselected selected definition', async function () { + mockUseValuesList(['elastic-co']); + render(); + + const definitionBtn = screen.getByText(/web application/i); + + fireEvent.click(definitionBtn); + + screen.getByText('Apply'); + }); +}); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_definition_col.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_definition_col.tsx new file mode 100644 index 00000000000000..ce11c869de0ab6 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_definition_col.tsx @@ -0,0 +1,95 @@ +/* + * 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 { EuiBadge, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { useIndexPatternContext } from '../../hooks/use_default_index_pattern'; +import { NEW_SERIES_KEY, useUrlStorage } from '../../hooks/use_url_strorage'; +import { CustomReportField } from '../custom_report_field'; +import FieldValueSuggestions from '../../../field_value_suggestions'; +import { DataSeries } from '../../types'; + +export function ReportDefinitionCol({ dataViewSeries }: { dataViewSeries: DataSeries }) { + const { indexPattern } = useIndexPatternContext(); + + const { series, setSeries } = useUrlStorage(NEW_SERIES_KEY); + + const { reportDefinitions: rtd = {} } = series; + + const { reportDefinitions, labels, filters } = dataViewSeries; + + const onChange = (field: string, value?: string) => { + if (!value) { + delete rtd[field]; + setSeries(NEW_SERIES_KEY, { + ...series, + reportDefinitions: { ...rtd }, + }); + } else { + setSeries(NEW_SERIES_KEY, { + ...series, + reportDefinitions: { ...rtd, [field]: value }, + }); + } + }; + + const onRemove = (field: string) => { + delete rtd[field]; + setSeries(NEW_SERIES_KEY, { + ...series, + reportDefinitions: rtd, + }); + }; + + return ( + + {indexPattern && + reportDefinitions.map(({ field, custom, options, defaultValue }) => ( + + {!custom ? ( + + + onChange(field, val)} + filters={(filters ?? []).map(({ query }) => query)} + time={series.time} + width={200} + /> + + {rtd?.[field] && ( + + onRemove(field)} + iconOnClick={() => onRemove(field)} + iconOnClickAriaLabel={'Click to remove'} + onClickAriaLabel={'Click to remove'} + > + {rtd?.[field]} + + + )} + + ) : ( + + )} + + ))} + + ); +} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_filters.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_filters.test.tsx new file mode 100644 index 00000000000000..674f5e6f49bded --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_filters.test.tsx @@ -0,0 +1,28 @@ +/* + * 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 { screen } from '@testing-library/react'; +import { render } from '../../../../../utils/test_helper'; +import { ReportFilters } from './report_filters'; +import { getDefaultConfigs } from '../../configurations/default_configs'; +import { mockIndexPattern, mockUrlStorage } from '../../rtl_helpers'; +import { NEW_SERIES_KEY } from '../../hooks/use_url_strorage'; + +describe('Series Builder ReportFilters', function () { + const dataViewSeries = getDefaultConfigs({ + reportType: 'pld', + indexPattern: mockIndexPattern, + seriesId: NEW_SERIES_KEY, + }); + mockUrlStorage({}); + it('should render properly', function () { + render(); + + screen.getByText('Add filter'); + }); +}); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_filters.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_filters.tsx new file mode 100644 index 00000000000000..903dda549aeee3 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_filters.tsx @@ -0,0 +1,22 @@ +/* + * 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 { SeriesFilter } from '../../series_editor/columns/series_filter'; +import { NEW_SERIES_KEY } from '../../hooks/use_url_strorage'; +import { DataSeries } from '../../types'; + +export function ReportFilters({ dataViewSeries }: { dataViewSeries: DataSeries }) { + return ( + + ); +} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_types_col.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_types_col.test.tsx new file mode 100644 index 00000000000000..567e2654130e80 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_types_col.test.tsx @@ -0,0 +1,65 @@ +/* + * 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 { fireEvent, screen } from '@testing-library/react'; +import { mockUrlStorage, render } from '../../rtl_helpers'; +import { ReportTypesCol, SELECTED_DATA_TYPE_FOR_REPORT } from './report_types_col'; +import { ReportTypes } from '../series_builder'; + +describe('ReportTypesCol', function () { + it('should render properly', function () { + render(); + screen.getByText('Performance distribution'); + screen.getByText('KPI over time'); + }); + + it('should display empty message', function () { + render(); + screen.getByText(SELECTED_DATA_TYPE_FOR_REPORT); + }); + + it('should set series on change', function () { + const { setSeries } = mockUrlStorage({}); + render(); + + fireEvent.click(screen.getByText(/monitor duration/i)); + + expect(setSeries).toHaveBeenCalledWith('newSeriesKey', { + breakdown: 'user_agent.name', + reportDefinitions: {}, + reportType: 'upd', + time: { from: 'now-15m', to: 'now' }, + }); + expect(setSeries).toHaveBeenCalledTimes(1); + }); + + it('should set selected as filled', function () { + const { setSeries } = mockUrlStorage({ + data: { + newSeriesKey: { + dataType: 'synthetics', + reportType: 'upp', + breakdown: 'monitor.status', + time: { from: 'now-15m', to: 'now' }, + }, + }, + }); + + render(); + + const button = screen.getByRole('button', { + name: /pings histogram/i, + }); + + expect(button.classList).toContain('euiButton--fill'); + fireEvent.click(button); + + // undefined on click selected + expect(setSeries).toHaveBeenCalledWith('newSeriesKey', { dataType: 'synthetics' }); + }); +}); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_types_col.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_types_col.tsx new file mode 100644 index 00000000000000..5c94a5bca60f85 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/columns/report_types_col.tsx @@ -0,0 +1,61 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; +import { ReportViewTypeId, SeriesUrl } from '../../types'; +import { NEW_SERIES_KEY, useUrlStorage } from '../../hooks/use_url_strorage'; + +interface Props { + reportTypes: Array<{ id: ReportViewTypeId; label: string }>; +} + +export function ReportTypesCol({ reportTypes }: Props) { + const { + series: { reportType: selectedReportType, ...restSeries }, + setSeries, + } = useUrlStorage(NEW_SERIES_KEY); + + return reportTypes?.length > 0 ? ( + + {reportTypes.map(({ id: reportType, label }) => ( + + { + if (reportType === selectedReportType) { + setSeries(NEW_SERIES_KEY, { + dataType: restSeries.dataType, + } as SeriesUrl); + } else { + setSeries(NEW_SERIES_KEY, { + ...restSeries, + reportType, + reportDefinitions: {}, + }); + } + }} + > + {label} + + + ))} + + ) : ( + {SELECTED_DATA_TYPE_FOR_REPORT} + ); +} + +export const SELECTED_DATA_TYPE_FOR_REPORT = i18n.translate( + 'xpack.observability.expView.reportType.noDataType', + { defaultMessage: 'Select a data type to start building a series.' } +); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/custom_report_field.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/custom_report_field.tsx new file mode 100644 index 00000000000000..6039fd4cba2804 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/custom_report_field.tsx @@ -0,0 +1,47 @@ +/* + * 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 { EuiSuperSelect } from '@elastic/eui'; +import { useUrlStorage } from '../hooks/use_url_strorage'; +import { ReportDefinition } from '../types'; + +interface Props { + field: string; + seriesId: string; + defaultValue?: string; + options: ReportDefinition['options']; +} + +export function CustomReportField({ field, seriesId, options: opts, defaultValue }: Props) { + const { series, setSeries } = useUrlStorage(seriesId); + + const { reportDefinitions: rtd = {} } = series; + + const onChange = (value: string) => { + setSeries(seriesId, { ...series, reportDefinitions: { ...rtd, [field]: value } }); + }; + + const { reportDefinitions } = series; + + const NO_SELECT = 'no_select'; + + const options = [{ label: 'Select metric', field: NO_SELECT }, ...(opts ?? [])]; + + return ( +
+ ({ + value: fd, + inputDisplay: label, + }))} + valueOfSelected={reportDefinitions?.[field] || defaultValue || NO_SELECT} + onChange={(value) => onChange(value)} + /> +
+ ); +} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/series_builder.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/series_builder.tsx new file mode 100644 index 00000000000000..983c18af031d09 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_builder/series_builder.tsx @@ -0,0 +1,201 @@ +/* + * 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, { useState } from 'react'; + +import { i18n } from '@kbn/i18n'; +import { EuiButton, EuiBasicTable, EuiSpacer, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import styled from 'styled-components'; +import { AppDataType, ReportViewTypeId, ReportViewTypes, SeriesUrl } from '../types'; +import { DataTypesCol } from './columns/data_types_col'; +import { ReportTypesCol } from './columns/report_types_col'; +import { ReportDefinitionCol } from './columns/report_definition_col'; +import { ReportFilters } from './columns/report_filters'; +import { ReportBreakdowns } from './columns/report_breakdowns'; +import { NEW_SERIES_KEY, useUrlStorage } from '../hooks/use_url_strorage'; +import { useIndexPatternContext } from '../hooks/use_default_index_pattern'; +import { getDefaultConfigs } from '../configurations/default_configs'; + +export const ReportTypes: Record> = { + synthetics: [ + { id: 'upd', label: 'Monitor duration' }, + { id: 'upp', label: 'Pings histogram' }, + ], + rum: [ + { id: 'pld', label: 'Performance distribution' }, + { id: 'kpi', label: 'KPI over time' }, + ], + apm: [ + { id: 'svl', label: 'Latency' }, + { id: 'tpt', label: 'Throughput' }, + ], + logs: [ + { + id: 'logs', + label: 'Logs Frequency', + }, + ], + metrics: [ + { id: 'cpu', label: 'CPU usage' }, + { id: 'mem', label: 'Memory usage' }, + { id: 'nwk', label: 'Network activity' }, + ], +}; + +export function SeriesBuilder() { + const { series, setSeries, allSeriesIds, removeSeries } = useUrlStorage(NEW_SERIES_KEY); + + const { dataType, reportType, reportDefinitions = {}, filters = [] } = series; + + const [isFlyoutVisible, setIsFlyoutVisible] = useState(!!series.dataType); + + const { indexPattern } = useIndexPatternContext(); + + const getDataViewSeries = () => { + return getDefaultConfigs({ + indexPattern, + reportType: reportType!, + seriesId: NEW_SERIES_KEY, + }); + }; + + const columns = [ + { + name: i18n.translate('xpack.observability.expView.seriesBuilder.dataType', { + defaultMessage: 'Data Type', + }), + width: '20%', + render: (val: string) => , + }, + { + name: i18n.translate('xpack.observability.expView.seriesBuilder.report', { + defaultMessage: 'Report', + }), + width: '20%', + render: (val: string) => ( + + ), + }, + { + name: i18n.translate('xpack.observability.expView.seriesBuilder.definition', { + defaultMessage: 'Definition', + }), + width: '30%', + render: (val: string) => + reportType && indexPattern ? ( + + ) : null, + }, + { + name: i18n.translate('xpack.observability.expView.seriesBuilder.filters', { + defaultMessage: 'Filters', + }), + width: '25%', + render: (val: string) => + reportType && indexPattern ? : null, + }, + { + name: i18n.translate('xpack.observability.expView.seriesBuilder.breakdown', { + defaultMessage: 'Breakdowns', + }), + width: '25%', + field: 'id', + render: (val: string) => + reportType && indexPattern ? ( + + ) : null, + }, + ]; + + const addSeries = () => { + if (reportType) { + const newSeriesId = `${ + reportDefinitions?.['service.name'] || + reportDefinitions?.['monitor.id'] || + ReportViewTypes[reportType] + }`; + + const newSeriesN = { + reportType, + time: { from: 'now-30m', to: 'now' }, + filters, + reportDefinitions, + } as SeriesUrl; + + setSeries(newSeriesId, newSeriesN).then(() => { + removeSeries(NEW_SERIES_KEY); + setIsFlyoutVisible(false); + }); + } + }; + + const items = [{ id: NEW_SERIES_KEY }]; + + let flyout; + + if (isFlyoutVisible) { + flyout = ( + + + + + + + {i18n.translate('xpack.observability.expView.seriesBuilder.add', { + defaultMessage: 'Add', + })} + + + + { + removeSeries(NEW_SERIES_KEY); + setIsFlyoutVisible(false); + }} + > + {i18n.translate('xpack.observability.expView.seriesBuilder.cancel', { + defaultMessage: 'Cancel', + })} + + + + + ); + } + + return ( +
+ {!isFlyoutVisible && ( + <> + setIsFlyoutVisible((prevState) => !prevState)} + disabled={allSeriesIds.length > 0} + > + {i18n.translate('xpack.observability.expView.seriesBuilder.addSeries', { + defaultMessage: 'Add series', + })} + + + + )} + {flyout} +
+ ); +} + +const BottomFlyout = styled.div` + height: 300px; +`; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_date_picker/index.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_date_picker/index.tsx new file mode 100644 index 00000000000000..71e3317ad6db86 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_date_picker/index.tsx @@ -0,0 +1,55 @@ +/* + * 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 { EuiSuperDatePicker } from '@elastic/eui'; +import React, { useEffect } from 'react'; +import { useHasData } from '../../../../hooks/use_has_data'; +import { useUrlStorage } from '../hooks/use_url_strorage'; +import { useQuickTimeRanges } from '../../../../hooks/use_quick_time_ranges'; + +export interface TimePickerTime { + from: string; + to: string; +} + +export interface TimePickerQuickRange extends TimePickerTime { + display: string; +} + +interface Props { + seriesId: string; +} + +export function SeriesDatePicker({ seriesId }: Props) { + const { onRefreshTimeRange } = useHasData(); + + const commonlyUsedRanges = useQuickTimeRanges(); + + const { series, setSeries } = useUrlStorage(seriesId); + + function onTimeChange({ start, end }: { start: string; end: string }) { + onRefreshTimeRange(); + setSeries(seriesId, { ...series, time: { from: start, to: end } }); + } + + useEffect(() => { + if (!series || !series.time) { + setSeries(seriesId, { ...series, time: { from: 'now-5h', to: 'now' } }); + } + }, [seriesId, series, setSeries]); + + return ( + + ); +} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_date_picker/series_date_picker.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_date_picker/series_date_picker.test.tsx new file mode 100644 index 00000000000000..acc9ba9658a081 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_date_picker/series_date_picker.test.tsx @@ -0,0 +1,76 @@ +/* + * 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 { mockUrlStorage, mockUseHasData, render } from '../rtl_helpers'; +import { fireEvent, waitFor } from '@testing-library/react'; +import { SeriesDatePicker } from './index'; + +describe('SeriesDatePicker', function () { + it('should render properly', function () { + mockUrlStorage({ + data: { + 'uptime-pings-histogram': { + reportType: 'upp', + breakdown: 'monitor.status', + time: { from: 'now-30m', to: 'now' }, + }, + }, + }); + const { getByText } = render(); + + getByText('Last 30 minutes'); + }); + + it('should set defaults', async function () { + const { setSeries: setSeries1 } = mockUrlStorage({ + data: { + 'uptime-pings-histogram': { + reportType: 'upp', + breakdown: 'monitor.status', + }, + }, + } as any); + render(); + expect(setSeries1).toHaveBeenCalledTimes(1); + expect(setSeries1).toHaveBeenCalledWith('uptime-pings-histogram', { + breakdown: 'monitor.status', + reportType: 'upp', + time: { from: 'now-5h', to: 'now' }, + }); + }); + + it('should set series data', async function () { + const { setSeries } = mockUrlStorage({ + data: { + 'uptime-pings-histogram': { + reportType: 'upp', + breakdown: 'monitor.status', + time: { from: 'now-30m', to: 'now' }, + }, + }, + }); + + const { onRefreshTimeRange } = mockUseHasData(); + const { getByTestId } = render(); + + await waitFor(function () { + fireEvent.click(getByTestId('superDatePickerToggleQuickMenuButton')); + }); + + fireEvent.click(getByTestId('superDatePickerCommonlyUsed_Today')); + + expect(onRefreshTimeRange).toHaveBeenCalledTimes(1); + + expect(setSeries).toHaveBeenCalledWith('series-id', { + breakdown: 'monitor.status', + reportType: 'upp', + time: { from: 'now/d', to: 'now/d' }, + }); + expect(setSeries).toHaveBeenCalledTimes(1); + }); +}); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/actions_col.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/actions_col.tsx new file mode 100644 index 00000000000000..c6209381a4da13 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/actions_col.tsx @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { DataSeries } from '../../types'; +import { SeriesChartTypes } from './chart_types'; +import { MetricSelection } from './metric_selection'; + +interface Props { + series: DataSeries; +} + +export function ActionsCol({ series }: Props) { + return ( + + + + + {series.hasMetricType && ( + + + + )} + + ); +} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/breakdowns.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/breakdowns.test.tsx new file mode 100644 index 00000000000000..654a93a08a7c8d --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/breakdowns.test.tsx @@ -0,0 +1,49 @@ +/* + * 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 { fireEvent, screen } from '@testing-library/react'; +import { Breakdowns } from './breakdowns'; +import { mockIndexPattern, mockUrlStorage, render } from '../../rtl_helpers'; +import { NEW_SERIES_KEY } from '../../hooks/use_url_strorage'; +import { getDefaultConfigs } from '../../configurations/default_configs'; +import { USER_AGENT_OS } from '../../configurations/data/elasticsearch_fieldnames'; + +describe('Breakdowns', function () { + const dataViewSeries = getDefaultConfigs({ + reportType: 'pld', + indexPattern: mockIndexPattern, + seriesId: NEW_SERIES_KEY, + }); + + it('should render properly', async function () { + mockUrlStorage({}); + + render(); + + screen.getAllByText('Browser family'); + }); + + it('should call set series on change', function () { + const { setSeries } = mockUrlStorage({ breakdown: USER_AGENT_OS }); + + render(); + + screen.getAllByText('Operating system'); + + fireEvent.click(screen.getByTestId('seriesBreakdown')); + + fireEvent.click(screen.getByText('Browser family')); + + expect(setSeries).toHaveBeenCalledWith('series-id', { + breakdown: 'user_agent.name', + reportType: 'pld', + time: { from: 'now-15m', to: 'now' }, + }); + expect(setSeries).toHaveBeenCalledTimes(1); + }); +}); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/breakdowns.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/breakdowns.tsx new file mode 100644 index 00000000000000..0d34d7245725ad --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/breakdowns.tsx @@ -0,0 +1,65 @@ +/* + * 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 { EuiSuperSelect } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FieldLabels } from '../../configurations/constants'; +import { useUrlStorage } from '../../hooks/use_url_strorage'; + +interface Props { + seriesId: string; + breakdowns: string[]; +} + +export function Breakdowns({ seriesId, breakdowns = [] }: Props) { + const { setSeries, series } = useUrlStorage(seriesId); + + const selectedBreakdown = series.breakdown; + const NO_BREAKDOWN = 'no_breakdown'; + + const onOptionChange = (optionId: string) => { + if (optionId === NO_BREAKDOWN) { + setSeries(seriesId, { + ...series, + breakdown: undefined, + }); + } else { + setSeries(seriesId, { + ...series, + breakdown: selectedBreakdown === optionId ? undefined : optionId, + }); + } + }; + + const items = breakdowns.map((breakdown) => ({ id: breakdown, label: FieldLabels[breakdown] })); + items.push({ + id: NO_BREAKDOWN, + label: i18n.translate('xpack.observability.exp.breakDownFilter.noBreakdown', { + defaultMessage: 'No breakdown', + }), + }); + + const options = items.map(({ id, label }) => ({ + inputDisplay: id === NO_BREAKDOWN ? label : {label}, + value: id, + dropdownDisplay: label, + })); + + return ( +
+ onOptionChange(value)} + data-test-subj={'seriesBreakdown'} + /> +
+ ); +} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/chart_types.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/chart_types.test.tsx new file mode 100644 index 00000000000000..f291d0de4dac0b --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/chart_types.test.tsx @@ -0,0 +1,56 @@ +/* + * 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 { fireEvent, screen, waitFor } from '@testing-library/react'; +import { SeriesChartTypes, XYChartTypes } from './chart_types'; +import { mockUrlStorage, render } from '../../rtl_helpers'; + +describe.skip('SeriesChartTypes', function () { + it('should render properly', async function () { + mockUrlStorage({}); + + render(); + + await waitFor(() => { + screen.getByText(/chart type/i); + }); + }); + + it('should call set series on change', async function () { + const { setSeries } = mockUrlStorage({}); + + render(); + + await waitFor(() => { + screen.getByText(/chart type/i); + }); + + fireEvent.click(screen.getByText(/chart type/i)); + fireEvent.click(screen.getByTestId('lnsXY_seriesType-bar_stacked')); + + expect(setSeries).toHaveBeenNthCalledWith(1, 'performance-distribution', { + breakdown: 'user_agent.name', + reportType: 'pld', + seriesType: 'bar_stacked', + time: { from: 'now-15m', to: 'now' }, + }); + expect(setSeries).toHaveBeenCalledTimes(3); + }); + + describe('XYChartTypes', function () { + it('should render properly', async function () { + mockUrlStorage({}); + + render(); + + await waitFor(() => { + screen.getByText(/chart type/i); + }); + }); + }); +}); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/chart_types.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/chart_types.tsx new file mode 100644 index 00000000000000..017655053eef2c --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/chart_types.tsx @@ -0,0 +1,149 @@ +/* + * 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, { useState } from 'react'; + +import { + EuiButton, + EuiButtonGroup, + EuiButtonIcon, + EuiLoadingSpinner, + EuiPopover, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import styled from 'styled-components'; +import { useKibana } from '../../../../../../../../../src/plugins/kibana_react/public'; +import { ObservabilityPublicPluginsStart } from '../../../../../plugin'; +import { useFetcher } from '../../../../..'; +import { useUrlStorage } from '../../hooks/use_url_strorage'; +import { SeriesType } from '../../../../../../../lens/public'; + +export function SeriesChartTypes({ + seriesId, + defaultChartType, +}: { + seriesId: string; + defaultChartType: SeriesType; +}) { + const { series, setSeries, allSeries } = useUrlStorage(seriesId); + + const seriesType = series?.seriesType ?? defaultChartType; + + const onChange = (value: SeriesType) => { + Object.keys(allSeries).forEach((seriesKey) => { + const seriesN = allSeries[seriesKey]; + + setSeries(seriesKey, { ...seriesN, seriesType: value }); + }); + }; + + return ( + + ); +} + +export interface XYChartTypesProps { + onChange: (value: SeriesType) => void; + value: SeriesType; + label?: string; + includeChartTypes?: string[]; + excludeChartTypes?: string[]; +} + +export function XYChartTypes({ + onChange, + value, + label, + includeChartTypes, + excludeChartTypes, +}: XYChartTypesProps) { + const [isOpen, setIsOpen] = useState(false); + + const { + services: { lens }, + } = useKibana(); + + const { data = [], loading } = useFetcher(() => lens.getXyVisTypes(), [lens]); + + let vizTypes = data ?? []; + + if ((excludeChartTypes ?? []).length > 0) { + vizTypes = vizTypes.filter(({ id }) => !excludeChartTypes?.includes(id)); + } + + if ((includeChartTypes ?? []).length > 0) { + vizTypes = vizTypes.filter(({ id }) => includeChartTypes?.includes(id)); + } + + return loading ? ( + + ) : ( + id === value)?.icon} + onClick={() => { + setIsOpen((prevState) => !prevState); + }} + > + {label} + + ) : ( + id === value)?.label} + iconType={vizTypes.find(({ id }) => id === value)?.icon!} + onClick={() => { + setIsOpen((prevState) => !prevState); + }} + /> + ) + } + closePopover={() => setIsOpen(false)} + > + ({ + id: t.id, + label: t.label, + title: t.label, + iconType: t.icon || 'empty', + 'data-test-subj': `lnsXY_seriesType-${t.id}`, + }))} + idSelected={value} + onChange={(valueN: string) => { + onChange(valueN as SeriesType); + }} + /> + + ); +} + +const ButtonGroup = styled(EuiButtonGroup)` + &&& { + .euiButtonGroupButton-isSelected { + background-color: #a5a9b1 !important; + } + } +`; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/date_picker_col.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/date_picker_col.tsx new file mode 100644 index 00000000000000..8c99de51978a7c --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/date_picker_col.tsx @@ -0,0 +1,20 @@ +/* + * 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 { SeriesDatePicker } from '../../series_date_picker'; + +interface Props { + seriesId: string; +} +export function DatePickerCol({ seriesId }: Props) { + return ( +
+ +
+ ); +} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/filter_expanded.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/filter_expanded.test.tsx new file mode 100644 index 00000000000000..edd5546f139409 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/filter_expanded.test.tsx @@ -0,0 +1,93 @@ +/* + * 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 { fireEvent, screen } from '@testing-library/react'; +import { FilterExpanded } from './filter_expanded'; +import { mockUrlStorage, mockUseValuesList, render } from '../../rtl_helpers'; +import { USER_AGENT_NAME } from '../../configurations/data/elasticsearch_fieldnames'; + +describe('FilterExpanded', function () { + it('should render properly', async function () { + mockUrlStorage({ filters: [{ field: USER_AGENT_NAME, values: ['Chrome'] }] }); + + render( + + ); + + screen.getByText('Browser Family'); + }); + it('should call go back on click', async function () { + mockUrlStorage({ filters: [{ field: USER_AGENT_NAME, values: ['Chrome'] }] }); + const goBack = jest.fn(); + + render( + + ); + + fireEvent.click(screen.getByText('Browser Family')); + + expect(goBack).toHaveBeenCalledTimes(1); + expect(goBack).toHaveBeenCalledWith(); + }); + + it('should call useValuesList on load', async function () { + mockUrlStorage({ filters: [{ field: USER_AGENT_NAME, values: ['Chrome'] }] }); + + const { spy } = mockUseValuesList(['Chrome', 'Firefox']); + + const goBack = jest.fn(); + + render( + + ); + + expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toBeCalledWith( + expect.objectContaining({ + time: { from: 'now-15m', to: 'now' }, + sourceField: USER_AGENT_NAME, + }) + ); + }); + it('should filter display values', async function () { + mockUrlStorage({ filters: [{ field: USER_AGENT_NAME, values: ['Chrome'] }] }); + + mockUseValuesList(['Chrome', 'Firefox']); + + render( + + ); + + expect(screen.queryByText('Firefox')).toBeTruthy(); + + fireEvent.input(screen.getByRole('searchbox'), { target: { value: 'ch' } }); + + expect(screen.queryByText('Firefox')).toBeFalsy(); + expect(screen.getByText('Chrome')).toBeTruthy(); + }); +}); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/filter_expanded.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/filter_expanded.tsx new file mode 100644 index 00000000000000..280912dd0902f7 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/filter_expanded.tsx @@ -0,0 +1,100 @@ +/* + * 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, { useState, Fragment } from 'react'; +import { + EuiFieldSearch, + EuiSpacer, + EuiButtonEmpty, + EuiLoadingSpinner, + EuiFilterGroup, +} from '@elastic/eui'; +import { useIndexPatternContext } from '../../hooks/use_default_index_pattern'; +import { useUrlStorage } from '../../hooks/use_url_strorage'; +import { UrlFilter } from '../../types'; +import { FilterValueButton } from './filter_value_btn'; +import { useValuesList } from '../../../../../hooks/use_values_list'; + +interface Props { + seriesId: string; + label: string; + field: string; + goBack: () => void; + nestedField?: string; +} + +export function FilterExpanded({ seriesId, field, label, goBack, nestedField }: Props) { + const { indexPattern } = useIndexPatternContext(); + + const [value, setValue] = useState(''); + + const [isOpen, setIsOpen] = useState({ value: '', negate: false }); + + const { series } = useUrlStorage(seriesId); + + const { values, loading } = useValuesList({ + sourceField: field, + time: series.time, + indexPattern, + }); + + const filters = series?.filters ?? []; + + const currFilter: UrlFilter | undefined = filters.find(({ field: fd }) => field === fd); + + const displayValues = (values || []).filter((opt) => + opt.toLowerCase().includes(value.toLowerCase()) + ); + + return ( + <> + goBack()}> + {label} + + { + setValue(evt.target.value); + }} + /> + + {loading && ( +
+ +
+ )} + {displayValues.map((opt) => ( + + + + + + + + ))} + + ); +} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/filter_value_btn.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/filter_value_btn.test.tsx new file mode 100644 index 00000000000000..7f76c9ea999eed --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/filter_value_btn.test.tsx @@ -0,0 +1,238 @@ +/* + * 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 { fireEvent, screen } from '@testing-library/react'; +import { FilterValueButton } from './filter_value_btn'; +import { mockUrlStorage, mockUseSeriesFilter, mockUseValuesList, render } from '../../rtl_helpers'; +import { + USER_AGENT_NAME, + USER_AGENT_VERSION, +} from '../../configurations/data/elasticsearch_fieldnames'; + +describe('FilterValueButton', function () { + it('should render properly', async function () { + render( + + ); + + screen.getByText('Chrome'); + }); + + it('should render display negate state', async function () { + render( + + ); + + screen.getByText('Not Chrome'); + screen.getByTitle('Not Chrome'); + const btn = screen.getByRole('button'); + expect(btn.classList).toContain('euiButtonEmpty--danger'); + }); + + it('should call set filter on click', async function () { + const { setFilter, removeFilter } = mockUseSeriesFilter(); + + render( + + ); + + fireEvent.click(screen.getByText('Not Chrome')); + + expect(removeFilter).toHaveBeenCalledTimes(0); + expect(setFilter).toHaveBeenCalledTimes(1); + + expect(setFilter).toHaveBeenCalledWith({ + field: 'user_agent.name', + negate: true, + value: 'Chrome', + }); + }); + it('should remove filter on click if already selected', async function () { + mockUrlStorage({}); + const { removeFilter } = mockUseSeriesFilter(); + + render( + + ); + + fireEvent.click(screen.getByText('Chrome')); + + expect(removeFilter).toHaveBeenCalledWith({ + field: 'user_agent.name', + negate: false, + value: 'Chrome', + }); + }); + + it('should change filter on negated one', async function () { + const { removeFilter } = mockUseSeriesFilter(); + + render( + + ); + + fireEvent.click(screen.getByText('Not Chrome')); + + expect(removeFilter).toHaveBeenCalledWith({ + field: 'user_agent.name', + negate: true, + value: 'Chrome', + }); + }); + + it('should force open nested', async function () { + mockUseSeriesFilter(); + const { spy } = mockUseValuesList(); + + render( + + ); + + expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toBeCalledWith( + expect.objectContaining({ + filters: [ + { + term: { + [USER_AGENT_NAME]: 'Chrome', + }, + }, + ], + sourceField: 'user_agent.version', + }) + ); + }); + it('should set isNestedOpen on click', async function () { + mockUseSeriesFilter(); + const { spy } = mockUseValuesList(); + + render( + + ); + + expect(spy).toHaveBeenCalledTimes(2); + expect(spy).toBeCalledWith( + expect.objectContaining({ + filters: [ + { + term: { + [USER_AGENT_NAME]: 'Chrome', + }, + }, + ], + sourceField: USER_AGENT_VERSION, + }) + ); + }); + + it('should set call setIsNestedOpen on click selected', async function () { + mockUseSeriesFilter(); + mockUseValuesList(); + + const setIsNestedOpen = jest.fn(); + + render( + + ); + + fireEvent.click(screen.getByText('Chrome')); + + expect(setIsNestedOpen).toHaveBeenCalledTimes(1); + expect(setIsNestedOpen).toHaveBeenCalledWith({ negate: false, value: '' }); + }); + + it('should set call setIsNestedOpen on click not selected', async function () { + mockUseSeriesFilter(); + mockUseValuesList(); + + const setIsNestedOpen = jest.fn(); + + render( + + ); + + fireEvent.click(screen.getByText('Not Chrome')); + + expect(setIsNestedOpen).toHaveBeenCalledTimes(1); + expect(setIsNestedOpen).toHaveBeenCalledWith({ negate: true, value: 'Chrome' }); + }); +}); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/filter_value_btn.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/filter_value_btn.tsx new file mode 100644 index 00000000000000..42cdfd595e66ba --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/filter_value_btn.tsx @@ -0,0 +1,117 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import React, { useMemo } from 'react'; +import { EuiFilterButton, hexToRgb } from '@elastic/eui'; +import { useIndexPatternContext } from '../../hooks/use_default_index_pattern'; +import { useUrlStorage } from '../../hooks/use_url_strorage'; +import { useSeriesFilters } from '../../hooks/use_series_filters'; +import { euiStyled } from '../../../../../../../../../src/plugins/kibana_react/common'; +import FieldValueSuggestions from '../../../field_value_suggestions'; + +interface Props { + value: string; + field: string; + allSelectedValues?: string[]; + negate: boolean; + nestedField?: string; + seriesId: string; + isNestedOpen: { + value: string; + negate: boolean; + }; + setIsNestedOpen: (val: { value: string; negate: boolean }) => void; +} + +export function FilterValueButton({ + isNestedOpen, + setIsNestedOpen, + value, + field, + negate, + seriesId, + nestedField, + allSelectedValues, +}: Props) { + const { series } = useUrlStorage(seriesId); + + const { indexPattern } = useIndexPatternContext(); + + const { setFilter, removeFilter } = useSeriesFilters({ seriesId }); + + const hasActiveFilters = (allSelectedValues ?? []).includes(value); + + const button = ( + { + if (hasActiveFilters) { + removeFilter({ field, value, negate }); + } else { + setFilter({ field, value, negate }); + } + if (!hasActiveFilters) { + setIsNestedOpen({ value, negate }); + } else { + setIsNestedOpen({ value: '', negate }); + } + }} + > + {negate + ? i18n.translate('xpack.observability.expView.filterValueButton.negate', { + defaultMessage: 'Not {value}', + values: { value }, + }) + : value} + + ); + + const onNestedChange = (val?: string) => { + setFilter({ field: nestedField!, value: val! }); + setIsNestedOpen({ value: '', negate }); + }; + + const forceOpenNested = isNestedOpen?.value === value && isNestedOpen.negate === negate; + + const filters = useMemo(() => { + return [ + { + term: { + [field]: value, + }, + }, + ]; + }, [field, value]); + + return nestedField && forceOpenNested ? ( + + ) : ( + button + ); +} + +const FilterButton = euiStyled(EuiFilterButton)` + background-color: rgba(${(props) => { + const color = props.hasActiveFilters + ? props.color === 'danger' + ? hexToRgb(props.theme.eui.euiColorDanger) + : hexToRgb(props.theme.eui.euiColorPrimary) + : 'initial'; + return `${color[0]}, ${color[1]}, ${color[2]}, 0.1`; + }}); +`; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/metric_selection.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/metric_selection.test.tsx new file mode 100644 index 00000000000000..ced04f0a59c8cb --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/metric_selection.test.tsx @@ -0,0 +1,112 @@ +/* + * 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 { fireEvent, screen } from '@testing-library/react'; +import { mockUrlStorage, render } from '../../rtl_helpers'; +import { MetricSelection } from './metric_selection'; + +describe('MetricSelection', function () { + it('should render properly', function () { + render(); + + screen.getByText('Average'); + }); + + it('should display selected value', function () { + mockUrlStorage({ + data: { + 'performance-distribution': { + reportType: 'kpi', + metric: 'median', + time: { from: 'now-15m', to: 'now' }, + }, + }, + }); + + render(); + + screen.getByText('Median'); + }); + + it('should be disabled on disabled state', function () { + render(); + + const btn = screen.getByRole('button'); + + expect(btn.classList).toContain('euiButton-isDisabled'); + }); + + it('should call set series on change', function () { + const { setSeries } = mockUrlStorage({ + data: { + 'performance-distribution': { + reportType: 'kpi', + metric: 'median', + time: { from: 'now-15m', to: 'now' }, + }, + }, + }); + + render(); + + fireEvent.click(screen.getByText('Median')); + + screen.getByText('Chart metric group'); + + fireEvent.click(screen.getByText('95th Percentile')); + + expect(setSeries).toHaveBeenNthCalledWith(1, 'performance-distribution', { + metric: '95th', + reportType: 'kpi', + time: { from: 'now-15m', to: 'now' }, + }); + // FIXME This is a bug in EUI EuiButtonGroup calls on change multiple times + // This should be one https://github.com/elastic/eui/issues/4629 + expect(setSeries).toHaveBeenCalledTimes(3); + }); + + it('should call set series on change for all series', function () { + const { setSeries } = mockUrlStorage({ + data: { + 'page-views': { + reportType: 'kpi', + metric: 'median', + time: { from: 'now-15m', to: 'now' }, + }, + 'performance-distribution': { + reportType: 'kpi', + metric: 'median', + time: { from: 'now-15m', to: 'now' }, + }, + }, + }); + + render(); + + fireEvent.click(screen.getByText('Median')); + + screen.getByText('Chart metric group'); + + fireEvent.click(screen.getByText('95th Percentile')); + + expect(setSeries).toHaveBeenNthCalledWith(1, 'page-views', { + metric: '95th', + reportType: 'kpi', + time: { from: 'now-15m', to: 'now' }, + }); + + expect(setSeries).toHaveBeenNthCalledWith(2, 'performance-distribution', { + metric: '95th', + reportType: 'kpi', + time: { from: 'now-15m', to: 'now' }, + }); + // FIXME This is a bug in EUI EuiButtonGroup calls on change multiple times + // This should be one https://github.com/elastic/eui/issues/4629 + expect(setSeries).toHaveBeenCalledTimes(6); + }); +}); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/metric_selection.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/metric_selection.tsx new file mode 100644 index 00000000000000..e01e371b5eeeb9 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/metric_selection.tsx @@ -0,0 +1,86 @@ +/* + * 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, { useState } from 'react'; +import { i18n } from '@kbn/i18n'; +import { EuiButton, EuiButtonGroup, EuiPopover } from '@elastic/eui'; +import { useUrlStorage } from '../../hooks/use_url_strorage'; +import { OperationType } from '../../../../../../../lens/public'; + +const toggleButtons = [ + { + id: `avg`, + label: i18n.translate('xpack.observability.expView.metricsSelect.average', { + defaultMessage: 'Average', + }), + }, + { + id: `median`, + label: i18n.translate('xpack.observability.expView.metricsSelect.median', { + defaultMessage: 'Median', + }), + }, + { + id: `95th`, + label: i18n.translate('xpack.observability.expView.metricsSelect.9thPercentile', { + defaultMessage: '95th Percentile', + }), + }, + { + id: `99th`, + label: i18n.translate('xpack.observability.expView.metricsSelect.99thPercentile', { + defaultMessage: '99th Percentile', + }), + }, +]; + +export function MetricSelection({ + seriesId, + isDisabled, +}: { + seriesId: string; + isDisabled: boolean; +}) { + const { series, setSeries, allSeries } = useUrlStorage(seriesId); + + const [isOpen, setIsOpen] = useState(false); + + const [toggleIdSelected, setToggleIdSelected] = useState(series?.metric ?? 'avg'); + + const onChange = (optionId: OperationType) => { + setToggleIdSelected(optionId); + + Object.keys(allSeries).forEach((seriesKey) => { + const seriesN = allSeries[seriesKey]; + + setSeries(seriesKey, { ...seriesN, metric: optionId }); + }); + }; + const button = ( + setIsOpen((prevState) => !prevState)} + size="s" + color="text" + isDisabled={isDisabled} + > + {toggleButtons.find(({ id }) => id === toggleIdSelected)!.label} + + ); + + return ( + setIsOpen(false)}> + onChange(id as OperationType)} + /> + + ); +} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/remove_series.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/remove_series.tsx new file mode 100644 index 00000000000000..67aebed9433269 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/remove_series.tsx @@ -0,0 +1,35 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import React from 'react'; +import { EuiButtonIcon } from '@elastic/eui'; +import { DataSeries } from '../../types'; +import { useUrlStorage } from '../../hooks/use_url_strorage'; + +interface Props { + series: DataSeries; +} + +export function RemoveSeries({ series }: Props) { + const { removeSeries } = useUrlStorage(); + + const onClick = () => { + removeSeries(series.id); + }; + return ( + + ); +} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/series_filter.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/series_filter.tsx new file mode 100644 index 00000000000000..24b65d2adb38e3 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/columns/series_filter.tsx @@ -0,0 +1,139 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import React, { useState, Fragment } from 'react'; +import { + EuiButton, + EuiPopover, + EuiSpacer, + EuiButtonEmpty, + EuiFlexItem, + EuiFlexGroup, +} from '@elastic/eui'; +import { FilterExpanded } from './filter_expanded'; +import { DataSeries } from '../../types'; +import { FieldLabels } from '../../configurations/constants'; +import { SelectedFilters } from '../selected_filters'; +import { NEW_SERIES_KEY, useUrlStorage } from '../../hooks/use_url_strorage'; + +interface Props { + seriesId: string; + defaultFilters: DataSeries['defaultFilters']; + series: DataSeries; + isNew?: boolean; +} + +export interface Field { + label: string; + field: string; + nested?: string; +} + +export function SeriesFilter({ series, isNew, seriesId, defaultFilters = [] }: Props) { + const [isPopoverVisible, setIsPopoverVisible] = useState(false); + + const [selectedField, setSelectedField] = useState(); + + const options = defaultFilters.map((field) => { + if (typeof field === 'string') { + return { label: FieldLabels[field], field }; + } + return { label: FieldLabels[field.field], field: field.field, nested: field.nested }; + }); + const disabled = seriesId === NEW_SERIES_KEY && !isNew; + + const { setSeries, series: urlSeries } = useUrlStorage(seriesId); + + const button = ( + { + setIsPopoverVisible(true); + }} + isDisabled={disabled} + size="s" + > + {i18n.translate('xpack.observability.expView.seriesEditor.addFilter', { + defaultMessage: 'Add filter', + })} + + ); + + const mainPanel = ( + <> + + {options.map((opt) => ( + + { + setSelectedField(opt); + }} + > + {opt.label} + + + + ))} + + ); + + const childPanel = selectedField ? ( + { + setSelectedField(undefined); + }} + /> + ) : null; + + const closePopover = () => { + setIsPopoverVisible(false); + setSelectedField(undefined); + }; + + return ( + + {!disabled && } + + + {!selectedField ? mainPanel : childPanel} + + + {(urlSeries.filters ?? []).length > 0 && ( + + { + setSeries(seriesId, { ...urlSeries, filters: undefined }); + }} + isDisabled={disabled} + size="s" + > + {i18n.translate('xpack.observability.expView.seriesEditor.clearFilter', { + defaultMessage: 'Clear filters', + })} + + + )} + + ); +} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/selected_filters.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/selected_filters.test.tsx new file mode 100644 index 00000000000000..5770a7e209f068 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/selected_filters.test.tsx @@ -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 React from 'react'; +import { screen, waitFor } from '@testing-library/react'; +import { mockIndexPattern, mockUrlStorage, render } from '../rtl_helpers'; +import { SelectedFilters } from './selected_filters'; +import { getDefaultConfigs } from '../configurations/default_configs'; +import { NEW_SERIES_KEY } from '../hooks/use_url_strorage'; +import { USER_AGENT_NAME } from '../configurations/data/elasticsearch_fieldnames'; + +describe('SelectedFilters', function () { + const dataViewSeries = getDefaultConfigs({ + reportType: 'pld', + indexPattern: mockIndexPattern, + seriesId: NEW_SERIES_KEY, + }); + + it('should render properly', async function () { + mockUrlStorage({ filters: [{ field: USER_AGENT_NAME, values: ['Chrome'] }] }); + + render(); + + await waitFor(() => { + screen.getByText('Chrome'); + screen.getByTitle('Filter: Browser family: Chrome. Select for more filter actions.'); + }); + }); +}); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/selected_filters.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/selected_filters.tsx new file mode 100644 index 00000000000000..be8b1feb4d7236 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/selected_filters.tsx @@ -0,0 +1,96 @@ +/* + * 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, { Fragment } from 'react'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { NEW_SERIES_KEY, useUrlStorage } from '../hooks/use_url_strorage'; +import { FilterLabel } from '../components/filter_label'; +import { DataSeries, UrlFilter } from '../types'; +import { useIndexPatternContext } from '../hooks/use_default_index_pattern'; +import { useSeriesFilters } from '../hooks/use_series_filters'; +import { getFiltersFromDefs } from '../hooks/use_lens_attributes'; + +interface Props { + seriesId: string; + series: DataSeries; + isNew?: boolean; +} +export function SelectedFilters({ seriesId, isNew, series: dataSeries }: Props) { + const { series } = useUrlStorage(seriesId); + + const { reportDefinitions = {} } = series; + + const { labels } = dataSeries; + + const filters: UrlFilter[] = series.filters ?? []; + + let definitionFilters: UrlFilter[] = getFiltersFromDefs(reportDefinitions, dataSeries); + + // we don't want to display report definition filters in new series view + if (seriesId === NEW_SERIES_KEY && isNew) { + definitionFilters = []; + } + + const { removeFilter } = useSeriesFilters({ seriesId }); + + const { indexPattern } = useIndexPatternContext(); + + return (filters.length > 0 || definitionFilters.length > 0) && indexPattern ? ( + + + {filters.map(({ field, values, notValues }) => ( + + {(values ?? []).map((val) => ( + + removeFilter({ field, value: val, negate: false })} + negate={false} + /> + + ))} + {(notValues ?? []).map((val) => ( + + removeFilter({ field, value: val, negate: true })} + /> + + ))} + + ))} + + {definitionFilters.map(({ field, values }) => ( + + {(values ?? []).map((val) => ( + + { + // FIXME handle this use case + }} + negate={false} + definitionFilter={true} + /> + + ))} + + ))} + + + ) : null; +} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/series_editor.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/series_editor.tsx new file mode 100644 index 00000000000000..2d423c9aee3fcd --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/series_editor.tsx @@ -0,0 +1,139 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import { EuiBasicTable, EuiIcon, EuiSpacer, EuiText } from '@elastic/eui'; +import { SeriesFilter } from './columns/series_filter'; +import { ActionsCol } from './columns/actions_col'; +import { Breakdowns } from './columns/breakdowns'; +import { DataSeries } from '../types'; +import { SeriesBuilder } from '../series_builder/series_builder'; +import { NEW_SERIES_KEY, useUrlStorage } from '../hooks/use_url_strorage'; +import { getDefaultConfigs } from '../configurations/default_configs'; +import { DatePickerCol } from './columns/date_picker_col'; +import { RemoveSeries } from './columns/remove_series'; +import { useIndexPatternContext } from '../hooks/use_default_index_pattern'; + +export function SeriesEditor() { + const { allSeries, firstSeriesId } = useUrlStorage(); + + const columns = [ + { + name: i18n.translate('xpack.observability.expView.seriesEditor.name', { + defaultMessage: 'Name', + }), + field: 'id', + width: '15%', + render: (val: string) => ( + + {' '} + {val === NEW_SERIES_KEY ? 'new-series-preview' : val} + + ), + }, + ...(firstSeriesId !== NEW_SERIES_KEY + ? [ + { + name: i18n.translate('xpack.observability.expView.seriesEditor.filters', { + defaultMessage: 'Filters', + }), + field: 'defaultFilters', + width: '25%', + render: (defaultFilters: string[], series: DataSeries) => ( + + ), + }, + { + name: i18n.translate('xpack.observability.expView.seriesEditor.breakdowns', { + defaultMessage: 'Breakdowns', + }), + field: 'breakdowns', + width: '15%', + render: (val: string[], item: DataSeries) => ( + + ), + }, + { + name: '', + align: 'center' as const, + width: '15%', + field: 'id', + render: (val: string, item: DataSeries) => , + }, + ] + : []), + { + name: ( +
+ {i18n.translate('xpack.observability.expView.seriesEditor.time', { + defaultMessage: 'Time', + })} +
+ ), + width: '20%', + field: 'id', + align: 'right' as const, + render: (val: string, item: DataSeries) => , + }, + + ...(firstSeriesId !== NEW_SERIES_KEY + ? [ + { + name: i18n.translate('xpack.observability.expView.seriesEditor.actions', { + defaultMessage: 'Actions', + }), + align: 'center' as const, + width: '5%', + field: 'id', + render: (val: string, item: DataSeries) => , + }, + ] + : []), + ]; + + const allSeriesKeys = Object.keys(allSeries); + + const items: DataSeries[] = []; + + const { indexPattern } = useIndexPatternContext(); + + allSeriesKeys.forEach((seriesKey) => { + const series = allSeries[seriesKey]; + if (series.reportType && indexPattern) { + items.push( + getDefaultConfigs({ + indexPattern, + reportType: series.reportType, + seriesId: seriesKey, + }) + ); + } + }); + + return ( + <> + + (firstSeriesId === NEW_SERIES_KEY ? {} : { height: 100 })} + noItemsMessage={i18n.translate('xpack.observability.expView.seriesEditor.notFound', { + defaultMessage: 'No series found, please add a series.', + })} + cellProps={{ + style: { + verticalAlign: 'top', + }, + }} + /> + + + + ); +} diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts new file mode 100644 index 00000000000000..444e0ddaecb4a1 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/types.ts @@ -0,0 +1,89 @@ +/* + * 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 { PaletteOutput } from 'src/plugins/charts/public'; +import { + LastValueIndexPatternColumn, + DateHistogramIndexPatternColumn, + SeriesType, + OperationType, + IndexPatternColumn, +} from '../../../../../lens/public'; + +import { PersistableFilter } from '../../../../../lens/common'; +import { IIndexPattern } from '../../../../../../../src/plugins/data/common/index_patterns'; + +export const ReportViewTypes = { + pld: 'page-load-dist', + kpi: 'kpi-trends', + upd: 'uptime-duration', + upp: 'uptime-pings', + svl: 'service-latency', + tpt: 'service-throughput', + logs: 'logs-frequency', + cpu: 'cpu-usage', + mem: 'memory-usage', + nwk: 'network-activity', +} as const; + +type ValueOf = T[keyof T]; + +export type ReportViewTypeId = keyof typeof ReportViewTypes; + +export type ReportViewType = ValueOf; + +export interface ReportDefinition { + field: string; + required?: boolean; + custom?: boolean; + defaultValue?: string; + options?: Array<{ field: string; label: string; description?: string }>; +} + +export interface DataSeries { + reportType: ReportViewType; + id: string; + xAxisColumn: Partial | Partial; + yAxisColumn: Partial; + + breakdowns: string[]; + defaultSeriesType: SeriesType; + defaultFilters: Array; + seriesTypes: SeriesType[]; + filters?: PersistableFilter[]; + reportDefinitions: ReportDefinition[]; + labels: Record; + hasMetricType: boolean; + palette?: PaletteOutput; +} + +export interface SeriesUrl { + time: { + to: string; + from: string; + }; + breakdown?: string; + filters?: UrlFilter[]; + seriesType?: SeriesType; + reportType: ReportViewTypeId; + metric?: OperationType; + dataType?: AppDataType; + reportDefinitions?: Record; +} + +export interface UrlFilter { + field: string; + values?: string[]; + notValues?: string[]; +} + +export interface ConfigProps { + seriesId: string; + indexPattern: IIndexPattern; +} + +export type AppDataType = 'synthetics' | 'rum' | 'logs' | 'metrics' | 'apm'; diff --git a/x-pack/plugins/observability/public/components/shared/field_value_suggestions/field_value_selection.tsx b/x-pack/plugins/observability/public/components/shared/field_value_suggestions/field_value_selection.tsx index b2c682dc58937f..a44aab2da85be7 100644 --- a/x-pack/plugins/observability/public/components/shared/field_value_suggestions/field_value_selection.tsx +++ b/x-pack/plugins/observability/public/components/shared/field_value_suggestions/field_value_selection.tsx @@ -15,14 +15,19 @@ import { EuiSelectableOption, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { PopoverAnchorPosition } from '@elastic/eui/src/components/popover/popover'; export interface FieldValueSelectionProps { value?: string; label: string; - loading: boolean; + loading?: boolean; onChange: (val?: string) => void; values?: string[]; setQuery: Dispatch>; + anchorPosition?: PopoverAnchorPosition; + forceOpen?: boolean; + button?: JSX.Element; + width?: number; } const formatOptions = (values?: string[], value?: string): EuiSelectableOption[] => { @@ -38,6 +43,10 @@ export function FieldValueSelection({ loading, values, setQuery, + button, + width, + forceOpen, + anchorPosition, onChange: onSelectionChange, }: FieldValueSelectionProps) { const [options, setOptions] = useState(formatOptions(values, value)); @@ -63,8 +72,9 @@ export function FieldValueSelection({ setQuery((evt.target as HTMLInputElement).value); }; - const button = ( + const anchorButton = ( void; + filters: ESFilter[]; + anchorPosition?: PopoverAnchorPosition; + time?: { from: string; to: string }; + forceOpen?: boolean; + button?: JSX.Element; + width?: number; } export function FieldValueSuggestions({ @@ -25,12 +33,18 @@ export function FieldValueSuggestions({ label, indexPattern, value, + filters, + button, + time, + width, + forceOpen, + anchorPosition, onChange: onSelectionChange, }: FieldValueSuggestionsProps) { const [query, setQuery] = useState(''); const [debouncedValue, setDebouncedValue] = useState(''); - const { values, loading } = useValuesList({ indexPattern, query, sourceField }); + const { values, loading } = useValuesList({ indexPattern, query, sourceField, filters, time }); useDebounce( () => { @@ -48,6 +62,10 @@ export function FieldValueSuggestions({ setQuery={setDebouncedValue} loading={loading} value={value} + button={button} + forceOpen={forceOpen} + anchorPosition={anchorPosition} + width={width} /> ); } diff --git a/x-pack/plugins/observability/public/context/has_data_context.test.tsx b/x-pack/plugins/observability/public/context/has_data_context.test.tsx index 5e48860a9b0492..01655c0d7b2d77 100644 --- a/x-pack/plugins/observability/public/context/has_data_context.test.tsx +++ b/x-pack/plugins/observability/public/context/has_data_context.test.tsx @@ -17,12 +17,19 @@ import { HasData, ObservabilityFetchDataPlugins } from '../typings/fetch_overvie import { HasDataContextProvider } from './has_data_context'; import * as pluginContext from '../hooks/use_plugin_context'; import { PluginContextValue } from './plugin_context'; +import { Router } from 'react-router-dom'; +import { createMemoryHistory } from 'history'; const relativeStart = '2020-10-08T06:00:00.000Z'; const relativeEnd = '2020-10-08T07:00:00.000Z'; function wrapper({ children }: { children: React.ReactElement }) { - return {children}; + const history = createMemoryHistory(); + return ( + + {children} + + ); } function unregisterAll() { diff --git a/x-pack/plugins/observability/public/context/has_data_context.tsx b/x-pack/plugins/observability/public/context/has_data_context.tsx index 085b7fd7ba028e..a2628d37828a44 100644 --- a/x-pack/plugins/observability/public/context/has_data_context.tsx +++ b/x-pack/plugins/observability/public/context/has_data_context.tsx @@ -7,6 +7,7 @@ import { uniqueId } from 'lodash'; import React, { createContext, useEffect, useState } from 'react'; +import { useRouteMatch } from 'react-router-dom'; import { Alert } from '../../../alerting/common'; import { getDataHandler } from '../data_handler'; import { FETCH_STATUS } from '../hooks/use_fetcher'; @@ -41,35 +42,38 @@ export function HasDataContextProvider({ children }: { children: React.ReactNode const [hasData, setHasData] = useState({}); + const isExploratoryView = useRouteMatch('/exploratory-view'); + useEffect( () => { - apps.forEach(async (app) => { - try { - if (app !== 'alert') { - const params = - app === 'ux' - ? { absoluteTime: { start: absoluteStart, end: absoluteEnd } } - : undefined; - - const result = await getDataHandler(app)?.hasData(params); + if (!isExploratoryView) + apps.forEach(async (app) => { + try { + if (app !== 'alert') { + const params = + app === 'ux' + ? { absoluteTime: { start: absoluteStart, end: absoluteEnd } } + : undefined; + + const result = await getDataHandler(app)?.hasData(params); + setHasData((prevState) => ({ + ...prevState, + [app]: { + hasData: result, + status: FETCH_STATUS.SUCCESS, + }, + })); + } + } catch (e) { setHasData((prevState) => ({ ...prevState, [app]: { - hasData: result, - status: FETCH_STATUS.SUCCESS, + hasData: undefined, + status: FETCH_STATUS.FAILURE, }, })); } - } catch (e) { - setHasData((prevState) => ({ - ...prevState, - [app]: { - hasData: undefined, - status: FETCH_STATUS.FAILURE, - }, - })); - } - }); + }); }, // eslint-disable-next-line react-hooks/exhaustive-deps [] diff --git a/x-pack/plugins/observability/public/hooks/use_breadcrumbs.ts b/x-pack/plugins/observability/public/hooks/use_breadcrumbs.ts new file mode 100644 index 00000000000000..a354ac8a07f050 --- /dev/null +++ b/x-pack/plugins/observability/public/hooks/use_breadcrumbs.ts @@ -0,0 +1,71 @@ +/* + * 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 { ChromeBreadcrumb } from 'kibana/public'; +import { i18n } from '@kbn/i18n'; +import { MouseEvent, useEffect } from 'react'; +import { EuiBreadcrumb } from '@elastic/eui'; +import { stringify } from 'query-string'; +import { useKibana } from '../../../../../src/plugins/kibana_react/public'; +import { useQueryParams } from './use_query_params'; + +const EMPTY_QUERY = '?'; + +function handleBreadcrumbClick( + breadcrumbs: ChromeBreadcrumb[], + navigateToHref?: (url: string) => Promise +) { + return breadcrumbs.map((bc) => ({ + ...bc, + ...(bc.href + ? { + onClick: (event: MouseEvent) => { + if (navigateToHref && bc.href) { + event.preventDefault(); + navigateToHref(bc.href); + } + }, + } + : {}), + })); +} + +export const makeBaseBreadcrumb = (href: string, params?: any): EuiBreadcrumb => { + if (params) { + const crumbParams = { ...params }; + + delete crumbParams.statusFilter; + const query = stringify(crumbParams, { skipEmptyString: true, skipNull: true }); + href += query === EMPTY_QUERY ? '' : query; + } + return { + text: i18n.translate('xpack.observability.breadcrumbs.observability', { + defaultMessage: 'Observability', + }), + href, + }; +}; + +export const useBreadcrumbs = (extraCrumbs: ChromeBreadcrumb[]) => { + const params = useQueryParams(); + + const { + services: { chrome, application }, + } = useKibana(); + + const setBreadcrumbs = chrome?.setBreadcrumbs; + const appPath = application?.getUrlForApp('observability-overview') ?? ''; + const navigate = application?.navigateToUrl; + + useEffect(() => { + if (setBreadcrumbs) { + setBreadcrumbs( + handleBreadcrumbClick([makeBaseBreadcrumb(appPath, params)].concat(extraCrumbs), navigate) + ); + } + }, [appPath, extraCrumbs, navigate, params, setBreadcrumbs]); +}; diff --git a/x-pack/plugins/observability/public/hooks/use_quick_time_ranges.tsx b/x-pack/plugins/observability/public/hooks/use_quick_time_ranges.tsx new file mode 100644 index 00000000000000..82a0fc39b8519c --- /dev/null +++ b/x-pack/plugins/observability/public/hooks/use_quick_time_ranges.tsx @@ -0,0 +1,22 @@ +/* + * 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 { useUiSetting } from '../../../../../src/plugins/kibana_react/public'; +import { UI_SETTINGS } from '../../../../../src/plugins/data/common'; +import { TimePickerQuickRange } from '../components/shared/exploratory_view/series_date_picker'; + +export function useQuickTimeRanges() { + const timePickerQuickRanges = useUiSetting( + UI_SETTINGS.TIMEPICKER_QUICK_RANGES + ); + + return timePickerQuickRanges.map(({ from, to, display }) => ({ + start: from, + end: to, + label: display, + })); +} diff --git a/x-pack/plugins/observability/public/hooks/use_values_list.ts b/x-pack/plugins/observability/public/hooks/use_values_list.ts index 25a12ab4a9ebd1..e17f515ed6cb9e 100644 --- a/x-pack/plugins/observability/public/hooks/use_values_list.ts +++ b/x-pack/plugins/observability/public/hooks/use_values_list.ts @@ -5,32 +5,58 @@ * 2.0. */ -import { IIndexPattern } from '../../../../../src/plugins/data/common'; +import { IndexPattern } from '../../../../../src/plugins/data/common'; import { useKibana } from '../../../../../src/plugins/kibana_react/public'; +import { DataPublicPluginStart } from '../../../../../src/plugins/data/public'; import { useFetcher } from './use_fetcher'; import { ESFilter } from '../../../../../typings/elasticsearch'; -import { DataPublicPluginStart } from '../../../../../src/plugins/data/public'; -interface Props { +export interface Props { sourceField: string; query?: string; - indexPattern: IIndexPattern; + indexPattern: IndexPattern; filters?: ESFilter[]; + time?: { from: string; to: string }; } -export const useValuesList = ({ sourceField, indexPattern, query, filters }: Props) => { +export const useValuesList = ({ + sourceField, + indexPattern, + query = '', + filters, + time, +}: Props): { values: string[]; loading?: boolean } => { const { services: { data }, } = useKibana<{ data: DataPublicPluginStart }>(); - const { data: values, status } = useFetcher(() => { + const { from, to } = time ?? {}; + + const { data: values, loading } = useFetcher(() => { + if (!sourceField || !indexPattern) { + return []; + } return data.autocomplete.getValueSuggestions({ indexPattern, query: query || '', - field: indexPattern.fields.find(({ name }) => name === sourceField)!, - boolFilter: filters ?? [], + useTimeRange: !(from && to), + field: indexPattern.getFieldByName(sourceField)!, + boolFilter: + from && to + ? [ + ...(filters || []), + { + range: { + '@timestamp': { + gte: from, + lte: to, + }, + }, + }, + ] + : filters || [], }); - }, [sourceField, query, data.autocomplete, indexPattern, filters]); + }, [query, sourceField, data.autocomplete, indexPattern, from, to, filters]); - return { values, loading: status === 'loading' || status === 'pending' }; + return { values: values as string[], loading }; }; diff --git a/x-pack/plugins/observability/public/index.ts b/x-pack/plugins/observability/public/index.ts index 35443ca090077f..837404d273ee43 100644 --- a/x-pack/plugins/observability/public/index.ts +++ b/x-pack/plugins/observability/public/index.ts @@ -55,3 +55,4 @@ export * from './typings'; export { useChartTheme } from './hooks/use_chart_theme'; export { useTheme } from './hooks/use_theme'; export { getApmTraceUrl } from './utils/get_apm_trace_url'; +export { createExploratoryViewUrl } from './components/shared/exploratory_view/configurations/utils'; diff --git a/x-pack/plugins/observability/public/routes/index.tsx b/x-pack/plugins/observability/public/routes/index.tsx index 20817901dab82d..49cc55832dcf27 100644 --- a/x-pack/plugins/observability/public/routes/index.tsx +++ b/x-pack/plugins/observability/public/routes/index.tsx @@ -14,6 +14,7 @@ import { OverviewPage } from '../pages/overview'; import { jsonRt } from './json_rt'; import { AlertsPage } from '../pages/alerts'; import { CasesPage } from '../pages/cases'; +import { ExploratoryViewPage } from '../components/shared/exploratory_view'; export type RouteParams = DecodeParams; @@ -115,4 +116,24 @@ export const routes = { }, ], }, + '/exploratory-view': { + handler: () => { + return ; + }, + params: { + query: t.partial({ + rangeFrom: t.string, + rangeTo: t.string, + refreshPaused: jsonRt.pipe(t.boolean), + refreshInterval: jsonRt.pipe(t.number), + }), + }, + breadcrumb: [ + { + text: i18n.translate('xpack.observability.overview.exploratoryView', { + defaultMessage: 'Exploratory view', + }), + }, + ], + }, }; diff --git a/x-pack/plugins/observability/public/utils/observability_index_patterns.ts b/x-pack/plugins/observability/public/utils/observability_index_patterns.ts new file mode 100644 index 00000000000000..b23a2461055442 --- /dev/null +++ b/x-pack/plugins/observability/public/utils/observability_index_patterns.ts @@ -0,0 +1,64 @@ +/* + * 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 { DataPublicPluginStart, IndexPattern } from '../../../../../src/plugins/data/public'; + +export type DataType = 'synthetics' | 'apm' | 'logs' | 'metrics' | 'rum'; + +const indexPatternList: Record = { + synthetics: 'synthetics_static_index_pattern_id', + apm: 'apm_static_index_pattern_id', + rum: 'apm_static_index_pattern_id', + logs: 'logs_static_index_pattern_id', + metrics: 'metrics_static_index_pattern_id', +}; + +const appToPatternMap: Record = { + synthetics: 'heartbeat-*', + apm: 'apm-*', + rum: 'apm-*', + logs: 'logs-*,filebeat-*', + metrics: 'metrics-*,metricbeat-*', +}; + +export class ObservabilityIndexPatterns { + data?: DataPublicPluginStart; + + constructor(data: DataPublicPluginStart) { + this.data = data; + } + + async createIndexPattern(app: DataType) { + if (!this.data) { + throw new Error('data is not defined'); + } + + const pattern = appToPatternMap[app]; + + const fields = await this.data.indexPatterns.getFieldsForWildcard({ + pattern, + }); + + return await this.data.indexPatterns.createAndSave({ + fields, + title: pattern, + id: indexPatternList[app], + timeFieldName: '@timestamp', + }); + } + + async getIndexPattern(app: DataType): Promise { + if (!this.data) { + throw new Error('data is not defined'); + } + try { + return await this.data?.indexPatterns.get(indexPatternList[app]); + } catch (e) { + return await this.createIndexPattern(app || 'apm'); + } + } +} diff --git a/x-pack/plugins/observability/tsconfig.json b/x-pack/plugins/observability/tsconfig.json index 083c35a26c20bf..cc6e298795e4a3 100644 --- a/x-pack/plugins/observability/tsconfig.json +++ b/x-pack/plugins/observability/tsconfig.json @@ -7,7 +7,14 @@ "declaration": true, "declarationMap": true }, - "include": ["common/**/*", "public/**/*", "server/**/*", "typings/**/*"], + "include": [ + "common/**/*", + "public/**/*", + "public/**/*.json", + "server/**/*", + "typings/**/*", + "../../../typings/**/*" + ], "references": [ { "path": "../../../src/core/tsconfig.json" }, { "path": "../../../src/plugins/data/tsconfig.json" }, diff --git a/x-pack/plugins/uptime/public/apps/plugin.ts b/x-pack/plugins/uptime/public/apps/plugin.ts index e3457884594a98..7ea6b72547386b 100644 --- a/x-pack/plugins/uptime/public/apps/plugin.ts +++ b/x-pack/plugins/uptime/public/apps/plugin.ts @@ -68,18 +68,21 @@ export class UptimePlugin return UptimeDataHelper(coreStart); }; - plugins.observability.dashboard.register({ - appName: 'uptime', - hasData: async () => { - const dataHelper = await getUptimeDataHelper(); - const status = await dataHelper.indexStatus(); - return status.docCount > 0; - }, - fetchData: async (params: FetchDataParams) => { - const dataHelper = await getUptimeDataHelper(); - return await dataHelper.overviewData(params); - }, - }); + + if (plugins.observability) { + plugins.observability.dashboard.register({ + appName: 'uptime', + hasData: async () => { + const dataHelper = await getUptimeDataHelper(); + const status = await dataHelper.indexStatus(); + return status.docCount > 0; + }, + fetchData: async (params: FetchDataParams) => { + const dataHelper = await getUptimeDataHelper(); + return await dataHelper.overviewData(params); + }, + }); + } core.application.register({ id: PLUGIN.ID,