rails_pulse 0.1.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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +638 -0
- data/Rakefile +207 -0
- data/app/assets/images/rails_pulse/dashboard.png +0 -0
- data/app/assets/images/rails_pulse/menu.svg +1 -0
- data/app/assets/images/rails_pulse/rails-pulse-logo.png +0 -0
- data/app/assets/images/rails_pulse/request.png +0 -0
- data/app/assets/images/rails_pulse/routes.png +0 -0
- data/app/assets/stylesheets/rails_pulse/application.css +102 -0
- data/app/assets/stylesheets/rails_pulse/components/alert.css +24 -0
- data/app/assets/stylesheets/rails_pulse/components/badge.css +58 -0
- data/app/assets/stylesheets/rails_pulse/components/base.css +79 -0
- data/app/assets/stylesheets/rails_pulse/components/breadcrumb.css +31 -0
- data/app/assets/stylesheets/rails_pulse/components/button.css +99 -0
- data/app/assets/stylesheets/rails_pulse/components/card.css +19 -0
- data/app/assets/stylesheets/rails_pulse/components/chart.css +18 -0
- data/app/assets/stylesheets/rails_pulse/components/csp_safe_positioning.css +86 -0
- data/app/assets/stylesheets/rails_pulse/components/descriptive_list.css +9 -0
- data/app/assets/stylesheets/rails_pulse/components/dialog.css +56 -0
- data/app/assets/stylesheets/rails_pulse/components/flash.css +47 -0
- data/app/assets/stylesheets/rails_pulse/components/input.css +80 -0
- data/app/assets/stylesheets/rails_pulse/components/layouts.css +63 -0
- data/app/assets/stylesheets/rails_pulse/components/menu.css +43 -0
- data/app/assets/stylesheets/rails_pulse/components/popover.css +36 -0
- data/app/assets/stylesheets/rails_pulse/components/prose.css +144 -0
- data/app/assets/stylesheets/rails_pulse/components/row.css +24 -0
- data/app/assets/stylesheets/rails_pulse/components/sidebar_menu.css +79 -0
- data/app/assets/stylesheets/rails_pulse/components/skeleton.css +5 -0
- data/app/assets/stylesheets/rails_pulse/components/table.css +37 -0
- data/app/assets/stylesheets/rails_pulse/components/utilities.css +36 -0
- data/app/controllers/concerns/chart_table_concern.rb +82 -0
- data/app/controllers/concerns/response_range_concern.rb +24 -0
- data/app/controllers/concerns/time_range_concern.rb +67 -0
- data/app/controllers/concerns/zoom_range_concern.rb +40 -0
- data/app/controllers/rails_pulse/application_controller.rb +67 -0
- data/app/controllers/rails_pulse/assets_controller.rb +33 -0
- data/app/controllers/rails_pulse/caches_controller.rb +115 -0
- data/app/controllers/rails_pulse/csp_test_controller.rb +57 -0
- data/app/controllers/rails_pulse/dashboard_controller.rb +6 -0
- data/app/controllers/rails_pulse/operations_controller.rb +219 -0
- data/app/controllers/rails_pulse/queries_controller.rb +121 -0
- data/app/controllers/rails_pulse/requests_controller.rb +69 -0
- data/app/controllers/rails_pulse/routes_controller.rb +99 -0
- data/app/helpers/rails_pulse/application_helper.rb +111 -0
- data/app/helpers/rails_pulse/breadcrumbs_helper.rb +62 -0
- data/app/helpers/rails_pulse/cached_component_helper.rb +73 -0
- data/app/helpers/rails_pulse/chart_formatters.rb +43 -0
- data/app/helpers/rails_pulse/chart_helper.rb +140 -0
- data/app/helpers/rails_pulse/formatting_helper.rb +29 -0
- data/app/helpers/rails_pulse/status_helper.rb +279 -0
- data/app/helpers/rails_pulse/table_helper.rb +54 -0
- data/app/javascript/rails_pulse/application.js +119 -0
- data/app/javascript/rails_pulse/controllers/color_scheme_controller.js +20 -0
- data/app/javascript/rails_pulse/controllers/context_menu_controller.js +16 -0
- data/app/javascript/rails_pulse/controllers/dialog_controller.js +21 -0
- data/app/javascript/rails_pulse/controllers/expandable_row_controller.js +67 -0
- data/app/javascript/rails_pulse/controllers/form_controller.js +39 -0
- data/app/javascript/rails_pulse/controllers/icon_controller.js +170 -0
- data/app/javascript/rails_pulse/controllers/index_controller.js +230 -0
- data/app/javascript/rails_pulse/controllers/menu_controller.js +60 -0
- data/app/javascript/rails_pulse/controllers/pagination_controller.js +69 -0
- data/app/javascript/rails_pulse/controllers/popover_controller.js +91 -0
- data/app/javascript/rails_pulse/controllers/timezone_controller.js +106 -0
- data/app/javascript/rails_pulse/theme.js +416 -0
- data/app/jobs/rails_pulse/application_job.rb +4 -0
- data/app/jobs/rails_pulse/cleanup_job.rb +21 -0
- data/app/mailers/rails_pulse/application_mailer.rb +6 -0
- data/app/models/rails_pulse/application_record.rb +7 -0
- data/app/models/rails_pulse/component_cache_key.rb +33 -0
- data/app/models/rails_pulse/dashboard/charts/average_response_time.rb +27 -0
- data/app/models/rails_pulse/dashboard/charts/p95_response_time.rb +37 -0
- data/app/models/rails_pulse/dashboard/tables/slow_queries.rb +59 -0
- data/app/models/rails_pulse/dashboard/tables/slow_routes.rb +45 -0
- data/app/models/rails_pulse/operation.rb +87 -0
- data/app/models/rails_pulse/queries/cards/average_query_times.rb +52 -0
- data/app/models/rails_pulse/queries/cards/execution_rate.rb +57 -0
- data/app/models/rails_pulse/queries/cards/percentile_query_times.rb +71 -0
- data/app/models/rails_pulse/queries/charts/average_query_times.rb +112 -0
- data/app/models/rails_pulse/query.rb +58 -0
- data/app/models/rails_pulse/request.rb +64 -0
- data/app/models/rails_pulse/requests/charts/average_response_times.rb +99 -0
- data/app/models/rails_pulse/requests/charts/operations_chart.rb +35 -0
- data/app/models/rails_pulse/route.rb +77 -0
- data/app/models/rails_pulse/routes/cards/average_response_times.rb +54 -0
- data/app/models/rails_pulse/routes/cards/error_rate_per_route.rb +73 -0
- data/app/models/rails_pulse/routes/cards/percentile_response_times.rb +73 -0
- data/app/models/rails_pulse/routes/cards/request_count_totals.rb +59 -0
- data/app/models/rails_pulse/routes/charts/average_response_times.rb +115 -0
- data/app/models/rails_pulse/routes/tables/index.rb +63 -0
- data/app/services/rails_pulse/sql_query_normalizer.rb +124 -0
- data/app/views/layouts/rails_pulse/_menu_items.html.erb +19 -0
- data/app/views/layouts/rails_pulse/_sidebar_menu.html.erb +44 -0
- data/app/views/layouts/rails_pulse/application.html.erb +72 -0
- data/app/views/rails_pulse/caches/show.html.erb +9 -0
- data/app/views/rails_pulse/components/_breadcrumbs.html.erb +12 -0
- data/app/views/rails_pulse/components/_code_panel.html.erb +12 -0
- data/app/views/rails_pulse/components/_metric_card.html.erb +55 -0
- data/app/views/rails_pulse/components/_metric_row.html.erb +9 -0
- data/app/views/rails_pulse/components/_operation_details_popover.html.erb +241 -0
- data/app/views/rails_pulse/components/_panel.html.erb +56 -0
- data/app/views/rails_pulse/components/_sparkline_stats.html.erb +15 -0
- data/app/views/rails_pulse/components/_table.html.erb +50 -0
- data/app/views/rails_pulse/components/_table_head.html.erb +20 -0
- data/app/views/rails_pulse/components/_table_pagination.html.erb +45 -0
- data/app/views/rails_pulse/components/_time_period.html.erb +16 -0
- data/app/views/rails_pulse/csp_test/show.html.erb +207 -0
- data/app/views/rails_pulse/dashboard/charts/_bar_chart.html.erb +1 -0
- data/app/views/rails_pulse/dashboard/index.html.erb +64 -0
- data/app/views/rails_pulse/dashboard/tables/_routes_table.html.erb +32 -0
- data/app/views/rails_pulse/dashboard/tables/_standard_table.html.erb +1 -0
- data/app/views/rails_pulse/operations/_operation_analysis_application.html.erb +43 -0
- data/app/views/rails_pulse/operations/_operation_analysis_database.html.erb +12 -0
- data/app/views/rails_pulse/operations/_operation_analysis_generic.html.erb +15 -0
- data/app/views/rails_pulse/operations/_operation_analysis_other.html.erb +69 -0
- data/app/views/rails_pulse/operations/_operation_analysis_view.html.erb +39 -0
- data/app/views/rails_pulse/operations/show.html.erb +79 -0
- data/app/views/rails_pulse/queries/_show_table.html.erb +19 -0
- data/app/views/rails_pulse/queries/_table.html.erb +31 -0
- data/app/views/rails_pulse/queries/index.html.erb +64 -0
- data/app/views/rails_pulse/queries/show.html.erb +86 -0
- data/app/views/rails_pulse/requests/_operations.html.erb +85 -0
- data/app/views/rails_pulse/requests/_table.html.erb +31 -0
- data/app/views/rails_pulse/requests/index.html.erb +64 -0
- data/app/views/rails_pulse/requests/show.html.erb +44 -0
- data/app/views/rails_pulse/routes/_table.html.erb +29 -0
- data/app/views/rails_pulse/routes/index.html.erb +65 -0
- data/app/views/rails_pulse/routes/show.html.erb +67 -0
- data/app/views/rails_pulse/skeletons/_chart.html.erb +3 -0
- data/app/views/rails_pulse/skeletons/_metric_card.html.erb +20 -0
- data/app/views/rails_pulse/skeletons/_panel.html.erb +19 -0
- data/app/views/rails_pulse/skeletons/_table.html.erb +8 -0
- data/config/importmap.rb +12 -0
- data/config/initializers/rails_charts_csp_patch.rb +83 -0
- data/config/initializers/rails_pulse.rb +198 -0
- data/config/routes.rb +16 -0
- data/db/migrate/20250227235904_create_routes.rb +12 -0
- data/db/migrate/20250227235915_create_requests.rb +19 -0
- data/db/migrate/20250228000000_create_queries.rb +14 -0
- data/db/migrate/20250228000056_create_operations.rb +24 -0
- data/lib/generators/rails_pulse/install_generator.rb +17 -0
- data/lib/generators/rails_pulse/templates/rails_pulse.rb +198 -0
- data/lib/rails_pulse/cleanup_service.rb +212 -0
- data/lib/rails_pulse/configuration.rb +176 -0
- data/lib/rails_pulse/engine.rb +88 -0
- data/lib/rails_pulse/middleware/asset_server.rb +84 -0
- data/lib/rails_pulse/middleware/request_collector.rb +120 -0
- data/lib/rails_pulse/migration.rb +29 -0
- data/lib/rails_pulse/subscribers/operation_subscriber.rb +280 -0
- data/lib/rails_pulse/version.rb +3 -0
- data/lib/rails_pulse.rb +38 -0
- data/lib/tasks/rails_pulse_tasks.rake +138 -0
- data/public/rails-pulse-assets/csp-test.js +110 -0
- data/public/rails-pulse-assets/rails-pulse-icons.js +89 -0
- data/public/rails-pulse-assets/rails-pulse-icons.js.map +13 -0
- data/public/rails-pulse-assets/rails-pulse.css +1 -0
- data/public/rails-pulse-assets/rails-pulse.css.map +1 -0
- data/public/rails-pulse-assets/rails-pulse.js +183 -0
- data/public/rails-pulse-assets/rails-pulse.js.map +7 -0
- metadata +339 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 418546b7a8b0324941402583074cd0a569d51ef4b8e4b0d02261957d16c6d2ab
|
4
|
+
data.tar.gz: 7d027dafdf22c964a503a4a8e66d6d7c0e7af8f3d299c3acd2c65b2a1bd63705
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 331a413a83ab2c81f43ee796676eb127dd0541f14912bba66982142ac3cfe5d2276e9c0aecd67aeb11e2219ffe66ad3f1f8c0791e7b68e5f1bba5f517072cdd6
|
7
|
+
data.tar.gz: 6d1885f4af1c42bef1caac9044aa72b514de7669536e4bf7f58b23e63ebbbddd32040106b72424d61bc7e7068241d0de1ce68816d6fe9b368e4279b4f62e6adf
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright Rails Pulse
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,638 @@
|
|
1
|
+
<div align="center">
|
2
|
+
<img src="app/assets/images/rails_pulse/rails-pulse-logo.png" alt="Rails Pulse" width="200" />
|
3
|
+
|
4
|
+
# Rails Pulse
|
5
|
+
|
6
|
+
**Real-time performance monitoring and debugging for Rails applications**
|
7
|
+
|
8
|
+

