karafka-web 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +9 -0
  4. data/Gemfile +1 -0
  5. data/Gemfile.lock +23 -11
  6. data/karafka-web.gemspec +2 -2
  7. data/lib/karafka/web/config.rb +5 -0
  8. data/lib/karafka/web/installer.rb +1 -2
  9. data/lib/karafka/web/processing/consumer.rb +2 -1
  10. data/lib/karafka/web/tracking/consumers/contracts/job.rb +1 -0
  11. data/lib/karafka/web/tracking/consumers/contracts/report.rb +1 -0
  12. data/lib/karafka/web/tracking/consumers/listeners/errors.rb +1 -1
  13. data/lib/karafka/web/tracking/consumers/listeners/processing.rb +2 -1
  14. data/lib/karafka/web/tracking/consumers/sampler.rb +9 -3
  15. data/lib/karafka/web/tracking/reporter.rb +2 -1
  16. data/lib/karafka/web/ui/app.rb +5 -0
  17. data/lib/karafka/web/ui/controllers/status.rb +23 -0
  18. data/lib/karafka/web/ui/models/process.rb +7 -0
  19. data/lib/karafka/web/ui/models/status.rb +169 -0
  20. data/lib/karafka/web/ui/pro/app.rb +5 -0
  21. data/lib/karafka/web/ui/pro/controllers/status.rb +26 -0
  22. data/lib/karafka/web/ui/pro/views/consumers/_consumer.erb +15 -7
  23. data/lib/karafka/web/ui/pro/views/consumers/consumer/_job.erb +4 -0
  24. data/lib/karafka/web/ui/pro/views/consumers/consumer/_metrics.erb +10 -0
  25. data/lib/karafka/web/ui/pro/views/jobs/_job.erb +4 -0
  26. data/lib/karafka/web/ui/pro/views/shared/_navigation.erb +5 -0
  27. data/lib/karafka/web/ui/views/consumers/_consumer.erb +15 -7
  28. data/lib/karafka/web/ui/views/jobs/_job.erb +4 -0
  29. data/lib/karafka/web/ui/views/shared/_navigation.erb +5 -0
  30. data/lib/karafka/web/ui/views/shared/exceptions/not_found.erb +2 -0
  31. data/lib/karafka/web/ui/views/status/_breadcrumbs.erb +5 -0
  32. data/lib/karafka/web/ui/views/status/_failure.erb +14 -0
  33. data/lib/karafka/web/ui/views/status/_halted.erb +11 -0
  34. data/lib/karafka/web/ui/views/status/_success.erb +11 -0
  35. data/lib/karafka/web/ui/views/status/failures/_connection.erb +7 -0
  36. data/lib/karafka/web/ui/views/status/failures/_initial_state.erb +20 -0
  37. data/lib/karafka/web/ui/views/status/failures/_live_reporting.erb +7 -0
  38. data/lib/karafka/web/ui/views/status/failures/_partitions.erb +19 -0
  39. data/lib/karafka/web/ui/views/status/failures/_state_calculation.erb +8 -0
  40. data/lib/karafka/web/ui/views/status/failures/_topics.erb +20 -0
  41. data/lib/karafka/web/ui/views/status/show.erb +94 -0
  42. data/lib/karafka/web/version.rb +1 -1
  43. data.tar.gz.sig +0 -0
  44. metadata +20 -6
  45. metadata.gz.sig +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3a70fc5cb35d0e6e60a348e3efe91113b54d0c62310b7c3af4e7584aa70cfb70
4
- data.tar.gz: 43a96b7e7a4622721dbc6ba144852335aecbfe907049bc47ab563ea07f40eb54
3
+ metadata.gz: eb17bd9d46e6fa0d0125bc665bff74a9d4277be394f1bf29223b6d49ef09e054
4
+ data.tar.gz: 2f1da7d4fa79116a67ae3300863b56c3ac2215d80dccba89520e33e78c3b1a84
5
5
  SHA512:
6
- metadata.gz: db0b153569ca93f1164a851216e0f224acc56e6a7533a35a86a44f6f2f8bffc1630e5ccf7c2e53a14455206401c45b59b1728eb266c59360be8f952794d3011b
7
- data.tar.gz: 794c77edb27f7f9a397c3de891b146f9020653b84bad46e1f1b537a1d547ffc793211e7bd5ffb0f426c0b8fa9b6359230bb3fe3ee8fa5ec668cb0e1d39782d5a
6
+ metadata.gz: cc9f331aa0b9276c1b3c2d6d4f400b9d8600da174123d472b1699554e0cd95de14ff60b7c4effbb0c4f86a423f24ff27f5facc282ff8215863c146a4b1c0bb41
7
+ data.tar.gz: 1f638b2ca877b1b34612654a19f0fb8d04ab88e5dc6b560a7090e74a6d1202da0257d4f941f8f182b6b874d8a099db30772a1ab9517b32ebae76161d9314797a
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Karafka Web changelog
2
2
 
