From 5840537777a067753204797a38ecbb4e35aecc1c Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Tue, 23 Jan 2024 15:20:51 +0000 Subject: [PATCH 01/15] [ML] Adding expanded rows to pattern analysis table --- .../create_category_request.ts | 2 +- .../process_category_results.ts | 1 + .../common/api/log_categorization/types.ts | 2 + .../category_table/category_table.tsx | 65 +++++++-- .../expanded_row/expanded_row.tsx | 49 +++++++ .../category_table/expanded_row/index.ts | 6 + .../log_categorization/formatted_text.tsx | 127 ++++++++++++++++++ 7 files changed, 239 insertions(+), 13 deletions(-) create mode 100644 x-pack/plugins/aiops/public/components/log_categorization/category_table/expanded_row/expanded_row.tsx create mode 100644 x-pack/plugins/aiops/public/components/log_categorization/category_table/expanded_row/index.ts create mode 100644 x-pack/plugins/aiops/public/components/log_categorization/formatted_text.tsx diff --git a/x-pack/plugins/aiops/common/api/log_categorization/create_category_request.ts b/x-pack/plugins/aiops/common/api/log_categorization/create_category_request.ts index 15b99f9d92cb4..1c5a4745064b5 100644 --- a/x-pack/plugins/aiops/common/api/log_categorization/create_category_request.ts +++ b/x-pack/plugins/aiops/common/api/log_categorization/create_category_request.ts @@ -15,7 +15,7 @@ import { createRandomSamplerWrapper } from '@kbn/ml-random-sampler-utils'; import { createCategorizeQuery } from './create_categorize_query'; const CATEGORY_LIMIT = 1000; -const EXAMPLE_LIMIT = 1; +const EXAMPLE_LIMIT = 4; export interface CategorizationAdditionalFilter { from: number; diff --git a/x-pack/plugins/aiops/common/api/log_categorization/process_category_results.ts b/x-pack/plugins/aiops/common/api/log_categorization/process_category_results.ts index a60c18d2a6651..e8a9cd6f37cdd 100644 --- a/x-pack/plugins/aiops/common/api/log_categorization/process_category_results.ts +++ b/x-pack/plugins/aiops/common/api/log_categorization/process_category_results.ts @@ -47,6 +47,7 @@ export function processCategoryResults( subFieldExamples: b.sub_time_range?.buckets[0].examples.hits.hits.map((h) => get(h._source, field)) ?? undefined, + regex: b.regex, }; }); return { diff --git a/x-pack/plugins/aiops/common/api/log_categorization/types.ts b/x-pack/plugins/aiops/common/api/log_categorization/types.ts index 25d9b4aad0f6d..445c976ef13c1 100644 --- a/x-pack/plugins/aiops/common/api/log_categorization/types.ts +++ b/x-pack/plugins/aiops/common/api/log_categorization/types.ts @@ -15,6 +15,7 @@ export interface Category { subFieldExamples?: string[]; examples: string[]; sparkline?: Record; + regex: string; } interface CategoryExamples { @@ -27,6 +28,7 @@ export interface CategoriesAgg { key: string; doc_count: number; examples: CategoryExamples; + regex: string; sparkline: { buckets: Array<{ key_as_string: string; key: number; doc_count: number }>; }; diff --git a/x-pack/plugins/aiops/public/components/log_categorization/category_table/category_table.tsx b/x-pack/plugins/aiops/public/components/log_categorization/category_table/category_table.tsx index 048ed1d1f91c2..0ec401b713703 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/category_table/category_table.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/category_table/category_table.tsx @@ -5,17 +5,16 @@ * 2.0. */ -import React, { FC, useMemo, useState } from 'react'; +import React, { FC, useCallback, useMemo, useState } from 'react'; import { useEuiBackgroundColor, EuiInMemoryTable, EuiBasicTableColumn, - EuiCode, - EuiText, EuiTableSelectionType, EuiHorizontalRule, EuiSpacer, + EuiButtonIcon, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -25,6 +24,7 @@ import { Filter } from '@kbn/es-query'; import { useTableState } from '@kbn/ml-in-memory-table'; import moment from 'moment'; +import { cloneDeep } from 'lodash'; import type { CategorizationAdditionalFilter } from '../../../../common/api/log_categorization/create_category_request'; import { type QueryMode, @@ -42,6 +42,8 @@ import type { EventRate } from '../use_categorize_request'; import { getLabels } from './labels'; import { TableHeader } from './table_header'; +import { ExpandedRow } from './expanded_row/expanded_row'; +import { FormattedPatternExamples } from '../formatted_text'; interface Props { categories: Category[]; @@ -83,6 +85,9 @@ export const CategoryTable: FC = ({ const { openInDiscoverWithFilter } = useDiscoverLinks(); const [selectedCategories, setSelectedCategories] = useState([]); const { onTableChange, pagination, sorting } = useTableState(categories ?? [], 'key'); + const [itemIdToExpandedRowMap, setItemIdToExpandedRowMap] = useState>( + {} + ); const labels = useMemo(() => { const isFlyout = onAddFilter !== undefined && onClose !== undefined; @@ -132,7 +137,48 @@ export const CategoryTable: FC = ({ ); }; + const toggleDetails = useCallback( + (category: Category) => { + const itemIdToExpandedRowMapValues = cloneDeep(itemIdToExpandedRowMap); + if (itemIdToExpandedRowMapValues[category.key]) { + delete itemIdToExpandedRowMapValues[category.key]; + } else { + const timefilterActiveBounds = timefilter.getActiveBounds(); + if (timefilterActiveBounds === undefined || selectedField === undefined) { + return; + } + itemIdToExpandedRowMapValues[category.key] = ( + {}} /> + ); + } + setItemIdToExpandedRowMap(itemIdToExpandedRowMapValues); + }, + [itemIdToExpandedRowMap, timefilter, selectedField] + ); + const columns: Array> = [ + { + align: 'left', + width: '40px', + isExpander: true, + render: (item: Category) => ( + toggleDetails(item)} + aria-label={ + itemIdToExpandedRowMap[item.key] + ? i18n.translate('xpack.ml.trainedModels.nodesList.collapseRow', { + defaultMessage: 'Collapse', + }) + : i18n.translate('xpack.ml.trainedModels.nodesList.expandRow', { + defaultMessage: 'Expand', + }) + } + iconType={itemIdToExpandedRowMap[item.key] ? 'arrowDown' : 'arrowRight'} + /> + ), + 'data-test-subj': 'mlNodesTableRowDetailsToggle', + }, { field: 'count', name: i18n.translate('xpack.aiops.logCategorization.column.count', { @@ -142,20 +188,13 @@ export const CategoryTable: FC = ({ width: '80px', }, { - field: 'examples', name: i18n.translate('xpack.aiops.logCategorization.column.examples', { defaultMessage: 'Examples', }), sortable: true, - render: (examples: string[]) => ( + render: (item: Category) => ( <> - {examples.map((e) => ( - - - {e} - - - ))} + ), }, @@ -271,6 +310,8 @@ export const CategoryTable: FC = ({ pagination={pagination} sorting={sorting} data-test-subj="aiopsLogPatternsTable" + isExpandable={true} + itemIdToExpandedRowMap={itemIdToExpandedRowMap} rowProps={(category) => { return enableRowActions ? { diff --git a/x-pack/plugins/aiops/public/components/log_categorization/category_table/expanded_row/expanded_row.tsx b/x-pack/plugins/aiops/public/components/log_categorization/category_table/expanded_row/expanded_row.tsx new file mode 100644 index 0000000000000..f93966580c5a0 --- /dev/null +++ b/x-pack/plugins/aiops/public/components/log_categorization/category_table/expanded_row/expanded_row.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, { FC } from 'react'; +import { EuiText, EuiSpacer } from '@elastic/eui'; + +import type { Category } from '../../../../../common/api/log_categorization/types'; +import { FormattedPatternExamples, FormattedRegex, FormattedTokens } from '../../formatted_text'; + +interface ExpandedRowProps { + category: Category; + onClose?(): void; +} + +export const ExpandedRow: FC = ({ category, onClose }) => { + return ( +
+ + + + Tokens + + + + + + + + Regex + + + + + + + + Examples + + + + + +
+ ); +}; diff --git a/x-pack/plugins/aiops/public/components/log_categorization/category_table/expanded_row/index.ts b/x-pack/plugins/aiops/public/components/log_categorization/category_table/expanded_row/index.ts new file mode 100644 index 0000000000000..1fec1c76430eb --- /dev/null +++ b/x-pack/plugins/aiops/public/components/log_categorization/category_table/expanded_row/index.ts @@ -0,0 +1,6 @@ +/* + * 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. + */ diff --git a/x-pack/plugins/aiops/public/components/log_categorization/formatted_text.tsx b/x-pack/plugins/aiops/public/components/log_categorization/formatted_text.tsx new file mode 100644 index 0000000000000..83ccfce285a58 --- /dev/null +++ b/x-pack/plugins/aiops/public/components/log_categorization/formatted_text.tsx @@ -0,0 +1,127 @@ +/* + * 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, { FC, useMemo } from 'react'; +import { EuiText, EuiHorizontalRule, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { css } from '@emotion/react'; +import type { Category } from '../../../common/api/log_categorization/types'; + +interface Props { + category: Category; + count?: number; +} + +const tokenStyle = css` + font-weight: bold; + color: #765b96; +`; +const wildcardStyle = css` + font-weight: bold; + color: #357160; +`; + +function createFormattedExample(key: string, example: string): JSX.Element[] { + const keyTokens = key.split(' '); + let tempExample = ` ${example} `; + const positions = keyTokens.map((t) => ({ + id: t, + start: 0, + end: 0, + })); + const elements: JSX.Element[] = []; + let offset = 0; + for (let i = 0; i < keyTokens.length; i++) { + const token = keyTokens[i]; + const tokenReg = new RegExp(`(\\W)(${token})(\\W)`); + + let j = 0; + const result = tokenReg.exec(tempExample); + if (!result) { + continue; + } + j = result.index; + positions[i].start = offset + j + 1; + positions[i].end = offset + j + token.length + 1; + tempExample = tempExample.slice(j + token.length + 1); + offset += j + token.length + 1; + } + + tempExample = ` ${example} `; + + elements.push({tempExample.substring(0, positions[0].start)}); + for (let i = 0; i < positions.length; i++) { + elements.push( + {tempExample.substring(positions[i].start, positions[i].end)} + ); + if (positions[i + 1]) { + elements.push( + + {tempExample.substring(positions[i].end, positions[i + 1].start)} + + ); + } + } + + elements.push( + {tempExample.substring(positions[positions.length - 1].end)} + ); + + return elements; +} + +export const FormattedPatternExamples: FC = ({ category, count }) => { + const e = useMemo(() => { + const { key, examples } = category; + const tempCount = + count === undefined || (count !== undefined && count > examples.length) + ? examples.length + : count; + const formattedExamples = new Array(tempCount) + .fill(0) + .map((_, i) => createFormattedExample(key, examples[i])); + return ( + + {formattedExamples.map((example, i) => ( + + {example} + {i < formattedExamples.length - 1 ? : null} + + ))} + + ); + }, [category, count]); + + return {e}; +}; + +export const FormattedRegex: FC = ({ category }) => { + const { regex } = category; + const formattedRegex = useMemo(() => { + const regexTokens = regex.split(/(\.\*\?)|(\.\+\?)/).filter((d) => d !== undefined); + const elements: JSX.Element[] = []; + for (let i = 0; i < regexTokens.length; i++) { + const token = regexTokens[i]; + if (token.match(/\.\*\?|\.\+\?/)) { + elements.push({token}); + } else { + elements.push({token}); + } + } + return elements; + }, [regex]); + return ( + + {formattedRegex} + + ); +}; + +export const FormattedTokens: FC = ({ category }) => ( + + {category.key} + +); From 056d997c170fb4a03d77fd0e22b1143432558e01 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Tue, 23 Jan 2024 15:27:22 +0000 Subject: [PATCH 02/15] translation ids --- .../log_categorization/category_table/category_table.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/aiops/public/components/log_categorization/category_table/category_table.tsx b/x-pack/plugins/aiops/public/components/log_categorization/category_table/category_table.tsx index 0ec401b713703..8307f176c2f40 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/category_table/category_table.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/category_table/category_table.tsx @@ -167,17 +167,17 @@ export const CategoryTable: FC = ({ onClick={() => toggleDetails(item)} aria-label={ itemIdToExpandedRowMap[item.key] - ? i18n.translate('xpack.ml.trainedModels.nodesList.collapseRow', { + ? i18n.translate('xpack.aiops.logCategorization.column.collapseRow', { defaultMessage: 'Collapse', }) - : i18n.translate('xpack.ml.trainedModels.nodesList.expandRow', { + : i18n.translate('xpack.aiops.logCategorization.column.expandRow', { defaultMessage: 'Expand', }) } iconType={itemIdToExpandedRowMap[item.key] ? 'arrowDown' : 'arrowRight'} /> ), - 'data-test-subj': 'mlNodesTableRowDetailsToggle', + 'data-test-subj': 'aiopsLogPatternsExpandRowToggle', }, { field: 'count', From 3b7736f6e281ef326634586458467b5256ebe8b0 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Tue, 23 Jan 2024 16:50:44 +0000 Subject: [PATCH 03/15] code clean up --- .../category_table/category_table.tsx | 2 +- .../expanded_row/expanded_row.tsx | 2 +- ...formatted_text.tsx => format_category.tsx} | 28 +++++++++++-------- 3 files changed, 18 insertions(+), 14 deletions(-) rename x-pack/plugins/aiops/public/components/log_categorization/{formatted_text.tsx => format_category.tsx} (83%) diff --git a/x-pack/plugins/aiops/public/components/log_categorization/category_table/category_table.tsx b/x-pack/plugins/aiops/public/components/log_categorization/category_table/category_table.tsx index 8307f176c2f40..4e1cad7914ae0 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/category_table/category_table.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/category_table/category_table.tsx @@ -43,7 +43,7 @@ import type { EventRate } from '../use_categorize_request'; import { getLabels } from './labels'; import { TableHeader } from './table_header'; import { ExpandedRow } from './expanded_row/expanded_row'; -import { FormattedPatternExamples } from '../formatted_text'; +import { FormattedPatternExamples } from '../format_category'; interface Props { categories: Category[]; diff --git a/x-pack/plugins/aiops/public/components/log_categorization/category_table/expanded_row/expanded_row.tsx b/x-pack/plugins/aiops/public/components/log_categorization/category_table/expanded_row/expanded_row.tsx index f93966580c5a0..3bd8eb006f7ab 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/category_table/expanded_row/expanded_row.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/category_table/expanded_row/expanded_row.tsx @@ -9,7 +9,7 @@ import React, { FC } from 'react'; import { EuiText, EuiSpacer } from '@elastic/eui'; import type { Category } from '../../../../../common/api/log_categorization/types'; -import { FormattedPatternExamples, FormattedRegex, FormattedTokens } from '../../formatted_text'; +import { FormattedPatternExamples, FormattedRegex, FormattedTokens } from '../../format_category'; interface ExpandedRowProps { category: Category; diff --git a/x-pack/plugins/aiops/public/components/log_categorization/formatted_text.tsx b/x-pack/plugins/aiops/public/components/log_categorization/format_category.tsx similarity index 83% rename from x-pack/plugins/aiops/public/components/log_categorization/formatted_text.tsx rename to x-pack/plugins/aiops/public/components/log_categorization/format_category.tsx index 83ccfce285a58..37544ec400f26 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/formatted_text.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/format_category.tsx @@ -32,8 +32,8 @@ function createFormattedExample(key: string, example: string): JSX.Element[] { start: 0, end: 0, })); - const elements: JSX.Element[] = []; let offset = 0; + // match each token in order and record the start and end position for (let i = 0; i < keyTokens.length; i++) { const token = keyTokens[i]; const tokenReg = new RegExp(`(\\W)(${token})(\\W)`); @@ -44,26 +44,30 @@ function createFormattedExample(key: string, example: string): JSX.Element[] { continue; } j = result.index; + const localEndOFToken = j + token.length + 1; positions[i].start = offset + j + 1; - positions[i].end = offset + j + token.length + 1; - tempExample = tempExample.slice(j + token.length + 1); - offset += j + token.length + 1; + positions[i].end = offset + localEndOFToken; + // slice the example string to remove the token and preceding text + // to ensure we don't match future tokens in earlier text + tempExample = tempExample.slice(localEndOFToken); + offset += localEndOFToken; } tempExample = ` ${example} `; - elements.push({tempExample.substring(0, positions[0].start)}); + // build up the list ot elements by chopping up the example string + // using the token positions found above + const elements: JSX.Element[] = []; + let pos = 0; for (let i = 0; i < positions.length; i++) { + elements.push( + {tempExample.substring(pos, positions[i].start)} + ); + elements.push( {tempExample.substring(positions[i].start, positions[i].end)} ); - if (positions[i + 1]) { - elements.push( - - {tempExample.substring(positions[i].end, positions[i + 1].start)} - - ); - } + pos = positions[i].end; } elements.push( From c960620215598627d573122308a23c4f6d2e772f Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Wed, 24 Jan 2024 09:54:50 +0000 Subject: [PATCH 04/15] code clean up --- .../log_categorization/format_category.tsx | 37 ++++++++++--------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/x-pack/plugins/aiops/public/components/log_categorization/format_category.tsx b/x-pack/plugins/aiops/public/components/log_categorization/format_category.tsx index 37544ec400f26..399039ab858ba 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/format_category.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/format_category.tsx @@ -6,7 +6,7 @@ */ import React, { FC, useMemo } from 'react'; -import { EuiText, EuiHorizontalRule, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { EuiText, EuiHorizontalRule } from '@elastic/eui'; import { css } from '@emotion/react'; import type { Category } from '../../../common/api/log_categorization/types'; @@ -16,13 +16,14 @@ interface Props { } const tokenStyle = css` - font-weight: bold; color: #765b96; `; const wildcardStyle = css` - font-weight: bold; color: #357160; `; +const generalStyle = css` + font-weight: bold; +`; function createFormattedExample(key: string, example: string): JSX.Element[] { const keyTokens = key.split(' '); @@ -87,19 +88,15 @@ export const FormattedPatternExamples: FC = ({ category, count }) => { const formattedExamples = new Array(tempCount) .fill(0) .map((_, i) => createFormattedExample(key, examples[i])); - return ( - - {formattedExamples.map((example, i) => ( - - {example} - {i < formattedExamples.length - 1 ? : null} - - ))} - - ); + return formattedExamples.map((example, i) => ( + <> + {example} + {i < formattedExamples.length - 1 ? : null} + + )); }, [category, count]); - return {e}; + return {e}; }; export const FormattedRegex: FC = ({ category }) => { @@ -118,14 +115,20 @@ export const FormattedRegex: FC = ({ category }) => { return elements; }, [regex]); return ( - + {formattedRegex} - + ); }; export const FormattedTokens: FC = ({ category }) => ( - + {category.key} + +); + +const WrapInText: FC = ({ children }) => ( + + {children} ); From 619fd7748f753ef233433f0b90c3a6554b5af1f5 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Wed, 24 Jan 2024 10:20:05 +0000 Subject: [PATCH 05/15] translations and code clean up --- .../category_table/category_table.tsx | 13 +---- .../expanded_row/expanded_row.tsx | 55 ++++++++++++------- .../log_categorization/format_category.tsx | 5 +- 3 files changed, 38 insertions(+), 35 deletions(-) diff --git a/x-pack/plugins/aiops/public/components/log_categorization/category_table/category_table.tsx b/x-pack/plugins/aiops/public/components/log_categorization/category_table/category_table.tsx index 4e1cad7914ae0..e7e5d9a67303d 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/category_table/category_table.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/category_table/category_table.tsx @@ -24,7 +24,6 @@ import { Filter } from '@kbn/es-query'; import { useTableState } from '@kbn/ml-in-memory-table'; import moment from 'moment'; -import { cloneDeep } from 'lodash'; import type { CategorizationAdditionalFilter } from '../../../../common/api/log_categorization/create_category_request'; import { type QueryMode, @@ -139,21 +138,15 @@ export const CategoryTable: FC = ({ const toggleDetails = useCallback( (category: Category) => { - const itemIdToExpandedRowMapValues = cloneDeep(itemIdToExpandedRowMap); + const itemIdToExpandedRowMapValues = { ...itemIdToExpandedRowMap }; if (itemIdToExpandedRowMapValues[category.key]) { delete itemIdToExpandedRowMapValues[category.key]; } else { - const timefilterActiveBounds = timefilter.getActiveBounds(); - if (timefilterActiveBounds === undefined || selectedField === undefined) { - return; - } - itemIdToExpandedRowMapValues[category.key] = ( - {}} /> - ); + itemIdToExpandedRowMapValues[category.key] = ; } setItemIdToExpandedRowMap(itemIdToExpandedRowMapValues); }, - [itemIdToExpandedRowMap, timefilter, selectedField] + [itemIdToExpandedRowMap] ); const columns: Array> = [ diff --git a/x-pack/plugins/aiops/public/components/log_categorization/category_table/expanded_row/expanded_row.tsx b/x-pack/plugins/aiops/public/components/log_categorization/category_table/expanded_row/expanded_row.tsx index 3bd8eb006f7ab..0c3d50fc73ace 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/category_table/expanded_row/expanded_row.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/category_table/expanded_row/expanded_row.tsx @@ -7,43 +7,56 @@ import React, { FC } from 'react'; import { EuiText, EuiSpacer } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import type { Category } from '../../../../../common/api/log_categorization/types'; import { FormattedPatternExamples, FormattedRegex, FormattedTokens } from '../../format_category'; interface ExpandedRowProps { category: Category; - onClose?(): void; } -export const ExpandedRow: FC = ({ category, onClose }) => { +export const ExpandedRow: FC = ({ category }) => { return (
- - Tokens - - - - - - - - Regex - - - - - +
+ +
+ +
+ +
+ +
+ +
+
+ ); +}; +const Section: FC<{ title: string }> = ({ title, children }) => { + return ( + <> - Examples + {title} - - + {children} - + ); }; diff --git a/x-pack/plugins/aiops/public/components/log_categorization/format_category.tsx b/x-pack/plugins/aiops/public/components/log_categorization/format_category.tsx index 399039ab858ba..b213d79d59c69 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/format_category.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/format_category.tsx @@ -21,9 +21,6 @@ const tokenStyle = css` const wildcardStyle = css` color: #357160; `; -const generalStyle = css` - font-weight: bold; -`; function createFormattedExample(key: string, example: string): JSX.Element[] { const keyTokens = key.split(' '); @@ -128,7 +125,7 @@ export const FormattedTokens: FC = ({ category }) => ( ); const WrapInText: FC = ({ children }) => ( - + {children} ); From a05d315a984370ff82cce0599c8c432fdb921b05 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Wed, 24 Jan 2024 11:28:02 +0000 Subject: [PATCH 06/15] adding tests --- .../format_category.test.tsx.snap | 92 +++++++++++++++++++ .../format_category.test.tsx | 53 +++++++++++ .../log_categorization/format_category.tsx | 7 +- 3 files changed, 147 insertions(+), 5 deletions(-) create mode 100644 x-pack/plugins/aiops/public/components/log_categorization/__snapshots__/format_category.test.tsx.snap create mode 100644 x-pack/plugins/aiops/public/components/log_categorization/format_category.test.tsx diff --git a/x-pack/plugins/aiops/public/components/log_categorization/__snapshots__/format_category.test.tsx.snap b/x-pack/plugins/aiops/public/components/log_categorization/__snapshots__/format_category.test.tsx.snap new file mode 100644 index 0000000000000..d0eb24beff1bc --- /dev/null +++ b/x-pack/plugins/aiops/public/components/log_categorization/__snapshots__/format_category.test.tsx.snap @@ -0,0 +1,92 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`FormattedPatternExamples renders each category correctly 1`] = ` + +`; + +exports[`FormattedPatternExamples renders each category correctly 2`] = ` + +`; + +exports[`FormattedPatternExamples renders each category correctly 3`] = ` + +`; + +exports[`FormattedPatternExamples renders each category correctly 4`] = ` + +`; + +exports[`FormattedPatternExamples renders each category correctly 5`] = ` + +`; + +exports[`FormattedPatternExamples renders each category correctly 6`] = ` + +`; + +exports[`FormattedPatternExamples renders each category correctly 7`] = ` + +`; diff --git a/x-pack/plugins/aiops/public/components/log_categorization/format_category.test.tsx b/x-pack/plugins/aiops/public/components/log_categorization/format_category.test.tsx new file mode 100644 index 0000000000000..27348caad8f89 --- /dev/null +++ b/x-pack/plugins/aiops/public/components/log_categorization/format_category.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 type { Category } from '../../../common/api/log_categorization/types'; +import { FormattedPatternExamples } from './format_category'; + +const categories = [ + { + key: 'Processed messages out of', + examples: ['Processed 676 messages out of 676'], + }, + { + key: 'Processed messages out of', + examples: ['Processed out 676 messages messages out of 676 Processed'], + }, + { + key: 'Processed of', + examples: ['Processed 676 messages out of 676'], + }, + { + key: 'Processed messages out of', + examples: ['Processed messages out of'], + }, + { + key: '', + examples: ['Processed messages out of'], + }, + { + key: 'Processed messages out of', + examples: ['Processed 676 (*?) message* out of 676'], + }, + { + key: '2024 0000 admin to admin console.prod 6000 api HTTP 1.1 https admin Mozilla 5.0 AppleWebKit KHTML like Gecko Chrome Safari', + examples: [ + '[05/Jan/2024 04:11:42 +0000] 40.69.144.53 - Lucio77 admin-console.you-got.mail to: admin-console.prod.008:6000: "GET /api/listCustomers HTTP/1.1" 200 383 "https://admin-console.you-got.mail" "Mozilla/5.0 (Windows; U; Windows NT 6.3) AppleWebKit/531.1.1 (KHTML, like Gecko) Chrome/23.0.835.0 Safari/531.1.1"', + ], + }, +] as Category[]; + +describe('FormattedPatternExamples', () => { + it('renders each category correctly', () => { + categories.forEach((category) => { + const component = ; + expect(component).toMatchSnapshot(); + }); + }); +}); diff --git a/x-pack/plugins/aiops/public/components/log_categorization/format_category.tsx b/x-pack/plugins/aiops/public/components/log_categorization/format_category.tsx index b213d79d59c69..57c37be49f312 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/format_category.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/format_category.tsx @@ -22,7 +22,7 @@ const wildcardStyle = css` color: #357160; `; -function createFormattedExample(key: string, example: string): JSX.Element[] { +export function createFormattedExample(key: string, example: string): JSX.Element[] { const keyTokens = key.split(' '); let tempExample = ` ${example} `; const positions = keyTokens.map((t) => ({ @@ -78,10 +78,7 @@ function createFormattedExample(key: string, example: string): JSX.Element[] { export const FormattedPatternExamples: FC = ({ category, count }) => { const e = useMemo(() => { const { key, examples } = category; - const tempCount = - count === undefined || (count !== undefined && count > examples.length) - ? examples.length - : count; + const tempCount = count === undefined || count > examples.length ? examples.length : count; const formattedExamples = new Array(tempCount) .fill(0) .map((_, i) => createFormattedExample(key, examples[i])); From 8575e44a64c5a0d0d2ed67cd26ffec3f11853d38 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Wed, 24 Jan 2024 11:36:14 +0000 Subject: [PATCH 07/15] updating tests --- .../format_category.test.tsx.snap | 213 +++++++++++++++++- .../format_category.test.tsx | 15 +- 2 files changed, 220 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/aiops/public/components/log_categorization/__snapshots__/format_category.test.tsx.snap b/x-pack/plugins/aiops/public/components/log_categorization/__snapshots__/format_category.test.tsx.snap index d0eb24beff1bc..32e424859a1c5 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/__snapshots__/format_category.test.tsx.snap +++ b/x-pack/plugins/aiops/public/components/log_categorization/__snapshots__/format_category.test.tsx.snap @@ -8,12 +8,41 @@ exports[`FormattedPatternExamples renders each category correctly 1`] = ` "Processed 676 messages out of 676", ], "key": "Processed messages out of", + "regex": ".*?Processed.+?messages.+?out.+?of.*?", } } /> `; exports[`FormattedPatternExamples renders each category correctly 2`] = ` + +`; + +exports[`FormattedPatternExamples renders each category correctly 3`] = ` + +`; + +exports[`FormattedPatternExamples renders each category correctly 4`] = ` `; -exports[`FormattedPatternExamples renders each category correctly 3`] = ` +exports[`FormattedPatternExamples renders each category correctly 5`] = ` + +`; + +exports[`FormattedPatternExamples renders each category correctly 6`] = ` + +`; + +exports[`FormattedPatternExamples renders each category correctly 7`] = ` `; -exports[`FormattedPatternExamples renders each category correctly 4`] = ` +exports[`FormattedPatternExamples renders each category correctly 8`] = ` + +`; + +exports[`FormattedPatternExamples renders each category correctly 9`] = ` + +`; + +exports[`FormattedPatternExamples renders each category correctly 10`] = ` `; -exports[`FormattedPatternExamples renders each category correctly 5`] = ` +exports[`FormattedPatternExamples renders each category correctly 11`] = ` + +`; + +exports[`FormattedPatternExamples renders each category correctly 12`] = ` + +`; + +exports[`FormattedPatternExamples renders each category correctly 13`] = ` `; -exports[`FormattedPatternExamples renders each category correctly 6`] = ` +exports[`FormattedPatternExamples renders each category correctly 14`] = ` + +`; + +exports[`FormattedPatternExamples renders each category correctly 15`] = ` + +`; + +exports[`FormattedPatternExamples renders each category correctly 16`] = ` `; -exports[`FormattedPatternExamples renders each category correctly 7`] = ` +exports[`FormattedPatternExamples renders each category correctly 17`] = ` + +`; + +exports[`FormattedPatternExamples renders each category correctly 18`] = ` + +`; + +exports[`FormattedPatternExamples renders each category correctly 19`] = ` +`; + +exports[`FormattedPatternExamples renders each category correctly 20`] = ` + +`; + +exports[`FormattedPatternExamples renders each category correctly 21`] = ` + diff --git a/x-pack/plugins/aiops/public/components/log_categorization/format_category.test.tsx b/x-pack/plugins/aiops/public/components/log_categorization/format_category.test.tsx index 27348caad8f89..a77e151709853 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/format_category.test.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/format_category.test.tsx @@ -8,46 +8,55 @@ import React from 'react'; import type { Category } from '../../../common/api/log_categorization/types'; -import { FormattedPatternExamples } from './format_category'; +import { FormattedPatternExamples, FormattedRegex, FormattedTokens } from './format_category'; const categories = [ { key: 'Processed messages out of', examples: ['Processed 676 messages out of 676'], + regex: '.*?Processed.+?messages.+?out.+?of.*?', }, { key: 'Processed messages out of', examples: ['Processed out 676 messages messages out of 676 Processed'], + regex: '.*?Processed.+?messages.+?out.+?of.*?', }, { key: 'Processed of', examples: ['Processed 676 messages out of 676'], + regex: '.*?Processed.+?of.*?', }, { key: 'Processed messages out of', examples: ['Processed messages out of'], + regex: '.*?Processed.+?messages.+?out.+?of.*?', }, { key: '', examples: ['Processed messages out of'], + regex: '.*?', }, { key: 'Processed messages out of', examples: ['Processed 676 (*?) message* out of 676'], + regex: '.*?Processed.+?messages.+?out.+?of.*?', }, { key: '2024 0000 admin to admin console.prod 6000 api HTTP 1.1 https admin Mozilla 5.0 AppleWebKit KHTML like Gecko Chrome Safari', examples: [ '[05/Jan/2024 04:11:42 +0000] 40.69.144.53 - Lucio77 admin-console.you-got.mail to: admin-console.prod.008:6000: "GET /api/listCustomers HTTP/1.1" 200 383 "https://admin-console.you-got.mail" "Mozilla/5.0 (Windows; U; Windows NT 6.3) AppleWebKit/531.1.1 (KHTML, like Gecko) Chrome/23.0.835.0 Safari/531.1.1"', ], + regex: + '.*?2024.+?0000.+?admin.+?to.+?admin.+?console.prod.+?6000.+?api.+?HTTP.+?1.1.+?https.+?admin.+?Mozilla.+?5.0.+?AppleWebKit.+?KHTML.+?like.+?Gecko.+?Chrome.+?Safari.*?', }, ] as Category[]; describe('FormattedPatternExamples', () => { it('renders each category correctly', () => { categories.forEach((category) => { - const component = ; - expect(component).toMatchSnapshot(); + expect().toMatchSnapshot(); + expect().toMatchSnapshot(); + expect().toMatchSnapshot(); }); }); }); From 1fb224944c52e741db71901fcf6aa68e669370eb Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Wed, 24 Jan 2024 11:37:12 +0000 Subject: [PATCH 08/15] removing export --- .../public/components/log_categorization/format_category.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/aiops/public/components/log_categorization/format_category.tsx b/x-pack/plugins/aiops/public/components/log_categorization/format_category.tsx index 57c37be49f312..bfdaa133897a0 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/format_category.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/format_category.tsx @@ -22,7 +22,7 @@ const wildcardStyle = css` color: #357160; `; -export function createFormattedExample(key: string, example: string): JSX.Element[] { +function createFormattedExample(key: string, example: string): JSX.Element[] { const keyTokens = key.split(' '); let tempExample = ` ${example} `; const positions = keyTokens.map((t) => ({ From 1a8167317d0f408831c3a41bc7c8dca575329654 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Wed, 24 Jan 2024 13:34:06 +0000 Subject: [PATCH 09/15] fixing dark mode --- .../category_table/category_table.tsx | 2 +- .../log_categorization/format_category.tsx | 148 +++++++++++------- .../aiops/public/hooks/use_eui_theme.ts | 7 +- 3 files changed, 101 insertions(+), 56 deletions(-) diff --git a/x-pack/plugins/aiops/public/components/log_categorization/category_table/category_table.tsx b/x-pack/plugins/aiops/public/components/log_categorization/category_table/category_table.tsx index e7e5d9a67303d..7efbe1f0315d1 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/category_table/category_table.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/category_table/category_table.tsx @@ -219,7 +219,7 @@ export const CategoryTable: FC = ({ ] as Array>; if (showSparkline === true) { - columns.splice(1, 0, { + columns.splice(2, 0, { field: 'sparkline', name: i18n.translate('xpack.aiops.logCategorization.column.logRate', { defaultMessage: 'Log rate', diff --git a/x-pack/plugins/aiops/public/components/log_categorization/format_category.tsx b/x-pack/plugins/aiops/public/components/log_categorization/format_category.tsx index bfdaa133897a0..699097caa3499 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/format_category.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/format_category.tsx @@ -7,75 +7,109 @@ import React, { FC, useMemo } from 'react'; import { EuiText, EuiHorizontalRule } from '@elastic/eui'; -import { css } from '@emotion/react'; +import { css, SerializedStyles } from '@emotion/react'; import type { Category } from '../../../common/api/log_categorization/types'; +import { useIsDarkTheme } from '../../hooks/use_eui_theme'; interface Props { category: Category; count?: number; } -const tokenStyle = css` +// copies of the syntax colors used in EuiCode +const tokenStyleLight = css` color: #765b96; `; -const wildcardStyle = css` +const wildcardStyleLight = css` color: #357160; `; +const tokenStyleDark = css` + color: #a68ac5; +`; +const wildcardStyleDark = css` + color: #54b399; +`; + +interface Styles { + tokenStyle: SerializedStyles; + wildcardStyle: SerializedStyles; +} + +const useStyles = (): Styles => { + const isDarkTheme = useIsDarkTheme(); + return isDarkTheme + ? { + tokenStyle: tokenStyleDark, + wildcardStyle: wildcardStyleDark, + } + : { + tokenStyle: tokenStyleLight, + wildcardStyle: wildcardStyleLight, + }; +}; + +const useCreateFormattedExample = () => { + const { tokenStyle, wildcardStyle } = useStyles(); -function createFormattedExample(key: string, example: string): JSX.Element[] { - const keyTokens = key.split(' '); - let tempExample = ` ${example} `; - const positions = keyTokens.map((t) => ({ - id: t, - start: 0, - end: 0, - })); - let offset = 0; - // match each token in order and record the start and end position - for (let i = 0; i < keyTokens.length; i++) { - const token = keyTokens[i]; - const tokenReg = new RegExp(`(\\W)(${token})(\\W)`); - - let j = 0; - const result = tokenReg.exec(tempExample); - if (!result) { - continue; + function createFormattedExample(key: string, example: string): JSX.Element[] { + const keyTokens = key.split(' '); + let tempExample = ` ${example} `; + const positions = keyTokens.map((t) => ({ + id: t, + start: 0, + end: 0, + })); + let offset = 0; + // match each token in order and record the start and end position + for (let i = 0; i < keyTokens.length; i++) { + const token = keyTokens[i]; + const tokenReg = new RegExp(`(\\W)(${token})(\\W)`); + + let j = 0; + const result = tokenReg.exec(tempExample); + if (!result) { + continue; + } + j = result.index; + const localEndOFToken = j + token.length + 1; + positions[i].start = offset + j + 1; + positions[i].end = offset + localEndOFToken; + // slice the example string to remove the token and preceding text + // to ensure we don't match future tokens in earlier text + tempExample = tempExample.slice(localEndOFToken); + offset += localEndOFToken; } - j = result.index; - const localEndOFToken = j + token.length + 1; - positions[i].start = offset + j + 1; - positions[i].end = offset + localEndOFToken; - // slice the example string to remove the token and preceding text - // to ensure we don't match future tokens in earlier text - tempExample = tempExample.slice(localEndOFToken); - offset += localEndOFToken; - } - tempExample = ` ${example} `; + tempExample = ` ${example} `; - // build up the list ot elements by chopping up the example string - // using the token positions found above - const elements: JSX.Element[] = []; - let pos = 0; - for (let i = 0; i < positions.length; i++) { - elements.push( - {tempExample.substring(pos, positions[i].start)} - ); + // build up the list ot elements by chopping up the example string + // using the token positions found above + const elements: JSX.Element[] = []; + let pos = 0; + for (let i = 0; i < positions.length; i++) { + elements.push( + {tempExample.substring(pos, positions[i].start)} + ); + + elements.push( + {tempExample.substring(positions[i].start, positions[i].end)} + ); + pos = positions[i].end; + } elements.push( - {tempExample.substring(positions[i].start, positions[i].end)} + {tempExample.substring(positions[positions.length - 1].end)} ); - pos = positions[i].end; - } - elements.push( - {tempExample.substring(positions[positions.length - 1].end)} - ); + return elements; + } - return elements; -} + return { createFormattedExample }; +}; export const FormattedPatternExamples: FC = ({ category, count }) => { + const { createFormattedExample } = useCreateFormattedExample(); + const e = useMemo(() => { const { key, examples } = category; const tempCount = count === undefined || count > examples.length ? examples.length : count; @@ -88,12 +122,14 @@ export const FormattedPatternExamples: FC = ({ category, count }) => { {i < formattedExamples.length - 1 ? : null} )); - }, [category, count]); + }, [category, count, createFormattedExample]); return {e}; }; export const FormattedRegex: FC = ({ category }) => { + const { tokenStyle, wildcardStyle } = useStyles(); + const { regex } = category; const formattedRegex = useMemo(() => { const regexTokens = regex.split(/(\.\*\?)|(\.\+\?)/).filter((d) => d !== undefined); @@ -107,7 +143,7 @@ export const FormattedRegex: FC = ({ category }) => { } } return elements; - }, [regex]); + }, [regex, tokenStyle, wildcardStyle]); return ( {formattedRegex} @@ -115,11 +151,15 @@ export const FormattedRegex: FC = ({ category }) => { ); }; -export const FormattedTokens: FC = ({ category }) => ( - - {category.key} - -); +export const FormattedTokens: FC = ({ category }) => { + const { tokenStyle } = useStyles(); + + return ( + + {category.key} + + ); +}; const WrapInText: FC = ({ children }) => ( diff --git a/x-pack/plugins/aiops/public/hooks/use_eui_theme.ts b/x-pack/plugins/aiops/public/hooks/use_eui_theme.ts index fa1374a22800b..7da2bd6be954a 100644 --- a/x-pack/plugins/aiops/public/hooks/use_eui_theme.ts +++ b/x-pack/plugins/aiops/public/hooks/use_eui_theme.ts @@ -5,10 +5,15 @@ * 2.0. */ -import { useCurrentEuiThemeVars } from '@kbn/ml-kibana-theme'; +import { useCurrentEuiThemeVars, useIsDarkTheme as useIsDarkThemeMl } from '@kbn/ml-kibana-theme'; import { useAiopsAppContext } from './use_aiops_app_context'; export function useEuiTheme() { const { theme } = useAiopsAppContext(); return useCurrentEuiThemeVars(theme).euiTheme; } + +export function useIsDarkTheme() { + const { theme } = useAiopsAppContext(); + return useIsDarkThemeMl(theme); +} From bbe71a2db251f417bfaf7563131e5d27bf1b0179 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Wed, 24 Jan 2024 17:14:24 +0000 Subject: [PATCH 10/15] fixing tests --- .../routes/log_rate_analysis/queries/fetch_categories.test.ts | 2 +- .../test/functional/services/aiops/log_pattern_analysis_page.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_categories.test.ts b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_categories.test.ts index 8d43c552a443e..e6e79108435e2 100644 --- a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_categories.test.ts +++ b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_categories.test.ts @@ -145,7 +145,7 @@ describe('getCategoryRequest', () => { }, aggs: { examples: { - top_hits: { size: 1, sort: ['the-time-field-name'], _source: 'the-field-name' }, + top_hits: { size: 4, sort: ['the-time-field-name'], _source: 'the-field-name' }, }, }, }, diff --git a/x-pack/test/functional/services/aiops/log_pattern_analysis_page.ts b/x-pack/test/functional/services/aiops/log_pattern_analysis_page.ts index 18b5004393027..4ee9f40b3f55d 100644 --- a/x-pack/test/functional/services/aiops/log_pattern_analysis_page.ts +++ b/x-pack/test/functional/services/aiops/log_pattern_analysis_page.ts @@ -128,7 +128,7 @@ export function LogPatternAnalysisPageProvider({ getService, getPageObject }: Ft const rows = await tableListContainer.findAllByClassName('euiTableRow'); const row = rows[rowIndex]; const cells = await row.findAllByClassName('euiTableRowCell'); - return Number(await cells[0].getVisibleText()); + return Number(await cells[1].getVisibleText()); }, async assertDiscoverDocCountExists() { From 9162fbaaf1dc27fb6a1722a7be50a623a836bb1e Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Wed, 24 Jan 2024 18:16:48 +0000 Subject: [PATCH 11/15] fixing types --- .../utils/build_extended_base_filter_criteria.ts | 3 +++ .../log_categorization/category_table/category_table.tsx | 2 +- .../category_table/{expanded_row => }/expanded_row.tsx | 4 ++-- .../log_categorization/category_table/expanded_row/index.ts | 6 ------ .../log_rate_analysis_results_table.tsx | 1 + .../analysis_handlers/histogram_handler.ts | 2 +- .../routes/log_rate_analysis/queries/fetch_categories.ts | 1 + .../log_rate_analysis/queries/fetch_category_counts.test.ts | 4 +++- .../queries/fetch_terms_2_categories_counts.ts | 4 ++-- .../routes/log_rate_analysis/queries/get_group_filter.ts | 1 + 10 files changed, 15 insertions(+), 13 deletions(-) rename x-pack/plugins/aiops/public/components/log_categorization/category_table/{expanded_row => }/expanded_row.tsx (93%) delete mode 100644 x-pack/plugins/aiops/public/components/log_categorization/category_table/expanded_row/index.ts diff --git a/x-pack/plugins/aiops/public/application/utils/build_extended_base_filter_criteria.ts b/x-pack/plugins/aiops/public/application/utils/build_extended_base_filter_criteria.ts index d01951b6b8655..ea3ee8b528d38 100644 --- a/x-pack/plugins/aiops/public/application/utils/build_extended_base_filter_criteria.ts +++ b/x-pack/plugins/aiops/public/application/utils/build_extended_base_filter_criteria.ts @@ -50,6 +50,7 @@ export function buildExtendedBaseFilterCriteria( key, count: docCount, examples: [], + regex: '', }, ]) ); @@ -70,6 +71,7 @@ export function buildExtendedBaseFilterCriteria( key: `${selectedSignificantItem.key}`, count: selectedSignificantItem.doc_count, examples: [], + regex: '', }, ]) ); @@ -97,6 +99,7 @@ export function buildExtendedBaseFilterCriteria( key: `${selectedSignificantItem.key}`, count: selectedSignificantItem.doc_count, examples: [], + regex: '', }, ]), ], diff --git a/x-pack/plugins/aiops/public/components/log_categorization/category_table/category_table.tsx b/x-pack/plugins/aiops/public/components/log_categorization/category_table/category_table.tsx index 7efbe1f0315d1..b3f68ce120795 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/category_table/category_table.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/category_table/category_table.tsx @@ -41,7 +41,7 @@ import type { EventRate } from '../use_categorize_request'; import { getLabels } from './labels'; import { TableHeader } from './table_header'; -import { ExpandedRow } from './expanded_row/expanded_row'; +import { ExpandedRow } from './expanded_row'; import { FormattedPatternExamples } from '../format_category'; interface Props { diff --git a/x-pack/plugins/aiops/public/components/log_categorization/category_table/expanded_row/expanded_row.tsx b/x-pack/plugins/aiops/public/components/log_categorization/category_table/expanded_row.tsx similarity index 93% rename from x-pack/plugins/aiops/public/components/log_categorization/category_table/expanded_row/expanded_row.tsx rename to x-pack/plugins/aiops/public/components/log_categorization/category_table/expanded_row.tsx index 0c3d50fc73ace..fe19b67595814 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/category_table/expanded_row/expanded_row.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/category_table/expanded_row.tsx @@ -9,8 +9,8 @@ import React, { FC } from 'react'; import { EuiText, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import type { Category } from '../../../../../common/api/log_categorization/types'; -import { FormattedPatternExamples, FormattedRegex, FormattedTokens } from '../../format_category'; +import type { Category } from '../../../../common/api/log_categorization/types'; +import { FormattedPatternExamples, FormattedRegex, FormattedTokens } from '../format_category'; interface ExpandedRowProps { category: Category; diff --git a/x-pack/plugins/aiops/public/components/log_categorization/category_table/expanded_row/index.ts b/x-pack/plugins/aiops/public/components/log_categorization/category_table/expanded_row/index.ts deleted file mode 100644 index 1fec1c76430eb..0000000000000 --- a/x-pack/plugins/aiops/public/components/log_categorization/category_table/expanded_row/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ diff --git a/x-pack/plugins/aiops/public/components/log_rate_analysis_results_table/log_rate_analysis_results_table.tsx b/x-pack/plugins/aiops/public/components/log_rate_analysis_results_table/log_rate_analysis_results_table.tsx index b0b4d699919be..55de63e7fb25d 100644 --- a/x-pack/plugins/aiops/public/components/log_rate_analysis_results_table/log_rate_analysis_results_table.tsx +++ b/x-pack/plugins/aiops/public/components/log_rate_analysis_results_table/log_rate_analysis_results_table.tsx @@ -136,6 +136,7 @@ export const LogRateAnalysisResultsTable: FC = key, count, examples: [], + regex: '', }, ]); return ( diff --git a/x-pack/plugins/aiops/server/routes/log_rate_analysis/analysis_handlers/histogram_handler.ts b/x-pack/plugins/aiops/server/routes/log_rate_analysis/analysis_handlers/histogram_handler.ts index 1ddb624c99056..35c6d74fcf83f 100644 --- a/x-pack/plugins/aiops/server/routes/log_rate_analysis/analysis_handlers/histogram_handler.ts +++ b/x-pack/plugins/aiops/server/routes/log_rate_analysis/analysis_handlers/histogram_handler.ts @@ -181,7 +181,7 @@ export const histogramHandlerFactory = const significantCategoriesHistogramQueries = significantCategories.map((d) => { const histogramQuery = getHistogramQuery(requestBody); const categoryQuery = getCategoryQuery(d.fieldName, [ - { key: `${d.key}`, count: d.doc_count, examples: [] }, + { key: `${d.key}`, count: d.doc_count, examples: [], regex: '' }, ]); if (Array.isArray(histogramQuery.bool?.filter)) { histogramQuery.bool?.filter?.push(categoryQuery); diff --git a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_categories.ts b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_categories.ts index 48fb888e58430..bbb64bc95cd30 100644 --- a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_categories.ts +++ b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_categories.ts @@ -169,6 +169,7 @@ export const fetchCategories = async ( count: b.doc_count, examples: b.examples.hits.hits.map((h) => get(h._source, fieldName)), sparkline, + regex: b.regex, }; }); result.push({ diff --git a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_category_counts.test.ts b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_category_counts.test.ts index b3fa6ff5f31a8..1593bf7dd5b18 100644 --- a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_category_counts.test.ts +++ b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_category_counts.test.ts @@ -15,6 +15,7 @@ describe('getCategoryCountRequest', () => { key: 'runTask ended no files to process', count: 667, examples: ['[runTask()] ended: no files to process'], + regex: '', }; const query = getCategoryCountRequest( @@ -65,8 +66,9 @@ describe('getCategoryCountMSearchRequest', () => { key: 'SLO summary transforms installed and started', count: 500, examples: ['SLO summary transforms installed and started'], + regex: '', }, - { key: 'Trusted Apps', count: 500, examples: ['Trusted Apps: '] }, + { key: 'Trusted Apps', count: 500, examples: ['Trusted Apps: '], regex: '' }, ]; const query = getCategoryCountMSearchRequest( diff --git a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_terms_2_categories_counts.ts b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_terms_2_categories_counts.ts index b9eac01041be1..a39418807e40a 100644 --- a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_terms_2_categories_counts.ts +++ b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/fetch_terms_2_categories_counts.ts @@ -93,7 +93,7 @@ export async function fetchTerms2CategoriesCounts( params, [{ fieldName: term.fieldName, fieldValue: term.fieldValue }], category.fieldName, - { key: `${category.key}`, count: category.doc_count, examples: [] }, + { key: `${category.key}`, count: category.doc_count, examples: [], regex: '' }, from, to ) as estypes.MsearchMultisearchBody @@ -121,7 +121,7 @@ export async function fetchTerms2CategoriesCounts( fieldValue, })), category.fieldName, - { key: `${category.key}`, count: category.doc_count, examples: [] }, + { key: `${category.key}`, count: category.doc_count, examples: [], regex: '' }, from, to ) as estypes.MsearchMultisearchBody diff --git a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_group_filter.ts b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_group_filter.ts index e2ae795004e18..b70ee26ae7f2a 100644 --- a/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_group_filter.ts +++ b/x-pack/plugins/aiops/server/routes/log_rate_analysis/queries/get_group_filter.ts @@ -43,6 +43,7 @@ export function getGroupFilter( key: d.key, count: d.docCount, examples: [], + regex: '', }, ]) ); From 5165088307dc1ab4ceb2c93bae77662c0a65cb00 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Fri, 26 Jan 2024 11:00:04 +0000 Subject: [PATCH 12/15] changes based on review --- .../category_table/category_table.tsx | 2 +- .../category_table/expanded_row.tsx | 11 +++++++++-- .../components/log_categorization/format_category.tsx | 4 ++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/aiops/public/components/log_categorization/category_table/category_table.tsx b/x-pack/plugins/aiops/public/components/log_categorization/category_table/category_table.tsx index b3f68ce120795..690dd1d56cdc4 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/category_table/category_table.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/category_table/category_table.tsx @@ -156,7 +156,7 @@ export const CategoryTable: FC = ({ isExpander: true, render: (item: Category) => ( toggleDetails(item)} aria-label={ itemIdToExpandedRowMap[item.key] diff --git a/x-pack/plugins/aiops/public/components/log_categorization/category_table/expanded_row.tsx b/x-pack/plugins/aiops/public/components/log_categorization/category_table/expanded_row.tsx index fe19b67595814..dfc1a3b7e9943 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/category_table/expanded_row.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/category_table/expanded_row.tsx @@ -6,9 +6,10 @@ */ import React, { FC } from 'react'; -import { EuiText, EuiSpacer } from '@elastic/eui'; +import { EuiText, EuiSpacer, useEuiTheme } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { css } from '@emotion/react'; import type { Category } from '../../../../common/api/log_categorization/types'; import { FormattedPatternExamples, FormattedRegex, FormattedTokens } from '../format_category'; @@ -17,8 +18,14 @@ interface ExpandedRowProps { } export const ExpandedRow: FC = ({ category }) => { + const { euiTheme } = useEuiTheme(); + const cssExpandedRow = css({ + marginRight: euiTheme.size.xxl, + width: '100%', + }); + return ( -
+
{ return elements; } - return { createFormattedExample }; + return createFormattedExample; }; export const FormattedPatternExamples: FC = ({ category, count }) => { - const { createFormattedExample } = useCreateFormattedExample(); + const createFormattedExample = useCreateFormattedExample(); const e = useMemo(() => { const { key, examples } = category; From ff9785b444d7e864589dc7fda7b8fef3b7be39b1 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Fri, 26 Jan 2024 11:28:20 +0000 Subject: [PATCH 13/15] updating test --- .../format_category.test.tsx.snap | 295 ------------------ .../format_category.test.tsx | 101 ++++-- .../log_categorization/format_category.tsx | 2 +- 3 files changed, 68 insertions(+), 330 deletions(-) delete mode 100644 x-pack/plugins/aiops/public/components/log_categorization/__snapshots__/format_category.test.tsx.snap diff --git a/x-pack/plugins/aiops/public/components/log_categorization/__snapshots__/format_category.test.tsx.snap b/x-pack/plugins/aiops/public/components/log_categorization/__snapshots__/format_category.test.tsx.snap deleted file mode 100644 index 32e424859a1c5..0000000000000 --- a/x-pack/plugins/aiops/public/components/log_categorization/__snapshots__/format_category.test.tsx.snap +++ /dev/null @@ -1,295 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`FormattedPatternExamples renders each category correctly 1`] = ` - -`; - -exports[`FormattedPatternExamples renders each category correctly 2`] = ` - -`; - -exports[`FormattedPatternExamples renders each category correctly 3`] = ` - -`; - -exports[`FormattedPatternExamples renders each category correctly 4`] = ` - -`; - -exports[`FormattedPatternExamples renders each category correctly 5`] = ` - -`; - -exports[`FormattedPatternExamples renders each category correctly 6`] = ` - -`; - -exports[`FormattedPatternExamples renders each category correctly 7`] = ` - -`; - -exports[`FormattedPatternExamples renders each category correctly 8`] = ` - -`; - -exports[`FormattedPatternExamples renders each category correctly 9`] = ` - -`; - -exports[`FormattedPatternExamples renders each category correctly 10`] = ` - -`; - -exports[`FormattedPatternExamples renders each category correctly 11`] = ` - -`; - -exports[`FormattedPatternExamples renders each category correctly 12`] = ` - -`; - -exports[`FormattedPatternExamples renders each category correctly 13`] = ` - -`; - -exports[`FormattedPatternExamples renders each category correctly 14`] = ` - -`; - -exports[`FormattedPatternExamples renders each category correctly 15`] = ` - -`; - -exports[`FormattedPatternExamples renders each category correctly 16`] = ` - -`; - -exports[`FormattedPatternExamples renders each category correctly 17`] = ` - -`; - -exports[`FormattedPatternExamples renders each category correctly 18`] = ` - -`; - -exports[`FormattedPatternExamples renders each category correctly 19`] = ` - -`; - -exports[`FormattedPatternExamples renders each category correctly 20`] = ` - -`; - -exports[`FormattedPatternExamples renders each category correctly 21`] = ` - -`; diff --git a/x-pack/plugins/aiops/public/components/log_categorization/format_category.test.tsx b/x-pack/plugins/aiops/public/components/log_categorization/format_category.test.tsx index a77e151709853..39c13fd901d2d 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/format_category.test.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/format_category.test.tsx @@ -5,58 +5,91 @@ * 2.0. */ -import React from 'react'; - import type { Category } from '../../../common/api/log_categorization/types'; -import { FormattedPatternExamples, FormattedRegex, FormattedTokens } from './format_category'; +import { useCreateFormattedExample } from './format_category'; + +jest.mock('../../hooks/use_eui_theme', () => ({ + useIsDarkTheme: () => false, +})); -const categories = [ +const categoryData: Array<{ + category: Category; + elementCount: number; +}> = [ { - key: 'Processed messages out of', - examples: ['Processed 676 messages out of 676'], - regex: '.*?Processed.+?messages.+?out.+?of.*?', + category: { + key: 'Processed messages out of', + count: 0, + examples: ['Processed 676 messages out of 676'], + regex: '.*?Processed.+?messages.+?out.+?of.*?', + }, + elementCount: 9, }, { - key: 'Processed messages out of', - examples: ['Processed out 676 messages messages out of 676 Processed'], - regex: '.*?Processed.+?messages.+?out.+?of.*?', + category: { + key: 'Processed messages out of', + count: 0, + examples: ['Processed out 676 messages messages out of 676 Processed'], + regex: '.*?Processed.+?messages.+?out.+?of.*?', + }, + elementCount: 9, }, { - key: 'Processed of', - examples: ['Processed 676 messages out of 676'], - regex: '.*?Processed.+?of.*?', + category: { + key: 'Processed of', + count: 0, + examples: ['Processed 676 messages out of 676'], + regex: '.*?Processed.+?of.*?', + }, + elementCount: 5, }, { - key: 'Processed messages out of', - examples: ['Processed messages out of'], - regex: '.*?Processed.+?messages.+?out.+?of.*?', + category: { + key: 'Processed messages out of', + count: 0, + examples: ['Processed messages out of'], + regex: '.*?Processed.+?messages.+?out.+?of.*?', + }, + elementCount: 9, }, { - key: '', - examples: ['Processed messages out of'], - regex: '.*?', + category: { + key: '', + count: 0, + examples: ['Processed messages out of'], + regex: '.*?', + }, + elementCount: 3, }, { - key: 'Processed messages out of', - examples: ['Processed 676 (*?) message* out of 676'], - regex: '.*?Processed.+?messages.+?out.+?of.*?', + category: { + key: 'Processed messages out of', + count: 0, + examples: ['Processed 676 (*?) message* out of 676'], + regex: '.*?Processed.+?messages.+?out.+?of.*?', + }, + elementCount: 9, }, { - key: '2024 0000 admin to admin console.prod 6000 api HTTP 1.1 https admin Mozilla 5.0 AppleWebKit KHTML like Gecko Chrome Safari', - examples: [ - '[05/Jan/2024 04:11:42 +0000] 40.69.144.53 - Lucio77 admin-console.you-got.mail to: admin-console.prod.008:6000: "GET /api/listCustomers HTTP/1.1" 200 383 "https://admin-console.you-got.mail" "Mozilla/5.0 (Windows; U; Windows NT 6.3) AppleWebKit/531.1.1 (KHTML, like Gecko) Chrome/23.0.835.0 Safari/531.1.1"', - ], - regex: - '.*?2024.+?0000.+?admin.+?to.+?admin.+?console.prod.+?6000.+?api.+?HTTP.+?1.1.+?https.+?admin.+?Mozilla.+?5.0.+?AppleWebKit.+?KHTML.+?like.+?Gecko.+?Chrome.+?Safari.*?', + category: { + key: '2024 0000 admin to admin console.prod 6000 api HTTP 1.1 https admin Mozilla 5.0 AppleWebKit KHTML like Gecko Chrome Safari', + count: 0, + examples: [ + '[05/Jan/2024 04:11:42 +0000] 40.69.144.53 - Lucio77 admin-console.you-got.mail to: admin-console.prod.008:6000: "GET /api/listCustomers HTTP/1.1" 200 383 "https://admin-console.you-got.mail" "Mozilla/5.0 (Windows; U; Windows NT 6.3) AppleWebKit/531.1.1 (KHTML, like Gecko) Chrome/23.0.835.0 Safari/531.1.1"', + ], + regex: + '.*?2024.+?0000.+?admin.+?to.+?admin.+?console.prod.+?6000.+?api.+?HTTP.+?1.1.+?https.+?admin.+?Mozilla.+?5.0.+?AppleWebKit.+?KHTML.+?like.+?Gecko.+?Chrome.+?Safari.*?', + }, + elementCount: 41, }, -] as Category[]; +]; describe('FormattedPatternExamples', () => { - it('renders each category correctly', () => { - categories.forEach((category) => { - expect().toMatchSnapshot(); - expect().toMatchSnapshot(); - expect().toMatchSnapshot(); + it('correctly splits each example into correct number of html elements', () => { + categoryData.forEach(({ category, elementCount }) => { + const createFormattedExample = useCreateFormattedExample(); + const resp = createFormattedExample(category.key, category.examples[0]); + expect(resp.length).toEqual(elementCount); }); }); }); diff --git a/x-pack/plugins/aiops/public/components/log_categorization/format_category.tsx b/x-pack/plugins/aiops/public/components/log_categorization/format_category.tsx index e27cb1025a652..acd76bdbe712d 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/format_category.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/format_category.tsx @@ -48,7 +48,7 @@ const useStyles = (): Styles => { }; }; -const useCreateFormattedExample = () => { +export const useCreateFormattedExample = () => { const { tokenStyle, wildcardStyle } = useStyles(); function createFormattedExample(key: string, example: string): JSX.Element[] { From c45c84906cc2524aa0e9d1d2863c65a91fb8130c Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Fri, 26 Jan 2024 13:24:56 +0000 Subject: [PATCH 14/15] hook improvements --- .../log_categorization/format_category.tsx | 124 ++++++++++-------- 1 file changed, 68 insertions(+), 56 deletions(-) diff --git a/x-pack/plugins/aiops/public/components/log_categorization/format_category.tsx b/x-pack/plugins/aiops/public/components/log_categorization/format_category.tsx index acd76bdbe712d..9c3d298c5ecfd 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/format_category.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/format_category.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC, useMemo } from 'react'; +import React, { FC, useCallback, useMemo } from 'react'; import { EuiText, EuiHorizontalRule } from '@elastic/eui'; import { css, SerializedStyles } from '@emotion/react'; import type { Category } from '../../../common/api/log_categorization/types'; @@ -37,72 +37,84 @@ interface Styles { const useStyles = (): Styles => { const isDarkTheme = useIsDarkTheme(); - return isDarkTheme - ? { - tokenStyle: tokenStyleDark, - wildcardStyle: wildcardStyleDark, - } - : { - tokenStyle: tokenStyleLight, - wildcardStyle: wildcardStyleLight, - }; + + return useMemo( + () => + isDarkTheme + ? { + tokenStyle: tokenStyleDark, + wildcardStyle: wildcardStyleDark, + } + : { + tokenStyle: tokenStyleLight, + wildcardStyle: wildcardStyleLight, + }, + [isDarkTheme] + ); }; export const useCreateFormattedExample = () => { const { tokenStyle, wildcardStyle } = useStyles(); - function createFormattedExample(key: string, example: string): JSX.Element[] { - const keyTokens = key.split(' '); - let tempExample = ` ${example} `; - const positions = keyTokens.map((t) => ({ - id: t, - start: 0, - end: 0, - })); - let offset = 0; - // match each token in order and record the start and end position - for (let i = 0; i < keyTokens.length; i++) { - const token = keyTokens[i]; - const tokenReg = new RegExp(`(\\W)(${token})(\\W)`); - - let j = 0; - const result = tokenReg.exec(tempExample); - if (!result) { - continue; + const createFormattedExample = useCallback( + (key: string, example: string): JSX.Element[] => { + const keyTokens = key.split(' '); + let tempExample = ` ${example} `; + const positions = keyTokens.map((t) => ({ + id: t, + start: 0, + end: 0, + })); + let offset = 0; + // match each token in order and record the start and end position + for (let i = 0; i < keyTokens.length; i++) { + const token = keyTokens[i]; + const tokenReg = new RegExp(`(\\W)(${token})(\\W)`); + + let j = 0; + const result = tokenReg.exec(tempExample); + if (!result) { + continue; + } + j = result.index; + const localEndOFToken = j + token.length + 1; + positions[i].start = offset + j + 1; + positions[i].end = offset + localEndOFToken; + // slice the example string to remove the token and preceding text + // to ensure we don't match future tokens in earlier text + tempExample = tempExample.slice(localEndOFToken); + offset += localEndOFToken; } - j = result.index; - const localEndOFToken = j + token.length + 1; - positions[i].start = offset + j + 1; - positions[i].end = offset + localEndOFToken; - // slice the example string to remove the token and preceding text - // to ensure we don't match future tokens in earlier text - tempExample = tempExample.slice(localEndOFToken); - offset += localEndOFToken; - } - tempExample = ` ${example} `; - - // build up the list ot elements by chopping up the example string - // using the token positions found above - const elements: JSX.Element[] = []; - let pos = 0; - for (let i = 0; i < positions.length; i++) { - elements.push( - {tempExample.substring(pos, positions[i].start)} - ); + tempExample = ` ${example} `; + + // build up the list ot elements by chopping up the example string + // using the token positions found above + const elements: JSX.Element[] = []; + let pos = 0; + for (let i = 0; i < positions.length; i++) { + elements.push( + {tempExample.substring(pos, positions[i].start)} + ); + + elements.push( + + {tempExample.substring(positions[i].start, positions[i].end)} + + ); + pos = positions[i].end; + } elements.push( - {tempExample.substring(positions[i].start, positions[i].end)} + + {tempExample.substring(positions[positions.length - 1].end)} + ); - pos = positions[i].end; - } - elements.push( - {tempExample.substring(positions[positions.length - 1].end)} - ); - - return elements; - } + return elements; + }, + [tokenStyle, wildcardStyle] + ); return createFormattedExample; }; From a60f24d0bee1da3d08e535b1b7aa352d7158f68c Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Fri, 26 Jan 2024 15:38:17 +0000 Subject: [PATCH 15/15] fixing test --- .../components/log_categorization/format_category.test.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/aiops/public/components/log_categorization/format_category.test.tsx b/x-pack/plugins/aiops/public/components/log_categorization/format_category.test.tsx index 39c13fd901d2d..b3eabc36cb735 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/format_category.test.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/format_category.test.tsx @@ -7,6 +7,7 @@ import type { Category } from '../../../common/api/log_categorization/types'; import { useCreateFormattedExample } from './format_category'; +import { renderHook } from '@testing-library/react-hooks'; jest.mock('../../hooks/use_eui_theme', () => ({ useIsDarkTheme: () => false, @@ -87,7 +88,8 @@ const categoryData: Array<{ describe('FormattedPatternExamples', () => { it('correctly splits each example into correct number of html elements', () => { categoryData.forEach(({ category, elementCount }) => { - const createFormattedExample = useCreateFormattedExample(); + const { result } = renderHook(() => useCreateFormattedExample()); + const createFormattedExample = result.current; const resp = createFormattedExample(category.key, category.examples[0]); expect(resp.length).toEqual(elementCount); });