diff --git a/.cypress/integration/panels_test/panels.spec.ts b/.cypress/integration/panels_test/panels.spec.ts index 6bd6abc67..c04c841dd 100644 --- a/.cypress/integration/panels_test/panels.spec.ts +++ b/.cypress/integration/panels_test/panels.spec.ts @@ -70,7 +70,11 @@ describe('Panels testing with Sample Data', { defaultCommandTimeout: 10000 }, () // cy.get('[id^=autocomplete-textarea]').focus().type(PPL_VISUALIZATIONS[1], { // delay: 50, // }); - cy.get('[id^=autocomplete-textarea]').focus().invoke('val', PPL_VISUALIZATIONS[1]).trigger('input').trigger('change'); + cy.get('[id^=autocomplete-textarea]') + .focus() + .invoke('val', PPL_VISUALIZATIONS[1]) + .trigger('input') + .trigger('change'); cy.get('.euiButton__text').contains('Run').trigger('mouseover').click(); cy.get('button[id="main-content-vis"]') .contains('Visualizations') diff --git a/common/utils/tenant_index_name.ts b/common/utils/tenant_index_name.ts new file mode 100644 index 000000000..697ec7fdd --- /dev/null +++ b/common/utils/tenant_index_name.ts @@ -0,0 +1,17 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export function getTenantIndexName(indexName: string, tenantName?: string) { + if (indexName.charAt(indexName.length - 1) === '*') { + indexName = indexName.slice(0, -1); + } + + if (tenantName) { + if (indexName.charAt(indexName.length - 1) !== '-') indexName += '-'; + indexName += `${tenantName.toLowerCase()}`; + } + + return indexName + '*'; +} diff --git a/public/components/app.tsx b/public/components/app.tsx index 6ccf017fc..8a77967e9 100644 --- a/public/components/app.tsx +++ b/public/components/app.tsx @@ -30,6 +30,7 @@ interface ObservabilityAppDeps { pplService: any; dslService: any; savedObjects: any; + config: PublicConfig; timestampUtils: any; queryManager: QueryManager; startPage: string; @@ -64,6 +65,7 @@ export const App = ({ pplService, dslService, savedObjects, + config, timestampUtils, queryManager, startPage, @@ -98,6 +100,7 @@ export const App = ({ pplService={pplService} dslService={dslService} savedObjects={savedObjects} + config={config} timestampUtils={timestampUtils} queryManager={queryManager} parentBreadcrumb={parentBreadcrumb} diff --git a/public/components/application_analytics/components/config_components/service_config.tsx b/public/components/application_analytics/components/config_components/service_config.tsx index 181636aea..29bef55c4 100644 --- a/public/components/application_analytics/components/config_components/service_config.tsx +++ b/public/components/application_analytics/components/config_components/service_config.tsx @@ -38,6 +38,7 @@ export const ServiceConfig = (props: ServiceConfigProps) => { http, selectedServices, setSelectedServices, + tenant, } = props; const { mode } = props; const [servicesOpen, setServicesOpen] = useState(false); @@ -49,7 +50,7 @@ export const ServiceConfig = (props: ServiceConfigProps) => { const [modalLayout, setModalLayout] = useState(); useEffect(() => { - handleServiceMapRequest(http, dslService, mode, '', setServiceMap); + handleServiceMapRequest(http, dslService, mode, '', setServiceMap, undefined, tenant); }, []); useEffect(() => { diff --git a/public/components/application_analytics/components/flyout_components/service_detail_flyout.tsx b/public/components/application_analytics/components/flyout_components/service_detail_flyout.tsx index 94fb24262..54f8d5f6f 100644 --- a/public/components/application_analytics/components/flyout_components/service_detail_flyout.tsx +++ b/public/components/application_analytics/components/flyout_components/service_detail_flyout.tsx @@ -48,6 +48,7 @@ export function ServiceDetailFlyout(props: ServiceFlyoutProps) { closeServiceFlyout, openSpanFlyout, mode, + tenant, } = props; const [fields, setFields] = useState({}); const [serviceMap, setServiceMap] = useState({}); @@ -131,7 +132,7 @@ export function ServiceDetailFlyout(props: ServiceFlyoutProps) { appConfigs ); handleServiceViewRequest(serviceName, http, serviceDSL, setFields, mode); - handleServiceMapRequest(http, serviceDSL, mode, '', setServiceMap, serviceName); + handleServiceMapRequest(http, serviceDSL, mode, '', setServiceMap, serviceName, tenant); const spanDSL = filtersToDsl(mode, filters, query, startTime, endTime, 'app', appConfigs); spanDSL.query.bool.must.push({ term: { diff --git a/public/components/application_analytics/components/flyout_components/trace_detail_render.tsx b/public/components/application_analytics/components/flyout_components/trace_detail_render.tsx index bb55a94d9..7ee6f8e54 100644 --- a/public/components/application_analytics/components/flyout_components/trace_detail_render.tsx +++ b/public/components/application_analytics/components/flyout_components/trace_detail_render.tsx @@ -20,10 +20,17 @@ interface TraceDetailRenderProps { traceId: string; http: HttpStart; openSpanFlyout: (spanId: string) => void; - mode : TraceAnalyticsMode + mode: TraceAnalyticsMode; + tenant?: string; } -export const TraceDetailRender = ({ traceId, http, openSpanFlyout, mode }: TraceDetailRenderProps) => { +export const TraceDetailRender = ({ + traceId, + http, + openSpanFlyout, + mode, + tenant, +}: TraceDetailRenderProps) => { const [fields, setFields] = useState({}); const [serviceBreakdownData, setServiceBreakdownData] = useState([]); const [payloadData, setPayloadData] = useState(''); @@ -86,9 +93,16 @@ export const TraceDetailRender = ({ traceId, http, openSpanFlyout, mode }: Trace }, [traceId, fields, serviceBreakdownData, colorMap, payloadData]); useEffect(() => { - handleTraceViewRequest(traceId, http, fields, setFields, mode); - handleServicesPieChartRequest(traceId, http, setServiceBreakdownData, setColorMap, mode); - handlePayloadRequest(traceId, http, payloadData, setPayloadData, mode); + handleTraceViewRequest(traceId, http, fields, setFields, mode, tenant); + handleServicesPieChartRequest( + traceId, + http, + setServiceBreakdownData, + setColorMap, + mode, + tenant + ); + handlePayloadRequest(traceId, http, payloadData, setPayloadData, mode, tenant); }, [traceId]); return renderContent; diff --git a/public/components/index.tsx b/public/components/index.tsx index 853d463b3..d192cb11f 100644 --- a/public/components/index.tsx +++ b/public/components/index.tsx @@ -10,6 +10,7 @@ import { AppMountParameters, CoreStart } from '../../../../src/core/public'; import { DataSourceManagementPluginSetup } from '../../../../src/plugins/data_source_management/public'; import { AppPluginStartDependencies } from '../types'; import { App } from './app'; +import { PublicConfig } from '../plugin'; export const Observability = ( CoreStartProp: CoreStart, @@ -24,7 +25,8 @@ export const Observability = ( dataSourcePluggables: any, dataSourceManagement: DataSourceManagementPluginSetup, savedObjectsMDSClient: CoreStart['savedObjects'], - defaultRoute?: string + config: PublicConfig, + defaultRoute?: string, ) => { const { setHeaderActionMenu } = AppMountParametersProp; const { dataSource } = DepsStart; @@ -35,6 +37,7 @@ export const Observability = ( pplService={pplService} dslService={dslService} savedObjects={savedObjects} + config={config} timestampUtils={timestampUtils} queryManager={queryManager} startPage={startPage} diff --git a/public/components/trace_analytics/components/common/__tests__/__snapshots__/helper_functions.test.tsx.snap b/public/components/trace_analytics/components/common/__tests__/__snapshots__/helper_functions.test.tsx.snap index 0d6dad1ca..9393d7104 100644 --- a/public/components/trace_analytics/components/common/__tests__/__snapshots__/helper_functions.test.tsx.snap +++ b/public/components/trace_analytics/components/common/__tests__/__snapshots__/helper_functions.test.tsx.snap @@ -116,6 +116,33 @@ exports[`Helper functions renders no match and missing configuration messages 2` `; +exports[`Helper functions renders no match and missing configuration messages 3`] = ` + + + Learn more + + } + body={ + + The indices required for trace analytics (otel-v1-apm-span-test* and otel-v1-apm-service-map-test*) do not exist or you do not have permission to access them. + + } + title={ +

+ Trace Analytics not set up +

+ } + /> +
+`; + exports[`Helper functions renders panel title 1`] = ` { it('renders no match and missing configuration messages', () => { const noMatchMessage = shallow(); - const missingConfigurationMessage = shallow() + const missingConfigurationMessage = shallow( + + ); + const missingConfigurationMessageWithTenant = shallow( + + ); expect(noMatchMessage).toMatchSnapshot(); expect(missingConfigurationMessage).toMatchSnapshot(); + expect(missingConfigurationMessageWithTenant).toMatchSnapshot(); }); it('renders benchmark', () => { diff --git a/public/components/trace_analytics/components/common/helper_functions.tsx b/public/components/trace_analytics/components/common/helper_functions.tsx index aa110ea50..f579f5ad5 100644 --- a/public/components/trace_analytics/components/common/helper_functions.tsx +++ b/public/components/trace_analytics/components/common/helper_functions.tsx @@ -22,10 +22,7 @@ import { TraceAnalyticsMode } from '../../home'; import { serviceMapColorPalette } from './color_palette'; import { FilterType } from './filters/filters'; import { ServiceObject } from './plots/service_map'; - -const missingJaegerTracesConfigurationMessage = `The indices required for trace analytics (${JAEGER_INDEX_NAME} and ${JAEGER_SERVICE_INDEX_NAME}) do not exist or you do not have permission to access them.`; - -const missingDataPrepperTracesConfigurationMessage = `The indices required for trace analytics (${DATA_PREPPER_INDEX_NAME} and ${DATA_PREPPER_SERVICE_INDEX_NAME}) do not exist or you do not have permission to access them.`; +import { getTenantIndexName } from '../../../../../common/utils/tenant_index_name'; export function PanelTitle({ title, totalItems }: { title: string; totalItems?: number }) { return ( @@ -56,7 +53,23 @@ export function NoMatchMessage(props: { size: SpacerSize }) { ); } -export function MissingConfigurationMessage(props: { mode: TraceAnalyticsMode }) { +export function MissingConfigurationMessage(props: { mode: TraceAnalyticsMode; tenant?: string }) { + const missingJaegerTracesConfigurationMessage = `The indices required for trace analytics (${getTenantIndexName( + JAEGER_INDEX_NAME, + props.tenant + )} and ${getTenantIndexName( + JAEGER_SERVICE_INDEX_NAME, + props.tenant + )}) do not exist or you do not have permission to access them.`; + + const missingDataPrepperTracesConfigurationMessage = `The indices required for trace analytics (${getTenantIndexName( + DATA_PREPPER_INDEX_NAME, + props.tenant + )} and ${getTenantIndexName( + DATA_PREPPER_SERVICE_INDEX_NAME, + props.tenant + )}) do not exist or you do not have permission to access them.`; + const missingConfigurationBody = props.mode === 'jaeger' ? missingJaegerTracesConfigurationMessage diff --git a/public/components/trace_analytics/components/common/indices.ts b/public/components/trace_analytics/components/common/indices.ts new file mode 100644 index 000000000..a850a3087 --- /dev/null +++ b/public/components/trace_analytics/components/common/indices.ts @@ -0,0 +1,28 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { CoreStart } from '../../../../../../../src/core/public'; + +export async function loadTenantInfo(http: CoreStart['http'], multitenancyEnabled: boolean) { + if (!multitenancyEnabled) { + return; + } + + return await http + .get('/api/v1/multitenancy/tenant') + .then((tenant) => { + if (tenant === '' || tenant === '__user__') { + tenant = ''; + } + return tenant; + }) + .catch((error) => { + if (error.body.statusCode === 404) { + // endpoint doesn't exist, security plugin is not enabled. + return undefined; + } + console.error(`failed to request tenant: ${String(error)}`); + }); +} diff --git a/public/components/trace_analytics/components/dashboard/__tests__/dashboard.test.tsx b/public/components/trace_analytics/components/dashboard/__tests__/dashboard.test.tsx index 0ad1a8c59..dadabef5b 100644 --- a/public/components/trace_analytics/components/dashboard/__tests__/dashboard.test.tsx +++ b/public/components/trace_analytics/components/dashboard/__tests__/dashboard.test.tsx @@ -7,6 +7,7 @@ import { configure, mount } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; import React from 'react'; import { Dashboard } from '..'; +// eslint-disable-next-line jest/no-mocks-import import { coreStartMock } from '../../../../../../test/__mocks__/coreMocks'; describe('Dashboard component', () => { diff --git a/public/components/trace_analytics/components/dashboard/dashboard_content.tsx b/public/components/trace_analytics/components/dashboard/dashboard_content.tsx index 71c698211..3e9cce32d 100644 --- a/public/components/trace_analytics/components/dashboard/dashboard_content.tsx +++ b/public/components/trace_analytics/components/dashboard/dashboard_content.tsx @@ -53,6 +53,7 @@ export function DashboardContent(props: DashboardProps) { jaegerIndicesExist, toasts, dataSourceMDSId, + tenant, attributesFilterFields, } = props; const [tableItems, setTableItems] = useState([]); @@ -193,7 +194,8 @@ export function DashboardContent(props: DashboardProps) { mode, () => setShowTimeoutToast(true), dataSourceMDSId[0].id, - setPercentileMap + setPercentileMap, + tenant ).then(() => setLoading(false)); // service map should not be filtered by service name (https://github.com/opensearch-project/observability/issues/442) const serviceMapDSL = cloneDeep(DSL); @@ -209,7 +211,8 @@ export function DashboardContent(props: DashboardProps) { throughputPltItems, setThroughputPltItems, mode, - dataSourceMDSId[0].id + dataSourceMDSId[0].id, + tenant ); handleDashboardErrorRatePltRequest( @@ -219,7 +222,8 @@ export function DashboardContent(props: DashboardProps) { errorRatePltItems, setErrorRatePltItems, mode, - dataSourceMDSId[0].id + dataSourceMDSId[0].id, + tenant ); }; @@ -338,7 +342,7 @@ export function DashboardContent(props: DashboardProps) { )} ) : ( - + )} ); diff --git a/public/components/trace_analytics/components/services/__tests__/service_view.test.tsx b/public/components/trace_analytics/components/services/__tests__/service_view.test.tsx index 0299fe255..61bb70afe 100644 --- a/public/components/trace_analytics/components/services/__tests__/service_view.test.tsx +++ b/public/components/trace_analytics/components/services/__tests__/service_view.test.tsx @@ -7,6 +7,7 @@ import { configure, shallow } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; import React from 'react'; import { ServiceView } from '..'; +// eslint-disable-next-line jest/no-mocks-import import { coreStartMock } from '../../../../../../test/__mocks__/coreMocks'; describe('Service view component', () => { diff --git a/public/components/trace_analytics/components/services/service_view.tsx b/public/components/trace_analytics/components/services/service_view.tsx index 356f17ea1..1a4b4025c 100644 --- a/public/components/trace_analytics/components/services/service_view.tsx +++ b/public/components/trace_analytics/components/services/service_view.tsx @@ -64,7 +64,7 @@ interface ServiceViewProps extends TraceAnalyticsComponentDeps { } export function ServiceView(props: ServiceViewProps) { - const { mode, page, setCurrentSelectedService } = props; + const { mode, page, setCurrentSelectedService, tenant } = props; const [fields, setFields] = useState({}); const [serviceMap, setServiceMap] = useState({}); const [serviceMapIdSelected, setServiceMapIdSelected] = useState< @@ -87,7 +87,8 @@ export function ServiceView(props: ServiceViewProps) { DSL, setFields, mode, - props.dataSourceMDSId[0].id + props.dataSourceMDSId[0].id, + tenant ); if (mode === 'data_prepper') { handleServiceMapRequest( @@ -96,7 +97,8 @@ export function ServiceView(props: ServiceViewProps) { mode, props.dataSourceMDSId[0].id, setServiceMap, - props.serviceName + props.serviceName, + tenant ); } }; diff --git a/public/components/trace_analytics/components/services/services_content.tsx b/public/components/trace_analytics/components/services/services_content.tsx index c46d73ade..662e48674 100644 --- a/public/components/trace_analytics/components/services/services_content.tsx +++ b/public/components/trace_analytics/components/services/services_content.tsx @@ -44,6 +44,7 @@ export function ServicesContent(props: ServicesProps) { dataPrepperIndicesExist, jaegerIndicesExist, dataSourceMDSId, + tenant, attributesFilterFields, } = props; const [tableItems, setTableItems] = useState([]); @@ -128,14 +129,24 @@ export function ServicesContent(props: ServicesProps) { ); } await Promise.all([ - handleServicesRequest(http, DSL, setTableItems, mode, dataSourceMDSId[0].id), + handleServicesRequest( + http, + DSL, + setTableItems, + mode, + dataSourceMDSId[0].id, + undefined, + undefined, + tenant + ), handleServiceMapRequest( http, serviceMapDSL, mode, dataSourceMDSId[0].id, setServiceMap, - currService || filteredService + currService || filteredService, + tenant ), ]); @@ -204,6 +215,7 @@ export function ServicesContent(props: ServicesProps) { setCurrentSelectedService={setCurrentSelectedService} jaegerIndicesExist={jaegerIndicesExist} dataPrepperIndicesExist={dataPrepperIndicesExist} + tenant={tenant} isServiceTrendEnabled={isServiceTrendEnabled} setIsServiceTrendEnabled={setIsServiceTrendEnabled} serviceTrends={serviceTrends} diff --git a/public/components/trace_analytics/components/services/services_table.tsx b/public/components/trace_analytics/components/services/services_table.tsx index b9afb0954..50b86a284 100644 --- a/public/components/trace_analytics/components/services/services_table.tsx +++ b/public/components/trace_analytics/components/services/services_table.tsx @@ -44,6 +44,7 @@ interface ServicesTableProps { mode: TraceAnalyticsMode; jaegerIndicesExist: boolean; dataPrepperIndicesExist: boolean; + tenant?: string; isServiceTrendEnabled: boolean; setIsServiceTrendEnabled: React.Dispatch>; serviceTrends: ServiceTrends; @@ -63,6 +64,7 @@ export function ServicesTable(props: ServicesTableProps) { setRedirect, jaegerIndicesExist, dataPrepperIndicesExist, + tenant, isServiceTrendEnabled, setIsServiceTrendEnabled, serviceTrends, @@ -272,7 +274,7 @@ export function ServicesTable(props: ServicesTableProps) { (mode === 'data_prepper' && dataPrepperIndicesExist) || (mode === 'jaeger' && jaegerIndicesExist) ) ? ( - + ) : items?.length > 0 ? ( void; + tenant?: string; }) { - const { mode } = props; + const { mode, tenant } = props; const storedFilters = sessionStorage.getItem('TraceAnalyticsSpanFilters'); const fromApp = props.page === 'app'; const [spanFilters, setSpanFilters] = useState>( storedFilters ? JSON.parse(storedFilters) : [] ); + const [DSL, setDSL] = useState({}); let data: { gantt: any[]; table: any[]; ganttMaxX: number }; let setData: (data: { gantt: any[]; table: any[]; ganttMaxX: number }) => void; + const [localData, localSetData] = useState<{ gantt: any[]; table: any[]; ganttMaxX: number }>({ gantt: [], table: [], @@ -91,7 +94,8 @@ export function SpanDetailPanel(props: { props.colorMap, refreshDSL, mode, - props.dataSourceMDSId + props.dataSourceMDSId, + tenant ); }, 150); diff --git a/public/components/trace_analytics/components/traces/trace_view.tsx b/public/components/trace_analytics/components/traces/trace_view.tsx index bfe75e67a..ae5792b64 100644 --- a/public/components/trace_analytics/components/traces/trace_view.tsx +++ b/public/components/trace_analytics/components/traces/trace_view.tsx @@ -46,10 +46,11 @@ interface TraceViewProps extends TraceAnalyticsCoreDeps { dataSourceMDSId: DataSourceOption[]; dataSourceManagement: DataSourceManagementPluginSetup; setActionMenu: (menuMount: MountPoint | undefined) => void; + tenant?: string; } export function TraceView(props: TraceViewProps) { - const { mode } = props; + const { mode, tenant } = props; const page = 'traceView'; const renderTitle = (traceId: string) => { return ( @@ -178,7 +179,8 @@ export function TraceView(props: TraceViewProps) { fields, setFields, mode, - props.dataSourceMDSId[0].id + props.dataSourceMDSId[0].id, + tenant ); handlePayloadRequest( props.traceId, @@ -186,7 +188,8 @@ export function TraceView(props: TraceViewProps) { payloadData, setPayloadData, mode, - props.dataSourceMDSId[0].id + props.dataSourceMDSId[0].id, + tenant ); handleServicesPieChartRequest( props.traceId, @@ -194,9 +197,18 @@ export function TraceView(props: TraceViewProps) { setServiceBreakdownData, setColorMap, mode, - props.dataSourceMDSId[0].id + props.dataSourceMDSId[0].id, + tenant + ); + handleServiceMapRequest( + props.http, + DSL, + mode, + props.dataSourceMDSId[0].id, + setServiceMap, + undefined, + tenant ); - handleServiceMapRequest(props.http, DSL, mode, props.dataSourceMDSId[0].id, setServiceMap); }; useEffect(() => { @@ -252,7 +264,8 @@ export function TraceView(props: TraceViewProps) { ] ); refresh(); - }, [props.mode]); + }, [props.mode, props.tenant]); + return ( <> @@ -288,6 +301,7 @@ export function TraceView(props: TraceViewProps) { data={ganttData} setData={setGanttData} dataSourceMDSId={props.dataSourceMDSId[0].id} + tenant={tenant} /> diff --git a/public/components/trace_analytics/components/traces/traces.tsx b/public/components/trace_analytics/components/traces/traces.tsx index 8e067895f..8ca77b58a 100644 --- a/public/components/trace_analytics/components/traces/traces.tsx +++ b/public/components/trace_analytics/components/traces/traces.tsx @@ -17,6 +17,7 @@ export interface TracesProps extends TraceAnalyticsComponentDeps { traceIdColumnAction: any; toasts: Toast[]; dataSourceMDSId: DataSourceOption[]; + tenant?: string; } export function Traces(props: TracesProps) { diff --git a/public/components/trace_analytics/components/traces/traces_content.tsx b/public/components/trace_analytics/components/traces/traces_content.tsx index 35039cbb0..39a95b3d5 100644 --- a/public/components/trace_analytics/components/traces/traces_content.tsx +++ b/public/components/trace_analytics/components/traces/traces_content.tsx @@ -34,6 +34,9 @@ export function TracesContent(props: TracesProps) { mode, dataPrepperIndicesExist, jaegerIndicesExist, + dataSourceManagement, + dataSourceMDSId, + tenant, attributesFilterFields, } = props; const [tableItems, setTableItems] = useState([]); @@ -98,7 +101,8 @@ export function TracesContent(props: TracesProps) { setTableItems, mode, props.dataSourceMDSId[0].id, - sort + sort, + tenant ); setLoading(false); }; @@ -146,6 +150,7 @@ export function TracesContent(props: TracesProps) { traceIdColumnAction={traceIdColumnAction} jaegerIndicesExist={jaegerIndicesExist} dataPrepperIndicesExist={dataPrepperIndicesExist} + tenant={tenant} /> ); diff --git a/public/components/trace_analytics/components/traces/traces_table.tsx b/public/components/trace_analytics/components/traces/traces_table.tsx index fe0231338..ce9f0f7e2 100644 --- a/public/components/trace_analytics/components/traces/traces_table.tsx +++ b/public/components/trace_analytics/components/traces/traces_table.tsx @@ -37,10 +37,11 @@ interface TracesTableProps { traceIdColumnAction: any; jaegerIndicesExist: boolean; dataPrepperIndicesExist: boolean; + tenant?: string; } export function TracesTable(props: TracesTableProps) { - const { items, refresh, mode, loading, traceIdColumnAction } = props; + const { items, refresh, mode, loading, traceIdColumnAction, tenant } = props; const renderTitleBar = (totalItems?: number) => { return ( @@ -51,11 +52,9 @@ export function TracesTable(props: TracesTableProps) { ); }; - const columns = useMemo( - () => { - if (mode === 'data_prepper') { - return( - [ + const columns = useMemo(() => { + if (mode === 'data_prepper') { + return [ { field: 'trace_id', name: 'Trace ID', @@ -65,7 +64,7 @@ export function TracesTable(props: TracesTableProps) { render: (item) => ( - traceIdColumnAction(item)}> + traceIdColumnAction(item)}> {item.length < 24 ? ( item ) : ( @@ -152,79 +151,76 @@ export function TracesTable(props: TracesTableProps) { sortable: true, render: (item) => (item === 0 || item ? item : '-'), }, - ] as Array>) + ] as Array>; } else { - return ( - [ - { - field: 'trace_id', - name: 'Trace ID', - align: 'left', - sortable: true, - truncateText: true, - render: (item) => ( - - - traceIdColumnAction(item)}> - {item.length < 24 ? ( - item - ) : ( -
{truncate(item, { length: 24 })}
- )} -
-
- - - {(copy) => ( - - Click to copy - - )} - - - -
+ return [ + { + field: 'trace_id', + name: 'Trace ID', + align: 'left', + sortable: true, + truncateText: true, + render: (item) => ( + + + traceIdColumnAction(item)}> + {item.length < 24 ? ( + item + ) : ( +
{truncate(item, { length: 24 })}
+ )} +
+
+ + + {(copy) => ( + + Click to copy + + )} + + + +
+ ), + }, + { + field: 'latency', + name: 'Latency (ms)', + align: 'right', + sortable: true, + truncateText: true, + }, + { + field: 'error_count', + name: 'Errors', + align: 'right', + sortable: true, + render: (item) => + item == null ? ( + '-' + ) : item > 0 ? ( + + Yes + + ) : ( + 'No' ), - }, - { - field: 'latency', - name: 'Latency (ms)', - align: 'right', - sortable: true, - truncateText: true, - }, - { - field: 'error_count', - name: 'Errors', - align: 'right', - sortable: true, - render: (item) => - item == null ? ( - '-' - ) : item > 0 ? ( - - Yes - - ) : ( - 'No' - ), - }, - { - field: 'last_updated', - name: 'Last updated', - align: 'left', - sortable: true, - render: (item) => (item === 0 || item ? item : '-'), - }, - ] as Array>) + }, + { + field: 'last_updated', + name: 'Last updated', + align: 'left', + sortable: true, + render: (item) => (item === 0 || item ? item : '-'), + }, + ] as Array>; } - }, - [items] - ); + }, [items]); const titleBar = useMemo(() => renderTitleBar(items?.length), [items]); @@ -235,7 +231,7 @@ export function TracesTable(props: TracesTableProps) { }, }); - const onTableChange = async ({ currPage, sort }: { currPage: any; sort: any }) => { + const onTableChange = async ({ sort }: { currPage: any; sort: any }) => { if (typeof sort?.field !== 'string') return; // maps table column key to DSL aggregation name @@ -270,8 +266,11 @@ export function TracesTable(props: TracesTableProps) { {titleBar} - {!((mode === 'data_prepper' && props.dataPrepperIndicesExist) || (mode === 'jaeger' && props.jaegerIndicesExist)) ? ( - + {!( + (mode === 'data_prepper' && props.dataPrepperIndicesExist) || + (mode === 'jaeger' && props.jaegerIndicesExist) + ) ? ( + ) : items?.length > 0 ? ( void; jaegerIndicesExist: boolean; dataPrepperIndicesExist: boolean; + tenant?: string; attributesFilterFields: string[]; setSpanFlyout: ({ spanId, @@ -83,6 +88,8 @@ export const Home = (props: HomeProps) => { const [mode, setMode] = useState( (sessionStorage.getItem('TraceAnalyticsMode') as TraceAnalyticsMode) || 'jaeger' ); + const [tenantLoaded, setTenantLoaded] = useState(false); + const [tenantName, setTenantName] = useState(); const storedFilters = sessionStorage.getItem('TraceAnalyticsFilters'); const [query, setQuery] = useState(sessionStorage.getItem('TraceAnalyticsQuery') || ''); const [filters, setFilters] = useState( @@ -158,13 +165,24 @@ export const Home = (props: HomeProps) => { }, [props.setActionMenu, props.savedObjectsMDSClient.client, props.notifications]); useEffect(() => { - handleDataPrepperIndicesExistRequest( - props.http, - setDataPrepperIndicesExist, - dataSourceMDSId[0].id - ); - handleJaegerIndicesExistRequest(props.http, setJaegerIndicesExist, dataSourceMDSId[0].id); - }, [dataSourceMDSId]); + if (!tenantLoaded) + loadTenantInfo(props.http, props.config.multitenancy.enabled).then((tenant) => { + setTenantLoaded(true); + setTenantName(tenant); + handleDataPrepperIndicesExistRequest( + props.http, + setDataPrepperIndicesExist, + dataSourceMDSId[0].id, + tenant + ); + handleJaegerIndicesExistRequest( + props.http, + setJaegerIndicesExist, + dataSourceMDSId[0].id, + tenant + ); + }); + }, [props.config.multitenancy.enabled, tenantLoaded, dataSourceMDSId]); const modes = [ { id: 'jaeger', title: 'Jaeger', 'data-test-subj': 'jaeger-mode' }, @@ -279,6 +297,7 @@ export const Home = (props: HomeProps) => { }, jaegerIndicesExist, dataPrepperIndicesExist, + tenant: tenantName, notifications: props.notifications, dataSourceEnabled: props.dataSourceEnabled, dataSourceManagement: props.dataSourceManagement, @@ -345,21 +364,24 @@ export const Home = (props: HomeProps) => { /> ( - - )} + render={(routerProps) => + tenantLoaded && ( + + ) + } /> { !isNavGroupEnabled ? ( {props.dataSourceEnabled && dataSourceMenuComponent} - + {tenantLoaded && ( + + )} ) : ( <> {props.dataSourceEnabled && dataSourceMenuComponent} - + {tenantLoaded && ( + + )} ) } diff --git a/public/components/trace_analytics/requests/dashboard_request_handler.ts b/public/components/trace_analytics/requests/dashboard_request_handler.ts index 4ae1f5c60..6f4bf4815 100644 --- a/public/components/trace_analytics/requests/dashboard_request_handler.ts +++ b/public/components/trace_analytics/requests/dashboard_request_handler.ts @@ -35,7 +35,8 @@ export const handleDashboardRequest = async ( mode, setShowTimeoutToast, dataSourceMDSId?, - setPercentileMap? + setPercentileMap?, + tenant?: string ) => { // latency_variance should only be affected by timefilter const latencyVariances = await handleDslRequest( @@ -43,7 +44,9 @@ export const handleDashboardRequest = async ( timeFilterDSL, getDashboardTraceGroupPercentiles(mode), mode, - dataSourceMDSId + dataSourceMDSId, + undefined, + tenant ) .then((response) => { const map: any = {}; @@ -62,17 +65,22 @@ export const handleDashboardRequest = async ( latencyTrendDSL, getLatencyTrendQuery(), mode, - setShowTimeoutToast + undefined, + setShowTimeoutToast, + tenant ) .then((response) => { const map: any = {}; response.aggregations.trace_group_name.buckets.map((bucket) => { const latencyTrend = bucket.group_by_hour.buckets .slice(-24) - .filter((bucket) => bucket.average_latency?.value || bucket.average_latency?.value === 0); + .filter( + (latencyBucket) => + latencyBucket.average_latency?.value || latencyBucket.average_latency?.value === 0 + ); const values = { - x: latencyTrend.map((bucket) => bucket.key), - y: latencyTrend.map((bucket) => bucket.average_latency?.value || 0), + x: latencyTrend.map((latencyXBucket) => latencyXBucket.key), + y: latencyTrend.map((latencyYBucket) => latencyYBucket.average_latency?.value || 0), }; const latencyTrendData = values.x?.length > 0 @@ -121,7 +129,15 @@ export const handleDashboardRequest = async ( }) .catch((error) => console.error(error)); - await handleDslRequest(http, DSL, getDashboardQuery(), mode, dataSourceMDSId, setShowTimeoutToast) + await handleDslRequest( + http, + DSL, + getDashboardQuery(), + mode, + dataSourceMDSId, + setShowTimeoutToast, + tenant + ) .then((response) => { return Promise.all( response.aggregations.trace_group_name.buckets.map((bucket) => { @@ -152,15 +168,13 @@ export const handleJaegerDashboardRequest = async ( setItems, mode, setShowTimeoutToast, - dataSourceMDSId?, - setPercentileMap? + dataSourceMDSId? ) => { const latencyTrends = await handleDslRequest( http, latencyTrendDSL, getJaegerLatencyTrendQuery(), mode, - dataSourceMDSId, setShowTimeoutToast ) .then((response) => { @@ -168,10 +182,13 @@ export const handleJaegerDashboardRequest = async ( response.aggregations.trace_group_name.buckets.map((bucket) => { const latencyTrend = bucket.group_by_hour.buckets .slice(-24) - .filter((bucket) => bucket.average_latency?.value || bucket.average_latency?.value === 0); + .filter( + (latencyBucket) => + latencyBucket.average_latency?.value || latencyBucket.average_latency?.value === 0 + ); const values = { - x: latencyTrend.map((bucket) => bucket.key), - y: latencyTrend.map((bucket) => bucket.average_latency?.value || 0), + x: latencyTrend.map((latencyXBucket) => latencyXBucket.key), + y: latencyTrend.map((latencyYBucket) => latencyYBucket.average_latency?.value || 0), }; const latencyTrendData = values.x?.length > 0 @@ -281,15 +298,13 @@ export const handleJaegerErrorDashboardRequest = async ( setItems, mode, setShowTimeoutToast, - dataSourceMDSId?, - setPercentileMap? + dataSourceMDSId? ) => { const errorTrends = await handleDslRequest( http, latencyTrendDSL, getJaegerErrorTrendQuery(), mode, - dataSourceMDSId, setShowTimeoutToast ) .then((response) => { @@ -297,10 +312,13 @@ export const handleJaegerErrorDashboardRequest = async ( response.aggregations.trace_group_name.buckets.map((bucket) => { const errorTrend = bucket.group_by_hour.buckets .slice(-24) - .filter((bucket) => bucket.error_rate?.value || bucket.error_rate?.value === 0); + .filter( + (latencyBucket) => + latencyBucket.error_rate?.value || latencyBucket.error_rate?.value === 0 + ); const values = { - x: errorTrend.map((bucket) => bucket.key), - y: errorTrend.map((bucket) => bucket.error_rate?.value || 0), + x: errorTrend.map((latencyXBucket) => latencyXBucket.key), + y: errorTrend.map((latencyYBucket) => latencyYBucket.error_rate?.value || 0), }; const errorTrendData = values.x?.length > 0 diff --git a/public/components/trace_analytics/requests/queries/dashboard_queries.ts b/public/components/trace_analytics/requests/queries/dashboard_queries.ts index e840ca1bd..7b70d9779 100644 --- a/public/components/trace_analytics/requests/queries/dashboard_queries.ts +++ b/public/components/trace_analytics/requests/queries/dashboard_queries.ts @@ -805,7 +805,7 @@ export const getDashboardThroughputPltQuery = (mode: TraceAnalyticsMode, fixedIn }; }; -export const getDashboardErrorTopGroupsQuery = (mode: TraceAnalyticsMode) => { +export const getDashboardErrorTopGroupsQuery = () => { return { size: 0, query: { diff --git a/public/components/trace_analytics/requests/queries/services_queries.ts b/public/components/trace_analytics/requests/queries/services_queries.ts index ab3cd3ce0..0e6fd3b04 100644 --- a/public/components/trace_analytics/requests/queries/services_queries.ts +++ b/public/components/trace_analytics/requests/queries/services_queries.ts @@ -3,6 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { getTenantIndexName } from '../../../../../common/utils/tenant_index_name'; import { DATA_PREPPER_SERVICE_INDEX_NAME, JAEGER_SERVICE_INDEX_NAME, @@ -137,9 +138,12 @@ export const getRelatedServicesQuery = (serviceName: string) => { return query; }; -export const getServiceNodesQuery = (mode: TraceAnalyticsMode) => { +export const getServiceNodesQuery = (mode: TraceAnalyticsMode, tenant?: string) => { return { - index: mode === 'jaeger' ? JAEGER_SERVICE_INDEX_NAME : DATA_PREPPER_SERVICE_INDEX_NAME, + index: getTenantIndexName( + mode === 'jaeger' ? JAEGER_SERVICE_INDEX_NAME : DATA_PREPPER_SERVICE_INDEX_NAME, + tenant + ), size: 0, query: { bool: { @@ -178,10 +182,14 @@ export const getServiceNodesQuery = (mode: TraceAnalyticsMode) => { export const getServiceEdgesQuery = ( source: 'destination' | 'target', - mode: TraceAnalyticsMode + mode: TraceAnalyticsMode, + tenant?: string, ) => { return { - index: mode === 'jaeger' ? JAEGER_SERVICE_INDEX_NAME : DATA_PREPPER_SERVICE_INDEX_NAME, + index: getTenantIndexName( + mode === 'jaeger' ? JAEGER_SERVICE_INDEX_NAME : DATA_PREPPER_SERVICE_INDEX_NAME, + tenant + ), size: 0, query: { bool: { diff --git a/public/components/trace_analytics/requests/queries/traces_queries.ts b/public/components/trace_analytics/requests/queries/traces_queries.ts index fbff7cf69..dbaf4fe10 100644 --- a/public/components/trace_analytics/requests/queries/traces_queries.ts +++ b/public/components/trace_analytics/requests/queries/traces_queries.ts @@ -47,7 +47,11 @@ export const getTraceGroupPercentilesQuery = () => { return query; }; -export const getTracesQuery = (mode: TraceAnalyticsMode, traceId: string = '', sort?: PropertySort) => { +export const getTracesQuery = ( + mode: TraceAnalyticsMode, + traceId: string = '', + sort?: PropertySort +) => { const field = sort?.field || '_key'; const direction = sort?.direction || 'asc'; const jaegerQuery: any = { @@ -173,7 +177,7 @@ export const getTracesQuery = (mode: TraceAnalyticsMode, traceId: string = '', s if (traceId) { jaegerQuery.query.bool.must.push({ term: { - "traceID": traceId, + traceID: traceId, }, }); dataPrepperQuery.query.bool.must.push({ @@ -193,7 +197,7 @@ export const getServiceBreakdownQuery = (traceId: string, mode: TraceAnalyticsMo must: [ { term: { - "traceID": traceId, + traceID: traceId, }, }, ], @@ -276,7 +280,7 @@ export const getServiceBreakdownQuery = (traceId: string, mode: TraceAnalyticsMo }, }, }; - return mode === 'jaeger'? jaegerQuery : dataPrepperQuery; + return mode === 'jaeger' ? jaegerQuery : dataPrepperQuery; }; export const getSpanDetailQuery = (mode: TraceAnalyticsMode, traceId: string, size = 3000) => { @@ -288,7 +292,7 @@ export const getSpanDetailQuery = (mode: TraceAnalyticsMode, traceId: string, si must: [ { term: { - "traceID": traceId, + traceID: traceId, }, }, { @@ -318,11 +322,11 @@ export const getSpanDetailQuery = (mode: TraceAnalyticsMode, traceId: string, si 'spanID', 'tag', 'duration', - 'references' - ] + 'references', + ], }, }; - } + } return { size, query: { @@ -374,7 +378,7 @@ export const getPayloadQuery = (mode: TraceAnalyticsMode, traceId: string, size must: [ { term: { - "traceID": traceId, + traceID: traceId, }, }, ], @@ -413,7 +417,7 @@ export const getSpanFlyoutQuery = (mode: TraceAnalyticsMode, spanId?: string, si must: [ { term: { - "spanID": spanId, + spanID: spanId, }, }, ], @@ -500,4 +504,4 @@ export const getValidTraceIdsQuery = (DSL) => { }); } return query; -}; \ No newline at end of file +}; diff --git a/public/components/trace_analytics/requests/request_handler.ts b/public/components/trace_analytics/requests/request_handler.ts index 5babe0a33..ca19d7f14 100644 --- a/public/components/trace_analytics/requests/request_handler.ts +++ b/public/components/trace_analytics/requests/request_handler.ts @@ -3,6 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { getTenantIndexName } from '../../../../common/utils/tenant_index_name'; import { CoreStart } from '../../../../../../src/core/public'; import { DATA_PREPPER_INDEX_NAME, @@ -19,7 +20,8 @@ export async function handleDslRequest( bodyQuery: any, mode: TraceAnalyticsMode, dataSourceMDSId?: string, - setShowTimeoutToast?: () => void + setShowTimeoutToast?: () => void, + tenant?: string ) { if (DSL?.query) { bodyQuery.query.bool.must.push(...DSL.query.bool.must); @@ -31,10 +33,16 @@ export async function handleDslRequest( } let body = bodyQuery; if (!bodyQuery.index) { - body = { ...bodyQuery, index: mode === 'jaeger' ? JAEGER_INDEX_NAME : DATA_PREPPER_INDEX_NAME }; + body = { + ...bodyQuery, + index: getTenantIndexName( + mode === 'jaeger' ? JAEGER_INDEX_NAME : DATA_PREPPER_INDEX_NAME, + tenant + ), + }; } const query = { - dataSourceMDSId: dataSourceMDSId, + dataSourceMDSId, }; if (setShowTimeoutToast) { const id = setTimeout(() => setShowTimeoutToast(), 25000); // 25 seconds @@ -64,13 +72,17 @@ export async function handleDslRequest( export async function handleJaegerIndicesExistRequest( http: CoreStart['http'], setJaegerIndicesExist, - dataSourceMDSId?: string + dataSourceMDSId?: string, + tenant?: string ) { const query = { - dataSourceMDSId: dataSourceMDSId, + dataSourceMDSId, }; http .post(TRACE_ANALYTICS_JAEGER_INDICES_ROUTE, { + body: JSON.stringify({ + tenant, + }), query, }) .then((exists) => setJaegerIndicesExist(exists)) @@ -80,13 +92,17 @@ export async function handleJaegerIndicesExistRequest( export async function handleDataPrepperIndicesExistRequest( http: CoreStart['http'], setDataPrepperIndicesExist, - dataSourceMDSId?: string + dataSourceMDSId?: string, + tenant?: string ) { const query = { - dataSourceMDSId: dataSourceMDSId, + dataSourceMDSId, }; http .post(TRACE_ANALYTICS_DATA_PREPPER_INDICES_ROUTE, { + body: JSON.stringify({ + tenant, + }), query, }) .then((exists) => setDataPrepperIndicesExist(exists)) diff --git a/public/components/trace_analytics/requests/services_request_handler.ts b/public/components/trace_analytics/requests/services_request_handler.ts index 03c35a807..6f89f7874 100644 --- a/public/components/trace_analytics/requests/services_request_handler.ts +++ b/public/components/trace_analytics/requests/services_request_handler.ts @@ -31,14 +31,18 @@ export const handleServicesRequest = async ( mode: TraceAnalyticsMode, dataSourceMDSId?: string, setServiceMap?: any, - serviceNameFilter?: string + serviceNameFilter?: string, + tenant?: string ) => { return handleDslRequest( http, DSL, getServicesQuery(mode, serviceNameFilter, DSL), mode, - dataSourceMDSId + dataSourceMDSId, + setServiceMap, + undefined, + tenant ) .then(async (response) => { const serviceObject: ServiceObject = await handleServiceMapRequest( @@ -46,7 +50,9 @@ export const handleServicesRequest = async ( DSL, mode, dataSourceMDSId, - setServiceMap + setServiceMap, + undefined, + tenant ); return Promise.all( response.aggregations.service.buckets @@ -81,7 +87,8 @@ export const handleServiceMapRequest = async ( mode: TraceAnalyticsMode, dataSourceMDSId?: string, setItems?: any, - currService?: string + currService?: string, + tenant?: string ) => { let minutesInDateRange: number; const startTime = DSL.custom?.timeFilter?.[0]?.range?.startTime; @@ -92,7 +99,7 @@ export const handleServiceMapRequest = async ( } const map: ServiceObject = {}; let id = 1; - await handleDslRequest(http, null, getServiceNodesQuery(mode), mode, dataSourceMDSId) + await handleDslRequest(http, null, getServiceNodesQuery(mode, tenant), mode, dataSourceMDSId) .then((response) => response.aggregations.service_name.buckets.map( (bucket: any) => @@ -111,7 +118,13 @@ export const handleServiceMapRequest = async ( .catch((error) => console.error(error)); const targets = {}; - await handleDslRequest(http, null, getServiceEdgesQuery('target', mode), mode, dataSourceMDSId) + await handleDslRequest( + http, + null, + getServiceEdgesQuery('target', mode, tenant), + mode, + dataSourceMDSId + ) .then((response) => response.aggregations.service_name.buckets.map((bucket: any) => { bucket.resource.buckets.map((resource: any) => { @@ -125,7 +138,7 @@ export const handleServiceMapRequest = async ( await handleDslRequest( http, null, - getServiceEdgesQuery('destination', mode), + getServiceEdgesQuery('destination', mode, tenant), mode, dataSourceMDSId ) @@ -154,7 +167,9 @@ export const handleServiceMapRequest = async ( DSL, getServiceMetricsQuery(DSL, Object.keys(map), map, mode), mode, - dataSourceMDSId + dataSourceMDSId, + undefined, + tenant ); latencies.aggregations.service_name.buckets.map((bucket: any) => { map[bucket.key].latency = bucket.average_latency.value; @@ -165,7 +180,15 @@ export const handleServiceMapRequest = async ( }); if (currService) { - await handleDslRequest(http, DSL, getRelatedServicesQuery(currService), mode, dataSourceMDSId) + await handleDslRequest( + http, + DSL, + getRelatedServicesQuery(currService), + mode, + dataSourceMDSId, + undefined, + tenant + ) .then((response) => response.aggregations.traces.buckets.filter((bucket: any) => bucket.service.doc_count > 0) ) @@ -191,9 +214,18 @@ export const handleServiceViewRequest = ( DSL: any, setFields: any, mode: TraceAnalyticsMode, - dataSourceMDSId?: string + dataSourceMDSId?: string, + tenant?: string ) => { - handleDslRequest(http, DSL, getServicesQuery(mode, serviceName), mode, dataSourceMDSId) + handleDslRequest( + http, + DSL, + getServicesQuery(mode, serviceName), + mode, + dataSourceMDSId, + undefined, + tenant + ) .then(async (response) => { const bucket = response.aggregations.service.buckets[0]; if (!bucket) return {}; @@ -201,7 +233,10 @@ export const handleServiceViewRequest = ( http, DSL, mode, - dataSourceMDSId + dataSourceMDSId, + undefined, + undefined, + tenant ); const connectedServices = [ ...serviceObject[bucket.key].targetServices, diff --git a/public/components/trace_analytics/requests/traces_request_handler.ts b/public/components/trace_analytics/requests/traces_request_handler.ts index a8bebb742..afb030a45 100644 --- a/public/components/trace_analytics/requests/traces_request_handler.ts +++ b/public/components/trace_analytics/requests/traces_request_handler.ts @@ -39,7 +39,8 @@ export const handleTracesRequest = async ( setItems: (items: any) => void, mode: TraceAnalyticsMode, dataSourceMDSId?: string, - sort?: any + sort?: any, + tenant?: string ) => { const binarySearch = (arr: number[], target: number) => { if (!arr) return Number.NaN; @@ -60,7 +61,9 @@ export const handleTracesRequest = async ( timeFilterDSL, getTraceGroupPercentilesQuery(), mode, - dataSourceMDSId + dataSourceMDSId, + undefined, + tenant ).then((response) => { const map: any = {}; response.aggregations.trace_group_name.buckets.forEach((traceGroup: any) => { @@ -71,7 +74,15 @@ export const handleTracesRequest = async ( return map; }); - return handleDslRequest(http, DSL, getTracesQuery(mode, undefined, sort), mode, dataSourceMDSId) + return handleDslRequest( + http, + DSL, + getTracesQuery(mode, undefined, sort), + mode, + dataSourceMDSId, + undefined, + tenant + ) .then((response) => { return Promise.all( response.aggregations.traces.buckets.map((bucket: any) => { @@ -111,9 +122,18 @@ export const handleTraceViewRequest = ( fields: {}, setFields: (fields: any) => void, mode: TraceAnalyticsMode, - dataSourceMDSId?: string + dataSourceMDSId?: string, + tenant?: string ) => { - handleDslRequest(http, null, getTracesQuery(mode, traceId), mode, dataSourceMDSId) + handleDslRequest( + http, + null, + getTracesQuery(mode, traceId), + mode, + dataSourceMDSId, + undefined, + tenant + ) .then(async (response) => { const bucket = response.aggregations.traces.buckets[0]; return { @@ -141,7 +161,8 @@ export const handleServicesPieChartRequest = async ( setServiceBreakdownData: (serviceBreakdownData: any) => void, setColorMap: (colorMap: any) => void, mode: TraceAnalyticsMode, - dataSourceMDSId?: string + dataSourceMDSId?: string, + tenant?: string ) => { const colors = [ '#7492e7', @@ -159,7 +180,15 @@ export const handleServicesPieChartRequest = async ( ]; const colorMap: any = {}; let index = 0; - await handleDslRequest(http, null, getServiceBreakdownQuery(traceId, mode), mode, dataSourceMDSId) + await handleDslRequest( + http, + null, + getServiceBreakdownQuery(traceId, mode), + mode, + dataSourceMDSId, + undefined, + tenant + ) .then((response) => Promise.all( response.aggregations.service_type.buckets.map((bucket: any) => { @@ -205,9 +234,18 @@ export const handleSpansGanttRequest = ( colorMap: any, spanFiltersDSL: any, mode: TraceAnalyticsMode, - dataSourceMDSId?: string + dataSourceMDSId?: string, + tenant?: string ) => { - handleDslRequest(http, spanFiltersDSL, getSpanDetailQuery(mode, traceId), mode, dataSourceMDSId) + handleDslRequest( + http, + spanFiltersDSL, + getSpanDetailQuery(mode, traceId), + mode, + dataSourceMDSId, + undefined, + tenant + ) .then((response) => hitsToSpanDetailData(response.hits.hits, colorMap, mode)) .then((newItems) => setSpanDetailData(newItems)) .catch((error) => console.error(error)); @@ -318,9 +356,18 @@ export const handlePayloadRequest = ( payloadData: any, setPayloadData: (payloadData: any) => void, mode: TraceAnalyticsMode, - dataSourceMDSId?: string + dataSourceMDSId?: string, + tenant?: string ) => { - handleDslRequest(http, null, getPayloadQuery(mode, traceId), mode, dataSourceMDSId) + handleDslRequest( + http, + null, + getPayloadQuery(mode, traceId), + mode, + dataSourceMDSId, + undefined, + tenant + ) .then((response) => setPayloadData(JSON.stringify(response.hits.hits, null, 2))) .catch((error) => console.error(error)); }; diff --git a/public/plugin.tsx b/public/plugin.tsx index b2ee97850..708b14f9f 100644 --- a/public/plugin.tsx +++ b/public/plugin.tsx @@ -115,13 +115,16 @@ import { import { TablesFlyout } from './components/event_analytics/explorer/datasources/tables_flyout'; import { registerAllPluginNavGroups } from './plugin_nav'; -interface PublicConfig { +export interface PublicConfig { query_assist: { enabled: boolean; }; summarize: { enabled: boolean; }; + multitenancy: { + enabled: boolean; + }; } export const [ @@ -295,7 +298,8 @@ export class ObservabilityPlugin dataSourcePluggables, // just pass down for now due to time constraint, later may better expose this as context dataSourceManagement, coreStart.savedObjects, - defaultRoute + this.config, + defaultRoute, ); }; diff --git a/server/index.ts b/server/index.ts index 9719a9f98..7be0b7261 100644 --- a/server/index.ts +++ b/server/index.ts @@ -21,6 +21,9 @@ const observabilityConfig = { summarize: schema.object({ enabled: schema.boolean({ defaultValue: false }), }), + multitenancy: schema.object({ + enabled: schema.boolean({ defaultValue: false }), + }), }), }; @@ -31,5 +34,6 @@ export const config: PluginConfigDescriptor = { exposeToBrowser: { query_assist: true, summarize: true, + multitenancy: true, }, }; diff --git a/server/routes/trace_analytics_dsl_router.ts b/server/routes/trace_analytics_dsl_router.ts index 4fe62ab5d..5d4725d98 100644 --- a/server/routes/trace_analytics_dsl_router.ts +++ b/server/routes/trace_analytics_dsl_router.ts @@ -16,21 +16,28 @@ import { TRACE_ANALYTICS_JAEGER_INDICES_ROUTE, } from '../../common/constants/trace_analytics'; import { addRequestToMetric } from '../common/metrics/metrics_helper'; +import { getTenantIndexName } from '../../common/utils/tenant_index_name'; export function registerTraceAnalyticsDslRouter(router: IRouter, dataSourceEnabled: boolean) { router.post( { path: TRACE_ANALYTICS_DATA_PREPPER_INDICES_ROUTE, validate: { - body: schema.any(), + body: schema.object({ + tenant: schema.maybe(schema.string()), + }), query: schema.object({ dataSourceMDSId: schema.maybe(schema.string({ defaultValue: '' })), }), }, }, async (context, request, response) => { + const { tenant } = request.body; const params: RequestParams.IndicesExists = { - index: [DATA_PREPPER_INDEX_NAME, DATA_PREPPER_SERVICE_INDEX_NAME], + index: [ + getTenantIndexName(DATA_PREPPER_INDEX_NAME, tenant), + getTenantIndexName(DATA_PREPPER_SERVICE_INDEX_NAME, tenant), + ], allow_no_indices: false, }; const { dataSourceMDSId } = request.query; @@ -61,7 +68,9 @@ export function registerTraceAnalyticsDslRouter(router: IRouter, dataSourceEnabl { path: TRACE_ANALYTICS_JAEGER_INDICES_ROUTE, validate: { - body: schema.any(), + body: schema.object({ + tenant: schema.maybe(schema.string()), + }), query: schema.object({ dataSourceMDSId: schema.maybe(schema.string({ defaultValue: '' })), }), @@ -69,8 +78,12 @@ export function registerTraceAnalyticsDslRouter(router: IRouter, dataSourceEnabl }, async (context, request, response) => { const { dataSourceMDSId } = request.query; + const { tenant } = request.body; const params: RequestParams.IndicesExists = { - index: [JAEGER_INDEX_NAME, JAEGER_SERVICE_INDEX_NAME], + index: [ + getTenantIndexName(JAEGER_INDEX_NAME, tenant), + getTenantIndexName(JAEGER_SERVICE_INDEX_NAME, tenant), + ], allow_no_indices: false, }; try { @@ -102,6 +115,7 @@ export function registerTraceAnalyticsDslRouter(router: IRouter, dataSourceEnabl validate: { body: schema.object({ index: schema.maybe(schema.string()), + tenant: schema.maybe(schema.string()), from: schema.maybe(schema.number()), size: schema.number(), query: schema.maybe( @@ -134,10 +148,10 @@ export function registerTraceAnalyticsDslRouter(router: IRouter, dataSourceEnabl }, async (context, request, response) => { addRequestToMetric('trace_analytics', 'get', 'count'); - const { index, size, ...rest } = request.body; + const { index, size, tenant, ...rest } = request.body; const { dataSourceMDSId } = request.query; const params: RequestParams.Search = { - index: index || DATA_PREPPER_INDEX_NAME, + index: index || getTenantIndexName(DATA_PREPPER_INDEX_NAME, tenant), size, body: rest, };