solid_observer 0.4.0 → 0.5.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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -0
  3. data/README.md +80 -20
  4. data/app/assets/javascripts/solid_observer/live_poll.js +3 -1
  5. data/app/controllers/solid_observer/application_controller.rb +1 -0
  6. data/app/controllers/solid_observer/cable_dashboard_controller.rb +52 -0
  7. data/app/controllers/solid_observer/cable_operations_controller.rb +16 -0
  8. data/app/controllers/solid_observer/cache_dashboard_controller.rb +33 -40
  9. data/app/controllers/solid_observer/dashboard_controller.rb +1 -7
  10. data/app/helpers/solid_observer/application_helper.rb +114 -0
  11. data/app/models/solid_observer/cable_event.rb +13 -0
  12. data/app/models/solid_observer/cable_metric.rb +12 -0
  13. data/app/models/solid_observer/cache_metric.rb +1 -2
  14. data/app/models/solid_observer/storage_info.rb +1 -1
  15. data/app/views/layouts/solid_observer/application.html.erb +19 -8
  16. data/app/views/solid_observer/cable_dashboard/_charts.html.erb +31 -0
  17. data/app/views/solid_observer/cable_dashboard/_recent_events.html.erb +34 -0
  18. data/app/views/solid_observer/cable_dashboard/_summary.html.erb +34 -0
  19. data/app/views/solid_observer/cable_dashboard/index.html.erb +118 -0
  20. data/app/views/solid_observer/dashboard/_queue_table.html.erb +1 -0
  21. data/app/views/solid_observer/dashboard/index.html.erb +2 -5
  22. data/app/views/solid_observer/events/index.html.erb +1 -0
  23. data/app/views/solid_observer/jobs/index.html.erb +1 -0
  24. data/app/views/solid_observer/storages/show.html.erb +29 -3
  25. data/config/routes.rb +2 -0
  26. data/db/migrate/20260612000001_add_event_type_recorded_at_index_to_cache_events.rb +21 -0
  27. data/db/migrate/20260619000001_create_solid_observer_cable_events.rb +22 -0
  28. data/db/migrate/20260619000002_create_solid_observer_cable_metrics.rb +17 -0
  29. data/lib/generators/solid_observer/install_generator.rb +8 -1
  30. data/lib/generators/solid_observer/templates/initializer.rb.tt +18 -3
  31. data/lib/solid_observer/base_event.rb +1 -1
  32. data/lib/solid_observer/base_metric.rb +1 -1
  33. data/lib/solid_observer/base_record.rb +8 -0
  34. data/lib/solid_observer/cable_event_buffer.rb +28 -0
  35. data/lib/solid_observer/cable_metric_buffer.rb +230 -0
  36. data/lib/solid_observer/cable_subscriber.rb +57 -0
  37. data/lib/solid_observer/cache_event_buffer.rb +11 -36
  38. data/lib/solid_observer/cache_metric_buffer.rb +229 -0
  39. data/lib/solid_observer/chart_buffer.rb +84 -27
  40. data/lib/solid_observer/configuration.rb +47 -4
  41. data/lib/solid_observer/engine.rb +46 -28
  42. data/lib/solid_observer/event_buffer_core.rb +218 -0
  43. data/lib/solid_observer/queue_event_buffer.rb +9 -201
  44. data/lib/solid_observer/services/cable_operations.rb +74 -0
  45. data/lib/solid_observer/services/cable_stats.rb +385 -0
  46. data/lib/solid_observer/services/cache_stats.rb +35 -18
  47. data/lib/solid_observer/services/cleanup_storage.rb +82 -47
  48. data/lib/solid_observer/services/flush_cable_event_buffer.rb +54 -0
  49. data/lib/solid_observer/services/flush_cable_metrics.rb +54 -0
  50. data/lib/solid_observer/services/flush_cache_metrics.rb +56 -0
  51. data/lib/solid_observer/services/record_cable_event.rb +114 -0
  52. data/lib/solid_observer/services/record_cable_metric.rb +73 -0
  53. data/lib/solid_observer/services/record_cache_event.rb +23 -0
  54. data/lib/solid_observer/services/record_cache_metric.rb +13 -21
  55. data/lib/solid_observer/services/storage_info_snapshot.rb +103 -15
  56. data/lib/solid_observer/version.rb +1 -1
  57. data/lib/solid_observer.rb +36 -11
  58. data/lib/tasks/solid_observer.rake +84 -23
  59. metadata +26 -6
  60. data/app/assets/stylesheets/solid_observer/application.css +0 -18
  61. data/bin/console +0 -11
  62. data/bin/quality_gate +0 -95
  63. data/bin/setup +0 -8
