load-mocks 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. #!/usr/bin/env python
  2. from sentry.runner import configure
  3. configure()
  4. import itertools
  5. import six
  6. from datetime import datetime, timedelta
  7. from django.conf import settings
  8. from django.db import IntegrityError, transaction
  9. from django.utils import timezone
  10. from hashlib import sha1
  11. from pytz import utc
  12. from random import randint
  13. from uuid import uuid4
  14. from sentry import roles
  15. from sentry.app import tsdb, buffer
  16. from sentry.models import (
  17. Activity, Broadcast, File, GroupMeta, Organization, OrganizationAccessRequest,
  18. OrganizationMember, Project, Release, ReleaseFile, Team, User, UserReport,
  19. GroupRelease, Environment, ReleaseEnvironment, ReleaseCommit, Commit, Repository,
  20. CommitAuthor, CommitFileChange,
  21. )
  22. from sentry.signals import mocks_loaded
  23. from sentry.utils.hashlib import md5_text
  24. from sentry.utils.samples import create_sample_event
  25. PLATFORMS = itertools.cycle([
  26. 'ruby',
  27. 'php',
  28. 'python',
  29. 'java',
  30. 'javascript',
  31. ])
  32. LEVELS = itertools.cycle([
  33. 'error',
  34. 'error',
  35. 'error',
  36. 'fatal',
  37. 'warning',
  38. ])
  39. ENVIRONMENTS = itertools.cycle([
  40. 'production',
  41. 'production',
  42. 'staging',
  43. 'alpha',
  44. 'beta',
  45. ])
  46. def create_system_time_series():
  47. now = datetime.utcnow().replace(tzinfo=utc)
  48. for _ in xrange(60):
  49. count = randint(1, 10)
  50. tsdb.incr_multi((
  51. (tsdb.models.internal, 'client-api.all-versions.responses.2xx'),
  52. (tsdb.models.internal, 'client-api.all-versions.requests'),
  53. ), now, int(count * 0.9))
  54. tsdb.incr_multi((
  55. (tsdb.models.internal, 'client-api.all-versions.responses.4xx'),
  56. ), now, int(count * 0.05))
  57. tsdb.incr_multi((
  58. (tsdb.models.internal, 'client-api.all-versions.responses.5xx'),
  59. ), now, int(count * 0.1))
  60. now = now - timedelta(seconds=1)
  61. for _ in xrange(24 * 30):
  62. count = randint(100, 1000)
  63. tsdb.incr_multi((
  64. (tsdb.models.internal, 'client-api.all-versions.responses.2xx'),
  65. (tsdb.models.internal, 'client-api.all-versions.requests'),
  66. ), now, int(count * 4.9))
  67. tsdb.incr_multi((
  68. (tsdb.models.internal, 'client-api.all-versions.responses.4xx'),
  69. ), now, int(count * 0.05))
  70. tsdb.incr_multi((
  71. (tsdb.models.internal, 'client-api.all-versions.responses.5xx'),
  72. ), now, int(count * 0.1))
  73. now = now - timedelta(hours=1)
  74. def create_sample_time_series(event, release=None):
  75. group = event.group
  76. project = group.project
  77. now = datetime.utcnow().replace(tzinfo=utc)
  78. environment = Environment.get_or_create(
  79. project=project,
  80. name=event.get_tag('environment') or ''
  81. )
  82. if release:
  83. ReleaseEnvironment.get_or_create(
  84. project=project,
  85. release=release,
  86. environment=environment,
  87. datetime=now,
  88. )
  89. grouprelease = GroupRelease.get_or_create(
  90. group=group,
  91. release=release,
  92. environment=environment,
  93. datetime=now,
  94. )
  95. for _ in xrange(60):
  96. count = randint(1, 10)
  97. tsdb.incr_multi((
  98. (tsdb.models.project, project.id),
  99. (tsdb.models.group, group.id),
  100. ), now, count)
  101. tsdb.incr_multi((
  102. (tsdb.models.organization_total_received, project.organization_id),
  103. (tsdb.models.project_total_received, project.id),
  104. ), now, int(count * 1.1))
  105. tsdb.incr_multi((
  106. (tsdb.models.organization_total_rejected, project.organization_id),
  107. (tsdb.models.project_total_rejected, project.id),
  108. ), now, int(count * 0.1))
  109. frequencies = [
  110. (tsdb.models.frequent_projects_by_organization, {
  111. project.organization_id: {
  112. project.id: count,
  113. },
  114. }),
  115. (tsdb.models.frequent_issues_by_project, {
  116. project.id: {
  117. group.id: count,
  118. },
  119. }),
  120. (tsdb.models.frequent_environments_by_group, {
  121. group.id: {
  122. environment.id: count,
  123. },
  124. })
  125. ]
  126. if release:
  127. frequencies.append(
  128. (tsdb.models.frequent_releases_by_group, {
  129. group.id: {
  130. grouprelease.id: count,
  131. },
  132. })
  133. )
  134. tsdb.record_frequency_multi(frequencies, now)
  135. now = now - timedelta(seconds=1)
  136. for _ in xrange(24 * 30):
  137. count = randint(100, 1000)
  138. tsdb.incr_multi((
  139. (tsdb.models.project, group.project.id),
  140. (tsdb.models.group, group.id),
  141. ), now, count)
  142. tsdb.incr_multi((
  143. (tsdb.models.organization_total_received, group.project.organization_id),
  144. (tsdb.models.project_total_received, group.project.id),
  145. ), now, int(count * 1.1))
  146. tsdb.incr_multi((
  147. (tsdb.models.organization_total_rejected, group.project.organization_id),
  148. (tsdb.models.project_total_rejected, group.project.id),
  149. ), now, int(count * 0.1))
  150. frequencies = [
  151. (tsdb.models.frequent_projects_by_organization, {
  152. project.organization_id: {
  153. project.id: count,
  154. },
  155. }),
  156. (tsdb.models.frequent_issues_by_project, {
  157. project.id: {
  158. group.id: count,
  159. },
  160. }),
  161. (tsdb.models.frequent_environments_by_group, {
  162. group.id: {
  163. environment.id: count,
  164. },
  165. })
  166. ]
  167. if release:
  168. frequencies.append(
  169. (tsdb.models.frequent_releases_by_group, {
  170. group.id: {
  171. grouprelease.id: count,
  172. },
  173. })
  174. )
  175. tsdb.record_frequency_multi(frequencies, now)
  176. now = now - timedelta(hours=1)
  177. def main(num_events=1):
  178. user = User.objects.filter(is_superuser=True)[0]
  179. dummy_user, _ = User.objects.get_or_create(
  180. username='dummy@example.com',
  181. defaults={
  182. 'email': 'dummy@example.com',
  183. }
  184. )
  185. dummy_user.set_password('dummy')
  186. dummy_user.save()
  187. mocks = (
  188. ('Massive Dynamic', ('Ludic Science',)),
  189. ('Captain Planet', ('Earth', 'Fire', 'Wind', 'Water', 'Heart')),
  190. )
  191. Broadcast.objects.create(
  192. title="Learn about Source Maps",
  193. message="Source maps are JSON files that contain information on how to map your transpiled source code back to their original source.",
  194. link="https://docs.sentry.io/hosted/clients/javascript/sourcemaps/#uploading-source-maps-to-sentry",
  195. )
  196. if settings.SENTRY_SINGLE_ORGANIZATION:
  197. org = Organization.get_default()
  198. else:
  199. print('Mocking org {}'.format('Default'))
  200. org, _ = Organization.objects.get_or_create(
  201. slug='default',
  202. )
  203. OrganizationMember.objects.get_or_create(
  204. user=user,
  205. organization=org,
  206. role=roles.get_top_dog().id,
  207. )
  208. dummy_member, _ = OrganizationMember.objects.get_or_create(
  209. user=dummy_user,
  210. organization=org,
  211. defaults={
  212. 'role': roles.get_default().id,
  213. }
  214. )
  215. for team_name, project_names in mocks:
  216. print('> Mocking team {}'.format(team_name))
  217. team, _ = Team.objects.get_or_create(
  218. name=team_name,
  219. defaults={
  220. 'organization': org,
  221. },
  222. )
  223. for project_name in project_names:
  224. print(' > Mocking project {}'.format(project_name))
  225. project, _ = Project.objects.get_or_create(
  226. team=team,
  227. name=project_name,
  228. defaults={
  229. 'organization': org,
  230. 'first_event': timezone.now(),
  231. }
  232. )
  233. if not project.first_event:
  234. project.update(
  235. first_event=project.date_added,
  236. )
  237. with transaction.atomic():
  238. has_release = Release.objects.filter(
  239. version=sha1(uuid4().bytes).hexdigest(),
  240. organization_id=project.organization_id,
  241. projects=project
  242. ).exists()
  243. if not has_release:
  244. release = Release.objects.filter(
  245. version=sha1(uuid4().bytes).hexdigest(),
  246. organization_id=project.organization_id,
  247. ).first()
  248. if not release:
  249. release = Release.objects.create(
  250. version=sha1(uuid4().bytes).hexdigest(),
  251. organization_id=project.organization_id
  252. )
  253. release.add_project(project)
  254. ReleaseFile.objects.get_or_create(
  255. organization_id=project.organization_id,
  256. release=release,
  257. name='an-example.js',
  258. file=File.objects.get_or_create(
  259. name='an-example.js',
  260. type='release.file',
  261. checksum='abcde' * 8,
  262. size=13043,
  263. )[0],
  264. defaults={'organization_id': project.organization_id}
  265. )
  266. raw_commits = [
  267. {
  268. 'key': '6fb7672bee9c469a8aa074f52ed72eddc939ae7d',
  269. 'message': 'Fix widget for real this time\n\nTurns out the sprocket configuration was broken.',
  270. 'author': (user.name, user.email),
  271. 'files': [
  272. ('/static/js/widget.js', 'M'),
  273. ],
  274. },
  275. {
  276. 'key': '98a0672968c19e3d7921def5d724cc977e85f527',
  277. 'message': 'Added .gitignore',
  278. 'author': ('Jane Doe', 'janedoe@example.com'),
  279. 'files': [
  280. ('.gitignore', 'A'),
  281. ('.DS_Store', 'D')
  282. ],
  283. },
  284. {
  285. 'key': '631cd9096bd9811a046a472bb0aa8b573e86e1f1',
  286. 'message': 'Fix widget',
  287. 'author': (user.name, user.email),
  288. 'files': [
  289. ('/static/html/widget.html', 'M'),
  290. ('/static/js/widget.js', 'M'),
  291. ('.DS_Store', 'A'),
  292. ],
  293. },
  294. ]
  295. for commit_index, raw_commit in enumerate(raw_commits):
  296. commit = Commit.objects.get_or_create(
  297. organization_id=org.id,
  298. repository_id=Repository.objects.get_or_create(
  299. organization_id=org.id,
  300. name='Example Repo',
  301. provider='github',
  302. external_id='example/example',
  303. )[0].id,
  304. key=raw_commit['key'],
  305. author=CommitAuthor.objects.get_or_create(
  306. organization_id=org.id,
  307. name=raw_commit['author'][0],
  308. email=raw_commit['author'][1],
  309. )[0],
  310. message=raw_commit['message'],
  311. )[0]
  312. for file in raw_commit['files']:
  313. CommitFileChange.objects.get_or_create(
  314. organization_id=org.id,
  315. commit=commit,
  316. filename=file[0],
  317. type=file[1],
  318. )
  319. ReleaseCommit.objects.get_or_create(
  320. organization_id=org.id,
  321. release=release,
  322. commit=commit,
  323. order=commit_index,
  324. )
  325. Activity.objects.create(
  326. type=Activity.RELEASE,
  327. project=project,
  328. ident=release.version,
  329. user=user,
  330. data={'version': release.version},
  331. )
  332. # Add a bunch of additional dummy events to support pagination
  333. last_event = None
  334. for _ in range(45):
  335. platform = PLATFORMS.next()
  336. last_event = create_sample_event(
  337. project=project,
  338. platform=platform,
  339. release=release.version,
  340. level=LEVELS.next(),
  341. environment=ENVIRONMENTS.next(),
  342. message='This is a mostly useless example %s exception' % platform,
  343. checksum=md5_text(platform + six.text_type(_)).hexdigest(),
  344. )
  345. for _ in range(num_events):
  346. event1 = create_sample_event(
  347. project=project,
  348. platform='python',
  349. release=release.version,
  350. environment=ENVIRONMENTS.next(),
  351. )
  352. event2 = create_sample_event(
  353. project=project,
  354. platform='javascript',
  355. release=release.version,
  356. environment=ENVIRONMENTS.next(),
  357. sdk={
  358. 'name': 'raven-js',
  359. 'version': '2.1.0',
  360. },
  361. )
  362. event3 = create_sample_event(project, 'java')
  363. event4 = create_sample_event(
  364. project=project,
  365. platform='ruby',
  366. release=release.version,
  367. environment=ENVIRONMENTS.next(),
  368. )
  369. event5 = create_sample_event(
  370. project=project,
  371. platform='cocoa',
  372. release=release.version,
  373. environment=ENVIRONMENTS.next(),
  374. )
  375. create_sample_event(
  376. project=project,
  377. platform='php',
  378. release=release.version,
  379. environment=ENVIRONMENTS.next(),
  380. message='This is a an example PHP event with an extremely long and annoying title\nIt also happens to contain some newlines in it,\nthus making it even more annoying.',
  381. )
  382. create_sample_event(
  383. project=project,
  384. environment=ENVIRONMENTS.next(),
  385. platform='csp',
  386. )
  387. with transaction.atomic():
  388. try:
  389. GroupMeta.objects.create(
  390. group=event1.group,
  391. key='github:tid',
  392. value='134',
  393. )
  394. except IntegrityError:
  395. pass
  396. UserReport.objects.create(
  397. project=project,
  398. event_id=event3.event_id,
  399. group=event3.group,
  400. name='Jane Doe',
  401. email='jane@example.com',
  402. comments='I have no idea how I got here.',
  403. )
  404. print(' > Loading time series data'.format(project_name))
  405. create_sample_time_series(event1, release=release)
  406. create_sample_time_series(event2, release=release)
  407. create_sample_time_series(event3)
  408. create_sample_time_series(event4, release=release)
  409. create_sample_time_series(event5, release=release)
  410. if hasattr(buffer, 'process_pending'):
  411. print(' > Processing pending buffers')
  412. buffer.process_pending()
  413. mocks_loaded.send(project=project, sender=__name__)
  414. OrganizationAccessRequest.objects.create_or_update(
  415. member=dummy_member,
  416. team=team,
  417. )
  418. Activity.objects.create(
  419. type=Activity.RELEASE,
  420. project=project,
  421. ident='4f38b65c62c4565aa94bba391ff8946922a8eed4',
  422. user=user,
  423. data={'version': '4f38b65c62c4565aa94bba391ff8946922a8eed4'},
  424. )
  425. create_system_time_series()
  426. if __name__ == '__main__':
  427. settings.CELERY_ALWAYS_EAGER = True
  428. from optparse import OptionParser
  429. parser = OptionParser()
  430. parser.add_option('--events', dest='num_events', default=1, type=int)
  431. (options, args) = parser.parse_args()
  432. try:
  433. main(num_events=options.num_events)
  434. except Exception:
  435. # Avoid reporting any issues recursively back into Sentry
  436. import traceback
  437. import sys
  438. traceback.print_exc()
  439. sys.exit(1)