test_organization_events_span_metrics.py 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862
  1. import pytest
  2. from django.urls import reverse
  3. from sentry.search.events import constants
  4. from sentry.testutils.cases import MetricsEnhancedPerformanceTestCase
  5. from sentry.testutils.helpers.datetime import before_now
  6. from sentry.testutils.silo import region_silo_test
  7. pytestmark = pytest.mark.sentry_metrics
  8. class OrganizationEventsMetricsEnhancedPerformanceEndpointTest(MetricsEnhancedPerformanceTestCase):
  9. viewname = "sentry-api-0-organization-events"
  10. # Poor intentionally omitted for test_measurement_rating_that_does_not_exist
  11. METRIC_STRINGS = [
  12. "foo_transaction",
  13. "bar_transaction",
  14. ]
  15. def setUp(self):
  16. super().setUp()
  17. self.min_ago = before_now(minutes=1)
  18. self.six_min_ago = before_now(minutes=6)
  19. self.three_days_ago = before_now(days=3)
  20. self.features = {
  21. "organizations:starfish-view": True,
  22. }
  23. def do_request(self, query, features=None):
  24. if features is None:
  25. features = {"organizations:discover-basic": True}
  26. features.update(self.features)
  27. self.login_as(user=self.user)
  28. url = reverse(
  29. self.viewname,
  30. kwargs={"organization_slug": self.organization.slug},
  31. )
  32. with self.feature(features):
  33. return self.client.get(url, query, format="json")
  34. def test_p50_with_no_data(self):
  35. response = self.do_request(
  36. {
  37. "field": ["p50()"],
  38. "query": "",
  39. "project": self.project.id,
  40. "dataset": "spansMetrics",
  41. }
  42. )
  43. assert response.status_code == 200, response.content
  44. data = response.data["data"]
  45. meta = response.data["meta"]
  46. assert len(data) == 1
  47. assert data[0]["p50()"] == 0
  48. assert meta["dataset"] == "spansMetrics"
  49. def test_count(self):
  50. self.store_span_metric(
  51. 1,
  52. internal_metric=constants.SELF_TIME_LIGHT,
  53. timestamp=self.three_days_ago,
  54. )
  55. response = self.do_request(
  56. {
  57. "field": ["count()"],
  58. "query": "",
  59. "project": self.project.id,
  60. "dataset": "spansMetrics",
  61. "statsPeriod": "7d",
  62. }
  63. )
  64. assert response.status_code == 200, response.content
  65. data = response.data["data"]
  66. meta = response.data["meta"]
  67. assert len(data) == 1
  68. assert data[0]["count()"] == 1
  69. assert meta["dataset"] == "spansMetrics"
  70. def test_count_unique(self):
  71. self.store_span_metric(
  72. 1,
  73. "user",
  74. timestamp=self.min_ago,
  75. )
  76. self.store_span_metric(
  77. 2,
  78. "user",
  79. timestamp=self.min_ago,
  80. )
  81. response = self.do_request(
  82. {
  83. "field": ["count_unique(user)"],
  84. "query": "",
  85. "project": self.project.id,
  86. "dataset": "spansMetrics",
  87. }
  88. )
  89. assert response.status_code == 200, response.content
  90. data = response.data["data"]
  91. meta = response.data["meta"]
  92. assert len(data) == 1
  93. assert data[0]["count_unique(user)"] == 2
  94. assert meta["dataset"] == "spansMetrics"
  95. def test_sum(self):
  96. self.store_span_metric(
  97. 321,
  98. internal_metric=constants.SELF_TIME_LIGHT,
  99. timestamp=self.min_ago,
  100. )
  101. self.store_span_metric(
  102. 99,
  103. internal_metric=constants.SELF_TIME_LIGHT,
  104. timestamp=self.min_ago,
  105. )
  106. response = self.do_request(
  107. {
  108. "field": ["sum(span.self_time)"],
  109. "query": "",
  110. "project": self.project.id,
  111. "dataset": "spansMetrics",
  112. }
  113. )
  114. assert response.status_code == 200, response.content
  115. data = response.data["data"]
  116. meta = response.data["meta"]
  117. assert len(data) == 1
  118. assert data[0]["sum(span.self_time)"] == 420
  119. assert meta["dataset"] == "spansMetrics"
  120. def test_percentile(self):
  121. self.store_span_metric(
  122. 1,
  123. internal_metric=constants.SELF_TIME_LIGHT,
  124. timestamp=self.min_ago,
  125. )
  126. response = self.do_request(
  127. {
  128. "field": ["percentile(span.self_time, 0.95)"],
  129. "query": "",
  130. "project": self.project.id,
  131. "dataset": "spansMetrics",
  132. }
  133. )
  134. assert response.status_code == 200, response.content
  135. data = response.data["data"]
  136. meta = response.data["meta"]
  137. assert len(data) == 1
  138. assert data[0]["percentile(span.self_time, 0.95)"] == 1
  139. assert meta["dataset"] == "spansMetrics"
  140. def test_fixed_percentile_functions(self):
  141. self.store_span_metric(
  142. 1,
  143. internal_metric=constants.SELF_TIME_LIGHT,
  144. timestamp=self.min_ago,
  145. )
  146. for function in ["p50()", "p75()", "p95()", "p99()", "p100()"]:
  147. response = self.do_request(
  148. {
  149. "field": [function],
  150. "query": "",
  151. "project": self.project.id,
  152. "dataset": "spansMetrics",
  153. }
  154. )
  155. assert response.status_code == 200, response.content
  156. data = response.data["data"]
  157. meta = response.data["meta"]
  158. assert len(data) == 1
  159. assert data[0][function] == 1, function
  160. assert meta["dataset"] == "spansMetrics", function
  161. assert meta["fields"][function] == "duration", function
  162. def test_fixed_percentile_functions_with_duration(self):
  163. self.store_span_metric(
  164. 1,
  165. internal_metric=constants.SPAN_METRICS_MAP["span.duration"],
  166. timestamp=self.min_ago,
  167. )
  168. for function in [
  169. "p50(span.duration)",
  170. "p75(span.duration)",
  171. "p95(span.duration)",
  172. "p99(span.duration)",
  173. "p100(span.duration)",
  174. ]:
  175. response = self.do_request(
  176. {
  177. "field": [function],
  178. "query": "",
  179. "project": self.project.id,
  180. "dataset": "spansMetrics",
  181. }
  182. )
  183. assert response.status_code == 200, response.content
  184. data = response.data["data"]
  185. meta = response.data["meta"]
  186. assert len(data) == 1, function
  187. assert data[0][function] == 1, function
  188. assert meta["dataset"] == "spansMetrics", function
  189. assert meta["fields"][function] == "duration", function
  190. def test_avg(self):
  191. self.store_span_metric(
  192. 1,
  193. internal_metric=constants.SELF_TIME_LIGHT,
  194. timestamp=self.min_ago,
  195. )
  196. response = self.do_request(
  197. {
  198. "field": ["avg()"],
  199. "query": "",
  200. "project": self.project.id,
  201. "dataset": "spansMetrics",
  202. }
  203. )
  204. assert response.status_code == 200, response.content
  205. data = response.data["data"]
  206. meta = response.data["meta"]
  207. assert len(data) == 1
  208. assert data[0]["avg()"] == 1
  209. assert meta["dataset"] == "spansMetrics"
  210. def test_eps(self):
  211. for _ in range(6):
  212. self.store_span_metric(
  213. 1,
  214. internal_metric=constants.SELF_TIME_LIGHT,
  215. timestamp=self.min_ago,
  216. )
  217. response = self.do_request(
  218. {
  219. "field": ["eps()", "sps()"],
  220. "query": "",
  221. "project": self.project.id,
  222. "dataset": "spansMetrics",
  223. "statsPeriod": "10m",
  224. }
  225. )
  226. assert response.status_code == 200, response.content
  227. data = response.data["data"]
  228. meta = response.data["meta"]
  229. assert len(data) == 1
  230. assert data[0]["eps()"] == 0.01
  231. assert data[0]["sps()"] == 0.01
  232. assert meta["fields"]["eps()"] == "rate"
  233. assert meta["fields"]["sps()"] == "rate"
  234. assert meta["units"]["eps()"] == "1/second"
  235. assert meta["units"]["sps()"] == "1/second"
  236. assert meta["dataset"] == "spansMetrics"
  237. def test_epm(self):
  238. for _ in range(6):
  239. self.store_span_metric(
  240. 1,
  241. internal_metric=constants.SELF_TIME_LIGHT,
  242. timestamp=self.min_ago,
  243. )
  244. response = self.do_request(
  245. {
  246. "field": ["epm()", "spm()"],
  247. "query": "",
  248. "project": self.project.id,
  249. "dataset": "spansMetrics",
  250. "statsPeriod": "10m",
  251. }
  252. )
  253. assert response.status_code == 200, response.content
  254. data = response.data["data"]
  255. meta = response.data["meta"]
  256. assert len(data) == 1
  257. assert data[0]["epm()"] == 0.6
  258. assert data[0]["spm()"] == 0.6
  259. assert meta["fields"]["epm()"] == "rate"
  260. assert meta["fields"]["spm()"] == "rate"
  261. assert meta["units"]["epm()"] == "1/minute"
  262. assert meta["units"]["spm()"] == "1/minute"
  263. assert meta["dataset"] == "spansMetrics"
  264. def test_time_spent_percentage(self):
  265. for _ in range(4):
  266. self.store_span_metric(
  267. 1,
  268. internal_metric=constants.SELF_TIME_LIGHT,
  269. tags={"transaction": "foo_transaction"},
  270. timestamp=self.min_ago,
  271. )
  272. self.store_span_metric(
  273. 1,
  274. tags={"transaction": "foo_transaction"},
  275. timestamp=self.min_ago,
  276. )
  277. self.store_span_metric(
  278. 1,
  279. internal_metric=constants.SELF_TIME_LIGHT,
  280. tags={"transaction": "bar_transaction"},
  281. timestamp=self.min_ago,
  282. )
  283. self.store_span_metric(
  284. 1,
  285. tags={"transaction": "bar_transaction"},
  286. timestamp=self.min_ago,
  287. )
  288. response = self.do_request(
  289. {
  290. "field": ["transaction", "time_spent_percentage()"],
  291. "query": "",
  292. "orderby": ["-time_spent_percentage()"],
  293. "project": self.project.id,
  294. "dataset": "spansMetrics",
  295. "statsPeriod": "10m",
  296. }
  297. )
  298. assert response.status_code == 200, response.content
  299. data = response.data["data"]
  300. meta = response.data["meta"]
  301. assert len(data) == 2
  302. assert data[0]["time_spent_percentage()"] == 0.8
  303. assert data[0]["transaction"] == "foo_transaction"
  304. assert data[1]["time_spent_percentage()"] == 0.2
  305. assert data[1]["transaction"] == "bar_transaction"
  306. assert meta["dataset"] == "spansMetrics"
  307. def test_time_spent_percentage_local(self):
  308. response = self.do_request(
  309. {
  310. "field": ["time_spent_percentage(local)"],
  311. "query": "",
  312. "orderby": ["-time_spent_percentage(local)"],
  313. "project": self.project.id,
  314. "dataset": "spansMetrics",
  315. "statsPeriod": "10m",
  316. }
  317. )
  318. assert response.status_code == 200, response.content
  319. data = response.data["data"]
  320. meta = response.data["meta"]
  321. assert len(data) == 1
  322. assert data[0]["time_spent_percentage(local)"] is None
  323. assert meta["dataset"] == "spansMetrics"
  324. def test_http_error_rate_and_count(self):
  325. for _ in range(4):
  326. self.store_span_metric(
  327. 1,
  328. internal_metric=constants.SELF_TIME_LIGHT,
  329. tags={"span.status_code": "500"},
  330. timestamp=self.min_ago,
  331. )
  332. self.store_span_metric(
  333. 1,
  334. internal_metric=constants.SELF_TIME_LIGHT,
  335. tags={"span.status_code": "200"},
  336. timestamp=self.min_ago,
  337. )
  338. response = self.do_request(
  339. {
  340. "field": ["http_error_count()", "http_error_rate()"],
  341. "query": "",
  342. "orderby": ["-http_error_rate()"],
  343. "project": self.project.id,
  344. "dataset": "spansMetrics",
  345. "statsPeriod": "10m",
  346. }
  347. )
  348. assert response.status_code == 200, response.content
  349. data = response.data["data"]
  350. meta = response.data["meta"]
  351. assert len(data) == 1
  352. assert data[0]["http_error_rate()"] == 0.8
  353. assert meta["dataset"] == "spansMetrics"
  354. assert meta["fields"]["http_error_count()"] == "integer"
  355. assert meta["fields"]["http_error_rate()"] == "percentage"
  356. def test_use_self_time_light(self):
  357. self.store_span_metric(
  358. 100,
  359. internal_metric=constants.SELF_TIME_LIGHT,
  360. tags={"transaction": "foo_transaction"},
  361. timestamp=self.min_ago,
  362. )
  363. response = self.do_request(
  364. {
  365. "field": ["p50(span.self_time)"],
  366. # Should be 0 since its filtering on transaction
  367. "query": "transaction:foo_transaction",
  368. "orderby": ["-p50(span.self_time)"],
  369. "project": self.project.id,
  370. "dataset": "spansMetrics",
  371. "statsPeriod": "10m",
  372. }
  373. )
  374. assert response.status_code == 200, response.content
  375. data = response.data["data"]
  376. meta = response.data["meta"]
  377. assert len(data) == 1
  378. assert data[0]["p50(span.self_time)"] == 0
  379. assert meta["dataset"] == "spansMetrics"
  380. assert meta["fields"]["p50(span.self_time)"] == "duration"
  381. response = self.do_request(
  382. {
  383. # Should be 0 since it has a transaction column
  384. "field": ["transaction", "p50(span.self_time)"],
  385. "query": "",
  386. "orderby": ["-p50(span.self_time)"],
  387. "project": self.project.id,
  388. "dataset": "spansMetrics",
  389. "statsPeriod": "10m",
  390. }
  391. )
  392. assert response.status_code == 200, response.content
  393. data = response.data["data"]
  394. meta = response.data["meta"]
  395. assert len(data) == 0
  396. response = self.do_request(
  397. {
  398. "field": ["p50(span.self_time)"],
  399. # Should be 100 since its not filtering on transaction
  400. "query": "",
  401. "orderby": ["-p50(span.self_time)"],
  402. "project": self.project.id,
  403. "dataset": "spansMetrics",
  404. "statsPeriod": "10m",
  405. }
  406. )
  407. assert response.status_code == 200, response.content
  408. data = response.data["data"]
  409. meta = response.data["meta"]
  410. assert len(data) == 1
  411. assert data[0]["p50(span.self_time)"] == 100
  412. assert meta["dataset"] == "spansMetrics"
  413. assert meta["fields"]["p50(span.self_time)"] == "duration"
  414. def test_span_module(self):
  415. self.store_span_metric(
  416. 1,
  417. internal_metric=constants.SELF_TIME_LIGHT,
  418. timestamp=self.six_min_ago,
  419. tags={"span.category": "http", "span.description": "f"},
  420. )
  421. self.store_span_metric(
  422. 3,
  423. internal_metric=constants.SELF_TIME_LIGHT,
  424. timestamp=self.six_min_ago,
  425. tags={"span.category": "db", "span.description": "e"},
  426. )
  427. self.store_span_metric(
  428. 5,
  429. internal_metric=constants.SELF_TIME_LIGHT,
  430. timestamp=self.six_min_ago,
  431. tags={"span.category": "foobar", "span.description": "d"},
  432. )
  433. self.store_span_metric(
  434. 7,
  435. internal_metric=constants.SELF_TIME_LIGHT,
  436. timestamp=self.six_min_ago,
  437. tags={"span.category": "cache", "span.description": "c"},
  438. )
  439. self.store_span_metric(
  440. 9,
  441. internal_metric=constants.SELF_TIME_LIGHT,
  442. timestamp=self.six_min_ago,
  443. tags={"span.category": "db", "span.op": "db.redis", "span.description": "b"},
  444. )
  445. self.store_span_metric(
  446. 11,
  447. internal_metric=constants.SELF_TIME_LIGHT,
  448. timestamp=self.six_min_ago,
  449. tags={"span.category": "db", "span.op": "db.sql.room", "span.description": "a"},
  450. )
  451. response = self.do_request(
  452. {
  453. "field": ["span.module", "span.description", "p50(span.self_time)"],
  454. "query": "",
  455. "orderby": ["-p50(span.self_time)"],
  456. "project": self.project.id,
  457. "dataset": "spansMetrics",
  458. "statsPeriod": "10m",
  459. }
  460. )
  461. assert response.status_code == 200, response.content
  462. data = response.data["data"]
  463. meta = response.data["meta"]
  464. assert len(data) == 6
  465. assert data[0]["p50(span.self_time)"] == 11
  466. assert data[0]["span.module"] == "other"
  467. assert data[0]["span.description"] == "a"
  468. assert data[1]["p50(span.self_time)"] == 9
  469. assert data[1]["span.module"] == "cache"
  470. assert data[1]["span.description"] == "b"
  471. assert data[2]["p50(span.self_time)"] == 7
  472. assert data[2]["span.module"] == "cache"
  473. assert data[2]["span.description"] == "c"
  474. assert data[3]["p50(span.self_time)"] == 5
  475. assert data[3]["span.module"] == "other"
  476. assert data[3]["span.description"] == "d"
  477. assert data[4]["p50(span.self_time)"] == 3
  478. assert data[4]["span.module"] == "db"
  479. assert data[4]["span.description"] == "e"
  480. assert data[5]["p50(span.self_time)"] == 1
  481. assert data[5]["span.module"] == "http"
  482. assert data[5]["span.description"] == "f"
  483. assert meta["dataset"] == "spansMetrics"
  484. assert meta["fields"]["p50(span.self_time)"] == "duration"
  485. def test_tag_search(self):
  486. self.store_span_metric(
  487. 321,
  488. internal_metric=constants.SELF_TIME_LIGHT,
  489. timestamp=self.min_ago,
  490. tags={"span.description": "foo"},
  491. )
  492. self.store_span_metric(
  493. 99,
  494. internal_metric=constants.SELF_TIME_LIGHT,
  495. timestamp=self.min_ago,
  496. tags={"span.description": "bar"},
  497. )
  498. response = self.do_request(
  499. {
  500. "field": ["sum(span.self_time)"],
  501. "query": "span.description:bar",
  502. "project": self.project.id,
  503. "dataset": "spansMetrics",
  504. }
  505. )
  506. assert response.status_code == 200, response.content
  507. data = response.data["data"]
  508. meta = response.data["meta"]
  509. assert len(data) == 1
  510. assert data[0]["sum(span.self_time)"] == 99
  511. assert meta["dataset"] == "spansMetrics"
  512. def test_free_text_search(self):
  513. self.store_span_metric(
  514. 321,
  515. internal_metric=constants.SELF_TIME_LIGHT,
  516. timestamp=self.min_ago,
  517. tags={"span.description": "foo"},
  518. )
  519. self.store_span_metric(
  520. 99,
  521. internal_metric=constants.SELF_TIME_LIGHT,
  522. timestamp=self.min_ago,
  523. tags={"span.description": "bar"},
  524. )
  525. response = self.do_request(
  526. {
  527. "field": ["sum(span.self_time)"],
  528. "query": "foo",
  529. "project": self.project.id,
  530. "dataset": "spansMetrics",
  531. }
  532. )
  533. assert response.status_code == 200, response.content
  534. data = response.data["data"]
  535. meta = response.data["meta"]
  536. assert len(data) == 1
  537. assert data[0]["sum(span.self_time)"] == 321
  538. assert meta["dataset"] == "spansMetrics"
  539. def test_avg_compare(self):
  540. self.store_span_metric(
  541. 100,
  542. internal_metric=constants.SELF_TIME_LIGHT,
  543. timestamp=self.min_ago,
  544. tags={"release": "foo"},
  545. )
  546. self.store_span_metric(
  547. 10,
  548. internal_metric=constants.SELF_TIME_LIGHT,
  549. timestamp=self.min_ago,
  550. tags={"release": "bar"},
  551. )
  552. for function_name in [
  553. "avg_compare(span.self_time, release, foo, bar)",
  554. 'avg_compare(span.self_time, release, "foo", "bar")',
  555. ]:
  556. response = self.do_request(
  557. {
  558. "field": [function_name],
  559. "query": "",
  560. "project": self.project.id,
  561. "dataset": "spansMetrics",
  562. }
  563. )
  564. assert response.status_code == 200, response.content
  565. data = response.data["data"]
  566. meta = response.data["meta"]
  567. assert len(data) == 1
  568. assert data[0][function_name] == -0.9
  569. assert meta["dataset"] == "spansMetrics"
  570. assert meta["fields"][function_name] == "percent_change"
  571. def test_avg_compare_invalid_column(self):
  572. response = self.do_request(
  573. {
  574. "field": ["avg_compare(span.self_time, transaction, foo, bar)"],
  575. "query": "",
  576. "project": self.project.id,
  577. "dataset": "spansMetrics",
  578. }
  579. )
  580. assert response.status_code == 400, response.content
  581. def test_span_domain_array(self):
  582. self.store_span_metric(
  583. 321,
  584. internal_metric=constants.SELF_TIME_LIGHT,
  585. timestamp=self.min_ago,
  586. tags={"span.domain": ",sentry_table1,"},
  587. )
  588. self.store_span_metric(
  589. 21,
  590. internal_metric=constants.SELF_TIME_LIGHT,
  591. timestamp=self.min_ago,
  592. tags={"span.domain": ",sentry_table1,sentry_table2,"},
  593. )
  594. response = self.do_request(
  595. {
  596. "field": ["span.domain", "p75(span.self_time)"],
  597. "query": "",
  598. "project": self.project.id,
  599. "orderby": ["-p75(span.self_time)"],
  600. "dataset": "spansMetrics",
  601. }
  602. )
  603. assert response.status_code == 200, response.content
  604. data = response.data["data"]
  605. meta = response.data["meta"]
  606. assert len(data) == 2
  607. assert data[0]["span.domain"] == ["sentry_table1"]
  608. assert data[1]["span.domain"] == ["sentry_table1", "sentry_table2"]
  609. assert meta["dataset"] == "spansMetrics"
  610. assert meta["fields"]["span.domain"] == "array"
  611. def test_span_domain_array_filter(self):
  612. self.store_span_metric(
  613. 321,
  614. internal_metric=constants.SELF_TIME_LIGHT,
  615. timestamp=self.min_ago,
  616. tags={"span.domain": ",sentry_table1,"},
  617. )
  618. self.store_span_metric(
  619. 21,
  620. internal_metric=constants.SELF_TIME_LIGHT,
  621. timestamp=self.min_ago,
  622. tags={"span.domain": ",sentry_table1,sentry_table2,"},
  623. )
  624. response = self.do_request(
  625. {
  626. "field": ["span.domain", "p75(span.self_time)"],
  627. "query": "span.domain:sentry_table2",
  628. "project": self.project.id,
  629. "dataset": "spansMetrics",
  630. }
  631. )
  632. assert response.status_code == 200, response.content
  633. data = response.data["data"]
  634. meta = response.data["meta"]
  635. assert len(data) == 1
  636. assert data[0]["span.domain"] == ["sentry_table1", "sentry_table2"]
  637. assert meta["dataset"] == "spansMetrics"
  638. assert meta["fields"]["span.domain"] == "array"
  639. def test_span_domain_array_filter_wildcard(self):
  640. self.store_span_metric(
  641. 321,
  642. internal_metric=constants.SELF_TIME_LIGHT,
  643. timestamp=self.min_ago,
  644. tags={"span.domain": ",sentry_table1,"},
  645. )
  646. self.store_span_metric(
  647. 21,
  648. internal_metric=constants.SELF_TIME_LIGHT,
  649. timestamp=self.min_ago,
  650. tags={"span.domain": ",sentry_table1,sentry_table2,"},
  651. )
  652. for query in ["sentry*2", "*table2", "sentry_table2*"]:
  653. response = self.do_request(
  654. {
  655. "field": ["span.domain", "p75(span.self_time)"],
  656. "query": f"span.domain:{query}",
  657. "project": self.project.id,
  658. "dataset": "spansMetrics",
  659. }
  660. )
  661. assert response.status_code == 200, response.content
  662. data = response.data["data"]
  663. meta = response.data["meta"]
  664. assert len(data) == 1, query
  665. assert data[0]["span.domain"] == ["sentry_table1", "sentry_table2"], query
  666. assert meta["dataset"] == "spansMetrics", query
  667. assert meta["fields"]["span.domain"] == "array"
  668. def test_span_domain_array_has_filter(self):
  669. self.store_span_metric(
  670. 321,
  671. internal_metric=constants.SELF_TIME_LIGHT,
  672. timestamp=self.min_ago,
  673. tags={"span.domain": ""},
  674. )
  675. self.store_span_metric(
  676. 21,
  677. internal_metric=constants.SELF_TIME_LIGHT,
  678. timestamp=self.min_ago,
  679. tags={"span.domain": ",sentry_table1,sentry_table2,"},
  680. )
  681. response = self.do_request(
  682. {
  683. "field": ["span.domain", "p75(span.self_time)"],
  684. "query": "has:span.domain",
  685. "project": self.project.id,
  686. "dataset": "spansMetrics",
  687. }
  688. )
  689. assert response.status_code == 200, response.content
  690. data = response.data["data"]
  691. meta = response.data["meta"]
  692. assert len(data) == 1
  693. assert data[0]["span.domain"] == ["sentry_table1", "sentry_table2"]
  694. assert meta["dataset"] == "spansMetrics"
  695. response = self.do_request(
  696. {
  697. "field": ["span.domain", "p75(span.self_time)"],
  698. "query": "!has:span.domain",
  699. "project": self.project.id,
  700. "dataset": "spansMetrics",
  701. }
  702. )
  703. assert response.status_code == 200, response.content
  704. data = response.data["data"]
  705. meta = response.data["meta"]
  706. assert len(data) == 1
  707. assert meta["dataset"] == "spansMetrics"
  708. assert meta["fields"]["span.domain"] == "array"
  709. def test_unique_values_span_domain(self):
  710. self.store_span_metric(
  711. 321,
  712. internal_metric=constants.SELF_TIME_LIGHT,
  713. timestamp=self.min_ago,
  714. tags={"span.domain": ",sentry_table1,"},
  715. )
  716. self.store_span_metric(
  717. 21,
  718. internal_metric=constants.SELF_TIME_LIGHT,
  719. timestamp=self.min_ago,
  720. tags={"span.domain": ",sentry_table2,sentry_table3,"},
  721. )
  722. response = self.do_request(
  723. {
  724. "field": ["unique.span_domains", "count()"],
  725. "query": "",
  726. "orderby": "unique.span_domains",
  727. "project": self.project.id,
  728. "dataset": "spansMetrics",
  729. }
  730. )
  731. assert response.status_code == 200, response.content
  732. data = response.data["data"]
  733. meta = response.data["meta"]
  734. assert len(data) == 3
  735. assert data[0]["unique.span_domains"] == "sentry_table1"
  736. assert data[1]["unique.span_domains"] == "sentry_table2"
  737. assert data[2]["unique.span_domains"] == "sentry_table3"
  738. assert meta["fields"]["unique.span_domains"] == "string"
  739. def test_unique_values_span_domain_with_filter(self):
  740. self.store_span_metric(
  741. 321,
  742. internal_metric=constants.SELF_TIME_LIGHT,
  743. timestamp=self.min_ago,
  744. tags={"span.domain": ",sentry_tible1,"},
  745. )
  746. self.store_span_metric(
  747. 21,
  748. internal_metric=constants.SELF_TIME_LIGHT,
  749. timestamp=self.min_ago,
  750. tags={"span.domain": ",sentry_table2,sentry_table3,"},
  751. )
  752. response = self.do_request(
  753. {
  754. "field": ["unique.span_domains", "count()"],
  755. "query": "span.domain:sentry_tab*",
  756. "orderby": "unique.span_domains",
  757. "project": self.project.id,
  758. "dataset": "spansMetrics",
  759. }
  760. )
  761. assert response.status_code == 200, response.content
  762. data = response.data["data"]
  763. meta = response.data["meta"]
  764. assert len(data) == 2
  765. assert data[0]["unique.span_domains"] == "sentry_table2"
  766. assert data[1]["unique.span_domains"] == "sentry_table3"
  767. assert meta["fields"]["unique.span_domains"] == "string"
  768. @region_silo_test
  769. class OrganizationEventsMetricsEnhancedPerformanceEndpointTestWithMetricLayer(
  770. OrganizationEventsMetricsEnhancedPerformanceEndpointTest
  771. ):
  772. def setUp(self):
  773. super().setUp()
  774. self.features["organizations:use-metrics-layer"] = True
  775. @pytest.mark.xfail(reason="Not implemented")
  776. def test_time_spent_percentage(self):
  777. super().test_time_spent_percentage()
  778. @pytest.mark.xfail(reason="Not implemented")
  779. def test_time_spent_percentage_local(self):
  780. super().test_time_spent_percentage_local()
  781. @pytest.mark.xfail(reason="Cannot group by function 'if'")
  782. def test_span_module(self):
  783. super().test_span_module()
  784. @pytest.mark.xfail(reason="Cannot search by tags")
  785. def test_tag_search(self):
  786. super().test_tag_search()
  787. @pytest.mark.xfail(reason="Cannot search by tags")
  788. def test_free_text_search(self):
  789. super().test_free_text_search()
  790. @pytest.mark.xfail(reason="Not implemented")
  791. def test_avg_compare(self):
  792. super().test_avg_compare()
  793. @pytest.mark.xfail(reason="Not implemented")
  794. def test_span_domain_array(self):
  795. super().test_span_domain_array()
  796. @pytest.mark.xfail(reason="Not implemented")
  797. def test_span_domain_array_filter(self):
  798. super().test_span_domain_array_filter()
  799. @pytest.mark.xfail(reason="Not implemented")
  800. def test_span_domain_array_filter_wildcard(self):
  801. super().test_span_domain_array_filter_wildcard()
  802. @pytest.mark.xfail(reason="Not implemented")
  803. def test_span_domain_array_has_filter(self):
  804. super().test_span_domain_array_has_filter()
  805. @pytest.mark.xfail(reason="Not implemented")
  806. def test_unique_values_span_domain(self):
  807. super().test_unique_values_span_domain()
  808. @pytest.mark.xfail(reason="Not implemented")
  809. def test_unique_values_span_domain_with_filter(self):
  810. super().test_unique_values_span_domain_with_filter()