diff --git a/common/constants/trace_analytics.ts b/common/constants/trace_analytics.ts index e1ea188715..060cf01cdc 100644 --- a/common/constants/trace_analytics.ts +++ b/common/constants/trace_analytics.ts @@ -7,14 +7,17 @@ export const JAEGER_INDEX_NAME = '*jaeger-span-*'; export const JAEGER_SERVICE_INDEX_NAME = '*jaeger-service*'; export const DATA_PREPPER_INDEX_NAME = 'otel-v1-apm-span-*'; export const DATA_PREPPER_SERVICE_INDEX_NAME = 'otel-v1-apm-service-map*'; -export const TRACE_ANALYTICS_DATE_FORMAT = 'MM/DD/YYYY HH:mm:ss'; -export const TRACE_ANALYTICS_PLOTS_DATE_FORMAT = 'MMM D, YYYY HH:mm:ss'; +export const TRACE_ANALYTICS_DATE_FORMAT = 'MM/DD/YYYY HH:mm:ss.SSS'; +export const TRACE_ANALYTICS_PLOTS_DATE_FORMAT = 'MMM D, YYYY HH:mm:ss.SSS'; export const SERVICE_MAP_MAX_NODES = 500; // size limit when requesting edge related queries, not necessarily the number of edges export const SERVICE_MAP_MAX_EDGES = 1000; export const TRACES_MAX_NUM = 3000; -export const TRACE_ANALYTICS_DOCUMENTATION_LINK = 'https://opensearch.org/docs/latest/observability-plugin/trace/index/'; +export const TRACE_ANALYTICS_DOCUMENTATION_LINK = + 'https://opensearch.org/docs/latest/observability-plugin/trace/index/'; -export const TRACE_ANALYTICS_JAEGER_INDICES_ROUTE = '/api/observability/trace_analytics/jaeger_indices'; -export const TRACE_ANALYTICS_DATA_PREPPER_INDICES_ROUTE = '/api/observability/trace_analytics/data_prepper_indices'; +export const TRACE_ANALYTICS_JAEGER_INDICES_ROUTE = + '/api/observability/trace_analytics/jaeger_indices'; +export const TRACE_ANALYTICS_DATA_PREPPER_INDICES_ROUTE = + '/api/observability/trace_analytics/data_prepper_indices'; export const TRACE_ANALYTICS_DSL_ROUTE = '/api/observability/trace_analytics/query'; diff --git a/public/components/application_analytics/components/application.tsx b/public/components/application_analytics/components/application.tsx index 411ad30059..991f28f95d 100644 --- a/public/components/application_analytics/components/application.tsx +++ b/public/components/application_analytics/components/application.tsx @@ -311,8 +311,6 @@ export function Application(props: AppDetailProps) { setSelectedTab(TAB_TRACE_ID); }; - const traceIdColumnAction = (item: any) => openTraceFlyout(item); - const getTrace = () => { return ( <> @@ -322,7 +320,7 @@ export function Application(props: AppDetailProps) { page="app" parentBreadcrumb={parentBreadcrumbs[0]} childBreadcrumbs={childBreadcrumbs} - traceIdColumnAction={traceIdColumnAction} + openTraceFlyout={openTraceFlyout} startTime={appStartTime} endTime={appEndTime} setStartTime={setStartTimeForApp} diff --git a/public/components/trace_analytics/components/traces/__tests__/__snapshots__/traces.test.tsx.snap b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/traces.test.tsx.snap index 1cdc7e0986..1b09ef9099 100644 --- a/public/components/trace_analytics/components/traces/__tests__/__snapshots__/traces.test.tsx.snap +++ b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/traces.test.tsx.snap @@ -195,6 +195,7 @@ exports[`Traces component renders empty traces page 1`] = ` } endTime="now" filters={Array []} + getTraceViewUri={[MockFunction]} http={[MockFunction]} mode="data_prepper" modes={ @@ -236,7 +237,6 @@ exports[`Traces component renders empty traces page 1`] = ` setQuery={[MockFunction]} setStartTime={[MockFunction]} startTime="now-5m" - traceIdColumnAction={[Function]} >
- + Percentile in trace group +
, + "render": [Function], + "sortable": true, + }, + Object { + "align": "right", + "field": "error_count", + "name": "Errors", + "render": [Function], + "sortable": true, + }, + Object { + "align": "left", + "field": "last_updated", + "name": "Last updated", + "render": [Function], + "sortable": true, + }, + ] + } + items={Array []} + loading={true} + onTableChange={[Function]} + pagination={ + Object { + "initialPageSize": 10, + "pageSizeOptions": Array [ + 5, + 10, + 15, + ], + } + } + responsive={true} + sorting={ + Object { + "sort": Object { + "direction": "asc", + "field": "trace_id", + }, + } + } + tableLayout="auto" > - -
- - - No data matches the selected filter. Clear the filter and/or increase the time range to see more results. - + + Percentile in trace group +
, + "render": [Function], + "sortable": true, + }, + Object { + "align": "right", + "field": "error_count", + "name": "Errors", + "render": [Function], + "sortable": true, + }, + Object { + "align": "left", + "field": "last_updated", + "name": "Last updated", + "render": [Function], + "sortable": true, + }, + ] + } + items={Array []} + loading={true} + noItemsMessage="No items found" + onChange={[Function]} + pagination={ + Object { + "hidePerPageOptions": undefined, + "pageIndex": 0, + "pageSize": 10, + "pageSizeOptions": Array [ + 5, + 10, + 15, + ], + "totalItemCount": 0, + } } - title={ -

- No matches -

+ responsive={true} + sorting={ + Object { + "allowNeutralSort": false, + "sort": Object { + "direction": "asc", + "field": "Trace ID", + }, + } } + tableLayout="auto" >
- -

- No matches -

-
- - - + +
-
- - -
- -
+ - No data matches the selected filter. Clear the filter and/or increase the time range to see more results. -
-
-
-
- - +
+ + +
+ + Percentile in trace group +
, + "onSort": [Function], + }, + Object { + "isSortAscending": undefined, + "isSorted": false, + "key": "_data_s_error_count_4", + "name": "Errors", + "onSort": [Function], + }, + Object { + "isSortAscending": undefined, + "isSorted": false, + "key": "_data_s_last_updated_5", + "name": "Last updated", + "onSort": [Function], + }, + ] + } + > +
+ + + + } + closePopover={[Function]} + display="inlineBlock" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelPaddingSize="none" + > +
+
+ + + +
+
+
+
+ +
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + +
+
+ + No items found + +
+
+
+
- - -
- - + +
@@ -1877,6 +2601,7 @@ exports[`Traces component renders jaeger traces page 1`] = ` } endTime="now" filters={Array []} + getTraceViewUri={[MockFunction]} http={[MockFunction]} jaegerIndicesExist={true} mode="jaeger" @@ -1921,7 +2646,6 @@ exports[`Traces component renders jaeger traces page 1`] = ` setQuery={[MockFunction]} setStartTime={[MockFunction]} startTime="now-5m" - traceIdColumnAction={[Function]} >
- - -
- - - No data matches the selected filter. Clear the filter and/or increase the time range to see more results. - + - No matches - + responsive={true} + sorting={ + Object { + "allowNeutralSort": false, + "sort": Object { + "direction": "asc", + "field": "Trace ID", + }, + } } + tableLayout="auto" >
- -

