rails_observatory 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +42 -0
  3. data/Rakefile +8 -0
  4. data/app/assets/config/rails_observatory_manifest.js +2 -0
  5. data/app/assets/images/rails_observatory/logo.svg +8 -0
  6. data/app/assets/js/application.js +88 -0
  7. data/app/assets/js/controllers/chart_controller.js +176 -0
  8. data/app/assets/js/controllers/event_details_controller.js +15 -0
  9. data/app/assets/js/controllers/index.js +9 -0
  10. data/app/assets/js/controllers/sparkline_controller.js +72 -0
  11. data/app/assets/stylesheets/application/card.css +51 -0
  12. data/app/assets/stylesheets/application/chart.css +34 -0
  13. data/app/assets/stylesheets/application/dropdown.css +62 -0
  14. data/app/assets/stylesheets/application/global_modifiers.css +10 -0
  15. data/app/assets/stylesheets/application/query_table.css +68 -0
  16. data/app/assets/stylesheets/application/side_nav.css +62 -0
  17. data/app/assets/stylesheets/application/side_panel.css +35 -0
  18. data/app/assets/stylesheets/application/tab_nav.css +64 -0
  19. data/app/assets/stylesheets/application/table_chart.css +66 -0
  20. data/app/assets/stylesheets/application/tbd.css +70 -0
  21. data/app/assets/stylesheets/application/top_nav.css +33 -0
  22. data/app/assets/stylesheets/application.css +42 -0
  23. data/app/assets/stylesheets/elements/a.css +8 -0
  24. data/app/assets/stylesheets/elements/button.css +21 -0
  25. data/app/assets/stylesheets/elements/details.css +12 -0
  26. data/app/assets/stylesheets/elements/root.css +26 -0
  27. data/app/assets/stylesheets/elements/section.css +9 -0
  28. data/app/assets/stylesheets/errors/show/details.css +13 -0
  29. data/app/assets/stylesheets/layout/app.css +23 -0
  30. data/app/assets/stylesheets/layout/details-side-panel.css +15 -0
  31. data/app/assets/stylesheets/layout/requests.css +45 -0
  32. data/app/assets/stylesheets/layout/two-column.css +17 -0
  33. data/app/assets/stylesheets/mixins/nav_button.css +19 -0
  34. data/app/assets/stylesheets/requests/stats.css +35 -0
  35. data/app/controllers/rails_observatory/application_controller.rb +24 -0
  36. data/app/controllers/rails_observatory/errors_controller.rb +27 -0
  37. data/app/controllers/rails_observatory/jobs_controller.rb +25 -0
  38. data/app/controllers/rails_observatory/mailers_controller.rb +11 -0
  39. data/app/controllers/rails_observatory/requests_controller.rb +33 -0
  40. data/app/helpers/rails_observatory/application_helper.rb +110 -0
  41. data/app/jobs/rails_observatory/application_job.rb +4 -0
  42. data/app/mailers/rails_observatory/application_mailer.rb +6 -0
  43. data/app/views/layouts/rails_observatory/application.html.erb +93 -0
  44. data/app/views/new_user_mailer/greeting.html.erb +1 -0
  45. data/app/views/posts/index.html.erb +1 -0
  46. data/app/views/rails_observatory/application/_chart.html.erb +23 -0
  47. data/app/views/rails_observatory/application/_events_table.html.erb +24 -0
  48. data/app/views/rails_observatory/application/_sparkline.html.erb +17 -0
  49. data/app/views/rails_observatory/application/_trace.html.erb +122 -0
  50. data/app/views/rails_observatory/errors/index.html.erb +87 -0
  51. data/app/views/rails_observatory/errors/show.html.erb +193 -0
  52. data/app/views/rails_observatory/jobs/_table_chart.html.erb +29 -0
  53. data/app/views/rails_observatory/jobs/index.html.erb +20 -0
  54. data/app/views/rails_observatory/jobs/show.html.erb +8 -0
  55. data/app/views/rails_observatory/logs/index.html.erb +18 -0
  56. data/app/views/rails_observatory/mailers/index.html.erb +11 -0
  57. data/app/views/rails_observatory/mailers/show.html.erb +10 -0
  58. data/app/views/rails_observatory/requests/_text_gauge.html.erb +4 -0
  59. data/app/views/rails_observatory/requests/index.html.erb +56 -0
  60. data/app/views/rails_observatory/requests/show.html.erb +16 -0
  61. data/config/routes.rb +7 -0
  62. data/lib/rails_observatory/action_mailer_subscriber.rb +14 -0
  63. data/lib/rails_observatory/engine.rb +49 -0
  64. data/lib/rails_observatory/event_collector.rb +43 -0
  65. data/lib/rails_observatory/log_collector.rb +46 -0
  66. data/lib/rails_observatory/mailer_previews/delivered_mail_preview.rb +9 -0
  67. data/lib/rails_observatory/middleware.rb +77 -0
  68. data/lib/rails_observatory/models/error.rb +67 -0
  69. data/lib/rails_observatory/models/event_collection.rb +137 -0
  70. data/lib/rails_observatory/models/events.rb +22 -0
  71. data/lib/rails_observatory/models/job_trace.rb +28 -0
  72. data/lib/rails_observatory/models/logs.rb +9 -0
  73. data/lib/rails_observatory/models/mail_delivery.rb +33 -0
  74. data/lib/rails_observatory/models/redis_model.rb +112 -0
  75. data/lib/rails_observatory/models/request_trace.rb +29 -0
  76. data/lib/rails_observatory/railties/active_job_instrumentation.rb +48 -0
  77. data/lib/rails_observatory/railties/redis_runtime.rb +11 -0
  78. data/lib/rails_observatory/redis/logging_middleware.rb +22 -0
  79. data/lib/rails_observatory/redis/redis_client_instrumentation.rb +18 -0
  80. data/lib/rails_observatory/redis/time_series/increment_script.lua +67 -0
  81. data/lib/rails_observatory/redis/time_series/insertion.rb +73 -0
  82. data/lib/rails_observatory/redis/time_series/query_builder.rb +149 -0
  83. data/lib/rails_observatory/redis/time_series/timing_script.lua +89 -0
  84. data/lib/rails_observatory/redis/time_series.rb +91 -0
  85. data/lib/rails_observatory/serializers/event_serializer.rb +19 -0
  86. data/lib/rails_observatory/serializers/headers_serializer.rb +12 -0
  87. data/lib/rails_observatory/serializers/job_serializer.rb +11 -0
  88. data/lib/rails_observatory/serializers/mail_delivery_job_serializer.rb +14 -0
  89. data/lib/rails_observatory/serializers/request_serializer.rb +17 -0
  90. data/lib/rails_observatory/serializers/response_serializer.rb +14 -0
  91. data/lib/rails_observatory/serializers/serializer.rb +51 -0
  92. data/lib/rails_observatory/version.rb +3 -0
  93. data/lib/rails_observatory.rb +3 -0
  94. data/public/assets/js/application.js +11186 -0
  95. data/public/assets/logo_with_text.svg +21 -0
  96. data/public/assets/stylesheets/application.css +757 -0
  97. metadata +197 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: f127883108bb93b52d5230b2201ca52356acebf2de4ea62dc9cccf1d1c44d1b6
