karafka-web 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ module Web
5
+ module Ui
6
+ module Models
7
+ # Single consumer process representation
8
+ class Process < Lib::HashProxy
9
+ class << self
10
+ # Looks for a given process based on its id
11
+ # @param state [State] state of the system based on which we will do the lookup
12
+ # @param process_id [String] id of the process we are looking for
13
+ # @return [Process] selected process or error raised
14
+ # @raise [::Karafka::Web::Errors::Ui::NotFoundError] raised if process not found
15
+ def find(state, process_id)
16
+ found_process = Processes.active(state).find { |process| process.id == process_id }
17
+ found_process || raise(::Karafka::Web::Errors::Ui::NotFoundError, process_id)
18
+ end
19
+ end
20
+
21
+ # @return [String] process id without the name and ip
22
+ def id
23
+ @id ||= name.split(':').last
24
+ end
25
+
26
+ # @return [Array<ConsumerGroup>] consumer groups to which this process is subscribed in
27
+ # an alphabetical order
28
+ def consumer_groups
29
+ super
30
+ .values
31
+ .map { |cg_hash| ConsumerGroup.new(cg_hash) }
32
+ .sort_by(&:id)
33
+ end
34
+
35
+ # Jobs sorted from longest running to youngest
36
+ # @return [Array<Job>] current jobs of this process
37
+ def jobs
38
+ super
39
+ .map { |job| Job.new(job) }
40
+ .sort_by(&:started_at)
41
+ end
42
+
43
+ # @return [Integer] collective lag on this process
44
+ def lag_stored
45
+ consumer_groups
46
+ .flat_map(&:topics)
47
+ .flat_map(&:partitions)
48
+ .map(&:lag_stored)
49
+ .delete_if(&:negative?)
50
+ .sum
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ module Web
5
+ module Ui
6
+ module Models
7
+ # Represents the active processes data
8
+ # @note Active also includes processes stopped recently. We use it to provide better
9
+ # visibility via UI.
10
+ module Processes
11
+ class << self
12
+ include ::Karafka::Core::Helpers::Time
13
+
14
+ # Returns the active processes in an array and alongside of that the current state of
15
+ # the system. We use those together in the UI and it would be expensive to pick it up
16
+ # while we've already had it.
17
+ #
18
+ # @param state [State] current system state from which we can get processes metadata
19
+ # @return [Array<Process>]
20
+ def active(state)
21
+ processes = fetch_reports(state)
22
+ evict_expired_processes(processes)
23
+ processes = squash_processes_data(processes)
24
+ processes = sort_processes(processes)
25
+
26
+ processes.map { |process_hash| Process.new(process_hash) }
27
+ end
28
+
29
+ private
30
+
31
+ # Fetches the relevant processes reports from the reports topic
32
+ # @param state [State]
33
+ # @return [Array<Hash>] array with deserialized processes reports
34
+ def fetch_reports(state)
35
+ offsets = state[:processes]
36
+ .values
37
+ .map { |process| process[:offset] }
38
+ .sort
39
+
40
+ ::Karafka::Admin.read_topic(
41
+ ::Karafka::Web.config.topics.consumers.reports,
42
+ 0,
43
+ # We set 10k here because we start from the latest offset of the reports, hence
44
+ # we will never get this much. Do do not know however exactly how many reports
45
+ # we may get as for some processes we may get few if the reporting interval
46
+ # was bypassed by state changes in the processes
47
+ 10_000,
48
+ offsets.first || -1
49
+ ).map(&:payload)
50
+ end
51
+
52
+ # Collapses processes data and only keeps the most recent report for give process
53
+ # @param processes [Array<Hash>]
54
+ # @return [Array<Hash>] unique processes data
55
+ def squash_processes_data(processes)
56
+ processes
57
+ .reverse
58
+ .uniq { |consumer| consumer[:process][:name] }
59
+ .reverse
60
+ end
61
+
62
+ # Removes processes that are no longer active. They may still be here because the state
63
+ # may have a small lag but we want to compensate for it that way.
64
+ # @param processes [Array<Hash>]
65
+ # @return [Array<Hash>] only active processes data
66
+ def evict_expired_processes(processes)
67
+ max_ttl = ::Karafka::Web.config.ttl / 1_000
68
+ now = float_now
69
+
70
+ processes.delete_if do |details|
71
+ now - details[:dispatched_at] > max_ttl
72
+ end
73
+ end
74
+
75
+ # Ensures that we always return processes sorted by their name
76
+ # @param processes [Array<Hash>]
77
+ # @return [Array<Hash>] sorted processes data
78
+ def sort_processes(processes)
79
+ processes.sort_by { |consumer| consumer[:process][:name] }
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ module Web
5
+ module Ui
6
+ module Models
7
+ # Represents the current consumer processes aggregated state
8
+ # This state is the core of Karafka reporting. It holds the most important aggregated data
9
+ # as well as pointers to states of particular consumers and their details.
10
+ class State < Lib::HashProxy
11
+ extend ::Karafka::Core::Helpers::Time
12
+
13
+ class << self
14
+ # @return [State, false] current aggregated state or false if not found
15
+ # @note Current state may contain expired data, for example of processes that were
16
+ # forcefully killed, etc. We clean this prior to returning the state.
17
+ def current
18
+ state = fetch
19
+
20
+ return false unless state
21
+
22
+ state = state.payload
23
+ evict_expired_processes(state)
24
+ sort_processes(state)
25
+
26
+ new(state)
27
+ end
28
+
29
+ # @return [State] current aggregated state
30
+ # @raise [::Karafka::Web::Errors::Ui::NotFoundError] raised when there is no current
31
+ # state. Probably because `karafka server` was never executed
32
+ def current!
33
+ current || raise(::Karafka::Web::Errors::Ui::NotFoundError)
34
+ end
35
+
36
+ private
37
+
38
+ # @return [::Karafka::Messages::Message, nil] most recent state or nil if none
39
+ def fetch
40
+ ::Karafka::Admin.read_topic(
41
+ Karafka::Web.config.topics.consumers.states,
42
+ 0,
43
+ 1
44
+ ).last
45
+ end
46
+
47
+ # Evicts (removes) details about processes that are beyond our TTL on liveliness
48
+ # @param state_hash [Hash] raw message state hash
49
+ def evict_expired_processes(state_hash)
50
+ max_ttl = ::Karafka::Web.config.ttl / 1_000
51
+
52
+ state_hash[:processes].delete_if do |_, details|
53
+ float_now - details[:dispatched_at] > max_ttl
54
+ end
55
+ end
56
+
57
+ # Sorts the processes based on their unique ids, so they are always in order
58
+ # @param state_hash [Hash] raw message state hash
59
+ def sort_processes(state_hash)
60
+ state_hash[:processes] = state_hash[:processes].to_a.sort_by(&:first).to_h
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ module Web
5
+ module Ui
6
+ module Models
7
+ # Single topic data representation model
8
+ class Topic < Lib::HashProxy
9
+ # @return [Array<Partition>] All topic partitions data
10
+ def partitions
11
+ super.values.map do |partition_hash|
12
+ Partition.new(partition_hash)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,120 @@
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
+ # Pro Web UI components
18
+ module Pro
19
+ # Main Roda Web App that servers all the metrics and stats
20
+ class App < Ui::Base
21
+ opts[:root] = Karafka::Web.gem_root.join('lib/karafka/web/ui/pro')
22
+
23
+ instance_exec(&CONTEXT_DETAILS)
24
+
25
+ plugin :render, escape: true, engine: 'erb', allowed_paths: [
26
+ Karafka::Web.gem_root.join('lib/karafka/web/ui/pro/views'),
27
+ Karafka::Web.gem_root.join('lib/karafka/web/ui/views')
28
+ ]
29
+
30
+ plugin :additional_view_directories, [
31
+ Karafka::Web.gem_root.join('lib/karafka/web/ui/views')
32
+ ]
33
+
34
+ route do |r|
35
+ r.root { r.redirect root_path('consumers') }
36
+
37
+ @current_page = params.current_page
38
+
39
+ r.on 'consumers' do
40
+ controller = Controllers::Consumers.new(params)
41
+
42
+ r.get String, 'jobs' do |process_id|
43
+ render_response controller.jobs(process_id)
44
+ end
45
+
46
+ r.get String, 'subscriptions' do |process_id|
47
+ render_response controller.subscriptions(process_id)
48
+ end
49
+
50
+ r.get do
51
+ @breadcrumbs = false
52
+ render_response controller.index
53
+ end
54
+ end
55
+
56
+ r.get 'jobs' do
57
+ controller = Controllers::Jobs.new(params)
58
+ render_response controller.index
59
+ end
60
+
61
+ r.on 'routing' do
62
+ controller = Controllers::Routing.new(params)
63
+
64
+ r.get String do |topic_id|
65
+ render_response controller.show(topic_id)
66
+ end
67
+
68
+ r.get do
69
+ render_response controller.index
70
+ end
71
+ end
72
+
73
+ r.on 'explorer' do
74
+ controller = Controllers::Explorer.new(params)
75
+
76
+ r.get String, Integer, Integer do |topic_id, partition_id, offset|
77
+ render_response controller.show(topic_id, partition_id, offset)
78
+ end
79
+
80
+ r.get String, Integer do |topic_id, partition_id|
81
+ render_response controller.partition(topic_id, partition_id)
82
+ end
83
+
84
+ r.get do
85
+ render_response controller.index
86
+ end
87
+ end
88
+
89
+ r.get 'health' do
90
+ controller = Controllers::Health.new(params)
91
+ render_response controller.index
92
+ end
93
+
94
+ r.get 'cluster' do
95
+ controller = Controllers::Cluster.new(params)
96
+ render_response controller.index
97
+ end
98
+
99
+ r.on 'errors' do
100
+ controller = Controllers::Errors.new(params)
101
+
102
+ r.get Integer do |partition_id|
103
+ render_response controller.index(partition_id)
104
+ end
105
+
106
+ r.get Integer, Integer do |partition_id, offset|
107
+ render_response controller.show(partition_id, offset)
108
+ end
109
+ end
110
+
111
+ r.get 'dlq' do
112
+ controller = Controllers::Dlq.new(params)
113
+ render_response controller.index
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ module Web
5
+ module Ui
6
+ module Pro
7
+ # Namespace for Pro controllers
8
+ module Controllers
9
+ # Cluster controller
10
+ class Cluster < Ui::Controllers::Cluster
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,54 @@
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
+ # Controller for displaying consumers states and details about them
20
+ class Consumers < Ui::Controllers::Base
21
+ # Consumers list
22
+ def index
23
+ @current_state = Models::State.current!
24
+ processes_total = Models::Processes.active(@current_state)
25
+ @counters = Lib::HashProxy.new(@current_state[:stats])
26
+ @processes, @next_page = Lib::PaginateArray.new.call(
27
+ processes_total,
28
+ @params.current_page
29
+ )
30
+
31
+ respond
32
+ end
33
+
34
+ # @param process_id [String] id of the process we're interested in
35
+ def jobs(process_id)
36
+ current_state = Models::State.current!
37
+ @process = Models::Process.find(current_state, process_id)
38
+
39
+ respond
40
+ end
41
+
42
+ # @param process_id [String] id of the process we're interested in
43
+ def subscriptions(process_id)
44
+ current_state = Models::State.current!
45
+ @process = Models::Process.find(current_state, process_id)
46
+
47
+ respond
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,44 @@
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
+ # DLQ topics overview
20
+ class Dlq < Ui::Controllers::Base
21
+ # Lists DLQ topics
22
+ def index
23
+ topics = Karafka::App.consumer_groups.flat_map(&:topics).flat_map(&:to_a)
24
+
25
+ dlq_topic_names = topics
26
+ .map { |source_topic| source_topic.dead_letter_queue.topic }
27
+ .uniq
28
+ .compact
29
+ .select(&:itself)
30
+
31
+ @dlq_topics = Karafka::Admin
32
+ .cluster_info
33
+ .topics
34
+ .select { |topic| dlq_topic_names.include?(topic[:topic_name]) }
35
+ .sort_by { |topic| topic[:topic_name] }
36
+
37
+ respond
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,57 @@
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
+ # Errors details controller
20
+ class Errors < Ui::Controllers::Base
21
+ # @param partition_id [Integer] id of the partition of errors we are interested in
22
+ def index(partition_id)
23
+ errors_topic = ::Karafka::Web.config.topics.errors
24
+ @partition_id = partition_id
25
+ @previous_page, @error_messages, @next_page, @partitions_count = \
26
+ Models::Message.page(
27
+ errors_topic,
28
+ @partition_id,
29
+ @params.current_page
30
+ )
31
+
32
+ respond
33
+ end
34
+
35
+ # Shows given error details
36
+ #
37
+ # @param partition_id [Integer]
38
+ # @param offset [Integer]
39
+ def show(partition_id, offset)
40
+ errors_topic = ::Karafka::Web.config.topics.errors
41
+
42
+ @partition_id = partition_id
43
+ @offset = offset
44
+ @error_message = Models::Message.find(
45
+ errors_topic,
46
+ @partition_id,
47
+ @offset
48
+ )
49
+
50
+ respond
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,79 @@
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
+ # Data explorer controller
20
+ class Explorer < Ui::Controllers::Base
21
+ # Lists all the topics we can explore
22
+ def index
23
+ @topics = Karafka::Admin
24
+ .cluster_info
25
+ .topics
26
+ .reject { |topic| topic[:topic_name] == '__consumer_offsets' }
27
+ .sort_by { |topic| topic[:topic_name] }
28
+
29
+ respond
30
+ end
31
+
32
+ # Shows messages available in a given partition
33
+ #
34
+ # @param topic_id [String]
35
+ # @param partition_id [Integer]
36
+ def partition(topic_id, partition_id)
37
+ @topic_id = topic_id
38
+ @partition_id = partition_id
39
+ @previous_page, @messages, @next_page, @partitions_count = Ui::Models::Message.page(
40
+ @topic_id,
41
+ @partition_id,
42
+ @params.current_page
43
+ )
44
+
45
+ respond
46
+ end
47
+
48
+ # Displays given message
49
+ #
50
+ # @param topic_id [String]
51
+ # @param partition_id [Integer]
52
+ # @param offset [Integer] offset of the message we want to display
53
+ def show(topic_id, partition_id, offset)
54
+ @topic_id = topic_id
55
+ @partition_id = partition_id
56
+ @offset = offset
57
+ @message = Ui::Models::Message.find(@topic_id, @partition_id, @offset)
58
+ @payload_error = false
59
+
60
+ @decrypt = if ::Karafka::App.config.encryption.active
61
+ ::Karafka::Web.config.ui.decrypt
62
+ else
63
+ true
64
+ end
65
+
66
+ begin
67
+ @pretty_payload = JSON.pretty_generate(@message.payload)
68
+ rescue StandardError => e
69
+ @payload_error = e
70
+ end
71
+
72
+ respond
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,33 @@
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
+ # Health state controller
20
+ class Health < Ui::Controllers::Base
21
+ # Displays the current system state
22
+ def index
23
+ current_state = Models::State.current!
24
+ @stats = Models::Health.current(current_state)
25
+
26
+ respond
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ 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
+ # Displays list of active jobs
20
+ class Jobs < Ui::Controllers::Jobs
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ 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
+ # Routing details - same as in OSS
20
+ class Routing < Ui::Controllers::Routing
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end