@@ -1,27 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "../cache_metric_buffer"
4
+
3
5
  module SolidObserver
4
6
  module Services
5
7
  class RecordCacheMetric
6
- def self.call(event:)
7
- new(event).call
8
+ def self.call(event:, buffer: SolidObserver::CacheMetricBuffer.instance)
9
+ new(event, buffer).call
8
10
  end
9
11
 
10
- def initialize(event)
12
+ def initialize(event, buffer)
11
13
  @event = event
14
+ @buffer = buffer
12
15
  end
13
16
 
14
17
  def call
15
- metric = SolidObserver::CacheMetric.find_or_create_by!(
18
+ @buffer.increment(
16
19
  event_type: event_type,
17
- period_start: period_start
20
+ period_start: period_start,
21
+ operations_count: 1,
22
+ hits_count: hit_increment,
23
+ misses_count: miss_increment,
24
+ errors_count: error_increment,
25
+ duration_total: duration_in_seconds
18
26
  )
19
-
20
- SolidObserver::CacheMetric
21
- .where(id: metric.id)
22
- .update_all(update_values)
23
- rescue ActiveRecord::RecordNotUnique
24
- retry
25
27
  rescue => error
26
28
  Rails.logger&.warn("[SolidObserver] Cache metric recording failed: #{error.message}") if defined?(Rails)
27
29
  end
@@ -36,16 +38,6 @@ module SolidObserver
36
38
  @event.name.delete_suffix(".active_support")
37
39
  end
38
40
 
39
- def update_values
40
- {
41
- operations_count: Arel.sql("operations_count + 1"),
42
- hits_count: Arel.sql("hits_count + #{hit_increment}"),
43
- misses_count: Arel.sql("misses_count + #{miss_increment}"),
44
- errors_count: Arel.sql("errors_count + #{error_increment}"),
45
- duration_total: Arel.sql("duration_total + #{duration_in_seconds}")
46
- }
47
- end
48
-
49
41
  def hit_increment
50
42
  (payload[:hit] == true) ? 1 : 0
51
43
  end
@@ -5,6 +5,57 @@ require_relative "database_size"
5
5
  module SolidObserver
6
6
  module Services
7
7
  class StorageInfoSnapshot
8
+ class RecordCount
9
+ def initialize(connection, table_name)
10
+ @connection = connection
11
+ @table_name = table_name
12
+ end
13
+
14
+ def solid_cache_count
15
+ case adapter_key
16
+ when :postgresql then postgresql_approximate_count
17
+ when :mysql then mysql_approximate_count
18
+ else
19
+ yield
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ attr_reader :connection, :table_name
26
+
27
+ def adapter_key
28
+ case connection.adapter_name.to_s.downcase
29
+ when /postgres|postgis/ then :postgresql
30
+ when "mysql2", "trilogy", "mysql" then :mysql
31
+ else
32
+ :other
33
+ end
34
+ end
35
+
36
+ def postgresql_approximate_count
37
+ quoted_table = connection.quote(table_name)
38
+
39
+ connection.query_value(<<~SQL.squish)&.to_i || 0
40
+ SELECT COALESCE(
41
+ (SELECT reltuples::bigint FROM pg_class WHERE oid = to_regclass(#{quoted_table})),
42
+ 0
43
+ )
44
+ SQL
45
+ end
46
+
47
+ def mysql_approximate_count
48
+ quoted_table = connection.quote(table_name)
49
+
50
+ connection.query_value(<<~SQL)&.to_i || 0
51
+ SELECT COALESCE(table_rows, 0)
52
+ FROM information_schema.tables
53
+ WHERE table_schema = DATABASE()
54
+ AND table_name = #{quoted_table}
55
+ SQL
56
+ end
57
+ end
58
+
8
59
  Component = Struct.new(:key, :label, :record_label, :model, :enabled, keyword_init: true) do
9
60
  def enabled?
10
61
  enabled.call
@@ -14,28 +65,25 @@ module SolidObserver
14
65
  key == "solid_cache"
15
66
  end
16
67
 
17
- def storage_model
18
- model.call
19
- end
20
-
21
- def data_source_exists?(connection, table_name)
22
- connection.data_source_exists?(table_name)
68
+ def solid_cable?
69
+ key == "solid_cable"
23
70
  end
24
71
 
25
- def database_size(connection, table_name)
26
- DatabaseSize.call(connection: connection, table_name: table_name)
72
+ def storage_model
73
+ model.call
27
74
  end
28
75
 
29
76
  def snapshot
30
77
  return unless enabled?
31
78
  return unavailable_snapshot(reason: "SolidCache is unavailable") if unavailable_solid_cache?
79
+ return unavailable_snapshot(reason: "SolidCable is unavailable") if solid_cable? && !defined?(::SolidCable::Message)
32
80
 
33
81
  existing_data_source_snapshot
34
82
  rescue *StorageInfoSnapshot::CONNECTION_ERRORS, TypeError
35
83
  unavailable_snapshot(reason: "Storage unavailable")
36
84
  end
37
85
 
38
- def available_snapshot(db_size_bytes:, event_count:)
86
+ def available_snapshot(db_size_bytes:, event_count:, **extras)
39
87
  {
40
88
  component: key,
41
89
  label: label,
@@ -45,7 +93,7 @@ module SolidObserver
45
93
  record_label: record_label,
46
94
  recorded_at: Time.current,
47
95
  unavailable_reason: nil
48
- }
96
+ }.merge(extras)
49
97
  end
50
98
 
51
99
  def unavailable_snapshot(reason:)
@@ -71,16 +119,41 @@ module SolidObserver
71
119
  record_model = storage_model
72
120
  connection = record_model.connection
73
121
  table_name = record_model.table_name.to_s
74
- return table_unavailable_snapshot if table_name.empty? || !data_source_exists?(connection, table_name)
122
+ return unavailable_snapshot(reason: "Table unavailable") unless data_source_available?(connection, table_name)
123
+
124
+ build_available_snapshot(record_model, connection, table_name)
125
+ end
126
+
127
+ def build_available_snapshot(record_model, connection, table_name)
128
+ count = -> { record_model.count }
129
+ event_count = solid_cache? ? RecordCount.new(connection, table_name).solid_cache_count(&count) : count.call
75
130
 
76
131
  available_snapshot(
77
- db_size_bytes: database_size(connection, table_name),
78
- event_count: record_model.count
132
+ db_size_bytes: DatabaseSize.call(connection: connection, table_name: table_name),
133
+ event_count: event_count,
134
+ **extras_for(record_model)
79
135
  )
80
136
  end
81
137
 
82
- def table_unavailable_snapshot
83
- unavailable_snapshot(reason: "Table unavailable")
138
+ def extras_for(record_model)
139
+ solid_cable? ? solid_cable_extras(record_model) : {}
140
+ end
141
+
142
+ def data_source_available?(connection, table_name)
143
+ !table_name.empty? && connection.data_source_exists?(table_name)
144
+ end
145
+
146
+ def solid_cable_extras(record_model)
147
+ {
148
+ trimmable_count: safe_query { record_model.trimmable.count },
149
+ oldest_message_age_seconds: safe_query { (Time.current - record_model.minimum(:created_at).to_time).to_i }
150
+ }
151
+ end
152
+
153
+ def safe_query
154
+ yield
155
+ rescue *StorageInfoSnapshot::CONNECTION_ERRORS, TypeError, NoMethodError
156
+ nil
84
157
  end
85
158
  end
86
159
 
@@ -105,6 +178,20 @@ module SolidObserver
105
178
  record_label: "cache rows",
106
179
  model: -> { ::SolidCache::Entry },
107
180
  enabled: -> { SolidObserver.config.solid_cache_enabled? }
181
+ ),
182
+ Component.new(
183
+ key: "cable_observer",
184
+ label: "Cable telemetry",
185
+ record_label: "observer events",
186
+ model: -> { SolidObserver::CableEvent },
187
+ enabled: -> { SolidObserver.config.solid_cable_enabled? }
188
+ ),
189
+ Component.new(
190
+ key: "solid_cable",
191
+ label: "Solid Cable messages",
192
+ record_label: "messages",
193
+ model: -> { ::SolidCable::Message },
194
+ enabled: -> { SolidObserver.config.solid_cable_enabled? }
108
195
  )
109
196
  ].freeze
