load-mocks 52 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299
  1. #!/usr/bin/env python
  2. import time
  3. from sentry.runner import configure
  4. from sentry.types.activity import ActivityType
  5. configure()
  6. import itertools
  7. import random
  8. from datetime import datetime, timedelta
  9. from hashlib import sha1
  10. from random import randint
  11. from uuid import uuid4
  12. from django.conf import settings
  13. from django.db import IntegrityError, transaction
  14. from django.db.models import F
  15. from django.utils import timezone
  16. from pytz import utc
  17. from sentry import buffer, roles, tsdb
  18. from sentry.event_manager import HashDiscarded
  19. from sentry.incidents.logic import create_alert_rule, create_alert_rule_trigger, create_incident
  20. from sentry.incidents.models import AlertRuleThresholdType, IncidentType
  21. from sentry.models import (
  22. TOMBSTONE_FIELDS_FROM_GROUP,
  23. Activity,
  24. Broadcast,
  25. Commit,
  26. CommitAuthor,
  27. CommitFileChange,
  28. Deploy,
  29. Environment,
  30. EventAttachment,
  31. File,
  32. Group,
  33. GroupRelease,
  34. GroupTombstone,
  35. Organization,
  36. OrganizationAccessRequest,
  37. OrganizationMember,
  38. Project,
  39. Release,
  40. ReleaseCommit,
  41. ReleaseEnvironment,
  42. ReleaseFile,
  43. ReleaseProjectEnvironment,
  44. Repository,
  45. Team,
  46. User,
  47. UserReport,
  48. )
  49. from sentry.monitors.models import (
  50. CheckInStatus,
  51. Monitor,
  52. MonitorCheckIn,
  53. MonitorEnvironment,
  54. MonitorStatus,
  55. MonitorType,
  56. )
  57. from sentry.signals import mocks_loaded
  58. from sentry.similarity import features
  59. from sentry.utils import loremipsum
  60. from sentry.utils.hashlib import md5_text
  61. from sentry.utils.samples import create_sample_event as _create_sample_event
  62. from sentry.utils.samples import create_trace, generate_user, random_normal
  63. PLATFORMS = itertools.cycle(["ruby", "php", "python", "java", "javascript"])
  64. LEVELS = itertools.cycle(["error", "error", "error", "fatal", "warning"])
  65. ENVIRONMENTS = itertools.cycle(["production", "production", "staging", "alpha", "beta", ""])
  66. MONITOR_NAMES = itertools.cycle(settings.CELERYBEAT_SCHEDULE.keys())
  67. MONITOR_SCHEDULES = itertools.cycle(["* * * * *", "0 * * * *", "0 0 * * *"])
  68. LONG_MESSAGE = """Code: 0.
  69. DB::Exception: String is too long for DateTime: 2018-10-26T19:14:18+00:00. Stack trace:
  70. 0. clickhouse-server(StackTrace::StackTrace()+0x16) [0x99e9626]
  71. 1. clickhouse-server(DB::Exception::Exception(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int)+0x22) [0x3087172]
  72. 2. clickhouse-server(DB::FunctionComparison<DB::EqualsOp, DB::NameEquals>::executeDateOrDateTimeOrEnumOrUUIDWithConstString(DB::Block&, unsigned long, DB::IColumn const*, DB::IColumn const*, std::shared_ptr<DB::IDataType const> const&, std::shared_ptr<DB::IDataType const> const&, bool, unsigned long)+0x13c8) [0x3b233d8]
  73. 3. clickhouse-server(DB::FunctionComparison<DB::EqualsOp, DB::NameEquals>::executeImpl(DB::Block&, std::vector<unsigned long, std::allocator<unsigned long> > const&, unsigned long, unsigned long)+0x576) [0x3bafc86]
  74. 4. clickhouse-server(DB::PreparedFunctionImpl::defaultImplementationForNulls(DB::Block&, std::vector<unsigned long, std::allocator<unsigned long> > const&, unsigned long, unsigned long)+0x174) [0x7953cd4]
  75. 5. clickhouse-server(DB::PreparedFunctionImpl::executeWithoutLowCardinalityColumns(DB::Block&, std::vector<unsigned long, std::allocator<unsigned long> > const&, unsigned long, unsigned long)+0x54) [0x7953b04]
  76. 6. clickhouse-server(DB::PreparedFunctionImpl::execute(DB::Block&, std::vector<unsigned long, std::allocator<unsigned long> > const&, unsigned long, unsigned long)+0x3e2) [0x7954222]
  77. 7. clickhouse-server(DB::ExpressionAction::execute(DB::Block&, std::unordered_map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, unsigned long, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, unsigned long> > >&) const+0x69b) [0x7b021fb]
  78. 8. clickhouse-server(DB::ExpressionActions::execute(DB::Block&) const+0xe6) [0x7b03676]
  79. 9. clickhouse-server(DB::FilterBlockInputStream::FilterBlockInputStream(std::shared_ptr<DB::IBlockInputStream> const&, std::shared_ptr<DB::ExpressionActions> const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool)+0x711) [0x79b7e31]
  80. 10. clickhouse-server() [0x75e9443]
  81. 11. clickhouse-server(DB::InterpreterSelectQuery::executeImpl(DB::InterpreterSelectQuery::Pipeline&, std::shared_ptr<DB::IBlockInputStream> const&, bool)+0x118f) [0x75f212f]
  82. 12. clickhouse-server(DB::InterpreterSelectQuery::InterpreterSelectQuery(std::shared_ptr<DB::IAST> const&, DB::Context const&, std::shared_ptr<DB::IBlockInputStream> const&, std::shared_ptr<DB::IStorage> const&, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, DB::QueryProcessingStage::Enum, unsigned long, bool)+0x5e6) [0x75f2d46]
  83. 13. clickhouse-server(DB::InterpreterSelectQuery::InterpreterSelectQuery(std::shared_ptr<DB::IAST> const&, DB::Context const&, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, DB::QueryProcessingStage::Enum, unsigned long, bool)+0x56) [0x75f3aa6]
  84. 14. clickhouse-server(DB::InterpreterSelectWithUnionQuery::InterpreterSelectWithUnionQuery(std::shared_ptr<DB::IAST> const&, DB::Context const&, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, DB::QueryProcessingStage::Enum, unsigned long, bool)+0x7e7) [0x75ffab7]
  85. 15. clickhouse-server(DB::InterpreterFactory::get(std::shared_ptr<DB::IAST>&, DB::Context&, DB::QueryProcessingStage::Enum)+0x3a8) [0x75dc138]
  86. 16. clickhouse-server() [0x768fad9]
  87. 17. clickhouse-server(DB::executeQuery(std::__cxx11::basic..."""
  88. def make_sentence(words=None):
  89. if words is None:
  90. words = int(random.weibullvariate(8, 3))
  91. return " ".join(random.choice(loremipsum.words) for _ in range(words))
  92. def create_sample_event(*args, **kwargs):
  93. try:
  94. event = _create_sample_event(*args, **kwargs)
  95. except HashDiscarded as e:
  96. print(f"> Skipping Event: {e.message}") # NOQA
  97. else:
  98. if event is not None:
  99. features.record([event])
  100. return event
  101. def generate_commits(user):
  102. commits = []
  103. for i in range(random.randint(1, 20)):
  104. if i == 1:
  105. filename = "raven/base.py"
  106. else:
  107. filename = random.choice(loremipsum.words) + ".js"
  108. if random.randint(0, 5) == 1:
  109. author = (user.name, user.email)
  110. else:
  111. author = (
  112. f"{random.choice(loremipsum.words)} {random.choice(loremipsum.words)}",
  113. f"{random.choice(loremipsum.words)}@example.com",
  114. )
  115. commits.append(
  116. {
  117. "key": sha1(uuid4().bytes).hexdigest(),
  118. "message": f"feat: Do something to {filename}\n{make_sentence()}",
  119. "author": author,
  120. "files": [(filename, "M")],
  121. }
  122. )
  123. return commits
  124. def generate_tombstones(project, user):
  125. # attempt to create a high enough previous_group_id
  126. # that it won't conflict with any group ids
  127. prev_group_id = 100000
  128. try:
  129. prev_group_id = (
  130. max(
  131. GroupTombstone.objects.order_by("-previous_group_id")[0].previous_group_id,
  132. prev_group_id,
  133. )
  134. + 1
  135. )
  136. except IndexError:
  137. pass
  138. for group in Group.objects.filter(project=project)[:5]:
  139. GroupTombstone.objects.create(
  140. previous_group_id=prev_group_id,
  141. actor_id=user.id,
  142. **{name: getattr(group, name) for name in TOMBSTONE_FIELDS_FROM_GROUP},
  143. )
  144. prev_group_id += 1
  145. def create_system_time_series():
  146. now = datetime.utcnow().replace(tzinfo=utc)
  147. for _ in range(60):
  148. count = randint(1, 10)
  149. tsdb.incr_multi(
  150. (
  151. (tsdb.models.internal, "client-api.all-versions.responses.2xx"),
  152. (tsdb.models.internal, "client-api.all-versions.requests"),
  153. ),
  154. now,
  155. int(count * 0.9),
  156. )
  157. tsdb.incr_multi(
  158. ((tsdb.models.internal, "client-api.all-versions.responses.4xx"),),
  159. now,
  160. int(count * 0.05),
  161. )
  162. tsdb.incr_multi(
  163. ((tsdb.models.internal, "client-api.all-versions.responses.5xx"),),
  164. now,
  165. int(count * 0.1),
  166. )
  167. now = now - timedelta(seconds=1)
  168. for _ in range(24 * 30):
  169. count = randint(100, 1000)
  170. tsdb.incr_multi(
  171. (
  172. (tsdb.models.internal, "client-api.all-versions.responses.2xx"),
  173. (tsdb.models.internal, "client-api.all-versions.requests"),
  174. ),
  175. now,
  176. int(count * 4.9),
  177. )
  178. tsdb.incr_multi(
  179. ((tsdb.models.internal, "client-api.all-versions.responses.4xx"),),
  180. now,
  181. int(count * 0.05),
  182. )
  183. tsdb.incr_multi(
  184. ((tsdb.models.internal, "client-api.all-versions.responses.5xx"),),
  185. now,
  186. int(count * 0.1),
  187. )
  188. now = now - timedelta(hours=1)
  189. def create_sample_time_series(event, release=None):
  190. if event is None:
  191. return
  192. group = event.group
  193. project = group.project
  194. key = project.key_set.all()[0]
  195. now = datetime.utcnow().replace(tzinfo=utc)
  196. environment = Environment.get_or_create(
  197. project=project, name=Environment.get_name_or_default(event.get_tag("environment"))
  198. )
  199. if release:
  200. ReleaseEnvironment.get_or_create(
  201. project=project, release=release, environment=environment, datetime=now
  202. )
  203. grouprelease = GroupRelease.get_or_create(
  204. group=group, release=release, environment=environment, datetime=now
  205. )
  206. for _ in range(60):
  207. count = randint(1, 10)
  208. tsdb.incr_multi(
  209. ((tsdb.models.project, project.id), (tsdb.models.group, group.id)),
  210. now,
  211. count,
  212. environment_id=environment.id,
  213. )
  214. tsdb.incr_multi(
  215. (
  216. (tsdb.models.organization_total_received, project.organization_id),
  217. (tsdb.models.project_total_received, project.id),
  218. (tsdb.models.key_total_received, key.id),
  219. ),
  220. now,
  221. int(count * 1.1),
  222. )
  223. tsdb.incr(
  224. tsdb.models.project_total_forwarded,
  225. project.id,
  226. now,
  227. int(count * 1.1),
  228. )
  229. tsdb.incr_multi(
  230. (
  231. (tsdb.models.organization_total_rejected, project.organization_id),
  232. (tsdb.models.project_total_rejected, project.id),
  233. (tsdb.models.key_total_rejected, key.id),
  234. ),
  235. now,
  236. int(count * 0.1),
  237. )
  238. frequencies = [
  239. (tsdb.models.frequent_issues_by_project, {project.id: {group.id: count}}),
  240. (tsdb.models.frequent_environments_by_group, {group.id: {environment.id: count}}),
  241. ]
  242. if release:
  243. frequencies.append(
  244. (tsdb.models.frequent_releases_by_group, {group.id: {grouprelease.id: count}})
  245. )
  246. tsdb.record_frequency_multi(frequencies, now)
  247. now = now - timedelta(seconds=1)
  248. for _ in range(24 * 30):
  249. count = randint(100, 1000)
  250. tsdb.incr_multi(
  251. ((tsdb.models.project, group.project.id), (tsdb.models.group, group.id)),
  252. now,
  253. count,
  254. environment_id=environment.id,
  255. )
  256. tsdb.incr_multi(
  257. (
  258. (tsdb.models.organization_total_received, project.organization_id),
  259. (tsdb.models.project_total_received, project.id),
  260. (tsdb.models.key_total_received, key.id),
  261. ),
  262. now,
  263. int(count * 1.1),
  264. )
  265. tsdb.incr_multi(
  266. (
  267. (tsdb.models.organization_total_rejected, project.organization_id),
  268. (tsdb.models.project_total_rejected, project.id),
  269. (tsdb.models.key_total_rejected, key.id),
  270. ),
  271. now,
  272. int(count * 0.1),
  273. )
  274. frequencies = [
  275. (tsdb.models.frequent_issues_by_project, {project.id: {group.id: count}}),
  276. (tsdb.models.frequent_environments_by_group, {group.id: {environment.id: count}}),
  277. ]
  278. if release:
  279. frequencies.append(
  280. (tsdb.models.frequent_releases_by_group, {group.id: {grouprelease.id: count}})
  281. )
  282. tsdb.record_frequency_multi(frequencies, now)
  283. now = now - timedelta(hours=1)
  284. def main(
  285. skip_default_setup=False,
  286. num_events=1,
  287. extra_events=False,
  288. load_trends=False,
  289. load_performance_issues=False,
  290. slow=False,
  291. ):
  292. from sentry.constants import ObjectStatus
  293. try:
  294. user = User.objects.filter(is_superuser=True)[0]
  295. except IndexError:
  296. raise Exception("No superuser exists (run `make bootstrap`)")
  297. dummy_user, _ = User.objects.get_or_create(
  298. username="dummy@example.com", defaults={"email": "dummy@example.com"}
  299. )
  300. dummy_user.set_password("dummy")
  301. dummy_user.save()
  302. mocks = (
  303. ("Massive Dynamic", ("Ludic Science",)),
  304. ("Captain Planet", ("Earth", "Fire", "Wind", "Water", "Heart")),
  305. )
  306. project_map = {}
  307. Broadcast.objects.create(
  308. title="Learn about Source Maps",
  309. message="Source maps are JSON files that contain information on how to map your transpiled source code back to their original source.",
  310. link="https://docs.sentry.io/platforms/javascript/#source-maps",
  311. )
  312. if settings.SENTRY_SINGLE_ORGANIZATION:
  313. org = Organization.get_default()
  314. print(f"Mocking org {org.name}") # NOQA
  315. else:
  316. print("Mocking org {}".format("Default")) # NOQA
  317. org, _ = Organization.objects.get_or_create(slug="default")
  318. OrganizationMember.objects.get_or_create(
  319. user=user, organization=org, role=roles.get_top_dog().id
  320. )
  321. dummy_member, _ = OrganizationMember.objects.get_or_create(
  322. user=dummy_user, organization=org, defaults={"role": roles.get_default().id}
  323. )
  324. # Allow for 0 events, if you only want transactions
  325. event1 = event2 = event3 = event4 = event5 = None
  326. if skip_default_setup:
  327. # Quickly fetch/create the teams and projects
  328. for team_name, project_names in mocks:
  329. print(f"> Mocking team {team_name}") # NOQA
  330. team, _ = Team.objects.get_or_create(name=team_name, defaults={"organization": org})
  331. for project_name in project_names:
  332. print(f" > Mocking project {project_name}") # NOQA
  333. project, _ = Project.objects.get_or_create(
  334. name=project_name,
  335. defaults={
  336. "organization": org,
  337. "first_event": timezone.now(),
  338. "flags": Project.flags.has_releases,
  339. },
  340. )
  341. project_map[project_name] = project
  342. project.add_team(team)
  343. else:
  344. for team_name, project_names in mocks:
  345. print(f"> Mocking team {team_name}") # NOQA
  346. team, _ = Team.objects.get_or_create(name=team_name, defaults={"organization": org})
  347. for project_name in project_names:
  348. print(f" > Mocking project {project_name}") # NOQA
  349. project, _ = Project.objects.get_or_create(
  350. name=project_name,
  351. defaults={
  352. "organization": org,
  353. "first_event": timezone.now(),
  354. "flags": Project.flags.has_releases,
  355. },
  356. )
  357. project_map[project_name] = project
  358. project.add_team(team)
  359. if not project.first_event:
  360. project.update(first_event=project.date_added)
  361. if not project.flags.has_releases:
  362. project.update(flags=F("flags").bitor(Project.flags.has_releases))
  363. environment = Environment.get_or_create(project=project, name=next(ENVIRONMENTS))
  364. monitor, _ = Monitor.objects.get_or_create(
  365. name=next(MONITOR_NAMES),
  366. project_id=project.id,
  367. organization_id=org.id,
  368. type=MonitorType.CRON_JOB,
  369. defaults={
  370. "status": ObjectStatus.DISABLED,
  371. "config": {"schedule": next(MONITOR_SCHEDULES)},
  372. "next_checkin": timezone.now() + timedelta(minutes=60),
  373. "last_checkin": timezone.now(),
  374. },
  375. )
  376. monitor_env, _ = MonitorEnvironment.objects.get_or_create(
  377. monitor=monitor,
  378. environment=environment,
  379. defaults={
  380. "status": MonitorStatus.DISABLED,
  381. "next_checkin": timezone.now() + timedelta(minutes=60),
  382. "last_checkin": timezone.now(),
  383. },
  384. )
  385. MonitorCheckIn.objects.create(
  386. project_id=monitor.project_id,
  387. monitor=monitor,
  388. monitor_environment=monitor_env,
  389. status=CheckInStatus.OK
  390. if monitor_env.status == MonitorStatus.OK
  391. else CheckInStatus.ERROR,
  392. )
  393. with transaction.atomic():
  394. has_release = Release.objects.filter(
  395. version=sha1(uuid4().bytes).hexdigest(),
  396. organization_id=project.organization_id,
  397. projects=project,
  398. ).exists()
  399. if not has_release:
  400. release = Release.objects.filter(
  401. version=sha1(uuid4().bytes).hexdigest(),
  402. organization_id=project.organization_id,
  403. ).first()
  404. if not release:
  405. release = Release.objects.create(
  406. version=sha1(uuid4().bytes).hexdigest(),
  407. organization_id=project.organization_id,
  408. )
  409. release.add_project(project)
  410. generate_tombstones(project, user)
  411. raw_commits = generate_commits(user)
  412. try:
  413. with transaction.atomic():
  414. repo, _ = Repository.objects.get_or_create(
  415. organization_id=org.id,
  416. provider="integrations:github",
  417. external_id="example/example",
  418. defaults={
  419. "name": "Example Repo",
  420. "url": "https://github.com/example/example",
  421. },
  422. )
  423. except IntegrityError:
  424. # for users with legacy github plugin
  425. # upgrade to the new integration
  426. repo = Repository.objects.get(
  427. organization_id=org.id,
  428. provider="github",
  429. external_id="example/example",
  430. name="Example Repo",
  431. )
  432. repo.provider = "integrations:github"
  433. repo.save()
  434. authors = set()
  435. for commit_index, raw_commit in enumerate(raw_commits):
  436. author = CommitAuthor.objects.get_or_create(
  437. organization_id=org.id,
  438. email=raw_commit["author"][1],
  439. defaults={"name": raw_commit["author"][0]},
  440. )[0]
  441. commit = Commit.objects.get_or_create(
  442. organization_id=org.id,
  443. repository_id=repo.id,
  444. key=raw_commit["key"],
  445. defaults={"author": author, "message": raw_commit["message"]},
  446. )[0]
  447. authors.add(author)
  448. for file in raw_commit["files"]:
  449. ReleaseFile.objects.get_or_create(
  450. organization_id=project.organization_id,
  451. release_id=release.id,
  452. name=file[0],
  453. file=File.objects.get_or_create(
  454. name=file[0], type="release.file", checksum="abcde" * 8, size=13043
  455. )[0],
  456. defaults={"organization_id": project.organization_id},
  457. )
  458. CommitFileChange.objects.get_or_create(
  459. organization_id=org.id, commit=commit, filename=file[0], type=file[1]
  460. )
  461. ReleaseCommit.objects.get_or_create(
  462. organization_id=org.id, release=release, commit=commit, order=commit_index
  463. )
  464. # create an unreleased commit
  465. Commit.objects.get_or_create(
  466. organization_id=org.id,
  467. repository_id=repo.id,
  468. key=sha1(uuid4().bytes).hexdigest(),
  469. defaults={
  470. "author": CommitAuthor.objects.get_or_create(
  471. organization_id=org.id, email=user.email, defaults={"name": user.name}
  472. )[0],
  473. "message": "feat: Do something to {}\n{}".format(
  474. random.choice(loremipsum.words) + ".js", make_sentence()
  475. ),
  476. },
  477. )[0]
  478. Activity.objects.create(
  479. type=ActivityType.RELEASE.value,
  480. project=project,
  481. ident=release.version,
  482. user_id=user.id,
  483. data={"version": release.version},
  484. )
  485. deploy = Deploy.objects.create(
  486. organization_id=project.organization_id,
  487. release=release,
  488. environment_id=environment.id,
  489. )
  490. release.update(
  491. commit_count=len(raw_commits),
  492. last_commit_id=commit.id,
  493. total_deploys=Deploy.objects.filter(release=release).count(),
  494. last_deploy_id=deploy.id,
  495. authors=[str(a.id) for a in authors],
  496. )
  497. ReleaseProjectEnvironment.objects.create_or_update(
  498. project=project,
  499. environment=environment,
  500. release=release,
  501. defaults={"last_deploy_id": deploy.id},
  502. )
  503. Activity.objects.create(
  504. type=ActivityType.DEPLOY.value,
  505. project=project,
  506. ident=release.version,
  507. data={
  508. "version": release.version,
  509. "deploy_id": deploy.id,
  510. "environment": environment.name,
  511. },
  512. datetime=deploy.date_finished,
  513. )
  514. # Add a bunch of additional dummy events to support pagination
  515. if extra_events:
  516. for _ in range(45):
  517. platform = next(PLATFORMS)
  518. create_sample_event(
  519. project=project,
  520. platform=platform,
  521. release=release.version,
  522. level=next(LEVELS),
  523. environment=next(ENVIRONMENTS),
  524. message="This is a mostly useless example %s exception" % platform,
  525. checksum=md5_text(platform + str(_)).hexdigest(),
  526. user=generate_user(),
  527. )
  528. for _ in range(num_events):
  529. event1 = create_sample_event(
  530. project=project,
  531. platform="python",
  532. release=release.version,
  533. environment=next(ENVIRONMENTS),
  534. user=generate_user(),
  535. )
  536. EventAttachment.objects.create(
  537. project_id=project.id,
  538. event_id=event1.event_id,
  539. name="example-logfile.txt",
  540. file_id=File.objects.get_or_create(
  541. name="example-logfile.txt",
  542. type="text/plain",
  543. checksum="abcde" * 8,
  544. size=13043,
  545. )[0].id,
  546. )
  547. event2 = create_sample_event(
  548. project=project,
  549. platform="javascript",
  550. release=release.version,
  551. environment=next(ENVIRONMENTS),
  552. sdk={"name": "raven-js", "version": "2.1.0"},
  553. user=generate_user(),
  554. )
  555. event3 = create_sample_event(project, "java")
  556. event4 = create_sample_event(
  557. project=project,
  558. platform="ruby",
  559. release=release.version,
  560. environment=next(ENVIRONMENTS),
  561. user=generate_user(),
  562. )
  563. event5 = create_sample_event(
  564. project=project,
  565. platform="cocoa",
  566. release=release.version,
  567. environment=next(ENVIRONMENTS),
  568. user=generate_user(),
  569. )
  570. create_sample_event(
  571. project=project,
  572. platform="php",
  573. release=release.version,
  574. environment=next(ENVIRONMENTS),
  575. message=LONG_MESSAGE,
  576. user=generate_user(),
  577. )
  578. create_sample_event(
  579. project=project,
  580. platform="cocoa",
  581. sample_name="react-native",
  582. release=release.version,
  583. environment=next(ENVIRONMENTS),
  584. user=generate_user(),
  585. )
  586. create_sample_event(
  587. project=project,
  588. platform="pii",
  589. release=release.version,
  590. environment=next(ENVIRONMENTS),
  591. user=generate_user(),
  592. )
  593. if event5:
  594. Commit.objects.get_or_create(
  595. organization_id=org.id,
  596. repository_id=repo.id,
  597. key=sha1(uuid4().bytes).hexdigest(),
  598. defaults={
  599. "author": CommitAuthor.objects.get_or_create(
  600. organization_id=org.id,
  601. email=user.email,
  602. defaults={"name": user.name},
  603. )[0],
  604. "message": f"Ooops!\nFixes {event5.group.qualified_short_id}",
  605. },
  606. )[0]
  607. create_sample_event(project=project, environment=next(ENVIRONMENTS), platform="csp")
  608. if event3:
  609. UserReport.objects.create(
  610. project_id=project.id,
  611. event_id=event3.event_id,
  612. group_id=event3.group.id,
  613. name="Jane Bloggs",
  614. email="jane@example.com",
  615. comments=make_sentence(),
  616. )
  617. # Metric alerts
  618. alert_rule = create_alert_rule(
  619. org,
  620. [project],
  621. "My Alert Rule",
  622. "level:error",
  623. "count()",
  624. 10,
  625. AlertRuleThresholdType.ABOVE,
  626. 1,
  627. )
  628. create_alert_rule_trigger(alert_rule, "critical", 10)
  629. create_incident(
  630. org,
  631. type_=IncidentType.DETECTED,
  632. title="My Incident",
  633. date_started=datetime.utcnow().replace(tzinfo=utc),
  634. alert_rule=alert_rule,
  635. projects=[project],
  636. )
  637. print(f" > Loading time series data") # NOQA
  638. if event1:
  639. create_sample_time_series(event1, release=release)
  640. if event2:
  641. create_sample_time_series(event2, release=release)
  642. if event3:
  643. create_sample_time_series(event3)
  644. if event4:
  645. create_sample_time_series(event4, release=release)
  646. if event5:
  647. create_sample_time_series(event5, release=release)
  648. if hasattr(buffer, "process_pending"):
  649. print(" > Processing pending buffers") # NOQA
  650. buffer.process_pending()
  651. mocks_loaded.send(project=project, sender=__name__)
  652. OrganizationAccessRequest.objects.create_or_update(member=dummy_member, team=team)
  653. create_mock_transactions(project_map, load_trends, load_performance_issues, slow)
  654. Activity.objects.create(
  655. type=ActivityType.RELEASE.value,
  656. project=project,
  657. ident="4f38b65c62c4565aa94bba391ff8946922a8eed4",
  658. user_id=user.id,
  659. data={"version": "4f38b65c62c4565aa94bba391ff8946922a8eed4"},
  660. )
  661. create_system_time_series()
  662. def create_mock_transactions(
  663. project_map, load_trends=False, load_performance_issues=False, slow=False
  664. ):
  665. backend_project = project_map["Earth"]
  666. frontend_project = project_map["Fire"]
  667. service_projects = [
  668. project_map["Wind"],
  669. project_map["Water"],
  670. project_map["Heart"],
  671. ]
  672. for project in project_map.values():
  673. if not project.flags.has_transactions:
  674. project.update(flags=F("flags").bitor(Project.flags.has_transactions))
  675. timestamp = timezone.now()
  676. print(f" > Loading a trace") # NOQA
  677. create_trace(
  678. slow,
  679. timestamp - timedelta(milliseconds=random_normal(4000, 250, 1000)),
  680. timestamp,
  681. generate_user(),
  682. uuid4().hex,
  683. None,
  684. {
  685. "project": frontend_project,
  686. "transaction": "/plants/:plantId/",
  687. "frontend": True,
  688. "errors": 1,
  689. "children": [
  690. {
  691. "project": backend_project,
  692. "transaction": "/api/plants/",
  693. "children": [
  694. {
  695. "project": service_projects[0],
  696. "transaction": "/products/all/",
  697. "children": [],
  698. },
  699. {
  700. "project": service_projects[1],
  701. "transaction": "/analytics/",
  702. "children": [],
  703. },
  704. {
  705. "project": service_projects[2],
  706. "transaction": "tasks.create_invoice",
  707. "children": [
  708. {
  709. "project": service_projects[2],
  710. "transaction": "tasks.process_invoice",
  711. "children": [
  712. {
  713. "project": service_projects[2],
  714. "transaction": "tasks.process_invoice",
  715. "children": [
  716. {
  717. "project": service_projects[2],
  718. "transaction": "tasks.process_invoice",
  719. "children": [
  720. {
  721. "project": service_projects[2],
  722. "transaction": "tasks.process_invoice",
  723. "children": [],
  724. },
  725. ],
  726. },
  727. ],
  728. },
  729. ],
  730. },
  731. ],
  732. },
  733. ],
  734. },
  735. ],
  736. },
  737. )
  738. if load_trends:
  739. print(f" > Loading trends data") # NOQA
  740. for day in range(14):
  741. for hour in range(24):
  742. timestamp = timezone.now() - timedelta(days=day, hours=hour)
  743. transaction_user = generate_user()
  744. trace_id = uuid4().hex
  745. frontend_span_id = uuid4().hex[:16]
  746. frontend_root_span_id = uuid4().hex[:16]
  747. frontend_duration = random_normal(2000 - 50 * day, 250, 1000)
  748. create_sample_event(
  749. project=frontend_project,
  750. platform="javascript-transaction",
  751. transaction="/trends/:frontend/",
  752. event_id=uuid4().hex,
  753. user=transaction_user,
  754. timestamp=timestamp,
  755. # start_timestamp decreases based on day so that there's a trend
  756. start_timestamp=timestamp - timedelta(milliseconds=frontend_duration),
  757. measurements={
  758. "fp": {"value": random_normal(1250 - 50 * day, 200, 500)},
  759. "fcp": {"value": random_normal(1250 - 50 * day, 200, 500)},
  760. "lcp": {"value": random_normal(2800 - 50 * day, 400, 2000)},
  761. "fid": {"value": random_normal(5 - 0.125 * day, 2, 1)},
  762. },
  763. # Root
  764. parent_span_id=None,
  765. span_id=frontend_root_span_id,
  766. trace=trace_id,
  767. spans=[
  768. {
  769. "same_process_as_parent": True,
  770. "op": "http",
  771. "description": "GET /api/plants/?all_plants=1",
  772. "data": {
  773. "duration": random_normal(
  774. 1 - 0.05 * day, 0.25, 0.01, frontend_duration / 1000
  775. ),
  776. "offset": 0.02,
  777. },
  778. "span_id": frontend_span_id,
  779. "trace_id": trace_id,
  780. }
  781. ],
  782. )
  783. # try to give clickhouse some breathing room
  784. if slow:
  785. time.sleep(0.05)
  786. backend_duration = random_normal(1500 + 50 * day, 250, 500)
  787. create_sample_event(
  788. project=backend_project,
  789. platform="transaction",
  790. transaction="/trends/backend/",
  791. event_id=uuid4().hex,
  792. user=transaction_user,
  793. timestamp=timestamp,
  794. start_timestamp=timestamp - timedelta(milliseconds=backend_duration),
  795. # match the trace from the javascript transaction
  796. trace=trace_id,
  797. parent_span_id=frontend_root_span_id,
  798. spans=[],
  799. )
  800. # try to give clickhouse some breathing room
  801. if slow:
  802. time.sleep(0.05)
  803. if load_performance_issues:
  804. def load_n_plus_one_issue():
  805. trace_id = uuid4().hex
  806. transaction_user = generate_user()
  807. frontend_root_span_id = uuid4().hex[:16]
  808. n_plus_one_db_current_offset = timestamp
  809. n_plus_one_db_duration = timedelta(milliseconds=100)
  810. parent_span_id = uuid4().hex[:16]
  811. source_span = {
  812. "timestamp": (timestamp + n_plus_one_db_duration).timestamp(),
  813. "start_timestamp": (timestamp + timedelta(milliseconds=10)).timestamp(),
  814. "description": "SELECT `books_book`.`id`, `books_book`.`title`, `books_book`.`author_id` FROM `books_book` ORDER BY `books_book`.`id` DESC LIMIT 10",
  815. "op": "db",
  816. "parent_span_id": parent_span_id,
  817. "span_id": uuid4().hex[:16],
  818. "hash": "858fea692d4d93e8",
  819. }
  820. def make_repeating_span(duration):
  821. nonlocal timestamp
  822. nonlocal n_plus_one_db_current_offset
  823. nonlocal n_plus_one_db_duration
  824. n_plus_one_db_duration += timedelta(milliseconds=duration) + timedelta(
  825. milliseconds=1
  826. )
  827. n_plus_one_db_current_offset = timestamp + n_plus_one_db_duration
  828. return {
  829. "timestamp": (
  830. n_plus_one_db_current_offset + timedelta(milliseconds=duration)
  831. ).timestamp(),
  832. "start_timestamp": (
  833. n_plus_one_db_current_offset + timedelta(milliseconds=1)
  834. ).timestamp(),
  835. "description": "SELECT `books_author`.`id`, `books_author`.`name` FROM `books_author` WHERE `books_author`.`id` = %s LIMIT 21",
  836. "op": "db",
  837. "span_id": uuid4().hex[:16],
  838. "parent_span_id": parent_span_id,
  839. "hash": "63f1e89e6a073441",
  840. }
  841. repeating_spans = [make_repeating_span(200) for _ in range(10)]
  842. parent_span = {
  843. "timestamp": (
  844. timestamp + n_plus_one_db_duration + timedelta(milliseconds=200)
  845. ).timestamp(),
  846. "start_timestamp": timestamp.timestamp(),
  847. "description": "new",
  848. "op": "django.view",
  849. "parent_span_id": uuid4().hex[:16],
  850. "span_id": parent_span_id,
  851. "hash": "0f43fb6f6e01ca52",
  852. }
  853. create_sample_event(
  854. project=backend_project,
  855. platform="transaction",
  856. transaction="/n_plus_one_db/backend/",
  857. event_id=uuid4().hex,
  858. user=transaction_user,
  859. timestamp=timestamp + n_plus_one_db_duration + timedelta(milliseconds=300),
  860. start_timestamp=timestamp,
  861. trace=trace_id,
  862. parent_span_id=frontend_root_span_id,
  863. spans=[
  864. parent_span,
  865. source_span,
  866. ]
  867. + repeating_spans,
  868. )
  869. time.sleep(1.0)
  870. create_sample_event(
  871. project=backend_project,
  872. platform="transaction",
  873. transaction="/file-io-main-thread/",
  874. event_id=uuid4().hex,
  875. user=transaction_user,
  876. timestamp=timestamp + timedelta(milliseconds=300),
  877. start_timestamp=timestamp,
  878. trace=trace_id,
  879. parent_span_id=frontend_root_span_id,
  880. spans=[
  881. parent_span,
  882. {
  883. "timestamp": (timestamp + timedelta(milliseconds=200)).timestamp(),
  884. "start_timestamp": timestamp.timestamp(),
  885. "description": "1669031858711_file.txt (4.0 kB)",
  886. "op": "file.write",
  887. "span_id": uuid4().hex[:16],
  888. "parent_span_id": parent_span_id,
  889. "status": "ok",
  890. "data": {
  891. "blocked_ui_thread": True,
  892. "call_stack": [
  893. {
  894. "function": "onClick",
  895. "in_app": True,
  896. "lineno": 2,
  897. "module": "io.sentry.samples.android.MainActivity$$ExternalSyntheticLambda6",
  898. "native": False,
  899. },
  900. {
  901. "filename": "MainActivity.java",
  902. "function": "lambda$onCreate$5$io-sentry-samples-android-MainActivity",
  903. "in_app": True,
  904. "lineno": 93,
  905. "module": "io.sentry.samples.android.MainActivity",
  906. "native": False,
  907. },
  908. ],
  909. "file.path": "/data/user/0/io.sentry.samples.android/files/1669031858711_file.txt",
  910. "file.size": 4010,
  911. },
  912. },
  913. ],
  914. )
  915. def load_uncompressed_asset_issue():
  916. time.sleep(1.0)
  917. transaction_user = generate_user()
  918. trace_id = uuid4().hex
  919. parent_span_id = uuid4().hex[:16]
  920. parent_span = {
  921. "timestamp": (timestamp + timedelta(milliseconds=300)).timestamp(),
  922. "start_timestamp": timestamp.timestamp(),
  923. "description": "new",
  924. "op": "pageload",
  925. "parent_span_id": uuid4().hex[:16],
  926. "span_id": parent_span_id,
  927. "hash": "0f43fb6f6e01ca52",
  928. }
  929. spans = [
  930. {
  931. "timestamp": (timestamp + timedelta(milliseconds=1000)).timestamp(),
  932. "start_timestamp": (timestamp + timedelta(milliseconds=300)).timestamp(),
  933. "description": "https://s1.sentry-cdn.com/_static/dist/sentry/entrypoints/app.js",
  934. "op": "resource.script",
  935. "parent_span_id": parent_span_id,
  936. "span_id": uuid4().hex[:16],
  937. "hash": "858fea692d4d93e9",
  938. "data": {
  939. "http.transfer_size": 1_000_000,
  940. "http.response_content_length": 1_000_000,
  941. "http.decoded_response_content_length": 1_000_000,
  942. },
  943. },
  944. ]
  945. create_sample_event(
  946. project=backend_project,
  947. platform="transaction",
  948. transaction="/uncompressed-asset/",
  949. event_id=uuid4().hex,
  950. user=transaction_user,
  951. timestamp=timestamp + timedelta(milliseconds=300),
  952. start_timestamp=timestamp,
  953. trace=trace_id,
  954. parent_span_id=parent_span_id,
  955. spans=[parent_span] + spans,
  956. )
  957. def load_consecutive_db_issue():
  958. time.sleep(1.0)
  959. transaction_user = generate_user()
  960. trace_id = uuid4().hex
  961. parent_span_id = uuid4().hex[:16]
  962. parent_span = {
  963. "timestamp": (timestamp + timedelta(milliseconds=300)).timestamp(),
  964. "start_timestamp": timestamp.timestamp(),
  965. "description": "new",
  966. "op": "django.view",
  967. "parent_span_id": uuid4().hex[:16],
  968. "span_id": parent_span_id,
  969. "hash": "0f43fb6f6e01ca52",
  970. }
  971. spans = [
  972. {
  973. "timestamp": (timestamp + timedelta(milliseconds=1000)).timestamp(),
  974. "start_timestamp": (timestamp + timedelta(milliseconds=300)).timestamp(),
  975. "description": "SELECT `customer`.`id` FROM `customers` WHERE `customer`.`name` = 'customerName'",
  976. "op": "db",
  977. "parent_span_id": parent_span_id,
  978. "span_id": uuid4().hex[:16],
  979. "hash": "858fea692d4d93e9",
  980. },
  981. {
  982. "timestamp": (timestamp + timedelta(milliseconds=2000)).timestamp(),
  983. "start_timestamp": (timestamp + timedelta(milliseconds=1000)).timestamp(),
  984. "description": "SELECT COUNT(*) FROM `customers`",
  985. "op": "db",
  986. "parent_span_id": parent_span_id,
  987. "span_id": uuid4().hex[:16],
  988. "hash": "858fea692d4d93e7",
  989. },
  990. {
  991. "timestamp": (timestamp + timedelta(milliseconds=3000)).timestamp(),
  992. "start_timestamp": (timestamp + timedelta(milliseconds=2000)).timestamp(),
  993. "description": "SELECT COUNT(*) FROM `items`",
  994. "op": "db",
  995. "parent_span_id": parent_span_id,
  996. "span_id": uuid4().hex[:16],
  997. "hash": "858fea692d4d93e6",
  998. },
  999. ]
  1000. create_sample_event(
  1001. project=backend_project,
  1002. platform="transaction",
  1003. transaction="/consecutive-db/",
  1004. event_id=uuid4().hex,
  1005. user=transaction_user,
  1006. timestamp=timestamp + timedelta(milliseconds=300),
  1007. start_timestamp=timestamp,
  1008. trace=trace_id,
  1009. parent_span_id=parent_span_id,
  1010. spans=[parent_span] + spans,
  1011. )
  1012. def load_render_blocking_asset_issue():
  1013. transaction_user = generate_user()
  1014. trace_id = uuid4().hex
  1015. parent_span_id = uuid4().hex[:16]
  1016. spans = [
  1017. {
  1018. "timestamp": (timestamp + timedelta(milliseconds=1300)).timestamp(),
  1019. "start_timestamp": (timestamp + timedelta(milliseconds=300)).timestamp(),
  1020. "description": "https://example.com/asset.js",
  1021. "op": "resource.script",
  1022. "parent_span_id": parent_span_id,
  1023. "span_id": uuid4().hex[:16],
  1024. "hash": "858fea692d4d93e8",
  1025. "data": {"http.response_content_length": 1000001},
  1026. }
  1027. ]
  1028. create_sample_event(
  1029. project=frontend_project,
  1030. platform="transaction",
  1031. transaction="/render-blocking-asset/",
  1032. event_id=uuid4().hex,
  1033. user=transaction_user,
  1034. timestamp=timestamp + timedelta(milliseconds=300),
  1035. start_timestamp=timestamp,
  1036. trace=trace_id,
  1037. parent_span_id=parent_span_id,
  1038. spans=spans,
  1039. measurements={
  1040. "fcp": {"value": 2500.0},
  1041. },
  1042. )
  1043. def load_m_n_plus_one_issue():
  1044. trace_id = uuid4().hex
  1045. transaction_user = generate_user()
  1046. parent_span_id = uuid4().hex[:16]
  1047. duration = 200
  1048. def make_repeating_span(i):
  1049. nonlocal timestamp
  1050. nonlocal duration
  1051. start_timestamp = timestamp + timedelta(milliseconds=i * (duration + 1))
  1052. end_timestamp = start_timestamp + timedelta(milliseconds=duration)
  1053. op = "http" if i % 2 == 0 else "db"
  1054. description = "GET /" if i % 2 == 0 else "SELECT * FROM authors WHERE id = %s"
  1055. hash = "63f1e89e6a073441" if i % 2 == 0 else "a109ff3ef40f7fb3"
  1056. return {
  1057. "timestamp": end_timestamp.timestamp(),
  1058. "start_timestamp": start_timestamp.timestamp(),
  1059. "description": description,
  1060. "op": op,
  1061. "span_id": uuid4().hex[:16],
  1062. "parent_span_id": parent_span_id,
  1063. "hash": hash,
  1064. }
  1065. span_count = 10
  1066. repeating_spans = [make_repeating_span(i) for i in range(span_count)]
  1067. parent_span = {
  1068. "timestamp": (
  1069. timestamp + timedelta(milliseconds=span_count * (duration + 1))
  1070. ).timestamp(),
  1071. "start_timestamp": timestamp.timestamp(),
  1072. "description": "execute",
  1073. "op": "graphql.execute",
  1074. "parent_span_id": uuid4().hex[:16],
  1075. "span_id": parent_span_id,
  1076. "hash": "0f43fb6f6e01ca52",
  1077. }
  1078. create_sample_event(
  1079. project=backend_project,
  1080. platform="transaction",
  1081. transaction="/m_n_plus_one_db/backend/",
  1082. event_id=uuid4().hex,
  1083. user=transaction_user,
  1084. timestamp=timestamp + timedelta(milliseconds=span_count * (duration + 1) + 100),
  1085. start_timestamp=timestamp,
  1086. trace=trace_id,
  1087. spans=[parent_span] + repeating_spans,
  1088. )
  1089. def load_performance_issues():
  1090. print(f" > Loading performance issues data") # NOQA
  1091. print(f" > Loading n plus one issue") # NOQA
  1092. load_n_plus_one_issue()
  1093. print(f" > Loading consecutive db issue") # NOQA
  1094. load_consecutive_db_issue()
  1095. print(f" > Loading uncompressed asset issue") # NOQA
  1096. load_uncompressed_asset_issue()
  1097. print(f" > Loading render blocking asset issue") # NOQA
  1098. load_render_blocking_asset_issue()
  1099. print(f" > Loading MN+1 issue") # NOQA
  1100. load_m_n_plus_one_issue()
  1101. load_performance_issues()
  1102. if __name__ == "__main__":
  1103. settings.CELERY_ALWAYS_EAGER = True
  1104. from optparse import OptionParser
  1105. parser = OptionParser()
  1106. parser.add_option("--events", default=1, type=int, help="number of events to generate")
  1107. parser.add_option(
  1108. "--skip-default-setup",
  1109. default=False,
  1110. action="store_true",
  1111. help="Skips creating the default project, teams and timeseries, useful when only loading specific transactions",
  1112. )
  1113. parser.add_option(
  1114. "--extra-events",
  1115. default=False,
  1116. action="store_true",
  1117. help="add multiple events for each error group",
  1118. )
  1119. parser.add_option(
  1120. "--load-trends",
  1121. default=False,
  1122. action="store_true",
  1123. help="load multiple transactions for each id to show trends",
  1124. )
  1125. parser.add_option(
  1126. "--load-performance-issues",
  1127. default=False,
  1128. action="store_true",
  1129. help="load transactions with performance issues, still needs options/flags on for issues to appear.",
  1130. )
  1131. parser.add_option(
  1132. "--slow",
  1133. default=False,
  1134. action="store_true",
  1135. help="sleep between each transaction to let clickhouse rest",
  1136. )
  1137. (options, args) = parser.parse_args()
  1138. try:
  1139. main(
  1140. skip_default_setup=options.skip_default_setup,
  1141. num_events=options.events,
  1142. extra_events=options.extra_events,
  1143. load_trends=options.load_trends,
  1144. load_performance_issues=options.load_performance_issues,
  1145. slow=options.slow,
  1146. )
  1147. from sentry.issues.producer import get_occurrence_producer
  1148. get_occurrence_producer().close()
  1149. except Exception:
  1150. # Avoid reporting any issues recursively back into Sentry
  1151. import sys
  1152. import traceback
  1153. traceback.print_exc()
  1154. sys.exit(1)