From 710d35e5d88422de187c4316b99dda3de953b2ef Mon Sep 17 00:00:00 2001 From: Hailong Cui Date: Thu, 23 May 2024 23:37:09 +0800 Subject: [PATCH 01/17] support date_nanos type Signed-off-by: Hailong Cui --- .../MonitorTimeField/MonitorTimeField.js | 4 ++- .../MonitorTimeField/MonitorTimeField.test.js | 27 +++++++++++++++---- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/public/pages/CreateMonitor/components/MonitorTimeField/MonitorTimeField.js b/public/pages/CreateMonitor/components/MonitorTimeField/MonitorTimeField.js index ba89267db..d0608a617 100644 --- a/public/pages/CreateMonitor/components/MonitorTimeField/MonitorTimeField.js +++ b/public/pages/CreateMonitor/components/MonitorTimeField/MonitorTimeField.js @@ -11,7 +11,9 @@ import { FormikComboBox } from '../../../../components/FormControls'; const MonitorTimeField = ({ dataTypes }) => { // Default empty option + options from index mappings mapped to ui select form - const dateFields = Array.from(dataTypes.date || []); + const dateFields = Array.from(dataTypes.date || []).concat( + Array.from(dataTypes.date_nanos || []) + ); const options = [].concat(dateFields).map((option) => ({ label: option })); return ( { expect(render(component)).toMatchSnapshot(); }); - test.skip('displays no options', () => { + test('displays no options', () => { const wrapper = mount( {}}> ); // Default blank option - expect(wrapper.find('select').props().children[1].length).toBe(1); + expect(wrapper.find('EuiComboBox').props().options.length).toBe(0); }); - test.skip('displays options', () => { + test('displays options', () => { const wrapper = mount( {}}> ); - // 3 options + default blank option - expect(wrapper.find('select').props().children[1].length).toBe(4); + // 3 options + expect(wrapper.find('EuiComboBox').props().options.length).toBe(3); + }); + + test('displays options includes date_nanos', () => { + const wrapper = mount( + {}}> + + + ); + expect(wrapper).toMatchSnapshot(); + + // 4 options + expect(wrapper.find('EuiComboBox').props().options.length).toBe(4); + expect(wrapper.find('EuiComboBox').props().options).toEqual( + expect.arrayContaining([{ label: 'date_nanos1' }]) + ); }); }); From 660fa08dd364746426f6f9ef6d1a4a6fbf2f6a46 Mon Sep 17 00:00:00 2001 From: Hailong Cui Date: Wed, 29 May 2024 09:04:12 +0800 Subject: [PATCH 02/17] support context aware alert analysis Signed-off-by: Hailong Cui --- opensearch_dashboards.json | 1 + .../pages/Dashboard/containers/Dashboard.js | 8 +-- public/pages/Dashboard/utils/tableUtils.js | 72 ++++++++++++++++++- public/plugin.tsx | 59 +++++++++++---- public/services/services.ts | 4 ++ public/types.ts | 12 ++++ yarn.lock | 15 ++-- 7 files changed, 148 insertions(+), 23 deletions(-) create mode 100644 public/types.ts diff --git a/opensearch_dashboards.json b/opensearch_dashboards.json index 3098ede0f..832fec201 100644 --- a/opensearch_dashboards.json +++ b/opensearch_dashboards.json @@ -15,6 +15,7 @@ "visAugmenter", "opensearchDashboardsUtils" ], + "optionalPlugins": ["assistantDashboards"], "server": true, "ui": true } diff --git a/public/pages/Dashboard/containers/Dashboard.js b/public/pages/Dashboard/containers/Dashboard.js index d7c4c63ac..cc7a11911 100644 --- a/public/pages/Dashboard/containers/Dashboard.js +++ b/public/pages/Dashboard/containers/Dashboard.js @@ -1,3 +1,4 @@ +/* eslint-disable camelcase */ /* * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 @@ -143,7 +144,6 @@ export default class Dashboard extends Component { }; const queryParamsString = queryString.stringify(params); - location.search; const { httpClient, history, notifications, perAlertView } = this.props; history.replace({ ...this.props.location, search: queryParamsString }); const dataSourceId = getDataSourceId(); @@ -221,7 +221,7 @@ export default class Dashboard extends Component { if (!selectedItems.length) return; - let selectedAlerts = perAlertView ? selectedItems : _.get(selectedItems, '0.alerts', []); + const selectedAlerts = perAlertView ? selectedItems : _.get(selectedItems, '0.alerts', []); await this.acknowledgeAlerts(selectedAlerts); this.setState({ selectedItems: [] }); @@ -373,7 +373,7 @@ export default class Dashboard extends Component { notifications, isAlertsFlyout = false, } = this.props; - let totalItems = perAlertView ? totalAlerts : totalTriggers; + const totalItems = perAlertView ? totalAlerts : totalTriggers; const isBucketMonitor = monitorType === MONITOR_TYPE.BUCKET_LEVEL; let columns; @@ -466,7 +466,7 @@ export default class Dashboard extends Component { onSelectionChange: this.onSelectionChange, selectable: perAlertView ? (item) => item.state === ALERT_STATE.ACTIVE - : (item) => item.ACTIVE > 0, + : (item) => item.ACTIVE >= 0, selectableMessage: perAlertView ? (selectable) => (selectable ? undefined : 'Only active alerts can be acknowledged.') : (selectable) => diff --git a/public/pages/Dashboard/utils/tableUtils.js b/public/pages/Dashboard/utils/tableUtils.js index 8b54fb17e..95fcee587 100644 --- a/public/pages/Dashboard/utils/tableUtils.js +++ b/public/pages/Dashboard/utils/tableUtils.js @@ -7,8 +7,10 @@ import React from 'react'; import _ from 'lodash'; import { EuiLink, EuiToolTip } from '@elastic/eui'; import moment from 'moment'; -import { ALERT_STATE, DEFAULT_EMPTY_DATA } from '../../../utils/constants'; +import { ALERT_STATE, DEFAULT_EMPTY_DATA, MONITOR_TYPE } from '../../../utils/constants'; import { PLUGIN_NAME } from '../../../../utils/constants'; +import { getAssistantDashboards } from '../../../services'; +import { getDataSourceQueryObj } from '../../../pages/utils/helpers'; export const renderTime = (time) => { const momentTime = moment(time); @@ -131,8 +133,9 @@ export const alertColumns = ( sortable: true, truncateText: false, render: (total, alert) => { - return ( + const component = ( { openFlyout({ ...alert, @@ -152,6 +155,71 @@ export const alertColumns = ( {`${total} alerts`} ); + const contextProvider = async () => { + // 1. get monitor definition + const dataSourceQuery = getDataSourceQueryObj(); + const monitorResp = await httpClient.get( + `../api/alerting/monitors/${alert.monitor_id}`, + dataSourceQuery + ); + const monitorDefinition = monitorResp.resp; + delete monitorDefinition.ui_metadata; + delete monitorDefinition.data_sources; + + let monitorDefinitionStr = JSON.stringify(monitorDefinition); + + // 2. get data triggers the alert + let alertTriggeredByData = ''; + let dsl = ''; + if ( + monitorResp.resp.monitor_type === MONITOR_TYPE.QUERY_LEVEL || + monitorResp.resp.monitor_type === MONITOR_TYPE.BUCKET_LEVEL + ) { + const search = monitorResp.resp.inputs[0].search; + const indices = search.indices; + let query = JSON.stringify(search.query); + // Only keep the query part + dsl = JSON.stringify({ query: search.query.query }); + if (query.indexOf('{{period_end}}') !== -1) { + query = query.replaceAll('{{period_end}}', alert.start_time); + const alertStartTime = moment.utc(alert.start_time).format('YYYY-MM-DD HH:mm:ss'); + dsl = dsl.replaceAll('{{period_end}}', alertStartTime); + // as we changed the format, remove it + dsl = dsl.replaceAll('"format":"epoch_millis",', ''); + monitorDefinitionStr = monitorDefinitionStr.replaceAll( + '{{period_end}}', + alertStartTime + ); + // as we changed the format, remove it + monitorDefinitionStr = monitorDefinitionStr.replaceAll('"format":"epoch_millis",', ''); + } + const alertData = await httpClient.post(`/api/console/proxy`, { + query: { + path: `${indices}/_search`, + method: 'GET', + dataSourceId: dataSourceQuery ? dataSourceQuery.query.dataSourceId : '', + }, + body: query, + prependBasePath: true, + asResponse: true, + withLongNumeralsSupport: true, + }); + + alertTriggeredByData = JSON.stringify(alertData.body); + } + + // 3. build the context + return ` + Here is the detail information about alert ${alert.name} + ### Monitor definition\n ${monitorDefinitionStr}\n + ### Active Alert\n ${JSON.stringify(alert)}\n + ### Data triggers this alert\n ${alertTriggeredByData}\n + ### Alert query DSL ${dsl} \n`; + }; + + return getAssistantDashboards().chatEnabled() + ? getAssistantDashboards().renderIncontextInsight({ children: component, contextProvider }) + : component; }, }, { diff --git a/public/plugin.tsx b/public/plugin.tsx index bbad0227b..b4d10f38b 100644 --- a/public/plugin.tsx +++ b/public/plugin.tsx @@ -4,11 +4,7 @@ */ import { PLUGIN_NAME } from '../utils/constants'; -import { - Plugin, - CoreSetup, - CoreStart, -} from '../../../src/core/public'; +import { Plugin, CoreSetup, CoreStart } from '../../../src/core/public'; import { ACTION_ALERTING } from './actions/alerting_dashboard_action'; import { CONTEXT_MENU_TRIGGER, EmbeddableStart } from '../../../src/plugins/embeddable/public'; import { getActions, getAdAction } from './utils/contextMenu/actions'; @@ -16,9 +12,22 @@ import { alertingTriggerAd } from './utils/contextMenu/triggers'; import { ExpressionsSetup } from '../../../src/plugins/expressions/public'; import { UiActionsSetup } from '../../../src/plugins/ui_actions/public'; import { overlayAlertsFunction } from './expressions/overlay_alerts'; -import { setClient, setEmbeddable, setNotifications, setOverlays, setSavedAugmentVisLoader, setUISettings, setQueryService, setSavedObjectsClient, setDataSourceEnabled, setDataSourceManagementPlugin } from './services'; +import { + setClient, + setEmbeddable, + setNotifications, + setOverlays, + setSavedAugmentVisLoader, + setUISettings, + setQueryService, + setSavedObjectsClient, + setDataSourceEnabled, + setDataSourceManagementPlugin, + setAssistantDashboards, +} from './services'; import { VisAugmenterStart } from '../../../src/plugins/vis_augmenter/public'; import { DataPublicPluginStart } from '../../../src/plugins/data/public'; +import { AssistantSetup } from './types'; import { DataSourceManagementPluginSetup } from '../../../src/plugins/data_source_management/public'; import { DataSourcePluginSetup } from '../../../src/plugins/data_source/public'; @@ -28,13 +37,15 @@ declare module '../../../src/plugins/ui_actions/public' { } } +// eslint-disable-next-line @typescript-eslint/no-empty-interface export interface AlertingSetup {} - +// eslint-disable-next-line @typescript-eslint/no-empty-interface export interface AlertingStart {} export interface AlertingSetupDeps { expressions: ExpressionsSetup; uiActions: UiActionsSetup; + assistantDashboards?: AssistantSetup; dataSourceManagement: DataSourceManagementPluginSetup; dataSource: DataSourcePluginSetup; } @@ -45,12 +56,22 @@ export interface AlertingStartDeps { data: DataPublicPluginStart; } -export class AlertingPlugin implements Plugin { - public setup(core: CoreSetup, { expressions, uiActions, dataSourceManagement, dataSource }: AlertingSetupDeps): AlertingSetup { +export class AlertingPlugin + implements Plugin { + public setup( + core: CoreSetup, + { + expressions, + uiActions, + assistantDashboards, + dataSourceManagement, + dataSource, + }: AlertingSetupDeps + ): AlertingSetup { core.application.register({ id: PLUGIN_NAME, title: 'Alerting', - description: 'OpenSearch Dashboards Alerting Plugin', + // description: 'OpenSearch Dashboards Alerting Plugin', category: { id: 'opensearch', label: 'OpenSearch Plugins', @@ -64,6 +85,17 @@ export class AlertingPlugin implements Plugin false }); + if (assistantDashboards && assistantDashboards?.chatEnabled()) { + assistantDashboards.registerIncontextInsight([ + { + key: 'alerts', + type: 'chatWithSuggestions', + suggestions: [`What's this alert?`, `How to address this alert?`], + }, + ]); + } + setUISettings(core.uiSettings); // Set the HTTP client so it can be pulled into expression fns to make @@ -92,10 +124,13 @@ export class AlertingPlugin implements Plugin(null); @@ -26,6 +27,9 @@ export const [getSavedAugmentVisLoader, setSavedAugmentVisLoader] = createGetter >('savedAugmentVisLoader'); export const [getUISettings, setUISettings] = createGetterSetter('UISettings'); +export const [getAssistantDashboards, setAssistantDashboards] = createGetterSetter< + AssistantSetup | {} +>('assistantDashboards'); export const [getEmbeddable, setEmbeddable] = createGetterSetter('embeddable'); diff --git a/public/types.ts b/public/types.ts new file mode 100644 index 000000000..4734f3a91 --- /dev/null +++ b/public/types.ts @@ -0,0 +1,12 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * Introduce a compile dependency on dashboards-assistant + * as alerting need some types from the plugin. + * It will give a type error when dashboards-assistant is not installed so add a ts-ignore to suppress the error. + */ +// @ts-ignore +export type { AssistantSetup } from '../../dashboards-assistant/public'; diff --git a/yarn.lock b/yarn.lock index a28402084..81203915f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2319,6 +2319,11 @@ glob-parent@^3.1.0, glob-parent@^5.1.2, glob-parent@~5.1.2: dependencies: is-glob "^4.0.1" +glob-to-regexp@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" + integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== + glob@^7.1.3, glob@^7.1.4, glob@^7.2.3: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" @@ -4935,10 +4940,10 @@ webpack-sources@^1.4.0, webpack-sources@^1.4.1: source-list-map "^2.0.0" source-map "~0.6.1" -"webpack@npm:@amoo-miki/webpack@4.46.0-rc.2": - version "4.46.0-rc.2" - resolved "https://registry.yarnpkg.com/@amoo-miki/webpack/-/webpack-4.46.0-rc.2.tgz#36824597c14557a7bb0a8e13203e30275e7b02bd" - integrity sha512-Y/ZqxTHOoDF1kz3SR63Y9SZGTDUpZNNFrisTRHofWhP8QvNX3LMN+TCmEP56UfLaiLVKMcaiFjx8kFb2TgyBaQ== +"webpack@npm:@amoo-miki/webpack@4.46.0-xxhash.1": + version "4.46.0-xxhash.1" + resolved "https://registry.yarnpkg.com/@amoo-miki/webpack/-/webpack-4.46.0-xxhash.1.tgz#e8fdb0399d36715e558ad35e3ff70fd1d4ea47a7" + integrity sha512-gPwQMqfrE9326g+rZoU4BPOfcYvEcAR0XxfpV9AGUcRwl2oHoqEwq7nxSWchilpGV1i9XI7mCa8u8k4ePz6ziA== dependencies: "@node-rs/xxhash" "^1.3.0" "@webassemblyjs/ast" "1.9.0" @@ -4951,11 +4956,11 @@ webpack-sources@^1.4.0, webpack-sources@^1.4.1: chrome-trace-event "^1.0.2" enhanced-resolve "^4.5.0" eslint-scope "^4.0.3" + glob-to-regexp "^0.4.1" json-parse-better-errors "^1.0.2" loader-runner "^2.4.0" loader-utils "^2.0.4" memory-fs "^0.4.1" - micromatch "^3.1.10" mkdirp "^0.5.3" neo-async "^2.6.1" node-libs-browser "^2.2.1" From 3e02bf9522b54bcc8886396662610c4c7b072ca2 Mon Sep 17 00:00:00 2001 From: Songkan Tang Date: Thu, 11 Jul 2024 13:35:58 +0800 Subject: [PATCH 03/17] Register summary generation type of IncontextInsight for alert summarization Signed-off-by: Songkan Tang --- public/pages/Dashboard/utils/tableUtils.js | 6 +++--- public/plugin.tsx | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/public/pages/Dashboard/utils/tableUtils.js b/public/pages/Dashboard/utils/tableUtils.js index 95fcee587..da4858cfc 100644 --- a/public/pages/Dashboard/utils/tableUtils.js +++ b/public/pages/Dashboard/utils/tableUtils.js @@ -211,9 +211,9 @@ export const alertColumns = ( // 3. build the context return ` Here is the detail information about alert ${alert.name} - ### Monitor definition\n ${monitorDefinitionStr}\n - ### Active Alert\n ${JSON.stringify(alert)}\n - ### Data triggers this alert\n ${alertTriggeredByData}\n + ### Monitor definition\n ${monitorDefinitionStr}\n + ### Active Alert\n ${JSON.stringify(alert)}\n + ### Data triggers this alert\n ${alertTriggeredByData}\n ### Alert query DSL ${dsl} \n`; }; diff --git a/public/plugin.tsx b/public/plugin.tsx index b4d10f38b..6a49ef476 100644 --- a/public/plugin.tsx +++ b/public/plugin.tsx @@ -71,7 +71,7 @@ export class AlertingPlugin core.application.register({ id: PLUGIN_NAME, title: 'Alerting', - // description: 'OpenSearch Dashboards Alerting Plugin', + description: 'OpenSearch Dashboards Alerting Plugin', category: { id: 'opensearch', label: 'OpenSearch Plugins', @@ -90,8 +90,8 @@ export class AlertingPlugin assistantDashboards.registerIncontextInsight([ { key: 'alerts', - type: 'chatWithSuggestions', - suggestions: [`What's this alert?`, `How to address this alert?`], + type: 'generate', + suggestions: [`Please summarize this alert`], }, ]); } From 36c4b8c5219d0c6d33c41e81ce09a26b9b65311e Mon Sep 17 00:00:00 2001 From: Songkan Tang Date: Tue, 16 Jul 2024 18:21:47 +0800 Subject: [PATCH 04/17] Fix dashboard unit test failure Signed-off-by: Songkan Tang --- public/pages/Dashboard/containers/Dashboard.test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/public/pages/Dashboard/containers/Dashboard.test.js b/public/pages/Dashboard/containers/Dashboard.test.js index 06811d23b..ddb2444b1 100644 --- a/public/pages/Dashboard/containers/Dashboard.test.js +++ b/public/pages/Dashboard/containers/Dashboard.test.js @@ -8,6 +8,7 @@ import { mount } from 'enzyme'; import Dashboard from './Dashboard'; import { historyMock, httpClientMock } from '../../../../test/mocks'; +import { setAssistantDashboards } from '../../../services'; const location = { hash: '', @@ -57,6 +58,8 @@ const sampleQueryAlerts = [ const runAllPromises = () => new Promise(setImmediate); describe('Dashboard', () => { + setAssistantDashboards({ chatEnabled: () => false }); + beforeEach(() => { jest.clearAllMocks(); }); From 2cabf621dc3b548b691ea1473d672dadd9f4352b Mon Sep 17 00:00:00 2001 From: Songkan Tang Date: Mon, 22 Jul 2024 15:01:12 +0800 Subject: [PATCH 05/17] Make each alert register its own IncontextInsight Signed-off-by: Songkan Tang --- public/pages/Dashboard/utils/tableUtils.js | 19 +++++++++++++++---- public/plugin.tsx | 9 --------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/public/pages/Dashboard/utils/tableUtils.js b/public/pages/Dashboard/utils/tableUtils.js index da4858cfc..98143739c 100644 --- a/public/pages/Dashboard/utils/tableUtils.js +++ b/public/pages/Dashboard/utils/tableUtils.js @@ -133,9 +133,10 @@ export const alertColumns = ( sortable: true, truncateText: false, render: (total, alert) => { + const alertId = `alerts_${alert.alerts[0].id}`; const component = ( { openFlyout({ ...alert, @@ -217,9 +218,19 @@ export const alertColumns = ( ### Alert query DSL ${dsl} \n`; }; - return getAssistantDashboards().chatEnabled() - ? getAssistantDashboards().renderIncontextInsight({ children: component, contextProvider }) - : component; + if (getAssistantDashboards().chatEnabled) { + getAssistantDashboards().registerIncontextInsight([ + { + key: alertId, + type: 'generate', + suggestions: [`Please summarize this alert`], + contextProvider: contextProvider, + }, + ]); + return getAssistantDashboards().renderIncontextInsight({ children: component }); + } else { + return component; + } }, }, { diff --git a/public/plugin.tsx b/public/plugin.tsx index 6a49ef476..049a17bd4 100644 --- a/public/plugin.tsx +++ b/public/plugin.tsx @@ -86,15 +86,6 @@ export class AlertingPlugin }); setAssistantDashboards(assistantDashboards || { chatEnabled: () => false }); - if (assistantDashboards && assistantDashboards?.chatEnabled()) { - assistantDashboards.registerIncontextInsight([ - { - key: 'alerts', - type: 'generate', - suggestions: [`Please summarize this alert`], - }, - ]); - } setUISettings(core.uiSettings); From bab04a720a39e0129471bc98fe34f4d3b34a3693 Mon Sep 17 00:00:00 2001 From: Songkan Tang Date: Mon, 22 Jul 2024 15:48:15 +0800 Subject: [PATCH 06/17] Enable context aware alert only if feature flag is enabled Signed-off-by: Songkan Tang --- public/pages/Dashboard/containers/Dashboard.test.js | 2 +- public/pages/Dashboard/utils/tableUtils.js | 2 +- public/plugin.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/public/pages/Dashboard/containers/Dashboard.test.js b/public/pages/Dashboard/containers/Dashboard.test.js index ddb2444b1..aa4ffe8a8 100644 --- a/public/pages/Dashboard/containers/Dashboard.test.js +++ b/public/pages/Dashboard/containers/Dashboard.test.js @@ -58,7 +58,7 @@ const sampleQueryAlerts = [ const runAllPromises = () => new Promise(setImmediate); describe('Dashboard', () => { - setAssistantDashboards({ chatEnabled: () => false }); + setAssistantDashboards({ chatEnabled: () => false, nextEnabled: () => false }); beforeEach(() => { jest.clearAllMocks(); diff --git a/public/pages/Dashboard/utils/tableUtils.js b/public/pages/Dashboard/utils/tableUtils.js index 98143739c..063d6ff04 100644 --- a/public/pages/Dashboard/utils/tableUtils.js +++ b/public/pages/Dashboard/utils/tableUtils.js @@ -218,7 +218,7 @@ export const alertColumns = ( ### Alert query DSL ${dsl} \n`; }; - if (getAssistantDashboards().chatEnabled) { + if (getAssistantDashboards().nextEnabled()) { getAssistantDashboards().registerIncontextInsight([ { key: alertId, diff --git a/public/plugin.tsx b/public/plugin.tsx index 049a17bd4..fc9655d4f 100644 --- a/public/plugin.tsx +++ b/public/plugin.tsx @@ -85,7 +85,7 @@ export class AlertingPlugin }, }); - setAssistantDashboards(assistantDashboards || { chatEnabled: () => false }); + setAssistantDashboards(assistantDashboards || { chatEnabled: () => false, nextEnabled: () => false }); setUISettings(core.uiSettings); From 9b4f175be56ca532b30af86e1ba6767473b11ece Mon Sep 17 00:00:00 2001 From: Songkan Tang Date: Thu, 22 Aug 2024 10:45:00 +0800 Subject: [PATCH 07/17] Avoid unnecessary change and minorly change summary question Signed-off-by: Songkan Tang --- public/pages/Dashboard/containers/Dashboard.js | 1 - public/pages/Dashboard/utils/tableUtils.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/public/pages/Dashboard/containers/Dashboard.js b/public/pages/Dashboard/containers/Dashboard.js index 809e9556f..7c9708018 100644 --- a/public/pages/Dashboard/containers/Dashboard.js +++ b/public/pages/Dashboard/containers/Dashboard.js @@ -1,4 +1,3 @@ -/* eslint-disable camelcase */ /* * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 diff --git a/public/pages/Dashboard/utils/tableUtils.js b/public/pages/Dashboard/utils/tableUtils.js index 18d152c8f..6f581ff27 100644 --- a/public/pages/Dashboard/utils/tableUtils.js +++ b/public/pages/Dashboard/utils/tableUtils.js @@ -222,7 +222,7 @@ export const alertColumns = ( { key: alertId, type: 'generate', - suggestions: [`Please summarize this alert`], + suggestions: [`Please summarize this alert, do not use any tool.`], contextProvider: contextProvider, }, ]); From a2a1d9a06dfbfc300ae99e8b89d98d9d8ff47b24 Mon Sep 17 00:00:00 2001 From: Songkan Tang Date: Tue, 27 Aug 2024 13:48:59 +0800 Subject: [PATCH 08/17] Fix undefined alert name Signed-off-by: Songkan Tang --- public/pages/Dashboard/utils/tableUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/pages/Dashboard/utils/tableUtils.js b/public/pages/Dashboard/utils/tableUtils.js index 6f581ff27..dfd165339 100644 --- a/public/pages/Dashboard/utils/tableUtils.js +++ b/public/pages/Dashboard/utils/tableUtils.js @@ -210,7 +210,7 @@ export const alertColumns = ( // 3. build the context return ` - Here is the detail information about alert ${alert.name} + Here is the detail information about alert ${alert.trigger_name} ### Monitor definition\n ${monitorDefinitionStr}\n ### Active Alert\n ${JSON.stringify(alert)}\n ### Data triggers this alert\n ${alertTriggeredByData}\n From 81785ca9be059886aa113c2135a7bfe905ea47f4 Mon Sep 17 00:00:00 2001 From: Songkan Tang Date: Tue, 27 Aug 2024 17:34:58 +0800 Subject: [PATCH 09/17] Pass monitor type to additional info object of contextProvider Signed-off-by: Songkan Tang --- public/pages/Dashboard/utils/tableUtils.js | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/public/pages/Dashboard/utils/tableUtils.js b/public/pages/Dashboard/utils/tableUtils.js index dfd165339..804d71473 100644 --- a/public/pages/Dashboard/utils/tableUtils.js +++ b/public/pages/Dashboard/utils/tableUtils.js @@ -209,12 +209,17 @@ export const alertColumns = ( } // 3. build the context - return ` - Here is the detail information about alert ${alert.trigger_name} - ### Monitor definition\n ${monitorDefinitionStr}\n - ### Active Alert\n ${JSON.stringify(alert)}\n - ### Data triggers this alert\n ${alertTriggeredByData}\n - ### Alert query DSL ${dsl} \n`; + return { + context: ` + Here is the detail information about alert ${alert.trigger_name} + ### Monitor definition\n ${monitorDefinitionStr}\n + ### Active Alert\n ${JSON.stringify(alert)}\n + ### Data triggers this alert\n ${alertTriggeredByData}\n + ### Alert query DSL ${dsl} \n`, + additionalInfo: { + monitorType: monitorResp.resp.monitor_type, + }, + }; }; if (getAssistantDashboards().nextEnabled()) { From 175d897e7089102d52d0e3023e37c38b3745cc5a Mon Sep 17 00:00:00 2001 From: Songkan Tang Date: Wed, 28 Aug 2024 16:03:28 +0800 Subject: [PATCH 10/17] Address some comments and change feature flag Signed-off-by: Songkan Tang --- public/pages/Dashboard/containers/Dashboard.js | 6 +++--- public/pages/Dashboard/containers/Dashboard.test.js | 2 +- public/pages/Dashboard/utils/tableUtils.js | 5 +++-- public/plugin.tsx | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/public/pages/Dashboard/containers/Dashboard.js b/public/pages/Dashboard/containers/Dashboard.js index 7c9708018..0838fe007 100644 --- a/public/pages/Dashboard/containers/Dashboard.js +++ b/public/pages/Dashboard/containers/Dashboard.js @@ -222,7 +222,7 @@ export default class Dashboard extends Component { if (!selectedItems.length) return; - const selectedAlerts = perAlertView ? selectedItems : _.get(selectedItems, '0.alerts', []); + let selectedAlerts = perAlertView ? selectedItems : _.get(selectedItems, '0.alerts', []); await this.acknowledgeAlerts(selectedAlerts); this.setState({ selectedItems: [] }); @@ -374,7 +374,7 @@ export default class Dashboard extends Component { notifications, isAlertsFlyout = false, } = this.props; - const totalItems = perAlertView ? totalAlerts : totalTriggers; + let totalItems = perAlertView ? totalAlerts : totalTriggers; const isBucketMonitor = monitorType === MONITOR_TYPE.BUCKET_LEVEL; let columns; @@ -467,7 +467,7 @@ export default class Dashboard extends Component { onSelectionChange: this.onSelectionChange, selectable: perAlertView ? (item) => item.state === ALERT_STATE.ACTIVE - : (item) => item.ACTIVE >= 0, + : (item) => item.ACTIVE > 0, selectableMessage: perAlertView ? (selectable) => (selectable ? undefined : 'Only active alerts can be acknowledged.') : (selectable) => diff --git a/public/pages/Dashboard/containers/Dashboard.test.js b/public/pages/Dashboard/containers/Dashboard.test.js index 903e62c53..c5486e7b2 100644 --- a/public/pages/Dashboard/containers/Dashboard.test.js +++ b/public/pages/Dashboard/containers/Dashboard.test.js @@ -63,7 +63,7 @@ beforeAll(() => { }); describe('Dashboard', () => { - setAssistantDashboards({ chatEnabled: () => false, nextEnabled: () => false }); + setAssistantDashboards({ getFeatureStatus: () => ({ chat: false, alertInsight: false }) }); beforeEach(() => { jest.clearAllMocks(); diff --git a/public/pages/Dashboard/utils/tableUtils.js b/public/pages/Dashboard/utils/tableUtils.js index 804d71473..97d23a55e 100644 --- a/public/pages/Dashboard/utils/tableUtils.js +++ b/public/pages/Dashboard/utils/tableUtils.js @@ -222,13 +222,14 @@ export const alertColumns = ( }; }; - if (getAssistantDashboards().nextEnabled()) { + const assistantFeatureStatus = getAssistantDashboards().getFeatureStatus(); + if (assistantFeatureStatus.alertInsight) { getAssistantDashboards().registerIncontextInsight([ { key: alertId, type: 'generate', suggestions: [`Please summarize this alert, do not use any tool.`], - contextProvider: contextProvider, + contextProvider, }, ]); return getAssistantDashboards().renderIncontextInsight({ children: component }); diff --git a/public/plugin.tsx b/public/plugin.tsx index 2f69ddc68..f9b8cf364 100644 --- a/public/plugin.tsx +++ b/public/plugin.tsx @@ -154,7 +154,7 @@ export class AlertingPlugin implements Plugin false, nextEnabled: () => false }); + setAssistantDashboards(assistantDashboards || { getFeatureStatus: () => ({ chat: false, alertInsight: false }) }); setUISettings(core.uiSettings); From 40796e497d4e399038369ac59d3791994253407a Mon Sep 17 00:00:00 2001 From: Songkan Tang Date: Tue, 3 Sep 2024 15:25:00 +0800 Subject: [PATCH 11/17] Add assistant capabilities check to control component rendering Signed-off-by: Songkan Tang --- public/pages/Dashboard/utils/tableUtils.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/public/pages/Dashboard/utils/tableUtils.js b/public/pages/Dashboard/utils/tableUtils.js index 97d23a55e..b6fd1bed4 100644 --- a/public/pages/Dashboard/utils/tableUtils.js +++ b/public/pages/Dashboard/utils/tableUtils.js @@ -8,7 +8,7 @@ import _ from 'lodash'; import { EuiLink, EuiToolTip } from '@elastic/eui'; import moment from 'moment'; import { ALERT_STATE, DEFAULT_EMPTY_DATA, MONITOR_TYPE } from '../../../utils/constants'; -import { getAssistantDashboards } from '../../../services'; +import { getApplication, getAssistantDashboards } from '../../../services'; import { getDataSourceQueryObj } from '../../../pages/utils/helpers'; export const renderTime = (time) => { @@ -222,8 +222,10 @@ export const alertColumns = ( }; }; + const isSubscriptionActive = + getApplication().capabilities?.assistant?.isSubscriptionActive === true; const assistantFeatureStatus = getAssistantDashboards().getFeatureStatus(); - if (assistantFeatureStatus.alertInsight) { + if (assistantFeatureStatus.alertInsight && isSubscriptionActive) { getAssistantDashboards().registerIncontextInsight([ { key: alertId, From 35f5f8ea5863a13323354c937d3a670b4526406a Mon Sep 17 00:00:00 2001 From: Songkan Tang Date: Tue, 3 Sep 2024 15:47:08 +0800 Subject: [PATCH 12/17] Fix mismatched unit test snapshots Signed-off-by: Songkan Tang --- .../containers/__snapshots__/Dashboard.test.js.snap | 13 +++++++++++++ .../__snapshots__/DestinationsList.test.js.snap | 3 +++ 2 files changed, 16 insertions(+) diff --git a/public/pages/Dashboard/containers/__snapshots__/Dashboard.test.js.snap b/public/pages/Dashboard/containers/__snapshots__/Dashboard.test.js.snap index 21adda480..575374ee4 100644 --- a/public/pages/Dashboard/containers/__snapshots__/Dashboard.test.js.snap +++ b/public/pages/Dashboard/containers/__snapshots__/Dashboard.test.js.snap @@ -221,6 +221,7 @@ exports[`Dashboard renders in flyout 1`] = ` > Date: Thu, 5 Sep 2024 16:48:47 +0800 Subject: [PATCH 13/17] Handle the edge case of multiple indices in search and return more information in additionalInfo Signed-off-by: Songkan Tang --- public/pages/Dashboard/utils/tableUtils.js | 33 +++++++++++++--------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/public/pages/Dashboard/utils/tableUtils.js b/public/pages/Dashboard/utils/tableUtils.js index b6fd1bed4..92a879f0a 100644 --- a/public/pages/Dashboard/utils/tableUtils.js +++ b/public/pages/Dashboard/utils/tableUtils.js @@ -171,12 +171,15 @@ export const alertColumns = ( // 2. get data triggers the alert let alertTriggeredByData = ''; let dsl = ''; + let index = ''; if ( monitorResp.resp.monitor_type === MONITOR_TYPE.QUERY_LEVEL || monitorResp.resp.monitor_type === MONITOR_TYPE.BUCKET_LEVEL ) { const search = monitorResp.resp.inputs[0].search; - const indices = search.indices; + const indices = String(search.indices); + const splitIndices = indices.split(','); + index = splitIndices.length > 0 ? splitIndices[0].trim() : ''; let query = JSON.stringify(search.query); // Only keep the query part dsl = JSON.stringify({ query: search.query.query }); @@ -193,19 +196,21 @@ export const alertColumns = ( // as we changed the format, remove it monitorDefinitionStr = monitorDefinitionStr.replaceAll('"format":"epoch_millis",', ''); } - const alertData = await httpClient.post(`/api/console/proxy`, { - query: { - path: `${indices}/_search`, - method: 'GET', - dataSourceId: dataSourceQuery ? dataSourceQuery.query.dataSourceId : '', - }, - body: query, - prependBasePath: true, - asResponse: true, - withLongNumeralsSupport: true, - }); + if (index) { + const alertData = await httpClient.post(`/api/console/proxy`, { + query: { + path: `${index}/_search`, + method: 'GET', + dataSourceId: dataSourceQuery ? dataSourceQuery.query.dataSourceId : '', + }, + body: query, + prependBasePath: true, + asResponse: true, + withLongNumeralsSupport: true, + }); - alertTriggeredByData = JSON.stringify(alertData.body); + alertTriggeredByData = JSON.stringify(alertData.body); + } } // 3. build the context @@ -218,6 +223,8 @@ export const alertColumns = ( ### Alert query DSL ${dsl} \n`, additionalInfo: { monitorType: monitorResp.resp.monitor_type, + dsl: dsl, + index: index, }, }; }; From 40da2ca652991fdf5c0439b4e1c9c29f339d7458 Mon Sep 17 00:00:00 2001 From: Songkan Tang Date: Fri, 6 Sep 2024 15:06:04 +0800 Subject: [PATCH 14/17] Reduce llm context input size by taking topN active alerts Signed-off-by: Songkan Tang --- public/pages/Dashboard/utils/tableUtils.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/public/pages/Dashboard/utils/tableUtils.js b/public/pages/Dashboard/utils/tableUtils.js index 92a879f0a..a6fc5b7d6 100644 --- a/public/pages/Dashboard/utils/tableUtils.js +++ b/public/pages/Dashboard/utils/tableUtils.js @@ -185,7 +185,7 @@ export const alertColumns = ( dsl = JSON.stringify({ query: search.query.query }); if (query.indexOf('{{period_end}}') !== -1) { query = query.replaceAll('{{period_end}}', alert.start_time); - const alertStartTime = moment.utc(alert.start_time).format('YYYY-MM-DD HH:mm:ss'); + const alertStartTime = moment.utc(alert.start_time).format('YYYY-MM-DDTHH:mm:ss'); dsl = dsl.replaceAll('{{period_end}}', alertStartTime); // as we changed the format, remove it dsl = dsl.replaceAll('"format":"epoch_millis",', ''); @@ -213,12 +213,18 @@ export const alertColumns = ( } } + const filteredAlert = { ...alert }; + const topN = 10; + const activeAlerts = alert.alerts.filter((alert) => alert.state === 'ACTIVE'); + // Reduce llm input token size by taking topN active alerts + filteredAlert.alerts = activeAlerts.slice(0, topN); + // 3. build the context return { context: ` Here is the detail information about alert ${alert.trigger_name} ### Monitor definition\n ${monitorDefinitionStr}\n - ### Active Alert\n ${JSON.stringify(alert)}\n + ### Active Alert\n ${JSON.stringify(filteredAlert)}\n ### Data triggers this alert\n ${alertTriggeredByData}\n ### Alert query DSL ${dsl} \n`, additionalInfo: { From d1685138bda28830c53b9c4bfac09fe6ebcbaebe Mon Sep 17 00:00:00 2001 From: Songkan Tang Date: Mon, 9 Sep 2024 16:05:33 +0800 Subject: [PATCH 15/17] Distinguish source data and aggregation that trigger the alert Signed-off-by: Songkan Tang --- public/pages/Dashboard/utils/tableUtils.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/public/pages/Dashboard/utils/tableUtils.js b/public/pages/Dashboard/utils/tableUtils.js index a6fc5b7d6..af2aac974 100644 --- a/public/pages/Dashboard/utils/tableUtils.js +++ b/public/pages/Dashboard/utils/tableUtils.js @@ -170,6 +170,7 @@ export const alertColumns = ( // 2. get data triggers the alert let alertTriggeredByData = ''; + let alertTriggeredByValue = ''; let dsl = ''; let index = ''; if ( @@ -180,7 +181,10 @@ export const alertColumns = ( const indices = String(search.indices); const splitIndices = indices.split(','); index = splitIndices.length > 0 ? splitIndices[0].trim() : ''; - let query = JSON.stringify(search.query); + const searchQuery = search.query; + // By default, we take top 20 sample data that triggered the alert + searchQuery.size = 20; + let query = JSON.stringify(searchQuery); // Only keep the query part dsl = JSON.stringify({ query: search.query.query }); if (query.indexOf('{{period_end}}') !== -1) { @@ -209,7 +213,10 @@ export const alertColumns = ( withLongNumeralsSupport: true, }); - alertTriggeredByData = JSON.stringify(alertData.body); + alertTriggeredByData = JSON.stringify(alertData.body.hits.hits); + alertTriggeredByValue = JSON.stringify( + alertData.body.aggregations?.metric.value || alertData.body.hits.total.value + ); } } @@ -225,7 +232,8 @@ export const alertColumns = ( Here is the detail information about alert ${alert.trigger_name} ### Monitor definition\n ${monitorDefinitionStr}\n ### Active Alert\n ${JSON.stringify(filteredAlert)}\n - ### Data triggers this alert\n ${alertTriggeredByData}\n + ### Source data triggers this alert\n ${alertTriggeredByData}\n + ### Value triggers this alert\n ${alertTriggeredByValue}\n ### Alert query DSL ${dsl} \n`, additionalInfo: { monitorType: monitorResp.resp.monitor_type, From 3cfafd4955c675b1ad917733bd5b1500e2c7e732 Mon Sep 17 00:00:00 2001 From: Songkan Tang Date: Wed, 11 Sep 2024 17:31:09 +0800 Subject: [PATCH 16/17] Rename the capability UI rendering flag per assistant plugin change Signed-off-by: Songkan Tang --- public/pages/Dashboard/utils/tableUtils.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/public/pages/Dashboard/utils/tableUtils.js b/public/pages/Dashboard/utils/tableUtils.js index 6984477a5..435f24c96 100644 --- a/public/pages/Dashboard/utils/tableUtils.js +++ b/public/pages/Dashboard/utils/tableUtils.js @@ -244,10 +244,9 @@ export const alertColumns = ( }; }; - const isSubscriptionActive = - getApplication().capabilities?.assistant?.isSubscriptionActive === true; + const assistantEnabled = getApplication().capabilities?.assistant?.enabled === true; const assistantFeatureStatus = getAssistantDashboards().getFeatureStatus(); - if (assistantFeatureStatus.alertInsight && isSubscriptionActive) { + if (assistantFeatureStatus.alertInsight && assistantEnabled) { getAssistantDashboards().registerIncontextInsight([ { key: alertId, From 6ef6588c1c85a281f924faf219cb0b0c420a824a Mon Sep 17 00:00:00 2001 From: Songkan Tang Date: Wed, 11 Sep 2024 17:44:18 +0800 Subject: [PATCH 17/17] Remove alert sample data per current requirement from context Signed-off-by: Songkan Tang --- public/pages/Dashboard/utils/tableUtils.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/public/pages/Dashboard/utils/tableUtils.js b/public/pages/Dashboard/utils/tableUtils.js index 435f24c96..9959af144 100644 --- a/public/pages/Dashboard/utils/tableUtils.js +++ b/public/pages/Dashboard/utils/tableUtils.js @@ -170,7 +170,6 @@ export const alertColumns = ( let monitorDefinitionStr = JSON.stringify(monitorDefinition); // 2. get data triggers the alert - let alertTriggeredByData = ''; let alertTriggeredByValue = ''; let dsl = ''; let index = ''; @@ -182,10 +181,7 @@ export const alertColumns = ( const indices = String(search.indices); const splitIndices = indices.split(','); index = splitIndices.length > 0 ? splitIndices[0].trim() : ''; - const searchQuery = search.query; - // By default, we take top 20 sample data that triggered the alert - searchQuery.size = 20; - let query = JSON.stringify(searchQuery); + let query = JSON.stringify(search.query); // Only keep the query part dsl = JSON.stringify({ query: search.query.query }); if (query.indexOf('{{period_end}}') !== -1) { @@ -214,7 +210,6 @@ export const alertColumns = ( withLongNumeralsSupport: true, }); - alertTriggeredByData = JSON.stringify(alertData.body.hits.hits); alertTriggeredByValue = JSON.stringify( alertData.body.aggregations?.metric.value || alertData.body.hits.total.value ); @@ -233,7 +228,6 @@ export const alertColumns = ( Here is the detail information about alert ${alert.trigger_name} ### Monitor definition\n ${monitorDefinitionStr}\n ### Active Alert\n ${JSON.stringify(filteredAlert)}\n - ### Source data triggers this alert\n ${alertTriggeredByData}\n ### Value triggers this alert\n ${alertTriggeredByValue}\n ### Alert query DSL ${dsl} \n`, additionalInfo: {