110
197
 
@@ -113,6 +200,7 @@ module SolidObserver
113
200
  ActiveRecord::StatementInvalid,
114
201
  *([PG::ConnectionBad] if defined?(PG::ConnectionBad)),
115
202
  *([Mysql2::Error::ConnectionError] if defined?(Mysql2::Error::ConnectionError)),
203
+ *([Trilogy::Error] if defined?(Trilogy::Error)),
116
204
  *([SQLite3::CantOpenException] if defined?(SQLite3::CantOpenException))
117
205
  ].freeze
118
206
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SolidObserver
4
- VERSION = "0.4.0"
4
+ VERSION = "0.5.0"
5
5
  RUBY_MINIMUM_VERSION = "3.2.0"
6
6
  RAILS_MINIMUM_VERSION = "8.0"
7
7
  end
@@ -1,30 +1,55 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/lazy_load_hooks"
4
+
3
5
  require_relative "solid_observer/version"
4
6
  require_relative "solid_observer/configuration"
5
7
  require_relative "solid_observer/correlation_id_resolver"
6
- require_relative "solid_observer/base_event" if defined?(ActiveRecord)
7
- require_relative "solid_observer/base_metric" if defined?(ActiveRecord)
8
8
  require_relative "solid_observer/params/jobs_filter"
