queries.tsx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. import {useQuery} from '@tanstack/react-query';
  2. import {NewQuery} from 'sentry/types';
  3. import EventView from 'sentry/utils/discover/eventView';
  4. import {DiscoverDatasets} from 'sentry/utils/discover/types';
  5. import {DefinedUseQueryResult} from 'sentry/utils/queryClient';
  6. import {useLocation} from 'sentry/utils/useLocation';
  7. import usePageFilters from 'sentry/utils/usePageFilters';
  8. import {getDateQueryFilter} from 'sentry/views/starfish/modules/databaseModule/queries';
  9. import {HOST} from 'sentry/views/starfish/utils/constants';
  10. import {
  11. datetimeToClickhouseFilterTimestamps,
  12. getDateFilters,
  13. } from 'sentry/views/starfish/utils/dates';
  14. import {useWrappedDiscoverTimeseriesQuery} from 'sentry/views/starfish/utils/useSpansQuery';
  15. export const getHostListQuery = ({datetime}) => {
  16. const {start_timestamp, end_timestamp} = datetimeToClickhouseFilterTimestamps(datetime);
  17. return `SELECT
  18. domain,
  19. toStartOfInterval(start_timestamp, INTERVAL 12 HOUR) as interval,
  20. quantile(0.99)(exclusive_time) as p99,
  21. count() as count,
  22. countIf(greaterOrEquals(status, 400) AND lessOrEquals(status, 599)) as failure_count,
  23. failure_count / count as failure_rate
  24. FROM spans_experimental_starfish
  25. WHERE module = 'http'
  26. AND domain != ''
  27. ${start_timestamp ? `AND greaterOrEquals(start_timestamp, '${start_timestamp}')` : ''}
  28. ${end_timestamp ? `AND lessOrEquals(start_timestamp, '${end_timestamp}')` : ''}
  29. GROUP BY domain, interval
  30. ORDER BY domain, interval asc
  31. `;
  32. };
  33. export const getHostListEventView = ({datetime}) => {
  34. return EventView.fromSavedQuery({
  35. name: '',
  36. fields: ['domain'],
  37. yAxis: ['p99(span.self_time)', 'count()'],
  38. query: 'module:http',
  39. topEvents: '10',
  40. start: datetime.start,
  41. end: datetime.end,
  42. range: datetime.period,
  43. dataset: DiscoverDatasets.SPANS_INDEXED,
  44. projects: [1],
  45. version: 2,
  46. });
  47. };
  48. export const getEndpointListQuery = ({domain, action, datetime, transaction}) => {
  49. const {start_timestamp, end_timestamp} = datetimeToClickhouseFilterTimestamps(datetime);
  50. return `SELECT
  51. description,
  52. group_id,
  53. domain,
  54. action,
  55. quantile(0.5)(exclusive_time) AS "p50(span.self_time)",
  56. quantile(0.95)(exclusive_time) AS "p95(span.self_time)",
  57. sum(exclusive_time) AS "sum(span.self_time)",
  58. uniq(user) AS "count_unique(user)", uniq(transaction) AS "count_unique(transaction)",
  59. count() AS count,
  60. countIf(greaterOrEquals(status, 400) AND lessOrEquals(status, 599)) AS failure_count,
  61. failure_count / count AS failure_rate
  62. FROM spans_experimental_starfish
  63. WHERE module = 'http'
  64. ${domain ? `AND domain = '${domain}'` : ''}
  65. ${action ? `AND action = '${action}'` : ''}
  66. ${transaction ? `AND transaction = '${transaction}'` : ''}
  67. ${start_timestamp ? `AND greaterOrEquals(start_timestamp, '${start_timestamp}')` : ''}
  68. ${end_timestamp ? `AND lessOrEquals(start_timestamp, '${end_timestamp}')` : ''}
  69. GROUP BY description, domain, action, group_id
  70. ORDER BY count DESC
  71. LIMIT 10
  72. `;
  73. };
  74. export const getEndpointListEventView = ({domain, action, datetime, transaction}) => {
  75. return EventView.fromSavedQuery({
  76. name: '',
  77. fields: [
  78. 'description',
  79. 'group_id',
  80. 'domain',
  81. 'action',
  82. 'p50(span.self_time)',
  83. 'p95(span.self_time)',
  84. 'sum(span.self_time)',
  85. 'count()',
  86. 'count_unique(user)',
  87. 'count_unique(transaction)',
  88. ],
  89. orderby: '-count',
  90. query: `module:http ${domain ? `domain:${domain}` : ''} ${
  91. action ? `action:${action}` : ''
  92. } ${transaction ? `transaction:${transaction}` : ''}`,
  93. start: datetime.start,
  94. end: datetime.end,
  95. range: datetime.period,
  96. dataset: DiscoverDatasets.SPANS_INDEXED,
  97. projects: [1],
  98. version: 2,
  99. });
  100. };
  101. export const getEndpointDomainsQuery = ({datetime}) => {
  102. const {start_timestamp, end_timestamp} = datetimeToClickhouseFilterTimestamps(datetime);
  103. return `SELECT domain, count(),
  104. sum(exclusive_time) as "sum(span.self_time)",
  105. max(exclusive_time) as "p100(span.self_time)",
  106. quantile(0.99)(exclusive_time) as "p99(span.self_time)",
  107. quantile(0.95)(exclusive_time) as "p95(span.self_time)",
  108. quantile(0.50)(exclusive_time) as "p50(span.self_time)"
  109. FROM spans_experimental_starfish
  110. WHERE module = 'http'
  111. ${start_timestamp ? `AND greaterOrEquals(start_timestamp, '${start_timestamp}')` : ''}
  112. ${end_timestamp ? `AND lessOrEquals(start_timestamp, '${end_timestamp}')` : ''}
  113. GROUP BY domain
  114. ORDER BY count() DESC
  115. `;
  116. };
  117. export const getEndpointDomainsEventView = ({datetime}) => {
  118. return EventView.fromSavedQuery({
  119. name: '',
  120. fields: [
  121. 'domain',
  122. 'count()',
  123. 'sum(span.self_time)',
  124. 'p100(span.self_time)',
  125. 'p99(span.self_time)',
  126. 'p95(span.self_time)',
  127. 'p50(span.self_time)',
  128. ],
  129. orderby: '-count',
  130. query: 'module:http',
  131. start: datetime.start,
  132. end: datetime.end,
  133. range: datetime.period,
  134. dataset: DiscoverDatasets.SPANS_INDEXED,
  135. projects: [1],
  136. version: 2,
  137. });
  138. };
  139. export const getEndpointGraphQuery = ({datetime}) => {
  140. const {start_timestamp, end_timestamp} = datetimeToClickhouseFilterTimestamps(datetime);
  141. return `SELECT
  142. toStartOfInterval(start_timestamp, INTERVAL 12 HOUR) as interval,
  143. quantile(0.5)(exclusive_time) as "p50(span.self_time)",
  144. quantile(0.75)(exclusive_time) as "p75(span.self_time)",
  145. quantile(0.95)(exclusive_time) as "p95(span.self_time)",
  146. quantile(0.99)(exclusive_time) as "p99(span.self_time)",
  147. count() as "count()",
  148. countIf(greaterOrEquals(status, 400) AND lessOrEquals(status, 599)) as "failure_count()",
  149. "failure_count()" / "count()" as "failure_rate()"
  150. FROM spans_experimental_starfish
  151. WHERE module = 'http'
  152. ${start_timestamp ? `AND greaterOrEquals(start_timestamp, '${start_timestamp}')` : ''}
  153. ${end_timestamp ? `AND lessOrEquals(start_timestamp, '${end_timestamp}')` : ''}
  154. GROUP BY interval
  155. ORDER BY interval asc
  156. `;
  157. };
  158. export const getEndpointGraphEventView = ({datetime}) => {
  159. return EventView.fromSavedQuery({
  160. name: '',
  161. fields: [
  162. 'count()',
  163. 'p50(span.self_time)',
  164. 'p75(span.self_time)',
  165. 'p95(span.self_time)',
  166. 'p99(span.self_time)',
  167. ],
  168. yAxis: [
  169. 'count()',
  170. 'p50(span.self_time)',
  171. 'p75(span.self_time)',
  172. 'p95(span.self_time)',
  173. 'p99(span.self_time)',
  174. ],
  175. query: 'module:http',
  176. start: datetime.start,
  177. end: datetime.end,
  178. range: datetime.period,
  179. dataset: DiscoverDatasets.SPANS_INDEXED,
  180. projects: [1],
  181. version: 2,
  182. });
  183. };
  184. export const getEndpointDetailSeriesQuery = ({
  185. description,
  186. transactionName,
  187. datetime,
  188. groupId,
  189. }) => {
  190. const {start_timestamp, end_timestamp} = datetimeToClickhouseFilterTimestamps(datetime);
  191. return `SELECT
  192. toStartOfInterval(start_timestamp, INTERVAL 12 HOUR) as interval,
  193. quantile(0.5)(exclusive_time) as p50,
  194. quantile(0.95)(exclusive_time) as p95,
  195. count() as count,
  196. countIf(greaterOrEquals(status, 400) AND lessOrEquals(status, 599)) as failure_count,
  197. failure_count / count as failure_rate
  198. FROM spans_experimental_starfish
  199. WHERE module = 'http'
  200. ${description ? `AND description = '${description}'` : ''}
  201. ${groupId ? `AND group_id = '${groupId}'` : ''}
  202. ${transactionName ? `AND transaction = '${transactionName}'` : ''}
  203. ${
  204. start_timestamp ? `AND greaterOrEquals(start_timestamp, '${start_timestamp}')` : ''
  205. }
  206. ${end_timestamp ? `AND lessOrEquals(start_timestamp, '${end_timestamp}')` : ''}
  207. GROUP BY interval
  208. ORDER BY interval asc
  209. `;
  210. };
  211. export const getEndpointDetailTableQuery = ({
  212. description,
  213. transactionName,
  214. datetime,
  215. groupId,
  216. }) => {
  217. const {start_timestamp, end_timestamp} = datetimeToClickhouseFilterTimestamps(datetime);
  218. return `
  219. SELECT transaction,
  220. count(),
  221. quantile(0.5)(exclusive_time) as "p50(span.self_time)",
  222. quantile(0.95)(exclusive_time) as "p95(span.self_time)",
  223. countIf(greaterOrEquals(status, 400) AND lessOrEquals(status, 599)) as failure_count,
  224. failure_count / count() as failure_rate,
  225. sum(exclusive_time) as "sum(span.self_time)",
  226. count(DISTINCT transaction_id) as "count_unique(transaction)"
  227. FROM spans_experimental_starfish
  228. WHERE module = 'http'
  229. ${description ? `AND description = '${description}'` : ''}
  230. ${groupId ? `AND group_id = '${groupId}'` : ''}
  231. ${transactionName ? `AND transaction = '${transactionName}'` : ''}
  232. ${start_timestamp ? `AND greaterOrEquals(start_timestamp, '${start_timestamp}')` : ''}
  233. ${end_timestamp ? `AND lessOrEquals(start_timestamp, '${end_timestamp}')` : ''}
  234. GROUP BY transaction
  235. ORDER BY count() DESC
  236. LIMIT 5
  237. `;
  238. };
  239. export const getEndpointDetailTableEventView = ({
  240. description,
  241. transactionName,
  242. datetime,
  243. groupId,
  244. }) => {
  245. return EventView.fromSavedQuery({
  246. name: '',
  247. fields: [
  248. 'transaction',
  249. 'count()',
  250. 'p50(span.self_time)',
  251. 'p95(span.self_time)',
  252. 'sum(span.self_time)',
  253. 'count_unique(transaction)',
  254. ],
  255. orderby: '-count',
  256. query: `module:http ${description ? `description:${description}` : ''} ${
  257. transactionName ? `transaction:${transactionName}` : ''
  258. } ${groupId ? `group_id:${groupId}` : ''}`,
  259. start: datetime.start,
  260. end: datetime.end,
  261. range: datetime.period,
  262. dataset: DiscoverDatasets.SPANS_INDEXED,
  263. projects: [1],
  264. version: 2,
  265. });
  266. };
  267. export const getHostStatusBreakdownQuery = ({domain, datetime}) => {
  268. const {start_timestamp, end_timestamp} = datetimeToClickhouseFilterTimestamps(datetime);
  269. return `
  270. SELECT count() as count, status
  271. FROM spans_experimental_starfish
  272. WHERE module = 'http'
  273. AND domain = '${domain}'
  274. ${start_timestamp ? `AND greaterOrEquals(start_timestamp, '${start_timestamp}')` : ''}
  275. ${end_timestamp ? `AND lessOrEquals(start_timestamp, '${end_timestamp}')` : ''}
  276. GROUP BY status
  277. ORDER BY count DESC
  278. `;
  279. };
  280. export const getHostStatusBreakdownEventView = ({domain, datetime}) => {
  281. return EventView.fromSavedQuery({
  282. name: '',
  283. fields: ['status', 'count()'],
  284. orderby: '-count',
  285. query: `module:http domain:${domain}`,
  286. start: datetime.start,
  287. end: datetime.end,
  288. range: datetime.period,
  289. dataset: DiscoverDatasets.SPANS_INDEXED,
  290. projects: [1],
  291. version: 2,
  292. });
  293. };
  294. export const getEndpointAggregatesQuery = ({datetime, transaction}) => {
  295. const {start_timestamp, end_timestamp} = datetimeToClickhouseFilterTimestamps(datetime);
  296. return `
  297. SELECT
  298. description,
  299. toStartOfInterval(start_timestamp, INTERVAL 12 HOUR) as interval,
  300. count() AS count,
  301. quantile(0.5)(exclusive_time) as p50,
  302. quantile(0.95)(exclusive_time) as p95
  303. FROM spans_experimental_starfish
  304. WHERE module = 'http'
  305. ${transaction ? `AND transaction = '${transaction}'` : ''}
  306. ${start_timestamp ? `AND greaterOrEquals(start_timestamp, '${start_timestamp}')` : ''}
  307. ${end_timestamp ? `AND lessOrEquals(start_timestamp, '${end_timestamp}')` : ''}
  308. GROUP BY description, interval
  309. ORDER BY interval asc
  310. `;
  311. };
  312. const ORDERBY = `
  313. -power(10, floor(log10(count()))), -quantile(0.75)(exclusive_time)
  314. `;
  315. const getTransactionsFromHostSubquery = (hostNames: string[], dateFilters: string) => {
  316. const hostFilter = `domain IN ('${hostNames.join(`', '`)}')`;
  317. return `
  318. SELECT
  319. transaction
  320. FROM default.spans_experimental_starfish
  321. WHERE
  322. startsWith(span_operation, 'http')
  323. AND ${hostFilter}
  324. ${dateFilters}
  325. GROUP BY transaction
  326. ORDER BY ${ORDERBY}
  327. LIMIT 5
  328. `;
  329. };
  330. type TopTransactionData = {
  331. interval: string;
  332. transaction: string;
  333. epm?: number;
  334. p75?: number;
  335. };
  336. export const useGetTransactionsForHosts = (
  337. hostNames: string[],
  338. interval: string
  339. ): DefinedUseQueryResult<TopTransactionData[]> => {
  340. const pageFilter = usePageFilters();
  341. const location = useLocation();
  342. const {startTime, endTime} = getDateFilters(pageFilter);
  343. const dateFilters = getDateQueryFilter(startTime, endTime);
  344. const transactionNameQuery = getTransactionsFromHostSubquery(hostNames, dateFilters);
  345. const {start, end, period} = pageFilter.selection.datetime;
  346. const {isLoading: isTopTransactionNamesLoading, data: topTransactionNamesData} =
  347. useQuery<{transaction: string}[]>({
  348. enabled: !!hostNames?.length,
  349. queryKey: ['topTransactionNames', hostNames.join(','), start, end],
  350. queryFn: () =>
  351. fetch(`${HOST}/?query=${transactionNameQuery}`).then(res => res.json()),
  352. retry: false,
  353. refetchOnWindowFocus: false,
  354. initialData: [],
  355. });
  356. const query: NewQuery = {
  357. id: undefined,
  358. name: '',
  359. query: `transaction:[${topTransactionNamesData
  360. ?.map(d => `"${d.transaction}"`)
  361. .join(',')}]`,
  362. projects: [1],
  363. fields: ['transaction', 'epm()', 'p75(transaction.duration)'],
  364. version: 1,
  365. topEvents: '5',
  366. start: start?.toString(),
  367. end: end?.toString(),
  368. dataset: DiscoverDatasets.METRICS_ENHANCED,
  369. interval,
  370. yAxis: ['epm()', 'p75(transaction.duration)'],
  371. };
  372. const eventView = EventView.fromNewQueryWithLocation(query, location);
  373. eventView.statsPeriod = period ?? undefined;
  374. const {
  375. isLoading: isTopTransactionSeriesLoading,
  376. data: topTransactionSeriesData,
  377. ...rest
  378. } = useWrappedDiscoverTimeseriesQuery({
  379. eventView,
  380. initialData: [],
  381. enabled: !isTopTransactionNamesLoading && !!topTransactionNamesData.length,
  382. });
  383. return {
  384. ...rest,
  385. isLoading: isTopTransactionSeriesLoading,
  386. data: topTransactionSeriesData,
  387. } as DefinedUseQueryResult<TopTransactionData[]>;
  388. };