karafka-web 0.8.0 → 0.8.1

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 (47) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +8 -0
  4. data/Gemfile.lock +1 -1
  5. data/lib/karafka/web/config.rb +4 -0
  6. data/lib/karafka/web/contracts/config.rb +1 -0
  7. data/lib/karafka/web/installer.rb +3 -2
  8. data/lib/karafka/web/management/actions/enable.rb +5 -0
  9. data/lib/karafka/web/management/actions/extend_boot_file.rb +3 -1
  10. data/lib/karafka/web/management/migrations/1706607960_introduce_lag_total_in_metrics.rb +38 -0
  11. data/lib/karafka/web/management/migrations/1706607960_introduce_lag_total_in_states.rb +22 -0
  12. data/lib/karafka/web/management/migrations/1706611396_rename_lag_total_to_lag_hybrid_in_metrics.rb +36 -0
  13. data/lib/karafka/web/management/migrations/1706611396_rename_lag_total_to_lag_hybrid_in_states.rb +21 -0
  14. data/lib/karafka/web/processing/consumers/aggregators/metrics.rb +7 -9
  15. data/lib/karafka/web/processing/consumers/aggregators/state.rb +8 -9
  16. data/lib/karafka/web/processing/consumers/contracts/aggregated_stats.rb +1 -2
  17. data/lib/karafka/web/processing/consumers/contracts/topic_stats.rb +1 -2
  18. data/lib/karafka/web/ui/controllers/consumers.rb +1 -1
  19. data/lib/karafka/web/ui/models/metrics/charts/topics.rb +5 -5
  20. data/lib/karafka/web/ui/models/partition.rb +22 -0
  21. data/lib/karafka/web/ui/models/process.rb +3 -14
  22. data/lib/karafka/web/ui/pro/app.rb +4 -0
  23. data/lib/karafka/web/ui/pro/controllers/consumers.rb +10 -4
  24. data/lib/karafka/web/ui/pro/controllers/health.rb +12 -0
  25. data/lib/karafka/web/ui/pro/views/consumers/_consumer.erb +1 -1
  26. data/lib/karafka/web/ui/pro/views/consumers/_counters.erb +2 -2
  27. data/lib/karafka/web/ui/pro/views/consumers/consumer/_partition.erb +3 -3
  28. data/lib/karafka/web/ui/pro/views/consumers/consumer/_subscription_group.erb +2 -2
  29. data/lib/karafka/web/ui/pro/views/consumers/index.erb +1 -1
  30. data/lib/karafka/web/ui/pro/views/dashboard/index.erb +3 -3
  31. data/lib/karafka/web/ui/pro/views/health/_breadcrumbs.erb +8 -0
  32. data/lib/karafka/web/ui/pro/views/health/_consumer_group_header.erb +14 -0
  33. data/lib/karafka/web/ui/pro/views/health/_partition.erb +1 -9
  34. data/lib/karafka/web/ui/pro/views/health/_partition_lags.erb +24 -0
  35. data/lib/karafka/web/ui/pro/views/health/_partition_offset.erb +1 -1
  36. data/lib/karafka/web/ui/pro/views/health/_tabs.erb +9 -0
  37. data/lib/karafka/web/ui/pro/views/health/changes.erb +1 -15
  38. data/lib/karafka/web/ui/pro/views/health/lags.erb +52 -0
  39. data/lib/karafka/web/ui/pro/views/health/offsets.erb +2 -15
  40. data/lib/karafka/web/ui/pro/views/health/overview.erb +2 -17
  41. data/lib/karafka/web/ui/views/consumers/_counters.erb +2 -2
  42. data/lib/karafka/web/ui/views/consumers/index.erb +1 -1
  43. data/lib/karafka/web/ui/views/dashboard/index.erb +3 -3
  44. data/lib/karafka/web/version.rb +1 -1
  45. data.tar.gz.sig +0 -0
  46. metadata +9 -2
  47. metadata.gz.sig +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 446dcc1a42f38d364747702c52aeefbdede83b203eb13bfa755c8e2e1f05438e
4
- data.tar.gz: 20e7cc3cb0b400b382715b184db667d4791aeb0d626b4e9c6af7b314394d3309
3
+ metadata.gz: 69148848d89de8a7c5a1cebec7d3f5c0c60e3bd85caa41eedea8b5082dd6bf85
4
+ data.tar.gz: c0f6acfdd3e732ebfc29a6e954cd8a1f8d2c75dff77eba28978a99d6394d4087
5
5
  SHA512:
6
- metadata.gz: f2ecb81d1dd77b5dc1c9feaa75dc1f262335da4a812785035c0ca85fdf5e1413cefa724a73b13032908d3fc02e52096140ee89eae18ca7d933193c1ed7ddc011
7
- data.tar.gz: 59c4a2324ee277cb61c197ffa190da2e59bb594d8c615296074a5f144b3a9d6ef3ebd31a70e37ab687e7c1a872f9efc9624b24400eb2a44be1034e0901d74586
6
+ metadata.gz: a89e22500fc5fedf8e432b666a84cf092d13c9b2747a4d08dc983d8ffba2f077781f06a131631b6315c64764bc00b7d06265a4d9fcd8c11bdd74d47eda5041f9
7
+ data.tar.gz: 7d29af2874b1df83af78fee69af89021bdcd1fa705686370f59ab276ee6808eef98e4a0b98dd273158888b472cea203bcca84f494e84c178f7733404b080166a
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Karafka Web changelog
2
2
 