9
9
  require_relative "solid_observer/params/events_filter"
10
- require_relative "solid_observer/queries/job_executions_query" if defined?(ActiveRecord)
11
- require_relative "solid_observer/queries/events_query" if defined?(ActiveRecord)
12
- require_relative "solid_observer/queries/execution_finder" if defined?(ActiveRecord)
13
- require_relative "solid_observer/services/record_event" if defined?(ActiveRecord)
14
- require_relative "solid_observer/services/flush_event_buffer" if defined?(ActiveRecord)
15
- require_relative "solid_observer/services/cleanup_storage" if defined?(ActiveRecord)
16
10
  require_relative "solid_observer/services/ui_auth_check"
17
- require_relative "solid_observer/queue_event_buffer" if defined?(ActiveRecord)
18
- require_relative "solid_observer/subscriber" if defined?(ActiveSupport)
11
+ require_relative "solid_observer/subscriber"
19
12
  require_relative "solid_observer/cli/base"
20
13
  require_relative "solid_observer/cli/status"
21
14
  require_relative "solid_observer/cli/storage"
22
15
  require_relative "solid_observer/cli/jobs"
23
16
  require_relative "solid_observer/queue_stats"
24
- require_relative "../app/presenters/solid_observer/execution_presenter"
25
17
  require_relative "solid_observer/engine" if defined?(Rails::Engine)
26
18
 
