karafka-web 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (178) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +3 -0
  3. data/.coditsu/ci.yml +3 -0
  4. data/.diffend.yml +3 -0
  5. data/.github/FUNDING.yml +1 -0
  6. data/.github/ISSUE_TEMPLATE/bug_report.md +50 -0
  7. data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  8. data/.github/workflows/ci.yml +49 -0
  9. data/.gitignore +69 -0
  10. data/.ruby-gemset +1 -0
  11. data/.ruby-version +1 -0
  12. data/CHANGELOG.md +9 -0
  13. data/CODE_OF_CONDUCT.md +46 -0
  14. data/Gemfile +7 -0
  15. data/Gemfile.lock +52 -0
  16. data/LICENSE +17 -0
  17. data/README.md +29 -0
  18. data/bin/karafka-web +33 -0
  19. data/certs/cert_chain.pem +26 -0
  20. data/config/locales/errors.yml +9 -0
  21. data/karafka-web.gemspec +44 -0
  22. data/lib/karafka/web/app.rb +17 -0
  23. data/lib/karafka/web/config.rb +80 -0
  24. data/lib/karafka/web/deserializer.rb +20 -0
  25. data/lib/karafka/web/errors.rb +25 -0
  26. data/lib/karafka/web/installer.rb +124 -0
  27. data/lib/karafka/web/processing/consumer.rb +66 -0
  28. data/lib/karafka/web/processing/consumers/aggregator.rb +130 -0
  29. data/lib/karafka/web/processing/consumers/state.rb +32 -0
  30. data/lib/karafka/web/tracking/base_contract.rb +31 -0
  31. data/lib/karafka/web/tracking/consumers/contracts/consumer_group.rb +33 -0
  32. data/lib/karafka/web/tracking/consumers/contracts/job.rb +26 -0
  33. data/lib/karafka/web/tracking/consumers/contracts/partition.rb +22 -0
  34. data/lib/karafka/web/tracking/consumers/contracts/report.rb +95 -0
  35. data/lib/karafka/web/tracking/consumers/contracts/topic.rb +29 -0
  36. data/lib/karafka/web/tracking/consumers/listeners/base.rb +33 -0
  37. data/lib/karafka/web/tracking/consumers/listeners/errors.rb +107 -0
  38. data/lib/karafka/web/tracking/consumers/listeners/pausing.rb +45 -0
  39. data/lib/karafka/web/tracking/consumers/listeners/processing.rb +157 -0
  40. data/lib/karafka/web/tracking/consumers/listeners/statistics.rb +123 -0
  41. data/lib/karafka/web/tracking/consumers/listeners/status.rb +58 -0
  42. data/lib/karafka/web/tracking/consumers/sampler.rb +216 -0
  43. data/lib/karafka/web/tracking/memoized_shell.rb +48 -0
  44. data/lib/karafka/web/tracking/reporter.rb +144 -0
  45. data/lib/karafka/web/tracking/ttl_array.rb +59 -0
  46. data/lib/karafka/web/tracking/ttl_hash.rb +16 -0
  47. data/lib/karafka/web/ui/app.rb +78 -0
  48. data/lib/karafka/web/ui/base.rb +77 -0
  49. data/lib/karafka/web/ui/controllers/base.rb +40 -0
  50. data/lib/karafka/web/ui/controllers/become_pro.rb +17 -0
  51. data/lib/karafka/web/ui/controllers/cluster.rb +24 -0
  52. data/lib/karafka/web/ui/controllers/consumers.rb +27 -0
  53. data/lib/karafka/web/ui/controllers/errors.rb +43 -0
  54. data/lib/karafka/web/ui/controllers/jobs.rb +33 -0
  55. data/lib/karafka/web/ui/controllers/requests/params.rb +30 -0
  56. data/lib/karafka/web/ui/controllers/responses/data.rb +26 -0
  57. data/lib/karafka/web/ui/controllers/routing.rb +30 -0
  58. data/lib/karafka/web/ui/helpers/application_helper.rb +144 -0
  59. data/lib/karafka/web/ui/lib/hash_proxy.rb +66 -0
  60. data/lib/karafka/web/ui/lib/paginate_array.rb +38 -0
  61. data/lib/karafka/web/ui/models/consumer_group.rb +20 -0
  62. data/lib/karafka/web/ui/models/health.rb +44 -0
  63. data/lib/karafka/web/ui/models/job.rb +13 -0
  64. data/lib/karafka/web/ui/models/message.rb +99 -0
  65. data/lib/karafka/web/ui/models/partition.rb +13 -0
  66. data/lib/karafka/web/ui/models/process.rb +56 -0
  67. data/lib/karafka/web/ui/models/processes.rb +86 -0
  68. data/lib/karafka/web/ui/models/state.rb +67 -0
  69. data/lib/karafka/web/ui/models/topic.rb +19 -0
  70. data/lib/karafka/web/ui/pro/app.rb +120 -0
  71. data/lib/karafka/web/ui/pro/controllers/cluster.rb +16 -0
  72. data/lib/karafka/web/ui/pro/controllers/consumers.rb +54 -0
  73. data/lib/karafka/web/ui/pro/controllers/dlq.rb +44 -0
  74. data/lib/karafka/web/ui/pro/controllers/errors.rb +57 -0
  75. data/lib/karafka/web/ui/pro/controllers/explorer.rb +79 -0
  76. data/lib/karafka/web/ui/pro/controllers/health.rb +33 -0
  77. data/lib/karafka/web/ui/pro/controllers/jobs.rb +26 -0
  78. data/lib/karafka/web/ui/pro/controllers/routing.rb +26 -0
  79. data/lib/karafka/web/ui/pro/views/consumers/_breadcrumbs.erb +27 -0
  80. data/lib/karafka/web/ui/pro/views/consumers/_consumer.erb +60 -0
  81. data/lib/karafka/web/ui/pro/views/consumers/_counters.erb +50 -0
  82. data/lib/karafka/web/ui/pro/views/consumers/_summary.erb +81 -0
  83. data/lib/karafka/web/ui/pro/views/consumers/consumer/_consumer_group.erb +109 -0
  84. data/lib/karafka/web/ui/pro/views/consumers/consumer/_job.erb +26 -0
  85. data/lib/karafka/web/ui/pro/views/consumers/consumer/_metrics.erb +126 -0
  86. data/lib/karafka/web/ui/pro/views/consumers/consumer/_no_jobs.erb +9 -0
  87. data/lib/karafka/web/ui/pro/views/consumers/consumer/_no_subscriptions.erb +9 -0
  88. data/lib/karafka/web/ui/pro/views/consumers/consumer/_partition.erb +32 -0
  89. data/lib/karafka/web/ui/pro/views/consumers/consumer/_stopped.erb +10 -0
  90. data/lib/karafka/web/ui/pro/views/consumers/consumer/_tabs.erb +20 -0
  91. data/lib/karafka/web/ui/pro/views/consumers/index.erb +30 -0
  92. data/lib/karafka/web/ui/pro/views/consumers/jobs.erb +42 -0
  93. data/lib/karafka/web/ui/pro/views/consumers/subscriptions.erb +23 -0
  94. data/lib/karafka/web/ui/pro/views/dlq/_breadcrumbs.erb +5 -0
  95. data/lib/karafka/web/ui/pro/views/dlq/_no_topics.erb +9 -0
  96. data/lib/karafka/web/ui/pro/views/dlq/_topic.erb +12 -0
  97. data/lib/karafka/web/ui/pro/views/dlq/index.erb +16 -0
  98. data/lib/karafka/web/ui/pro/views/errors/_breadcrumbs.erb +25 -0
  99. data/lib/karafka/web/ui/pro/views/errors/_detail.erb +29 -0
  100. data/lib/karafka/web/ui/pro/views/errors/_error.erb +26 -0
  101. data/lib/karafka/web/ui/pro/views/errors/_partition_option.erb +7 -0
  102. data/lib/karafka/web/ui/pro/views/errors/index.erb +58 -0
  103. data/lib/karafka/web/ui/pro/views/errors/show.erb +56 -0
  104. data/lib/karafka/web/ui/pro/views/explorer/_breadcrumbs.erb +29 -0
  105. data/lib/karafka/web/ui/pro/views/explorer/_detail.erb +21 -0
  106. data/lib/karafka/web/ui/pro/views/explorer/_encryption_enabled.erb +18 -0
  107. data/lib/karafka/web/ui/pro/views/explorer/_failed_deserialization.erb +4 -0
  108. data/lib/karafka/web/ui/pro/views/explorer/_message.erb +16 -0
  109. data/lib/karafka/web/ui/pro/views/explorer/_partition_option.erb +7 -0
  110. data/lib/karafka/web/ui/pro/views/explorer/_topic.erb +12 -0
  111. data/lib/karafka/web/ui/pro/views/explorer/index.erb +17 -0
  112. data/lib/karafka/web/ui/pro/views/explorer/partition.erb +56 -0
  113. data/lib/karafka/web/ui/pro/views/explorer/show.erb +65 -0
  114. data/lib/karafka/web/ui/pro/views/health/_breadcrumbs.erb +5 -0
  115. data/lib/karafka/web/ui/pro/views/health/_partition.erb +35 -0
  116. data/lib/karafka/web/ui/pro/views/health/index.erb +60 -0
  117. data/lib/karafka/web/ui/pro/views/jobs/_breadcrumbs.erb +5 -0
  118. data/lib/karafka/web/ui/pro/views/jobs/_job.erb +31 -0
  119. data/lib/karafka/web/ui/pro/views/jobs/_no_jobs.erb +9 -0
  120. data/lib/karafka/web/ui/pro/views/jobs/index.erb +34 -0
  121. data/lib/karafka/web/ui/pro/views/shared/_navigation.erb +57 -0
  122. data/lib/karafka/web/ui/public/images/favicon.ico +0 -0
  123. data/lib/karafka/web/ui/public/images/logo.svg +28 -0
  124. data/lib/karafka/web/ui/public/javascripts/application.js +41 -0
  125. data/lib/karafka/web/ui/public/javascripts/bootstrap.min.js +7 -0
  126. data/lib/karafka/web/ui/public/javascripts/highlight.min.js +337 -0
  127. data/lib/karafka/web/ui/public/javascripts/live_poll.js +124 -0
  128. data/lib/karafka/web/ui/public/javascripts/timeago.min.js +1 -0
  129. data/lib/karafka/web/ui/public/stylesheets/application.css +106 -0
  130. data/lib/karafka/web/ui/public/stylesheets/bootstrap.min.css +7 -0
  131. data/lib/karafka/web/ui/public/stylesheets/bootstrap.min.css.map +1 -0
  132. data/lib/karafka/web/ui/public/stylesheets/highlight.min.css +10 -0
  133. data/lib/karafka/web/ui/views/cluster/_breadcrumbs.erb +5 -0
  134. data/lib/karafka/web/ui/views/cluster/_broker.erb +5 -0
  135. data/lib/karafka/web/ui/views/cluster/_partition.erb +22 -0
  136. data/lib/karafka/web/ui/views/cluster/index.erb +72 -0
  137. data/lib/karafka/web/ui/views/consumers/_breadcrumbs.erb +27 -0
  138. data/lib/karafka/web/ui/views/consumers/_consumer.erb +43 -0
  139. data/lib/karafka/web/ui/views/consumers/_counters.erb +44 -0
  140. data/lib/karafka/web/ui/views/consumers/_summary.erb +81 -0
  141. data/lib/karafka/web/ui/views/consumers/consumer/_consumer_group.erb +109 -0
  142. data/lib/karafka/web/ui/views/consumers/consumer/_job.erb +26 -0
  143. data/lib/karafka/web/ui/views/consumers/consumer/_metrics.erb +126 -0
  144. data/lib/karafka/web/ui/views/consumers/consumer/_no_jobs.erb +9 -0
  145. data/lib/karafka/web/ui/views/consumers/consumer/_no_subscriptions.erb +9 -0
  146. data/lib/karafka/web/ui/views/consumers/consumer/_partition.erb +32 -0
  147. data/lib/karafka/web/ui/views/consumers/consumer/_stopped.erb +10 -0
  148. data/lib/karafka/web/ui/views/consumers/consumer/_tabs.erb +20 -0
  149. data/lib/karafka/web/ui/views/consumers/index.erb +29 -0
  150. data/lib/karafka/web/ui/views/errors/_breadcrumbs.erb +19 -0
  151. data/lib/karafka/web/ui/views/errors/_detail.erb +29 -0
  152. data/lib/karafka/web/ui/views/errors/_error.erb +26 -0
  153. data/lib/karafka/web/ui/views/errors/index.erb +38 -0
  154. data/lib/karafka/web/ui/views/errors/show.erb +30 -0
  155. data/lib/karafka/web/ui/views/jobs/_breadcrumbs.erb +5 -0
  156. data/lib/karafka/web/ui/views/jobs/_job.erb +22 -0
  157. data/lib/karafka/web/ui/views/jobs/_no_jobs.erb +9 -0
  158. data/lib/karafka/web/ui/views/jobs/index.erb +31 -0
  159. data/lib/karafka/web/ui/views/layout.erb +23 -0
  160. data/lib/karafka/web/ui/views/routing/_breadcrumbs.erb +15 -0
  161. data/lib/karafka/web/ui/views/routing/_consumer_group.erb +34 -0
  162. data/lib/karafka/web/ui/views/routing/_detail.erb +25 -0
  163. data/lib/karafka/web/ui/views/routing/_topic.erb +18 -0
  164. data/lib/karafka/web/ui/views/routing/index.erb +10 -0
  165. data/lib/karafka/web/ui/views/routing/show.erb +26 -0
  166. data/lib/karafka/web/ui/views/shared/_become_pro.erb +13 -0
  167. data/lib/karafka/web/ui/views/shared/_brand.erb +3 -0
  168. data/lib/karafka/web/ui/views/shared/_content.erb +31 -0
  169. data/lib/karafka/web/ui/views/shared/_header.erb +20 -0
  170. data/lib/karafka/web/ui/views/shared/_navigation.erb +57 -0
  171. data/lib/karafka/web/ui/views/shared/_pagination.erb +21 -0
  172. data/lib/karafka/web/ui/views/shared/exceptions/not_found.erb +39 -0
  173. data/lib/karafka/web/ui/views/shared/exceptions/pro_only.erb +52 -0
  174. data/lib/karafka/web/version.rb +8 -0
  175. data/lib/karafka/web.rb +60 -0
  176. data.tar.gz.sig +0 -0
  177. metadata +328 -0
  178. metadata.gz.sig +0 -0
