rails_pulse 0.1.1 โ 0.1.3
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.
- checksums.yaml +4 -4
- data/README.md +79 -177
- data/Rakefile +77 -2
- data/app/assets/images/rails_pulse/dashboard.png +0 -0
- data/app/assets/images/rails_pulse/request.png +0 -0
- data/app/assets/stylesheets/rails_pulse/application.css +28 -17
- data/app/assets/stylesheets/rails_pulse/components/badge.css +13 -0
- data/app/assets/stylesheets/rails_pulse/components/base.css +12 -2
- data/app/assets/stylesheets/rails_pulse/components/collapsible.css +30 -0
- data/app/assets/stylesheets/rails_pulse/components/popover.css +0 -1
- data/app/assets/stylesheets/rails_pulse/components/row.css +55 -3
- data/app/assets/stylesheets/rails_pulse/components/sidebar_menu.css +23 -0
- data/app/controllers/concerns/chart_table_concern.rb +21 -4
- data/app/controllers/concerns/response_range_concern.rb +6 -3
- data/app/controllers/concerns/time_range_concern.rb +5 -10
- data/app/controllers/concerns/zoom_range_concern.rb +32 -1
- data/app/controllers/rails_pulse/application_controller.rb +13 -5
- data/app/controllers/rails_pulse/dashboard_controller.rb +12 -0
- data/app/controllers/rails_pulse/queries_controller.rb +111 -51
- data/app/controllers/rails_pulse/requests_controller.rb +37 -12
- data/app/controllers/rails_pulse/routes_controller.rb +98 -24
- data/app/helpers/rails_pulse/application_helper.rb +0 -1
- data/app/helpers/rails_pulse/chart_formatters.rb +3 -3
- data/app/helpers/rails_pulse/chart_helper.rb +21 -9
- data/app/helpers/rails_pulse/status_helper.rb +10 -4
- data/app/javascript/rails_pulse/application.js +34 -3
- data/app/javascript/rails_pulse/controllers/collapsible_controller.js +32 -0
- data/app/javascript/rails_pulse/controllers/color_scheme_controller.js +2 -1
- data/app/javascript/rails_pulse/controllers/expandable_rows_controller.js +58 -0
- data/app/javascript/rails_pulse/controllers/index_controller.js +353 -39
- data/app/javascript/rails_pulse/controllers/pagination_controller.js +17 -27
- data/app/javascript/rails_pulse/controllers/popover_controller.js +28 -4
- data/app/javascript/rails_pulse/controllers/table_sort_controller.js +14 -0
- data/app/jobs/rails_pulse/backfill_summaries_job.rb +41 -0
- data/app/jobs/rails_pulse/summary_job.rb +53 -0
- data/app/models/rails_pulse/dashboard/charts/average_response_time.rb +28 -7
- data/app/models/rails_pulse/dashboard/charts/p95_response_time.rb +18 -22
- data/app/models/rails_pulse/dashboard/tables/slow_queries.rb +18 -7
- data/app/models/rails_pulse/dashboard/tables/slow_routes.rb +34 -41
- data/app/models/rails_pulse/operation.rb +1 -1
- data/app/models/rails_pulse/queries/cards/average_query_times.rb +49 -25
- data/app/models/rails_pulse/queries/cards/execution_rate.rb +40 -28
- data/app/models/rails_pulse/queries/cards/percentile_query_times.rb +37 -43
- data/app/models/rails_pulse/queries/charts/average_query_times.rb +23 -97
- data/app/models/rails_pulse/queries/tables/index.rb +74 -0
- data/app/models/rails_pulse/query.rb +47 -0
- data/app/models/rails_pulse/requests/charts/average_response_times.rb +23 -84
- data/app/models/rails_pulse/route.rb +1 -6
- data/app/models/rails_pulse/routes/cards/average_response_times.rb +45 -25
- data/app/models/rails_pulse/routes/cards/error_rate_per_route.rb +43 -45
- data/app/models/rails_pulse/routes/cards/percentile_response_times.rb +36 -44
- data/app/models/rails_pulse/routes/cards/request_count_totals.rb +37 -27
- data/app/models/rails_pulse/routes/charts/average_response_times.rb +23 -100
- data/app/models/rails_pulse/routes/tables/index.rb +57 -40
- data/app/models/rails_pulse/summary.rb +143 -0
- data/app/services/rails_pulse/analysis/backtrace_analyzer.rb +256 -0
- data/app/services/rails_pulse/analysis/base_analyzer.rb +67 -0
- data/app/services/rails_pulse/analysis/explain_plan_analyzer.rb +206 -0
- data/app/services/rails_pulse/analysis/index_recommendation_engine.rb +326 -0
- data/app/services/rails_pulse/analysis/n_plus_one_detector.rb +241 -0
- data/app/services/rails_pulse/analysis/query_characteristics_analyzer.rb +146 -0
- data/app/services/rails_pulse/analysis/suggestion_generator.rb +217 -0
- data/app/services/rails_pulse/query_analysis_service.rb +125 -0
- data/app/services/rails_pulse/summary_service.rb +199 -0
- data/app/views/layouts/rails_pulse/_sidebar_menu.html.erb +0 -1
- data/app/views/layouts/rails_pulse/application.html.erb +4 -6
- data/app/views/rails_pulse/components/_breadcrumbs.html.erb +1 -1
- data/app/views/rails_pulse/components/_code_panel.html.erb +17 -3
- data/app/views/rails_pulse/components/_empty_state.html.erb +11 -0
- data/app/views/rails_pulse/components/_metric_card.html.erb +37 -28
- data/app/views/rails_pulse/components/_panel.html.erb +1 -1
- data/app/views/rails_pulse/components/_sparkline_stats.html.erb +5 -7
- data/app/views/rails_pulse/components/_table_head.html.erb +6 -1
- data/app/views/rails_pulse/dashboard/index.html.erb +55 -37
- data/app/views/rails_pulse/operations/show.html.erb +17 -15
- data/app/views/rails_pulse/queries/_analysis_error.html.erb +15 -0
- data/app/views/rails_pulse/queries/_analysis_prompt.html.erb +27 -0
- data/app/views/rails_pulse/queries/_analysis_results.html.erb +87 -0
- data/app/views/rails_pulse/queries/_analysis_section.html.erb +39 -0
- data/app/views/rails_pulse/queries/_show_table.html.erb +2 -2
- data/app/views/rails_pulse/queries/_table.html.erb +11 -13
- data/app/views/rails_pulse/queries/index.html.erb +32 -28
- data/app/views/rails_pulse/queries/show.html.erb +45 -34
- data/app/views/rails_pulse/requests/_operations.html.erb +38 -45
- data/app/views/rails_pulse/requests/_table.html.erb +3 -3
- data/app/views/rails_pulse/requests/index.html.erb +33 -28
- data/app/views/rails_pulse/routes/_table.html.erb +14 -14
- data/app/views/rails_pulse/routes/index.html.erb +34 -29
- data/app/views/rails_pulse/routes/show.html.erb +43 -36
- data/config/initializers/rails_pulse.rb +0 -12
- data/config/routes.rb +5 -1
- data/db/migrate/20241222000001_create_rails_pulse_summaries.rb +54 -0
- data/db/migrate/20250916031656_add_analysis_to_rails_pulse_queries.rb +13 -0
- data/db/rails_pulse_schema.rb +130 -0
- data/lib/generators/rails_pulse/convert_to_migrations_generator.rb +65 -0
- data/lib/generators/rails_pulse/install_generator.rb +94 -4
- data/lib/generators/rails_pulse/templates/db/rails_pulse_schema.rb +60 -0
- data/lib/generators/rails_pulse/templates/migrations/install_rails_pulse_tables.rb +22 -0
- data/lib/generators/rails_pulse/templates/migrations/upgrade_rails_pulse_tables.rb +19 -0
- data/lib/generators/rails_pulse/templates/rails_pulse.rb +0 -12
- data/lib/generators/rails_pulse/upgrade_generator.rb +225 -0
- data/lib/rails_pulse/configuration.rb +0 -11
- data/lib/rails_pulse/engine.rb +0 -1
- data/lib/rails_pulse/version.rb +1 -1
- data/lib/tasks/rails_pulse.rake +77 -0
- data/public/rails-pulse-assets/rails-pulse.css +1 -1
- data/public/rails-pulse-assets/rails-pulse.css.map +1 -1
- data/public/rails-pulse-assets/rails-pulse.js +53 -53
- data/public/rails-pulse-assets/rails-pulse.js.map +4 -4
- data/public/rails-pulse-assets/search.svg +43 -0
- metadata +48 -14
- data/app/assets/images/rails_pulse/rails-pulse-logo.png +0 -0
- data/app/assets/images/rails_pulse/routes.png +0 -0
- data/app/controllers/rails_pulse/caches_controller.rb +0 -115
- data/app/helpers/rails_pulse/cached_component_helper.rb +0 -73
- data/app/javascript/rails_pulse/controllers/expandable_row_controller.js +0 -67
- data/app/models/rails_pulse/component_cache_key.rb +0 -33
- data/app/views/rails_pulse/caches/show.html.erb +0 -9
- data/db/migrate/20250227235904_create_routes.rb +0 -12
- data/db/migrate/20250227235915_create_requests.rb +0 -19
- data/db/migrate/20250228000000_create_queries.rb +0 -14
- data/db/migrate/20250228000056_create_operations.rb +0 -24
- data/lib/rails_pulse/migration.rb +0 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 11728d425611e7ab3a9edb171f05638a783d1c8d3ded8dff112bb615e8a18d11
|
4
|
+
data.tar.gz: 3e16c2d59f4f4bd8d2df49625d9f6005edc98dec701212a6052f4abfd1cac6f3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 443645ed917ef9beea2d642ff8c4a7d2e57cc87559a09e74dfd75d20d18fb0ff11040eac6e825f3ff0af35637ea23757c88b24e78f35e32f64a7660168aa940a
|
7
|
+
data.tar.gz: d11227a7a11c24bff167104e712f9d075a394130a196938ed71b360e6cbc82a8f930672187b92d0009ed5c14fee882ff23d3d88a3df25b1ddeff3a8839452b5b
|
data/README.md
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
**Real-time performance monitoring and debugging for Rails applications**
|
7
7
|
|
8
8
|