19
+ ActiveSupport.on_load(:active_record) do
20
+ require_relative "solid_observer/base_record"
21
+ require_relative "solid_observer/base_event"
22
+ require_relative "solid_observer/base_metric"
23
+ require_relative "solid_observer/queries/job_executions_query"
24
+ require_relative "solid_observer/queries/events_query"
25
+ require_relative "solid_observer/queries/execution_finder"
26
+ require_relative "solid_observer/services/record_event"
27
+ require_relative "solid_observer/services/flush_event_buffer"
28
+ require_relative "solid_observer/services/cleanup_storage"
29
+ require_relative "solid_observer/queue_event_buffer"
30
+ require_relative "solid_observer/cache_event_buffer"
31
+ require_relative "solid_observer/services/flush_cache_metrics"
32
+ require_relative "solid_observer/cache_metric_buffer"
33
+ require_relative "solid_observer/cache_subscriber"
34
+ require_relative "solid_observer/services/record_cache_event"
35
+ require_relative "solid_observer/services/record_cache_metric"
36
+ require_relative "solid_observer/services/flush_cache_event_buffer"
37
+ require_relative "solid_observer/services/cache_stats"
38
+ require_relative "solid_observer/services/cache_operations"
39
+ require_relative "solid_observer/cable_event_buffer"
40
+ require_relative "solid_observer/services/flush_cable_metrics"
41
+ require_relative "solid_observer/cable_metric_buffer"
42
+ require_relative "solid_observer/cable_subscriber"
43
+ require_relative "solid_observer/services/record_cable_event"
44
+ require_relative "solid_observer/services/record_cable_metric"
45
+ require_relative "solid_observer/services/flush_cable_event_buffer"
46
+ require_relative "solid_observer/services/cable_stats"
47
+ require_relative "solid_observer/services/cable_operations"
48
+ end
49
+
27
50
  module SolidObserver
51
+ autoload :ExecutionPresenter, File.expand_path("../app/presenters/solid_observer/execution_presenter", __dir__)
52
+
28
53
  class Error < StandardError; end
29
54
 
30
55
  class << self
@@ -40,30 +40,48 @@ namespace :solid_observer do
40
40
  end
41
41
 
42
42
  namespace :buffer do
43
- desc "Flush the event buffer to the database"
43
+ desc "Flush the event buffers to the database"
44
44
  task flush: :environment do
45
- buffer = SolidObserver::QueueEventBuffer.instance
46
- buffer_size = buffer.size
47
-
48
- if buffer_size.zero?
49
- puts "Buffer is empty, nothing to flush"
45
+ buffers = [
46
+ {label: "queue events", buffer: SolidObserver::QueueEventBuffer.instance},
47
+ {label: "cache events", buffer: SolidObserver::CacheEventBuffer.instance},
48
+ {label: "cache metric buckets", buffer: SolidObserver::CacheMetricBuffer.instance}
49
+ ]
50
+ buffer_sizes = buffers.to_h { |entry| [entry, entry[:buffer].size] }
51
+
52
+ if buffer_sizes.values.sum.zero?
53
+ puts "Buffers are empty, nothing to flush"
50
54
  else
51
- puts "Flushing #{buffer_size} events from buffer..."
52
- buffer.flush!
53
- puts "✓ Buffer flushed successfully"
55
+ buffers.each do |entry|
56
+ size = buffer_sizes.fetch(entry)
57
+ next if size.zero?
58
+
59
+ puts "Flushing #{size} #{entry[:label]} from buffer..."
60
+ entry[:buffer].flush!
61
+ end
62
+ puts "✓ Buffers flushed successfully"
54
63
  end
55
64
  end
56
65
 
57
- desc "Clear the event buffer without flushing to database"
66
+ desc "Clear the event buffers without flushing to database"
58
67
  task clear: :environment do
59
- buffer = SolidObserver::QueueEventBuffer.instance
60
- buffer_size = buffer.size
61
-
62
- if buffer_size.zero?
63
- puts "Buffer is already empty"
68
+ buffers = [
69
+ {label: "queue events", buffer: SolidObserver::QueueEventBuffer.instance},
70
+ {label: "cache events", buffer: SolidObserver::CacheEventBuffer.instance},
71
+ {label: "cache metric buckets", buffer: SolidObserver::CacheMetricBuffer.instance}
72
+ ]
73
+ buffer_sizes = buffers.to_h { |entry| [entry, entry[:buffer].size] }
74
+
75
+ if buffer_sizes.values.sum.zero?
76
+ puts "Buffers are already empty"
64
77
  else