3
+ ## 0.2.0 (2023-02-24)
4
+ - **[Feature]** Introduce ability to tag `Karafka::Process` to display process-centric tags in the Web UI.
5
+ - **[Feature]** Introduce ability to tag consumer instances to display consumption-centric tags in the Web UI.
6
+ - **[Feature]** Introduce a /status page that can validate the setup and tell what is missing (#1318)
7
+ - [Improvement] Allow for disabling the consumer subscription from Web for multi-tenant Web UI usage (#1331)
8
+ - [Improvement] Make sure that states and reports are always dispatched to the partition `0`. This should prevent UI from not fully working when someone accidentally creates more partitions than expected.
9
+ - [Fix] Fix a bug where bootstrapping would create two initial states.
10
+ - [Fix] Fix a case, where errors listener would try to force encoding on a frozen error message.
11
+
3
12
  ## 0.1.3 (2023-02-14)
4
13
  - Skip topics creation if web topics already exist (do not raise error)
5
14
  - Support ability to provide replication factor in the install command
data/Gemfile CHANGED
@@ -8,6 +8,7 @@ gemspec
8
8
 
9
9
  group :test do
10
10
  gem 'byebug'
11
+ gem 'factory_bot'
11
12
  gem 'rspec'
12
13
  gem 'simplecov'
13
14
  end
data/Gemfile.lock CHANGED
@@ -1,41 +1,51 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- karafka-web (0.1.3)
4
+ karafka-web (0.2.0)
5
5
  erubi (~> 1.4)
6
- karafka (>= 2.0.29, < 3.0.0)
7
- karafka-core (>= 2.0.10, < 3.0.0)
6
+ karafka (>= 2.0.33, < 3.0.0)
7
+ karafka-core (>= 2.0.12, < 3.0.0)
8
8
  roda (~> 3.63)
9
9
  tilt (~> 2.0)
10
10
 
11
11
  GEM
12
12
  remote: https://rubygems.org/
13
13
  specs:
14
+ activesupport (7.0.4.2)
15
+ concurrent-ruby (~> 1.0, >= 1.0.2)
16
+ i18n (>= 1.6, < 2)
17
+ minitest (>= 5.1)
18
+ tzinfo (~> 2.0)
14
19
  byebug (11.1.3)
15
20
  concurrent-ruby (1.2.0)
16
21
  diff-lcs (1.5.0)
17
22
  docile (1.4.0)
18
23
  erubi (1.12.0)
24
+ factory_bot (6.2.1)
25
+ activesupport (>= 5.0.0)
19
26
  ffi (1.15.5)
20
- karafka (2.0.30)
21
- karafka-core (>= 2.0.9, < 3.0.0)
27
+ i18n (1.12.0)
28
+ concurrent-ruby (~> 1.0)
29
+ karafka (2.0.33)
30
+ karafka-core (>= 2.0.12, < 3.0.0)
22
31
  thor (>= 0.20)
23
32
  waterdrop (>= 2.4.10, < 3.0.0)
24
33
  zeitwerk (~> 2.3)
25
- karafka-core (2.0.10)
34
+ karafka-core (2.0.12)
26
35
  concurrent-ruby (>= 1.1)
27
- karafka-rdkafka (>= 0.12)
28
- karafka-rdkafka (0.12.0)
36
+ karafka-rdkafka (>= 0.12.1)
37
+ karafka-rdkafka (0.12.1)
29
38
  ffi (~> 1.15)
30
39
  mini_portile2 (~> 2.6)
31
40
  rake (> 12)
32
41
  mini_portile2 (2.8.1)
42
+ minitest (5.17.0)
33
43
  rack (3.0.4.1)
34
44
  rackup (0.2.3)
35
45
  rack (>= 3.0.0.beta1)
36
46
  webrick
37
47
  rake (13.0.6)
38
- roda (3.64.0)
48
+ roda (3.65.0)
39
49
  rack
40
50
  rspec (3.12.0)
41
51
  rspec-core (~> 3.12.0)
@@ -57,7 +67,9 @@ GEM
57
67
  simplecov-html (0.12.3)
58
68
  simplecov_json_formatter (0.1.4)
59
69
  thor (1.2.1)
60
- tilt (2.0.11)
70
+ tilt (2.1.0)
71
+ tzinfo (2.0.6)
72
+ concurrent-ruby (~> 1.0)
61
73
  waterdrop (2.4.10)
62
74
  karafka-core (>= 2.0.9, < 3.0.0)
63
75
  zeitwerk (~> 2.3)
@@ -65,11 +77,11 @@ GEM
65
77
  zeitwerk (2.6.7)
66
78
 
67
79
  PLATFORMS
68
- arm64-darwin-21
69
80
  x86_64-linux
70
81
 
71
82
  DEPENDENCIES
72
83
  byebug
84
+ factory_bot
73
85
  karafka-web!
74
86
  rackup (~> 0.2)
75
87
  rspec
data/karafka-web.gemspec CHANGED
@@ -17,8 +17,8 @@ Gem::Specification.new do |spec|
17
17
  spec.licenses = %w[LGPL-3.0 Commercial]
18
18
 
19
19
  spec.add_dependency 'erubi', '~> 1.4'
20
- spec.add_dependency 'karafka', '>= 2.0.29', '< 3.0.0'
21
- spec.add_dependency 'karafka-core', '>= 2.0.10', '< 3.0.0'
20
+ spec.add_dependency 'karafka', '>= 2.0.33', '< 3.0.0'
21
+ spec.add_dependency 'karafka-core', '>= 2.0.12', '< 3.0.0'
22
22
  spec.add_dependency 'roda', '~> 3.63'
23
23
  spec.add_dependency 'tilt', '~> 2.0'
24
24
 
@@ -56,6 +56,11 @@ module Karafka
56
56
 
57
57
  # States processing related settings
58
58
  setting :processing do
59
+ # Should we actively process reports
60
+ # This can be disabled in case of using a multi-tenant approach where only one of the
61
+ # apps should materialize the state
62
+ setting :active, default: true
63
+
59
64
  # What should be the consumer group name for web consumer
60
65
  setting :consumer_group, default: 'karafka_web'
61
66
 
@@ -45,6 +45,7 @@ module Karafka
45
45
  consumer_group ::Karafka::Web.config.processing.consumer_group do
46
46
  # Topic we listen on to materialize the states
47
47
  topic ::Karafka::Web.config.topics.consumers.reports do
48
+ active ::Karafka::Web.config.processing.active
48
49
  # Since we materialize state in intervals, we can poll for half of this time without
49
50
  # impacting the reporting responsiveness
50
51
  max_wait_time ::Karafka::Web.config.processing.interval / 2
@@ -128,8 +129,6 @@ module Karafka
128
129
  replication_factor
129
130
  )
130
131
  end
131
-
132
- bootstrap_state!
133
132
  end
134
133
 
135
134
  # Creates the initial state record with all values being empty
@@ -57,7 +57,8 @@ module Karafka
57
57
  topic: Karafka::Web.config.topics.consumers.states,
58
58
  payload: @consumers_aggregator.to_json,
59
59
  # This will ensure that the consumer states are compacted
60
- key: Karafka::Web.config.topics.consumers.states
60
+ key: Karafka::Web.config.topics.consumers.states,
61
+ partition: 0
61
62
  )
