karafka-web 0.2.5 → 0.3.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 (41) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +39 -0
  4. data/Gemfile.lock +3 -3
  5. data/karafka-web.gemspec +1 -1
  6. data/lib/karafka/web/installer.rb +7 -2
  7. data/lib/karafka/web/tracking/consumers/sampler.rb +9 -22
  8. data/lib/karafka/web/tracking/sampler.rb +57 -0
  9. data/lib/karafka/web/ui/controllers/errors.rb +2 -0
  10. data/lib/karafka/web/ui/controllers/status.rb +1 -0
  11. data/lib/karafka/web/ui/models/job.rb +0 -4
  12. data/lib/karafka/web/ui/models/message.rb +71 -14
  13. data/lib/karafka/web/ui/models/process.rb +0 -7
  14. data/lib/karafka/web/ui/models/watermark_offsets.rb +39 -0
  15. data/lib/karafka/web/ui/pro/controllers/errors.rb +2 -1
  16. data/lib/karafka/web/ui/pro/controllers/explorer.rb +3 -0
  17. data/lib/karafka/web/ui/pro/views/consumers/consumer/_metrics.erb +29 -21
  18. data/lib/karafka/web/ui/pro/views/consumers/consumer/_partition.erb +14 -2
  19. data/lib/karafka/web/ui/pro/views/errors/_cleaned.erb +3 -0
  20. data/lib/karafka/web/ui/pro/views/errors/_error.erb +33 -25
  21. data/lib/karafka/web/ui/pro/views/errors/_no_errors.erb +3 -0
  22. data/lib/karafka/web/ui/pro/views/errors/index.erb +29 -21
  23. data/lib/karafka/web/ui/pro/views/explorer/_message.erb +27 -16
  24. data/lib/karafka/web/ui/pro/views/explorer/partition/_cleaned.erb +3 -0
  25. data/lib/karafka/web/ui/pro/views/explorer/partition/_empty.erb +3 -0
  26. data/lib/karafka/web/ui/pro/views/explorer/partition/_messages.erb +18 -0
  27. data/lib/karafka/web/ui/pro/views/explorer/partition/_watermark_offsets.erb +10 -0
  28. data/lib/karafka/web/ui/pro/views/explorer/partition.erb +10 -19
  29. data/lib/karafka/web/ui/public/stylesheets/application.css +4 -0
  30. data/lib/karafka/web/ui/views/errors/_cleaned.erb +3 -0
  31. data/lib/karafka/web/ui/views/errors/_error.erb +33 -25
  32. data/lib/karafka/web/ui/views/errors/_no_errors.erb +3 -0
  33. data/lib/karafka/web/ui/views/errors/_watermark_offsets.erb +10 -0
  34. data/lib/karafka/web/ui/views/errors/index.erb +29 -21
  35. data/lib/karafka/web/ui/views/status/_info.erb +14 -0
  36. data/lib/karafka/web/ui/views/status/info/_components.erb +34 -0
  37. data/lib/karafka/web/ui/views/status/show.erb +9 -1
  38. data/lib/karafka/web/version.rb +1 -1
  39. data.tar.gz.sig +0 -0
  40. metadata +17 -4
  41. metadata.gz.sig +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0f0eb0ab715c86da7538f8c83f3caa648f36663437ec1895c4a14fcd51d350d5
4
- data.tar.gz: c40f2936ea80c059e94c9d911ad8765859fd737d90d12a43490feb5b1b2c4282
3
+ metadata.gz: 1b6f97a725c2cd9e8458d8b4a32a347e42898e1f5598b3998a460e063fc0b149
4
+ data.tar.gz: 4a8762c41fa42f5e9c75380ce098423acd72db1720dbf412fd33cb412efc3855
5
5
  SHA512:
6
- metadata.gz: dcb9e83ad553937ff1de9c760d38e599de491a6866112c0ea55ba944d985026736392981c74e5c1d4b0e3c19157f6759b4deca8281c3a3ef5301724e51a79d6b
7
- data.tar.gz: aa56092d3ea42cb02880f4caa32a1e741a989ccdc9491e65c7d787dd68cd713758df3dc06475de217b277f6bcde794a67047c5107ca5d127834bf90b4007ad42
6
+ metadata.gz: b1899bee43d1597e59755ce9f148b817e2c69c3b1b76ee7c6058aef2fc4a985f057b50c26bd000cc121c3cf73c694f906a92a85885e2d5337630ed728ba3e1a1
7
+ data.tar.gz: aaca8f979aa93075cceb315f25be6ca98dcde650a6302cca3b4d134df7159210996c71010be28043cb673d0ec54a8a54f5c058ec3f83d30a3d343c230de1a4cb
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -1,5 +1,44 @@
1
1
  # Karafka Web changelog
2
2
 