65
- buffer.clear
66
- puts "✓ Cleared #{buffer_size} events from buffer (not saved to database)"
78
+ buffers.each do |entry|
79
+ size = buffer_sizes.fetch(entry)
80
+ next if size.zero?
81
+
82
+ entry[:buffer].clear
83
+ puts "✓ Cleared #{size} #{entry[:label]} from buffer (not saved to database)"
84
+ end
67
85
  end
68
86
  end
69
87
  end
@@ -97,6 +115,18 @@ namespace :solid_observer do
97
115
  end
98
116
  end
99
117
 
118
+ namespace :cable do
119
+ desc "Trim expired Solid Cable messages"
120
+ task trim: :environment do
121
+ if !SolidObserver::Services::CableOperations.available?
122
+ puts SolidObserver::Services::CableOperations.unavailable_message
123
+ next
124
+ end
125
+
126
+ puts SolidObserver::Services::CableOperations.trim[:message]
127
+ end
128
+ end
129
+
100
130
  namespace :storage do
101
131
  desc "Run storage cleanup based on retention policy"
102
132
  task cleanup: :environment do
@@ -104,7 +134,7 @@ namespace :solid_observer do
104
134
  puts "Running storage cleanup (retention: #{retention.inspect})..."
105
135
 
106
136
  deleted_count = SolidObserver::Services::CleanupStorage.call
107
- puts "✓ Cleanup complete: #{deleted_count} old events deleted"
137
+ puts "✓ Cleanup complete: #{deleted_count} old telemetry rows deleted"
108
138
  end
109
139
 
110
140
  desc "Purge ALL SolidObserver storage data (use with caution!)"
@@ -114,10 +144,30 @@ namespace :solid_observer do
114
144
 
115
145
  confirmation = $stdin.gets&.strip&.downcase
116
146
  if confirmation == "y"
117
- event_count = SolidObserver::QueueEvent.count
147
+ data_source_exists = lambda do |model|
148
+ table_name = model.table_name.to_s
149
+ !table_name.empty? && model.connection.data_source_exists?(table_name)
150
+ rescue ActiveRecord::ConnectionNotEstablished, ActiveRecord::StatementInvalid, TypeError
151
+ false
152
+ end
153
+
154
+ telemetry_models = [
155
+ {label: :queue_events, model: SolidObserver::QueueEvent},
156
+ {label: :cache_events, model: SolidObserver::CacheEvent},
157
+ {label: :cache_metrics, model: SolidObserver::CacheMetric}
158
+ ]
159
+
160
+ telemetry_counts = telemetry_models.to_h do |entry|
161
+ count = data_source_exists.call(entry[:model]) ? entry[:model].count : 0
162
+ [entry[:label], count]
163
+ end
118
164
  snapshot_count = SolidObserver::StorageInfo.count
119
165
 
120
- SolidObserver::QueueEvent.delete_all
166
+ telemetry_models.each do |entry|
167
+ next unless data_source_exists.call(entry[:model])
168
+
169
+ entry[:model].delete_all
170
+ end
121
171
  SolidObserver::StorageInfo.delete_all
122
172
 
123
173
  connection = SolidObserver::QueueEvent.connection
@@ -126,12 +176,23 @@ namespace :solid_observer do
126
176
  connection.execute("VACUUM")
127
177
  puts "✓ Database vacuumed to reclaim disk space"
128
178
  when "postgresql"
129
- connection.execute("ANALYZE solid_observer_queue_events")
130
- connection.execute("ANALYZE solid_observer_storage_info")
179
+ [
180
+ SolidObserver::QueueEvent.table_name,
181
+ SolidObserver::StorageInfo.table_name,
182
+ (SolidObserver::CacheEvent.table_name if data_source_exists.call(SolidObserver::CacheEvent)),
183
+ (SolidObserver::CacheMetric.table_name if data_source_exists.call(SolidObserver::CacheMetric))
184
+ ].compact.each do |table_name|
185
+ connection.execute("ANALYZE #{table_name}")
186
+ end
131
187
  puts "✓ Database tables analyzed"
132
188
  end
133
189
 