- No matches -

-
- - - + +
-
- - -
- -
+ - No data matches the selected filter. Clear the filter and/or increase the time range to see more results. -
-
-
-
- - -
- - -
- - +
+ + +
+ +
+ + + + } + closePopover={[Function]} + display="inlineBlock" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelPaddingSize="none" + > +
+
+ + + +
+
+
+
+
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + +
+
+ + No items found + +
+
+
+
+
+
+
@@ -3568,6 +4849,7 @@ exports[`Traces component renders traces page 1`] = ` } endTime="now" filters={Array []} + getTraceViewUri={[MockFunction]} http={[MockFunction]} mode="data_prepper" modes={ @@ -3611,7 +4893,6 @@ exports[`Traces component renders traces page 1`] = ` setQuery={[MockFunction]} setStartTime={[MockFunction]} startTime="now-5m" - traceIdColumnAction={[Function]} >
- + Percentile in trace group +
, + "render": [Function], + "sortable": true, + }, + Object { + "align": "right", + "field": "error_count", + "name": "Errors", + "render": [Function], + "sortable": true, + }, + Object { + "align": "left", + "field": "last_updated", + "name": "Last updated", + "render": [Function], + "sortable": true, + }, + ] + } + items={Array []} + loading={true} + onTableChange={[Function]} + pagination={ + Object { + "initialPageSize": 10, + "pageSizeOptions": Array [ + 5, + 10, + 15, + ], + } + } + responsive={true} + sorting={ + Object { + "sort": Object { + "direction": "asc", + "field": "trace_id", + }, + } + } + tableLayout="auto" > - -
- - - No data matches the selected filter. Clear the filter and/or increase the time range to see more results. - + + Percentile in trace group +
, + "render": [Function], + "sortable": true, + }, + Object { + "align": "right", + "field": "error_count", + "name": "Errors", + "render": [Function], + "sortable": true, + }, + Object { + "align": "left", + "field": "last_updated", + "name": "Last updated", + "render": [Function], + "sortable": true, + }, + ] } - title={ -

- No matches -

+ items={Array []} + loading={true} + noItemsMessage="No items found" + onChange={[Function]} + pagination={ + Object { + "hidePerPageOptions": undefined, + "pageIndex": 0, + "pageSize": 10, + "pageSizeOptions": Array [ + 5, + 10, + 15, + ], + "totalItemCount": 0, + } + } + responsive={true} + sorting={ + Object { + "allowNeutralSort": false, + "sort": Object { + "direction": "asc", + "field": "Trace ID", + }, + } } + tableLayout="auto" >
- -

- No matches -

-
- - - + +
-
- - -
- -
+ - No data matches the selected filter. Clear the filter and/or increase the time range to see more results. -
-
-
-
- - +
+ + +
+ + Percentile in trace group +
, + "onSort": [Function], + }, + Object { + "isSortAscending": undefined, + "isSorted": false, + "key": "_data_s_error_count_4", + "name": "Errors", + "onSort": [Function], + }, + Object { + "isSortAscending": undefined, + "isSorted": false, + "key": "_data_s_last_updated_5", + "name": "Last updated", + "onSort": [Function], + }, + ] + } + > +
+ + + + } + closePopover={[Function]} + display="inlineBlock" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelPaddingSize="none" + > +
+
+ + + +
+
+
+
+ +
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + +
+
+ + No items found + +
+
+
+
- - -
- - + +
diff --git a/public/components/trace_analytics/components/traces/__tests__/__snapshots__/traces_table.test.tsx.snap b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/traces_table.test.tsx.snap index 0662d5db1e..3ff69536e4 100644 --- a/public/components/trace_analytics/components/traces/__tests__/__snapshots__/traces_table.test.tsx.snap +++ b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/traces_table.test.tsx.snap @@ -8,7 +8,7 @@ exports[`Traces table component renders empty traces table message 1`] = ` loading={false} mode="data_prepper" refresh={[MockFunction]} - traceIdColumnAction={[Function]} + getTraceViewUri={[Function]} >
- : + : 10 } @@ -1488,7 +1488,7 @@ exports[`Traces table component renders jaeger traces table 1`] = ` > Rows per page - : + : 10 @@ -1769,7 +1769,7 @@ exports[`Traces table component renders traces table 1`] = ` loading={false} mode="data_prepper" refresh={[MockFunction]} - traceIdColumnAction={[Function]} + getTraceViewUri={[Function]} >
- : + : 10 } @@ -3128,7 +3128,7 @@ exports[`Traces table component renders traces table 1`] = ` > Rows per page - : + : 10 diff --git a/public/components/trace_analytics/components/traces/__tests__/traces.test.tsx b/public/components/trace_analytics/components/traces/__tests__/traces.test.tsx index 2cf1b8fb6a..2bfe5b5883 100644 --- a/public/components/trace_analytics/components/traces/__tests__/traces.test.tsx +++ b/public/components/trace_analytics/components/traces/__tests__/traces.test.tsx @@ -22,8 +22,7 @@ describe('Traces component', () => { const setFilters = jest.fn(); const setStartTime = jest.fn(); const setEndTime = jest.fn(); - const traceIdColumnAction = (item: any) => - location.assign(`#/trace_analytics/traces/${encodeURIComponent(item)}`); + const getTraceViewUri = jest.fn(); const childBreadcrumbs = [ { text: 'Trace analytics', @@ -40,7 +39,7 @@ describe('Traces component', () => { chrome={chrome!} parentBreadcrumb={{ text: 'test', href: 'test#/' }} childBreadcrumbs={childBreadcrumbs} - traceIdColumnAction={traceIdColumnAction} + getTraceViewUri={getTraceViewUri} query="" setQuery={setQuery} filters={[]} @@ -68,8 +67,7 @@ describe('Traces component', () => { const setFilters = jest.fn(); const setStartTime = jest.fn(); const setEndTime = jest.fn(); - const traceIdColumnAction = (item: any) => - location.assign(`#/trace_analytics/traces/${encodeURIComponent(item)}`); + const getTraceViewUri = jest.fn(); const childBreadcrumbs = [ { text: 'Trace analytics', @@ -86,7 +84,7 @@ describe('Traces component', () => { chrome={chrome!} parentBreadcrumbs={[{ text: 'test', href: 'test#/' }]} childBreadcrumbs={childBreadcrumbs} - traceIdColumnAction={traceIdColumnAction} + getTraceViewUri={getTraceViewUri} query="" setQuery={setQuery} filters={[]} @@ -114,8 +112,7 @@ describe('Traces component', () => { const setFilters = jest.fn(); const setStartTime = jest.fn(); const setEndTime = jest.fn(); - const traceIdColumnAction = (item: any) => - location.assign(`#/trace_analytics/traces/${encodeURIComponent(item)}`); + const getTraceViewUri = jest.fn(); const childBreadcrumbs = [ { text: 'Trace analytics', @@ -132,7 +129,7 @@ describe('Traces component', () => { chrome={chrome!} parentBreadcrumbs={[{ text: 'test', href: 'test#/' }]} childBreadcrumbs={childBreadcrumbs} - traceIdColumnAction={traceIdColumnAction} + getTraceViewUri={getTraceViewUri} query="" setQuery={setQuery} filters={[]} diff --git a/public/components/trace_analytics/components/traces/__tests__/traces_table.test.tsx b/public/components/trace_analytics/components/traces/__tests__/traces_table.test.tsx index b0dcc6f06c..33f01f1ea6 100644 --- a/public/components/trace_analytics/components/traces/__tests__/traces_table.test.tsx +++ b/public/components/trace_analytics/components/traces/__tests__/traces_table.test.tsx @@ -13,7 +13,7 @@ describe('Traces table component', () => { it('renders empty traces table message', () => { const refresh = jest.fn(); - const traceIdColumnAction = (item: any) => + const getTraceViewUri = (item: any) => location.assign(`#/trace_analytics/traces/${encodeURIComponent(item)}`); const noIndicesTable = mount( { refresh={refresh} dataPrepperIndicesExist={false} jaegerIndicesExist={false} - mode='data_prepper' + mode="data_prepper" loading={false} - traceIdColumnAction={traceIdColumnAction} + getTraceViewUri={getTraceViewUri} /> ); expect(noIndicesTable).toMatchSnapshot(); @@ -34,9 +34,9 @@ describe('Traces table component', () => { refresh={refresh} dataPrepperIndicesExist={true} jaegerIndicesExist={false} - mode='data_prepper' + mode="data_prepper" loading={false} - traceIdColumnAction={traceIdColumnAction} + getTraceViewUri={getTraceViewUri} /> ); expect(emptyTable).toMatchSnapshot(); @@ -55,7 +55,7 @@ describe('Traces table component', () => { actions: '#', }, ]; - const traceIdColumnAction = (item: any) => + const getTraceViewUri = (item: any) => location.assign(`#/trace_analytics/traces/${encodeURIComponent(item)}`); const refresh = jest.fn(); const wrapper = mount( @@ -64,9 +64,9 @@ describe('Traces table component', () => { refresh={refresh} dataPrepperIndicesExist={true} jaegerIndicesExist={false} - mode='data_prepper' + mode="data_prepper" loading={false} - traceIdColumnAction={traceIdColumnAction} + getTraceViewUri={getTraceViewUri} /> ); expect(wrapper).toMatchSnapshot(); @@ -86,7 +86,7 @@ describe('Traces table component', () => { actions: '#', }, ]; - const traceIdColumnAction = (item: any) => + const getTraceViewUri = (item: any) => location.assign(`#/trace_analytics/traces/${encodeURIComponent(item)}`); const refresh = jest.fn(); const wrapper = mount( @@ -95,9 +95,9 @@ describe('Traces table component', () => { refresh={refresh} dataPrepperIndicesExist={false} jaegerIndicesExist={true} - mode='jaeger' + mode="jaeger" loading={false} - traceIdColumnAction={traceIdColumnAction} + getTraceViewUri={getTraceViewUri} /> ); expect(wrapper).toMatchSnapshot(); diff --git a/public/components/trace_analytics/components/traces/traces.tsx b/public/components/trace_analytics/components/traces/traces.tsx index 8e067895f1..948a4a0b9e 100644 --- a/public/components/trace_analytics/components/traces/traces.tsx +++ b/public/components/trace_analytics/components/traces/traces.tsx @@ -14,7 +14,8 @@ import { TracesContent } from './traces_content'; export interface TracesProps extends TraceAnalyticsComponentDeps { page: 'traces' | 'app'; childBreadcrumbs: EuiBreadcrumb[]; - traceIdColumnAction: any; + getTraceViewUri?: (traceId: string) => string; + openTraceFlyout?: (traceId: string) => void; toasts: Toast[]; dataSourceMDSId: DataSourceOption[]; } diff --git a/public/components/trace_analytics/components/traces/traces_content.tsx b/public/components/trace_analytics/components/traces/traces_content.tsx index 35039cbb02..1059298835 100644 --- a/public/components/trace_analytics/components/traces/traces_content.tsx +++ b/public/components/trace_analytics/components/traces/traces_content.tsx @@ -26,7 +26,8 @@ export function TracesContent(props: TracesProps) { startTime, endTime, childBreadcrumbs, - traceIdColumnAction, + getTraceViewUri, + openTraceFlyout, setQuery, setFilters, setStartTime, @@ -143,7 +144,8 @@ export function TracesContent(props: TracesProps) { refresh={refresh} mode={mode} loading={loading} - traceIdColumnAction={traceIdColumnAction} + getTraceViewUri={getTraceViewUri} + openTraceFlyout={openTraceFlyout} jaegerIndicesExist={jaegerIndicesExist} dataPrepperIndicesExist={dataPrepperIndicesExist} /> diff --git a/public/components/trace_analytics/components/traces/traces_table.tsx b/public/components/trace_analytics/components/traces/traces_table.tsx index fe0231338b..9c6359a894 100644 --- a/public/components/trace_analytics/components/traces/traces_table.tsx +++ b/public/components/trace_analytics/components/traces/traces_table.tsx @@ -18,6 +18,7 @@ import { EuiText, PropertySort, } from '@elastic/eui'; +import { CriteriaWithPagination } from '@opensearch-project/oui/src/eui_components/basic_table'; import round from 'lodash/round'; import truncate from 'lodash/truncate'; import React, { useMemo, useState } from 'react'; @@ -31,16 +32,17 @@ import { interface TracesTableProps { items: any[]; - refresh: (sort?: PropertySort) => void; + refresh: (sort?: PropertySort) => Promise; mode: TraceAnalyticsMode; loading: boolean; - traceIdColumnAction: any; + getTraceViewUri?: (traceId: string) => string; + openTraceFlyout?: (traceId: string) => void; jaegerIndicesExist: boolean; dataPrepperIndicesExist: boolean; } export function TracesTable(props: TracesTableProps) { - const { items, refresh, mode, loading, traceIdColumnAction } = props; + const { items, refresh, mode, loading, getTraceViewUri, openTraceFlyout } = props; const renderTitleBar = (totalItems?: number) => { return ( @@ -51,26 +53,26 @@ 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', align: 'left', sortable: true, - truncateText: true, + truncateText: false, render: (item) => ( - - traceIdColumnAction(item)}> - {item.length < 24 ? ( - item - ) : ( -
{truncate(item, { length: 24 })}
- )} + + openTraceFlyout(item) })} + > + + {item} + @@ -86,7 +88,6 @@ export function TracesTable(props: TracesTableProps) { )} -
), }, @@ -99,11 +100,7 @@ export function TracesTable(props: TracesTableProps) { render: (item) => item ? ( - {item.length < 36 ? ( - item - ) : ( -
{truncate(item, { length: 36 })}
- )} + {item.length < 36 ? item :
{truncate(item, { length: 36 })}
}
) : ( '-' @@ -118,12 +115,7 @@ export function TracesTable(props: TracesTableProps) { }, { field: 'percentile_in_trace_group', - name: ( - <> -
Percentile in trace group
- {/*
trace group
*/} - - ), + name:
Percentile in trace group
, align: 'right', sortable: true, render: (item) => @@ -152,79 +144,77 @@ 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) => ( + + + openTraceFlyout(item) })} + > + + {item} + + + + + + {(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 +225,7 @@ export function TracesTable(props: TracesTableProps) { }, }); - const onTableChange = async ({ currPage, sort }: { currPage: any; sort: any }) => { + const onTableChange = async ({ sort }: CriteriaWithPagination) => { if (typeof sort?.field !== 'string') return; // maps table column key to DSL aggregation name @@ -253,7 +243,8 @@ export function TracesTable(props: TracesTableProps) { return; } - // using await when sorting the default sorted field leads to a bug in UI + // using await when sorting the default sorted field leads to a bug in UI, + // user needs to click one time more to change sort back to ascending if (sort.field === 'trace_id') { refresh({ ...sort, field }); setSorting({ sort }); @@ -270,11 +261,15 @@ export function TracesTable(props: TracesTableProps) { {titleBar} - {!((mode === 'data_prepper' && props.dataPrepperIndicesExist) || (mode === 'jaeger' && props.jaegerIndicesExist)) ? ( - - ) : items?.length > 0 ? ( + {!( + (mode === 'data_prepper' && props.dataPrepperIndicesExist) || + (mode === 'jaeger' && props.jaegerIndicesExist) + ) ? ( + + ) : items?.length > 0 || loading ? ( { const traceColumnAction = () => location.assign('#/traces'); - const traceIdColumnAction = (item: any) => - location.assign(`#/traces/${encodeURIComponent(item)}`); + const getTraceViewUri = (traceId: string) => `#/traces/${encodeURIComponent(traceId)}`; const [spanFlyoutComponent, setSpanFlyoutComponent] = useState(<>); @@ -321,7 +320,7 @@ export const Home = (props: HomeProps) => { { { 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, }, }, ], @@ -459,45 +463,3 @@ export const getSpansQuery = (spanSearchParams: SpanSearchParams) => { }; return query; }; - -export const getValidTraceIdsQuery = (DSL) => { - const query: any = { - size: 0, - query: { - bool: { - must: [], - filter: [], - should: [], - must_not: [], - }, - }, - aggs: { - traces: { - terms: { - field: 'traceID', - size: 10000, - }, - }, - }, - }; - if (DSL.custom?.timeFilter.length > 0) query.query.bool.must.push(...DSL.custom.timeFilter); - if (DSL.custom?.traceGroupFields.length > 0) { - query.query.bool.filter.push({ - terms: { - traceGroup: DSL.custom.traceGroup, - }, - }); - } - if (DSL.custom?.percentiles?.query.bool.should.length > 0) { - query.query.bool.should.push(...DSL.custom.percentiles.query.bool.should); - query.query.bool.minimum_should_match = DSL.custom.percentiles.query.bool.minimum_should_match; - } - if (DSL.custom?.serviceNames.length > 0) { - query.query.bool.filter.push({ - terms: { - serviceName: DSL.custom.serviceNames, - }, - }); - } - return query; -}; \ No newline at end of file diff --git a/public/components/trace_analytics/requests/traces_request_handler.ts b/public/components/trace_analytics/requests/traces_request_handler.ts index a8bebb742d..0cabb6614f 100644 --- a/public/components/trace_analytics/requests/traces_request_handler.ts +++ b/public/components/trace_analytics/requests/traces_request_handler.ts @@ -3,6 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { PropertySort } from '@elastic/eui'; import get from 'lodash/get'; import round from 'lodash/round'; import moment from 'moment'; @@ -21,16 +22,9 @@ import { getSpansQuery, getTraceGroupPercentilesQuery, getTracesQuery, - getValidTraceIdsQuery, } from './queries/traces_queries'; import { handleDslRequest } from './request_handler'; -export const handleValidTraceIds = (http: HttpSetup, DSL: any, mode: TraceAnalyticsMode) => { - return handleDslRequest(http, {}, getValidTraceIdsQuery(DSL), mode) - .then((response) => response.aggregations.traces.buckets.map((bucket: any) => bucket.key)) - .catch((error) => console.error(error)); -}; - export const handleTracesRequest = async ( http: HttpSetup, DSL: any, @@ -39,7 +33,7 @@ export const handleTracesRequest = async ( setItems: (items: any) => void, mode: TraceAnalyticsMode, dataSourceMDSId?: string, - sort?: any + sort?: PropertySort ) => { const binarySearch = (arr: number[], target: number) => { if (!arr) return Number.NaN; @@ -54,50 +48,63 @@ export const handleTracesRequest = async ( return Math.max(0, Math.min(100, low)); }; - // percentile should only be affected by timefilter - const percentileRanges = await handleDslRequest( + const responsePromise = handleDslRequest( http, - timeFilterDSL, - getTraceGroupPercentilesQuery(), + DSL, + getTracesQuery(mode, undefined, sort), mode, dataSourceMDSId - ).then((response) => { - const map: any = {}; - response.aggregations.trace_group_name.buckets.forEach((traceGroup: any) => { - map[traceGroup.key] = Object.values(traceGroup.percentiles.values).map((value: any) => - nanoToMilliSec(value) - ); - }); - return map; - }); + ); - return handleDslRequest(http, DSL, getTracesQuery(mode, undefined, sort), mode, dataSourceMDSId) - .then((response) => { - return Promise.all( - response.aggregations.traces.buckets.map((bucket: any) => { - if (mode === 'data_prepper') { - return { - trace_id: bucket.key, - trace_group: bucket.trace_group.buckets[0]?.key, - latency: bucket.latency.value, - last_updated: moment(bucket.last_updated.value).format(TRACE_ANALYTICS_DATE_FORMAT), - error_count: bucket.error_count.doc_count, - percentile_in_trace_group: binarySearch( - percentileRanges[bucket.trace_group.buckets[0]?.key], - bucket.latency.value - ), - actions: '#', - }; - } + // percentile should only be affected by timefilter + const percentileRangesPromise = + mode === 'data_prepper' + ? handleDslRequest( + http, + timeFilterDSL, + getTraceGroupPercentilesQuery(), + mode, + dataSourceMDSId + ).then((response) => { + const map: Record = {}; + response.aggregations.trace_group_name.buckets.forEach((traceGroup: any) => { + map[traceGroup.key] = Object.values(traceGroup.percentiles.values).map((value: any) => + nanoToMilliSec(value) + ); + }); + return map; + }) + : Promise.reject('Only data_prepper mode supports percentile'); + + return Promise.allSettled([responsePromise, percentileRangesPromise]) + .then(([responseResult, percentileRangesResult]) => { + if (responseResult.status === 'rejected') return Promise.reject(responseResult.reason); + const percentileRanges = + percentileRangesResult.status === 'fulfilled' ? percentileRangesResult.value : {}; + const response = responseResult.value; + return response.aggregations.traces.buckets.map((bucket: any) => { + if (mode === 'data_prepper') { return { trace_id: bucket.key, + trace_group: bucket.trace_group.buckets[0]?.key, latency: bucket.latency.value, last_updated: moment(bucket.last_updated.value).format(TRACE_ANALYTICS_DATE_FORMAT), error_count: bucket.error_count.doc_count, + percentile_in_trace_group: binarySearch( + percentileRanges[bucket.trace_group.buckets[0]?.key], + bucket.latency.value + ), actions: '#', }; - }) - ); + } + return { + trace_id: bucket.key, + latency: bucket.latency.value, + last_updated: moment(bucket.last_updated.value).format(TRACE_ANALYTICS_DATE_FORMAT), + error_count: bucket.error_count.doc_count, + actions: '#', + }; + }); }) .then((newItems) => { setItems(newItems); @@ -254,8 +261,7 @@ const hitsToSpanDetailData = async (hits: any, colorMap: any, mode: TraceAnalyti mode === 'jaeger' ? get(hit, ['_source', 'process']).serviceName : get(hit, ['_source', 'serviceName']); - const name = - mode === 'jaeger' ? get(hit, '_source.operationName') : get(hit, '_source.name'); + const name = mode === 'jaeger' ? get(hit, '_source.operationName') : get(hit, '_source.name'); const error = mode === 'jaeger' ? hit._source.tag?.['error'] === true