karafka-web 0.5.2 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +69 -6
  4. data/Gemfile.lock +14 -14
  5. data/karafka-web.gemspec +3 -3
  6. data/lib/karafka/web/config.rb +11 -5
  7. data/lib/karafka/web/installer.rb +2 -3
  8. data/lib/karafka/web/tracking/consumers/contracts/consumer_group.rb +1 -1
  9. data/lib/karafka/web/tracking/consumers/contracts/job.rb +4 -1
  10. data/lib/karafka/web/tracking/consumers/contracts/partition.rb +1 -1
  11. data/lib/karafka/web/tracking/consumers/contracts/report.rb +8 -4
  12. data/lib/karafka/web/tracking/consumers/contracts/subscription_group.rb +1 -1
  13. data/lib/karafka/web/tracking/consumers/contracts/topic.rb +3 -1
  14. data/lib/karafka/web/tracking/consumers/listeners/base.rb +2 -2
  15. data/lib/karafka/web/tracking/consumers/listeners/errors.rb +8 -44
  16. data/lib/karafka/web/tracking/consumers/listeners/processing.rb +5 -0
  17. data/lib/karafka/web/tracking/consumers/reporter.rb +151 -0
  18. data/lib/karafka/web/tracking/consumers/sampler.rb +2 -1
  19. data/lib/karafka/web/tracking/contracts/base.rb +34 -0
  20. data/lib/karafka/web/tracking/contracts/error.rb +31 -0
  21. data/lib/karafka/web/tracking/helpers/error_info.rb +50 -0
  22. data/lib/karafka/web/tracking/memoized_shell.rb +1 -1
  23. data/lib/karafka/web/tracking/producers/listeners/base.rb +33 -0
  24. data/lib/karafka/web/tracking/producers/listeners/errors.rb +66 -0
  25. data/lib/karafka/web/tracking/producers/listeners/reporter.rb +21 -0
  26. data/lib/karafka/web/tracking/producers/reporter.rb +101 -0
  27. data/lib/karafka/web/tracking/producers/sampler.rb +42 -0
  28. data/lib/karafka/web/tracking/sampler.rb +5 -0
  29. data/lib/karafka/web/ui/controllers/consumers.rb +2 -4
  30. data/lib/karafka/web/ui/models/counters.rb +51 -0
  31. data/lib/karafka/web/ui/models/status.rb +31 -7
  32. data/lib/karafka/web/ui/pro/controllers/consumers.rb +2 -3
  33. data/lib/karafka/web/ui/pro/views/consumers/consumer/_job.erb +6 -6
  34. data/lib/karafka/web/ui/pro/views/consumers/consumer/_metrics.erb +6 -1
  35. data/lib/karafka/web/ui/pro/views/consumers/index.erb +25 -21
  36. data/lib/karafka/web/ui/pro/views/consumers/jobs.erb +1 -1
  37. data/lib/karafka/web/ui/pro/views/errors/_breadcrumbs.erb +1 -2
  38. data/lib/karafka/web/ui/pro/views/errors/_error.erb +8 -6
  39. data/lib/karafka/web/ui/pro/views/errors/show.erb +3 -2
  40. data/lib/karafka/web/ui/public/stylesheets/application.css +4 -0
  41. data/lib/karafka/web/ui/views/consumers/_no_consumers.erb +9 -0
  42. data/lib/karafka/web/ui/views/consumers/index.erb +24 -20
  43. data/lib/karafka/web/ui/views/errors/_breadcrumbs.erb +1 -2
  44. data/lib/karafka/web/ui/views/errors/_detail.erb +9 -1
  45. data/lib/karafka/web/ui/views/errors/_error.erb +8 -6
  46. data/lib/karafka/web/ui/views/errors/show.erb +50 -2
  47. data/lib/karafka/web/ui/views/shared/_feature_pro.erb +4 -0
  48. data/lib/karafka/web/ui/views/shared/_pagination.erb +8 -2
  49. data/lib/karafka/web/ui/views/shared/exceptions/pro_only.erb +0 -4
  50. data/lib/karafka/web/ui/views/status/failures/_initial_state.erb +1 -10
  51. data/lib/karafka/web/ui/views/status/info/_components.erb +6 -1
  52. data/lib/karafka/web/ui/views/status/show.erb +6 -1
  53. data/lib/karafka/web/ui/views/status/successes/_connection.erb +1 -0
  54. data/lib/karafka/web/ui/views/status/warnings/_connection.erb +11 -0
  55. data/lib/karafka/web/version.rb +1 -1
  56. data.tar.gz.sig +0 -0
  57. metadata +28 -16
  58. metadata.gz.sig +0 -0
  59. data/lib/karafka/web/tracking/base_contract.rb +0 -31
  60. data/lib/karafka/web/tracking/reporter.rb +0 -144
  61. data/lib/karafka/web/ui/pro/views/consumers/_summary.erb +0 -81
  62. data/lib/karafka/web/ui/pro/views/errors/_cleaned.erb +0 -3
  63. data/lib/karafka/web/ui/pro/views/errors/_detail.erb +0 -31
  64. data/lib/karafka/web/ui/pro/views/errors/_no_errors.erb +0 -3
  65. data/lib/karafka/web/ui/pro/views/jobs/_breadcrumbs.erb +0 -5
  66. data/lib/karafka/web/ui/views/consumers/_breadcrumbs.erb +0 -27