134
- puts "✓ Purged #{event_count} events and #{snapshot_count} storage snapshots"
190
+ puts(
191
+ "✓ Purged #{telemetry_counts.fetch(:queue_events)} queue events, " \
192
+ "#{telemetry_counts.fetch(:cache_events)} cache events, " \
193
+ "#{telemetry_counts.fetch(:cache_metrics)} cache metrics, " \
194
+ "and #{snapshot_count} storage snapshots"
195
+ )
135
196
  else
136
197
  puts "Aborted"
137
198
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solid_observer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - BartOz
@@ -50,11 +50,12 @@ files:
50
50
  - LICENSE.txt
51
51
  - README.md
52
52
  - app/assets/javascripts/solid_observer/live_poll.js
53
- - app/assets/stylesheets/solid_observer/application.css
54
53
  - app/controllers/concerns/solid_observer/paginatable.rb
55
54
  - app/controllers/concerns/solid_observer/require_persistence_mode.rb
56
55
  - app/controllers/concerns/solid_observer/require_solid_queue.rb
57
56
  - app/controllers/solid_observer/application_controller.rb
57
+ - app/controllers/solid_observer/cable_dashboard_controller.rb
58
+ - app/controllers/solid_observer/cable_operations_controller.rb
58
59
  - app/controllers/solid_observer/cache_dashboard_controller.rb
59
60
  - app/controllers/solid_observer/cache_operations_controller.rb
60
61
  - app/controllers/solid_observer/dashboard_controller.rb
@@ -64,6 +65,8 @@ files:
64
65
  - app/helpers/solid_observer/application_helper.rb
65
66
  - app/helpers/solid_observer/dashboard_helper.rb
66
67
  - app/jobs/solid_observer/cleanup_job.rb
68
+ - app/models/solid_observer/cable_event.rb
69
+ - app/models/solid_observer/cable_metric.rb
67
70
  - app/models/solid_observer/cache_event.rb
68
71
  - app/models/solid_observer/cache_metric.rb
69
72
  - app/models/solid_observer/queue_event.rb
@@ -71,6 +74,10 @@ files:
71
74
  - app/models/solid_observer/storage_info.rb
72
75
  - app/presenters/solid_observer/execution_presenter.rb
73
76
  - app/views/layouts/solid_observer/application.html.erb
77
+ - app/views/solid_observer/cable_dashboard/_charts.html.erb
78
+ - app/views/solid_observer/cable_dashboard/_recent_events.html.erb
79
+ - app/views/solid_observer/cable_dashboard/_summary.html.erb
80
+ - app/views/solid_observer/cable_dashboard/index.html.erb
74
81
  - app/views/solid_observer/cache_dashboard/_charts.html.erb
75
82
  - app/views/solid_observer/cache_dashboard/_recent_events.html.erb
76
83
  - app/views/solid_observer/cache_dashboard/_summary.html.erb
@@ -92,9 +99,6 @@ files:
92
99
  - app/views/solid_observer/shared/_pagination.html.erb
93
100
  - app/views/solid_observer/shared/_stat_card.html.erb
94
101
  - app/views/solid_observer/storages/show.html.erb
95
- - bin/console
96
- - bin/quality_gate
97
- - bin/setup
98
102
  - config/routes.rb
99
103
  - db/migrate/20260115000001_create_solid_observer_queue_events.rb
100
104
  - db/migrate/20260115000002_create_solid_observer_metrics.rb
@@ -103,12 +107,20 @@ files:
103
107
  - db/migrate/20260601000001_create_solid_observer_cache_events.rb
104
108
  - db/migrate/20260601000002_create_solid_observer_cache_metrics.rb
105
109
  - db/migrate/20260602000001_add_component_to_solid_observer_storage_infos.rb
110
+ - db/migrate/20260612000001_add_event_type_recorded_at_index_to_cache_events.rb
111
+ - db/migrate/20260619000001_create_solid_observer_cable_events.rb
112
+ - db/migrate/20260619000002_create_solid_observer_cable_metrics.rb
106
113
  - lib/generators/solid_observer/install_generator.rb