3
+ ## 0.8.1 (2024-02-01)
4
+ - [Enhancement] Introduce "Lags" health view.
5
+ - [Enhancement] Remove "Stored Lag" and "Committed Offset" from Health Overview due to Lags Tab.
6
+ - [Enhancement] Report lag on consumers that did not yet marked offsets.
7
+ - [Enhancement] Use more accurate lag reporting that compensates for lack of stored lag.
8
+ - [Fix] When first message after process start is crashed without DLQ lag is not reported.
9
+ - [Fix] Wrong order of enabled injection causes fresh install to crash.
10
+
3
11
  ## 0.8.0 (2024-01-26)
4
12
  - **[Feature]** Provide ability to sort table data for part of the views (note: not all attributes can be sorted due to technical limitations of sub-components fetching from Kafka).
5
13
  - **[Feature]** Track and report pause timeouts via "Changes" view in Health.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- karafka-web (0.8.0)
4
+ karafka-web (0.8.1)
5
5
  erubi (~> 1.4)
6
6
  karafka (>= 2.3.0, < 2.4.0)
7
7
  karafka-core (>= 2.3.0, < 2.4.0)
@@ -6,6 +6,10 @@ module Karafka
6
6
  class Config
7
7
  include ::Karafka::Core::Configurable
8
8
 
9
+ # Is the Web UI enabled and things were configured.
10
+ # Automatically set to true in case things got enabled.
11
+ setting :enabled, default: false
12
+
9
13
  # How long do we consider the process alive without receiving status info about it
10
14
  # For this long we also display dead processes (shutdown) in the UI
11
15
  # This is used both in the processing for eviction and in the UI
@@ -10,6 +10,7 @@ module Karafka
10
10
  # Use the same regexp as Karafka for topics validation
11
11
  TOPIC_REGEXP = ::Karafka::Contracts::TOPIC_REGEXP
12
12
 
13
+ required(:enabled) { |val| [true, false, nil].include?(val) }
13
14
  required(:ttl) { |val| val.is_a?(Numeric) && val.positive? }
14
15
 
15
16
  nested(:topics) do
@@ -15,17 +15,18 @@ module Karafka
15
15
  puts
16
16
  puts 'Installing Karafka Web UI...'
17
17
  puts
18
+ Management::Actions::ExtendBootFile.new.call
19
+ puts
18
20
  puts 'Creating necessary topics and populating state data...'
19
21
  puts
20
22
  Management::Actions::CreateTopics.new.call(replication_factor)
21
23
  wait_for_topics
24
+ enable!
22
25
  Management::Actions::CreateInitialStates.new.call
23
26
  puts
24
27
  puts 'Running data migrations...'
25
28
  Management::Actions::MigrateStatesData.new.call
26
29
  puts
27
- Management::Actions::ExtendBootFile.new.call
28
- puts
29
30
  puts("Installation #{green('completed')}. Have fun!")
30
31
  puts
31
32
  end
@@ -10,6 +10,11 @@ module Karafka
10
10
  class Enable < Base
11
11
  # Enables routing consumer group and subscribes Web-UI listeners
12
12
  def call
13
+ # Prevent double enabling
14
+ return if ::Karafka::Web.config.enabled
15
+
16
+ ::Karafka::Web.config.enabled = true
17
+
13
18
  extend_routing
14
19
  setup_tracking_activity
15
20
 
@@ -22,7 +22,9 @@ module Karafka
22
22
 
23
23
  # Adds needed code
24
24
  def call
25
- if File.read(Karafka.boot_file).include?(ENABLER_CODE)
25
+ # We detect this that way so in case our template or user has enabled as a comment
26
+ # it still adds the template and runs install
27
+ if File.readlines(Karafka.boot_file).any? { |line| line.start_with?(ENABLER_CODE) }
26
28
  puts "Web UI #{already} installed."
27
29
  else