3
+ ## 0.3.1 (2023-03-27)
4
+ - [Fix] Add missing retention policy for states topic.
5
+ - [Fix] Fix display of compacted messages placeholders for offsets lower than low watermark.
6
+ - [Fix] Fix invalid pagination per page count.
7
+
8
+ ### Upgrade notes
9
+
10
+ If upgrading from `0.3.0`, nothing.
11
+
12
+ If upgrading from lower, please follow `0.3.0` upgrade procedure.
13
+
14
+ ## 0.3.0 (2023-03-27)
15
+ - **[Feature]** Support paginating over compacted topics partitions.
16
+ - [Improvement] Display watermark offsets in the errors view.
17
+ - [Improvement] Display informative message when partition is empty due to a retention policy.
18
+ - [Improvement] Display informative message when partition is empty instead of displaying nothing.
19
+ - [Improvement] Display current watermark offsets in the Explorer when viewing list of messages from a given partition.
20
+ - [Improvement] Report extra debug info in the status section.
21
+ - [Improvement] Report not only `Karafka` and `WaterDrop` versions but also `Karafka::Core`, `Rdkafka` and `librdkafka` versions.
22
+ - [Improvement] Small CSS improvements.
23
+ - [Improvement] Provide nicer info when errors topic does not contain any errors or was compacted.
24
+ - [Improvement] Improve listing of errors including compacted once.
25
+ - [Fix] Fix pagination for compacted indexes that would display despite no data being available below the low watermark offset.
26
+ - [Fix] Fix a case where reading from a compacted offset would return no data despite data being available.
27
+ - [Fix] Fix a case where explorer pagination would suggest more pages for compacted topics.
28
+ - [Fix] Fix incorrect support of compacted partitions and partitions with low watermark offset other than 0.
29
+ - [Fix] Display `N/A` instead of `-1` and `-1001` on lag stored and stored offset for consumer processes that did not mark any messages as consumed yet in the per consumer view.
30
+ - [Maintenance] Remove compatibility fallbacks for job and process tags (#1342)
31
+ - [Maintenance] Extract base sampler for tracking and web.
32
+
33
+ ### Upgrade notes
34
+
35
+ Because of the removal of compatibility fallbacks for some metrics fetches, it is recommended to:
36
+
37
+ - First, deploy **all** the Karafka consumer processes (`karafka server`)
38
+ - Deploy the Web update to your web server.
39
+
40
+ Please note that if you decide to use the updated Web UI with not updated consumers, you may hit a 500 error.
41
+
3
42
  ## 0.2.5 (2023-03-17)
4
43
  - [Fix] Critical instrumentation async errors intercepted by Web don't have JID for job removal (#1366)
5
44
 
data/Gemfile.lock CHANGED
@@ -1,9 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- karafka-web (0.2.5)
4
+ karafka-web (0.3.1)
5
5
  erubi (~> 1.4)
6
- karafka (>= 2.0.35, < 3.0.0)
6
+ karafka (>= 2.0.38, < 3.0.0)
7
7
  karafka-core (>= 2.0.12, < 3.0.0)
8
8
  roda (~> 3.63)
9
9
  tilt (~> 2.0)
@@ -26,7 +26,7 @@ GEM
26
26
  ffi (1.15.5)
27
27
  i18n (1.12.0)
28
28
  concurrent-ruby (~> 1.0)
29
- karafka (2.0.35)
29
+ karafka (2.0.38)
30
30
  karafka-core (>= 2.0.12, < 3.0.0)
31
31
  thor (>= 0.20)
32
32
  waterdrop (>= 2.4.10, < 3.0.0)
data/karafka-web.gemspec CHANGED
@@ -17,7 +17,7 @@ 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.35', '< 3.0.0'
20
+ spec.add_dependency 'karafka', '>= 2.0.38', '< 3.0.0'
21
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'
@@ -102,8 +102,13 @@ module Karafka
102
102
  consumers_states_topic,
103
103
  1,
104
104
  replication_factor,
105
- # We care only about the most recent state, previous are irrelevant
106
- { 'cleanup.policy': 'compact' }
105
+ # We care only about the most recent state, previous are irrelevant. So we can easily
106
+ # compact after one minute. We do not use this beyond the most recent collective
107
+ # state, hence it all can easily go away.
108
+ {
109
+ 'cleanup.policy': 'compact',
110
+ 'retention.ms': 60 * 60 * 1_000
111
+ }
107
112
  )
108
113
  end
109
114
 
@@ -6,7 +6,7 @@ module Karafka
6
6
  # Namespace for all the things related to tracking consumers and consuming processes
7
7
  module Consumers
8
8
  # Samples for fetching and storing metrics samples about the consumer process
9
- class Sampler
9
+ class Sampler < Tracking::Sampler
10
10
  include ::Karafka::Core::Helpers::Time
11
11
 
12
12
  attr_reader :counters, :consumer_groups, :errors, :times, :pauses, :jobs
@@ -14,7 +14,7 @@ module Karafka
14
14
  # Current schema version
15
15
  # This can be used in the future for detecting incompatible changes and writing
16
16
  # migrations
17
- SCHEMA_VERSION = '1.0.1'
17
+ SCHEMA_VERSION = '1.0.2'
18
18
 
19
19
  # 60 seconds window for time tracked window-based metrics
20
20
  TIMES_TTL = 60
@@ -25,6 +25,8 @@ module Karafka
25
25
  private_constant :TIMES_TTL, :TIMES_TTL_MS, :SCHEMA_VERSION
26
26
 
27
27
  def initialize
