useTrace.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. import {useMemo} from 'react';
  2. import type {Location} from 'history';
  3. import * as qs from 'query-string';
  4. import type {Client} from 'sentry/api';
  5. import {normalizeDateTimeParams} from 'sentry/components/organizations/pageFilters/parse';
  6. import type {PageFilters} from 'sentry/types';
  7. import type {
  8. TraceFullDetailed,
  9. TraceSplitResults,
  10. } from 'sentry/utils/performance/quickTrace/types';
  11. import {useApiQuery, type UseApiQueryResult} from 'sentry/utils/queryClient';
  12. import {decodeScalar} from 'sentry/utils/queryString';
  13. import useOrganization from 'sentry/utils/useOrganization';
  14. import usePageFilters from 'sentry/utils/usePageFilters';
  15. import {useParams} from 'sentry/utils/useParams';
  16. export function fetchTrace(
  17. api: Client,
  18. params: {
  19. orgSlug: string;
  20. query: string;
  21. traceId: string;
  22. }
  23. ): Promise<TraceSplitResults<TraceFullDetailed>> {
  24. return api.requestPromise(
  25. `/organizations/${params.orgSlug}/events-trace/${params.traceId}/?${params.query}`
  26. );
  27. }
  28. const DEFAULT_TIMESTAMP_LIMIT = 10_000;
  29. const DEFAULT_LIMIT = 1_000;
  30. export function getTraceQueryParams(
  31. query: Location['query'],
  32. filters: Partial<PageFilters> = {},
  33. options: {limit?: number} = {}
  34. ): {
  35. eventId: string | undefined;
  36. limit: number;
  37. timestamp: string | undefined;
  38. useSpans: number;
  39. pageEnd?: string | undefined;
  40. pageStart?: string | undefined;
  41. statsPeriod?: string | undefined;
  42. } {
  43. const normalizedParams = normalizeDateTimeParams(query, {
  44. allowAbsolutePageDatetime: true,
  45. });
  46. const statsPeriod = decodeScalar(normalizedParams.statsPeriod);
  47. const timestamp = decodeScalar(normalizedParams.timestamp);
  48. let decodedLimit: string | number | undefined =
  49. options.limit ?? decodeScalar(normalizedParams.limit);
  50. if (typeof decodedLimit === 'string') {
  51. decodedLimit = parseInt(decodedLimit, 10);
  52. }
  53. const eventId = decodeScalar(normalizedParams.eventId);
  54. if (timestamp) {
  55. decodedLimit = decodedLimit ?? DEFAULT_TIMESTAMP_LIMIT;
  56. } else {
  57. decodedLimit = decodedLimit ?? DEFAULT_LIMIT;
  58. }
  59. const limit = decodedLimit;
  60. const otherParams: Record<string, string | string[] | undefined | null> = {
  61. end: normalizedParams.pageEnd,
  62. start: normalizedParams.pageStart,
  63. statsPeriod: statsPeriod || filters.datetime?.period,
  64. };
  65. // We prioritize timestamp over statsPeriod as it makes the query more specific, faster
  66. // and not prone to time drift issues.
  67. if (timestamp) {
  68. delete otherParams.statsPeriod;
  69. }
  70. const queryParams = {...otherParams, limit, timestamp, eventId, useSpans: 1};
  71. for (const key in queryParams) {
  72. if (
  73. queryParams[key] === '' ||
  74. queryParams[key] === null ||
  75. queryParams[key] === undefined
  76. ) {
  77. delete queryParams[key];
  78. }
  79. }
  80. return queryParams;
  81. }
  82. type UseTraceParams = {
  83. limit?: number;
  84. };
  85. const DEFAULT_OPTIONS = {};
  86. export function useTrace(
  87. options: Partial<UseTraceParams> = DEFAULT_OPTIONS
  88. ): UseApiQueryResult<TraceSplitResults<TraceFullDetailed>, any> {
  89. const filters = usePageFilters();
  90. const organization = useOrganization();
  91. const params = useParams<{traceSlug?: string}>();
  92. const queryParams = useMemo(() => {
  93. const query = qs.parse(location.search);
  94. return getTraceQueryParams(query, filters.selection, options);
  95. // eslint-disable-next-line react-hooks/exhaustive-deps
  96. }, [options]);
  97. return useApiQuery(
  98. [
  99. `/organizations/${organization.slug}/events-trace/${params.traceSlug ?? ''}/`,
  100. {query: queryParams},
  101. ],
  102. {
  103. staleTime: Infinity,
  104. enabled: !!params.traceSlug && !!organization.slug,
  105. }
  106. );
  107. }