28
30
  puts 'Updating the Karafka boot file...'
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ module Web
5
+ module Management
6
+ module Migrations
7
+ # Moves to using lag total as a normalization for both lags
8
+ class IntroduceLagTotalInMetrics < Base
9
+ self.versions_until = '1.2.0'
10
+ self.type = :consumers_metrics
11
+
12
+ # @param state [Hash]
13
+ def migrate(state)
14
+ state[:aggregated].each_value do |metrics|
15
+ metrics.each do |metric|
16
+ metric.last[:lag_total] = metric.last[:lag_stored]
17
+ metric.last.delete(:lag_stored)
18
+ metric.last.delete(:lag)
19
+ end
20
+ end
21
+
22
+ state[:consumer_groups].each_value do |metrics|
23
+ metrics.each do |metric_group|
24
+ metric_group.last.each_value do |metric|
25
+ metric.each_value do |sample|
26
+ sample[:lag_total] = sample[:lag_stored]
27
+ sample.delete(:lag_stored)
28
+ sample.delete(:lag)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ module Web
5
+ module Management
6
+ module Migrations
7
+ # Moves to using lag total as a normalization for both lags
8
+ class IntroduceLagTotalInStates < Base
9
+ self.versions_until = '1.3.0'
10
+ self.type = :consumers_state
11
+
12
+ # @param state [Hash]
13
+ def migrate(state)
14
+ state[:stats][:lag_total] = state[:stats][:lag_stored]
15
+ state[:stats].delete(:lag)
16
+ state[:stats].delete(:lag_stored)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ module Web
5
+ module Management
6
+ module Migrations
7
+ # Renames total lag to hybrid to better represent what it is
8
+ class RenameLagTotalToLagHybridInMetrics < Base
9
+ self.versions_until = '1.2.1'
10
+ self.type = :consumers_metrics
11
+
12
+ # @param state [Hash]
13
+ def migrate(state)
14
+ state[:aggregated].each_value do |metrics|
15
+ metrics.each do |metric|
16
+ metric.last[:lag_hybrid] = metric.last[:lag_total] || 0
17
+ metric.last.delete(:lag_total)
18
+ end
19
+ end
20
+
21
+ state[:consumer_groups].each_value do |metrics|
22
+ metrics.each do |metric_group|
23
+ metric_group.last.each_value do |metric|
24
+ metric.each_value do |sample|
25
+ sample[:lag_hybrid] = sample[:lag_total]
26
+ sample.delete(:lag_total)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ module Web
5
+ module Management
6
+ module Migrations
7
+ # Renames total lag to hybrid to better represent what it is
8
+ class RenameLagTotalToLagHybridInStates < Base
9
+ self.versions_until = '1.3.1'
10
+ self.type = :consumers_state
11
+
12
+ # @param state [Hash]
13
+ def migrate(state)
14
+ state[:stats][:lag_hybrid] = state[:stats][:lag_total] || 0
15
+ state[:stats].delete(:lag_total)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -11,7 +11,7 @@ module Karafka
11
11
  class Metrics < Base
12
12
  # Current schema version
13
13
  # This is used for detecting incompatible changes and writing migrations
14
- SCHEMA_VERSION = '1.1.2'
14
+ SCHEMA_VERSION = '1.2.1'
15
15
 
16
16
  def initialize
17
17
  super
@@ -92,12 +92,11 @@ module Karafka
92
92
  cgs = {}
93
93
 
94
94
  iterate_partitions_data do |group_name, topic_name, partitions_data|
95
- lags = partitions_data
96
- .map { |p_details| p_details.fetch(:lag, -1) }
97
- .reject(&:negative?)
98
-
99
- lags_stored = partitions_data
100
- .map { |p_details| p_details.fetch(:lag_stored, -1) }
95
+ lags_hybrid = partitions_data
96
+ .map do |p_details|
97
+ lag_stored = p_details.fetch(:lag_stored, -1)
98
+ lag_stored.negative? ? p_details.fetch(:lag, -1) : lag_stored
99
+ end
101
100
  .reject(&:negative?)
102
101
 
103
102
  offsets_hi = partitions_data
@@ -121,8 +120,7 @@ module Karafka
121
120
 
122
121
  cgs[group_name] ||= {}