28
+ super
29
+
28
30
  @counters = {
29
31
  batches: 0,
30
32
  messages: 0,
@@ -72,8 +74,11 @@ module Karafka
72
74
 
73
75
  versions: {
74
76
  ruby: ruby_version,
75
- karafka: ::Karafka::VERSION,
76
- waterdrop: ::WaterDrop::VERSION
77
+ karafka: karafka_version,
78
+ waterdrop: waterdrop_version,
79
+ karafka_core: karafka_core_version,
80
+ rdkafka: rdkafka_version,
81
+ librdkafka: librdkafka_version
77
82
  },
78
83
 
79
84
  stats: jobs_queue_statistics.merge(
@@ -118,11 +123,6 @@ module Karafka
118
123
  Karafka::Server.listeners&.count.to_i
119
124
  end
120
125
 
121
- # @return [String] Unique process name
122
- def process_name
123
- @process_name ||= "#{Socket.gethostname}:#{::Process.pid}:#{SecureRandom.hex(6)}"
124
- end
125
-
126
126
  # @return [Integer] memory used by this process in kilobytes
127
127
  def memory_usage
128
128
  pid = ::Process.pid
@@ -210,19 +210,6 @@ module Karafka
210
210
  @cpu_count ||= Etc.nprocessors
211
211
  end
212
212
 
213
- # @return [String] currently used ruby version with details
214
- def ruby_version
215
- if defined?(JRUBY_VERSION)
216
- revision = JRUBY_REVISION.to_s
217
- version = JRUBY_VERSION
218
- else
219
- revision = RUBY_REVISION.to_s
220
- version = RUBY_ENGINE_VERSION
221
- end
222
-
223
- "#{RUBY_ENGINE} #{version}-#{RUBY_PATCHLEVEL} #{revision[0..5]}"
224
- end
225
-
226
213
  # @return [Integer] number of threads that process work
227
214
  def concurrency
228
215
  @concurrency ||= Karafka::App.config.concurrency
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ module Web
5
+ module Tracking
6
+ # Base sampler with some basic info collectors
7
+ # This sampler should store **only** collectors that can be used for producers, consumers and
8
+ # the Web-UI itself. All specific to a given aspect of operations should be moved out.
9
+ class Sampler
10
+ # @return [String] Unique process name
11
+ def process_name
12
+ @process_name ||= "#{Socket.gethostname}:#{::Process.pid}:#{SecureRandom.hex(6)}"
13
+ end
14
+
15
+ # @return [String] currently used ruby version with details
16
+ def ruby_version
17
+ return @ruby_version if @ruby_version
18
+
19
+ if defined?(JRUBY_VERSION)
20
+ revision = JRUBY_REVISION.to_s
21
+ version = JRUBY_VERSION
22
+ else
23
+ revision = RUBY_REVISION.to_s
24
+ version = RUBY_ENGINE_VERSION
25
+ end
26
+
27
+ @ruby_version = "#{RUBY_ENGINE} #{version}-#{RUBY_PATCHLEVEL} #{revision[0..5]}"
28
+ end
29
+
30
+ # @return [String] Karafka version
31
+ def karafka_version
32
+ ::Karafka::VERSION
33
+ end
34
+
35
+ # @return [String] Karafka::Core version
36
+ def karafka_core_version
37
+ ::Karafka::Core::VERSION
38
+ end
39
+
40
+ # @return [String] rdkafka version
41
+ def rdkafka_version
42
+ ::Rdkafka::VERSION
43
+ end
44
+
45
+ # @return [String] librdkafka version
46
+ def librdkafka_version
47
+ ::Rdkafka::LIBRDKAFKA_VERSION
48
+ end
49
+
50
+ # @return [String] WaterDrop version
51
+ def waterdrop_version
52
+ ::WaterDrop::VERSION
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -16,6 +16,8 @@ module Karafka
16
16
  @params.current_page
17
17
  )
18
18
 
19
+ @watermark_offsets = Ui::Models::WatermarkOffsets.find(errors_topic, 0)
20
+
19
21
  respond
20
22
  end
21
23
 
@@ -13,6 +13,7 @@ module Karafka
13
13
  # Displays the Web UI setup status
14
14
  def show
15
15
  @status = Models::Status.new
16
+ @sampler = Tracking::Sampler.new
16
17
 
17
18
  respond
18
19
  end
@@ -6,10 +6,6 @@ module Karafka
6
6
  module Models
7
7
  # Single job data representation model
8
8
  class Job < Lib::HashProxy
9
- # @return [Array<String>] tags of this consuming job / consumer
10
- def tags
11
- @hash[:tags] || []
12
- end
13
9
  end
14
10
  end
15
11
  end
@@ -38,43 +38,83 @@ module Karafka
38
38
  # @return [Array] We return both page data as well as all the details needed to build
39
39
  # the pagination details.
40
40
  def page(topic_id, partition_id, page)
41
- # Establish the leading offset
42
- lead = Karafka::Admin.read_topic(topic_id, partition_id, 1).first
41
+ low_offset, high_offset = Karafka::Admin.read_watermark_offsets(
42
+ topic_id,
43
+ partition_id
44
+ )
43
45
 
44
46
  partitions_count = fetch_partition_count(topic_id)
45
47
 
48
+ no_data_result = [false, [], false, partitions_count]
49
+
46
50
  # If there is not even one message, we need to early exit
47
- return [false, [], false, partitions_count] unless lead
51
+ # If low and high watermark offsets are of the same value, it means no data in the
52
+ # topic is present
53
+ return no_data_result if low_offset == high_offset
48
54
 
49
55
  # We add plus one because we compute previous offset from which we want to start and
50
56
  # not previous page leading offset
51
- previous_offset = lead.offset - (per_page * page) + 1
57
+ start_offset = high_offset - (per_page * page)
52
58
 
53
- if previous_offset.negative?
54
- count = per_page + previous_offset
59
+ if start_offset <= low_offset
60
+ count = per_page - (low_offset - start_offset)
55
61
  previous_page = page < 2 ? false : page - 1
56
62
  next_page = false
57
- previous_offset = 0
63
+ start_offset = low_offset
58
64
  else
59
65
  previous_page = page < 2 ? false : page - 1
60
66
  next_page = page + 1
61
67
  count = per_page
62
68
  end
63
69
 
64
- [
65
- previous_page,
66
- read_topic(topic_id, partition_id, count, previous_offset).reverse,
67
- next_page,
68
- partitions_count
69
- ]
70
+ # This code is a bit tricky. Since topics can be compacted and certain offsets may
71
+ # not be present at all, it may happen that we want to read from a non-existing
72
+ # offset. In case like this we need to catch this error (we do it in `read_topic`)
73
+ # and we need to move to an offset closer to high offset. This is not fast but it is
74
+ # an edge case that should not happen often when inspecting real time data. This can
75
+ # happen more often for heavily compacted topics with short retention but even then
76
+ # it is ok for 25 elements we usually operate on a single page.
77
+ count.times do |index|
78
+ context_offset = start_offset + index
79
+ # We need to get less if we move up with missing offsets to get exactly
80
+ # the number we needed
81
+ context_count = count - index
82
+
83
+ messages = read_topic(
84
+ topic_id,
85
+ partition_id,
86
+ context_count,
87
+ context_offset,
88
+ # We do not reset the offset here because we are not interested in seeking from
89
+ # any offset. We are interested in the indication, that there is no offset of a
90
+ # given value so we can try with a more recent one
91
+ 'auto.offset.reset': 'error'
92
+ )
93
+
94
+ next unless messages
95
+
96
+ return [
97
+ previous_page,
98
+ fill_compacted(messages, context_offset, context_count).reverse,
99
+ next_page,
100
+ partitions_count
101
+ ]
102
+ end
103
+
104
+ no_data_result
70
105
  end
71
106
 
72
107
  private
73
108
 
74
109
  # @param args [Object] anything required by the admin `#read_topic`
75
- # @return [Array<Karafka::Messages::Message>] topic partition messages
110
+ # @return [Array<Karafka::Messages::Message>, false] topic partition messages or false
111
+ # in case we hit a non-existing offset
76
112
  def read_topic(*args)
77
113
  ::Karafka::Admin.read_topic(*args)
114
+ rescue Rdkafka::RdkafkaError => e
115
+ return false if e.code == :auto_offset_reset
116
+
117
+ raise
78
118
  end
79
119
 
80
120
  # @param topic_id [String] id of the topic
@@ -91,6 +131,23 @@ module Karafka
91
131
  def per_page
92
132
  ::Karafka::Web.config.ui.per_page
93
133
  end
134
+
135
+ # Since we paginate with compacted offsets visible but we do not get compacted messages
136
+ # we need to fill those with just the missing offset and handle this on the UI.
137
+ #
138
+ # @param messages [Array<Karafka::Messages::Message>] selected messages
139
+ # @param start_offset [Integer] offset of the first message (lowest) that we received
140
+ # @param count [Integer] how many messages we wanted - we need that to fill spots to
141
+ # have exactly the number that was requested and not more
142
+ # @return [Array<Karafka::Messages::Message, Integer>] array with gaps filled with the
143
+ # missing offset
144
+ def fill_compacted(messages, start_offset, count)
145
+ Array.new(count) do |index|
146
+ messages.find do |message|
147
+ (message.offset - start_offset) == index
148
+ end || start_offset + index
149
+ end
150
+ end
94
151
  end
95
152
  end
96
153
  end
@@ -40,13 +40,6 @@ 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
-
50
43
  # @return [Integer] collective lag on this process
51
44
  def lag_stored
52
45
  consumer_groups
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ module Web
5
+ module Ui
6
+ module Models
7
+ # Model used for accessing watermark offsets
8
+ class WatermarkOffsets < Lib::HashProxy
9
+ class << self
10
+ # Retrieve watermark offsets for given topic partition
11
+ #
12
+ # @param topic_id [String]
13
+ # @param partition_id [Integer]
14
+ # @return [WatermarkOffsets]
15
+ def find(topic_id, partition_id)
16
+ offsets = ::Karafka::Admin.read_watermark_offsets(topic_id, partition_id)
17
+
18
+ new(
19
+ low: offsets.first,
20
+ high: offsets.last
21
+ )
22
+ end
23
+ end
24
+
25
+ # @return [Boolean] true if given partition never had any messages and is empty
26
+ def empty?
27
+ low.zero? && high.zero?
28
+ end
29
+
30
+ # @return [Boolean] true if given partition had data but all of it was removed due
31
+ # to log retention and compaction policies
32
+ def cleaned?
33
+ !empty? && low == high
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -29,6 +29,8 @@ module Karafka
29
29
  @params.current_page
30
30
  )