@@ -1,144 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Karafka
4
- module Web
5
- module Tracking
6
- # Reports the collected data about the process and sends it, so we can use it in the UI
7
- class Reporter
8
- include ::Karafka::Core::Helpers::Time
9
- include ::Karafka::Helpers::Async
10
-
11
- # Minimum number of messages to produce to produce then in sync mode
12
- # This acts as a small back-off not to overload the system in case we would have extremely
13
- # big number of errors happening
14
- PRODUCE_SYNC_THRESHOLD = 25
15
-
16
- private_constant :PRODUCE_SYNC_THRESHOLD
17
-
18
- # This mutex is shared between tracker and samplers so there is no case where metrics
19
- # would be collected same time tracker reports
20
- MUTEX = Mutex.new
21
-
22
- def initialize
23
- # Move back so first report is dispatched fast to indicate, that the process is alive
24
- @tracked_at = monotonic_now - 10_000
25
- @consumer_contract = Consumers::Contracts::Report.new
26
- end
27
-
28
- # Dispatches the current state from sampler to appropriate topics
29
- #
30
- # @param forced [Boolean] should we report bypassing the time frequency or should we report
31
- # only in case we would not send the report for long enough time.
32
- def report(forced: false)
33
- MUTEX.synchronize do
34
- # Start background thread only when needed
35
- # This prevents us from starting it too early or for non-consumer processes where
36
- # Karafka is being included
37
- async_call unless @running
38
-
39
- return unless report?(forced)
40
-
41
- @tracked_at = monotonic_now
42
-
43
- consumer_report = consumer_sampler.to_report
44
-
45
- @consumer_contract.validate!(consumer_report)
46
-
47
- process_name = consumer_report[:process][:name]
48
-
49
- # Report consumers statuses
50
- messages = [
51
- {
52
- topic: ::Karafka::Web.config.topics.consumers.reports,
53
- payload: consumer_report.to_json,
54
- key: process_name,
55
- partition: 0
56
- }
57
- ]
58
-
59
- # Report errors that occurred (if any)
60
- messages += consumer_sampler.errors.map do |error|
61
- {
62
- topic: Karafka::Web.config.topics.errors,
63
- payload: error.to_json,
64
- # Always dispatch errors from the same process to the same partition
65
- key: process_name
66
- }
67
- end
68
-
69
- produce(messages)
70
-
71
- # Clear the sampler so it tracks new state changes without previous once impacting
72
- # the data
73
- consumer_sampler.clear
74
- end
75
- # Since we run this in a background thread, there may be a case upon shutdown, where the
76
- # producer is closed right before a potential dispatch. It is not worth dealing with this
77
- # and we can just safely ignore this
78
- rescue WaterDrop::Errors::ProducerClosedError
79
- nil
80
- end
81
-
82
- # Reports bypassing frequency check. This can be used to report when state changes in the
83
- # process drastically. For example when process is stopping, we want to indicate this as
84
- # fast as possible in the UI, etc.
85
- def report!
86
- report(forced: true)
87
- end
88
-
89
- private
90
-
91
- # Reports the process state once in a while
92
- def call
93
- @running = true
94
-
95
- loop do
96
- report
97
-
98
- # We won't track more often anyhow but want to try frequently not to miss a window
99
- # We need to convert the sleep interval into seconds for sleep
100
- sleep(::Karafka::Web.config.tracking.interval / 1_000 / 10)
101
- end
102
- end
103
-
104
- # @param forced [Boolean] is this report forced. Forced means that as long as we can flush
105
- # we will flush
106
- # @return [Boolean] Should we report or is it not yet time to do so
107
- def report?(forced)
108
- # We never report in initializing phase because things are not yet fully configured
109
- return false if ::Karafka::App.initializing?
110
- # We never report in the initialized because server is not yet ready until Karafka is
111
- # fully running and some of the things like listeners are not yet available
112
- return false if ::Karafka::App.initialized?
113
-
114
- return true if forced
115
-
116
- (monotonic_now - @tracked_at) >= ::Karafka::Web.config.tracking.interval
117
- end
118
-
119
- # @return [Object] sampler for the metrics
120
- def consumer_sampler
121
- @consumer_sampler ||= ::Karafka::Web.config.tracking.consumers.sampler
122
- end
123
-
124
- # Produces messages to Kafka.
125
- #
126
- # @param messages [Array<Hash>]
127
- #
128
- # @note We pick either sync or async dependent on number of messages. The trick here is,
129
- # that we do not want to end up overloading the internal queue with messages in case
130
- # someone has a lot of errors from processing or other errors. Producing sync will wait
131
- # for the delivery, hence will slow things down a little bit. On the other hand during
132
- # normal operations we should not have that many messages to dispatch and it should not
133
- # slowdown any processing.
134
- def produce(messages)
135
- if messages.count >= PRODUCE_SYNC_THRESHOLD
136
- ::Karafka.producer.produce_many_sync(messages)
137
- else
138
- ::Karafka.producer.produce_many_async(messages)
139
- end
140
- end
141
- end
142
- end
143
- end
144
- end
@@ -1,81 +0,0 @@
1
- <div id="summary" class="container text-center mb-5">
2
- <div class="row">
3
-
4
- <div class="col-lg-2 offset-md-1">
5
- <div class="card mb-0">
6
- <div class="card-body">
7
- <p class="card-text">
8
- <div class="stat mb-1">
9
- <%= @counters.processes %>
10
- </div>
11
- <div class="desc">
12
- Processes
13
- </div>
14
- </p>
15
- </div>
16
- </div>
17
- </div>
18
-
19
- <div class="col-lg-2">
20
- <div class="card mb-0">
21
- <div class="card-body">
22
- <p class="card-text">
23
- <div class="stat mb-1">
24
- <%= @counters.threads_count %>
25
- </div>
26
- <div class="desc">
27
- Worker threads
28
- </div>
29
- </p>
30
- </div>
31
- </div>
32
- </div>
33
-
34
- <div class="col-lg-2">
35
- <div class="card mb-0">
36
- <div class="card-body">
37
- <p class="card-text">
38
- <div class="stat mb-1">
39
- <%= @counters.listeners_count %>
40
- </div>
41
- <div class="desc">
42
- Listeners
43
- </div>
44
- </p>
45
- </div>
46
- </div>
47
- </div>
48
-
49
- <div class="col-lg-2">
50
- <div class="card mb-0">
51
- <div class="card-body">
52
- <p class="card-text">
53
- <div class="stat mb-1">
54
- <%= @counters.utilization.round(2) %>
55
- %
56
- </div>
57
- <div class="desc">
58
- Utilization
59
- </div>
60
- </p>
61
- </div>
62
- </div>
63
- </div>
64
-
65
- <div class="col-lg-2">
66
- <div class="card mb-0">
67
- <div class="card-body">
68
- <p class="card-text">
69
- <div class="stat mb-1">
70
- <%= format_memory @counters.rss %>
71
- </div>
72
- <div class="desc">
73
- RSS
74
- </div>
75
- </p>
76
- </div>
77
- </div>
78
- </div>
79
-
80
- </div>
81
- </div>
@@ -1,3 +0,0 @@
1
- <div class="alert alert-info" role="alert">
2
- This errors topic partition had all of its errored compacted and cleaned.
3
- </div>
@@ -1,31 +0,0 @@
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 %w[sasl ssl].any? { |scope| k2.to_s.include?(scope) } %>
9
- ***
10
- <% elsif k2.to_s == 'tags' %>
11
- <%== tags(v2) %>
12
- <% else %>
13
- <%= v2 %>
14
- <% end %>
15
- </td>
16
- </tr>
17
- <% end %>
18
- <% else %>
19
- <tr>
20
- <td>
21
- <%= k %>
22
- </td>
23
- <td>
24
- <% if k == :occurred_at %>
25
- <%== relative_time v %>
26
- <% else %>
27
- <%= v %>
28
- <% end %>
29
- </td>
30
- </tr>
31
- <% end %>
@@ -1,3 +0,0 @@
1
- <div class="alert alert-info" role="alert">
2
- There are no errors in this errors topic partition.
3
- </div>
@@ -1,5 +0,0 @@
1
- <li class="breadcrumb-item">
2
- <a href="<%= root_path('jobs') %>">
3
- Running jobs
4
- </a>
5
- </li>
@@ -1,27 +0,0 @@
1
- <% if @process %>
2
- <li class="breadcrumb-item">
3
- <a href="<%= root_path('consumers') %>">
4
- Consumers
5
- </a>
6
- </li>
7
-
8
- <li class="breadcrumb-item">
9
- <a href="<%= root_path('consumers', @process.id, 'subscriptions') %>">
10
- <%= @process.name %>
11
- </a>
12
- </li>
13
-
14
- <% if current_path.include?('/jobs') %>
15
- <li class="breadcrumb-item">
16
- <a href="<%= root_path('consumers', @process.id, 'jobs') %>">
17
- Running jobs
18
- </a>
19
- </li>
20
- <% else %>
21
- <li class="breadcrumb-item">
22
- <a href="<%= root_path('consumers', @process.id, 'subscriptions') %>">
23
- Active subscriptions
24
- </a>
25
- </li>
26
- <% end %>
27
- <% end %>