123
122
  cgs[group_name][topic_name] = {
124
- lag_stored: lags_stored.sum,
125
- lag: lags.sum,
123
+ lag_hybrid: lags_hybrid.sum,
126
124
  pace: offsets_hi.sum,
127
125
  # Take max last stable offset duration without any change. This can
128
126
  # indicate a hanging transaction, because the offset will not move forward
@@ -20,7 +20,7 @@ module Karafka
20
20
  # Current schema version
21
21
  # This can be used in the future for detecting incompatible changes and writing
22
22
  # migrations
23
- SCHEMA_VERSION = '1.2.2'
23
+ SCHEMA_VERSION = '1.3.1'
24
24
 
25
25
  # @param schema_manager [Karafka::Web::Processing::Consumers::SchemaManager] schema
26
26
  # manager that tracks the compatibility of schemas.
@@ -127,8 +127,7 @@ module Karafka
127
127
  stats[:processes] = 0
128
128
  stats[:rss] = 0
129
129
  stats[:listeners] = { active: 0, standby: 0 }
130
- stats[:lag] = 0
131
- stats[:lag_stored] = 0
130
+ stats[:lag_hybrid] = 0
132
131
  stats[:bytes_received] = 0
133
132
  stats[:bytes_sent] = 0
134
133
  utilization = 0
@@ -140,12 +139,13 @@ module Karafka
140
139
  report_stats = report[:stats]
141
140
  report_process = report[:process]
142
141
 
143
- lags = []
144
- lags_stored = []
142
+ lags_hybrid = []
145
143
 
146
144
  iterate_partitions(report) do |partition_stats|
147
- lags << partition_stats[:lag]
148
- lags_stored << partition_stats[:lag_stored]
145
+ lag_stored = partition_stats[:lag_stored]
146
+ lag = partition_stats[:lag]
147
+
148
+ lags_hybrid << (lag_stored.negative? ? lag : lag_stored)
149
149
  end
150
150
 
151
151
  stats[:busy] += report_stats[:busy]
@@ -157,8 +157,7 @@ module Karafka
157
157
  stats[:listeners][:standby] += report_process[:listeners][:standby]
158
158
  stats[:processes] += 1
159
159
  stats[:rss] += report_process[:memory_usage]
160
- stats[:lag] += lags.compact.reject(&:negative?).sum
161
- stats[:lag_stored] += lags_stored.compact.reject(&:negative?).sum
160
+ stats[:lag_hybrid] += lags_hybrid.compact.reject(&:negative?).sum
162
161
  utilization += report_stats[:utilization]
163
162
  end
164
163
 
@@ -21,8 +21,7 @@ module Karafka
21
21
  required(:processes) { |val| val.is_a?(Integer) && val >= 0 }
22
22
  required(:rss) { |val| val.is_a?(Numeric) && val >= 0 }
23
23
  required(:utilization) { |val| val.is_a?(Numeric) && val >= 0 }
24
- required(:lag_stored) { |val| val.is_a?(Integer) }
25
- required(:lag) { |val| val.is_a?(Integer) }
24
+ required(:lag_hybrid) { |val| val.is_a?(Integer) }
26
25
 
27
26
  nested(:listeners) do
28
27
  required(:active) { |val| val.is_a?(Integer) && val >= 0 }
@@ -9,8 +9,7 @@ module Karafka
9
9
  class TopicStats < Web::Contracts::Base
10
10
  configure
11
11
 
12
- required(:lag_stored) { |val| val.is_a?(Integer) }
13
- required(:lag) { |val| val.is_a?(Integer) }
12
+ required(:lag_hybrid) { |val| val.is_a?(Integer) }
14
13
  required(:pace) { |val| val.is_a?(Integer) }
15
14
  required(:ls_offset_fd) { |val| val.is_a?(Integer) && val >= 0 }
16
15
  end
@@ -9,7 +9,7 @@ module Karafka
9
9
  self.sortable_attributes = %w[
10
10
  name
11
11
  started_at
12
- lag_stored
12
+ lag_hybrid
13
13
  ].freeze
14
14
 
15
15
  # List page with consumers
@@ -16,17 +16,17 @@ module Karafka
16
16
 
17
17
  # @return [String] JSON with lags of each of the topics + total lag of all the topics
18
18
  # from all the consumer groups.
19
- def lags_stored
19
+ def lags_hybrid
20
20
  total = Hash.new { |h, v| h[v] = 0 }
21
21
 
22
22
  @data.to_h.each_value do |metrics|
23
23
  metrics.each do |metric|
24
24
  time = metric.first
25
- lag_stored = metric.last[:lag_stored]
25
+ lag_hybrid = metric.last[:lag_hybrid]
26
26
 
27
- if lag_stored
27
+ if lag_hybrid
28
28
  total[time] ||= 0
29
- total[time] += lag_stored
29
+ total[time] += lag_hybrid
30
30
  else
31
31
  next if total.key?(time)
32
32
 
@@ -37,7 +37,7 @@ module Karafka
37
37
 
38
38
  # Extract the lag stored only from all the data
39
39
  per_topic = @data.to_h.map do |topic, metrics|
40
- extracted = metrics.map { |metric| [metric.first, metric.last[:lag_stored]] }
40
+ extracted = metrics.map { |metric| [metric.first, metric.last[:lag_hybrid]] }
41
41
 
42
42
  [topic, extracted]
43
43
  end.to_h
@@ -6,6 +6,28 @@ module Karafka
6
6
  module Models
7
7
  # Single topic partition data representation model
8
8
  class Partition < Lib::HashProxy
9
+ # @param args [Object] anything hash proxy accepts
10
+ def initialize(*args)
11
+ super
12
+
13
+ # We initialize those here because we want to have them stored in the internal has
14
+ # for sorting
15
+ lag_hybrid
16
+ lag_hybrid_d
17
+ end
18
+
19
+ # Because `lag_stored` is not available until first marking, we fallback to the lag
20
+ # value that may be behind but is always available until stored lag is available.
21
+ # @return [Integer] hybrid log value
22
+ def lag_hybrid
23
+ self[:lag_hybrid] ||= lag_stored.negative? ? lag : lag_stored
24
+ end
25
+
26
+ # @return [Integer] hybrid log delta
27
+ def lag_hybrid_d
28
+ self[:lag_hybrid_d] ||= lag_stored.negative? ? lag_d : lag_stored_d
29
+ end
30
+
9
31
  # @return [Symbol] one of three states in which LSO can be in the correlation to given
10
32
  # partition in the context of a consumer group.
11
33
  #
@@ -41,24 +41,13 @@ module Karafka
41
41
  .then { |jobs| Jobs.new(jobs) }
42
42
  end
43
43
 
44
- # @return [Integer] collective stored lag on this process
45
- def lag_stored
44
+ # @return [Integer] collective hybrid lag on this process
45
+ def lag_hybrid
46
46
  consumer_groups
47
47
  .flat_map(&:subscription_groups)
48
48
  .flat_map(&:topics)
49
49
  .flat_map(&:partitions)
50
- .map(&:lag_stored)
51
- .delete_if(&:negative?)
52
- .sum
53
- end
54
-
55
- # @return [Integer] collective lag on this process
56
- def lag
57
- consumer_groups
58
- .flat_map(&:subscription_groups)
59
- .flat_map(&:topics)
60
- .flat_map(&:partitions)
61
- .map(&:lag)
50
+ .map(&:lag_hybrid)
62
51
  .delete_if(&:negative?)
63
52
  .sum
64
53
  end
@@ -163,6 +163,10 @@ module Karafka
163
163
  r.on 'health' do
164
164
  controller = Controllers::Health.new(params)
165
165
 
166
+ r.get 'lags' do
167
+ controller.lags
168
+ end
169
+
166
170
  r.get 'offsets' do
167
171
  controller.offsets
168
172
  end
@@ -19,11 +19,11 @@ module Karafka
19
19
  # Controller for displaying consumers states and details about them
20
20
  class Consumers < Ui::Controllers::Base
21
21
  self.sortable_attributes = %w[
22
+ id
22
23
  name
23
24
  started_at
24
- lag_stored
25
- id
26
- lag_stored_d
25
+ lag_hybrid
26
+ lag_hybrid_d
27
27
  committed_offset
28
28
  stored_offset
29
29
  fetch_state
@@ -93,7 +93,13 @@ module Karafka
93
93
 
94
94
  # We want to have sorting but on a per subscription group basis and not to sort
95
95
  # everything
96
- @process.consumer_groups.each { |subscription_group| refine(subscription_group) }
96
+ @process.consumer_groups.each do |consumer_group|
97
+ # We need to initialize the whole structure so dynamic fields are also built into
98
+ # the underlying hashes for sorting
99
+ consumer_group.subscription_groups.flat_map(&:topics).flat_map(&:partitions)
100
+
101
+ refine(consumer_group)
102
+ end
97
103
 
98
104
  render
99
105
  end
@@ -20,8 +20,12 @@ module Karafka
20
20
  class Health < Ui::Controllers::Base
21
21
  self.sortable_attributes = %w[
22
22
  id
23
+ lag
24
+ lag_d
23
25
  lag_stored
24
26
  lag_stored_d
27
+ lag_hybrid
28
+ lag_hybrid_d
25
29
  committed_offset
26
30
  committed_offset_fd
27
31
  stored_offset
@@ -50,6 +54,14 @@ module Karafka
50
54
  render
51
55
  end
52
56
 
57
+ # Displays details about lags and their progression/statuses
58
+ def lags
59
+ # Same data as overview but presented differently
60
+ overview
61
+
62
+ render
63
+ end
64
+
53
65
  # Displays details about offsets and their progression/statuses
54
66
  def offsets
55
67
  # Same data as overview but presented differently
@@ -71,6 +71,6 @@
71
71
  </td>
72
72
 
73
73
  <td>
74
- <%= process.lag_stored %>
74
+ <%= process.lag_hybrid %>
75
75
  </td>
76
76
  </tr>
@@ -19,9 +19,9 @@
19
19
  </li>
20
20
  <li class="col-sm">
21
21
  <div class="count mb-1">
22
- <%= number_with_delimiter @counters.lag_stored, ' ' %>
22
+ <%= number_with_delimiter @counters.lag_hybrid, ' ' %>
23
23
  </div>
24
- <div class="desc">Lag stored</div>
24
+ <div class="desc">Total lag</div>
25
25
  </li>
26
26
  <li class="col-sm">
27
27
  <a href="<%= root_path('jobs/running') %>">
@@ -3,11 +3,11 @@
3
3
  <%= partition.id %>
4
4
  </td>
5
5
  <td>
6
- <%== lag_with_label partition.lag_stored %>
6
+ <%== lag_with_label partition.lag_hybrid %>
7
7
  </td>
8
8
  <td>
9
- <span class="badge <%= lag_trend_bg(partition.lag_stored_d) %>">
10
- <%= partition.lag_stored_d %>
9
+ <span class="badge <%= lag_trend_bg(partition.lag_hybrid_d) %>">
10
+ <%= partition.lag_hybrid_d %>
11
11
  </span>
12
12
  </td>
13
13
  <td>
@@ -104,8 +104,8 @@
104
104
  <tr class="align-middle">
105
105
  </tr>
106
106
  <th><%== sort_link('Partition', :id) %></th>
107
- <th><%== sort_link(:lag_stored) %></th>
108
- <th><%== sort_link('Lag stored trend', :lag_stored_d) %></th>
107
+ <th><%== sort_link('Lag', :lag_hybrid) %></th>
108
+ <th><%== sort_link('Lag trend', :lag_hybrid_d) %></th>
109
109
  <th><%== sort_link(:committed_offset) %></th>
110
110
  <th><%== sort_link(:stored_offset) %></th>
111
111
  <th><%== sort_link(:fetch_state) %></th>
@@ -17,7 +17,7 @@
17
17
  <th class="col-sm-1">Memory</th>
18
18
  <th class="col-sm-1">Performance</th>
19
19
  <th class="col-sm-1">Load</th>
20
- <th class="col-sm-1"><%== sort_link(:lag_stored) %></th>
20
+ <th class="col-sm-1"><%== sort_link('Lag', :lag_hybrid) %></th>
21
21
  </tr>
22
22
  </thead>
23
23
  <tbody>
@@ -13,7 +13,7 @@
13
13
  <ul class="nav nav-tabs" id="graphs1" role="tablist">
14
14
  <%== partial 'shared/tab_nav', locals: { title: 'Messages', id: 'messages', active: true } %>
15
15
  <%== partial 'shared/tab_nav', locals: { title: 'Batches', id: 'batches' } %>
16
- <%== partial 'shared/tab_nav', locals: { title: 'Lags stored', id: 'lags-stored' } %>
16
+ <%== partial 'shared/tab_nav', locals: { title: 'Topics lags', id: 'topics-lags' } %>
17
17
  <%== partial 'shared/tab_nav', locals: { title: 'Topics pace', id: 'topics-pace' } %>
18
18
  <%== partial 'shared/tab_nav', locals: { title: 'Max LSO time', id: 'max-lso-time' } %>
19
19
  </ul>
@@ -29,8 +29,8 @@
29
29
  <%== partial 'shared/chart', locals: { data: data, id: 'batches' } %>
30
30
  </div>
31
31
 
32
- <div class="tab-pane" id="lags-stored" role="tabpanel">
33
- <%== partial 'shared/chart', locals: { data: @topics_charts.lags_stored, id: 'lags-stored' } %>
32
+ <div class="tab-pane" id="topics-lags" role="tabpanel">
33
+ <%== partial 'shared/chart', locals: { data: @topics_charts.lags_hybrid, id: 'topics-lags' } %>
34
34
  </div>
35
35
 
36
36
  <div class="tab-pane" id="topics-pace" role="tabpanel">
@@ -4,6 +4,14 @@
4
4
  </a>
5
5
  </li>
6
6
 
7
+ <% if current_path.include?('/lags') %>
8
+ <li class="breadcrumb-item">
9
+ <a href="<%= root_path('health', 'lags') %>">
10
+ Lags
11
+ </a>
12
+ </li>
13
+ <% end %>
14
+
7
15
  <% if current_path.include?('/overview') %>
8
16
  <li class="breadcrumb-item">
9
17
  <a href="<%= root_path('health', 'overview') %>">
@@ -0,0 +1,14 @@
1
+ <div class="row mb-4">
2
+ <div class="col-sm-8">
3
+ <h4 class="mb-4"><%= cg_name %></h4>
4
+ </div>
5
+
6
+ <div class="col-sm-4">
7
+ <span class="float-end">
8
+ Last rebalance:
9
+ <span class="badge bg-secondary">
10
+ <%== relative_time(details[:rebalanced_at]) %>
11
+ </span>
12
+ </span>
13
+ </div>
14
+ </div>
@@ -3,15 +3,7 @@
3
3
  <%= partition_id %>
4
4
  </td>
5
5
  <td>
6
- <%== lag_with_label details.lag_stored %>
7
- </td>
8
- <td>
9
- <span class="badge <%= lag_trend_bg(details.lag_stored_d) %>">
10
- <%= details.lag_stored_d %>
11
- </span>
12
- </td>
13
- <td>
14
- <%== offset_with_label topic_name, partition_id, details.committed_offset %>
6
+ <%== lag_with_label details.lag_hybrid %>
15
7
  </td>
16
8
  <td>
17
9
  <%== offset_with_label topic_name, partition_id, details.stored_offset %>
@@ -0,0 +1,24 @@
1
+ <tr class="align-middle <%= lso_risk_state_bg(details) %> status-row-<%= details.process.status %>">
2
+ <td>
3
+ <%= partition_id %>
4
+ </td>
5
+ <td>
6
+ <%== lag_with_label details.lag %>
7
+ </td>
8
+ <td>
9
+ <span class="badge <%= lag_trend_bg(details.lag_d) %>">
10
+ <%= details.lag_d %>
11
+ </span>
12
+ </td>
13
+ <td>
14
+ <%== lag_with_label details.lag_stored %>
15
+ </td>
16
+ <td>
17
+ <span class="badge <%= lag_trend_bg(details.lag_stored_d) %>">
18
+ <%= details.lag_stored_d %>
19
+ </span>
20
+ </td>
21
+ <td>
22
+ <%== poll_state_with_change_time_label(details.poll_state, details.poll_state_ch) %>
23
+ </td>
24
+ </tr>
@@ -3,7 +3,7 @@
3
3
  <%= partition_id %>
4
4
  </td>
5
5
  <td>
6
- <%== lag_with_label details.lag_stored %>
6
+ <%== lag_with_label details.lag_hybrid %>
7
7
  </td>
8
8
  <td>
9
9
  <%== offset_with_label topic_name, partition_id, details.committed_offset %>
@@ -12,6 +12,15 @@
12
12
  </a>
13
13
  </li>
14
14
 
15
+ <li class="nav-item">
16
+ <a
17
+ class="nav-link <%= nav_class(include: 'lags') %>"
18
+ href="<%= root_path('health', 'lags') %>"
19
+ >
20
+ Lags
21
+ </a>
22
+ </li>
23
+
15
24
  <li class="nav-item">
16
25
  <a
17
26
  class="nav-link <%= nav_class(include: 'offsets') %>"
@@ -6,23 +6,9 @@
6
6
  <%== partial 'health/tabs' %>
7
7
  <% end %>
8
8
 
9
-
10
9
  <% @stats.each_with_index do |(cg_name, details), index| %>
11
10
  <div class="container mb-5">
12
- <div class="row mb-4">
13
- <div class="col-sm-8">
14
- <h4 class="mb-4"><%= cg_name %></h4>
15
- </div>
16
-
17
- <div class="col-sm-4">
18
- <span class="float-end">
19
- Last rebalance:
20
- <span class="badge bg-secondary">
21
- <%== relative_time(details[:rebalanced_at]) %>
22
- </span>
23
- </span>
24
- </div>
25
- </div>
11
+ <%== partial 'health/consumer_group_header', locals: { cg_name: cg_name, details: details } %>
26
12
 
27
13
  <div class="row mb-3">
28
14
  <div class="col-sm-12">
@@ -0,0 +1,52 @@
1
+ <%== view_title('Consumers groups lags details') %>
2
+
3
+ <% if @stats.empty? %>
4
+ <%== partial 'health/no_data' %>
5
+ <% else %>
6
+ <%== partial 'health/tabs' %>
7
+ <% end %>
8
+
9
+ <% @stats.each_with_index do |(cg_name, details), index| %>
10
+ <div class="container mb-5">
11
+ <%== partial 'health/consumer_group_header', locals: { cg_name: cg_name, details: details } %>
12
+
13
+ <div class="row mb-3">
14
+ <div class="col-sm-12">
15
+ <% topics = details[:topics] %>
16
+ <% topics.each_with_index do |(topic_name, partitions), index| %>
17
+ <table class="processes bg-white table table-hover table-bordered table-striped align-middle <%= (index+1 < topics.size) ? 'mb-5' : 'mb-3' %>">
18
+ <thead>
19
+ <tr class="align-middle">
20
+ <th colspan="12">
21
+ <h5 class="mb-0"><%= topic_name %></h4>
22
+ </th>
23
+ </tr>
24
+ <tr class="align-middle">
25
+ <th><%== sort_link('Partition', :id) %></th>
26
+ <th><%== sort_link('Lag', :lag) %></th>
27
+ <th><%== sort_link('Lag trend', :lag_d) %></th>
28
+ <th><%== sort_link('Lag stored', :lag_stored) %></th>
29
+ <th><%== sort_link('Lag stored trend', :lag_stored_d) %></th>
30
+ <th><%== sort_link(:poll_state) %></th>
31
+ </tr>
32
+ </thead>
33
+ <tbody>
34
+ <% partitions.each do |partition_id, details| %>
35
+ <%==
36
+ partial(
37
+ 'health/partition_lags',
38
+ locals: {
39
+ topic_name: topic_name,
40
+ partition_id: partition_id,
41
+ details: details
42
+ }
43
+ )
44
+ %>
45
+ <% end %>
46
+ </tbody>
47
+ </table>
48
+ <% end %>
49
+ </div>
50
+ </div>
51
+ </div>
52
+ <% end %>
@@ -8,20 +8,7 @@
8
8
 
9
9
  <% @stats.each_with_index do |(cg_name, details), index| %>
10
10
  <div class="container mb-5">
11
- <div class="row mb-4">
12
- <div class="col-sm-8">
13
- <h4 class="mb-4"><%= cg_name %></h4>
14
- </div>
15
-
16
- <div class="col-sm-4">
17
- <span class="float-end">
18
- Last rebalance:
19
- <span class="badge bg-secondary">
20
- <%== relative_time(details[:rebalanced_at]) %>
21
- </span>
22
- </span>
23
- </div>
24
- </div>
11
+ <%== partial 'health/consumer_group_header', locals: { cg_name: cg_name, details: details } %>
25
12
 
26
13
  <div class="row mb-3">
27
14
  <div class="col-sm-12">
@@ -36,7 +23,7 @@
36
23
  </tr>
37
24
  <tr class="align-middle">
38
25
  <th><%== sort_link('Partition', :id) %></th>
39
- <th><%== sort_link(:lag_stored) %></th>
26
+ <th><%== sort_link('Lag', :lag_hybrid) %></th>
40
27
  <th><%== sort_link(:committed_offset) %></th>
41
28
  <th><%== sort_link('Committed offset change', :committed_offset_fd) %></th>
42
29
  <th><%== sort_link(:stored_offset) %></th>
@@ -8,20 +8,7 @@
8
8
 
9
9
  <% @stats.each_with_index do |(cg_name, details), index| %>
10
10
  <div class="container mb-5">
11
- <div class="row mb-4">
12
- <div class="col-sm-8">
13
- <h4 class="mb-4"><%= cg_name %></h4>
14
- </div>
15
-
16
- <div class="col-sm-4">
17
- <span class="float-end">
18
- Last rebalance:
19
- <span class="badge bg-secondary">
20
- <%== relative_time(details[:rebalanced_at]) %>
21
- </span>
22
- </span>
23
- </div>
24
- </div>
11
+ <%== partial 'health/consumer_group_header', locals: { cg_name: cg_name, details: details } %>
25
12
 
26
13
  <div class="row mb-3">
27
14
  <div class="col-sm-12">
@@ -36,9 +23,7 @@
36
23
  </tr>
37
24
  <tr class="align-middle">
38
25
  <th><%== sort_link('Partition', :id) %></th>
39
- <th><%== sort_link(:lag_stored) %></th>
40
- <th><%== sort_link('Lag stored trend', :lag_stored_d) %></th>
41
- <th><%== sort_link(:committed_offset) %></th>
26
+ <th><%== sort_link('Lag', :lag_hybrid) %></th>
42
27
  <th><%== sort_link(:stored_offset) %></th>
43
28
  <th><%== sort_link(:fetch_state) %></th>
44
29
  <th><%== sort_link(:poll_state) %></th>
@@ -19,9 +19,9 @@
19
19
  </li>
20
20
  <li class="col-sm">
21
21
  <div class="count mb-1">
22
- <%= number_with_delimiter @counters.lag_stored, ' ' %>
22
+ <%= number_with_delimiter @counters.lag_hybrid, ' ' %>
23
23
  </div>
24
- <div class="desc">Lag stored</div>
24
+ <div class="desc">Total lag</div>
25
25
  </li>
26
26
  <li class="col-sm">
27
27
  <a href="<%= root_path('jobs/running') %>">
@@ -16,7 +16,7 @@
16
16
  <th class="col-sm-2"><%== sort_link('Started', :started_at, rev: true) %></th>
17
17
  <th class="col-sm-1">Memory</th>
18
18
  <th class="col-sm-1">Utilization</th>
19
- <th class="col-sm-1"><%== sort_link(:lag_stored) %></th>
19
+ <th class="col-sm-1"><%== sort_link('Lag', :lag_hybrid) %></th>
20
20
  </tr>
21
21
  </thead>
22
22
  <tbody>
@@ -23,7 +23,7 @@
23
23
  <ul class="nav nav-tabs" id="graphs1" role="tablist">
24
24
  <%== partial 'shared/tab_nav', locals: { title: 'Messages', id: 'messages', active: true } %>
25
25
  <%== partial 'shared/tab_nav', locals: { title: 'Batches', id: 'batches' } %>
26
- <%== partial 'shared/tab_nav', locals: { title: 'Lags stored', id: 'lags-stored' } %>
26
+ <%== partial 'shared/tab_nav', locals: { title: 'Topics Lags', id: 'topics-lags' } %>
27
27
  <%== partial 'shared/tab_nav', locals: { title: 'Topics pace', id: 'topics-pace' } %>
28
28
  <%== partial 'shared/tab_nav', locals: { title: 'Max LSO time', id: 'max-lso-time' } %>
29
29
  </ul>
@@ -39,10 +39,10 @@
39
39
  <%== partial 'shared/chart', locals: { data: data, id: 'batches' } %>
40
40
  </div>
41
41
 
42
- <div class="tab-pane" id="lags-stored" role="tabpanel">
42
+ <div class="tab-pane" id="topics-lags" role="tabpanel">
43
43
  <%== partial 'dashboard/feature_pro' %>
44
44
  <% data = { enqueued: set.call, busy: set.call }.to_json %>
45
- <%== partial 'shared/chart', locals: { data: data, id: 'lags-stored', blurred: true } %>
45
+ <%== partial 'shared/chart', locals: { data: data, id: 'topics-lags', blurred: true } %>
46
46
  </div>
47
47
 
48
48
  <div class="tab-pane" id="topics-pace" role="tabpanel">
@@ -3,6 +3,6 @@
3
3
  module Karafka
4
4
  module Web
5
5
  # Current gem version
6
- VERSION = '0.8.0'
6
+ VERSION = '0.8.1'
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.8.0
4
+ version: 0.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maciej Mensfeld
@@ -35,7 +35,7 @@ cert_chain:
35
35
  AnG1dJU+yL2BK7vaVytLTstJME5mepSZ46qqIJXMuWob/YPDmVaBF39TDSG9e34s
36
36
  msG3BiCqgOgHAnL23+CN3Rt8MsuRfEtoTKpJVcCfoEoNHOkc
37
37
  -----END CERTIFICATE-----
38
- date: 2024-01-26 00:00:00.000000000 Z
38
+ date: 2024-02-01 00:00:00.000000000 Z
39
39
  dependencies:
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: erubi
@@ -205,6 +205,10 @@ files:
205
205
  - lib/karafka/web/management/migrations/1700234522_remove_processing_from_consumers_state.rb
206
206
  - lib/karafka/web/management/migrations/1704722380_split_listeners_into_active_and_paused_in_metrics.rb
207
207
  - lib/karafka/web/management/migrations/1704722380_split_listeners_into_active_and_paused_in_states.rb
208
+ - lib/karafka/web/management/migrations/1706607960_introduce_lag_total_in_metrics.rb
209
+ - lib/karafka/web/management/migrations/1706607960_introduce_lag_total_in_states.rb
210
+ - lib/karafka/web/management/migrations/1706611396_rename_lag_total_to_lag_hybrid_in_metrics.rb
211
+ - lib/karafka/web/management/migrations/1706611396_rename_lag_total_to_lag_hybrid_in_states.rb
208
212
  - lib/karafka/web/management/migrator.rb
209
213
  - lib/karafka/web/processing/consumer.rb
210
214
  - lib/karafka/web/processing/consumers/aggregators/base.rb
@@ -369,12 +373,15 @@ files:
369
373
  - lib/karafka/web/ui/pro/views/explorer/topic/_empty.erb
370
374
  - lib/karafka/web/ui/pro/views/explorer/topic/_limited.erb
371
375
  - lib/karafka/web/ui/pro/views/health/_breadcrumbs.erb
376
+ - lib/karafka/web/ui/pro/views/health/_consumer_group_header.erb
372
377
  - lib/karafka/web/ui/pro/views/health/_no_data.erb
373
378
  - lib/karafka/web/ui/pro/views/health/_partition.erb
379
+ - lib/karafka/web/ui/pro/views/health/_partition_lags.erb
374
380
  - lib/karafka/web/ui/pro/views/health/_partition_offset.erb
375
381
  - lib/karafka/web/ui/pro/views/health/_partition_times.erb
376
382
  - lib/karafka/web/ui/pro/views/health/_tabs.erb
377
383
  - lib/karafka/web/ui/pro/views/health/changes.erb
384
+ - lib/karafka/web/ui/pro/views/health/lags.erb
378
385
  - lib/karafka/web/ui/pro/views/health/offsets.erb
379
386
  - lib/karafka/web/ui/pro/views/health/overview.erb
380
387
  - lib/karafka/web/ui/pro/views/jobs/_job.erb
metadata.gz.sig CHANGED
Binary file