31
31
 
32
+ @watermark_offsets = Ui::Models::WatermarkOffsets.find(errors_topic, @partition_id)
33
+
32
34
  respond
33
35
  end
34
36
 
@@ -38,7 +40,6 @@ module Karafka
38
40
  # @param offset [Integer]
39
41
  def show(partition_id, offset)
40
42
  errors_topic = ::Karafka::Web.config.topics.errors
41
-
42
43
  @partition_id = partition_id
43
44
  @offset = offset
44
45
  @error_message = Models::Message.find(
@@ -36,6 +36,9 @@ module Karafka
36
36
  def partition(topic_id, partition_id)
37
37
  @topic_id = topic_id
38
38
  @partition_id = partition_id
39
+
40
+ @watermark_offsets = Ui::Models::WatermarkOffsets.find(topic_id, partition_id)
41
+
39
42
  @previous_page, @messages, @next_page, @partitions_count = Ui::Models::Message.page(
40
43
  @topic_id,
41
44
  @partition_id,
@@ -102,27 +102,35 @@
102
102
  <div class="card">
103
103
  <div class="card-body">
104
104
  <h5 class="card-title">Versions</h5>
105
- <p class="card-text">
106
- <ul style="list-style: square !important;">
107
- <li class="align-items-center d-flex justify-content-between">
108
- Ruby:
109
- <span class="badge bg-secondary">
110
- <%= @process.ruby %>
111
- </span>
112
- </li>
113
- <li class="align-items-center d-flex justify-content-between">
114
- Karafka:
115
- <span class="badge bg-secondary">
116
- <%= @process.karafka %>
117
- </span>
118
- </li>
119
- <li class="align-items-center d-flex justify-content-between">
120
- WaterDrop version:
121
- <span class="badge bg-secondary">
122
- <%= @process.waterdrop %>
123
- </span>
124
- </li>
125
- </ul>
105
+ <p class="card-text text-center">
106
+ <span class="badge bg-secondary">
107
+ <%= @process.ruby %>
108
+ </span>
109
+
110
+ <span class="badge bg-secondary">
111
+ karafka
112
+ <%= @process.karafka %>
113
+ </span>
114
+
115
+ <span class="badge bg-secondary">
116
+ karafka core
117
+ <%= @process.karafka_core %>
118
+ </span>
119
+
120
+ <span class="badge bg-secondary">
121
+ rdkafka
122
+ <%= @process.rdkafka %>
123
+ </span>
124
+
125
+ <span class="badge bg-secondary">
126
+ librdkafka
127
+ <%= @process.librdkafka %>
128
+ </span>
129
+
130
+ <span class="badge bg-secondary">
131
+ waterdrop
132
+ <%= @process.waterdrop %>
133
+ </span>
126
134
  </p>
127
135
  </div>
128
136
  </div>
@@ -6,7 +6,13 @@
6
6
  <%= partition.id %>
7
7
  </td>
8
8
  <td>
9
- <%= partition.lag_stored %>
9
+ <% if partition.lag_stored.to_i < 0 %>
10
+ <span class="badge bg-secondary" title="Not available until first offset commit">
11
+ N/A
12
+ </span>
13
+ <% else %>
14
+ <%= partition.lag_stored %>
15
+ <% end %>
10
16
  </td>
11
17
  <td>
12
18
  <span class="badge <%= lag_trend_bg(partition.lag_stored_d) %>">
@@ -17,7 +23,13 @@
17
23
  <%= partition.committed_offset %>
18
24
  </td>
19
25
  <td>
20
- <%= partition.stored_offset %>
26
+ <% if partition.stored_offset.to_i < 0 %>
27
+ <span class="badge bg-secondary" title="Not available until first offset commit">
28
+ N/A
29
+ </span>
30
+ <% else %>
31
+ <%= partition.stored_offset %>
32
+ <% end %>
21
33
  </td>
22
34
  <td>
23
35
  <span class="badge <%= kafka_state_bg(partition.fetch_state) %> mt-1 mb-1">
@@ -0,0 +1,3 @@
1
+ <div class="alert alert-info" role="alert">
2
+ This errors topic partition had all of its errored compacted and cleaned.
3
+ </div>
@@ -1,26 +1,34 @@
1
- <% error = error_msg.payload %>
1
+ <% if error_msg.is_a?(Integer) %>
2
+ <tr>
3
+ <td colspan="5" class="text-center text-muted">
4
+ This error has either been removed or compacted and is no longer available.
5
+ </td>
6
+ </tr>
7
+ <% else %>
8
+ <% error = error_msg.payload %>
2
9
 
3
- <tr>
4
- <td>
5
- <% if error[:details].key?(:topic) %>
6
- <%= error[:details][:topic] %>: <%= error[:details][:partition] %>
7
- <% else %>
8
- <%= error[:type] %>
9
- <% end %>
10
- </td>
11
- <td>
12
- <%== error[:process_name] %>
13
- </td>
14
- <td>
15
- <%= error[:error_class] %>:
16
- <%= error[:error_message].first(200) %>
17
- </td>
18
- <td>
19
- <%== relative_time error[:occurred_at] %>
20
- </td>
21
- <td>
22
- <a href="<%= root_path('errors', error_msg.partition, error_msg.offset) %>" class="btn btn-sm btn-secondary text-white">
23
- Details
24
- </a>
25
- </td>
26
- </tr>
10
+ <tr>
11
+ <td>
12
+ <% if error[:details].key?(:topic) %>
13
+ <%= error[:details][:topic] %>: <%= error[:details][:partition] %>
14
+ <% else %>
15
+ <%= error[:type] %>
16
+ <% end %>
17
+ </td>
18
+ <td>
19
+ <%== error[:process_name] %>
20
+ </td>
21
+ <td>
22
+ <%= error[:error_class] %>:
23
+ <%= error[:error_message].first(200) %>
24
+ </td>
25
+ <td>
26
+ <%== relative_time error[:occurred_at] %>
27
+ </td>
28
+ <td class="text-center">
29
+ <a href="<%= root_path('errors', error_msg.partition, error_msg.offset) %>" class="btn btn-sm btn-secondary text-white">
30
+ Details
31
+ </a>
32
+ </td>
33
+ </tr>
34
+ <% end %>
@@ -0,0 +1,3 @@
1
+ <div class="alert alert-info" role="alert">
2
+ There are no errors in this errors topic partition.
3
+ </div>
@@ -1,4 +1,4 @@
1
- <div class="container mb-5">
1
+ <div class="container mb-4">
2
2
  <div class="row">
3
3
  <div class="col">
4
4
  <h3>
@@ -33,26 +33,34 @@
33
33
  <div class="container">
34
34
  <div class="row mb-5">
35
35
  <div class="col-sm-12">
36
- <table class="processes bg-white table table-hover table-bordered table-striped mb-0 align-middle">
37
- <thead>
38
- <tr class="align-middle">
39
- <th>Origin</th>
40
- <th>Process name</th>
41
- <th>Error</th>
42
- <th>Occurred at</th>
43
- <th></th>
44
- </tr>
45
- </thead>
46
- <tbody>
47
- <%==
48
- each_partial(
49
- @error_messages,
50
- 'errors/error',
51
- local: :error_msg
52
- )
53
- %>
54
- </tbody>
55
- </table>
36
+ <%== partial('explorer/partition/watermark_offsets') %>
37
+
38
+ <% if @watermark_offsets.empty? %>
39
+ <%== partial 'errors/no_errors' %>
40
+ <% elsif @watermark_offsets.cleaned? %>
41
+ <%== partial 'errors/cleaned' %>
42
+ <% else %>
43
+ <table class="processes bg-white table table-hover table-bordered table-striped mb-0 align-middle">
44
+ <thead>
45
+ <tr class="align-middle">
46
+ <th>Origin</th>
47
+ <th>Process name</th>
48
+ <th>Error</th>
49
+ <th>Occurred at</th>
50
+ <th></th>
51
+ </tr>
52
+ </thead>
53
+ <tbody>
54
+ <%==
55
+ each_partial(
56
+ @error_messages,
57
+ 'errors/error',
58
+ local: :error_msg
59
+ )
60
+ %>
61
+ </tbody>
62
+ </table>
63
+ <% end %>
56
64
  </div>
57
65
  </div>
58
66
  </div>
@@ -1,16 +1,27 @@
1
- <tr>
2
- <td>
3
- <%= message.offset %>
4
- </td>
5
- <td>
6
- <%== relative_time message.timestamp %>
7
- </td>
8
- <td>
9
- <%= message.key %>
10
- </td>
11
- <td class="text-center">
12
- <a href="<%= root_path('explorer', message.topic, message.partition, message.offset) %>" class="btn btn-sm btn-secondary">
13
- Details
14
- </a>
15
- </td>
16
- </tr>
1
+ <% if message.is_a?(Integer) %>
2
+ <tr>
3
+ <td class="text-muted">
4
+ <%= message %>
5
+ </td>
6
+ <td colspan="3" class="text-center text-muted">
7
+ This message has either been removed or compacted and is no longer available.
8
+ </td>
9
+ </tr>
10
+ <% else %>
11
+ <tr>
12
+ <td>
13
+ <%= message.offset %>
14
+ </td>
15
+ <td>
16
+ <%== relative_time message.timestamp %>
17
+ </td>
18
+ <td>
19
+ <%= message.key %>
20
+ </td>
21
+ <td class="text-center">
22
+ <a href="<%= root_path('explorer', message.topic, message.partition, message.offset) %>" class="btn btn-sm btn-secondary">
23
+ Details
24
+ </a>
25
+ </td>
26
+ </tr>
27
+ <% end %>
@@ -0,0 +1,3 @@
1
+ <div class="alert alert-info mt-4" role="alert">
2
+ This partition no longer contains any data and has been fully compacted.
3
+ </div>
@@ -0,0 +1,3 @@
1
+ <div class="alert alert-info mt-4" role="alert">
2
+ This partition is empty and does not contain any data.
3
+ </div>
@@ -0,0 +1,18 @@
1
+ <table class="processes bg-white table table-hover table-bordered table-striped mb-0 align-middle">
2
+ <thead>
3
+ <tr class="align-middle">
4
+ <th>Offset</th>
5
+ <th>Timestamp</th>
6
+ <th>Key</th>
7
+ <th></th>
8
+ </tr>
9
+ </thead>
10
+ <tbody>
11
+ <%==
12
+ each_partial(
13
+ @messages,
14
+ 'explorer/message'
15
+ )
16
+ %>
17
+ </tbody>
18
+ </table>
@@ -0,0 +1,10 @@
1
+ <p class="text-end mb-4">
2
+ Watermark offsets:
3
+ <span class="badge bg-secondary mt-1 mb-1">
4
+ high: <%= @watermark_offsets.high %>
5
+ </span>
6
+
7
+ <span class="badge bg-secondary mt-1 mb-1">
8
+ low: <%= @watermark_offsets.low %>
9
+ </span>
10
+ </p>
@@ -1,4 +1,4 @@
1
- <div class="container mb-5">
1
+ <div class="container mb-4">
2
2
  <div class="row">
3
3
  <div class="col">
4
4
  <h3>
@@ -33,24 +33,15 @@
33
33
  <div class="container">
34
34
  <div class="row mb-5">
35
35
  <div class="col-sm-12">
36
- <table class="processes bg-white table table-hover table-bordered table-striped mb-0 align-middle">
37
- <thead>
38
- <tr class="align-middle">
39
- <th>Offset</th>
40
- <th>Timestamp</th>
41
- <th>Key</th>
42
- <th></th>
43
- </tr>
44
- </thead>
45
- <tbody>
46
- <%==
47
- each_partial(
48
- @messages,
49
- 'explorer/message'
50
- )
51
- %>
52
- </tbody>
53
- </table>
36
+ <%== partial('explorer/partition/watermark_offsets') %>
37
+
38
+ <% if @watermark_offsets.empty? %>
39
+ <%== partial 'explorer/partition/empty' %>
40
+ <% elsif @watermark_offsets.cleaned? %>
41
+ <%== partial 'explorer/partition/cleaned' %>
42
+ <% else %>
43
+ <%== partial('explorer/partition/messages') %>
44
+ <% end %>
54
45
  </div>
55
46
  </div>
56
47
  </div>
@@ -104,3 +104,7 @@ code.wrapped {
104
104
  #content .error-message {
105
105
  max-width: 700px;
106
106
  }
107
+
108
+ #metrics ul {
109
+ padding-left: 0;
110
+ }
@@ -0,0 +1,3 @@
1
+ <div class="alert alert-info" role="alert">
2
+ This errors topic partition had all of its errored compacted and cleaned.
3
+ </div>
@@ -1,26 +1,34 @@
1
- <% error = error_msg.payload %>
1
+ <% if error_msg.is_a?(Integer) %>
2
+ <tr>
3
+ <td colspan="5" class="text-center text-muted">
4
+ This error has either been removed or compacted and is no longer available.
5
+ </td>
6
+ </tr>
7
+ <% else %>
8
+ <% error = error_msg.payload %>
2
9
 
3
- <tr>
4
- <td>
5
- <% if error[:details].key?(:topic) %>
6
- <%= error[:details][:topic] %>: <%= error[:details][:partition] %>
7
- <% else %>
8
- <%= error[:type] %>
9
- <% end %>
10
- </td>
11
- <td>
12
- <%== error[:process_name] %>
13
- </td>
14
- <td>
15
- <%= error[:error_class] %>:
16
- <%= error[:error_message].first(200) %>
17
- </td>
18
- <td>
19
- <%== relative_time error[:occurred_at] %>
20
- </td>
21
- <td>
22
- <a href="<%= root_path('errors', error_msg.offset) %>" class="btn btn-sm btn-secondary text-white">
23
- Details
24
- </a>
25
- </td>
26
- </tr>
10
+ <tr>
11
+ <td>
12
+ <% if error[:details].key?(:topic) %>
13
+ <%= error[:details][:topic] %>: <%= error[:details][:partition] %>
14
+ <% else %>
15
+ <%= error[:type] %>
16
+ <% end %>
17
+ </td>
18
+ <td>
19
+ <%== error[:process_name] %>
20
+ </td>
21
+ <td>
22
+ <%= error[:error_class] %>:
23
+ <%= error[:error_message].first(200) %>
24
+ </td>
25
+ <td>
26
+ <%== relative_time error[:occurred_at] %>
27
+ </td>
28
+ <td class="text-center">
29
+ <a href="<%= root_path('errors', error_msg.offset) %>" class="btn btn-sm btn-secondary text-white">
30
+ Details
31
+ </a>
32
+ </td>
33
+ </tr>
34
+ <% end %>
@@ -0,0 +1,3 @@
1
+ <div class="alert alert-info" role="alert">
2
+ There are no errors in this errors topic partition.
3
+ </div>
@@ -0,0 +1,10 @@
1
+ <p class="text-end mb-4">
2
+ Watermark offsets:
3
+ <span class="badge bg-secondary mt-1 mb-1">
4
+ high: <%= @watermark_offsets.high %>
5
+ </span>
6
+
7
+ <span class="badge bg-secondary mt-1 mb-1">
8
+ low: <%= @watermark_offsets.low %>
9
+ </span>
10
+ </p>
@@ -1,4 +1,4 @@
1
- <div class="container mb-5">
1
+ <div class="container mb-4">
2
2
  <div class="row">
3
3
  <div class="col">
4
4
  <h3>
@@ -13,26 +13,34 @@
13
13
  <div class="container">
14
14
  <div class="row mb-5">
15
15
  <div class="col-sm-12">
16
- <table class="processes bg-white table table-hover table-bordered table-striped mb-0 align-middle">
17
- <thead>
18
- <tr class="align-middle">
19
- <th>Origin</th>
20
- <th>Process name</th>
21
- <th>Error</th>
22
- <th>Occurred at</th>
23
- <th></th>
24
- </tr>
25
- </thead>
26
- <tbody>
27
- <%==
28
- each_partial(
29
- @error_messages,
30
- 'errors/error',
31
- local: :error_msg
32
- )
33
- %>
34
- </tbody>
35
- </table>
16
+ <%== partial('errors/watermark_offsets') %>
17
+
18
+ <% if @watermark_offsets.empty? %>
19
+ <%== partial 'errors/no_errors' %>
20
+ <% elsif @watermark_offsets.cleaned? %>
21
+ <%== partial 'errors/cleaned' %>
22
+ <% else %>
23
+ <table class="processes bg-white table table-hover table-bordered table-striped mb-0 align-middle">
24
+ <thead>
25
+ <tr class="align-middle">
26
+ <th>Origin</th>
27
+ <th>Process name</th>
28
+ <th>Error</th>
29
+ <th>Occurred at</th>
30
+ <th></th>
31
+ </tr>
32
+ </thead>
33
+ <tbody>
34
+ <%==
35
+ each_partial(
36
+ @error_messages,
37
+ 'errors/error',
38
+ local: :error_msg
39
+ )
40
+ %>
41
+ </tbody>
42
+ </table>
43
+ <% end %>
36
44
  </div>
37
45
  </div>
38
46
  </div>
@@ -0,0 +1,14 @@
1
+ <div class="card text-bg-alt 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-secondary">Info</span>
9
+ </span>
10
+ </div>
11
+ <div class="card-body">
12
+ <%== description %>
13
+ </div>
14
+ </div>
@@ -0,0 +1,34 @@
1
+ <p>
2
+ Below you can find information about your setup. This can be helpful when debugging or reporting bugs and issues.
3
+ </p>
4
+
5
+ <p class="mb-0">
6
+ <span class="badge bg-secondary">
7
+ <%= @sampler.ruby_version %>
8
+ </span>
9
+
10
+ <span class="badge bg-secondary">
11
+ karafka
12
+ <%= @sampler.karafka_version %>
13
+ </span>
14
+
15
+ <span class="badge bg-secondary">
16
+ karafka core
17
+ <%= @sampler.karafka_core_version %>
18
+ </span>
19
+
20
+ <span class="badge bg-secondary">
21
+ rdkafka
22
+ <%= @sampler.rdkafka_version %>
23
+ </span>
24
+
25
+ <span class="badge bg-secondary">
26
+ librdkafka
27
+ <%= @sampler.librdkafka_version %>
28
+ </span>
29
+
30
+ <span class="badge bg-secondary">
31
+ waterdrop
32
+ <%= @sampler.waterdrop_version %>
33
+ </span>
34
+ </p>
@@ -3,7 +3,6 @@
3
3
  <div class="container mb-5">
4
4
  <div class="row">
5
5
  <div class="col-lg-10 offset-md-1">
6
-
7
6
  <%==
8
7
  partial(
9
8
  "status/#{@status.connection.to_s}",
@@ -104,6 +103,15 @@
104
103
  )
105
104
  %>
106
105
 
106
+ <%==
107
+ partial(
108
+ 'status/info',
109
+ locals: {
110
+ title: 'Components info',
111
+ description: partial('status/info/components')
112
+ }
113
+ )
114
+ %>
107
115
  </div>
108
116
  </div>
109
117
  </div>
@@ -3,6 +3,6 @@
3
3
  module Karafka
4
4
  module Web
5
5
  # Current gem version
6
- VERSION = '0.2.5'
6
+ VERSION = '0.3.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.2.5
4
+ version: 0.3.1
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-03-17 00:00:00.000000000 Z
38
+ date: 2023-03-27 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.35
60
+ version: 2.0.38
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.35
70
+ version: 2.0.38
71
71
  - - "<"
72
72
  - !ruby/object:Gem::Version
73
73
  version: 3.0.0
@@ -186,6 +186,7 @@ files:
186
186
  - lib/karafka/web/tracking/consumers/sampler.rb
187
187
  - lib/karafka/web/tracking/memoized_shell.rb
188
188
  - lib/karafka/web/tracking/reporter.rb
189
+ - lib/karafka/web/tracking/sampler.rb
189
190
  - lib/karafka/web/tracking/ttl_array.rb
190
191
  - lib/karafka/web/tracking/ttl_hash.rb
191
192
  - lib/karafka/web/ui/app.rb
@@ -213,6 +214,7 @@ files:
213
214
  - lib/karafka/web/ui/models/state.rb
214
215
  - lib/karafka/web/ui/models/status.rb
215
216
  - lib/karafka/web/ui/models/topic.rb
217
+ - lib/karafka/web/ui/models/watermark_offsets.rb
216
218
  - lib/karafka/web/ui/pro/app.rb
217
219
  - lib/karafka/web/ui/pro/controllers/cluster.rb
218
220
  - lib/karafka/web/ui/pro/controllers/consumers.rb
@@ -243,8 +245,10 @@ files:
243
245
  - lib/karafka/web/ui/pro/views/dlq/_topic.erb
244
246
  - lib/karafka/web/ui/pro/views/dlq/index.erb
245
247
  - lib/karafka/web/ui/pro/views/errors/_breadcrumbs.erb
248
+ - lib/karafka/web/ui/pro/views/errors/_cleaned.erb
246
249
  - lib/karafka/web/ui/pro/views/errors/_detail.erb
247
250
  - lib/karafka/web/ui/pro/views/errors/_error.erb
251
+ - lib/karafka/web/ui/pro/views/errors/_no_errors.erb
248
252
  - lib/karafka/web/ui/pro/views/errors/_partition_option.erb
249
253
  - lib/karafka/web/ui/pro/views/errors/index.erb
250
254
  - lib/karafka/web/ui/pro/views/errors/show.erb
@@ -257,6 +261,10 @@ files:
257
261
  - lib/karafka/web/ui/pro/views/explorer/_topic.erb
258
262
  - lib/karafka/web/ui/pro/views/explorer/index.erb
259
263
  - lib/karafka/web/ui/pro/views/explorer/partition.erb
264
+ - lib/karafka/web/ui/pro/views/explorer/partition/_cleaned.erb
265
+ - lib/karafka/web/ui/pro/views/explorer/partition/_empty.erb
266
+ - lib/karafka/web/ui/pro/views/explorer/partition/_messages.erb
267
+ - lib/karafka/web/ui/pro/views/explorer/partition/_watermark_offsets.erb
260
268
  - lib/karafka/web/ui/pro/views/explorer/show.erb
261
269
  - lib/karafka/web/ui/pro/views/health/_breadcrumbs.erb
262
270
  - lib/karafka/web/ui/pro/views/health/_partition.erb
@@ -287,8 +295,11 @@ files:
287
295
  - lib/karafka/web/ui/views/consumers/_summary.erb
288
296
  - lib/karafka/web/ui/views/consumers/index.erb
289
297
  - lib/karafka/web/ui/views/errors/_breadcrumbs.erb
298
+ - lib/karafka/web/ui/views/errors/_cleaned.erb
290
299
  - lib/karafka/web/ui/views/errors/_detail.erb
291
300
  - lib/karafka/web/ui/views/errors/_error.erb
301
+ - lib/karafka/web/ui/views/errors/_no_errors.erb
302
+ - lib/karafka/web/ui/views/errors/_watermark_offsets.erb
292
303
  - lib/karafka/web/ui/views/errors/index.erb
293
304
  - lib/karafka/web/ui/views/errors/show.erb
294
305
  - lib/karafka/web/ui/views/jobs/_breadcrumbs.erb
@@ -313,6 +324,7 @@ files:
313
324
  - lib/karafka/web/ui/views/status/_breadcrumbs.erb
314
325
  - lib/karafka/web/ui/views/status/_failure.erb
315
326
  - lib/karafka/web/ui/views/status/_halted.erb
327
+ - lib/karafka/web/ui/views/status/_info.erb
316
328
  - lib/karafka/web/ui/views/status/_success.erb
317
329
  - lib/karafka/web/ui/views/status/_warning.erb
318
330
  - lib/karafka/web/ui/views/status/failures/_connection.erb
@@ -321,6 +333,7 @@ files:
321
333
  - lib/karafka/web/ui/views/status/failures/_partitions.erb
322
334
  - lib/karafka/web/ui/views/status/failures/_state_calculation.erb
323
335
  - lib/karafka/web/ui/views/status/failures/_topics.erb
336
+ - lib/karafka/web/ui/views/status/info/_components.erb
324
337
  - lib/karafka/web/ui/views/status/show.erb
325
338
  - lib/karafka/web/ui/views/status/warnings/_pro_subscription.erb
326
339
  - lib/karafka/web/version.rb
metadata.gz.sig CHANGED
Binary file