|
@@ -1,37 +1,29 @@
|
|
|
import {useTheme} from '@emotion/react';
|
|
|
import styled from '@emotion/styled';
|
|
|
-import moment from 'moment';
|
|
|
|
|
|
import {getInterval} from 'sentry/components/charts/utils';
|
|
|
import {Panel} from 'sentry/components/panels';
|
|
|
+import Placeholder from 'sentry/components/placeholder';
|
|
|
import {space} from 'sentry/styles/space';
|
|
|
import {PageFilters} from 'sentry/types';
|
|
|
import {Series} from 'sentry/types/echarts';
|
|
|
+import {useDiscoverQuery} from 'sentry/utils/discover/discoverQuery';
|
|
|
import EventView from 'sentry/utils/discover/eventView';
|
|
|
import {DiscoverDatasets} from 'sentry/utils/discover/types';
|
|
|
+import {useLocation} from 'sentry/utils/useLocation';
|
|
|
+import useOrganization from 'sentry/utils/useOrganization';
|
|
|
import usePageFilters from 'sentry/utils/usePageFilters';
|
|
|
-import {MODULE_COLOR} from 'sentry/views/starfish/colours';
|
|
|
-import {ModuleName} from 'sentry/views/starfish/types';
|
|
|
-import {PERIOD_REGEX} from 'sentry/views/starfish/utils/dates';
|
|
|
-import {useSpansQuery} from 'sentry/views/starfish/utils/useSpansQuery';
|
|
|
-import {zeroFillSeries} from 'sentry/views/starfish/utils/zeroFillSeries';
|
|
|
-import {
|
|
|
- getOtherModulesTimeseries,
|
|
|
- getTopModules,
|
|
|
- getTopModulesTimeseries,
|
|
|
- totalCumulativeTime,
|
|
|
-} from 'sentry/views/starfish/views/webServiceView/queries';
|
|
|
+import {useWrappedDiscoverTimeseriesQuery} from 'sentry/views/starfish/utils/useSpansQuery';
|
|
|
import {SpanGroupBreakdown} from 'sentry/views/starfish/views/webServiceView/spanGroupBreakdown';
|
|
|
|
|
|
-export const OTHER_SPAN_GROUP_MODULE = 'other';
|
|
|
-const FORCE_USE_DISCOVER = true;
|
|
|
+export const OTHER_SPAN_GROUP_MODULE = 'Other';
|
|
|
|
|
|
type Props = {
|
|
|
transaction?: string;
|
|
|
};
|
|
|
|
|
|
type Group = {
|
|
|
- 'span.module': string;
|
|
|
+ 'span.category': string;
|
|
|
};
|
|
|
|
|
|
export type Segment = Group & {
|
|
@@ -47,161 +39,104 @@ export type DataRow = {
|
|
|
export function SpanGroupBreakdownContainer({transaction: maybeTransaction}: Props) {
|
|
|
const transaction = maybeTransaction ?? '';
|
|
|
const pageFilter = usePageFilters();
|
|
|
+ const organization = useOrganization();
|
|
|
+ const location = useLocation();
|
|
|
const {selection} = pageFilter;
|
|
|
const theme = useTheme();
|
|
|
|
|
|
- const {data: segments, isLoading: isSegmentsLoading} = useSpansQuery<Segment[]>({
|
|
|
- queryString: `${getTopModules({
|
|
|
- transaction,
|
|
|
- datetime: selection.datetime,
|
|
|
- })}`,
|
|
|
+ const {data: segments, isLoading: isSegmentsLoading} = useDiscoverQuery({
|
|
|
eventView: getEventView(
|
|
|
selection,
|
|
|
- `span.module:[db,http] ${transaction ? `transaction:${transaction}` : ''}`,
|
|
|
- ['span.module']
|
|
|
+ // TODO: Fix has:span.category in the backend
|
|
|
+ `has:span.category ${transaction ? `transaction:${transaction}` : ''}`,
|
|
|
+ ['span.category']
|
|
|
),
|
|
|
- initialData: [],
|
|
|
- forceUseDiscover: FORCE_USE_DISCOVER,
|
|
|
+ orgSlug: organization.slug,
|
|
|
+ location,
|
|
|
+ limit: 4,
|
|
|
});
|
|
|
|
|
|
- const {data: cumulativeTime} = useSpansQuery({
|
|
|
- queryString: `${totalCumulativeTime({
|
|
|
- transaction,
|
|
|
- datetime: selection.datetime,
|
|
|
- })}`,
|
|
|
+ const {data: cumulativeTime} = useDiscoverQuery({
|
|
|
eventView: getEventView(
|
|
|
selection,
|
|
|
`${transaction ? `transaction:${transaction}` : ''}`,
|
|
|
[]
|
|
|
),
|
|
|
+ orgSlug: organization.slug,
|
|
|
+ location,
|
|
|
+ });
|
|
|
+
|
|
|
+ const {isLoading: isTopDataLoading, data: topData} = useWrappedDiscoverTimeseriesQuery({
|
|
|
+ eventView: getEventView(
|
|
|
+ selection,
|
|
|
+ `has:span.category ${transaction ? `transaction:${transaction}` : ''}`,
|
|
|
+ ['span.category'],
|
|
|
+ true
|
|
|
+ ),
|
|
|
initialData: [],
|
|
|
- forceUseDiscover: FORCE_USE_DISCOVER,
|
|
|
});
|
|
|
|
|
|
- const totalValues = cumulativeTime.reduce(
|
|
|
- (acc, segment) => acc + segment['sum(span.duration)'],
|
|
|
- 0
|
|
|
- );
|
|
|
- const totalSegments = segments.reduce(
|
|
|
- (acc, segment) => acc + segment['sum(span.duration)'],
|
|
|
- 0
|
|
|
- );
|
|
|
- const otherValue = totalValues - totalSegments;
|
|
|
+ if (!segments?.data || !cumulativeTime?.data || topData.length === 0) {
|
|
|
+ return <Placeholder height="200px" />;
|
|
|
+ }
|
|
|
+
|
|
|
+ const totalValues = cumulativeTime.data[0]['sum(span.duration)']
|
|
|
+ ? parseInt(cumulativeTime?.data[0]['sum(span.duration)'] as string, 10)
|
|
|
+ : 0;
|
|
|
+ const totalSegments =
|
|
|
+ segments?.data.reduce(
|
|
|
+ (acc, segment) => acc + parseInt(segment['sum(span.duration)'] as string, 10),
|
|
|
+ 0
|
|
|
+ ) ?? 0;
|
|
|
+
|
|
|
+ const otherValue = totalValues ? totalValues - totalSegments : 0;
|
|
|
|
|
|
const transformedData: DataRow[] = [];
|
|
|
|
|
|
- for (let index = 0; index < segments.length; index++) {
|
|
|
- const element = segments[index];
|
|
|
+ for (let index = 0; index < segments.data.length; index++) {
|
|
|
+ const element = segments.data[index];
|
|
|
transformedData.push({
|
|
|
- cumulativeTime: element['sum(span.duration)'],
|
|
|
+ cumulativeTime: parseInt(element['sum(span.duration)'] as string, 10),
|
|
|
group: {
|
|
|
- 'span.module': element['span.module'],
|
|
|
+ 'span.category': element['span.category'] as string,
|
|
|
},
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- transformedData.push({
|
|
|
- cumulativeTime: otherValue,
|
|
|
- group: {
|
|
|
- 'span.module': OTHER_SPAN_GROUP_MODULE,
|
|
|
- },
|
|
|
- });
|
|
|
-
|
|
|
- let topConditions =
|
|
|
- segments.length > 0 ? ` span.module = '${segments[0]['span.module']}'` : '';
|
|
|
-
|
|
|
- for (let index = 1; index < segments.length; index++) {
|
|
|
- const element = segments[index];
|
|
|
- topConditions = topConditions.concat(
|
|
|
- ' OR ',
|
|
|
- ` span.module = '${element['span.module']}'`
|
|
|
- );
|
|
|
+ if (otherValue > 0) {
|
|
|
+ transformedData.push({
|
|
|
+ cumulativeTime: otherValue,
|
|
|
+ group: {
|
|
|
+ 'span.category': OTHER_SPAN_GROUP_MODULE,
|
|
|
+ },
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
- const {isLoading: isTopDataLoading, data: topData} = useSpansQuery({
|
|
|
- queryString: `${getTopModulesTimeseries({
|
|
|
- transaction,
|
|
|
- topConditions,
|
|
|
- datetime: selection.datetime,
|
|
|
- })}`,
|
|
|
- eventView: getEventView(
|
|
|
- selection,
|
|
|
- `span.module:[db,http] ${transaction ? `transaction:${transaction}` : ''}`,
|
|
|
- ['span.module'],
|
|
|
- true
|
|
|
- ),
|
|
|
- initialData: [],
|
|
|
- forceUseDiscover: FORCE_USE_DISCOVER,
|
|
|
- });
|
|
|
+ const seriesByDomain: {[category: string]: Series} = {};
|
|
|
+ const colorPalette = theme.charts.getColorPalette(transformedData.length - 2);
|
|
|
|
|
|
- const {isLoading: isOtherDataLoading, data: otherData} = useSpansQuery({
|
|
|
- queryString: `${getOtherModulesTimeseries({
|
|
|
- transaction,
|
|
|
- topConditions,
|
|
|
- datetime: selection.datetime,
|
|
|
- })}`,
|
|
|
- eventView: getEventView(
|
|
|
- selection,
|
|
|
- `!span.module:[db,http] ${transaction ? `transaction:${transaction}` : ''}`,
|
|
|
- [],
|
|
|
- true
|
|
|
- ),
|
|
|
- initialData: [],
|
|
|
- forceUseDiscover: FORCE_USE_DISCOVER,
|
|
|
- });
|
|
|
-
|
|
|
- const seriesByDomain: {[module: string]: Series} = {};
|
|
|
- const [_, num, unit] = pageFilter.selection.datetime.period?.match(PERIOD_REGEX) ?? [];
|
|
|
- const start =
|
|
|
- num && unit
|
|
|
- ? moment().subtract(num, unit as 'h' | 'd')
|
|
|
- : moment(pageFilter.selection.datetime.start);
|
|
|
- const end = moment(pageFilter.selection.datetime.end ?? undefined);
|
|
|
-
|
|
|
- const colorPalette = theme.charts.getColorPalette(transformedData.length - 3);
|
|
|
-
|
|
|
- if (
|
|
|
- !isTopDataLoading &&
|
|
|
- !isOtherDataLoading &&
|
|
|
- topData.length > 0 &&
|
|
|
- segments.length > 0
|
|
|
- ) {
|
|
|
- segments.forEach(segment => {
|
|
|
- const label = segment['span.module'] as ModuleName;
|
|
|
+ if (!isTopDataLoading && topData.length > 0 && transformedData.length > 0) {
|
|
|
+ transformedData.forEach((segment, index) => {
|
|
|
+ const label = segment.group['span.category'];
|
|
|
seriesByDomain[label] = {
|
|
|
seriesName: `${label}`,
|
|
|
data: [],
|
|
|
- color: MODULE_COLOR[label],
|
|
|
+ color: colorPalette[index],
|
|
|
};
|
|
|
});
|
|
|
|
|
|
topData.forEach(value => {
|
|
|
- seriesByDomain[value['span.module'] ?? value.group].data.push({
|
|
|
- value: value['p95(span.duration)'],
|
|
|
- name: value.interval,
|
|
|
- });
|
|
|
- });
|
|
|
-
|
|
|
- seriesByDomain.Other = {
|
|
|
- seriesName: `Other`,
|
|
|
- data: [],
|
|
|
- color: theme.gray100,
|
|
|
- };
|
|
|
-
|
|
|
- otherData.forEach(value => {
|
|
|
- seriesByDomain.Other.data.push({
|
|
|
+ seriesByDomain[value.group].data.push({
|
|
|
value: value['p95(span.duration)'],
|
|
|
name: value.interval,
|
|
|
});
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- const data = Object.values(seriesByDomain).map(series =>
|
|
|
- zeroFillSeries(series, moment.duration(12, 'hour'), start, end)
|
|
|
- );
|
|
|
+ const data = Object.values(seriesByDomain);
|
|
|
|
|
|
const initialShowSeries = transformedData.map(
|
|
|
- segment => segment.group['span.module'] !== OTHER_SPAN_GROUP_MODULE
|
|
|
+ segment => segment.group['span.category'] !== OTHER_SPAN_GROUP_MODULE
|
|
|
);
|
|
|
|
|
|
return (
|
|
@@ -238,9 +173,10 @@ const getEventView = (
|
|
|
start: pageFilters.datetime.start ?? undefined,
|
|
|
end: pageFilters.datetime.end ?? undefined,
|
|
|
range: pageFilters.datetime.period ?? undefined,
|
|
|
+ orderby: '-sum_span_duration',
|
|
|
projects: [1],
|
|
|
version: 2,
|
|
|
- topEvents: groups.length > 0 ? '5' : undefined,
|
|
|
+ topEvents: groups.length > 0 ? '4' : undefined,
|
|
|
interval: getTimeseries ? getInterval(pageFilters.datetime, 'low') : undefined,
|
|
|
});
|
|
|
};
|