queries.tsx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  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 {HOST} from 'sentry/views/starfish/utils/constants';
  9. import {
  10. datetimeToClickhouseFilterTimestamps,
  11. getDateFilters,
  12. } from 'sentry/views/starfish/utils/dates';
  13. import {getDateQueryFilter} from 'sentry/views/starfish/utils/getDateQueryFilter';
  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. const interval = 12;
  192. return `SELECT
  193. toStartOfInterval(start_timestamp, INTERVAL ${interval} HOUR) as interval,
  194. quantile(0.5)(exclusive_time) as p50,
  195. quantile(0.95)(exclusive_time) as p95,
  196. divide(count(), multiply(${interval}, 60)) as spm,
  197. count() as count,
  198. countIf(greaterOrEquals(status, 400) AND lessOrEquals(status, 599)) as failure_count,
  199. failure_count / count as failure_rate
  200. FROM spans_experimental_starfish
  201. WHERE module = 'http'
  202. ${description ? `AND description = '${description}'` : ''}
  203. ${groupId ? `AND group_id = '${groupId}'` : ''}
  204. ${transactionName ? `AND transaction = '${transactionName}'` : ''}
  205. ${
  206. start_timestamp ? `AND greaterOrEquals(start_timestamp, '${start_timestamp}')` : ''
  207. }
  208. ${end_timestamp ? `AND lessOrEquals(start_timestamp, '${end_timestamp}')` : ''}
  209. GROUP BY interval
  210. ORDER BY interval asc
  211. `;
  212. };
  213. export const getEndpointDetailTableQuery = ({
  214. description,
  215. transactionName,
  216. datetime,
  217. groupId,
  218. }) => {
  219. const {start_timestamp, end_timestamp} = datetimeToClickhouseFilterTimestamps(datetime);
  220. return `
  221. SELECT transaction,
  222. count(),
  223. quantile(0.5)(exclusive_time) as "p50(span.self_time)",
  224. quantile(0.95)(exclusive_time) as "p95(span.self_time)",
  225. countIf(greaterOrEquals(status, 400) AND lessOrEquals(status, 599)) as failure_count,
  226. failure_count / count() as failure_rate,
  227. sum(exclusive_time) as "sum(span.self_time)",
  228. count(DISTINCT transaction_id) as "count_unique(transaction)"
  229. FROM spans_experimental_starfish
  230. WHERE module = 'http'
  231. ${description ? `AND description = '${description}'` : ''}
  232. ${groupId ? `AND group_id = '${groupId}'` : ''}
  233. ${transactionName ? `AND transaction = '${transactionName}'` : ''}
  234. ${start_timestamp ? `AND greaterOrEquals(start_timestamp, '${start_timestamp}')` : ''}
  235. ${end_timestamp ? `AND lessOrEquals(start_timestamp, '${end_timestamp}')` : ''}
  236. GROUP BY transaction
  237. ORDER BY count() DESC
  238. LIMIT 5
  239. `;
  240. };
  241. export const getEndpointDetailTableEventView = ({
  242. description,
  243. transactionName,
  244. datetime,
  245. groupId,
  246. }) => {
  247. return EventView.fromSavedQuery({
  248. name: '',
  249. fields: [
  250. 'transaction',
  251. 'count()',
  252. 'p50(span.self_time)',
  253. 'p95(span.self_time)',
  254. 'sum(span.self_time)',
  255. 'count_unique(transaction)',
  256. ],
  257. orderby: '-count',
  258. query: `module:http ${description ? `description:${description}` : ''} ${
  259. transactionName ? `transaction:${transactionName}` : ''
  260. } ${groupId ? `group_id:${groupId}` : ''}`,
  261. start: datetime.start,
  262. end: datetime.end,
  263. range: datetime.period,
  264. dataset: DiscoverDatasets.SPANS_INDEXED,
  265. projects: [1],
  266. version: 2,
  267. });
  268. };
  269. export const getHostStatusBreakdownQuery = ({domain, datetime}) => {
  270. const {start_timestamp, end_timestamp} = datetimeToClickhouseFilterTimestamps(datetime);
  271. return `
  272. SELECT count() as count, status
  273. FROM spans_experimental_starfish
  274. WHERE module = 'http'
  275. AND domain = '${domain}'
  276. ${start_timestamp ? `AND greaterOrEquals(start_timestamp, '${start_timestamp}')` : ''}
  277. ${end_timestamp ? `AND lessOrEquals(start_timestamp, '${end_timestamp}')` : ''}
  278. GROUP BY status
  279. ORDER BY count DESC
  280. `;
  281. };
  282. export const getHostStatusBreakdownEventView = ({domain, datetime}) => {
  283. return EventView.fromSavedQuery({
  284. name: '',
  285. fields: ['status', 'count()'],
  286. orderby: '-count',
  287. query: `module:http domain:${domain}`,
  288. start: datetime.start,
  289. end: datetime.end,
  290. range: datetime.period,
  291. dataset: DiscoverDatasets.SPANS_INDEXED,
  292. projects: [1],
  293. version: 2,
  294. });
  295. };
  296. export const getEndpointAggregatesQuery = ({datetime, transaction}) => {
  297. const {start_timestamp, end_timestamp} = datetimeToClickhouseFilterTimestamps(datetime);
  298. return `
  299. SELECT
  300. description,
  301. toStartOfInterval(start_timestamp, INTERVAL 12 HOUR) as interval,
  302. count() AS count,
  303. quantile(0.5)(exclusive_time) as p50,
  304. quantile(0.95)(exclusive_time) as p95
  305. FROM spans_experimental_starfish
  306. WHERE module = 'http'
  307. ${transaction ? `AND transaction = '${transaction}'` : ''}
  308. ${start_timestamp ? `AND greaterOrEquals(start_timestamp, '${start_timestamp}')` : ''}
  309. ${end_timestamp ? `AND lessOrEquals(start_timestamp, '${end_timestamp}')` : ''}
  310. GROUP BY description, interval
  311. ORDER BY interval asc
  312. `;
  313. };
  314. const ORDERBY = `
  315. -power(10, floor(log10(count()))), -quantile(0.75)(exclusive_time)
  316. `;
  317. const getTransactionsFromHostSubquery = (hostNames: string[], dateFilters: string) => {
  318. const hostFilter = `domain IN ('${hostNames.join(`', '`)}')`;
  319. return `
  320. SELECT
  321. transaction
  322. FROM default.spans_experimental_starfish
  323. WHERE
  324. startsWith(span_operation, 'http')
  325. AND ${hostFilter}
  326. ${dateFilters}
  327. GROUP BY transaction
  328. ORDER BY ${ORDERBY}
  329. LIMIT 5
  330. `;
  331. };
  332. type TopTransactionData = {
  333. interval: string;
  334. transaction: string;
  335. epm?: number;
  336. p75?: number;
  337. };
  338. export const useGetTransactionsForHosts = (
  339. hostNames: string[],
  340. interval: string
  341. ): DefinedUseQueryResult<TopTransactionData[]> => {
  342. const pageFilter = usePageFilters();
  343. const location = useLocation();
  344. const {startTime, endTime} = getDateFilters(pageFilter);
  345. const dateFilters = getDateQueryFilter(startTime, endTime);
  346. const transactionNameQuery = getTransactionsFromHostSubquery(hostNames, dateFilters);
  347. const {start, end, period} = pageFilter.selection.datetime;
  348. const {isLoading: isTopTransactionNamesLoading, data: topTransactionNamesData} =
  349. useQuery<{transaction: string}[]>({
  350. enabled: !!hostNames?.length,
  351. queryKey: ['topTransactionNames', hostNames.join(','), start, end],
  352. queryFn: () =>
  353. fetch(`${HOST}/?query=${transactionNameQuery}`).then(res => res.json()),
  354. retry: false,
  355. refetchOnWindowFocus: false,
  356. initialData: [],
  357. });
  358. const query: NewQuery = {
  359. id: undefined,
  360. name: '',
  361. query: `transaction:[${topTransactionNamesData
  362. ?.map(d => `"${d.transaction}"`)
  363. .join(',')}]`,
  364. projects: [1],
  365. fields: ['transaction', 'epm()', 'p75(transaction.duration)'],
  366. version: 1,
  367. topEvents: '5',
  368. start: start?.toString(),
  369. end: end?.toString(),
  370. dataset: DiscoverDatasets.METRICS_ENHANCED,
  371. interval,
  372. yAxis: ['epm()', 'p75(transaction.duration)'],
  373. };
  374. const eventView = EventView.fromNewQueryWithLocation(query, location);
  375. eventView.statsPeriod = period ?? undefined;
  376. const {
  377. isLoading: isTopTransactionSeriesLoading,
  378. data: topTransactionSeriesData,
  379. ...rest
  380. } = useWrappedDiscoverTimeseriesQuery({
  381. eventView,
  382. initialData: [],
  383. enabled: !isTopTransactionNamesLoading && !!topTransactionNamesData.length,
  384. });
  385. return {
  386. ...rest,
  387. isLoading: isTopTransactionSeriesLoading,
  388. data: topTransactionSeriesData,
  389. } as DefinedUseQueryResult<TopTransactionData[]>;
  390. };