4
+ data.tar.gz: 90007d376e64259aad9633c375d7dce81a93d4bec9de7a9a61f9e72d1f39d5ab
5
+ SHA512:
6
+ metadata.gz: 6a25967194df5b78f63bbb8e380a146706bf345224e3da519da64556639d9ec9e37cad25a9332d224ea47f4336ae260e74272e69d6ee8498787f3cafdd498432
7
+ data.tar.gz: c847561c550175312c4442930dc65a2523dec1c915c97387e3858bf1396c38d262e498f849fc6ca108cb0f8316a69df09138b9844be6f3e55902db18b9134775
data/README.md ADDED
@@ -0,0 +1,42 @@
1
+ # Rails Observatory
2
+
3
+ Simple observability for your Rails app.
4
+
5
+ Rails observatory hooks into ActiveSupport::Instrumentation
6
+ with [RedisStack](https://redis.io/docs/about/about-stack/) to provide
7
+ a simple way to observe what is happening your Rails app, without third party integrations.
8
+
9
+ <img src="https://github.com/mgodwin/rails_observatory/blob/main/.github/observatory_trace.png?raw=true">
10
+
11
+ ## Features
12
+
13
+ - A simple APM to see what is happening in your application
14
+ - Traces for requests and jobs, and an interface to view them
15
+ - Captures logs emitted during a trace and provides an interface to view them
16
+ - Captures errors and provides an interface to view them
17
+ - In development, captures all delivered emails and provides an interface to view them
18
+
19
+ ## Requirements
20
+
21
+ - Redis w/ [TimeSeries module](https://github.com/RedisTimeSeries/RedisTimeSeries) (
22
+ or [RedisStack](https://github.com/redis-stack))
23
+ - Rails 7+
24
+
25
+ ## Installation
26
+
27
+ ```shell
28
+ bundle add observatory-rails
29
+ ```
30
+
31
+ ## Getting Started
32
+
33
+ Check out the Getting Started wiki page.
34
+
35
+ ## Contributing
36
+
37
+ Pull requests, issues and more are welcome!
38
+
39
+ ## License
40
+
41
+ The gem is available as open source under the terms of the LGPL v2 License.
42
+ If you'd like a commercial license, please contact me mark.godwin@hey.com
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/setup"
2
+
3
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
4
+ load "rails/tasks/engine.rake"
5
+
6
+ load "rails/tasks/statistics.rake"
7
+
8
+ require "bundler/gem_tasks"
@@ -0,0 +1,2 @@
1
+ //= link_tree ../stylesheets/rails_observatory/builds
2
+ //= link rails_observatory/logo_with_text.svg
@@ -0,0 +1,8 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"
2
+ width="72" height="78" viewBox="10 0 82 87">
3
+
4
+ <path d="M48.46,42.868L47.781,41.691C47.703,41.546 47.641,41.397 47.609,41.234C47.519,40.781 47.647,40.3 47.952,39.952C48.062,39.828 48.19,39.73 48.33,39.642L54.212,36.247C54.329,36.184 54.446,36.131 54.574,36.097C54.67,36.071 54.765,36.058 54.864,36.049C54.962,36.046 54.962,36.046 55.06,36.049C55.159,36.058 55.254,36.071 55.35,36.097C55.604,36.165 55.837,36.299 56.023,36.485C56.116,36.579 56.191,36.683 56.261,36.796L63.727,49.727C63.805,49.873 63.867,50.021 63.899,50.184C63.989,50.638 63.861,51.118 63.556,51.466C63.446,51.591 63.318,51.689 63.178,51.776L57.296,55.172C57.15,55.25 57.002,55.312 56.839,55.344C56.385,55.434 55.905,55.306 55.557,55.001C55.432,54.891 55.334,54.763 55.247,54.623L54.568,53.447L44.925,59.014C45.381,59.796 45.828,60.583 46.266,61.375C46.335,61.513 46.387,61.656 46.415,61.808C46.49,62.226 46.382,62.665 46.12,62.999C46.013,63.136 45.883,63.249 45.738,63.344C45.354,63.576 44.968,63.805 44.581,64.032L54.856,80.685C54.901,80.762 54.914,80.78 54.95,80.862C55.018,81.015 55.06,81.178 55.075,81.345C55.092,81.545 55.068,81.748 55.006,81.939C54.954,82.097 54.875,82.247 54.774,82.38C54.693,82.487 54.598,82.582 54.491,82.664C54.061,82.993 53.469,83.064 52.973,82.844C52.79,82.763 52.623,82.645 52.486,82.499C52.416,82.425 52.359,82.344 52.303,82.26L45.408,71.086L46.423,77.952C46.432,78.032 46.436,78.052 46.438,78.133C46.443,78.314 46.414,78.496 46.355,78.667C46.295,78.838 46.204,78.998 46.087,79.137C45.99,79.253 45.875,79.353 45.748,79.435C45.62,79.516 45.481,79.578 45.335,79.618C44.803,79.764 44.219,79.599 43.842,79.195C43.698,79.04 43.587,78.855 43.519,78.655C43.489,78.568 43.471,78.481 43.455,78.391L42.497,71.906L40.26,81.065L40.233,81.161C40.199,81.257 40.163,81.348 40.114,81.437C40.016,81.613 39.884,81.768 39.725,81.891C39.594,81.994 39.445,82.075 39.287,82.129C39.16,82.172 39.028,82.198 38.894,82.206C38.388,82.237 37.889,82.002 37.59,81.592C37.472,81.43 37.387,81.244 37.341,81.048C37.304,80.886 37.293,80.717 37.311,80.55C37.32,80.462 37.327,80.44 37.345,80.353L40.968,65.525C40.784,65.465 40.611,65.371 40.462,65.245C40.344,65.145 40.247,65.028 40.162,64.899C39.695,64.124 39.237,63.343 38.788,62.557L27.846,68.875C27.805,68.896 27.765,68.919 27.723,68.938C27.597,68.996 27.463,69.037 27.326,69.058C26.865,69.13 26.386,68.977 26.052,68.653C25.985,68.588 25.925,68.518 25.871,68.442C25.845,68.405 25.822,68.365 25.797,68.326L25.5,67.811C23.547,68.963 21.561,70.057 19.598,71.19C19.463,71.264 19.324,71.322 19.174,71.355C18.751,71.45 18.297,71.353 17.95,71.093C17.806,70.985 17.689,70.854 17.588,70.706C16.709,69.269 15.902,67.789 15.059,66.33C14.986,66.196 14.928,66.057 14.894,65.907C14.8,65.483 14.897,65.03 15.157,64.682C15.265,64.538 15.396,64.422 15.544,64.321C17.499,63.125 19.503,62.009 21.496,60.876L21.189,60.345C21.168,60.304 21.145,60.264 21.125,60.222C21.087,60.138 21.056,60.05 21.033,59.961C20.92,59.508 21.027,59.018 21.319,58.654C21.406,58.546 21.508,58.451 21.621,58.371C21.659,58.344 21.699,58.321 21.738,58.296L48.46,42.868ZM22.998,63.479L18.408,66.129L19.397,67.842L23.987,65.192L22.998,63.479ZM24.537,60.144L24.848,60.682C25.711,62.098 26.506,63.555 27.335,64.991L27.645,65.527L33.783,61.983C32.73,60.199 31.718,58.391 30.691,56.591L24.537,60.144ZM42.311,60.523L41.402,61.048L41.98,62.051L42.89,61.526L42.311,60.523ZM41.141,50.557L33.314,55.077C34.366,56.861 35.379,58.669 36.405,60.469L38.604,59.199C39.76,58.503 40.928,57.829 42.109,57.176L44.233,55.95C43.18,54.165 42.167,52.357 41.141,50.557ZM50.115,45.733L49.96,45.466L43.763,49.044C44.816,50.828 45.829,52.636 46.855,54.436L53.068,50.849L50.115,45.733ZM52.713,44.233L57.095,51.824L60.379,49.928L54.413,39.595C53.318,40.227 52.224,40.859 51.129,41.491L52.713,44.233ZM81.631,41.699C81.637,41.122 81.645,40.545 81.657,39.969C81.667,39.805 81.697,39.645 81.756,39.491C81.903,39.108 82.209,38.796 82.589,38.641C82.742,38.579 82.9,38.546 83.064,38.533C83.126,38.53 83.186,38.53 83.248,38.533C83.411,38.546 83.57,38.579 83.723,38.641C84.103,38.796 84.408,39.108 84.556,39.491C84.615,39.645 84.645,39.805 84.655,39.969C84.666,40.545 84.675,41.122 84.681,41.699C85.257,41.704 85.834,41.713 86.41,41.724C86.636,41.738 86.854,41.793 87.055,41.899C87.217,41.986 87.363,42.102 87.483,42.241C87.603,42.38 87.698,42.541 87.76,42.713C87.95,43.24 87.825,43.843 87.442,44.251C87.344,44.355 87.231,44.445 87.108,44.517C86.894,44.643 86.657,44.707 86.41,44.722C85.834,44.734 85.257,44.742 84.681,44.748C84.675,45.325 84.666,45.901 84.655,46.478C84.64,46.724 84.575,46.961 84.45,47.175C84.378,47.299 84.288,47.411 84.184,47.509C83.776,47.893 83.172,48.018 82.646,47.827C82.473,47.765 82.312,47.671 82.174,47.55C82.035,47.43 81.919,47.284 81.832,47.122C81.725,46.921 81.671,46.704 81.657,46.478C81.645,45.901 81.637,45.325 81.631,44.748C81.055,44.742 80.478,44.734 79.901,44.722C79.675,44.708 79.458,44.654 79.257,44.547C79.095,44.461 78.949,44.344 78.829,44.206C78.709,44.067 78.614,43.906 78.552,43.733C78.362,43.207 78.487,42.603 78.87,42.196C78.968,42.091 79.08,42.002 79.204,41.929C79.418,41.804 79.655,41.74 79.901,41.724C80.478,41.713 81.055,41.704 81.631,41.699ZM75.365,13.194C75.806,13.202 76.244,13.235 76.68,13.302C77.562,13.437 78.425,13.699 79.234,14.077C81.162,14.977 82.756,16.534 83.703,18.439C84.1,19.236 84.382,20.09 84.538,20.966C84.715,21.951 84.733,22.963 84.594,23.954C84.46,24.915 84.175,25.854 83.754,26.729C83.26,27.753 82.58,28.685 81.757,29.469C80.905,30.281 79.902,30.933 78.812,31.379C77.682,31.841 76.465,32.078 75.244,32.078C74.023,32.078 72.805,31.841 71.675,31.379C70.586,30.933 69.582,30.281 68.73,29.469C67.908,28.685 67.228,27.753 66.734,26.729C66.313,25.854 66.028,24.915 65.893,23.954C65.755,22.963 65.773,21.951 65.949,20.966C66.106,20.09 66.388,19.236 66.785,18.439C67.732,16.534 69.326,14.977 71.254,14.077C72.063,13.699 72.926,13.437 73.808,13.302C74.244,13.235 74.682,13.202 75.122,13.194C75.244,13.193 75.243,13.193 75.365,13.194ZM75.16,16.194C74.859,16.2 74.56,16.222 74.262,16.268C73.661,16.359 73.074,16.537 72.524,16.795C71.255,17.388 70.196,18.397 69.542,19.636C69.26,20.17 69.054,20.745 68.933,21.337C68.785,22.059 68.762,22.807 68.864,23.537C68.952,24.166 69.135,24.78 69.403,25.355C69.732,26.059 70.189,26.701 70.745,27.244C71.32,27.805 71.998,28.258 72.738,28.572C73.503,28.895 74.33,29.066 75.16,29.077C75.994,29.088 76.828,28.937 77.604,28.631C78.352,28.336 79.042,27.899 79.631,27.351C80.199,26.822 80.671,26.191 81.017,25.496C81.311,24.905 81.512,24.27 81.612,23.617C81.719,22.915 81.71,22.194 81.585,21.494C81.479,20.898 81.287,20.317 81.017,19.775C80.393,18.521 79.359,17.486 78.104,16.862C77.562,16.593 76.981,16.401 76.385,16.294C76.09,16.241 75.793,16.211 75.494,16.198C75.382,16.194 75.272,16.193 75.16,16.194ZM34.084,17.795C34.09,17.218 34.099,16.642 34.11,16.065C34.12,15.901 34.15,15.742 34.209,15.588C34.357,15.205 34.662,14.893 35.042,14.738C35.195,14.675 35.354,14.643 35.517,14.629C35.579,14.627 35.639,14.627 35.701,14.629C35.865,14.643 36.024,14.675 36.176,14.738C36.556,14.893 36.862,15.205 37.009,15.588C37.068,15.742 37.098,15.901 37.108,16.065C37.12,16.642 37.128,17.218 37.134,17.795C37.71,17.801 38.287,17.809 38.864,17.821C39.11,17.836 39.347,17.9 39.561,18.026C39.685,18.098 39.797,18.188 39.895,18.292C40.278,18.7 40.403,19.303 40.213,19.83C40.151,20.002 40.056,20.163 39.936,20.302C39.816,20.441 39.67,20.557 39.508,20.644C39.307,20.751 39.09,20.805 38.864,20.819C38.287,20.83 37.71,20.839 37.134,20.845C37.128,21.421 37.12,21.998 37.108,22.574C37.094,22.8 37.04,23.018 36.933,23.219C36.847,23.381 36.73,23.527 36.591,23.647C36.453,23.767 36.292,23.862 36.119,23.924C35.985,23.973 35.843,24.002 35.701,24.01C35.142,24.045 34.598,23.755 34.315,23.272C34.19,23.058 34.125,22.821 34.11,22.574C34.099,21.998 34.09,21.421 34.084,20.845C33.508,20.839 32.931,20.83 32.355,20.819C32.129,20.805 31.911,20.751 31.71,20.644C31.548,20.557 31.402,20.441 31.282,20.302C31.162,20.163 31.067,20.002 31.005,19.83C30.956,19.695 30.927,19.554 30.919,19.412C30.884,18.853 31.174,18.309 31.657,18.026C31.871,17.9 32.108,17.836 32.355,17.821C32.931,17.809 33.508,17.801 34.084,17.795ZM56.159,7.514C56.164,6.937 56.173,6.36 56.184,5.784C56.194,5.62 56.224,5.46 56.283,5.307C56.431,4.923 56.736,4.612 57.116,4.456C57.269,4.394 57.428,4.361 57.591,4.348C57.653,4.345 57.713,4.345 57.775,4.348C57.939,4.361 58.098,4.394 58.25,4.456C58.63,4.612 58.936,4.923 59.083,5.307C59.142,5.46 59.172,5.62 59.182,5.784C59.194,6.36 59.202,6.937 59.208,7.514C59.785,7.519 60.361,7.528 60.938,7.54C61.184,7.555 61.421,7.619 61.635,7.745C61.759,7.817 61.871,7.907 61.969,8.011C62.353,8.418 62.477,9.022 62.287,9.548C62.225,9.721 62.131,9.882 62.01,10.021C61.89,10.16 61.744,10.276 61.582,10.362C61.381,10.469 61.164,10.523 60.938,10.537C60.361,10.549 59.785,10.558 59.208,10.563C59.202,11.14 59.194,11.716 59.182,12.293C59.168,12.519 59.114,12.737 59.007,12.937C58.921,13.099 58.804,13.245 58.665,13.365C58.527,13.486 58.366,13.58 58.193,13.643C57.667,13.833 57.063,13.708 56.655,13.324C56.551,13.227 56.462,13.114 56.389,12.991C56.264,12.777 56.2,12.54 56.184,12.293C56.173,11.716 56.164,11.14 56.159,10.563C55.582,10.558 55.005,10.549 54.429,10.537C54.182,10.522 53.945,10.458 53.731,10.332C53.248,10.049 52.958,9.505 52.993,8.947C53.001,8.804 53.031,8.663 53.079,8.529C53.142,8.356 53.236,8.195 53.356,8.056C53.476,7.917 53.622,7.801 53.784,7.715C53.985,7.608 54.203,7.554 54.429,7.54C55.005,7.528 55.582,7.519 56.159,7.514Z"
5
+ style="fill:#fff"/>
6
+
7
+ </svg>
8
+
@@ -0,0 +1,88 @@
1
+ import ApexCharts from 'apexcharts'
2
+ import * as Stimulus from "@hotwired/stimulus"
3
+ import {controllers} from "./controllers"
4
+
5
+ window.Apex = {
6
+ chart: {
7
+ foreColor: '#fff',
8
+ animations: {
9
+ enabled: false
10
+ },
11
+ toolbar: {
12
+ show: false
13
+ },
14
+ },
15
+ // colors: ["#7209b7"],
16
+ grid: {
17
+ borderColor: 'var(--divider)',
18
+ strokeDashArray: 4,
19
+ xaxis: {
20
+ lines: {
21
+ show: true
22
+ }
23
+ },
24
+ yaxis: {
25
+ lines: {
26
+ show: true
27
+ }
28
+ },
29
+ padding: {
30
+ top: 0,
31
+ right: 0,
32
+ bottom: 0,
33
+ left: 0
34
+ },
35
+ },
36
+ title: {
37
+ align: 'left',
38
+ offsetY: 20,
39
+ style: {
40
+ fontSize: '1rem',
41
+ fontWeight: 500,
42
+ fontFamily: 'inherit',
43
+ color: 'var(--white)'
44
+ }
45
+ },
46
+ stroke: {
47
+ width: 3,
48
+ curve: 'straight'
49
+ },
50
+ dataLabels: {
51
+ enabled: false
52
+ },
53
+ tooltip: {
54
+ x: {
55
+ format: 'dd MMM yyyy HH:mm'
56
+ },
57
+ theme: 'dark',
58
+ },
59
+ xaxis: {
60
+ type: 'datetime',
61
+ axisBorder: {
62
+ show: false,
63
+ },
64
+ axisTicks: {
65
+ show: false
66
+ },
67
+ crosshairs: {
68
+ width: 1
69
+ },
70
+ },
71
+ yaxis: {
72
+ decimalsInFloat: 0,
73
+ labels: {
74
+ offsetX: -10,
75
+ // align: 'left',
76
+ },
77
+ axisTicks: {
78
+ show: false
79
+ },
80
+ },
81
+ }
82
+ window.Stimulus = Stimulus
83
+
84
+ const application = Stimulus.Application.start()
85
+
86
+ Object.entries(controllers).forEach(([key, controller]) => {
87
+ application.register(key, controller)
88
+ })
@@ -0,0 +1,176 @@
1
+ import {Controller} from "@hotwired/stimulus";
2
+ import Apexcharts from "apexcharts";
3
+
4
+ const icicleChartOptions = function(controller) {
5
+ return {
6
+ chart: {
7
+ id: controller.element.id,
8
+ group: controller.groupValue,
9
+ type: 'rangeBar',
10
+ height: 300,
11
+ events: {
12
+ dataPointSelection: function(event, chartContext, config) {
13
+ controller.dispatch('selected', {detail: {
14
+ ...config.w.config.series[config.seriesIndex].data[config.dataPointIndex]
15
+ }})
16
+ }
17
+ },
18
+ },
19
+ title: {
20
+ text: controller.element.dataset.chartName,
21
+ },
22
+ plotOptions: {
23
+ bar: {
24
+ horizontal: true,
25
+ rangeBarGroupRows: true,
26
+ dataLabels: {
27
+ position: 'bottom'
28
+ },
29
+ // barHeight: '80%'
30
+ }
31
+ },
32
+ series: controller.series(),
33
+
34
+ xaxis: {
35
+
36
+ type: 'numeric',
37
+ position: 'top',
38
+ axisTicks: {
39
+ show: true
40
+ },
41
+ tooltip: {
42
+ enabled: true,
43
+ }
44
+ },
45
+ yaxis: {
46
+ labels: {
47
+ show: false,
48
+
49
+ },
50
+
51
+ },
52
+ tooltip: {
53
+ x: {
54
+ formatter: function (value, obj) {
55
+ if (obj) {
56
+ return obj.w.config.series[obj.seriesIndex].data[obj.dataPointIndex].event_name
57
+ } else {
58
+ return value + 'ms'
59
+
60
+ }
61
+ }
62
+ },
63
+ },
64
+ legend: {
65
+ position: 'right',
66
+ showForSingleSeries: true,
67
+ formatter: function (seriesName, opts) {
68
+
69
+ const seriesSelfTime = controller.series()[opts.seriesIndex].data.reduce((acc, val) => {
70
+ return acc + val['event_self_time']
71
+ }, 0)
72
+ console.log(controller.series()[opts.seriesIndex].name, controller.series()[opts.seriesIndex].data);
73
+ const totalSelfTime = controller.series().reduce((acc, val) => { return acc + val.data.reduce((acc, val) => { return acc + val['event_self_time'] }, 0) }, 0)
74
+ const percent = seriesSelfTime / totalSelfTime * 100
75
+ return `${seriesName} <span class="percent">${seriesSelfTime.toFixed(1)}ms <div class="bar"><div style="width:${percent.toFixed(1)}%"></div></div></span> `
76
+ },
77
+ itemMargin: {
78
+ horizontal: '14'
79
+ }
80
+ },
81
+ dataLabels: {
82
+ enabled: true,
83
+ formatter: function (value, {seriesIndex, dataPointIndex, w}) {
84
+ return `${w.config.series[seriesIndex].data[dataPointIndex].event_name} (${(value[1] - value[0]).toFixed(2)}ms)`
85
+ },
86
+ offsetX: 0,
87
+ textAnchor: 'start'
88
+ },
89
+ theme: {
90
+ palette: 'palette6',
91
+ },
92
+ stroke: {
93
+ width: 2,
94
+ curve: 'straight'
95
+ }
96
+ }
97
+
98
+ }
99
+
100
+ const defaultOptions = function(controller) {
101
+ return {
102
+ chart: {
103
+ id: controller.element.id,
104
+ group: controller.groupValue,
105
+ type: controller.typeValue,
106
+ height: 250,
107
+ },
108
+ title: {
109
+ text: controller.element.dataset.chartName,
110
+ },
111
+ series: controller.series(),
112
+ xaxis: {
113
+ min: controller.startXValue,
114
+ max: controller.endXValue,
115
+ type: 'datetime',
116
+ },
117
+ tooltip: {
118
+ x: {
119
+ format: 'dd MMM yyyy HH:mm'
120
+ },
121
+ },
122
+ fill: {
123
+ gradient: {
124
+ enabled: true,
125
+ opacityFrom: 0.55,
126
+ opacityTo: 0
127
+ }
128
+ },
129
+ theme: {
130
+ monochrome: {
131
+ enabled: true,
132
+ color: '#0c8be8',
133
+ shadeTo: 'dark',
134
+ shadeIntensity: 0.65
135
+ }
136
+ },
137
+ stroke: {
138
+ width: 2,
139
+ curve: 'straight'
140
+ }
141
+ }
142
+
143
+ }
144
+
145
+ export class ChartController extends Controller {
146
+ static targets = ["chart", "data"]
147
+
148
+ static values = {
149
+ type: String,
150
+ group: String,
151
+ palette: String,
152
+ startX: Number,
153
+ endX: Number,
154
+ }
155
+
156
+ chartOptions() {
157
+ switch (this.typeValue) {
158
+ case 'icicle':
159
+ return icicleChartOptions(this)
160
+ default:
161
+ return defaultOptions(this)
162
+ }
163
+ }
164
+
165
+ series() {
166
+ return this.dataTargets.map((target) => ({
167
+ name: target.dataset.seriesName,
168
+ data: JSON.parse(target.innerHTML)
169
+ }));
170
+ }
171
+
172
+ connect() {
173
+ this.chart = new Apexcharts(this.chartTarget, this.chartOptions())
174
+ this.chart.render();
175
+ }
176
+ }
@@ -0,0 +1,15 @@
1
+ import {Controller} from "@hotwired/stimulus";
2
+
3
+ export class EventDetailsController extends Controller {
4
+ static targets = ["tab"]
5
+
6
+ show(event) {
7
+ [...this.element.children].forEach(el => el.hidden = true)
8
+ const el = document.getElementById(event.detail.start_at)
9
+ if (el) {
10
+ el.hidden = false
11
+ }
12
+
13
+
14
+ }
15
+ }
@@ -0,0 +1,9 @@
1
+ import {ChartController} from "./chart_controller";
2
+ import {SparklineController} from "./sparkline_controller";
3
+ import {EventDetailsController} from "./event_details_controller";
4
+
5
+ export const controllers = {
6
+ "chart": ChartController,
7
+ "sparkline": SparklineController,
8
+ "event-details": EventDetailsController,
9
+ }
@@ -0,0 +1,72 @@
1
+ import {ChartController} from "./chart_controller";
2
+
3
+ export class SparklineController extends ChartController {
4
+
5
+ maxSeries() {
6
+ return this.series()[0].data.reduce((a, b) => Math.max(a, b[1]), 0)
7
+ }
8
+
9
+ chartOptions() {
10
+ return {
11
+ chart: {
12
+ type: this.typeValue,
13
+ height: 50,
14
+ sparkline: {
15
+ enabled: true
16
+ },
17
+ },
18
+ colors: ["#7209b7"],
19
+ series: this.series(),
20
+ xaxis: {
21
+ min: this.startXValue,
22
+ max: this.endXValue,
23
+ axisBorder: {
24
+ show: true,
25
+ height: 2,
26
+ color: 'var(--divider)',
27
+ },
28
+ },
29
+ yaxis: {
30
+ max: this.maxSeries(),
31
+ },
32
+ fill: {
33
+ gradient: {
34
+ enabled: true,
35
+ opacityFrom: 0.55,
36
+ opacityTo: 0
37
+ }
38
+ },
39
+ theme: {
40
+ monochrome: {
41
+ enabled: true,
42
+ color: '#ba181b',
43
+ shadeTo: 'dark',
44
+ shadeIntensity: 0.65
45
+ }
46
+ },
47
+ tooltip: {
48
+ fixed: {
49
+ enabled: false
50
+ },
51
+ x: {
52
+ show: true,
53
+ },
54
+ y: {
55
+ title: {
56
+ formatter: (seriesName) => 'Occurrences',
57
+ }
58
+ },
59
+ marker: {
60
+ show: false
61
+ },
62
+
63
+
64
+ },
65
+
66
+ stroke: {
67
+ width: 1,
68
+ curve: 'straight'
69
+ },
70
+ }
71
+ }
72
+ }
@@ -0,0 +1,51 @@
1
+ .card {
2
+ border-radius: 0.5rem;
3
+ background-color: var(--surface-card);
4
+ box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
5
+ border: 1px solid var(--divider);
6
+ padding: 0;
7
+
8
+ & h2 {
9
+ padding: 1rem;
10
+ margin: 0;
11
+ }
12
+
13
+ &:has(> table, >.\~scrollable>table) {
14
+
15
+ & table {
16
+ width: 100%;
17
+ border-spacing: 0;
18
+ white-space: nowrap;
19
+
20
+ & th {
21
+ text-align: left;
22
+ font-weight: 400;
23
+ padding: 0.5rem 1rem;
24
+ border-bottom: 1px solid var(--divider);
25
+
26
+ &:first-child {
27
+ border-top-left-radius: .5rem;
28
+ }
29
+
30
+ &:last-child {
31
+ border-top-right-radius: .5rem;
32
+ }
33
+
34
+ }
35
+
36
+ & tr:last-child td {
37
+ border-bottom: none;
38
+ /*padding-bottom: 1rem;*/
39
+ }
40
+
41
+ & td {
42
+ padding: .5rem 1rem;
43
+ border-bottom: 1px solid var(--divider);
44
+
45
+ & + & {
46
+ border-left: 1px solid var(--divider);
47
+ }
48
+ }
49
+ }
50
+ }
51
+ }
@@ -0,0 +1,34 @@
1
+ [data-chart-type-value="icicle"] {
2
+ .apexcharts-legend-series {
3
+ display:flex;
4
+ gap: .25rem;
5
+ align-items: center;
6
+ }
7
+ .apexcharts-legend-text {
8
+ display: flex;
9
+ flex-grow: 1;
10
+ align-items: center;
11
+ justify-content: space-between;
12
+ gap: 2rem;
13
+ padding-block: .25rem;
14
+
15
+ .percent {
16
+ display: flex;
17
+ gap: .5rem;
18
+ }
19
+
20
+ .bar {
21
+ width: 2rem;
22
+ height: 14px;
23
+ background-color: var(--surface-card);
24
+ & > div {
25
+ height: 100%;
26
+ background-color: var(--blue);
27
+ }
28
+ }
29
+ }
30
+ }
31
+
32
+ .chart {
33
+ overflow: hidden;
34
+ }
@@ -0,0 +1,62 @@
1
+ .dropdown {
2
+ position: relative;
3
+
4
+ & > ul {
5
+ background-color: var(--surface-dropdown);
6
+ opacity: 0;
7
+ visibility: hidden;
8
+ transform: translate(0, -1rem);
9
+ transition: opacity .2s ease-in-out, visibility .2s ease-in-out, transform .2s ease-in-out;
10
+ list-style: none;
11
+ margin: 0;
12
+ padding: 0;
13
+ position: absolute;
14
+ z-index: 100;
15
+ width: 100%;
16
+
17
+ & > li {
18
+
19
+ border-bottom: 1px solid var(--divider);
20
+ text-align: left;
21
+
22
+ &:last-child {
23
+ border-bottom: none;
24
+ }
25
+
26
+ & > a {
27
+ color: var(--white);
28
+ text-decoration: none;
29
+ font-weight: 200;
30
+ padding: .5rem .75rem;
31
+ display: flex;
32
+ align-items: center;
33
+ justify-content: space-between;
34
+
35
+ & svg {
36
+ display: none;
37
+ }
38
+
39
+ &.active {
40
+ font-weight: 400;
41
+
42
+ & svg {
43
+ display: block;
44
+ }
45
+ }
46
+
47
+
48
+ &:not(.active):hover {
49
+ background-color: var(--surface-hover);
50
+ }
51
+ }
52
+ }
53
+ }
54
+
55
+ &:focus-within {
56
+ & > ul {
57
+ opacity: 100;
58
+ visibility: visible;
59
+ transform: translate(0, 0);
60
+ }
61
+ }
62
+ }
@@ -0,0 +1,10 @@
1
+ .--scrollable {
2
+ overflow: auto;
3
+ }
4
+
5
+ .--sticky {
6
+ position: sticky;
7
+ top: 0;
8
+ background-color: var(--black);
9
+ z-index: 1;
10
+ }
@@ -0,0 +1,68 @@
1
+ .query-table {
2
+
3
+ display: grid;
4
+ --column-count: 10;
5
+ grid-template-columns: repeat(var(--column-count), auto);
6
+ grid-template-rows: min-content auto;
7
+
8
+ & .query-table-column {
9
+ padding: .5rem 1rem;
10
+ border-bottom: 1px solid var(--divider);
11
+ white-space: nowrap;
12
+
13
+ & + & {
14
+ border-left: 1px solid var(--divider);
15
+ }
16
+
17
+ &:first-child {
18
+ padding-left: 2rem;
19
+ }
20
+ &:last-child {
21
+ padding-right: 2rem;
22
+ }
23
+ }
24
+
25
+ & > header {
26
+ display: grid;
27
+ grid-template-columns: subgrid;
28
+ grid-column: -1 / 1;
29
+ flex-wrap: nowrap;
30
+ font-weight: var(--font-weight-bold);
31
+
32
+ }
33
+
34
+ .query-table-body {
35
+ display: grid;
36
+ grid-template-columns: subgrid;
37
+ grid-column: -1 / 1;
38
+ }
39
+
40
+ .query-table-row {
41
+ display: grid;
42
+ grid-template-columns: subgrid;
43
+ grid-column: -1 / 1;
44
+ }
45
+
46
+ & > table {
47
+ width: 100%;
48
+ border-spacing: 0;
49
+ white-space: nowrap;
50
+
51
+ & th {
52
+ text-align: left;
53
+ font-weight: 400;
54
+ padding: 0.5rem 1rem;
55
+ border-bottom: 1px solid var(--divider);
56
+ }
57
+
58
+ & td {
59
+ padding: .5rem 1rem;
60
+ border-bottom: 1px solid var(--divider);
61
+
62
+ & + & {
63
+ border-left: 1px solid var(--divider);
64
+ }
65
+ }
66
+ }
67
+
68
+ }