karafka-web 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +3 -0
- data/.coditsu/ci.yml +3 -0
- data/.diffend.yml +3 -0
- data/.github/FUNDING.yml +1 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +50 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- data/.github/workflows/ci.yml +49 -0
- data/.gitignore +69 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +9 -0
- data/CODE_OF_CONDUCT.md +46 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +52 -0
- data/LICENSE +17 -0
- data/README.md +29 -0
- data/bin/karafka-web +33 -0
- data/certs/cert_chain.pem +26 -0
- data/config/locales/errors.yml +9 -0
- data/karafka-web.gemspec +44 -0
- data/lib/karafka/web/app.rb +17 -0
- data/lib/karafka/web/config.rb +80 -0
- data/lib/karafka/web/deserializer.rb +20 -0
- data/lib/karafka/web/errors.rb +25 -0
- data/lib/karafka/web/installer.rb +124 -0
- data/lib/karafka/web/processing/consumer.rb +66 -0
- data/lib/karafka/web/processing/consumers/aggregator.rb +130 -0
- data/lib/karafka/web/processing/consumers/state.rb +32 -0
- data/lib/karafka/web/tracking/base_contract.rb +31 -0
- data/lib/karafka/web/tracking/consumers/contracts/consumer_group.rb +33 -0
- data/lib/karafka/web/tracking/consumers/contracts/job.rb +26 -0
- data/lib/karafka/web/tracking/consumers/contracts/partition.rb +22 -0
- data/lib/karafka/web/tracking/consumers/contracts/report.rb +95 -0
- data/lib/karafka/web/tracking/consumers/contracts/topic.rb +29 -0
- data/lib/karafka/web/tracking/consumers/listeners/base.rb +33 -0
- data/lib/karafka/web/tracking/consumers/listeners/errors.rb +107 -0
- data/lib/karafka/web/tracking/consumers/listeners/pausing.rb +45 -0
- data/lib/karafka/web/tracking/consumers/listeners/processing.rb +157 -0
- data/lib/karafka/web/tracking/consumers/listeners/statistics.rb +123 -0
- data/lib/karafka/web/tracking/consumers/listeners/status.rb +58 -0
- data/lib/karafka/web/tracking/consumers/sampler.rb +216 -0
- data/lib/karafka/web/tracking/memoized_shell.rb +48 -0
- data/lib/karafka/web/tracking/reporter.rb +144 -0
- data/lib/karafka/web/tracking/ttl_array.rb +59 -0
- data/lib/karafka/web/tracking/ttl_hash.rb +16 -0
- data/lib/karafka/web/ui/app.rb +78 -0
- data/lib/karafka/web/ui/base.rb +77 -0
- data/lib/karafka/web/ui/controllers/base.rb +40 -0
- data/lib/karafka/web/ui/controllers/become_pro.rb +17 -0
- data/lib/karafka/web/ui/controllers/cluster.rb +24 -0
- data/lib/karafka/web/ui/controllers/consumers.rb +27 -0
- data/lib/karafka/web/ui/controllers/errors.rb +43 -0
- data/lib/karafka/web/ui/controllers/jobs.rb +33 -0
- data/lib/karafka/web/ui/controllers/requests/params.rb +30 -0
- data/lib/karafka/web/ui/controllers/responses/data.rb +26 -0
- data/lib/karafka/web/ui/controllers/routing.rb +30 -0
- data/lib/karafka/web/ui/helpers/application_helper.rb +144 -0
- data/lib/karafka/web/ui/lib/hash_proxy.rb +66 -0
- data/lib/karafka/web/ui/lib/paginate_array.rb +38 -0
- data/lib/karafka/web/ui/models/consumer_group.rb +20 -0
- data/lib/karafka/web/ui/models/health.rb +44 -0
- data/lib/karafka/web/ui/models/job.rb +13 -0
- data/lib/karafka/web/ui/models/message.rb +99 -0
- data/lib/karafka/web/ui/models/partition.rb +13 -0
- data/lib/karafka/web/ui/models/process.rb +56 -0
- data/lib/karafka/web/ui/models/processes.rb +86 -0
- data/lib/karafka/web/ui/models/state.rb +67 -0
- data/lib/karafka/web/ui/models/topic.rb +19 -0
- data/lib/karafka/web/ui/pro/app.rb +120 -0
- data/lib/karafka/web/ui/pro/controllers/cluster.rb +16 -0
- data/lib/karafka/web/ui/pro/controllers/consumers.rb +54 -0
- data/lib/karafka/web/ui/pro/controllers/dlq.rb +44 -0
- data/lib/karafka/web/ui/pro/controllers/errors.rb +57 -0
- data/lib/karafka/web/ui/pro/controllers/explorer.rb +79 -0
- data/lib/karafka/web/ui/pro/controllers/health.rb +33 -0
- data/lib/karafka/web/ui/pro/controllers/jobs.rb +26 -0
- data/lib/karafka/web/ui/pro/controllers/routing.rb +26 -0
- data/lib/karafka/web/ui/pro/views/consumers/_breadcrumbs.erb +27 -0
- data/lib/karafka/web/ui/pro/views/consumers/_consumer.erb +60 -0
- data/lib/karafka/web/ui/pro/views/consumers/_counters.erb +50 -0
- data/lib/karafka/web/ui/pro/views/consumers/_summary.erb +81 -0
- data/lib/karafka/web/ui/pro/views/consumers/consumer/_consumer_group.erb +109 -0
- data/lib/karafka/web/ui/pro/views/consumers/consumer/_job.erb +26 -0
- data/lib/karafka/web/ui/pro/views/consumers/consumer/_metrics.erb +126 -0
- data/lib/karafka/web/ui/pro/views/consumers/consumer/_no_jobs.erb +9 -0
- data/lib/karafka/web/ui/pro/views/consumers/consumer/_no_subscriptions.erb +9 -0
- data/lib/karafka/web/ui/pro/views/consumers/consumer/_partition.erb +32 -0
- data/lib/karafka/web/ui/pro/views/consumers/consumer/_stopped.erb +10 -0
- data/lib/karafka/web/ui/pro/views/consumers/consumer/_tabs.erb +20 -0
- data/lib/karafka/web/ui/pro/views/consumers/index.erb +30 -0
- data/lib/karafka/web/ui/pro/views/consumers/jobs.erb +42 -0
- data/lib/karafka/web/ui/pro/views/consumers/subscriptions.erb +23 -0
- data/lib/karafka/web/ui/pro/views/dlq/_breadcrumbs.erb +5 -0
- data/lib/karafka/web/ui/pro/views/dlq/_no_topics.erb +9 -0
- data/lib/karafka/web/ui/pro/views/dlq/_topic.erb +12 -0
- data/lib/karafka/web/ui/pro/views/dlq/index.erb +16 -0
- data/lib/karafka/web/ui/pro/views/errors/_breadcrumbs.erb +25 -0
- data/lib/karafka/web/ui/pro/views/errors/_detail.erb +29 -0
- data/lib/karafka/web/ui/pro/views/errors/_error.erb +26 -0
- data/lib/karafka/web/ui/pro/views/errors/_partition_option.erb +7 -0
- data/lib/karafka/web/ui/pro/views/errors/index.erb +58 -0
- data/lib/karafka/web/ui/pro/views/errors/show.erb +56 -0
- data/lib/karafka/web/ui/pro/views/explorer/_breadcrumbs.erb +29 -0
- data/lib/karafka/web/ui/pro/views/explorer/_detail.erb +21 -0
- data/lib/karafka/web/ui/pro/views/explorer/_encryption_enabled.erb +18 -0
- data/lib/karafka/web/ui/pro/views/explorer/_failed_deserialization.erb +4 -0
- data/lib/karafka/web/ui/pro/views/explorer/_message.erb +16 -0
- data/lib/karafka/web/ui/pro/views/explorer/_partition_option.erb +7 -0
- data/lib/karafka/web/ui/pro/views/explorer/_topic.erb +12 -0
- data/lib/karafka/web/ui/pro/views/explorer/index.erb +17 -0
- data/lib/karafka/web/ui/pro/views/explorer/partition.erb +56 -0
- data/lib/karafka/web/ui/pro/views/explorer/show.erb +65 -0
- data/lib/karafka/web/ui/pro/views/health/_breadcrumbs.erb +5 -0
- data/lib/karafka/web/ui/pro/views/health/_partition.erb +35 -0
- data/lib/karafka/web/ui/pro/views/health/index.erb +60 -0
- data/lib/karafka/web/ui/pro/views/jobs/_breadcrumbs.erb +5 -0
- data/lib/karafka/web/ui/pro/views/jobs/_job.erb +31 -0
- data/lib/karafka/web/ui/pro/views/jobs/_no_jobs.erb +9 -0
- data/lib/karafka/web/ui/pro/views/jobs/index.erb +34 -0
- data/lib/karafka/web/ui/pro/views/shared/_navigation.erb +57 -0
- data/lib/karafka/web/ui/public/images/favicon.ico +0 -0
- data/lib/karafka/web/ui/public/images/logo.svg +28 -0
- data/lib/karafka/web/ui/public/javascripts/application.js +41 -0
- data/lib/karafka/web/ui/public/javascripts/bootstrap.min.js +7 -0
- data/lib/karafka/web/ui/public/javascripts/highlight.min.js +337 -0
- data/lib/karafka/web/ui/public/javascripts/live_poll.js +124 -0
- data/lib/karafka/web/ui/public/javascripts/timeago.min.js +1 -0
- data/lib/karafka/web/ui/public/stylesheets/application.css +106 -0
- data/lib/karafka/web/ui/public/stylesheets/bootstrap.min.css +7 -0
- data/lib/karafka/web/ui/public/stylesheets/bootstrap.min.css.map +1 -0
- data/lib/karafka/web/ui/public/stylesheets/highlight.min.css +10 -0
- data/lib/karafka/web/ui/views/cluster/_breadcrumbs.erb +5 -0
- data/lib/karafka/web/ui/views/cluster/_broker.erb +5 -0
- data/lib/karafka/web/ui/views/cluster/_partition.erb +22 -0
- data/lib/karafka/web/ui/views/cluster/index.erb +72 -0
- data/lib/karafka/web/ui/views/consumers/_breadcrumbs.erb +27 -0
- data/lib/karafka/web/ui/views/consumers/_consumer.erb +43 -0
- data/lib/karafka/web/ui/views/consumers/_counters.erb +44 -0
- data/lib/karafka/web/ui/views/consumers/_summary.erb +81 -0
- data/lib/karafka/web/ui/views/consumers/consumer/_consumer_group.erb +109 -0
- data/lib/karafka/web/ui/views/consumers/consumer/_job.erb +26 -0
- data/lib/karafka/web/ui/views/consumers/consumer/_metrics.erb +126 -0
- data/lib/karafka/web/ui/views/consumers/consumer/_no_jobs.erb +9 -0
- data/lib/karafka/web/ui/views/consumers/consumer/_no_subscriptions.erb +9 -0
- data/lib/karafka/web/ui/views/consumers/consumer/_partition.erb +32 -0
- data/lib/karafka/web/ui/views/consumers/consumer/_stopped.erb +10 -0
- data/lib/karafka/web/ui/views/consumers/consumer/_tabs.erb +20 -0
- data/lib/karafka/web/ui/views/consumers/index.erb +29 -0
- data/lib/karafka/web/ui/views/errors/_breadcrumbs.erb +19 -0
- data/lib/karafka/web/ui/views/errors/_detail.erb +29 -0
- data/lib/karafka/web/ui/views/errors/_error.erb +26 -0
- data/lib/karafka/web/ui/views/errors/index.erb +38 -0
- data/lib/karafka/web/ui/views/errors/show.erb +30 -0
- data/lib/karafka/web/ui/views/jobs/_breadcrumbs.erb +5 -0
- data/lib/karafka/web/ui/views/jobs/_job.erb +22 -0
- data/lib/karafka/web/ui/views/jobs/_no_jobs.erb +9 -0
- data/lib/karafka/web/ui/views/jobs/index.erb +31 -0
- data/lib/karafka/web/ui/views/layout.erb +23 -0
- data/lib/karafka/web/ui/views/routing/_breadcrumbs.erb +15 -0
- data/lib/karafka/web/ui/views/routing/_consumer_group.erb +34 -0
- data/lib/karafka/web/ui/views/routing/_detail.erb +25 -0
- data/lib/karafka/web/ui/views/routing/_topic.erb +18 -0
- data/lib/karafka/web/ui/views/routing/index.erb +10 -0
- data/lib/karafka/web/ui/views/routing/show.erb +26 -0
- data/lib/karafka/web/ui/views/shared/_become_pro.erb +13 -0
- data/lib/karafka/web/ui/views/shared/_brand.erb +3 -0
- data/lib/karafka/web/ui/views/shared/_content.erb +31 -0
- data/lib/karafka/web/ui/views/shared/_header.erb +20 -0
- data/lib/karafka/web/ui/views/shared/_navigation.erb +57 -0
- data/lib/karafka/web/ui/views/shared/_pagination.erb +21 -0
- data/lib/karafka/web/ui/views/shared/exceptions/not_found.erb +39 -0
- data/lib/karafka/web/ui/views/shared/exceptions/pro_only.erb +52 -0
- data/lib/karafka/web/version.rb +8 -0
- data/lib/karafka/web.rb +60 -0
- data.tar.gz.sig +0 -0
- metadata +328 -0
- metadata.gz.sig +0 -0
@@ -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,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,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,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,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,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>
|