@@ -0,0 +1,9 @@
1
+ <div class="container mb-4">
2
+ <div class="row">
3
+ <div class="col-lg-12">
4
+ <div class="alert alert-info" role="alert">
5
+ No Dead Letter Queue topics exist in Kafka.
6
+ </div>
7
+ </div>
8
+ </div>
9
+ </div>
@@ -0,0 +1,12 @@
1
+ <div class="col">
2
+ <div class="card" >
3
+ <div class="card-body p-2">
4
+ <p class="card-text mb-0 p-2">
5
+ <a href="<%= root_path('explorer', topic[:topic_name], 0) %>">
6
+ <%= topic[:topic_name] %> /
7
+ <%= topic[:partition_count] %>
8
+ </a>
9
+ </p>
10
+ </div>
11
+ </div>
12
+ </div>
@@ -0,0 +1,16 @@
1
+ <%== view_title('Dead Letter Queue topics', hr: true) %>
2
+
3
+ <% if @dlq_topics.empty? %>
4
+ <%== partial 'dlq/no_topics' %>
5
+ <% else %>
6
+ <div class="container">
7
+ <div class="row mb-5 row-cols-1 row-cols-md-4 g-4">
8
+ <%==
9
+ each_partial(
10
+ @dlq_topics,
11
+ 'dlq/topic'
12
+ )
13
+ %>
14
+ </div>
15
+ </div>
16
+ <% end %>
@@ -0,0 +1,25 @@
1
+ <li class="breadcrumb-item">
2
+ <a href="<%= root_path('errors', 0) %>">
3
+ Errors
4
+ </a>
5
+ </li>
6
+
7
+ <li class="breadcrumb-item">
8
+ <a href="<%= root_path('errors', @partition_id) %>">
9
+ Partition <%= @partition_id %>
10
+ </a>
11
+ </li>
12
+
13
+ <% if @offset %>
14
+ <li class="breadcrumb-item">
15
+ <a href="<%= root_path('errors', @partition_id, @offset) %>">
16
+ <%=
17
+ type = @error_message.payload[:type]
18
+ error_class = @error_message.payload[:error_class]
19
+ offset = @error_message.offset
20
+
21
+ "#{type}: #{error_class} #{offset}"
22
+ %>
23
+ </a>
24
+ </li>
25
+ <% end %>
@@ -0,0 +1,29 @@
1
+ <% if v.is_a?(Hash) %>
2
+ <% v.each do |k2, v2| %>
3
+ <tr>
4
+ <td>
5
+ <%= "#{k}.#{k2}" %>
6
+ </td>
7
+ <td>
8
+ <% if k2.to_s.include?('ssl') %>
9
+ ***
10
+ <% else %>
11
+ <%= v2 %>
12
+ <% end %>
13
+ </td>
14
+ </tr>
15
+ <% end %>
16
+ <% else %>
17
+ <tr>
18
+ <td>
19
+ <%= k %>
20
+ </td>
21
+ <td>
22
+ <% if k == :occurred_at %>
23
+ <%== relative_time v %>
24
+ <% else %>
25
+ <%= v %>
26
+ <% end %>
27
+ </td>
28
+ </tr>
29
+ <% end %>
@@ -0,0 +1,26 @@
1
+ <% error = error_msg.payload %>
2
+
3
+ <tr>
4
+ <td>
5
+ <% if error[:details].key?(:topic) %>
6
+ <%= error[:details][:topic] %>: <%= error[:details][:partition] %>
7
+ <% else %>
8
+ <%= error[:type] %>
9
+ <% end %>
10
+ </td>
11
+ <td>
12
+ <%== error[:process_name] %>
13
+ </td>
14
+ <td>
15
+ <%= error[:error_class] %>:
16
+ <%= error[:error_message].first(200) %>
17
+ </td>
18
+ <td>
19
+ <%== relative_time error[:occurred_at] %>
20
+ </td>
21
+ <td>
22
+ <a href="<%= root_path('errors', error_msg.partition, error_msg.offset) %>" class="btn btn-sm btn-secondary text-white">
23
+ Details
24
+ </a>
25
+ </td>
26
+ </tr>
@@ -0,0 +1,7 @@
1
+ <% if @partition_id == partition %>
2
+ <option value="<%= root_path('errors', partition) %>" selected=selected>
3
+ <% else %>
4
+ <option value="<%= root_path('errors', partition) %>">
5
+ <% end %>
6
+ <%= partition %>
7
+ </option>
@@ -0,0 +1,58 @@
1
+ <div class="container mb-5">
2
+ <div class="row">
3
+ <div class="col">
4
+ <h3>
5
+ Errors
6
+ </h3>
7
+ </div>
8
+
9
+ <div class="col">
10
+ <div class="col-auto text-end">
11
+ <label class="col-form-label">Partition</label>
12
+ </div>
13
+ </div>
14
+
15
+ <div class="col pt-1 mb-0 pb-0">
16
+ <div class="col-auto">
17
+ <select class="form-select form-select-sm mb-0 form-control" id="current-partition">
18
+ <%==
19
+ each_partial(
20
+ @partitions_count.times.to_a,
21
+ 'errors/partition_option',
22
+ local: :partition
23
+ )
24
+ %>
25
+ </select>
26
+ </div>
27
+ </div>
28
+ </div>
29
+
30
+ <hr>
31
+ </div>
32
+
33
+ <div class="container">
34
+ <div class="row mb-5">
35
+ <div class="col-sm-12">
36
+ <table class="processes bg-white table table-hover table-bordered table-striped mb-0 align-middle">
37
+ <thead>
38
+ <tr class="align-middle">
39
+ <th>Origin</th>
40
+ <th>Process name</th>
41
+ <th>Error</th>
42
+ <th>Occurred at</th>
43
+ <th></th>
44
+ </tr>
45
+ </thead>
46
+ <tbody>
47
+ <%==
48
+ each_partial(
49
+ @error_messages,
50
+ 'errors/error',
51
+ local: :error_msg
52
+ )
53
+ %>
54
+ </tbody>
55
+ </table>
56
+ </div>
57
+ </div>
58
+ </div>
@@ -0,0 +1,56 @@
1
+ <%==
2
+ type = @error_message.payload[:type]
3
+ error_class = @error_message.payload[:error_class]
4
+ offset = @error_message.offset
5
+
6
+ view_title("#{type}: #{error_class} #{offset}")
7
+ %>
8
+
9
+ <div class="container">
10
+ <div class="row mb-4">
11
+ <div class="col-sm-12">
12
+ <h5 class="mb-2">
13
+ Metadata
14
+ </h5>
15
+ <hr/>
16
+ </div>
17
+ </div>
18
+
19
+ <div class="row mb-5">
20
+ <div class="col-sm-12 table-responsive">
21
+ <table class="processes bg-white table table-hover table-bordered table-striped mb-0 align-middle">
22
+ <tbody>
23
+ <% @error_message.payload.each do |k, v| %>
24
+ <% next if k == :backtrace %>
25
+ <%==
26
+ partial(
27
+ 'errors/detail',
28
+ locals: {
29
+ k: k,
30
+ v: v
31
+ }
32
+ )
33
+ %>
34
+ <% end %>
35
+ </tbody>
36
+ </table>
37
+ </div>
38
+ </div>
39
+ <div class="row mb-4">
40
+ <div class="col-sm-12">
41
+ <h5 class="mb-2">
42
+ Backtrace
43
+ </h5>
44
+ <hr/>
45
+ </div>
46
+ </div>
47
+ <div class="row mb-4">
48
+ <div class="col-sm-12">
49
+ <div class="card">
50
+ <div class="card-body">
51
+ <pre class="m-0 p-0"><code class="wrapped json p-0 m-0"><%= @error_message.payload[:backtrace] %></code></pre>
52
+ </div>
53
+ </div>
54
+ </div>
55
+ </div>
56
+ </div>
@@ -0,0 +1,29 @@
1
+ <li class="breadcrumb-item">
2
+ <a href="<%= root_path('explorer') %>">
3
+ Explorer
4
+ </a>
5
+ </li>
6
+
7
+ <% if @topic_id %>
8
+ <li class="breadcrumb-item">
9
+ <a href="<%= root_path('explorer', @topic_id, 0) %>">
10
+ <%= @topic_id %>
11
+ </a>
12
+ </li>
13
+ <% end %>
14
+
15
+ <% if @partition_id %>
16
+ <li class="breadcrumb-item">
17
+ <a href="<%= root_path('explorer', @topic_id, @partition_id) %>">
18
+ Partition <%= @partition_id %>
19
+ </a>
20
+ </li>
21
+ <% end %>
22
+
23
+ <% if @offset %>
24
+ <li class="breadcrumb-item active">
25
+ <a href="<%= root_path('explorer', @topic_id, @partition_id, @offset) %>">
26
+ <%= @offset %>
27
+ </a>
28
+ </li>
29
+ <% end %>
@@ -0,0 +1,21 @@
1
+ <% if v.is_a?(Hash) && !v.empty? %>
2
+ <% v.each do |k2,v2| %>
3
+ <tr class="align-middle">
4
+ <td>
5
+ <%= "#{k}.#{k2}" %>
6
+ </td>
7
+ <td>
8
+ <%= v2 %>
9
+ </td>
10
+ </tr>
11
+ <% end %>
12
+ <% else %>
13
+ <tr>
14
+ <td>
15
+ <%= k %>
16
+ </td>
17
+ <td>
18
+ <%= object_value_to_s(v) %>
19
+ </td>
20
+ </tr>
21
+ <% end %>
@@ -0,0 +1,18 @@
1
+ <div class="row">
2
+ <div class="col-sm-12">
3
+ <div class="alert alert-warning" role="alert">
4
+ <h4 class="alert-heading">
5
+ The payload cannot be displayed.
6
+ </h4>
7
+ <p>
8
+ Encryption is enabled.
9
+ </p>
10
+ <hr>
11
+ <p class="mb-0">
12
+ When encryption is enabled, the payload is not visible via the web UI.
13
+
14
+ Please set the <code>ui.decrypt</code> config option to <code>true</code> if you want the payload to be visible here.
15
+ </p>
16
+ </div>
17
+ </div>
18
+ </div>
@@ -0,0 +1,4 @@
1
+ <div class="alert alert-warning" role="alert">
2
+ We could not deserialize the data due to the following error:
3
+ <code><%= @payload_error.class %></code>. Raw payload displayed instead.
4
+ </div>
@@ -0,0 +1,16 @@
1
+ <tr>
2
+ <td>
3
+ <%= message.offset %>
4
+ </td>
5
+ <td>
6
+ <%== relative_time message.timestamp %>
7
+ </td>
8
+ <td>
9
+ <%= message.key %>
10
+ </td>
11
+ <td class="text-center">
12
+ <a href="<%= root_path('explorer', message.topic, message.partition, message.offset) %>" class="btn btn-sm btn-secondary">
13
+ Details
14
+ </a>
15
+ </td>
16
+ </tr>
@@ -0,0 +1,7 @@
1
+ <% if @partition_id == partition %>
2
+ <option value="<%= root_path('explorer', @topic_id, partition) %>" selected=selected>
3
+ <% else %>
4
+ <option value="<%= root_path('explorer', @topic_id, partition) %>">
5
+ <% end %>
6
+ <%= partition %>
7
+ </option>
@@ -0,0 +1,12 @@
1
+ <div class="col">
2
+ <div class="card" >
3
+ <div class="card-body p-2">
4
+ <p class="card-text mb-0 p-2">
5
+ <a href="<%= root_path('explorer', topic[:topic_name], 0) %>">
6
+ <%= topic[:topic_name] %> /
7
+ <%= topic[:partition_count] %>
8
+ </a>
9
+ </p>
10
+ </div>
11
+ </div>
12
+ </div>
@@ -0,0 +1,17 @@
1
+ <div class="container mb-5">
2
+ <div class="row">
3
+ <h3>Explorer</h3>
4
+ </div>
5
+ <hr>
6
+ </div>
7
+
8
+ <div class="container">
9
+ <div class="row mb-5 row-cols-1 row-cols-md-4 g-4">
10
+ <%==
11
+ each_partial(
12
+ @topics,
13
+ 'explorer/topic'
14
+ )
15
+ %>
16
+ </div>
17
+ </div>
@@ -0,0 +1,56 @@
1
+ <div class="container mb-5">
2
+ <div class="row">
3
+ <div class="col">
4
+ <h3>
5
+ <%= @topic_id %>
6
+ </h3>
7
+ </div>
8
+
9
+ <div class="col">
10
+ <div class="col-auto text-end">
11
+ <label class="col-form-label">Partition</label>
12
+ </div>
13
+ </div>
14
+
15
+ <div class="col pt-1 mb-0 pb-0">
16
+ <div class="col-auto">
17
+ <select class="form-select form-select-sm mb-0 form-control" id="current-partition">
18
+ <%==
19
+ each_partial(
20
+ @partitions_count.times.to_a,
21
+ 'explorer/partition_option',
22
+ local: :partition
23
+ )
24
+ %>
25
+ </select>
26
+ </div>
27
+ </div>
28
+ </div>
29
+
30
+ <hr>
31
+ </div>
32
+
33
+ <div class="container">
34
+ <div class="row mb-5">
35
+ <div class="col-sm-12">
36
+ <table class="processes bg-white table table-hover table-bordered table-striped mb-0 align-middle">
37
+ <thead>
38
+ <tr class="align-middle">
39
+ <th>Offset</th>
40
+ <th>Timestamp</th>
41
+ <th>Key</th>
42
+ <th></th>
43
+ </tr>
44
+ </thead>
45
+ <tbody>
46
+ <%==
47
+ each_partial(
48
+ @messages,
49
+ 'explorer/message'
50
+ )
51
+ %>
52
+ </tbody>
53
+ </table>
54
+ </div>
55
+ </div>
56
+ </div>
@@ -0,0 +1,65 @@
1
+ <div class="container">
2
+ <div class="row mb-4">
3
+ <div class="col-sm-12">
4
+ <h5 class="mb-2">
5
+ Metadata
6
+ </h5>
7
+ <hr/>
8
+
9
+ </div>
10
+ </div>
11
+
12
+ <div class="row mb-5">
13
+ <div class="col-sm-12">
14
+ <table class="processes bg-white table table-hover table-bordered table-striped mb-0 align-middle">
15
+ <tbody>
16
+ <% @message.metadata.to_h.except(:received_at).each do |k, v| %>
17
+ <%==
18
+ partial(
19
+ 'explorer/detail',
20
+ locals: {
21
+ k: k,
22
+ v: v
23
+ }
24
+ )
25
+ %>
26
+ <% end %>
27
+ </tbody>
28
+ </table>
29
+ </div>
30
+ </div>
31
+ </div>
32
+
33
+ <div class="container">
34
+ <div class="row mb-4">
35
+ <div class="col-sm-12">
36
+ <h5 class="mb-2">
37
+ Payload
38
+ </h5>
39
+ <hr/>
40
+
41
+ </div>
42
+ </div>
43
+
44
+ <% if @decrypt %>
45
+ <div class="row">
46
+ <div class="col-sm-12">
47
+ <% if @payload_error %>
48
+ <%== partial 'explorer/failed_deserialization' %>
49
+ <% end %>
50
+
51
+ <div class="card">
52
+ <div class="card-body">
53
+ <% if @payload_error %>
54
+ <pre class="m-0 p-0"><code class="wrapped json p-0 m-0"><%= @message.raw_payload %></code></pre>
55
+ <% else %>
56
+ <pre class="m-0 p-0"><code class="wrapped json p-0 m-0"><%= @pretty_payload %></code></pre>
57
+ <% end %>
58
+ </div>
59
+ </div>
60
+ </div>
61
+ </div>
62
+ <% else %>
63
+ <%== partial 'explorer/encryption_enabled' %>
64
+ <% end %>
65
+ </div>
@@ -0,0 +1,5 @@
1
+ <li class="breadcrumb-item">
2
+ <a href="<%= root_path('health') %>">
3
+ Consumers groups health
4
+ </a>
5
+ </li>
@@ -0,0 +1,35 @@
1
+ <tr class="align-middle status-row-<%= details[:process].status %>">
2
+ <td>
3
+ <%= topic_name %>
4
+ </td>
5
+ <td>
6
+ <%= partition_id %>
7
+ </td>
8
+ <td><%= details[:lag_stored] %></td>
9
+ <td>
10
+ <span class="badge <%= lag_trend_bg(details[:lag_stored_d]) %>">
11
+ <%= details[:lag_stored_d] %>
12
+ </span>
13
+ </td>
14
+ <td>
15
+ <%= details[:committed_offset] %>
16
+ </td>
17
+ <td>
18
+ <%= details[:stored_offset] %>
19
+ </td>
20
+ <td>
21
+ <span class="badge <%= kafka_state_bg(details[:fetch_state]) %> mt-1 mb-1">
22
+ <%= details[:fetch_state] %>
23
+ </span>
24
+ </td>
25
+ <td>
26
+ <span class="badge <%= kafka_state_bg(details[:poll_state]) %> mt-1 mb-1">
27
+ <%= details[:poll_state] %>
28
+ </span>
29
+ </td>
30
+ <td>
31
+ <a href="<%= root_path('consumers', details[:process].id, 'subscriptions') %>">
32
+ <%= details[:process].name %>
33
+ </a>
34
+ </td>
35
+ </tr>
@@ -0,0 +1,60 @@
1
+ <%== view_title('Consumers groups health') %>
2
+
3
+ <% if @stats.empty? %>
4
+ <div class="container mb-4">
5
+ <div class="row">
6
+ <div class="col-lg-12">
7
+ <div class="alert alert-info" role="alert">
8
+ No health data is available. It may mean no processes are running.
9
+ </div>
10
+ </div>
11
+ </div>
12
+ </div>
13
+ <% end %>
14
+
15
+ <% @stats.each do |cg_name, details| %>
16
+ <div class="container mb-5">
17
+ <div class="row mb-3">
18
+ <div class="col-sm-12">
19
+ <h4 class="mb-4"><%= cg_name %></h4>
20
+ <hr/>
21
+ </div>
22
+ </div>
23
+
24
+ <div class="row mb-5">
25
+ <div class="col-sm-12">
26
+ <table class="processes bg-white table table-hover table-bordered table-striped mb-0 align-middle">
27
+ <thead>
28
+ <tr class="align-middle">
29
+ <th class="align-middle">Topic</th>
30
+ <th>Partition</th>
31
+ <th>Lag stored</th>
32
+ <th>Lag trend</th>
33
+ <th>Committed offset</th>
34
+ <th>Stored offset</th>
35
+ <th>Fetch state</th>
36
+ <th>Poll state</th>
37
+ <th>Process name</th>
38
+ </tr>
39
+ </thead>
40
+ <tbody>
41
+ <% details.sort_by(&:first).each do |topic_name, partitions| %>
42
+ <% partitions.sort_by(&:first).each do |partition_id, details| %>
43
+ <%==
44
+ partial(
45
+ 'health/partition',
46
+ locals: {
47
+ topic_name: topic_name,
48
+ partition_id: partition_id,
49
+ details: details
50
+ }
51
+ )
52
+ %>
53
+ <% end %>
54
+ <% end %>
55
+ </tbody>
56
+ </table>
57
+ </div>
58
+ </div>
59
+ </div>
60
+ <% end %>
@@ -0,0 +1,5 @@
1
+ <li class="breadcrumb-item">
2
+ <a href="<%= root_path('jobs') %>">
3
+ Running jobs
4
+ </a>
5
+ </li>
@@ -0,0 +1,31 @@
1
+ <tr>
2
+ <td>
3
+ <a href="<%= root_path('consumers', job.process.id, 'subscriptions') %>">
4
+ <%= job.process.name %>
5
+ </a>
6
+ </td>
7
+ <td>
8
+ <span class="badge bg-secondary badge-topic" title="Consumer group: <%= job.consumer_group %>">
9
+ <%= job.topic %>:
10
+ <%= job.partition %>
11
+ </span>
12
+ </td>
13
+ <td>
14
+ <code><%= job.consumer %></code>
15
+ </td>
16
+ <td>
17
+ <code>#<%= job.type %></code>
18
+ </td>
19
+ <td>
20
+ <%= job.first_offset %>
21
+ </td>
22
+ <td>
23
+ <%= job.last_offset %>
24
+ </td>
25
+ <td>
26
+ <%= job.comitted_offset %>
27
+ </td>
28
+ <td>
29
+ <%== relative_time job.started_at %>
30
+ </td>
31
+ </tr>
@@ -0,0 +1,9 @@
1
+ <div class="container mb-4">
2
+ <div class="row">
3
+ <div class="col-lg-12">
4
+ <div class="alert alert-info" role="alert">
5
+ There are no running jobs at the moment.
6
+ </div>
7
+ </div>
8
+ </div>
9
+ </div>