|
9
|
-

|
10
10
|

|
11
11
|

|
12
12
|
</div>
|
@@ -25,16 +25,14 @@
|
|
25
25
|
- [Authentication](#authentication)
|
26
26
|
- [Authentication Setup](#authentication-setup)
|
27
27
|
- [Authentication Examples](#authentication-examples)
|
28
|
-
- [Security Considerations](#security-considerations)
|
29
28
|
- [Data Management](#data-management)
|
30
29
|
- [Cleanup Strategies](#cleanup-strategies)
|
31
30
|
- [Cleanup Configuration](#cleanup-configuration)
|
32
31
|
- [Manual Cleanup Operations](#manual-cleanup-operations)
|
33
|
-
|
34
|
-
- [Multiple Database Support](#multiple-database-support)
|
32
|
+
- [Separate Database Support](#separate-database-support)
|
35
33
|
- [Configuration](#configuration)
|
36
34
|
- [Database Configuration](#database-configuration)
|
37
|
-
- [
|
35
|
+
- [Schema Loading](#schema-loading)
|
38
36
|
- [Testing](#testing)
|
39
37
|
- [Technology Stack](#technology-stack)
|
40
38
|
- [Advantages Over Other Solutions](#advantages-over-other-solutions)
|
@@ -44,33 +42,17 @@
|
|
44
42
|
|
45
43
|
## Introduction
|
46
44
|
|
47
|
-
Rails Pulse is a comprehensive performance monitoring and debugging gem that provides
|
48
|
-
|
49
|
-
**Why Rails Pulse?**
|
50
|
-
|
51
|
-
- **Visual**: Beautiful, responsive dashboards with actionable insights
|
52
|
-
- **Comprehensive**: Monitors requests, database queries, and application operations
|
53
|
-
- **Real-time**: Live performance metrics
|
54
|
-
- **Zero Configuration**: Works out of the box with sensible defaults
|
55
|
-
- **Lightweight**: Minimal performance overhead in production
|
56
|
-
- **Asset Independent**: Pre-compiled assets work with any Rails build system
|
57
|
-
- **CSP Compliant**: Secure by default with Content Security Policy support
|
45
|
+
Rails Pulse is a comprehensive performance monitoring and debugging gem that provides insights into your Rails application's health. Built as a Rails Engine, it seamlessly integrates with your existing application to capture, analyze, and visualize performance metrics without impacting your production workload.
|
58
46
|
|
59
47
|
## Features
|
60
48
|
|
61
|
-
###
|
49
|
+
### Performance Monitoring
|
62
50
|
- Interactive dashboard with response time charts and request analytics
|
63
51
|
- SQL query performance tracking with slow query identification
|
64
52
|
- Route-specific metrics with configurable performance thresholds
|
65
53
|
- Week-over-week trend analysis with visual indicators
|
66
54
|
|
67
|
-
###
|
68
|
-
- Content Security Policy (CSP) compliant with pre-compiled assets
|
69
|
-
- Flexible authentication system with multiple authentication methods
|
70
|
-
- Automatic data cleanup with configurable retention policies
|
71
|
-
- Zero build dependencies - works with any Rails setup
|
72
|
-
|
73
|
-
### โก **Developer Experience**
|
55
|
+
### Developer Experience
|
74
56
|
- Zero configuration setup with sensible defaults
|
75
57
|
- Beautiful responsive interface with dark/light mode
|
76
58
|
- Smart caching with minimal performance overhead
|
@@ -78,7 +60,13 @@ Rails Pulse is a comprehensive performance monitoring and debugging gem that pro
|
|
78
60
|
|
79
61
|
## Screenshots
|
80
62
|
|
81
|
-
<
|
63
|
+
<table>
|
64
|
+
<tr>
|
65
|
+
<td><img src="app/assets/images/rails_pulse/dashboard.png" alt="Rails Pulse Dashboard" width="400" /></td>
|
66
|
+
<td><img src="app/assets/images/rails_pulse/request.png" alt="Rails Pulse Requests" width="400" /></td>
|
67
|
+
</tr>
|
68
|
+
</table>
|
69
|
+
|
82
70
|
|
83
71
|
## Getting Started
|
84
72
|
|
@@ -102,22 +90,30 @@ Generate the installation files:
|
|
102
90
|
rails generate rails_pulse:install
|
103
91
|
```
|
104
92
|
|
105
|
-
|
93
|
+
Load the database schema:
|
106
94
|
|
107
95
|
```bash
|
108
|
-
rails db:
|
96
|
+
rails db:prepare
|
109
97
|
```
|
110
98
|
|
111
99
|
Add the Rails Pulse route to your application:
|
112
100
|
|
113
101
|
```ruby
|
114
|
-
# config/routes.rb
|
115
102
|
Rails.application.routes.draw do
|
116
103
|
mount RailsPulse::Engine => "/rails_pulse"
|
117
|
-
# ... your other routes
|
118
104
|
end
|
119
105
|
```
|
120
106
|
|
107
|
+
Schedule background jobs:
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
# Schedule to run 5 minutes past every hour. cron: 5 * * * *
|
111
|
+
RailsPulse::SummaryJob.perform_later
|
112
|
+
|
113
|
+
# Schedule to run daily. cron: 0 1 * * *
|
114
|
+
RailsPulse::CleanupJob.perform_later
|
115
|
+
```
|
116
|
+
|
121
117
|
### Quick Setup
|
122
118
|
|
123
119
|
Rails Pulse automatically starts collecting performance data once installed. Access your monitoring dashboard at:
|
@@ -135,14 +131,14 @@ RailsPulse.configure do |config|
|
|
135
131
|
# Enable or disable Rails Pulse
|
136
132
|
config.enabled = true
|
137
133
|
|
138
|
-
# Set performance thresholds for
|
134
|
+
# Set performance thresholds for route response times (in milliseconds)
|
139
135
|
config.route_thresholds = {
|
140
136
|
slow: 500,
|
141
137
|
very_slow: 1500,
|
142
138
|
critical: 3000
|
143
139
|
}
|
144
140
|
|
145
|
-
# Set performance thresholds for
|
141
|
+
# Set performance thresholds for request response times (in milliseconds)
|
146
142
|
config.request_thresholds = {
|
147
143
|
slow: 700,
|
148
144
|
very_slow: 2000,
|
@@ -157,8 +153,8 @@ RailsPulse.configure do |config|
|
|
157
153
|
}
|
158
154
|
|
159
155
|
# Asset tracking configuration
|
160
|
-
config.track_assets = false
|
161
|
-
config.custom_asset_patterns = []
|
156
|
+
config.track_assets = false # Ignore asset requests by default
|
157
|
+
config.custom_asset_patterns = [] # Additional asset patterns to ignore
|
162
158
|
|
163
159
|
# Rails Pulse mount path (optional)
|
164
160
|
# Specify if Rails Pulse is mounted at a custom path to prevent self-tracking
|
@@ -171,7 +167,7 @@ RailsPulse.configure do |config|
|
|
171
167
|
|
172
168
|
# Data cleanup
|
173
169
|
config.archiving_enabled = true # Enable automatic cleanup
|
174
|
-
config.full_retention_period = 2.weeks
|
170
|
+
config.full_retention_period = 2.weeks # Delete records older than this
|
175
171
|
config.max_table_records = { # Maximum records per table
|
176
172
|
rails_pulse_requests: 10000,
|
177
173
|
rails_pulse_operations: 50000,
|
@@ -179,10 +175,6 @@ RailsPulse.configure do |config|
|
|
179
175
|
rails_pulse_queries: 500
|
180
176
|
}
|
181
177
|
|
182
|
-
# Metric caching for performance
|
183
|
-
config.component_cache_enabled = true
|
184
|
-
config.component_cache_duration = 1.day
|
185
|
-
|
186
178
|
# Multiple database support (optional)
|
187
179
|
# Uncomment to store Rails Pulse data in a separate database
|
188
180
|
# config.connects_to = {
|
@@ -219,7 +211,7 @@ end
|
|
219
211
|
|
220
212
|
Rails Pulse works with any authentication system. Here are common patterns:
|
221
213
|
|
222
|
-
####
|
214
|
+
#### Devise with Admin Role
|
223
215
|
|
224
216
|
```ruby
|
225
217
|
config.authentication_method = proc {
|
@@ -229,36 +221,7 @@ config.authentication_method = proc {
|
|
229
221
|
}
|
230
222
|
```
|
231
223
|
|
232
|
-
####
|
233
|
-
|
234
|
-
```ruby
|
235
|
-
config.authentication_method = proc {
|
236
|
-
unless session[:user_id] && User.find_by(id: session[:user_id])&.admin?
|
237
|
-
redirect_to main_app.login_path, alert: "Please log in as an admin"
|
238
|
-
end
|
239
|
-
}
|
240
|
-
```
|
241
|
-
|
242
|
-
#### **HTTP Basic Authentication**
|
243
|
-
|
244
|
-
```ruby
|
245
|
-
config.authentication_method = proc {
|
246
|
-
authenticate_or_request_with_http_basic do |username, password|
|
247
|
-
username == ENV['RAILS_PULSE_USERNAME'] &&
|
248
|
-
password == ENV['RAILS_PULSE_PASSWORD']
|
249
|
-
end
|
250
|
-
}
|
251
|
-
```
|
252
|
-
|
253
|
-
#### **Warden Authentication**
|
254
|
-
|
255
|
-
```ruby
|
256
|
-
config.authentication_method = proc {
|
257
|
-
warden.authenticate!(scope: :admin)
|
258
|
-
}
|
259
|
-
```
|
260
|
-
|
261
|
-
#### **Custom Authorization Logic**
|
224
|
+
#### Custom Authorization Logic
|
262
225
|
|
263
226
|
```ruby
|
264
227
|
config.authentication_method = proc {
|
@@ -269,16 +232,6 @@ config.authentication_method = proc {
|
|
269
232
|
}
|
270
233
|
```
|
271
234
|
|
272
|
-
### Security Considerations
|
273
|
-
|
274
|
-
- **Production Security**: Always enable authentication in production environments
|
275
|
-
- **Admin-only Access**: Limit access to administrators or authorized personnel
|
276
|
-
- **Environment Variables**: Use environment variables for credentials, never hardcode
|
277
|
-
- **HTTPS Required**: Always use HTTPS in production when authentication is enabled
|
278
|
-
- **Regular Access Review**: Periodically review who has access to monitoring data
|
279
|
-
|
280
|
-
**Important**: The authentication method runs in the context of the Rails Pulse ApplicationController, giving you access to all standard Rails controller methods like `redirect_to`, `render`, `session`, and any methods from your host application's authentication system.
|
281
|
-
|
282
235
|
## Data Management
|
283
236
|
|
284
237
|
Rails Pulse provides data cleanup to prevent your monitoring database from growing indefinitely while preserving essential performance insights.
|
@@ -329,28 +282,22 @@ rails rails_pulse:cleanup_stats
|
|
329
282
|
|
330
283
|
**Schedule automated cleanup:**
|
331
284
|
```ruby
|
332
|
-
# Using whenever gem or similar scheduler
|
333
285
|
RailsPulse::CleanupJob.perform_later
|
334
286
|
```
|
335
287
|
|
336
|
-
|
337
|
-
|
338
|
-
1. **Time-based Phase**: Delete all records older than `full_retention_period`
|
339
|
-
2. **Count-based Phase**: If tables still exceed limits, delete oldest remaining records
|
340
|
-
3. **Safe Deletion**: Respects foreign key constraints (operations โ requests โ queries/routes)
|
341
|
-
4. **Comprehensive Logging**: Detailed cleanup statistics and operation logs
|
288
|
+
## Separate Database Support
|
342
289
|
|
343
|
-
|
290
|
+
Rails Pulse supports storing performance monitoring data in a **separate database**. By default, Rails Pulse stores data in your main application database alongside your existing tables.
|
344
291
|
|
345
|
-
|
346
|
-
|
347
|
-
Rails Pulse supports storing performance monitoring data in a separate database. This is particularly useful for:
|
292
|
+
Use a separate database when you want:
|
348
293
|
|
349
294
|
- **Isolating monitoring data** from your main application database
|
350
295
|
- **Using different database engines** optimized for time-series data
|
351
296
|
- **Scaling monitoring independently** from your application
|
352
297
|
- **Simplified backup strategies** with separate retention policies
|
353
298
|
|
299
|
+
**For shared database setup (default)**, no database configuration is needed - simply run `rails db:prepare` after installation.
|
300
|
+
|
354
301
|
### Configuration
|
355
302
|
|
356
303
|
To use a separate database, configure the `connects_to` option in your Rails Pulse initializer:
|
@@ -380,6 +327,7 @@ production:
|
|
380
327
|
rails_pulse:
|
381
328
|
adapter: sqlite3
|
382
329
|
database: storage/rails_pulse_production.sqlite3
|
330
|
+
migrations_paths: db/rails_pulse_migrate
|
383
331
|
pool: 5
|
384
332
|
timeout: 5000
|
385
333
|
|
@@ -392,6 +340,7 @@ production:
|
|
392
340
|
username: rails_pulse_user
|
393
341
|
password: <%= Rails.application.credentials.dig(:rails_pulse, :database_password) %>
|
394
342
|
host: localhost
|
343
|
+
migrations_paths: db/rails_pulse_migrate
|
395
344
|
pool: 5
|
396
345
|
|
397
346
|
# For MySQL
|
@@ -403,35 +352,31 @@ production:
|
|
403
352
|
username: rails_pulse_user
|
404
353
|
password: <%= Rails.application.credentials.dig(:rails_pulse, :database_password) %>
|
405
354
|
host: localhost
|
355
|
+
migrations_paths: db/rails_pulse_migrate
|
406
356
|
pool: 5
|
407
357
|
```
|
408
358
|
|
409
|
-
###
|
359
|
+
### Schema Loading
|
410
360
|
|
411
|
-
|
361
|
+
After installation, load the Rails Pulse database schema:
|
412
362
|
|
413
363
|
```bash
|
414
|
-
|
415
|
-
rails db:migrate
|
416
|
-
|
417
|
-
# If you need to run migrations on a specific database
|
418
|
-
RAILS_ENV=production rails db:migrate
|
364
|
+
rails db:prepare
|
419
365
|
```
|
420
366
|
|
421
|
-
|
367
|
+
This command works for both:
|
368
|
+
- Shared database setup (default): Loads tables into your main application database
|
369
|
+
- Separate database setup: Automatically loads tables into your configured Rails Pulse database
|
422
370
|
|
423
371
|
## Testing
|
424
372
|
|
425
|
-
Rails Pulse includes a comprehensive test suite designed for speed and reliability across multiple databases
|
373
|
+
Rails Pulse includes a comprehensive test suite designed for speed and reliability across multiple databases and Rails versions.
|
426
374
|
|
427
375
|
### Running the Complete Test Suite
|
428
376
|
|
429
377
|
```bash
|
430
|
-
# Run all tests (unit, functional, integration)
|
378
|
+
# Run all tests (unit, functional, integration, instrumentation)
|
431
379
|
rails test:all
|
432
|
-
|
433
|
-
# Run tests with speed optimizations
|
434
|
-
rails test:fast
|
435
380
|
```
|
436
381
|
|
437
382
|
### Running Individual Test Types
|
@@ -452,83 +397,46 @@ rails test:integration
|
|
452
397
|
```bash
|
453
398
|
# Run a specific test file
|
454
399
|
rails test test/models/rails_pulse/request_test.rb
|
455
|
-
|
456
|
-
# Run controller tests
|
457
|
-
rails test test/controllers/rails_pulse/dashboard_controller_test.rb
|
458
|
-
|
459
|
-
# Run helper tests
|
460
|
-
rails test test/helpers/rails_pulse/application_helper_test.rb
|
461
|
-
|
462
|
-
# Run factory verification tests
|
463
|
-
rails test test/factories_test.rb
|
464
400
|
```
|
465
401
|
|
466
|
-
### Multi-Rails Version Testing
|
402
|
+
### Multi-Database and Rails Version Testing
|
467
403
|
|
468
|
-
Test against multiple Rails versions using
|
404
|
+
Test against multiple databases and Rails versions using the matrix task:
|
469
405
|
|
470
406
|
```bash
|
471
|
-
#
|
472
|
-
|
473
|
-
|
474
|
-
# Run tests against all Rails versions
|
475
|
-
bundle exec appraisal rails test:all
|
476
|
-
|
477
|
-
# Run tests against specific Rails version
|
478
|
-
bundle exec appraisal rails-7-1 rails test:unit
|
407
|
+
# Test all database and Rails version combinations locally
|
408
|
+
rails test:matrix
|
479
409
|
```
|
480
410
|
|
481
|
-
|
482
|
-
|
483
|
-
- **
|
484
|
-
- **Transaction rollback**: Tests use database transactions for fast cleanup
|
485
|
-
- **Stubbed dependencies**: External calls and expensive operations are stubbed
|
486
|
-
- **Parallel execution**: Tests run in parallel when supported
|
487
|
-
|
488
|
-
### Database Testing
|
489
|
-
|
490
|
-
Rails Pulse supports testing with multiple database adapters using simplified Rake tasks:
|
491
|
-
|
492
|
-
```bash
|
493
|
-
# Quick Commands (Recommended)
|
494
|
-
rails test:sqlite # Test with SQLite (default)
|
495
|
-
rails test:postgresql # Test with PostgreSQL
|
496
|
-
rails test:mysql # Test with MySQL
|
497
|
-
|
498
|
-
# Test Matrix (before pushing)
|
499
|
-
rails test:matrix # Test SQLite + PostgreSQL
|
500
|
-
rails test:matrix_full # Test all databases (SQLite + PostgreSQL + MySQL)
|
501
|
-
```
|
411
|
+
This command tests all combinations locally:
|
412
|
+
- **Databases**: SQLite3, PostgreSQL, MySQL2 (local testing only)
|
413
|
+
- **Rails versions**: 7.2, 8.0
|
502
414
|
|
503
|
-
|
415
|
+
**Note**: CI only tests SQLite3 + PostgreSQL for reliability. MySQL is available for local testing but excluded from CI due to flakiness.
|
504
416
|
|
505
|
-
|
506
|
-
```bash
|
507
|
-
./scripts/setup-git-hooks
|
508
|
-
```
|
509
|
-
This installs a pre-commit hook that runs RuboCop before each commit.
|
417
|
+
### Development Environment Setup
|
510
418
|
|
511
|
-
|
419
|
+
1. **Copy the environment template:**
|
512
420
|
```bash
|
513
421
|
cp .env.example .env
|
514
422
|
```
|
515
423
|
|
516
|
-
|
424
|
+
2. **Configure your database credentials in `.env` (for local multi-database testing):**
|
517
425
|
```bash
|
518
|
-
# PostgreSQL Configuration
|
426
|
+
# PostgreSQL Configuration (used in CI + local)
|
519
427
|
POSTGRES_USERNAME=your_username
|
520
428
|
POSTGRES_PASSWORD=your_password
|
521
429
|
POSTGRES_HOST=localhost
|
522
430
|
POSTGRES_PORT=5432
|
523
431
|
|
524
|
-
# MySQL Configuration
|
432
|
+
# MySQL Configuration (local testing only)
|
525
433
|
MYSQL_USERNAME=root
|
526
434
|
MYSQL_PASSWORD=your_password
|
527
435
|
MYSQL_HOST=localhost
|
528
436
|
MYSQL_PORT=3306
|
529
437
|
```
|
530
438
|
|
531
|
-
|
439
|
+
3. **Create test databases:**
|
532
440
|
```bash
|
533
441
|
# PostgreSQL
|
534
442
|
createdb rails_pulse_test
|
@@ -537,32 +445,32 @@ rails test:matrix_full # Test all databases (SQLite + PostgreSQL + MySQL)
|
|
537
445
|
mysql -u root -p -e "CREATE DATABASE rails_pulse_test;"
|
538
446
|
```
|
539
447
|
|
540
|
-
|
541
|
-
|
448
|
+
### Manual Database Testing
|
449
|
+
|
450
|
+
Test individual databases locally:
|
542
451
|
|
543
452
|
```bash
|
544
|
-
# Test with SQLite (default
|
453
|
+
# Test with SQLite (default)
|
545
454
|
rails test:all
|
546
455
|
|
547
|
-
# Test with PostgreSQL
|
548
|
-
|
456
|
+
# Test with PostgreSQL
|
457
|
+
DB=postgresql FORCE_DB_CONFIG=true rails test:all
|
549
458
|
|
550
|
-
# Test with MySQL (
|
551
|
-
|
459
|
+
# Test with MySQL (local only)
|
460
|
+
DB=mysql2 FORCE_DB_CONFIG=true rails test:all
|
552
461
|
```
|
553
462
|
|
554
|
-
|
463
|
+
### CI Testing
|
555
464
|
|
556
|
-
|
557
|
-
-
|
558
|
-
-
|
559
|
-
-
|
465
|
+
GitHub Actions CI automatically tests:
|
466
|
+
- **Databases**: SQLite3, PostgreSQL only (MySQL excluded for reliability)
|
467
|
+
- **Rails versions**: 7.2, 8.0
|
468
|
+
- **Environment**: Uses memory SQLite and PostgreSQL service
|
560
469
|
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
```
|
470
|
+
**Local vs CI differences**:
|
471
|
+
- **Local**: Can test all 3 databases (SQLite3, PostgreSQL, MySQL2)
|
472
|
+
- **CI**: Only SQLite3 + PostgreSQL for fast, reliable builds
|
473
|
+
- **Database switching**: Requires `FORCE_DB_CONFIG=true` locally
|
566
474
|
|
567
475
|
## Technology Stack
|
568
476
|
|
@@ -602,12 +510,6 @@ Rails Pulse is built using modern, battle-tested technologies that ensure reliab
|
|
602
510
|
- **Customizable**: Full control over metrics, thresholds, and interface
|
603
511
|
- **Asset Independence**: Works with any Rails build system (Sprockets, esbuild, Webpack, Vite)
|
604
512
|
|
605
|
-
### **vs. Built-in Rails Logging**
|
606
|
-
- **Visual Interface**: Beautiful dashboards instead of log parsing
|
607
|
-
- **Structured Data**: Queryable metrics instead of text logs
|
608
|
-
- **Historical Analysis**: Persistent storage with trend analysis
|
609
|
-
- **Real-time Monitoring**: Live updates and health scoring
|
610
|
-
|
611
513
|
### **vs. Custom Monitoring Solutions**
|
612
514
|
- **Batteries Included**: Complete monitoring solution out of the box
|
613
515
|
- **Proven Architecture**: Built on Rails best practices
|
data/Rakefile
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
require "bundler/setup"
|
2
2
|
|
3
|
+
# Load environment variables from .env file
|
4
|
+
require "dotenv/load" if File.exist?(".env")
|
5
|
+
|
3
6
|
APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
|
4
7
|
load "rails/tasks/engine.rake"
|
5
8
|
load "rails/tasks/statistics.rake"
|
@@ -8,9 +11,9 @@ require "bundler/gem_tasks"
|
|
8
11
|
|
9
12
|
# Test tasks
|
10
13
|
namespace :test do
|
11
|
-
desc "Run unit tests (models, helpers, services)"
|
14
|
+
desc "Run unit tests (models, helpers, services, instrumentation)"
|
12
15
|
task :unit do
|
13
|
-
sh "rails test test/models test/helpers test/services test/support"
|
16
|
+
sh "rails test test/models test/helpers test/services test/support test/instrumentation"
|
14
17
|
end
|
15
18
|
|
16
19
|
desc "Run functional tests (controllers)"
|
@@ -27,6 +30,78 @@ namespace :test do
|
|
27
30
|
task :all do
|
28
31
|
sh "rails test"
|
29
32
|
end
|
33
|
+
|
34
|
+
desc "Run tests across all database and Rails version combinations (local only - CI uses sqlite3 + postgresql)"
|
35
|
+
task :matrix do
|
36
|
+
databases = [ "sqlite3", "postgresql", "mysql2" ]
|
37
|
+
rails_versions = [ "rails-7-2", "rails-8-0" ]
|
38
|
+
|
39
|
+
failed_combinations = []
|
40
|
+
|
41
|
+
databases.each do |database|
|
42
|
+
rails_versions.each do |rails_version|
|
43
|
+
puts "\n" + "=" * 80
|
44
|
+
puts "๐งช Local Testing: #{database.upcase} + #{rails_version.upcase}"
|
45
|
+
puts "(CI only tests SQLite3 + PostgreSQL for reliability)"
|
46
|
+
puts "=" * 80
|
47
|
+
|
48
|
+
begin
|
49
|
+
gemfile = "gemfiles/#{rails_version.gsub('-', '_')}.gemfile"
|
50
|
+
|
51
|
+
# Set environment variables
|
52
|
+
env_vars = {
|
53
|
+
"DB" => database,
|
54
|
+
"BUNDLE_GEMFILE" => gemfile,
|
55
|
+
"FORCE_DB_CONFIG" => "true"
|
56
|
+
}
|
57
|
+
|
58
|
+
# Add database-specific environment variables
|
59
|
+
case database
|
60
|
+
when "postgresql"
|
61
|
+
env_vars.merge!({
|
62
|
+
"POSTGRES_USERNAME" => ENV.fetch("POSTGRES_USERNAME", "postgres"),
|
63
|
+
"POSTGRES_PASSWORD" => ENV.fetch("POSTGRES_PASSWORD", ""),
|
64
|
+
"POSTGRES_HOST" => ENV.fetch("POSTGRES_HOST", "localhost"),
|
65
|
+
"POSTGRES_PORT" => ENV.fetch("POSTGRES_PORT", "5432")
|
66
|
+
})
|
67
|
+
when "mysql2"
|
68
|
+
env_vars.merge!({
|
69
|
+
"MYSQL_USERNAME" => ENV.fetch("MYSQL_USERNAME", "root"),
|
70
|
+
"MYSQL_PASSWORD" => ENV.fetch("MYSQL_PASSWORD", "password"),
|
71
|
+
"MYSQL_HOST" => ENV.fetch("MYSQL_HOST", "localhost"),
|
72
|
+
"MYSQL_PORT" => ENV.fetch("MYSQL_PORT", "3306")
|
73
|
+
})
|
74
|
+
end
|
75
|
+
|
76
|
+
# Build environment string
|
77
|
+
env_string = env_vars.map { |k, v| "#{k}=#{v}" }.join(" ")
|
78
|
+
|
79
|
+
# Run the test command
|
80
|
+
sh "#{env_string} bundle exec rails test:all"
|
81
|
+
|
82
|
+
puts "โ
PASSED: #{database} + #{rails_version}"
|
83
|
+
|
84
|
+
rescue => e
|
85
|
+
puts "โ FAILED: #{database} + #{rails_version}"
|
86
|
+
puts "Error: #{e.message}"
|
87
|
+
failed_combinations << "#{database} + #{rails_version}"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
puts "\n" + "=" * 80
|
93
|
+
puts "๐ Local Test Matrix Results"
|
94
|
+
puts "(CI automatically tests SQLite3 + PostgreSQL only)"
|
95
|
+
puts "=" * 80
|
96
|
+
|
97
|
+
if failed_combinations.empty?
|
98
|
+
puts "โ
All combinations passed!"
|
99
|
+
else
|
100
|
+
puts "โ Failed combinations:"
|
101
|
+
failed_combinations.each { |combo| puts " - #{combo}" }
|
102
|
+
exit 1
|
103
|
+
end
|
104
|
+
end
|
30
105
|
end
|
31
106
|
|
32
107
|
# Override default test task
|
Binary file
|
Binary file
|
@@ -4,25 +4,48 @@
|
|
4
4
|
|
5
5
|
a {
|
6
6
|
text-decoration: underline;
|
7
|
-
color:
|
7
|
+
color: var(--color-link);
|
8
8
|
}
|
9
9
|
|
10
10
|
#header {
|
11
|
-
background-color:
|
11
|
+
background-color: var(--header-bg);
|
12
12
|
}
|
13
13
|
|
14
14
|
#header a {
|
15
|
-
color:
|
15
|
+
color: var(--header-link);
|
16
|
+
text-decoration: none;
|
16
17
|
}
|
17
18
|
|
18
19
|
#header a:hover {
|
19
|
-
background-color:
|
20
|
+
background-color: transparent;
|
21
|
+
text-decoration: underline;
|
20
22
|
}
|
21
23
|
|
22
24
|
a:hover {
|
23
25
|
cursor: pointer;
|
24
26
|
}
|
25
27
|
|
28
|
+
/* Dark mode */
|
29
|
+
|
30
|
+
/* Dark scheme tweaks via component variables */
|
31
|
+
html[data-color-scheme="dark"] .card {
|
32
|
+
/* Scope card surfaces slightly darker than page */
|
33
|
+
--color-bg: rgb(47, 47, 47);
|
34
|
+
--color-border: rgb(64, 64, 64);
|
35
|
+
}
|
36
|
+
|
37
|
+
/* Header colors are handled by --header-* tokens in base.css */
|
38
|
+
|
39
|
+
html[data-color-scheme="dark"] .badge--positive-inverse,
|
40
|
+
html[data-color-scheme="dark"] .badge--negative-inverse {
|
41
|
+
--badge-background: rgb(47, 47, 47);
|
42
|
+
}
|
43
|
+
|
44
|
+
html[data-color-scheme="dark"] .input {
|
45
|
+
--input-background: #535252;
|
46
|
+
--input-border-color: #7e7d7d;
|
47
|
+
}
|
48
|
+
|
26
49
|
.hidden {
|
27
50
|
display: none;
|
28
51
|
}
|
@@ -66,7 +89,7 @@ a:hover {
|
|
66
89
|
height: 16px;
|
67
90
|
padding: 2px;
|
68
91
|
position: absolute;
|
69
|
-
top:
|
92
|
+
top: 20px;
|
70
93
|
}
|
71
94
|
|
72
95
|
/* REQUEST OPERATIONS BAR */
|
@@ -80,18 +103,6 @@ a:hover {
|
|
80
103
|
position:absolute;
|
81
104
|
top:0
|
82
105
|
}
|
83
|
-
.bar.db {
|
84
|
-
background-color:#92c282
|
85
|
-
}
|
86
|
-
.bar.app {
|
87
|
-
background-color:#00adc4
|
88
|
-
}
|
89
|
-
.bar.gc {
|
90
|
-
background-color:#323333
|
91
|
-
}
|
92
|
-
.bar.view {
|
93
|
-
background-color:#b48da3
|
94
|
-
}
|
95
106
|
.bar:first-child {
|
96
107
|
border-bottom-left-radius:1px;
|
97
108
|
border-top-left-radius:1px
|