bugsink 0.1.12__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (376) hide show
  1. bugsink-0.1.12/.github/workflows/ci.yml +79 -0
  2. bugsink-0.1.12/.gitignore +51 -0
  3. bugsink-0.1.12/DESIGN-alerts.md +77 -0
  4. bugsink-0.1.12/DESIGN-breadcrumbs.md +5 -0
  5. bugsink-0.1.12/DESIGN-connections.md +76 -0
  6. bugsink-0.1.12/DESIGN-log-messages.md +6 -0
  7. bugsink-0.1.12/DESIGN-orgs-teams.md +18 -0
  8. bugsink-0.1.12/DESIGN-performance.md +76 -0
  9. bugsink-0.1.12/DESIGN-process-model.md +52 -0
  10. bugsink-0.1.12/DESIGN.md +86 -0
  11. bugsink-0.1.12/Dockerfile +37 -0
  12. bugsink-0.1.12/Dockerfile.db +7 -0
  13. bugsink-0.1.12/LICENSE +47 -0
  14. bugsink-0.1.12/PKG-INFO +84 -0
  15. bugsink-0.1.12/README.md +9 -0
  16. bugsink-0.1.12/alerts/__init__.py +0 -0
  17. bugsink-0.1.12/alerts/admin.py +1 -0
  18. bugsink-0.1.12/alerts/apps.py +6 -0
  19. bugsink-0.1.12/alerts/migrations/__init__.py +0 -0
  20. bugsink-0.1.12/alerts/models.py +1 -0
  21. bugsink-0.1.12/alerts/tasks.py +86 -0
  22. bugsink-0.1.12/alerts/templates/mails/issue_alert.html +527 -0
  23. bugsink-0.1.12/alerts/templates/mails/issue_alert.txt +12 -0
  24. bugsink-0.1.12/alerts/tests.py +134 -0
  25. bugsink-0.1.12/alerts/views.py +19 -0
  26. bugsink-0.1.12/api/LICENSE +10 -0
  27. bugsink-0.1.12/api/README.md +51 -0
  28. bugsink-0.1.12/api/event.schema.json +4321 -0
  29. bugsink-0.1.12/assets/04d16c3eff614748b759d4c52fa92aff5eb3b8c6.webp +0 -0
  30. bugsink-0.1.12/assets/0d0bedb635b44d99b9b1cca084a2ef80c6005e84.webp +0 -0
  31. bugsink-0.1.12/assets/1670e81db185490ab05bc83368b5f741.webp +0 -0
  32. bugsink-0.1.12/assets/1804883e2eba4aac82c45bf1f5ee6924c6005e82-2.webp +0 -0
  33. bugsink-0.1.12/assets/1804883e2eba4aac82c45bf1f5ee6924c6005e82.webp +0 -0
  34. bugsink-0.1.12/assets/187e9877407748bebd70be23771a1c0a9753c842.webp +0 -0
  35. bugsink-0.1.12/assets/1d37517924814e75942097098c74fe00c6005e82.webp +0 -0
  36. bugsink-0.1.12/assets/46cfd4b0046e48ca9beaefabcce233329753c844.webp +0 -0
  37. bugsink-0.1.12/assets/526c29422982427f8555d08a91e38d32c6005e83.webp +0 -0
  38. bugsink-0.1.12/assets/62e873c78f204679a9daaf911ac79e11778a75d4.webp +0 -0
  39. bugsink-0.1.12/assets/7183dec640db4b298bd518a683aaed6fc6005e83.webp +0 -0
  40. bugsink-0.1.12/assets/7c4b39bd49b549ebbdb7859e03029b33c6005e80.webp +0 -0
  41. bugsink-0.1.12/assets/93a1913577e2403da96af73a4ca1f2154501f2a0.webp +0 -0
  42. bugsink-0.1.12/assets/98ac676ef12643368442e08b5c4591ecc6005e83.webp +0 -0
  43. bugsink-0.1.12/assets/ab948b8962534410a94735bc8b90fdc19d2270f2.webp +0 -0
  44. bugsink-0.1.12/assets/b3f9a6541efc48cf982a5f3514e80bf9.webp +0 -0
  45. bugsink-0.1.12/assets/b5780a5c9d6d4851b146ff4967d53a02c6005e80.webp +0 -0
  46. bugsink-0.1.12/assets/bigbug-32x32.png +0 -0
  47. bugsink-0.1.12/assets/bigbug-64-64.png +0 -0
  48. bugsink-0.1.12/assets/blue-32x32.png +0 -0
  49. bugsink-0.1.12/assets/blue-64x64-manual-changes.png +0 -0
  50. bugsink-0.1.12/assets/blue-64x64-manual-changes.xcf +0 -0
  51. bugsink-0.1.12/assets/blue-64x64.webp +0 -0
  52. bugsink-0.1.12/assets/c4fb59360a9c4160809526e974414489.webp +0 -0
  53. bugsink-0.1.12/assets/c8aa0483abb343a6a67c89b3cd393336.webp +0 -0
  54. bugsink-0.1.12/assets/f390b92d28794a21869d473210e21d97c6005e84.webp +0 -0
  55. bugsink-0.1.12/assets/fe3212cbc7f042b9a77ad476011f669f9d2270f0.webp +0 -0
  56. bugsink-0.1.12/assets/newspaper.jpeg +0 -0
  57. bugsink-0.1.12/assets/sentry-sdk-issues/README.md +1 -0
  58. bugsink-0.1.12/assets/sentry-sdk-issues/django-templates.md +12 -0
  59. bugsink-0.1.12/assets/sites-and-prompts.txt +5 -0
  60. bugsink-0.1.12/assets/yello-64x64.png +0 -0
  61. bugsink-0.1.12/assets/yellow-32x32.png +0 -0
  62. bugsink-0.1.12/bugsink/__init__.py +26 -0
  63. bugsink-0.1.12/bugsink/_version.py +16 -0
  64. bugsink-0.1.12/bugsink/app_settings.py +106 -0
  65. bugsink-0.1.12/bugsink/conf_templates/docker.py.template +132 -0
  66. bugsink-0.1.12/bugsink/conf_templates/local.py.template +63 -0
  67. bugsink-0.1.12/bugsink/conf_templates/recommended.py.template +89 -0
  68. bugsink-0.1.12/bugsink/context_processors.py +15 -0
  69. bugsink-0.1.12/bugsink/dbrouters.py +17 -0
  70. bugsink-0.1.12/bugsink/debug_views.py +232 -0
  71. bugsink-0.1.12/bugsink/decorators.py +112 -0
  72. bugsink-0.1.12/bugsink/email_backends.py +10 -0
  73. bugsink-0.1.12/bugsink/event_schema.py +39730 -0
  74. bugsink-0.1.12/bugsink/exceptions.py +2 -0
  75. bugsink-0.1.12/bugsink/middleware.py +76 -0
  76. bugsink-0.1.12/bugsink/moreiterutils.py +36 -0
  77. bugsink-0.1.12/bugsink/period_utils.py +19 -0
  78. bugsink-0.1.12/bugsink/pygments_extensions.py +110 -0
  79. bugsink-0.1.12/bugsink/scripts/__init__.py +0 -0
  80. bugsink-0.1.12/bugsink/scripts/create_conf.py +67 -0
  81. bugsink-0.1.12/bugsink/scripts/manage.py +33 -0
  82. bugsink-0.1.12/bugsink/scripts/runsnappea.py +31 -0
  83. bugsink-0.1.12/bugsink/scripts/show_version.py +7 -0
  84. bugsink-0.1.12/bugsink/settings/__init__.py +0 -0
  85. bugsink-0.1.12/bugsink/settings/default.py +277 -0
  86. bugsink-0.1.12/bugsink/settings/development.py +158 -0
  87. bugsink-0.1.12/bugsink/streams.py +171 -0
  88. bugsink-0.1.12/bugsink/tests.py +363 -0
  89. bugsink-0.1.12/bugsink/timed_sqlite_backend/__init__.py +0 -0
  90. bugsink-0.1.12/bugsink/timed_sqlite_backend/base.py +86 -0
  91. bugsink-0.1.12/bugsink/tooling.py +12 -0
  92. bugsink-0.1.12/bugsink/transaction.py +184 -0
  93. bugsink-0.1.12/bugsink/urls.py +61 -0
  94. bugsink-0.1.12/bugsink/utils.py +33 -0
  95. bugsink-0.1.12/bugsink/version.py +8 -0
  96. bugsink-0.1.12/bugsink/views.py +83 -0
  97. bugsink-0.1.12/bugsink/volume_based_condition.py +23 -0
  98. bugsink-0.1.12/bugsink/wsgi.py +16 -0
  99. bugsink-0.1.12/bugsink.egg-info/PKG-INFO +84 -0
  100. bugsink-0.1.12/bugsink.egg-info/SOURCES.txt +374 -0
  101. bugsink-0.1.12/bugsink.egg-info/dependency_links.txt +1 -0
  102. bugsink-0.1.12/bugsink.egg-info/entry_points.txt +5 -0
  103. bugsink-0.1.12/bugsink.egg-info/requires.txt +17 -0
  104. bugsink-0.1.12/bugsink.egg-info/top_level.txt +18 -0
  105. bugsink-0.1.12/builddocker.bash +29 -0
  106. bugsink-0.1.12/buildxdocker.bash +29 -0
  107. bugsink-0.1.12/compat/__init__.py +0 -0
  108. bugsink-0.1.12/compat/auth.py +16 -0
  109. bugsink-0.1.12/compat/dsn.py +56 -0
  110. bugsink-0.1.12/compat/tests.py +102 -0
  111. bugsink-0.1.12/compat/timestamp.py +31 -0
  112. bugsink-0.1.12/compat/vars.py +27 -0
  113. bugsink-0.1.12/cornless-interrupt-sqlite.py +54 -0
  114. bugsink-0.1.12/cornless-print-other-thread.py +54 -0
  115. bugsink-0.1.12/cornless-set-progress-handler.py +66 -0
  116. bugsink-0.1.12/cornless.py +21 -0
  117. bugsink-0.1.12/events/__init__.py +0 -0
  118. bugsink-0.1.12/events/admin.py +98 -0
  119. bugsink-0.1.12/events/apps.py +20 -0
  120. bugsink-0.1.12/events/factories.py +50 -0
  121. bugsink-0.1.12/events/management/__init__.py +0 -0
  122. bugsink-0.1.12/events/management/commands/__init__.py +0 -0
  123. bugsink-0.1.12/events/management/commands/cleanup_events.py +19 -0
  124. bugsink-0.1.12/events/management/commands/make_consistent.py +41 -0
  125. bugsink-0.1.12/events/management/commands/store_events.py +24 -0
  126. bugsink-0.1.12/events/migrations/0001_initial.py +42 -0
  127. bugsink-0.1.12/events/migrations/0002_initial.py +20 -0
  128. bugsink-0.1.12/events/migrations/0003_initial.py +24 -0
  129. bugsink-0.1.12/events/migrations/0004_event_irrelevance_for_retention.py +19 -0
  130. bugsink-0.1.12/events/migrations/0005_event_events_even_project_abe572_idx.py +17 -0
  131. bugsink-0.1.12/events/migrations/0006_event_never_evict.py +18 -0
  132. bugsink-0.1.12/events/migrations/0007_set_never_evict.py +18 -0
  133. bugsink-0.1.12/events/migrations/0008_remove_event_events_even_project_abe572_idx_and_more.py +21 -0
  134. bugsink-0.1.12/events/migrations/0009_event_events_even_issue_i_90497b_idx.py +17 -0
  135. bugsink-0.1.12/events/migrations/0010_rename_ingest_order_event_digest_order_and_more.py +24 -0
  136. bugsink-0.1.12/events/migrations/0011_remove_event_events_even_project_adcdee_idx_and_more.py +34 -0
  137. bugsink-0.1.12/events/migrations/0012_event_ingested_at.py +20 -0
  138. bugsink-0.1.12/events/migrations/0013_harmonize_foogested_at.py +25 -0
  139. bugsink-0.1.12/events/migrations/__init__.py +0 -0
  140. bugsink-0.1.12/events/models.py +247 -0
  141. bugsink-0.1.12/events/retention.py +326 -0
  142. bugsink-0.1.12/events/retention_insight.py +64 -0
  143. bugsink-0.1.12/events/retention_simulator.py +183 -0
  144. bugsink-0.1.12/events/templates/events/event_stacktrace.txt +6 -0
  145. bugsink-0.1.12/events/tests.py +96 -0
  146. bugsink-0.1.12/events/ua_stuff.py +45 -0
  147. bugsink-0.1.12/events/urls.py +11 -0
  148. bugsink-0.1.12/events/views.py +27 -0
  149. bugsink-0.1.12/ingest/__init__.py +0 -0
  150. bugsink-0.1.12/ingest/admin.py +0 -0
  151. bugsink-0.1.12/ingest/apps.py +6 -0
  152. bugsink-0.1.12/ingest/event_counter.py +70 -0
  153. bugsink-0.1.12/ingest/filestore.py +10 -0
  154. bugsink-0.1.12/ingest/management/__init__.py +0 -0
  155. bugsink-0.1.12/ingest/management/commands/__init__.py +0 -0
  156. bugsink-0.1.12/ingest/management/commands/check_migrations.py +24 -0
  157. bugsink-0.1.12/ingest/management/commands/fetch_event_schema_json.py +52 -0
  158. bugsink-0.1.12/ingest/management/commands/raise_exception.py +49 -0
  159. bugsink-0.1.12/ingest/management/commands/send_json.py +157 -0
  160. bugsink-0.1.12/ingest/management/commands/showstat.py +19 -0
  161. bugsink-0.1.12/ingest/management/commands/stress_test.py +210 -0
  162. bugsink-0.1.12/ingest/migrations/0001_set_sqlite_wal.py +91 -0
  163. bugsink-0.1.12/ingest/migrations/__init__.py +0 -0
  164. bugsink-0.1.12/ingest/models.py +0 -0
  165. bugsink-0.1.12/ingest/parsers.py +190 -0
  166. bugsink-0.1.12/ingest/tasks.py +26 -0
  167. bugsink-0.1.12/ingest/tests.py +778 -0
  168. bugsink-0.1.12/ingest/urls.py +9 -0
  169. bugsink-0.1.12/ingest/views.py +548 -0
  170. bugsink-0.1.12/issues/__init__.py +0 -0
  171. bugsink-0.1.12/issues/admin.py +78 -0
  172. bugsink-0.1.12/issues/apps.py +6 -0
  173. bugsink-0.1.12/issues/factories.py +46 -0
  174. bugsink-0.1.12/issues/forms.py +29 -0
  175. bugsink-0.1.12/issues/migrations/0001_initial.py +60 -0
  176. bugsink-0.1.12/issues/migrations/0002_initial.py +53 -0
  177. bugsink-0.1.12/issues/migrations/0003_alter_turningpoint_triggering_event.py +20 -0
  178. bugsink-0.1.12/issues/migrations/0004_rename_event_count_issue_digested_event_count.py +18 -0
  179. bugsink-0.1.12/issues/migrations/0005_rename_ingest_order_issue_digest_order_and_more.py +23 -0
  180. bugsink-0.1.12/issues/migrations/0006_issue_next_unmute_check.py +18 -0
  181. bugsink-0.1.12/issues/migrations/__init__.py +0 -0
  182. bugsink-0.1.12/issues/models.py +422 -0
  183. bugsink-0.1.12/issues/regressions.py +85 -0
  184. bugsink-0.1.12/issues/templates/issues/_event_nav.html +40 -0
  185. bugsink-0.1.12/issues/templates/issues/base.html +241 -0
  186. bugsink-0.1.12/issues/templates/issues/breadcrumbs.html +63 -0
  187. bugsink-0.1.12/issues/templates/issues/event_404.html +46 -0
  188. bugsink-0.1.12/issues/templates/issues/event_details.html +206 -0
  189. bugsink-0.1.12/issues/templates/issues/event_list.html +170 -0
  190. bugsink-0.1.12/issues/templates/issues/grouping.html +13 -0
  191. bugsink-0.1.12/issues/templates/issues/history.html +173 -0
  192. bugsink-0.1.12/issues/templates/issues/issue_list.html +227 -0
  193. bugsink-0.1.12/issues/templates/issues/stacktrace.html +169 -0
  194. bugsink-0.1.12/issues/tests.py +645 -0
  195. bugsink-0.1.12/issues/urls.py +67 -0
  196. bugsink-0.1.12/issues/utils.py +148 -0
  197. bugsink-0.1.12/issues/views.py +557 -0
  198. bugsink-0.1.12/manage.py +22 -0
  199. bugsink-0.1.12/performance/__init__.py +0 -0
  200. bugsink-0.1.12/performance/bursty_data.py +66 -0
  201. bugsink-0.1.12/performance/context_managers.py +48 -0
  202. bugsink-0.1.12/performance/management/__init__.py +0 -0
  203. bugsink-0.1.12/performance/management/commands/__init__.py +0 -0
  204. bugsink-0.1.12/performance/stress-with-eviction/README.md +21 -0
  205. bugsink-0.1.12/performance/stress-with-eviction/df-day.png +0 -0
  206. bugsink-0.1.12/performance/stress-with-eviction/event_ingest_count-day.png +0 -0
  207. bugsink-0.1.12/performance/stress-with-eviction/response_time_api_avg-day.png +0 -0
  208. bugsink-0.1.12/performance/stress-with-eviction/response_time_api_max-day.png +0 -0
  209. bugsink-0.1.12/performance/stress-with-eviction/snappea_queue_size-day.png +0 -0
  210. bugsink-0.1.12/performance/stress-with-eviction/total_requests-day.png +0 -0
  211. bugsink-0.1.12/pre-commit +8 -0
  212. bugsink-0.1.12/projects/__init__.py +0 -0
  213. bugsink-0.1.12/projects/admin.py +70 -0
  214. bugsink-0.1.12/projects/apps.py +6 -0
  215. bugsink-0.1.12/projects/context_processors.py +9 -0
  216. bugsink-0.1.12/projects/forms.py +119 -0
  217. bugsink-0.1.12/projects/migrations/0001_initial.py +38 -0
  218. bugsink-0.1.12/projects/migrations/0002_initial.py +36 -0
  219. bugsink-0.1.12/projects/migrations/0003_project_retention_max_event_count.py +16 -0
  220. bugsink-0.1.12/projects/migrations/0004_project_quota_exceeded_until.py +18 -0
  221. bugsink-0.1.12/projects/migrations/0005_project_ingested_event_count.py +18 -0
  222. bugsink-0.1.12/projects/migrations/0006_initial_ingested_count_value.py +27 -0
  223. bugsink-0.1.12/projects/migrations/0007_rename_ingested_event_count_project_digested_event_count.py +20 -0
  224. bugsink-0.1.12/projects/migrations/0008_project_next_quota_check.py +18 -0
  225. bugsink-0.1.12/projects/migrations/__init__.py +0 -0
  226. bugsink-0.1.12/projects/models.py +132 -0
  227. bugsink-0.1.12/projects/tasks.py +47 -0
  228. bugsink-0.1.12/projects/templates/mails/project_membership_invite.html +519 -0
  229. bugsink-0.1.12/projects/templates/mails/project_membership_invite.txt +5 -0
  230. bugsink-0.1.12/projects/templates/mails/project_membership_invite_new_user.html +519 -0
  231. bugsink-0.1.12/projects/templates/mails/project_membership_invite_new_user.txt +5 -0
  232. bugsink-0.1.12/projects/templates/projects/project_edit.html +36 -0
  233. bugsink-0.1.12/projects/templates/projects/project_list.html +162 -0
  234. bugsink-0.1.12/projects/templates/projects/project_member_settings.html +53 -0
  235. bugsink-0.1.12/projects/templates/projects/project_members.html +94 -0
  236. bugsink-0.1.12/projects/templates/projects/project_members_accept.html +31 -0
  237. bugsink-0.1.12/projects/templates/projects/project_members_invite.html +58 -0
  238. bugsink-0.1.12/projects/templates/projects/project_new.html +32 -0
  239. bugsink-0.1.12/projects/templates/projects/project_sdk_setup.html +137 -0
  240. bugsink-0.1.12/projects/tests.py +1 -0
  241. bugsink-0.1.12/projects/urls.py +23 -0
  242. bugsink-0.1.12/projects/views.py +392 -0
  243. bugsink-0.1.12/pyproject.toml +61 -0
  244. bugsink-0.1.12/releases/__init__.py +0 -0
  245. bugsink-0.1.12/releases/admin.py +25 -0
  246. bugsink-0.1.12/releases/apps.py +6 -0
  247. bugsink-0.1.12/releases/migrations/0001_initial.py +31 -0
  248. bugsink-0.1.12/releases/migrations/__init__.py +0 -0
  249. bugsink-0.1.12/releases/models.py +161 -0
  250. bugsink-0.1.12/releases/tests.py +59 -0
  251. bugsink-0.1.12/releases/views.py +1 -0
  252. bugsink-0.1.12/requirements.development.txt +2 -0
  253. bugsink-0.1.12/requirements.txt +17 -0
  254. bugsink-0.1.12/sentry/LICENSE +12 -0
  255. bugsink-0.1.12/sentry/__init__.py +0 -0
  256. bugsink-0.1.12/sentry/stacktraces/functions.py +228 -0
  257. bugsink-0.1.12/sentry/stacktraces/platform.py +10 -0
  258. bugsink-0.1.12/sentry/stacktraces/processing.py +41 -0
  259. bugsink-0.1.12/sentry/utils/safe.py +95 -0
  260. bugsink-0.1.12/sentry/utils/strings.py +7 -0
  261. bugsink-0.1.12/sentry_sdk_extensions/__init__.py +113 -0
  262. bugsink-0.1.12/sentry_sdk_extensions/nohub.py +133 -0
  263. bugsink-0.1.12/sentry_sdk_extensions/transport.py +13 -0
  264. bugsink-0.1.12/setup.cfg +4 -0
  265. bugsink-0.1.12/snappea/__init__.py +50 -0
  266. bugsink-0.1.12/snappea/admin.py +1 -0
  267. bugsink-0.1.12/snappea/apps.py +6 -0
  268. bugsink-0.1.12/snappea/datastructures.py +30 -0
  269. bugsink-0.1.12/snappea/decorators.py +39 -0
  270. bugsink-0.1.12/snappea/example_tasks.py +25 -0
  271. bugsink-0.1.12/snappea/foreman.py +376 -0
  272. bugsink-0.1.12/snappea/management/__init__.py +0 -0
  273. bugsink-0.1.12/snappea/management/commands/__init__.py +0 -0
  274. bugsink-0.1.12/snappea/management/commands/checksnappea.py +11 -0
  275. bugsink-0.1.12/snappea/management/commands/runsnappea.py +10 -0
  276. bugsink-0.1.12/snappea/migrations/0001_initial.py +50 -0
  277. bugsink-0.1.12/snappea/migrations/0002_create_models.py +22 -0
  278. bugsink-0.1.12/snappea/migrations/__init__.py +0 -0
  279. bugsink-0.1.12/snappea/models.py +26 -0
  280. bugsink-0.1.12/snappea/settings.py +53 -0
  281. bugsink-0.1.12/snappea/tests.py +1 -0
  282. bugsink-0.1.12/snappea/views.py +1 -0
  283. bugsink-0.1.12/static/favicon.png +0 -0
  284. bugsink-0.1.12/static/fonts/ibm-plex-mono-v19-cyrillic_cyrillic-ext_latin_latin-ext_vietnamese-700.woff2 +0 -0
  285. bugsink-0.1.12/static/fonts/ibm-plex-mono-v19-cyrillic_cyrillic-ext_latin_latin-ext_vietnamese-700italic.woff2 +0 -0
  286. bugsink-0.1.12/static/fonts/ibm-plex-mono-v19-cyrillic_cyrillic-ext_latin_latin-ext_vietnamese-italic.woff2 +0 -0
  287. bugsink-0.1.12/static/fonts/ibm-plex-mono-v19-cyrillic_cyrillic-ext_latin_latin-ext_vietnamese-regular.woff2 +0 -0
  288. bugsink-0.1.12/static/fonts/ibm-plex-sans-v19-cyrillic_cyrillic-ext_greek_latin_latin-ext_vietnamese-700.woff2 +0 -0
  289. bugsink-0.1.12/static/fonts/ibm-plex-sans-v19-cyrillic_cyrillic-ext_greek_latin_latin-ext_vietnamese-700italic.woff2 +0 -0
  290. bugsink-0.1.12/static/fonts/ibm-plex-sans-v19-cyrillic_cyrillic-ext_greek_latin_latin-ext_vietnamese-italic.woff2 +0 -0
  291. bugsink-0.1.12/static/fonts/ibm-plex-sans-v19-cyrillic_cyrillic-ext_greek_latin_latin-ext_vietnamese-regular.woff2 +0 -0
  292. bugsink-0.1.12/static/images/bugsink-logo.png +0 -0
  293. bugsink-0.1.12/static/js/issue_history.js +29 -0
  294. bugsink-0.1.12/static/js/issue_list.js +45 -0
  295. bugsink-0.1.12/static/js/issue_stacktrace.js +145 -0
  296. bugsink-0.1.12/static/js/project_list.js +6 -0
  297. bugsink-0.1.12/static/js/team_list.js +6 -0
  298. bugsink-0.1.12/teams/__init__.py +0 -0
  299. bugsink-0.1.12/teams/admin.py +61 -0
  300. bugsink-0.1.12/teams/apps.py +6 -0
  301. bugsink-0.1.12/teams/forms.py +62 -0
  302. bugsink-0.1.12/teams/migrations/0001_initial.py +33 -0
  303. bugsink-0.1.12/teams/migrations/0002_initial.py +25 -0
  304. bugsink-0.1.12/teams/migrations/__init__.py +0 -0
  305. bugsink-0.1.12/teams/models.py +50 -0
  306. bugsink-0.1.12/teams/tasks.py +47 -0
  307. bugsink-0.1.12/teams/templates/mails/team_membership_invite.html +519 -0
  308. bugsink-0.1.12/teams/templates/mails/team_membership_invite.txt +5 -0
  309. bugsink-0.1.12/teams/templates/mails/team_membership_invite_new_user.html +519 -0
  310. bugsink-0.1.12/teams/templates/mails/team_membership_invite_new_user.txt +5 -0
  311. bugsink-0.1.12/teams/templates/teams/team_edit.html +34 -0
  312. bugsink-0.1.12/teams/templates/teams/team_list.html +144 -0
  313. bugsink-0.1.12/teams/templates/teams/team_member_settings.html +53 -0
  314. bugsink-0.1.12/teams/templates/teams/team_members.html +93 -0
  315. bugsink-0.1.12/teams/templates/teams/team_members_accept.html +31 -0
  316. bugsink-0.1.12/teams/templates/teams/team_members_invite.html +60 -0
  317. bugsink-0.1.12/teams/templates/teams/team_new.html +31 -0
  318. bugsink-0.1.12/teams/tests.py +1 -0
  319. bugsink-0.1.12/teams/urls.py +19 -0
  320. bugsink-0.1.12/teams/views.py +364 -0
  321. bugsink-0.1.12/templates/403.html +11 -0
  322. bugsink-0.1.12/templates/403_csrf.html +19 -0
  323. bugsink-0.1.12/templates/404.html +11 -0
  324. bugsink-0.1.12/templates/500.html +12 -0
  325. bugsink-0.1.12/templates/admin/change_form_object_tools.html +10 -0
  326. bugsink-0.1.12/templates/bugsink/csrf_debug.html +88 -0
  327. bugsink-0.1.12/templates/bugsink/login.html +55 -0
  328. bugsink-0.1.12/templates/bugsink/settings.html +51 -0
  329. bugsink-0.1.12/templates/signup.html +37 -0
  330. bugsink-0.1.12/theme/__init__.py +0 -0
  331. bugsink-0.1.12/theme/apps.py +5 -0
  332. bugsink-0.1.12/theme/static/css/dist/styles.css +1 -0
  333. bugsink-0.1.12/theme/static_src/.gitignore +1 -0
  334. bugsink-0.1.12/theme/static_src/package-lock.json +1543 -0
  335. bugsink-0.1.12/theme/static_src/package.json +29 -0
  336. bugsink-0.1.12/theme/static_src/postcss.config.js +7 -0
  337. bugsink-0.1.12/theme/static_src/src/styles.css +212 -0
  338. bugsink-0.1.12/theme/static_src/tailwind.config.js +76 -0
  339. bugsink-0.1.12/theme/templates/bare_base.html +24 -0
  340. bugsink-0.1.12/theme/templates/barest_base.html +20 -0
  341. bugsink-0.1.12/theme/templates/base.html +52 -0
  342. bugsink-0.1.12/theme/templates/tailwind_forms/formfield.html +18 -0
  343. bugsink-0.1.12/theme/templatetags/__init__.py +0 -0
  344. bugsink-0.1.12/theme/templatetags/datetime_formatting.py +37 -0
  345. bugsink-0.1.12/theme/templatetags/issues.py +132 -0
  346. bugsink-0.1.12/theme/templatetags/stricter_templates.py +35 -0
  347. bugsink-0.1.12/theme/templatetags/tailwind_forms.py +32 -0
  348. bugsink-0.1.12/theme/templatetags/user.py +14 -0
  349. bugsink-0.1.12/theme/templatetags/version.py +9 -0
  350. bugsink-0.1.12/theme/tests.py +61 -0
  351. bugsink-0.1.12/tox.ini +6 -0
  352. bugsink-0.1.12/users/__init__.py +16 -0
  353. bugsink-0.1.12/users/admin.py +8 -0
  354. bugsink-0.1.12/users/apps.py +6 -0
  355. bugsink-0.1.12/users/forms.py +146 -0
  356. bugsink-0.1.12/users/migrations/0001_initial.py +54 -0
  357. bugsink-0.1.12/users/migrations/__init__.py +0 -0
  358. bugsink-0.1.12/users/models.py +31 -0
  359. bugsink-0.1.12/users/tasks.py +34 -0
  360. bugsink-0.1.12/users/templates/mails/confirm_email.html +519 -0
  361. bugsink-0.1.12/users/templates/mails/confirm_email.txt +5 -0
  362. bugsink-0.1.12/users/templates/mails/reset_password_email.html +519 -0
  363. bugsink-0.1.12/users/templates/mails/reset_password_email.txt +5 -0
  364. bugsink-0.1.12/users/templates/users/confirm_email.html +29 -0
  365. bugsink-0.1.12/users/templates/users/confirm_email_sent.html +23 -0
  366. bugsink-0.1.12/users/templates/users/logged_out.html +21 -0
  367. bugsink-0.1.12/users/templates/users/preferences.html +37 -0
  368. bugsink-0.1.12/users/templates/users/request_reset_password.html +33 -0
  369. bugsink-0.1.12/users/templates/users/resend_confirmation.html +34 -0
  370. bugsink-0.1.12/users/templates/users/reset_password.html +37 -0
  371. bugsink-0.1.12/users/templates/users/reset_password_email_sent.html +21 -0
  372. bugsink-0.1.12/users/templates/users/user_edit.html +33 -0
  373. bugsink-0.1.12/users/templates/users/user_list.html +86 -0
  374. bugsink-0.1.12/users/tests.py +1 -0
  375. bugsink-0.1.12/users/urls.py +8 -0
  376. bugsink-0.1.12/users/views.py +246 -0