62
63
  end
63
64
  end
@@ -18,6 +18,7 @@ module Karafka
18
18
  required(:last_offset) { |val| val.is_a?(Integer) && val >= 0 }
19
19
  required(:comitted_offset) { |val| val.is_a?(Integer) }
20
20
  required(:type) { |val| %w[consume revoked shutdown].include?(val) }
21
+ required(:tags) { |val| val.is_a?(Karafka::Core::Taggable::Tags) }
21
22
  end
22
23
  end
23
24
  end
@@ -27,6 +27,7 @@ module Karafka
27
27
  required(:status) { |val| ::Karafka::Status::STATES.key?(val.to_sym) }
28
28
  required(:listeners) { |val| val.is_a?(Integer) && val >= 0 }
29
29
  required(:concurrency) { |val| val.is_a?(Integer) && val.positive? }
30
+ required(:tags) { |val| val.is_a?(Karafka::Core::Taggable::Tags) }
30
31
 
31
32
  required(:cpu_usage) do |val|
32
33
  val.is_a?(Array) &&
@@ -74,7 +74,7 @@ module Karafka
74
74
  # @param error [StandardError] error that occurred
75
75
  # @return [Array<String, String, String>] array with error name, message and backtrace
76
76
  def extract_error_info(error)
77
- error_message = error.message.to_s
77
+ error_message = error.message.to_s.dup
78
78
  error_message.force_encoding('utf-8')
79
79
  error_message.scrub!
80
80
 
@@ -146,7 +146,8 @@ module Karafka
146
146
  comitted_offset: consumer.coordinator.seek_offset - 1,
147
147
  consumer: consumer.class.to_s,
148
148
  consumer_group: consumer.topic.consumer_group.id,
149
- type: type
149
+ type: type,
150
+ tags: consumer.tags
150
151
  }
151
152
  end
152
153
  end
@@ -11,13 +11,18 @@ module Karafka
11
11
 
12
12
  attr_reader :counters, :consumer_groups, :errors, :times, :pauses, :jobs
13
13
 
14
+ # Current schema version
15
+ # This can be used in the future for detecting incompatible changes and writing
16
+ # migrations
17
+ SCHEMA_VERSION = '1.0.1'
18
+
14
19
  # 60 seconds window for time tracked window-based metrics
15
20
  TIMES_TTL = 60
16
21
 
17
22
  # Times ttl in ms
18
23
  TIMES_TTL_MS = TIMES_TTL * 1_000
19
24
 
20
- private_constant :TIMES_TTL, :TIMES_TTL_MS
25
+ private_constant :TIMES_TTL, :TIMES_TTL_MS, :SCHEMA_VERSION
21
26
 
22
27
  def initialize