107
114
  - lib/generators/solid_observer/templates/initializer.rb.tt
108
115
  - lib/solid_observer.rb
109
116
  - lib/solid_observer/base_event.rb
110
117
  - lib/solid_observer/base_metric.rb
118
+ - lib/solid_observer/base_record.rb
119
+ - lib/solid_observer/cable_event_buffer.rb
120
+ - lib/solid_observer/cable_metric_buffer.rb
121
+ - lib/solid_observer/cable_subscriber.rb
111
122
  - lib/solid_observer/cache_event_buffer.rb
123
+ - lib/solid_observer/cache_metric_buffer.rb
112
124
  - lib/solid_observer/cache_subscriber.rb
113
125
  - lib/solid_observer/chart_buffer.rb
114
126
  - lib/solid_observer/cli/base.rb
@@ -118,6 +130,7 @@ files:
118
130
  - lib/solid_observer/configuration.rb
119
131
  - lib/solid_observer/correlation_id_resolver.rb
120
132
  - lib/solid_observer/engine.rb
133
+ - lib/solid_observer/event_buffer_core.rb
121
134
  - lib/solid_observer/params/events_filter.rb
122
135
  - lib/solid_observer/params/jobs_filter.rb
123
136
  - lib/solid_observer/queries/events_query.rb
@@ -125,13 +138,20 @@ files:
125
138
  - lib/solid_observer/queries/job_executions_query.rb
126
139
  - lib/solid_observer/queue_event_buffer.rb
127
140
  - lib/solid_observer/queue_stats.rb
141
+ - lib/solid_observer/services/cable_operations.rb
142
+ - lib/solid_observer/services/cable_stats.rb
128
143
  - lib/solid_observer/services/cache_operations.rb
129
144
  - lib/solid_observer/services/cache_stats.rb
130
145
  - lib/solid_observer/services/cleanup_storage.rb
131
146
  - lib/solid_observer/services/database_size.rb
147
+ - lib/solid_observer/services/flush_cable_event_buffer.rb
148
+ - lib/solid_observer/services/flush_cable_metrics.rb
132
149
  - lib/solid_observer/services/flush_cache_event_buffer.rb
150
+ - lib/solid_observer/services/flush_cache_metrics.rb
133
151
  - lib/solid_observer/services/flush_event_buffer.rb
134
152
  - lib/solid_observer/services/install_migrations.rb
153
+ - lib/solid_observer/services/record_cable_event.rb
154
+ - lib/solid_observer/services/record_cable_metric.rb
135
155
  - lib/solid_observer/services/record_cache_event.rb
136
156
  - lib/solid_observer/services/record_cache_metric.rb
137
157
  - lib/solid_observer/services/record_event.rb
@@ -163,7 +183,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
163
183
  - !ruby/object:Gem::Version
164
184
  version: '0'
165
185
  requirements: []
166
- rubygems_version: 4.0.3
186
+ rubygems_version: 4.0.6
167
187
  specification_version: 4
168
188
  summary: Observability for the Rails 8's Solid Stack
169
189
  test_files: []
@@ -1,18 +0,0 @@
1
- .so-sidebar__nav .active {
2
- font-weight: 600;
3
- }
4
-
5
- .so-sidebar__nav a:focus-visible {
6
- outline: 2px solid var(--so-info);
7
- outline-offset: 2px;
8
- box-shadow: 0 0 0 3px var(--so-focus-ring);
9
- }
10
-
11
- .so-sidebar__section {
12
- font-size: 0.7rem;
13
- text-transform: uppercase;
14
- letter-spacing: 0.08em;
15
- color: var(--so-text-muted);
16
- padding: 0.5rem 0.75rem 0.25rem;
17
- margin: 0.5rem 0.75rem 0.25rem;
18
- }
data/bin/console DELETED
@@ -1,11 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require "bundler/setup"
5
- require "solid_observer"
6
-
7
- # You can add fixtures and/or initialization code here to make experimenting
8
- # with your gem easier. You can also use a different console, if you like.
9
-
10
- require "irb"
11
- IRB.start(__FILE__)