@@ -0,0 +1,79 @@
1
+ name: Continuous Integration
2
+
3
+ on:
4
+ push:
5
+ branches: [ "main" ]
6
+ pull_request:
7
+ branches: [ "main" ]
8
+
9
+ env:
10
+ DJANGO_SETTINGS_MODULE: "bugsink.settings.development"
11
+
12
+ jobs:
13
+ flake8:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ - name: "Set up Python 3.11"
18
+ uses: actions/setup-python@v5
19
+ with:
20
+ python-version: "3.11" # below 3.12 to avoid false positives inside f-string
21
+ - name: Install Flake8
22
+ run: |
23
+ python -m pip install --upgrade flake8
24
+ - name: Run Flake8
25
+ run: |
26
+ # We ignore 2 classes of whitespace errors (which are useful in the local context,
27
+ # but not worth breaking the build).
28
+ # https://github.com/PyCQA/flake8/issues/515 shows a dead end of doing this "properly"
29
+ # so we just specify it on the command line
30
+ flake8 --extend-ignore=E127,E741,E501 `git ls-files | grep py$`
31
+
32
+ test:
33
+ runs-on: ubuntu-latest
34
+ strategy:
35
+ matrix:
36
+ python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
37
+ steps:
38
+ - uses: actions/checkout@v4
39
+ - name: Set up Python ${{ matrix.python-version }}
40
+ uses: actions/setup-python@v5
41
+ with:
42
+ python-version: ${{ matrix.python-version }}
43
+ - name: Install build
44
+ run: |
45
+ python -m pip install --upgrade pip
46
+ pip install build
47
+ - name: Build wheel
48
+ run: |
49
+ python -m build --wheel
50
+ - name: Install from wheel
51
+ run: |
52
+ python -m pip install dist/*.whl
53
+ - name: Install development dependencies
54
+ run: |
55
+ pip install -r requirements.development.txt
56
+ - name: Check out event-samples
57
+ uses: actions/checkout@master
58
+ with:
59
+ repository: bugsink/event-samples
60
+ path: "event-samples"
61
+ - name: Create separate dir to avoid accidentally using non-packaged code
62
+ run: |
63
+ mkdir separate_dir
64
+ - name: Run Makemigrations --check
65
+ working-directory: separate_dir
66
+ run: |
67
+ bugsink-manage makemigrations --check
68
+ - name: Run Tests
69
+ working-directory: separate_dir
70
+ env:
71
+ SAMPLES_DIR: "${{ github.workspace }}/event-samples"
72
+ PYTHONWARNINGS: all
73
+ run: |
74
+ # because we're outside the project directory, the test discovery won't find our packages. We simply enumerate
75
+ # them using some shell-magic. Note that the only non-app that we still care about is 'bugsink' (project, not app)
76
+ # which we mention separately
77
+ bugsink-manage test `bugsink-manage shell -c 'from django.conf import settings; print(" ".join(settings.BUGSINK_APPS))'` bugsink -v2
78
+ # bugsink-manage test ${GITHUB_WORKSPACE} -v2 # fails with the following, which I don't understand:
79
+ # ImportError: 'tests' module incorrectly imported from '/opt/hostedtoolcache/Python/3.10.15/x64/lib/python3.10/site-packages/alerts'. Expected '/home/runner/work/bugsink-private/bugsink-private/alerts'. Is this module globally installed?
@@ -0,0 +1,51 @@
1
+ # Python
2
+ *.pyc
3
+ __pycache__
4
+
5
+ # Virtual Environments / build
6
+ /.env
7
+ /.venv
8
+ /bin/
9
+ /include/
10
+ /lib/
11
+ /lib64
12
+ /pyvenv.cfg
13
+ /share/
14
+ /bugsink.egg-info/
15
+ /bugsink/_version.py
16
+ /dist/
17
+
18
+
19
+ # sqlite
20
+ /db.sqlite3
21
+ /db.*.sqlite3
22
+ /test.sqlite3
23
+
24
+ /db.sqlite3-wal
25
+ /db.*.sqlite3-wal
26
+ /test.sqlite3-wal
27
+
28
+ /db.sqlite3-shm
29
+ /db.*.sqlite3-shm
30
+ /test.sqlite3-shm
31
+
32
+ /snappea.sqlite3
33
+ /snappea.sqlite3-shm
34
+ /snappea.sqlite3-wal
35
+
36
+ # vim
37
+ *.swo
38
+ *.swp
39
+
40
+ # node (tailwind)
41
+ node_modules
42
+ /package*
43
+
44
+ # conf
45
+ /bugsink_conf.py
46
+
47
+ # static files
48
+ /collectedstatic
49
+
50
+ # Docker artifacts
51
+ /bugsink*tar
@@ -0,0 +1,77 @@
1
+ # Alert Rules
2
+
3
+ ## Opinionated take
4
+
5
+ Default setting, may be adapted at organisational level.
6
+
7
+ You should get alerts for any state change for the worse, such as:
8
+
9
+ * New issues
10
+ * Regressions
11
+ * Unmuting (could be due to volume)
12
+
13
+ The basic belief underlying this is: "you should care about the errors on your project". And therefore, you'll be
14
+ alerted when they occur.
15
+
16
+ ### Volume-Based Rules for unmuting
17
+
18
+ Volume based rules may be configured per-issue for unmuting. e.g.
19
+
20
+ - First time more than 5 events per the last 3 hours occur
21
+ - First time more than 10 events per day
22
+ - First time the total number of events exceeds 100
23
+
24
+ The idea is: "I know about this issue, I've determined it's not important, and I only want to get notified when it start
25
+ occurrung a lot (for some definition of 'a lot')"
26
+
27
+ The tie-in with alerts is: you can send notification on-unmute. (by the definition of unmuting, the alert
28
+ occurs only the _first time_ the condition occurs)
29
+
30
+ ## "Later": auto-mute w/ default unmute rules
31
+
32
+ At some point we may make it so that you can configure per-project that issues are initially muted (on create) but with
33
+ some predefined set of volume-based unmute conditions, which is set on the muted issues on-create.
34
+
35
+ (This is in place of project-level volume-based alert settings. The main reason for this is that I want to keep a
36
+ symmetry/tracability between what's going on in the UI and the alerts that are going out)
37
+
38
+ ## "Later": more than first-time-only
39
+
40
+ (The below only works if you let go of the idea that the only way you get volume-based alerts is when some unmute-condition occurs).
41
+
42
+ Rather than just having first-time only rules, you could have alerting rules that are triggered when a condition
43
+ persists. e.g.
44
+
45
+ * Any time more than 5 events occur the past 3 hours (ignoring any events that occured before the last time this was
46
+ triggered).
47
+
48
+ ## Personal Notification Settings
49
+
50
+ Personal notification settings exist both globally (i.e. configured per User) and per Project.
51
+
52
+ Reasons for per-project settings include scenarios where someone is involved in the project but not to the extent of
53
+ needing constant updates (e.g., consulting members or certain leads).
54
+
55
+ However, these settings are limited to a single toggle: yes/no/(default). That is, you can't choose specific rules to
56
+ follow for a project (e.g. just on unmute, or just on regressions)
57
+
58
+ More detailed configuration of alerting rules is project-centered. The idea is that the 2 main variables that control
59
+ when alerts should be sent are dictated by the nature of the project, not the preferences of the member, namely:
60
+
61
+ * how broken the project is (how many errors are generated)
62
+ * how important brokenness is
63
+
64
+ I.e. there is a single (configurable) threshold per project for what constitues "worth alerting about but avoiding
65
+ swamping in false positives" which you can then subscribe to or not.
66
+
67
+ (Note that the thoughts in this section are already less necessary to make explicit, because most of the volume-based
68
+ alerting has (for now) been chosen not to implement in favor of vbc-unmute-rules (which are by definition not per user)
69
+
70
+ ## Chat-Ops
71
+
72
+ You may configure any number of chat-ops endpoints (mattermost/slack channels). These are not connected to individual
73
+ users. There's likely a default setting at the organization level. But it's also well imaginable that some project-based
74
+ settings are necessary, e.g. when each project has its own channel.
75
+
76
+ The chat-ops channels always receive the per-project configured set of notifications, i.e. the threshold cannot be
77
+ changed per chat-op-channel (as with users).
@@ -0,0 +1,5 @@
1
+ Thoughts on breadcrumbs
2
+
3
+ I think it is only a moderately useful functionality; it seems like an idea they once had, but which was never _really_ followed through on. Perhaps you as a user can make it more useful by making more aggressive choices on the client side. But how to (e.g.) disable it in the Django Integration is not easy to find, and disabling useless things is always important if you really want to take something in hand. What happens with the logging integration is something I still have to read up. i.e. do certain logs just always become breadcrumbs? and how does that relate to logs that are automatically translated into events? (also read what I wrote about this in sentry-stfu)
4
+
5
+ And all those types and categories are only half thought through and defined, at least as far as the documentation is concerned. If I want to show such images it is a bit of reverse engineering (in combination with RTFM). It could be that in the JavaScript world, and combined with transactions, there is something more useful. I should see that then. As with log messages: we need some support for it, because the clients support this.
@@ -0,0 +1,76 @@
1
+ Connection closing and subsequent re-opening is not free. I've done some experiments; it looks like the connection
2
+ close/open themselves are in the sub-1ms range.
3
+
4
+ But: when being the first connection to write, there is a c. 13ms penalty. Hypothesis: the opening of the WAL file.
5
+
6
+ This is the code I played with to establish this.
7
+ Note that the result of running the second half (the Django part) without first running the first half are very
8
+ different from doing them both at once. Hence "being the first connection", i.e. there's a cross-connection effect.
9
+
10
+ ```
11
+ from performance.context_managers import time_it
12
+ import sqlite3
13
+
14
+ conn = sqlite3.connect('db.sqlite3')
15
+ cursor = conn.cursor()
16
+
17
+ with time_it() as timings:
18
+ cursor.execute('UPDATE auth_user set username = username')
19
+ conn.commit()
20
+
21
+ print("fresh conn", timings.took)
22
+
23
+ with time_it() as timings:
24
+ cursor.execute('UPDATE auth_user set username = username')
25
+ conn.commit()
26
+
27
+ print("reused conn", timings.took)
28
+
29
+
30
+ from performance.context_managers import time_it
31
+ import sqlite3
32
+ from django.db import connection
33
+ from django.db import models
34
+ from users.models import User
35
+ from performance.context_managers import time_it
36
+ from bugsink.transaction import immediate_atomic
37
+
38
+ with time_it() as timings:
39
+ with immediate_atomic():
40
+ User.objects.update(username=models.F('username'))
41
+
42
+ print("django fresh conn", timings.took)
43
+
44
+ with time_it() as timings:
45
+ with immediate_atomic():
46
+ User.objects.update(username=models.F('username'))
47
+
48
+ print("django reused conn", timings.took)
49
+ ```
50
+
51
+ With just the second half:
52
+
53
+ ```
54
+ ... with immediate_atomic():
55
+ ... User.objects.update(username=models.F('username'))
56
+ ...
57
+ CONNECTION created /mnt/datacrypt/dev/bugsink/db.sqlite3 124812146634816 in 0ms MainThread
58
+ 1.79ms BEGIN IMMEDIATE, A.K.A. get-write-lock ↴
59
+ 0.69ms ABOUT TO END IMMEDIATE transaction' ↴
60
+ 10.67ms END IMMEDIATE transaction' ↴
61
+ >>> print("django fresh conn", timings.took)
62
+
63
+ django fresh conn 13.312101364135742
64
+
65
+ >>>
66
+ >>> with time_it() as timings:
67
+ ... with immediate_atomic():
68
+ ... User.objects.update(username=models.F('username'))
69
+ ...
70
+ 0.19ms BEGIN IMMEDIATE, A.K.A. get-write-lock ↴
71
+ 0.35ms ABOUT TO END IMMEDIATE transaction' ↴
72
+ 0.50ms END IMMEDIATE transaction' ↴
73
+ >>> print("django reused conn", timings.took)
74
+
75
+ django reused conn 0.9033679962158203
76
+ ```
@@ -0,0 +1,6 @@
1
+ We support Logging as good as we can, because we've taken the approach of being compatible with Sentry clients, and those occassionally send Log messages. We don't want to be confusing in that case. Having said that:
2
+
3
+ Bugsink is about Error handling, not about arbitrary logging. Looking at the competition (Sentry, GlicthTip), I don't think log messages show up particularly strong there: because the message is lifted to the main title element, and because there is barely any info to show (certainly no stacktrace), they are in fact more confusing than anything (we've at least taken a more explicit approach, of putting some general "Log Message" at the top, and showing the message where the exception messages are generally shown). Perhaps that logging shines when you see it through the lens of transactions (then again: perhaps not -- maybe they're just chasing the trend of "log everythign").
4
+
5
+ One further question: I see a lot of "error" levels in the messages as sent with some quick tests... even when those messages had lower log-levels.
6
+
@@ -0,0 +1,18 @@
1
+ Thoughts on Teams and Organizations
2
+
3
+ Our approach doesn't incorporate a sentry-like model for "teams." Instead, individuals are either part of a project or
4
+ not. Envisioned roles are:
5
+
6
+ * read-only access
7
+ * regular (allowing state changes to issues)
8
+ * admin (with privileges to manage settings and memberships).
9
+
10
+ Regarding organizations, the use cases are:
11
+
12
+ * if you're employed at "big-co", it serves as a platform to establish your "bigger team," which could oversee multiple
13
+ see e.g. GitHub, GitLab, and CloudFoundry for comparison
14
+ * when I develop hosted.bugsink.com, the "organization" is the natural unit a user will have access to or not.
15
+
16
+ These organizations can serve as points for inherited permissions, as well as provide a systematic grouping of
17
+ projects. Additionally, they serve as a central repository for inheritable settings, streamlining the management and
18
+ configuration of multiple projects within a broader organizational context.
@@ -0,0 +1,76 @@
1
+ ## Some thoughts on performance
2
+
3
+ ### 18 July surprise
4
+
5
+ In the last few days I've been observing 85/s requests ingestion. What has changed? No idea...
6
+
7
+ ### Thoughts after -wal cleanup (better connection closing)
8
+
9
+ There seems to be a small drop in ingestion performance, to approx. 30/s events. Given that this was (in "Original
10
+ thoughts") the max, this is fine (for the increased (presumed) stability). (Pre-wal-cleanup this was approx 40/s)
11
+
12
+ If this becomes a problem, the thing to consider is "keeping threads, and associated connections, open in the foreman".
13
+
14
+ ### Thoughts after implementing eviction
15
+
16
+ (See also contents of ./performance/stress-with-eviction/)
17
+
18
+ * Surprise 1: 50 events/s (60% more than what I found below)
19
+ * Surprise 2: in this config, I _am_ getting snappea backlog.
20
+
21
+ ### Original thoughts
22
+
23
+ Now that we have playground.bugsink.com, I could get some real data on that system too.
24
+
25
+ I suppose the most "interesting" finding is that the ~30/s events I can handle seem to be entirely limited by the
26
+ (https?) nginx stack.
27
+
28
+ This also means that, in this setup, snappea is able to deal with "postponed" work basically as fast as the frontend can
29
+ deliver it, i.e. there is no actual backlog. Which raises some serious(?) questions about snappea in this setup.
30
+
31
+ Some things I played with (more or less in order I did them):
32
+
33
+ * try to remove the (physical) network from the equation by doing local-loopback
34
+ * use compression (brotli) to avoid network overhead
35
+ * compare with my local laptop
36
+ * drop actual handling of the request, i.e. just do a `request.read(); return HttpResponse()`
37
+ * remove nginx from the equation and just connect on `:8000`
38
+
39
+ Some numbers:
40
+
41
+ All measurements are with a 50k event. (NOTE: after removal of whitespace this is actually a 40k event)
42
+
43
+ * Starting point is ~30/s. local to playground; actual (non-immediate) handling of events. varying number of gunicorn
44
+ and snappea workers doesn't seem to do much.
45
+
46
+ * local loopback on playground.bugsink.com: ~21/s. i.e. it's slower. Presumably: the cost of running the stress test.
47
+
48
+ * local loopback on playground.bugsink.com, but dropping the request on the floor: ~25/s.
49
+
50
+ * compressing as brotli and doing local -> playgrond: ~18/s. Surprisingly the cost of unpacking is larger than the
51
+ advantage of having to deal with less data.
52
+
53
+ * locally (laptop), I got to ~280/s with actual handling turned on. This is where I (slightly) outrun snappea.
54
+
55
+ * locally with drop-to-floor I got to ~455/s. Noteworthy: this is not even twice as fast as the "real" (postponed)
56
+ handling. i.e. we're already close to our limits with that.
57
+
58
+ * turning off nginx, local -> playground: 146/s. Noteworthy: this is the only thing on playground that helped me go
59
+ faster. But we don't actually want to recommend that, of course. Also: this is the only setup where I was able to
60
+ outrun snappea (for a short while). Note that tuning thread for gunicorn / stress-test matters here. (I used 25)
61
+
62
+ * playground locally w/o nginx and w/ drop-to-floor: 400/s. Noteworthy: very close to what I get on my laptop.
63
+
64
+
65
+
66
+ Some conclusions:
67
+
68
+ * 30/s is still "a lot"; that's 2.5M/day or 77M/month, which is _more_ than the maximum Sentry allows you to select in
69
+ the pricing page. (50M maxes out at $5,795.50 prepaid per month)
70
+
71
+ * Still, the above raises some questions on "is snappea worth it in this setup". Counterpoints (stability,
72
+ predictability, the fact that there may be other slow async things) still apply.
73
+
74
+ * I never really got a chance to tune my setup. I did raise gunicorn workers to "enough to deal with the number of
75
+ threads" which was in the 16 - 32 range. But with snappea without a backlog the number of workers is not material to
76
+ the performance.
@@ -0,0 +1,52 @@
1
+ ### Snappea
2
+
3
+ I ditched Celery.
4
+
5
+ Why? It needs a broker. And the broker is "yet another thing to set up". Moving parts are the enemy!
6
+ There may still be a future scenario where celery is a choice one can make. I've kept the interface as similar to celery
7
+ as I could, so I can have it swapped back in later if needed.
8
+
9
+ Considered alternatives:
10
+
11
+ * redislite w/ celery
12
+ this seems "risky", you're basically putting an unsupported part in the (already complicated) machine and hope for
13
+ the best.
14
+
15
+ * huey with file or sqlite backend?
16
+ the documentation seems to steer one away from this.
17
+
18
+ * "inside" gunicorn: this didn't seem straightforward at all. uvicorn/channels may be better ways forward, but again,
19
+ the docs are steering one away from this.
20
+
21
+ For now I'm just running in always-eager mode to facilitate running debugserver. This will probably change at some point.
22
+
23
+
24
+
25
+ Considered alternatives for the "waking up"
26
+
27
+ Currently implemented using inotify.
28
+ Main drawback: tie-in to Linux.
29
+
30
+ However, the model of "just writing some unique file" is very simple to understand.
31
+ And the division of labor regarding these files is also simple (the clients just put files there, the snappeaserver just cleans)
32
+ And it's a nicely decoupled model too: if either server or client is temporarily gone, the messages are not lost/blocking ("postbox model")
33
+ And it provides a potential path forward if we ever want to put everything (the messages themselves) in those files.
34
+
35
+ * signals: abandoned, e.g. https://github.com/python/cpython/issues/118143 for the reason
36
+
37
+ * SIGSTP / SIGCONT: abandoned, I couldn't get this work reliably with "many signals" either. Process hangs mysteriously.
38
+
39
+ * busy loop with read-on-the-db: still a good candidate. However: the read on the DB is somewhere between .1ms and 1ms.
40
+ and appears to be CPU-intensive. This means that the sleep() in the loop becomes something to think about and
41
+ potentially even configure (boooh!). In particular, you get a trade-off between the latency of picking up the work,
42
+ and the CPU load of the busy loop, which may depend on the fastness of your platform. This is exactly the kind of
43
+ thinking that I want to take away from myusers (and myself).
44
+
45
+ * Zero MQ: still a strong candidate. I like that it's not tying us to Linux. And it's still brokerless. However, half
46
+ way through reading its manual I decided implementing this myself would still be faster than understanding yet another
47
+ component. Also: TCP is basically implied, which is another point of questions (firewalls etc).
48
+
49
+ * Python's multiprocessing.connection.Listener ... introduces pickling. Yuck!
50
+
51
+ * A FIFO where we write bytes: it doesn't seem to be a good fit for more than a single writer.
52
+
@@ -0,0 +1,86 @@
1
+ ## Goals
2
+
3
+ * Simplicity
4
+ * Stability: easy to deploy; deploy once, and then forget it.
5
+
6
+ Not "feature rich"
7
+
8
+ Get *notified* about *programming errors* (not: connection errors) as they occur.
9
+ Enough *context* to solve these errors.
10
+
11
+ On-prem running is the expected default.
12
+
13
+ They sent a monolith to catch a monolith.
14
+
15
+ Flowing from desire for "stability":
16
+
17
+ * quota-from-the-ground-up (because otherwise: accidental DDOS)
18
+ * thinking about resource-usage from-the-ground-up.
19
+
20
+
21
+ CLI-first
22
+
23
+ proxying should be a primitive
24
+ i.e. local client should be similar to servers.
25
+ (passing events is natural)
26
+
27
+
28
+ built from understood/known performance characteristics
29
+
30
+
31
+ Solve as much client-side as possible.
32
+
33
+ What you care about: "issues", not "events"
34
+ * issue-grouping
35
+ * We don't make money per-issue, we don't want to know about re-occurrences (or we want to know only a little about them)
36
+
37
+
38
+ How valuable is the data? do we care about throwing out info?
39
+ "not as valuable as a running system"
40
+ errors that you care about will likely re-occur.
41
+ still: it's nice to not lose information.
42
+
43
+
44
+ Splitting the issue-database from the organizational database?
45
+ "maybe"
46
+ con: extra complexity
47
+ pro: these things have different backup/reproduction regimes
48
+ the issues (other than "resolution") can be reconstructed from
49
+
50
+
51
+
52
+ Event-based from the ground up.
53
+ because "duh"... this is a textbook event system
54
+ because stability: easier to reason about costs this way.
55
+ because easier to get performant: do your calculations incrementally (e.g. quota usage becomes a +=1 operation)
56
+
57
+
58
+
59
+ TECHNICAL CHOICES:
60
+
61
+ mysql v.s. postgres (v.s. sqlite): make an _informed_ decision
62
+
63
+
64
+
65
+ NEXT UP
66
+
67
+ Start building
68
+ motto: off the shelve and boring components, but with an architecture which takes replacability in mind
69
+
70
+ ingesting first
71
+ as a simple Django app which dumps everything into a textfield (this is TSTTCPW)
72
+
73
+ this also allows for
74
+
75
+ dogfooding becomes possible:
76
+ turn on sentry-SDK and send issues your own way.
77
+
78
+ a bunch of example events are availabe in e.g. GlitchTip.
79
+
80
+ install both GlitchTip and Sentry locally.
81
+ optie 1: met de aangeraden docker-compose
82
+ optie 2: the "developer" view (misschien beter als je pdb wilt kunnen doen??)
83
+
84
+
85
+ NEXT READING SESSION: last OS version of sentry itself.
86
+
@@ -0,0 +1,37 @@
1
+ ARG PYTHON_VERSION=3.12
2
+
3
+ # Build image: non-slim, in particular to build the mysqlclient wheel
4
+ FROM python:${PYTHON_VERSION} AS build
5
+
6
+ ARG WHEEL_FILE=wheelfile-not-specified.whoops
7
+
8
+ COPY dist/$WHEEL_FILE /wheels/
9
+ RUN --mount=type=cache,target=/var/cache/buildkit/pip \
10
+ pip wheel --wheel-dir /wheels /wheels/${WHEEL_FILE} mysqlclient
11
+
12
+
13
+ # Actual image (based on slim)
14
+ FROM python:${PYTHON_VERSION}-slim
15
+
16
+ # ARGs are not inherited from the build stage; https://stackoverflow.com/a/56748289/339144
17
+ ARG WHEEL_FILE
18
+ ENV PYTHONUNBUFFERED=1
19
+
20
+ ENV PORT=8000
21
+
22
+ WORKDIR /app
23
+
24
+ # mysqlclient dependencies; needed here too, because the built wheel depends on .o files
25
+ RUN apt update && apt install default-libmysqlclient-dev -y
26
+
27
+ COPY --from=build /wheels /wheels
28
+ RUN --mount=type=cache,target=/var/cache/buildkit/pip \
29
+ pip install --find-links /wheels --no-index /wheels/$WHEEL_FILE mysqlclient
30
+
31
+ COPY bugsink/conf_templates/docker.py.template bugsink_conf.py
32
+
33
+ RUN ["bugsink-manage", "migrate", "snappea", "--database=snappea"]
34
+
35
+ EXPOSE $PORT
36
+
37
+ CMD [ "monofy", "bugsink-manage", "check", "--deploy", "--fail-level", "WARNING", "&&", "bugsink-manage", "migrate", "&&", "gunicorn", "--bind=0.0.0.0:$PORT", "--workers=10", "--access-logfile", "-", "bugsink.wsgi", "|||", "bugsink-runsnappea"]
@@ -0,0 +1,7 @@
1
+ FROM mysql
2
+
3
+ ENV MYSQL_DATABASE=bugsink
4
+ ENV MYSQL_USER=bugsink
5
+
6
+ # Expose the default port
7
+ EXPOSE 3306
bugsink-0.1.12/LICENSE ADDED
@@ -0,0 +1,47 @@
1
+ With regard to the Bugsink Software:
2
+
3
+ This software and associated documentation files (the "Software") may only be
4
+ used under either of the following 2 conditions:
5
+
6
+ 1. In production, if you (and any entity that you represent) have agreed to,
7
+ and are in compliance with, the Bugsink Subscription Terms of Service,
8
+ available at TODO (the "Terms"), or other agreement governing the use of the
9
+ Software, as agreed by you and Bugsink B.V., and otherwise have a valid
10
+ Bugsink subscription for the correct number of users.
11
+
12
+ OR
13
+
14
+ 2. In a non-production environment, for a single user, for the purpose of
15
+ evaluating the Software, provided that you are not using or have not used
16
+ the Software in a way that would violate the Terms.
17
+
18
+ Subject to the foregoing condition, you are free to modify this Software,
19
+ provided that you do not remove the copyright notice and the license notice and
20
+ do not modify the code in a way that would conflict with the Terms.
21
+
22
+ You are not granted any other rights beyond what is expressly stated herein.
23
+
24
+ Subject to the foregoing, it is forbidden to copy, merge, publish, distribute,
25
+ sublicense, and/or sell the Software.
26
+
27
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
32
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33
+ SOFTWARE.
34
+
35
+ For all third party components incorporated into the Bugsink Software, those
36
+ components are licensed under the original license provided by the owner of the
37
+ applicable component:
38
+
39
+ * The icons in SVG format, directly included in various html templates are from
40
+ Heroicons by Tailwind Labs, Inc. (MIT License)
41
+
42
+ * The code in the 'sentry' directory is Copyright 2019 Sentry
43
+ (https://sentry.io) and individual contributors. (BSD 3-Clause License)
44
+
45
+ * Your package manager (typically pip) will install additional third party
46
+ components upon installing Bugsink. Please refer to the license of the
47
+ respective component in your package manager's repository.