23
28
  @counters = {
@@ -47,7 +52,7 @@ module Karafka
47
52
  # @return [Hash] report hash with all the details about consumer operations
48
53
  def to_report
49
54
  {
50
- schema_version: '1.0.0',
55
+ schema_version: SCHEMA_VERSION,
51
56
  type: 'consumer',
52
57
  dispatched_at: float_now,
53
58
 
@@ -61,7 +66,8 @@ module Karafka
61
66
  memory_total_usage: memory_total_usage,
62
67
  memory_size: memory_size,
63
68
  cpu_count: cpu_count,
64
- cpu_usage: cpu_usage
69
+ cpu_usage: cpu_usage,
70
+ tags: Karafka::Process.tags
65
71
  },
66
72
 
67
73
  versions: {
@@ -49,7 +49,8 @@ module Karafka
49
49
  {
50
50
  topic: ::Karafka::Web.config.topics.consumers.reports,
51
51
  payload: consumer_report.to_json,
52
- key: consumer_report[:process][:name]
52
+ key: consumer_report[:process][:name],
53
+ partition: 0
53
54
  }
54
55
  ]
55
56
 
@@ -71,6 +71,11 @@ module Karafka
71
71
  render_response controller.index
72
72
  end
73
73
  end
74
+
75
+ r.get 'status' do
76
+ controller = Controllers::Status.new(params)
77
+ render_response controller.show
78
+ end
74
79
  end
75
80
  end
76
81
  end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ module Web
5
+ module Ui
6
+ module Controllers
7
+ # View that helps understand the status of the Web UI
8
+ # Many people reported problems understanding the requirements or misconfigured things.
9
+ # While all of the things are documented, people are lazy. Hence we provide a status
10
+ # page where we check that everything is as expected and if not, we can provide some
11
+ # helpful instructions on how to fix the issues.
12
+ class Status < Base
13
+ # Displays the Web UI setup status
14
+ def show
15
+ @status = Models::Status.new
16
+
17
+ respond
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -40,6 +40,13 @@ module Karafka
40
40
  .sort_by(&:started_at)
41
41
  end
42
42
 
43
+ # @return [Array<String>] tags of this consuming process
44
+ # @note We use direct reference here and a fallback for users that come from the versions
45
+ # that did not report tags
46
+ def tags
47
+ @hash[:process][:tags] || []
48
+ end
49
+
43
50
  # @return [Integer] collective lag on this process
44
51
  def lag_stored
45
52
  consumer_groups
@@ -0,0 +1,169 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ module Web
5
+ module Ui
6
+ module Models
7
+ # Model that represents the general status of the Web UI.
8
+ # We use this data to display a status page that helps with debugging on what is missing
9
+ # in the overall setup of the Web UI.
10
+ #
11
+ # People have various problems like too many partitions, not created topics, etc. and this
12
+ # data and view aims to help them with understanding the current status of the setup
13
+ class Status
14
+ # Status of a single step of setup
15
+ Step = Struct.new(:status, :details) do
16
+ # @return [Boolean] is the given step successfully configured and working
17
+ def success?
18
+ status == :success
19
+ end
20
+
21
+ # @return [String] stringified status
22
+ def to_s
23
+ status.to_s
24
+ end
25
+ end
26
+
27
+ # Initializes the status object and tries to connect to Kafka
28
+ def initialize
29
+ connect
30
+ end
31
+
32
+ # @return [Status::Step] were we able to connect to Kafka or not
33
+ def connection
34
+ Step.new(
35
+ @connected ? :success : :failure,
36
+ nil
37
+ )
38
+ end
39
+
40
+ # @return [Status::Step] do all the needed topics exist
41
+ def topics
42
+ if connection.success?
43
+ details = topics_details
44
+ status = details.all? { |_, detail| detail[:present] } ? :success : :failure
45
+ else
46
+ status = :halted
47
+ details = {}
48
+ end
49
+
50
+ Step.new(
51
+ status,
52
+ details
53
+ )
54
+ end
55
+
56
+ # @return [Status::Step] do we have all topics with expected number of partitions
57
+ def partitions
58
+ if topics.success?
59
+ status = :success
60
+ status = :failure if topics_details[topics_consumers_states][:partitions] != 1
61
+ status = :failure if topics_details[topics_consumers_reports][:partitions] != 1
62
+ details = topics_details
63
+ else
64
+ status = :halted
65
+ details = {}
66
+ end
67
+
68
+ Step.new(
69
+ status,
70
+ details
71
+ )
72
+ end
73
+
74
+ # @return [Status::Step] Is the initial state present in the setup or not
75
+ def initial_state
76
+ if partitions.success?
77
+ @current_state ||= Models::State.current
78
+ status = @current_state ? :success : :failure
79
+ else
80
+ status = :halted
81
+ end
82
+
83
+ Step.new(
84
+ status,
85
+ nil
86
+ )
87
+ end
88
+
89
+ # @return [Status::Step] Is there at least one active karafka server reporting to the
90
+ # Web UI
91
+ def live_reporting
92
+ if initial_state.success?
93
+ @processes ||= Models::Processes.active(@current_state)
94
+ status = @processes.empty? ? :failure : :success
95
+ else
96
+ status = :halted
97
+ end
98
+
99
+ Step.new(
100
+ status,
101
+ nil
102
+ )
103
+ end
104
+
105
+ # @return [Status::Step] is there a subscription to our reports topic that is being
106
+ # consumed actively.
107
+ def state_calculation
108
+ if live_reporting.success?
109
+ @subscriptions ||= Models::Health.current(@current_state).values.flat_map(&:keys)
110
+ status = @subscriptions.include?(topics_consumers_reports) ? :success : :failure
111
+ else
112
+ status = :halted
113
+ end
114
+
115
+ Step.new(
116
+ status,
117
+ nil
118
+ )
119
+ end
120
+
121
+ private
122
+
123
+ # @return [String] consumers states topic name
124
+ def topics_consumers_states
125
+ ::Karafka::Web.config.topics.consumers.states.to_s
126
+ end
127
+
128
+ # @return [String] consumers reports topic name
129
+ def topics_consumers_reports
130
+ ::Karafka::Web.config.topics.consumers.reports.to_s
131
+ end
132
+
133
+ # @return [String] errors topic name
134
+ def topics_errors
135
+ ::Karafka::Web.config.topics.errors
136
+ end
137
+
138
+ # @return [Hash] hash with topics with which we work details (even if don't exist)
139
+ def topics_details
140
+ topics = {
141
+ topics_consumers_states => { present: false, partitions: 0 },
142
+ topics_consumers_reports => { present: false, partitions: 0 },
143
+ topics_errors => { present: false, partitions: 0 }
144
+ }
145
+
146
+ @cluster_info.topics.each do |topic|
147
+ name = topic[:topic_name]
148
+
149
+ next unless topics.key?(name)
150
+
151
+ topics[name][:present] = true
152
+ topics[name][:partitions] = topic[:partition_count]
153
+ end
154
+
155
+ topics
156
+ end
157
+
158
+ # Tries connecting with the cluster and sets the connection state
159
+ def connect
160
+ @cluster_info = ::Karafka::Admin.cluster_info
161
+ @connected = true
162
+ rescue ::Rdkafka::RdkafkaError
163
+ @connected = false
164
+ end
165
+ end
166
+ end
167
+ end
168
+ end
169
+ end
@@ -112,6 +112,11 @@ module Karafka
112
112
  controller = Controllers::Dlq.new(params)
113
113
  render_response controller.index
114
114
  end
115
+
116
+ r.get 'status' do
117
+ controller = Controllers::Status.new(params)
118
+ render_response controller.show
119
+ end
115
120
  end
116
121
  end
117
122
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This Karafka component is a Pro component under a commercial license.
4
+ # This Karafka component is NOT licensed under LGPL.
5
+ #
6
+ # All of the commercial components are present in the lib/karafka/pro directory of this
7
+ # repository and their usage requires commercial license agreement.
8
+ #
9
+ # Karafka has also commercial-friendly license, commercial support and commercial components.
10
+ #
11
+ # By sending a pull request to the pro components, you are agreeing to transfer the copyright of
12
+ # your code to Maciej Mensfeld.
13
+
14
+ module Karafka
15
+ module Web
16
+ module Ui
17
+ module Pro
18
+ module Controllers
19
+ # Status details - same as in OSS
20
+ class Status < Ui::Controllers::Status
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -8,16 +8,24 @@
8
8
  <%= process.name %>
9
9
  </a>
10
10
 
11
- <br/>
11
+ <p class="mt-0 mb-1">
12
+ <% process.consumer_groups.each do |consumer_group| %>
13
+ <% consumer_group.topics.each do |topic| %>
14
+ <span class="badge bg-secondary badge-topic" title="Consumer group: <%= consumer_group.id %>">
15
+ <%= topic.name %>:
16
+ <%= topic.partitions.map(&:id).join(',') %>
17
+ </span>
18
+ <% end %>
19
+ <% end %>
20
+ </p>
12
21
 
13
- <% process.consumer_groups.each do |consumer_group| %>
14
- <% consumer_group.topics.each do |topic| %>
15
- <span class="badge bg-secondary badge-topic" title="Consumer group: <%= consumer_group.id %>">
16
- <%= topic.name %>:
17
- <%= topic.partitions.map(&:id).join(',') %>
22
+ <p class="mt-0 mb-1">
23
+ <% process.tags.each do |tag| %>
24
+ <span class="badge bg-info badge-topic">
25
+ <%= tag %>
18
26
  </span>
19
27
  <% end %>
20
- <% end %>
28
+ </p>
21
29
  </td>
22
30
 
23
31
  <td>
@@ -1,6 +1,10 @@
1
1
  <tr>
2
2
  <td>
3
3
  <code><%= job.consumer %></code>
4
+
5
+ <% job.tags.each do |tag| %>
6
+ <span class="badge bg-info"><%= tag %></span>
7
+ <% end %>
4
8
  </td>
5
9
  <td>
6
10
  <span class="badge bg-secondary badge-topic" title="Consumer group: <%= job.consumer_group %>">
@@ -27,6 +27,16 @@
27
27
  </li>
28
28
  </ul>
29
29
  </p>
30
+
31
+ <% unless @process.tags.empty? %>
32
+ <p class="mb-0 text-end">
33
+ <% @process.tags.each do |tag| %>
34
+ <span class="badge bg-info badge-topic">
35
+ <%= tag %>
36
+ </span>
37
+ <% end %>
38
+ </p>
39
+ <% end %>
30
40
  </div>
31
41
  </div>
32
42
  <div class="card">
@@ -12,6 +12,10 @@
12
12
  </td>
13
13
  <td>
14
14
  <code><%= job.consumer %></code>
15
+
16
+ <% job.tags.each do |tag| %>
17
+ <span class="badge bg-info"><%= tag %></span>
18
+ <% end %>
15
19
  </td>
16
20
  <td>
17
21
  <code>#<%= job.type %></code>
@@ -45,6 +45,11 @@
45
45
  Cluster
46
46
  </a>
47
47
  </li>
48
+ <li class="nav-item ms-3">
49
+ <a class="nav-link <%= nav_class(start_with: '/status') %>" href="<%= root_path('Status') %>">
50
+ Status
51
+ </a>
52
+ </li>
48
53
  </ul>
49
54
  </div>
50
55
 
@@ -8,16 +8,24 @@
8
8
  <%= process.name %>
9
9
  </a>
10
10
 
11
- <br/>
11
+ <p class="mt-0 mb-1">
12
+ <% process.consumer_groups.each do |consumer_group| %>
13
+ <% consumer_group.topics.each do |topic| %>
14
+ <span class="badge bg-secondary badge-topic" title="Consumer group: <%= consumer_group.id %>">
15
+ <%= topic.name %>:
16
+ <%= topic.partitions.map(&:id).join(',') %>
17
+ </span>
18
+ <% end %>
19
+ <% end %>
20
+ </p>
12
21
 
13
- <% process.consumer_groups.each do |consumer_group| %>
14
- <% consumer_group.topics.each do |topic| %>
15
- <span class="badge bg-secondary badge-topic" title="Consumer group: <%= consumer_group.id %>">
16
- <%= topic.name %>:
17
- <%= topic.partitions.map(&:id).join(',') %>
22
+ <p class="mt-0 mb-1">
23
+ <% process.tags.each do |tag| %>
24
+ <span class="badge bg-info badge-topic">
25
+ <%= tag %>
18
26
  </span>
19
27
  <% end %>
20
- <% end %>
28
+ </p>
21
29
  </td>
22
30
 
23
31
  <td>
@@ -12,6 +12,10 @@
12
12
  </td>
13
13
  <td>
14
14
  <code><%= job.consumer %></code>
15
+
16
+ <% job.tags.each do |tag| %>
17
+ <span class="badge bg-info"><%= tag %></span>
18
+ <% end %>
15
19
  </td>
16
20
  <td>
17
21
  <code>#<%= job.type %></code>
@@ -45,6 +45,11 @@
45
45
  Cluster
46
46
  </a>
47
47
  </li>
48
+ <li class="nav-item ms-3">
49
+ <a class="nav-link <%= nav_class(start_with: '/status') %>" href="<%= root_path('status') %>">
50
+ Status
51
+ </a>
52
+ </li>
48
53
  </ul>
49
54
  </div>
50
55
 
@@ -20,6 +20,7 @@
20
20
  </p>
21
21
 
22
22
  <ul class="mb-5 text-start">
23
+ <li>You have visited the <a href="<%= root_path('status') %>">Status</a> page to troubleshoot any potential issues</li>
23
24
  <li>All the topics required by Karafka Web exist</li>
24
25
  <li>You have used <code>bundle exec karafka-web install</code> to initialize the Web UI</li>
25
26
  <li>You have a working connection with your Kafka cluster</li>
@@ -32,6 +33,7 @@
32
33
 
33
34
  <p>
34
35
  <a href="<%= root_path %>" class="btn btn-primary">Go Home</a>
36
+ <a href="<%= root_path('status') %>" class="btn btn-success">Status page</a>
35
37
  </p>
36
38
  </div>
37
39
  </div>
@@ -0,0 +1,5 @@
1
+ <li class="breadcrumb-item">
2
+ <a href="<%= root_path('status') %>">
3
+ Web UI status details
4
+ </a>
5
+ </li>
@@ -0,0 +1,14 @@
1
+ <div class="card border-danger mb-3">
2
+ <div class="card-header text-bg-danger">
3
+ <span>
4
+ <%= title %>
5
+ </span>
6
+
7
+ <span class="float-end">
8
+ <span class="badge text-bg-light">Failure</span>
9
+ </span>
10
+ </div>
11
+ <div class="card-body">
12
+ <%== description %>
13
+ </div>
14
+ </div>
@@ -0,0 +1,11 @@
1
+ <div class="card text-bg-secondary mb-3">
2
+ <div class="card-header">
3
+ <span>
4
+ <%= title %>
5
+ </span>
6
+
7
+ <span class="float-end">
8
+ <span class="badge text-bg-light">Halted</span>
9
+ </span>
10
+ </div>
11
+ </div>
@@ -0,0 +1,11 @@
1
+ <div class="card text-bg-success mb-3">
2
+ <div class="card-header">
3
+ <span>
4
+ <%= title %>
5
+ </span>
6
+
7
+ <span class="float-end">
8
+ <span class="badge text-bg-light">Successful</span>
9
+ </span>
10
+ </div>
11
+ </div>
@@ -0,0 +1,7 @@
1
+ <p>
2
+ Web UI was not able to establish a connection with the Kafka cluster.
3
+ </p>
4
+
5
+ <p class="mb-0">
6
+ Please make sure that Web UI can reach Kafka.
7
+ </p>
@@ -0,0 +1,20 @@
1
+ <p>
2
+ The initial state for the Web UI was not created.
3
+ </p>
4
+
5
+ <p>
6
+ It means that the <code>bundle exec karafka-web install</code> was not executed or failed.
7
+ </p>
8
+
9
+ <p>
10
+ To fix this, you can either:
11
+ </p>
12
+
13
+ <ul>
14
+ <li>Run <code>bundle exec karafka-web install</code></li>
15
+ <li>Run at least one Karafka consumer process</li>
16
+ </ul>
17
+
18
+ <p class="mb-0">
19
+ Any of the above, when successful, will bootstrap the initial state.
20
+ </p>
@@ -0,0 +1,7 @@
1
+ <p>
2
+ There are no Karafka consumer processes actively reporting to the Web UI.
3
+ </p>
4
+
5
+ <p class="mb-0">
6
+ If you are sure you are running at least one <code>karafka server</code> instance, please make sure that it can report to the <code><%= Karafka::Web.config.topics.consumers.reports %></code> topic.
7
+ </p>
@@ -0,0 +1,19 @@
1
+ <p>
2
+ Both
3
+ <code><%= Karafka::Web.config.topics.consumers.states %></code>
4
+ and
5
+ <code><%= Karafka::Web.config.topics.consumers.reports %></code>
6
+ topics need to be configured with <strong>exactly</strong> one partition.
7
+ </p>
8
+
9
+ <p>
10
+ Your current setup contains the following:
11
+ </p>
12
+
13
+ <ul class="mb-0">
14
+ <% details.each do |name, details| %>
15
+ <li>
16
+ <code><%= name %> </code> with <code><%= details[:partitions] %> </code> partitions.
17
+ </li>
18
+ <% end %>
19
+ </ul>
@@ -0,0 +1,8 @@
1
+ <p>
2
+ None of the <code>karafka server</code> processes is subscribed to handle the
3
+ <code><%= Karafka::Web.config.topics.consumers.reports %></code> topic data aggregations.
4
+ </p>
5
+
6
+ <p class="mb-0">
7
+ If you are limiting the topics you consume using the <a href="https://karafka.io/docs/CLI/#limiting-consumer-groups-used-per-process" target="_blank">limiting API</a>, please include the Karafka Web consumer group and the <code><%= Karafka::Web.config.topics.consumers.reports %></code> topic.
8
+ </p>
@@ -0,0 +1,20 @@
1
+ <p>
2
+ Web UI requires the following topics to exist:
3
+ </p>
4
+
5
+ <ul>
6
+ <% details.each do |name, details| %>
7
+ <li>
8
+ <code><%= name %></code> - <%= details[:present] ? 'Exists' : 'Missing' %>
9
+ </li>
10
+ <% end %>
11
+ </ul>
12
+
13
+ <p>
14
+ Please ensure all those topics exist and are accessible to your Karafka user.
15
+ </p>
16
+
17
+ <p class="mb-0">
18
+ You can read more about their setup and configuration
19
+ <a href="https://karafka.io/docs/Web-UI-Getting-Started/" target="_blank">here</a>.
20
+ </p>
@@ -0,0 +1,94 @@
1
+ <%== view_title('Web UI status details') %>
2
+
3
+ <div class="container mb-5">
4
+ <div class="row">
5
+ <div class="col-lg-10 offset-md-1">
6
+
7
+ <%==
8
+ partial(
9
+ "status/#{@status.connection.to_s}",
10
+ locals: {
11
+ title: 'Connection to Kafka',
12
+ description: partial('status/failures/connection')
13
+ }
14
+ )
15
+ %>
16
+
17
+ <%==
18
+ partial(
19
+ "status/#{@status.topics.to_s}",
20
+ locals: {
21
+ title: 'Topics presence',
22
+ description: partial(
23
+ 'status/failures/topics',
24
+ locals: {
25
+ details: @status.topics.details
26
+ }
27
+ )
28
+ }
29
+ )
30
+ %>
31
+
32
+ <%==
33
+ partial(
34
+ "status/#{@status.partitions.to_s}",
35
+ locals: {
36
+ title: 'Partitions count',
37
+ description: partial(
38
+ 'status/failures/partitions',
39
+ locals: {
40
+ details: @status.partitions.details
41
+ }
42
+ )
43
+ }
44
+ )
45
+ %>
46
+
47
+ <%==
48
+ partial(
49
+ "status/#{@status.initial_state.to_s}",
50
+ locals: {
51
+ title: 'Initial state presence',
52
+ description: partial(
53
+ 'status/failures/initial_state',
54
+ locals: {
55
+ details: @status.initial_state.details
56
+ }
57
+ )
58
+ }
59
+ )
60
+ %>
61
+
62
+ <%==
63
+ partial(
64
+ "status/#{@status.live_reporting.to_s}",
65
+ locals: {
66
+ title: 'Live reporting',
67
+ description: partial(
68
+ 'status/failures/live_reporting',
69
+ locals: {
70
+ details: @status.live_reporting.details
71
+ }
72
+ )
73
+ }
74
+ )
75
+ %>
76
+
77
+ <%==
78
+ partial(
79
+ "status/#{@status.state_calculation.to_s}",
80
+ locals: {
81
+ title: 'State calculation subscription',
82
+ description: partial(
83
+ 'status/failures/state_calculation',
84
+ locals: {
85
+ details: @status.state_calculation.details
86
+ }
87
+ )
88
+ }
89
+ )
90
+ %>
91
+
92
+ </div>
93
+ </div>
94
+ </div>
@@ -3,6 +3,6 @@
3
3
  module Karafka
4
4
  module Web
5
5
  # Current gem version
6
- VERSION = '0.1.3'
6
+ VERSION = '0.2.0'
7
7
  end
8
8
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: karafka-web
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maciej Mensfeld
@@ -35,7 +35,7 @@ cert_chain:
35
35
  Qf04B9ceLUaC4fPVEz10FyobjaFoY4i32xRto3XnrzeAgfEe4swLq8bQsR3w/EF3
36
36
  MGU0FeSV2Yj7Xc2x/7BzLK8xQn5l7Yy75iPF+KP3vVmDHnNl
37
37
  -----END CERTIFICATE-----
38
- date: 2023-02-14 00:00:00.000000000 Z
38
+ date: 2023-02-24 00:00:00.000000000 Z
39
39
  dependencies:
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: erubi
@@ -57,7 +57,7 @@ dependencies:
57
57
  requirements:
58
58
  - - ">="
59
59
  - !ruby/object:Gem::Version
60
- version: 2.0.29
60
+ version: 2.0.33
61
61
  - - "<"
62
62
  - !ruby/object:Gem::Version
63
63
  version: 3.0.0
@@ -67,7 +67,7 @@ dependencies:
67
67
  requirements:
68
68
  - - ">="
69
69
  - !ruby/object:Gem::Version
70
- version: 2.0.29
70
+ version: 2.0.33
71
71
  - - "<"
72
72
  - !ruby/object:Gem::Version
73
73
  version: 3.0.0
@@ -77,7 +77,7 @@ dependencies:
77
77
  requirements:
78
78
  - - ">="
79
79
  - !ruby/object:Gem::Version
80
- version: 2.0.10
80
+ version: 2.0.12
81
81
  - - "<"
82
82
  - !ruby/object:Gem::Version
83
83
  version: 3.0.0
@@ -87,7 +87,7 @@ dependencies:
87
87
  requirements:
88
88
  - - ">="
89
89
  - !ruby/object:Gem::Version
90
- version: 2.0.10
90
+ version: 2.0.12
91
91
  - - "<"
92
92
  - !ruby/object:Gem::Version
93
93
  version: 3.0.0
@@ -199,6 +199,7 @@ files:
199
199
  - lib/karafka/web/ui/controllers/requests/params.rb
200
200
  - lib/karafka/web/ui/controllers/responses/data.rb
201
201
  - lib/karafka/web/ui/controllers/routing.rb
202
+ - lib/karafka/web/ui/controllers/status.rb
202
203
  - lib/karafka/web/ui/helpers/application_helper.rb
203
204
  - lib/karafka/web/ui/lib/hash_proxy.rb
204
205
  - lib/karafka/web/ui/lib/paginate_array.rb
@@ -210,6 +211,7 @@ files:
210
211
  - lib/karafka/web/ui/models/process.rb
211
212
  - lib/karafka/web/ui/models/processes.rb
212
213
  - lib/karafka/web/ui/models/state.rb
214
+ - lib/karafka/web/ui/models/status.rb
213
215
  - lib/karafka/web/ui/models/topic.rb
214
216
  - lib/karafka/web/ui/pro/app.rb
215
217
  - lib/karafka/web/ui/pro/controllers/cluster.rb
@@ -220,6 +222,7 @@ files:
220
222
  - lib/karafka/web/ui/pro/controllers/health.rb
221
223
  - lib/karafka/web/ui/pro/controllers/jobs.rb
222
224
  - lib/karafka/web/ui/pro/controllers/routing.rb
225
+ - lib/karafka/web/ui/pro/controllers/status.rb
223
226
  - lib/karafka/web/ui/pro/views/consumers/_breadcrumbs.erb
224
227
  - lib/karafka/web/ui/pro/views/consumers/_consumer.erb
225
228
  - lib/karafka/web/ui/pro/views/consumers/_counters.erb
@@ -315,6 +318,17 @@ files:
315
318
  - lib/karafka/web/ui/views/shared/_pagination.erb
316
319
  - lib/karafka/web/ui/views/shared/exceptions/not_found.erb
317
320
  - lib/karafka/web/ui/views/shared/exceptions/pro_only.erb
321
+ - lib/karafka/web/ui/views/status/_breadcrumbs.erb
322
+ - lib/karafka/web/ui/views/status/_failure.erb
323
+ - lib/karafka/web/ui/views/status/_halted.erb
324
+ - lib/karafka/web/ui/views/status/_success.erb
325
+ - lib/karafka/web/ui/views/status/failures/_connection.erb
326
+ - lib/karafka/web/ui/views/status/failures/_initial_state.erb
327
+ - lib/karafka/web/ui/views/status/failures/_live_reporting.erb
328
+ - lib/karafka/web/ui/views/status/failures/_partitions.erb
329
+ - lib/karafka/web/ui/views/status/failures/_state_calculation.erb
330
+ - lib/karafka/web/ui/views/status/failures/_topics.erb
331
+ - lib/karafka/web/ui/views/status/show.erb
318
332
  - lib/karafka/web/version.rb
319
333
  homepage: https://karafka.io
320
334
  licenses:
metadata.gz.sig CHANGED
Binary file