|
9
|
+

|
10
|
+

|
11
|
+

|
12
|
+
</div>
|
13
|
+
|
14
|
+
---
|
15
|
+
|
16
|
+
## Table of Contents
|
17
|
+
|
18
|
+
- [Introduction](#introduction)
|
19
|
+
- [Features](#features)
|
20
|
+
- [Screenshots](#screenshots)
|
21
|
+
- [Getting Started](#getting-started)
|
22
|
+
- [Installation](#installation)
|
23
|
+
- [Quick Setup](#quick-setup)
|
24
|
+
- [Basic Configuration](#basic-configuration)
|
25
|
+
- [Authentication](#authentication)
|
26
|
+
- [Authentication Setup](#authentication-setup)
|
27
|
+
- [Authentication Examples](#authentication-examples)
|
28
|
+
- [Security Considerations](#security-considerations)
|
29
|
+
- [Data Management](#data-management)
|
30
|
+
- [Cleanup Strategies](#cleanup-strategies)
|
31
|
+
- [Cleanup Configuration](#cleanup-configuration)
|
32
|
+
- [Manual Cleanup Operations](#manual-cleanup-operations)
|
33
|
+
- [How Cleanup Works](#how-cleanup-works)
|
34
|
+
- [Multiple Database Support](#multiple-database-support)
|
35
|
+
- [Configuration](#configuration)
|
36
|
+
- [Database Configuration](#database-configuration)
|
37
|
+
- [Migration](#migration)
|
38
|
+
- [Testing](#testing)
|
39
|
+
- [Technology Stack](#technology-stack)
|
40
|
+
- [Advantages Over Other Solutions](#advantages-over-other-solutions)
|
41
|
+
- [License](#license)
|
42
|
+
|
43
|
+
---
|
44
|
+
|
45
|
+
## Introduction
|
46
|
+
|
47
|
+
Rails Pulse is a comprehensive performance monitoring and debugging gem that provides real-time 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.
|
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
|
58
|
+
|
59
|
+
## Features
|
60
|
+
|
61
|
+
### 🎯 **Performance Monitoring**
|
62
|
+
- Interactive dashboard with response time charts and request analytics
|
63
|
+
- SQL query performance tracking with slow query identification
|
64
|
+
- Route-specific metrics with configurable performance thresholds
|
65
|
+
- Week-over-week trend analysis with visual indicators
|
66
|
+
|
67
|
+
### 🔒 **Production Ready**
|
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**
|
74
|
+
- Zero configuration setup with sensible defaults
|
75
|
+
- Beautiful responsive interface with dark/light mode
|
76
|
+
- Smart caching with minimal performance overhead
|
77
|
+
- Multiple database support (SQLite, PostgreSQL, MySQL)
|
78
|
+
|
79
|
+
## Screenshots
|
80
|
+
|
81
|
+
<img src="app/assets/images/rails_pulse/dashboard.png" alt="Rails Pulse" />
|
82
|
+
|
83
|
+
## Getting Started
|
84
|
+
|
85
|
+
### Installation
|
86
|
+
|
87
|
+
Add Rails Pulse to your application's Gemfile:
|
88
|
+
|
89
|
+
```ruby
|
90
|
+
gem 'rails_pulse'
|
91
|
+
```
|
92
|
+
|
93
|
+
Install the gem:
|
94
|
+
|
95
|
+
```bash
|
96
|
+
bundle install
|
97
|
+
```
|
98
|
+
|
99
|
+
Generate the installation files:
|
100
|
+
|
101
|
+
```bash
|
102
|
+
rails generate rails_pulse:install
|
103
|
+
```
|
104
|
+
|
105
|
+
Run the migrations:
|
106
|
+
|
107
|
+
```bash
|
108
|
+
rails db:migrate
|
109
|
+
```
|
110
|
+
|
111
|
+
Add the Rails Pulse route to your application:
|
112
|
+
|
113
|
+
```ruby
|
114
|
+
# config/routes.rb
|
115
|
+
Rails.application.routes.draw do
|
116
|
+
mount RailsPulse::Engine => "/rails_pulse"
|
117
|
+
# ... your other routes
|
118
|
+
end
|
119
|
+
```
|
120
|
+
|
121
|
+
### Quick Setup
|
122
|
+
|
123
|
+
Rails Pulse automatically starts collecting performance data once installed. Access your monitoring dashboard at:
|
124
|
+
|
125
|
+
```
|
126
|
+
http://localhost:3000/rails_pulse
|
127
|
+
```
|
128
|
+
|
129
|
+
### Basic Configuration
|
130
|
+
|
131
|
+
Customize Rails Pulse in `config/initializers/rails_pulse.rb`:
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
RailsPulse.configure do |config|
|
135
|
+
# Enable or disable Rails Pulse
|
136
|
+
config.enabled = true
|
137
|
+
|
138
|
+
# Set performance thresholds for routes (in milliseconds)
|
139
|
+
config.route_thresholds = {
|
140
|
+
slow: 500,
|
141
|
+
very_slow: 1500,
|
142
|
+
critical: 3000
|
143
|
+
}
|
144
|
+
|
145
|
+
# Set performance thresholds for requests (in milliseconds)
|
146
|
+
config.request_thresholds = {
|
147
|
+
slow: 700,
|
148
|
+
very_slow: 2000,
|
149
|
+
critical: 4000
|
150
|
+
}
|
151
|
+
|
152
|
+
# Set performance thresholds for database queries (in milliseconds)
|
153
|
+
config.query_thresholds = {
|
154
|
+
slow: 100,
|
155
|
+
very_slow: 500,
|
156
|
+
critical: 1000
|
157
|
+
}
|
158
|
+
|
159
|
+
# Asset tracking configuration
|
160
|
+
config.track_assets = false # Ignore asset requests by default
|
161
|
+
config.custom_asset_patterns = [] # Additional asset patterns to ignore
|
162
|
+
|
163
|
+
# Rails Pulse mount path (optional)
|
164
|
+
# Specify if Rails Pulse is mounted at a custom path to prevent self-tracking
|
165
|
+
config.mount_path = nil # e.g., "/admin/monitoring"
|
166
|
+
|
167
|
+
# Route filtering - ignore specific routes from performance tracking
|
168
|
+
config.ignored_routes = [] # Array of strings or regex patterns
|
169
|
+
config.ignored_requests = [] # Array of request patterns to ignore
|
170
|
+
config.ignored_queries = [] # Array of query patterns to ignore
|
171
|
+
|
172
|
+
# Data cleanup
|
173
|
+
config.archiving_enabled = true # Enable automatic cleanup
|
174
|
+
config.full_retention_period = 2.weeks # Delete records older than this
|
175
|
+
config.max_table_records = { # Maximum records per table
|
176
|
+
rails_pulse_requests: 10000,
|
177
|
+
rails_pulse_operations: 50000,
|
178
|
+
rails_pulse_routes: 1000,
|
179
|
+
rails_pulse_queries: 500
|
180
|
+
}
|
181
|
+
|
182
|
+
# Metric caching for performance
|
183
|
+
config.component_cache_enabled = true
|
184
|
+
config.component_cache_duration = 1.day
|
185
|
+
|
186
|
+
# Multiple database support (optional)
|
187
|
+
# Uncomment to store Rails Pulse data in a separate database
|
188
|
+
# config.connects_to = {
|
189
|
+
# database: { writing: :rails_pulse, reading: :rails_pulse }
|
190
|
+
# }
|
191
|
+
end
|
192
|
+
```
|
193
|
+
|
194
|
+
## Authentication
|
195
|
+
|
196
|
+
Rails Pulse supports flexible authentication to secure access to your monitoring dashboard.
|
197
|
+
|
198
|
+
### Authentication Setup
|
199
|
+
|
200
|
+
Enable authentication by configuring the following options in your Rails Pulse initializer:
|
201
|
+
|
202
|
+
```ruby
|
203
|
+
# config/initializers/rails_pulse.rb
|
204
|
+
RailsPulse.configure do |config|
|
205
|
+
# Enable authentication
|
206
|
+
config.authentication_enabled = true
|
207
|
+
|
208
|
+
# Where to redirect unauthorized users (optional, defaults to "/")
|
209
|
+
config.authentication_redirect_path = "/login"
|
210
|
+
|
211
|
+
# Define your authentication logic
|
212
|
+
config.authentication_method = proc {
|
213
|
+
# Your authentication logic here
|
214
|
+
}
|
215
|
+
end
|
216
|
+
```
|
217
|
+
|
218
|
+
### Authentication Examples
|
219
|
+
|
220
|
+
Rails Pulse works with any authentication system. Here are common patterns:
|
221
|
+
|
222
|
+
#### **Devise with Admin Role**
|
223
|
+
|
224
|
+
```ruby
|
225
|
+
config.authentication_method = proc {
|
226
|
+
unless user_signed_in? && current_user.admin?
|
227
|
+
redirect_to main_app.root_path, alert: "Access denied"
|
228
|
+
end
|
229
|
+
}
|
230
|
+
```
|
231
|
+
|
232
|
+
#### **Custom Session-based Authentication**
|
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**
|
262
|
+
|
263
|
+
```ruby
|
264
|
+
config.authentication_method = proc {
|
265
|
+
current_user = User.find_by(id: session[:user_id])
|
266
|
+
unless current_user&.can_access_monitoring?
|
267
|
+
render plain: "Forbidden", status: :forbidden
|
268
|
+
end
|
269
|
+
}
|
270
|
+
```
|
271
|
+
|
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
|
+
## Data Management
|
283
|
+
|
284
|
+
Rails Pulse provides data cleanup to prevent your monitoring database from growing indefinitely while preserving essential performance insights.
|
285
|
+
|
286
|
+
### Cleanup Strategies
|
287
|
+
|
288
|
+
**Time-based Cleanup**
|
289
|
+
- Automatically delete performance records older than a specified period
|
290
|
+
- Configurable retention period (default: 2 days)
|
291
|
+
- Keeps recent data for debugging while removing historical noise
|
292
|
+
|
293
|
+
**Count-based Cleanup**
|
294
|
+
- Enforce maximum record limits per table
|
295
|
+
- Prevents any single table from consuming excessive storage
|
296
|
+
- Configurable limits for each Rails Pulse table
|
297
|
+
|
298
|
+
### Cleanup Configuration
|
299
|
+
|
300
|
+
```ruby
|
301
|
+
RailsPulse.configure do |config|
|
302
|
+
# Enable or disable automatic cleanup
|
303
|
+
config.archiving_enabled = true
|
304
|
+
|
305
|
+
# Time-based retention
|
306
|
+
config.full_retention_period = 2.weeks
|
307
|
+
|
308
|
+
# Count-based retention - maximum records per table
|
309
|
+
config.max_table_records = {
|
310
|
+
rails_pulse_requests: 10000, # HTTP requests
|
311
|
+
rails_pulse_operations: 50000, # Operations within requests
|
312
|
+
rails_pulse_routes: 1000, # Unique routes
|
313
|
+
rails_pulse_queries: 500 # Normalized SQL queries
|
314
|
+
}
|
315
|
+
end
|
316
|
+
```
|
317
|
+
|
318
|
+
### Manual Cleanup Operations
|
319
|
+
|
320
|
+
**Run cleanup manually:**
|
321
|
+
```bash
|
322
|
+
rails rails_pulse:cleanup
|
323
|
+
```
|
324
|
+
|
325
|
+
**Check current database status:**
|
326
|
+
```bash
|
327
|
+
rails rails_pulse:cleanup_stats
|
328
|
+
```
|
329
|
+
|
330
|
+
**Schedule automated cleanup:**
|
331
|
+
```ruby
|
332
|
+
# Using whenever gem or similar scheduler
|
333
|
+
RailsPulse::CleanupJob.perform_later
|
334
|
+
```
|
335
|
+
|
336
|
+
### How Cleanup Works
|
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
|
342
|
+
|
343
|
+
This two-phase approach ensures you keep the most valuable recent performance data while maintaining manageable database sizes.
|
344
|
+
|
345
|
+
## Multiple Database Support
|
346
|
+
|
347
|
+
Rails Pulse supports storing performance monitoring data in a separate database. This is particularly useful for:
|
348
|
+
|
349
|
+
- **Isolating monitoring data** from your main application database
|
350
|
+
- **Using different database engines** optimized for time-series data
|
351
|
+
- **Scaling monitoring independently** from your application
|
352
|
+
- **Simplified backup strategies** with separate retention policies
|
353
|
+
|
354
|
+
### Configuration
|
355
|
+
|
356
|
+
To use a separate database, configure the `connects_to` option in your Rails Pulse initializer:
|
357
|
+
|
358
|
+
```ruby
|
359
|
+
RailsPulse.configure do |config|
|
360
|
+
# Single separate database
|
361
|
+
config.connects_to = {
|
362
|
+
database: { writing: :rails_pulse, reading: :rails_pulse }
|
363
|
+
}
|
364
|
+
|
365
|
+
# Or primary/replica configuration
|
366
|
+
config.connects_to = {
|
367
|
+
database: { writing: :rails_pulse_primary, reading: :rails_pulse_replica }
|
368
|
+
}
|
369
|
+
end
|
370
|
+
```
|
371
|
+
|
372
|
+
### Database Configuration
|
373
|
+
|
374
|
+
Add the corresponding database configurations to your `config/database.yml`:
|
375
|
+
|
376
|
+
```yaml
|
377
|
+
# For SQLite
|
378
|
+
production:
|
379
|
+
# ... your main database ...
|
380
|
+
rails_pulse:
|
381
|
+
adapter: sqlite3
|
382
|
+
database: storage/rails_pulse_production.sqlite3
|
383
|
+
pool: 5
|
384
|
+
timeout: 5000
|
385
|
+
|
386
|
+
# For PostgreSQL
|
387
|
+
production:
|
388
|
+
# ... your main database ...
|
389
|
+
rails_pulse:
|
390
|
+
adapter: postgresql
|
391
|
+
database: myapp_rails_pulse_production
|
392
|
+
username: rails_pulse_user
|
393
|
+
password: <%= Rails.application.credentials.dig(:rails_pulse, :database_password) %>
|
394
|
+
host: localhost
|
395
|
+
pool: 5
|
396
|
+
|
397
|
+
# For MySQL
|
398
|
+
production:
|
399
|
+
# ... your main database ...
|
400
|
+
rails_pulse:
|
401
|
+
adapter: mysql2
|
402
|
+
database: myapp_rails_pulse_production
|
403
|
+
username: rails_pulse_user
|
404
|
+
password: <%= Rails.application.credentials.dig(:rails_pulse, :database_password) %>
|
405
|
+
host: localhost
|
406
|
+
pool: 5
|
407
|
+
```
|
408
|
+
|
409
|
+
### Migration
|
410
|
+
|
411
|
+
When using a separate database, run migrations targeting the Rails Pulse database:
|
412
|
+
|
413
|
+
```bash
|
414
|
+
# Run Rails Pulse migrations on the configured database
|
415
|
+
rails db:migrate
|
416
|
+
|
417
|
+
# If you need to run migrations on a specific database
|
418
|
+
RAILS_ENV=production rails db:migrate
|
419
|
+
```
|
420
|
+
|
421
|
+
**Note:** Rails Pulse maintains full backward compatibility. If no `connects_to` configuration is provided, all data will be stored in your main application database as before.
|
422
|
+
|
423
|
+
## Testing
|
424
|
+
|
425
|
+
Rails Pulse includes a comprehensive test suite designed for speed and reliability across multiple databases (SQLite, MySQL, PostgreSQL) and Rails versions.
|
426
|
+
|
427
|
+
### Running the Complete Test Suite
|
428
|
+
|
429
|
+
```bash
|
430
|
+
# Run all tests (unit, functional, integration)
|
431
|
+
rails test:all
|
432
|
+
|
433
|
+
# Run tests with speed optimizations
|
434
|
+
rails test:fast
|
435
|
+
```
|
436
|
+
|
437
|
+
### Running Individual Test Types
|
438
|
+
|
439
|
+
```bash
|
440
|
+
# Unit tests (models, helpers, utilities)
|
441
|
+
rails test:unit
|
442
|
+
|
443
|
+
# Functional tests (controllers, views)
|
444
|
+
rails test:functional
|
445
|
+
|
446
|
+
# Integration tests (end-to-end workflows)
|
447
|
+
rails test:integration
|
448
|
+
```
|
449
|
+
|
450
|
+
### Running Individual Test Files
|
451
|
+
|
452
|
+
```bash
|
453
|
+
# Run a specific test file
|
454
|
+
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
|
+
```
|
465
|
+
|
466
|
+
### Multi-Rails Version Testing
|
467
|
+
|
468
|
+
Test against multiple Rails versions using Appraisal:
|
469
|
+
|
470
|
+
```bash
|
471
|
+
# Install dependencies for all Rails versions
|
472
|
+
bundle exec appraisal install
|
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
|
479
|
+
```
|
480
|
+
|
481
|
+
### Test Performance Features
|
482
|
+
|
483
|
+
- **In-memory SQLite**: Unit and functional tests use fast in-memory databases
|
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
|
+
```
|
502
|
+
|
503
|
+
#### Development Environment Setup
|
504
|
+
|
505
|
+
1. **Set up git hooks (optional but recommended):**
|
506
|
+
```bash
|
507
|
+
./scripts/setup-git-hooks
|
508
|
+
```
|
509
|
+
This installs a pre-commit hook that runs RuboCop before each commit.
|
510
|
+
|
511
|
+
2. **Copy the environment template:**
|
512
|
+
```bash
|
513
|
+
cp .env.example .env
|
514
|
+
```
|
515
|
+
|
516
|
+
3. **Configure your database credentials in `.env`:**
|
517
|
+
```bash
|
518
|
+
# PostgreSQL Configuration
|
519
|
+
POSTGRES_USERNAME=your_username
|
520
|
+
POSTGRES_PASSWORD=your_password
|
521
|
+
POSTGRES_HOST=localhost
|
522
|
+
POSTGRES_PORT=5432
|
523
|
+
|
524
|
+
# MySQL Configuration
|
525
|
+
MYSQL_USERNAME=root
|
526
|
+
MYSQL_PASSWORD=your_password
|
527
|
+
MYSQL_HOST=localhost
|
528
|
+
MYSQL_PORT=3306
|
529
|
+
```
|
530
|
+
|
531
|
+
4. **Create test databases:**
|
532
|
+
```bash
|
533
|
+
# PostgreSQL
|
534
|
+
createdb rails_pulse_test
|
535
|
+
|
536
|
+
# MySQL
|
537
|
+
mysql -u root -p -e "CREATE DATABASE rails_pulse_test;"
|
538
|
+
```
|
539
|
+
|
540
|
+
#### Manual Commands
|
541
|
+
If you prefer the explicit approach:
|
542
|
+
|
543
|
+
```bash
|
544
|
+
# Test with SQLite (default, uses in-memory database)
|
545
|
+
rails test:all
|
546
|
+
|
547
|
+
# Test with PostgreSQL (requires local PostgreSQL setup)
|
548
|
+
DATABASE_ADAPTER=postgresql FORCE_DB_CONFIG=true rails test:all
|
549
|
+
|
550
|
+
# Test with MySQL (requires MySQL setup and mysql2 gem compilation)
|
551
|
+
DATABASE_ADAPTER=mysql FORCE_DB_CONFIG=true rails test:all
|
552
|
+
```
|
553
|
+
|
554
|
+
**Note**: Database switching is disabled by default for stability. The Rake tasks automatically handle the `FORCE_DB_CONFIG=true` requirement.
|
555
|
+
|
556
|
+
**MySQL Testing**: MySQL testing requires:
|
557
|
+
- MySQL server running locally with a `rails_pulse_test` database
|
558
|
+
- Successful compilation of the `mysql2` gem (may require system dependencies like `zstd`)
|
559
|
+
- CI environments come pre-configured, but local setup may require additional dependencies
|
560
|
+
|
561
|
+
### Quick Testing Before Push
|
562
|
+
```bash
|
563
|
+
# Recommended: Test the same databases as CI
|
564
|
+
rails test:matrix
|
565
|
+
```
|
566
|
+
|
567
|
+
## Technology Stack
|
568
|
+
|
569
|
+
Rails Pulse is built using modern, battle-tested technologies that ensure reliability, performance, and maintainability:
|
570
|
+
|
571
|
+
### **Frontend Technologies**
|
572
|
+
- **[CSS Zero](https://github.com/lazaronixon/css-zero)** - Modern utility-first CSS framework bundled for asset independence
|
573
|
+
- **[Stimulus](https://stimulus.hotwired.dev/)** - Progressive JavaScript framework for enhanced interactivity
|
574
|
+
- **[Turbo](https://turbo.hotwired.dev/)** - Fast navigation and real-time updates without full page reloads
|
575
|
+
- **[Turbo Frames](https://turbo.hotwired.dev/handbook/frames)** - Lazy loading and partial page updates for optimal performance
|
576
|
+
|
577
|
+
### **Data Visualization**
|
578
|
+
- **[Rails Charts](https://github.com/railsjazz/rails_charts)** - Rails wrapper around Apache ECharts
|
579
|
+
- **[Lucide Icons](https://lucide.dev/)** - Beautiful, consistent iconography with pre-compiled SVG bundle
|
580
|
+
|
581
|
+
### **Asset Management**
|
582
|
+
- **Pre-compiled Assets** - All CSS, JavaScript, and icons bundled into the gem
|
583
|
+
- **CSP-Safe Implementation** - Secure DOM methods and nonce-based asset loading
|
584
|
+
- **Build System** - Node.js-based build process for asset compilation
|
585
|
+
- **Zero External Dependencies** - Self-contained assets work with any Rails build system
|
586
|
+
|
587
|
+
### **Performance & Optimization**
|
588
|
+
- **[Request Store](https://github.com/steveklabnik/request_store)** - Thread-safe request-scoped storage for performance data
|
589
|
+
- **[Rails Caching](https://guides.rubyonrails.org/caching_with_rails.html)** - Fragment caching with smart invalidation strategies
|
590
|
+
- **[ActiveRecord Instrumentation](https://guides.rubyonrails.org/active_support_instrumentation.html)** - Built-in Rails performance monitoring hooks
|
591
|
+
|
592
|
+
### **Development & Testing**
|
593
|
+
- **[Rails Generators](https://guides.rubyonrails.org/generators.html)** - Automated installation and configuration
|
594
|
+
- **[Omakase Ruby Styling](https://github.com/rails/rubocop-rails-omakase)** - Consistent code formatting and style
|
595
|
+
|
596
|
+
## Advantages Over Other Solutions
|
597
|
+
|
598
|
+
### **vs. Application Performance Monitoring (APM) Services**
|
599
|
+
- **No External Dependencies**: Everything runs in your Rails application with pre-compiled assets
|
600
|
+
- **Zero Monthly Costs**: No subscription fees or usage-based pricing
|
601
|
+
- **Data Privacy**: All performance data stays in your database(s)
|
602
|
+
- **Customizable**: Full control over metrics, thresholds, and interface
|
603
|
+
- **Asset Independence**: Works with any Rails build system (Sprockets, esbuild, Webpack, Vite)
|
604
|
+
|
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
|
+
### **vs. Custom Monitoring Solutions**
|
612
|
+
- **Batteries Included**: Complete monitoring solution out of the box
|
613
|
+
- **Proven Architecture**: Built on Rails best practices
|
614
|
+
- **Community Driven**: Open source with active development
|
615
|
+
- **Professional Design**: Production-ready interface
|
616
|
+
|
617
|
+
### **Key Differentiators**
|
618
|
+
- **Rails-Native**: Designed specifically for Rails applications
|
619
|
+
- **Developer Experience**: Optimized for debugging and development
|
620
|
+
- **Positive Focus**: Celebrates good performance alongside problem identification
|
621
|
+
- **Contextual Insights**: Deep Rails framework integration for meaningful metrics
|
622
|
+
- **Security First**: CSP-compliant by default with secure asset handling
|
623
|
+
- **Zero Build Dependencies**: Pre-compiled assets work with any Rails setup
|
624
|
+
- **Flexible Data Storage**: Support for multiple database backends (SQLite, PostgreSQL, MySQL)
|
625
|
+
|
626
|
+
## License
|
627
|
+
|
628
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
629
|
+
|
630
|
+
---
|
631
|
+
|
632
|
+
<div align="center">
|
633
|
+
<strong>Built with ❤️ for the Rails community</strong>
|
634
|
+
|
635
|
+
[Documentation](https://github.com/scottharvey/rails_pulse/wiki) •
|
636
|
+
[Issues](https://github.com/scottharvey/rails_pulse/issues) •
|
637
|
+
[Contributing](CONTRIBUTING.md)
|
638
|
+
</div>
|