useSpanMetrics.tsx 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. import {Location} from 'history';
  2. import EventView from 'sentry/utils/discover/eventView';
  3. import {Sort} from 'sentry/utils/discover/fields';
  4. import {DiscoverDatasets} from 'sentry/utils/discover/types';
  5. import {MutableSearch} from 'sentry/utils/tokenizeSearch';
  6. import {useLocation} from 'sentry/utils/useLocation';
  7. import {
  8. MetricsProperty,
  9. MetricsResponse,
  10. SpanMetricsQueryFilters,
  11. } from 'sentry/views/starfish/types';
  12. import {useWrappedDiscoverQuery} from 'sentry/views/starfish/utils/useSpansQuery';
  13. import {EMPTY_OPTION_VALUE} from 'sentry/views/starfish/views/spans/selectors/emptyOption';
  14. export const useSpanMetrics = <T extends MetricsProperty[]>(
  15. filters: SpanMetricsQueryFilters,
  16. fields: T,
  17. sorts?: Sort[],
  18. limit?: number,
  19. cursor?: string,
  20. referrer: string = 'api.starfish.use-span-metrics'
  21. ) => {
  22. const location = useLocation();
  23. const eventView = getEventView(filters, fields, sorts, location);
  24. const enabled = Object.values(filters).every(value => Boolean(value));
  25. const result = useWrappedDiscoverQuery({
  26. eventView,
  27. initialData: [],
  28. limit,
  29. enabled,
  30. referrer,
  31. cursor,
  32. });
  33. // This type is a little awkward but it explicitly states that the response could be empty. This doesn't enable unchecked access errors, but it at least indicates that it's possible that there's no data
  34. // eslint-disable-next-line @typescript-eslint/ban-types
  35. const data = (result?.data ?? []) as Pick<MetricsResponse, T[number]>[] | [];
  36. return {
  37. ...result,
  38. data,
  39. isEnabled: enabled,
  40. };
  41. };
  42. function getEventView(
  43. filters: SpanMetricsQueryFilters,
  44. fields: string[] = [],
  45. sorts: Sort[] = [],
  46. location: Location
  47. ) {
  48. const query = new MutableSearch('');
  49. Object.entries(filters).forEach(([key, value]) => {
  50. if (!value) {
  51. return;
  52. }
  53. if (value === EMPTY_OPTION_VALUE) {
  54. query.addFilterValue('!has', key);
  55. }
  56. query.addFilterValue(key, value, !ALLOWED_WILDCARD_FIELDS.includes(key));
  57. });
  58. // TODO: This condition should be enforced everywhere
  59. // query.addFilterValue('has', 'span.description');
  60. const eventView = EventView.fromNewQueryWithLocation(
  61. {
  62. name: '',
  63. query: query.formatString(),
  64. fields,
  65. dataset: DiscoverDatasets.SPANS_METRICS,
  66. version: 2,
  67. },
  68. location
  69. );
  70. if (sorts.length > 0) {
  71. eventView.sorts = sorts;
  72. }
  73. return eventView;
  74. }
  75. const ALLOWED_WILDCARD_FIELDS = ['span.description'];