rails_pulse 0.3.0.pre.2 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +46 -813
- data/Rakefile +1 -1
- data/app/assets/images/rails_pulse/dashboard.png +0 -0
- data/app/assets/images/rails_pulse/query-show.png +0 -0
- data/app/assets/images/rails_pulse/request-show.png +0 -0
- data/app/assets/images/rails_pulse/route-show.png +0 -0
- data/app/controllers/rails_pulse/requests_controller.rb +1 -1
- data/db/rails_pulse_migrate/{20260420000001_expand_normalized_sql_column.rb → 20260420000001_expand_normalized_query_column.rb} +1 -1
- data/lib/generators/rails_pulse/templates/db/rails_pulse_schema.rb +8 -3
- data/lib/rails_pulse/version.rb +1 -1
- data/lib/rails_pulse.rb +5 -1
- metadata +15 -10
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bc7710c1fd792d4caca32fe285af8c8d9c11f53cd5e31ba177e061d44f92600e
|
|
4
|
+
data.tar.gz: 483b8c6a00e0e24d2331895299dfdee8629bc44c39a5717697d1914317da39f4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 79604b447464e692b6640be70cba507516481d1633e2ff556171c0e55a55fc6cc6d4077b1018bf567d2a72ec4b312fdcd05e575dfc6b5cc76635363b37655266
|
|
7
|
+
data.tar.gz: ffdc4668b94956f68697b9339aa1de8a2065f99e9346e8fa1e93e97d3e12adf0dc32cf4fc5b8ddc8a7bbe24d44392ec6d03f69060f6574d5bb05e2eda6285915
|
data/README.md
CHANGED
|
@@ -1,133 +1,49 @@
|
|
|
1
1
|
<div align="center">
|
|
2
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
3
|
</div>
|
|
13
4
|
|
|
14
5
|
---
|
|
15
6
|
|
|
16
|
-
|
|
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
|
-
- [Background Job Monitoring](#background-job-monitoring)
|
|
26
|
-
- [Overview](#overview)
|
|
27
|
-
- [Supported Adapters](#supported-adapters)
|
|
28
|
-
- [Job Tracking Configuration](#job-tracking-configuration)
|
|
29
|
-
- [Privacy & Security](#privacy--security)
|
|
30
|
-
- [Authentication](#authentication)
|
|
31
|
-
- [Authentication Setup](#authentication-setup)
|
|
32
|
-
- [Authentication Examples](#authentication-examples)
|
|
33
|
-
- [Tagging System](#tagging-system)
|
|
34
|
-
- [Configuring Tags](#configuring-tags)
|
|
35
|
-
- [Using Tags](#using-tags)
|
|
36
|
-
- [Filtering by Tags](#filtering-by-tags)
|
|
37
|
-
- [Data Management](#data-management)
|
|
38
|
-
- [Cleanup Strategies](#cleanup-strategies)
|
|
39
|
-
- [Cleanup Configuration](#cleanup-configuration)
|
|
40
|
-
- [Manual Cleanup Operations](#manual-cleanup-operations)
|
|
41
|
-
- [Separate Database Support](#separate-database-support)
|
|
42
|
-
- [Configuration](#configuration)
|
|
43
|
-
- [Database Configuration](#database-configuration)
|
|
44
|
-
- [Schema Loading](#schema-loading)
|
|
45
|
-
- [Performance Impact](#performance-impact)
|
|
46
|
-
- [Standalone Dashboard Deployment](#standalone-dashboard-deployment)
|
|
47
|
-
- [Testing](#testing)
|
|
48
|
-
- [Technology Stack](#technology-stack)
|
|
49
|
-
- [Advantages Over Other Solutions](#advantages-over-other-solutions)
|
|
50
|
-
- [License](#license)
|
|
7
|
+
# Rails Pulse
|
|
51
8
|
|
|
52
|
-
|
|
9
|
+
**Self-hosted performance monitoring for Rails apps**
|
|
53
10
|
|
|
54
|
-
|
|
11
|
+

|
|
12
|
+

|
|
13
|
+

|
|
14
|
+

|
|
55
15
|
|
|
56
|
-
Rails Pulse is a
|
|
16
|
+
Rails Pulse is a Rails engine that monitors your app's performance from the inside. It tracks slow requests, N+1 queries, SQL performance, and background jobs. All data stays in your own database, no third-party cloud, no SaaS subscription, no data leaving your servers.
|
|
57
17
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
- **Background job monitoring** with execution tracking and failure analysis
|
|
65
|
-
- Week-over-week trend analysis with visual indicators
|
|
66
|
-
|
|
67
|
-
### Background Job Tracking
|
|
68
|
-
- **Universal job tracking** compatible with all ActiveJob adapters
|
|
69
|
-
- Monitor job performance, failures, and retries
|
|
70
|
-
- Track individual job executions with detailed metrics
|
|
71
|
-
- View operations and SQL queries executed during jobs
|
|
72
|
-
- Configurable privacy controls for job arguments
|
|
73
|
-
|
|
74
|
-
### Developer Experience
|
|
75
|
-
- Zero configuration setup with sensible defaults
|
|
76
|
-
- Beautiful responsive interface with dark/light mode
|
|
77
|
-
- Smart caching with minimal performance overhead
|
|
78
|
-
- Multiple database support (SQLite, PostgreSQL, MySQL)
|
|
79
|
-
|
|
80
|
-
### Organization & Filtering
|
|
81
|
-
- Flexible tagging system for routes, requests, queries, and jobs
|
|
82
|
-
- Filter performance data by custom tags
|
|
83
|
-
- Organize monitoring data by environment, priority, or custom categories
|
|
84
|
-
|
|
85
|
-
## Screenshots
|
|
86
|
-
|
|
87
|
-
<table>
|
|
18
|
+
<table border="0">
|
|
19
|
+
<tr border="0" style="border:0">
|
|
20
|
+
<td border="0" style="border:0">
|
|
21
|
+
<img src="app/assets/images/rails_pulse/dashboard.png" alt="Dashboard" width="400" /></td>
|
|
22
|
+
<td style="border:0"><img src="app/assets/images/rails_pulse/request-show.png" alt="Request detail" width="400" /></td>
|
|
23
|
+
</tr>
|
|
88
24
|
<tr>
|
|
89
|
-
<td><img src="app/assets/images/rails_pulse/
|
|
90
|
-
<td><img src="app/assets/images/rails_pulse/
|
|
25
|
+
<td style="border:0"><img src="app/assets/images/rails_pulse/query-show.png" alt="Query detail" width="400" /></td>
|
|
26
|
+
<td style="border:0"><img src="app/assets/images/rails_pulse/route-show.png" alt="Route detail" width="400" /></td>
|
|
91
27
|
</tr>
|
|
92
28
|
</table>
|
|
93
29
|
|
|
30
|
+
## Installation
|
|
94
31
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
### Installation
|
|
98
|
-
|
|
99
|
-
Add Rails Pulse to your application's Gemfile:
|
|
32
|
+
Add to your Gemfile:
|
|
100
33
|
|
|
101
34
|
```ruby
|
|
102
35
|
gem 'rails_pulse'
|
|
103
36
|
```
|
|
104
37
|
|
|
105
|
-
|
|
38
|
+
Run the installer:
|
|
106
39
|
|
|
107
40
|
```bash
|
|
108
41
|
bundle install
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
Generate the installation files:
|
|
112
|
-
|
|
113
|
-
```bash
|
|
114
|
-
# Install with single database setup (default - recommended)
|
|
115
42
|
rails generate rails_pulse:install
|
|
116
|
-
|
|
117
|
-
# Or install with separate database setup
|
|
118
|
-
rails generate rails_pulse:install --database=separate
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
**For single database setup (default):**
|
|
122
|
-
```bash
|
|
123
|
-
rails db:migrate # Creates Rails Pulse tables in your main database
|
|
43
|
+
rails db:migrate
|
|
124
44
|
```
|
|
125
45
|
|
|
126
|
-
|
|
127
|
-
1. Configure `config/database.yml` with your Rails Pulse database settings
|
|
128
|
-
2. Run: `rails db:prepare` to create and load the schema
|
|
129
|
-
|
|
130
|
-
Add the Rails Pulse route to your application:
|
|
46
|
+
Mount the dashboard in `config/routes.rb`:
|
|
131
47
|
|
|
132
48
|
```ruby
|
|
133
49
|
Rails.application.routes.draw do
|
|
@@ -135,757 +51,74 @@ Rails.application.routes.draw do
|
|
|
135
51
|
end
|
|
136
52
|
```
|
|
137
53
|
|
|
138
|
-
Schedule background jobs:
|
|
54
|
+
Schedule the background jobs:
|
|
139
55
|
|
|
140
56
|
```ruby
|
|
141
|
-
#
|
|
142
|
-
RailsPulse::
|
|
143
|
-
|
|
144
|
-
# Schedule to run daily. cron: 0 1 * * *
|
|
145
|
-
RailsPulse::CleanupJob.perform_later
|
|
57
|
+
RailsPulse::SummaryJob.perform_later # cron: 5 * * * *
|
|
58
|
+
RailsPulse::CleanupJob.perform_later # cron: 0 1 * * *
|
|
146
59
|
```
|
|
147
60
|
|
|
148
|
-
|
|
61
|
+
Your dashboard is now at `http://localhost:3000/rails_pulse`.
|
|
149
62
|
|
|
150
|
-
|
|
63
|
+
Full install guide: [railspulse.com/documentation/installation](https://railspulse.com/documentation/installation)
|
|
151
64
|
|
|
152
|
-
|
|
153
|
-
http://localhost:3000/rails_pulse
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
**Database Setup:**
|
|
157
|
-
- **Single Database (default)**: Rails Pulse tables are created in your main database - no additional configuration needed
|
|
158
|
-
- **Separate Database**: See the [Separate Database Support](#separate-database-support) section for setup instructions
|
|
65
|
+
Separate database setup: [railspulse.com/documentation/database](https://railspulse.com/documentation/database)
|
|
159
66
|
|
|
160
|
-
|
|
67
|
+
## Configuration
|
|
161
68
|
|
|
162
|
-
|
|
69
|
+
Rails Pulse works out of the box with sensible defaults. To customise, edit `config/initializers/rails_pulse.rb`:
|
|
163
70
|
|
|
164
71
|
```ruby
|
|
165
72
|
RailsPulse.configure do |config|
|
|
166
|
-
# Enable or disable Rails Pulse
|
|
167
73
|
config.enabled = true
|
|
168
74
|
|
|
169
|
-
# Set performance thresholds for route response times (in milliseconds)
|
|
170
|
-
config.route_thresholds = {
|
|
171
|
-
slow: 500,
|
|
172
|
-
very_slow: 1500,
|
|
173
|
-
critical: 3000
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
# Set performance thresholds for request response times (in milliseconds)
|
|
177
75
|
config.request_thresholds = {
|
|
178
76
|
slow: 700,
|
|
179
77
|
very_slow: 2000,
|
|
180
78
|
critical: 4000
|
|
181
79
|
}
|
|
182
80
|
|
|
183
|
-
# Set performance thresholds for database queries (in milliseconds)
|
|
184
|
-
config.query_thresholds = {
|
|
185
|
-
slow: 100,
|
|
186
|
-
very_slow: 500,
|
|
187
|
-
critical: 1000
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
# Set performance thresholds for background jobs (in milliseconds)
|
|
191
|
-
config.job_thresholds = {
|
|
192
|
-
slow: 5_000, # 5 seconds
|
|
193
|
-
very_slow: 30_000, # 30 seconds
|
|
194
|
-
critical: 60_000 # 1 minute
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
# Asset tracking configuration
|
|
198
|
-
config.track_assets = false # Ignore asset requests by default
|
|
199
|
-
config.custom_asset_patterns = [] # Additional asset patterns to ignore
|
|
200
|
-
|
|
201
|
-
# Job tracking configuration
|
|
202
|
-
config.track_jobs = true # Enable background job tracking
|
|
203
|
-
config.capture_job_arguments = false # Disable argument capture for privacy
|
|
204
|
-
|
|
205
|
-
# Rails Pulse mount path (optional)
|
|
206
|
-
# Specify if Rails Pulse is mounted at a custom path to prevent self-tracking
|
|
207
|
-
config.mount_path = nil # e.g., "/admin/monitoring"
|
|
208
|
-
|
|
209
|
-
# Route filtering - ignore specific routes from performance tracking
|
|
210
|
-
config.ignored_routes = [] # Array of strings or regex patterns
|
|
211
|
-
config.ignored_requests = [] # Array of request patterns to ignore
|
|
212
|
-
config.ignored_queries = [] # Array of query patterns to ignore
|
|
213
|
-
config.ignored_jobs = [] # Array of job class names to ignore
|
|
214
|
-
config.ignored_queues = [] # Array of queue names to ignore
|
|
215
|
-
|
|
216
|
-
# Tagging system - define available tags for categorizing performance data
|
|
217
|
-
config.tags = ["production", "staging", "critical", "needs-optimization"]
|
|
218
|
-
|
|
219
|
-
# Data cleanup
|
|
220
|
-
config.archiving_enabled = true # Enable automatic cleanup
|
|
221
|
-
config.full_retention_period = 30.days # Delete records older than this
|
|
222
|
-
config.max_table_records = { # Maximum records per table
|
|
223
|
-
rails_pulse_operations: 100_000,
|
|
224
|
-
rails_pulse_requests: 50_000,
|
|
225
|
-
rails_pulse_job_runs: 50_000,
|
|
226
|
-
rails_pulse_queries: 10_000,
|
|
227
|
-
rails_pulse_routes: 1_000,
|
|
228
|
-
rails_pulse_jobs: 1_000
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
# Multiple database support (optional)
|
|
232
|
-
# Uncomment to store Rails Pulse data in a separate database
|
|
233
|
-
# config.connects_to = {
|
|
234
|
-
# database: { writing: :rails_pulse, reading: :rails_pulse }
|
|
235
|
-
# }
|
|
236
|
-
end
|
|
237
|
-
```
|
|
238
|
-
|
|
239
|
-
## Background Job Monitoring
|
|
240
|
-
|
|
241
|
-
Rails Pulse provides comprehensive monitoring for ActiveJob background jobs, tracking performance, failures, and execution details across all major job adapters.
|
|
242
|
-
|
|
243
|
-
### Overview
|
|
244
|
-
|
|
245
|
-
Background job monitoring is **enabled by default** and works automatically with any ActiveJob adapter. Rails Pulse captures:
|
|
246
|
-
|
|
247
|
-
- **Job execution metrics**: Duration, status, retry attempts
|
|
248
|
-
- **Failure tracking**: Error class, error message, failure rates
|
|
249
|
-
- **Performance analysis**: Slow jobs, aggregate metrics by job class
|
|
250
|
-
- **Operation timeline**: SQL queries and operations during job execution
|
|
251
|
-
- **Job arguments**: Optional capture for debugging (disabled by default for privacy)
|
|
252
|
-
|
|
253
|
-
Access the jobs dashboard at `/rails_pulse/jobs` to view:
|
|
254
|
-
- All job classes with aggregate metrics (total runs, failure rate, average duration)
|
|
255
|
-
- Individual job executions with detailed performance data
|
|
256
|
-
- Filtering by time range, status, queue, and performance thresholds
|
|
257
|
-
- Tagging support for organizing jobs by team, priority, or category
|
|
258
|
-
|
|
259
|
-
### Supported Adapters
|
|
260
|
-
|
|
261
|
-
Rails Pulse works with all ActiveJob adapters through universal tracking:
|
|
262
|
-
|
|
263
|
-
- **Sidekiq** - Enhanced tracking via custom middleware
|
|
264
|
-
- **Solid Queue** - Universal ActiveJob tracking
|
|
265
|
-
- **Good Job** - Universal ActiveJob tracking
|
|
266
|
-
- **Delayed Job** - Enhanced tracking via custom plugin
|
|
267
|
-
- **Resque** - Universal ActiveJob tracking
|
|
268
|
-
- **Any ActiveJob adapter** - Falls back to universal tracking
|
|
269
|
-
|
|
270
|
-
No additional configuration needed - job tracking works out of the box with your existing setup.
|
|
271
|
-
|
|
272
|
-
### Job Tracking Configuration
|
|
273
|
-
|
|
274
|
-
Customize job tracking in your Rails Pulse initializer:
|
|
275
|
-
|
|
276
|
-
```ruby
|
|
277
|
-
RailsPulse.configure do |config|
|
|
278
|
-
# Enable or disable job tracking (default: true)
|
|
279
81
|
config.track_jobs = true
|
|
82
|
+
config.capture_job_arguments = false # keep false to protect sensitive data
|
|
280
83
|
|
|
281
|
-
|
|
282
|
-
config.job_thresholds = {
|
|
283
|
-
slow: 5_000, # 5 seconds
|
|
284
|
-
very_slow: 30_000, # 30 seconds
|
|
285
|
-
critical: 60_000 # 1 minute
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
# Ignore specific job classes from tracking
|
|
289
|
-
config.ignored_jobs = [
|
|
290
|
-
"ActiveStorage::AnalyzeJob",
|
|
291
|
-
"ActiveStorage::PurgeJob"
|
|
292
|
-
]
|
|
293
|
-
|
|
294
|
-
# Ignore specific queues from tracking
|
|
295
|
-
config.ignored_queues = ["low_priority", "mailers"]
|
|
296
|
-
|
|
297
|
-
# Capture job arguments for debugging (default: false)
|
|
298
|
-
# WARNING: May expose sensitive data - use with caution
|
|
299
|
-
config.capture_job_arguments = false
|
|
300
|
-
|
|
301
|
-
# Configure adapter-specific settings
|
|
302
|
-
config.job_adapters = {
|
|
303
|
-
sidekiq: { enabled: true, track_queue_depth: false },
|
|
304
|
-
solid_queue: { enabled: true, track_recurring: false },
|
|
305
|
-
good_job: { enabled: true, track_cron: false },
|
|
306
|
-
delayed_job: { enabled: true },
|
|
307
|
-
resque: { enabled: true }
|
|
308
|
-
}
|
|
309
|
-
end
|
|
310
|
-
```
|
|
311
|
-
|
|
312
|
-
**Disabling job tracking for specific jobs:**
|
|
313
|
-
|
|
314
|
-
```ruby
|
|
315
|
-
class MyBackgroundJob < ApplicationJob
|
|
316
|
-
# Skip Rails Pulse tracking for this job
|
|
317
|
-
def perform(*args)
|
|
318
|
-
RailsPulse.with_tracking_disabled do
|
|
319
|
-
# Job logic here
|
|
320
|
-
end
|
|
321
|
-
end
|
|
322
|
-
end
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
### Privacy & Security
|
|
326
|
-
|
|
327
|
-
**Job argument capture is disabled by default** to protect sensitive information. Job arguments may contain:
|
|
328
|
-
- User credentials or tokens
|
|
329
|
-
- Personal identifiable information (PII)
|
|
330
|
-
- API keys or secrets
|
|
331
|
-
- Sensitive business data
|
|
332
|
-
|
|
333
|
-
Only enable `capture_job_arguments` in development or when explicitly needed for debugging. Consider using parameter filtering if you need to capture arguments:
|
|
334
|
-
|
|
335
|
-
```ruby
|
|
336
|
-
# In your job class
|
|
337
|
-
class SensitiveJob < ApplicationJob
|
|
338
|
-
def perform(user_id:, api_key:)
|
|
339
|
-
# Rails Pulse will track execution but not arguments by default
|
|
340
|
-
end
|
|
84
|
+
config.full_retention_period = 30.days
|
|
341
85
|
end
|
|
342
86
|
```
|
|
343
87
|
|
|
344
|
-
|
|
345
|
-
- Minimal overhead: ~1-2ms per job execution
|
|
346
|
-
- No blocking of job processing
|
|
347
|
-
- Configurable cleanup prevents database growth
|
|
348
|
-
- Can be disabled per-job or globally
|
|
88
|
+
Full configuration reference: [railspulse.com/documentation/advanced](https://railspulse.com/documentation/advanced)
|
|
349
89
|
|
|
350
90
|
## Authentication
|
|
351
91
|
|
|
352
|
-
Rails Pulse
|
|
353
|
-
|
|
354
|
-
### Authentication Setup
|
|
355
|
-
|
|
356
|
-
Enable authentication by configuring the following options in your Rails Pulse initializer:
|
|
92
|
+
Rails Pulse has no built-in authentication, you protect the dashboard using your app's existing auth. Add an `authentication_method` to the initializer:
|
|
357
93
|
|
|
358
94
|
```ruby
|
|
359
|
-
# config/initializers/rails_pulse.rb
|
|
360
95
|
RailsPulse.configure do |config|
|
|
361
|
-
# Enable authentication
|
|
362
96
|
config.authentication_enabled = true
|
|
363
|
-
|
|
364
|
-
# Where to redirect unauthorized users (optional, defaults to "/")
|
|
365
97
|
config.authentication_redirect_path = "/login"
|
|
366
98
|
|
|
367
|
-
# Define your authentication logic
|
|
368
99
|
config.authentication_method = proc {
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
end
|
|
372
|
-
```
|
|
373
|
-
|
|
374
|
-
### Authentication Examples
|
|
375
|
-
|
|
376
|
-
Rails Pulse works with any authentication system. Here are common patterns:
|
|
377
|
-
|
|
378
|
-
#### Devise with Admin Role
|
|
379
|
-
|
|
380
|
-
```ruby
|
|
381
|
-
config.authentication_method = proc {
|
|
382
|
-
unless user_signed_in? && current_user.admin?
|
|
383
|
-
redirect_to main_app.root_path, alert: "Access denied"
|
|
384
|
-
end
|
|
385
|
-
}
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
#### Custom Authorization Logic
|
|
389
|
-
|
|
390
|
-
```ruby
|
|
391
|
-
config.authentication_method = proc {
|
|
392
|
-
current_user = User.find_by(id: session[:user_id])
|
|
393
|
-
unless current_user&.can_access_monitoring?
|
|
394
|
-
render plain: "Forbidden", status: :forbidden
|
|
395
|
-
end
|
|
396
|
-
}
|
|
397
|
-
```
|
|
398
|
-
|
|
399
|
-
## Tagging System
|
|
400
|
-
|
|
401
|
-
Rails Pulse includes a flexible tagging system that allows you to categorize and organize your performance data. Tag routes, requests, queries, jobs, and job runs with custom labels to better organize and filter your monitoring data.
|
|
402
|
-
|
|
403
|
-
### Configuring Tags
|
|
404
|
-
|
|
405
|
-
Define available tags in your Rails Pulse initializer:
|
|
406
|
-
|
|
407
|
-
```ruby
|
|
408
|
-
RailsPulse.configure do |config|
|
|
409
|
-
config.tags = [
|
|
410
|
-
"production",
|
|
411
|
-
"staging",
|
|
412
|
-
"critical",
|
|
413
|
-
"needs-optimization",
|
|
414
|
-
"high-traffic",
|
|
415
|
-
"background-job"
|
|
416
|
-
]
|
|
417
|
-
end
|
|
418
|
-
```
|
|
419
|
-
|
|
420
|
-
### Using Tags
|
|
421
|
-
|
|
422
|
-
**Tag from the UI:**
|
|
423
|
-
|
|
424
|
-
1. Navigate to any route, request, query, job, or job run detail page
|
|
425
|
-
2. Click the "+ tag" button next to the record
|
|
426
|
-
3. Select from your configured tags
|
|
427
|
-
4. Remove tags by clicking the × button on any tag badge
|
|
428
|
-
|
|
429
|
-
**Tag Programmatically:**
|
|
430
|
-
|
|
431
|
-
```ruby
|
|
432
|
-
# Tag a route
|
|
433
|
-
route = RailsPulse::Route.find_by(path: "/api/users")
|
|
434
|
-
route.add_tag("critical")
|
|
435
|
-
route.add_tag("high-traffic")
|
|
436
|
-
|
|
437
|
-
# Tag a query
|
|
438
|
-
query = RailsPulse::Query.find_by(normalized_sql: "SELECT * FROM users WHERE id = ?")
|
|
439
|
-
query.add_tag("needs-optimization")
|
|
440
|
-
|
|
441
|
-
# Tag a job
|
|
442
|
-
job = RailsPulse::Job.find_by(name: "UserNotificationJob")
|
|
443
|
-
job.add_tag("high-priority")
|
|
444
|
-
job.add_tag("user-facing")
|
|
445
|
-
|
|
446
|
-
# Tag a specific job run
|
|
447
|
-
job_run = RailsPulse::JobRun.find_by(run_id: "abc123")
|
|
448
|
-
job_run.add_tag("investigated")
|
|
449
|
-
|
|
450
|
-
# Remove a tag
|
|
451
|
-
route.remove_tag("critical")
|
|
452
|
-
|
|
453
|
-
# Check if has tag
|
|
454
|
-
route.has_tag?("production") # => true
|
|
455
|
-
```
|
|
456
|
-
|
|
457
|
-
### Filtering by Tags
|
|
458
|
-
|
|
459
|
-
Use the global filters modal to filter performance data by tags:
|
|
460
|
-
|
|
461
|
-
1. Click the filter icon in the top navigation
|
|
462
|
-
2. Select one or more tags from the tag selector
|
|
463
|
-
3. Apply filters to see only records with those tags
|
|
464
|
-
4. Tags appear as badges in all data tables for quick visual identification
|
|
465
|
-
|
|
466
|
-
**Common Tagging Strategies:**
|
|
467
|
-
|
|
468
|
-
- **By Environment**: `production`, `staging`, `development`
|
|
469
|
-
- **By Priority**: `critical`, `high`, `medium`, `low`
|
|
470
|
-
- **By Status**: `needs-optimization`, `investigating`, `resolved`
|
|
471
|
-
- **By Type**: `api`, `background-job`, `user-facing`, `admin`
|
|
472
|
-
- **By Team**: `team-frontend`, `team-backend`, `team-data`
|
|
473
|
-
|
|
474
|
-
## Data Management
|
|
475
|
-
|
|
476
|
-
Rails Pulse provides data cleanup to prevent your monitoring database from growing indefinitely while preserving essential performance insights.
|
|
477
|
-
|
|
478
|
-
### Cleanup Strategies
|
|
479
|
-
|
|
480
|
-
**Time-based Cleanup**
|
|
481
|
-
- Automatically delete performance records older than a specified period
|
|
482
|
-
- Configurable retention period (default: 2 days)
|
|
483
|
-
- Keeps recent data for debugging while removing historical noise
|
|
484
|
-
|
|
485
|
-
**Count-based Cleanup**
|
|
486
|
-
- Enforce maximum record limits per table
|
|
487
|
-
- Prevents any single table from consuming excessive storage
|
|
488
|
-
- Configurable limits for each Rails Pulse table
|
|
489
|
-
|
|
490
|
-
### Cleanup Configuration
|
|
491
|
-
|
|
492
|
-
```ruby
|
|
493
|
-
RailsPulse.configure do |config|
|
|
494
|
-
# Enable or disable automatic cleanup
|
|
495
|
-
config.archiving_enabled = true
|
|
496
|
-
|
|
497
|
-
# Time-based retention
|
|
498
|
-
config.full_retention_period = 2.weeks
|
|
499
|
-
|
|
500
|
-
# Count-based retention - maximum records per table
|
|
501
|
-
config.max_table_records = {
|
|
502
|
-
rails_pulse_requests: 10000, # HTTP requests
|
|
503
|
-
rails_pulse_operations: 50000, # Operations within requests
|
|
504
|
-
rails_pulse_routes: 1000, # Unique routes
|
|
505
|
-
rails_pulse_queries: 500 # Normalized SQL queries
|
|
506
|
-
}
|
|
507
|
-
end
|
|
508
|
-
```
|
|
509
|
-
|
|
510
|
-
### Manual Cleanup Operations
|
|
511
|
-
|
|
512
|
-
**Run cleanup manually:**
|
|
513
|
-
```bash
|
|
514
|
-
rails rails_pulse:cleanup
|
|
515
|
-
```
|
|
516
|
-
|
|
517
|
-
**Check current database status:**
|
|
518
|
-
```bash
|
|
519
|
-
rails rails_pulse:cleanup_stats
|
|
520
|
-
```
|
|
521
|
-
|
|
522
|
-
**Schedule automated cleanup:**
|
|
523
|
-
```ruby
|
|
524
|
-
RailsPulse::CleanupJob.perform_later
|
|
525
|
-
```
|
|
526
|
-
|
|
527
|
-
## Separate Database Support
|
|
528
|
-
|
|
529
|
-
Rails Pulse offers two database setup options to fit your application's needs:
|
|
530
|
-
|
|
531
|
-
### Option 1: Single Database (Default - Recommended)
|
|
532
|
-
|
|
533
|
-
Stores Rails Pulse data in your main application database alongside your existing tables. This is the simplest setup and works great for most applications.
|
|
534
|
-
|
|
535
|
-
**Advantages:**
|
|
536
|
-
- Zero additional configuration required
|
|
537
|
-
- Simpler backup and deployment strategies
|
|
538
|
-
- Works with any database (SQLite, PostgreSQL, MySQL)
|
|
539
|
-
|
|
540
|
-
**Installation:**
|
|
541
|
-
```bash
|
|
542
|
-
rails generate rails_pulse:install
|
|
543
|
-
rails db:migrate
|
|
544
|
-
```
|
|
545
|
-
|
|
546
|
-
### Option 2: Separate Database
|
|
547
|
-
|
|
548
|
-
Stores Rails Pulse data in a dedicated database, completely isolated from your main application.
|
|
549
|
-
|
|
550
|
-
**Use a separate database when you want:**
|
|
551
|
-
- **Isolating monitoring data** from your main application database
|
|
552
|
-
- **Using different database engines** optimized for time-series data
|
|
553
|
-
- **Scaling monitoring independently** from your application
|
|
554
|
-
- **Simplified backup strategies** with separate retention policies
|
|
555
|
-
|
|
556
|
-
### Configuration
|
|
557
|
-
|
|
558
|
-
To use a separate database, install with the `--database=separate` flag, then configure the `connects_to` option in your Rails Pulse initializer:
|
|
559
|
-
|
|
560
|
-
```ruby
|
|
561
|
-
RailsPulse.configure do |config|
|
|
562
|
-
# Single separate database
|
|
563
|
-
config.connects_to = {
|
|
564
|
-
database: { writing: :rails_pulse, reading: :rails_pulse }
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
# Or primary/replica configuration
|
|
568
|
-
config.connects_to = {
|
|
569
|
-
database: { writing: :rails_pulse_primary, reading: :rails_pulse_replica }
|
|
100
|
+
unless user_signed_in? && current_user.admin?
|
|
101
|
+
redirect_to main_app.root_path, alert: "Access denied"
|
|
102
|
+
end
|
|
570
103
|
}
|
|
571
104
|
end
|
|
572
105
|
```
|
|
573
106
|
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
Add the corresponding database configurations to your `config/database.yml`:
|
|
577
|
-
|
|
578
|
-
```yaml
|
|
579
|
-
# For SQLite
|
|
580
|
-
production:
|
|
581
|
-
# ... your main database ...
|
|
582
|
-
rails_pulse:
|
|
583
|
-
adapter: sqlite3
|
|
584
|
-
database: storage/rails_pulse_production.sqlite3
|
|
585
|
-
migrations_paths: db/rails_pulse_migrate
|
|
586
|
-
pool: 5
|
|
587
|
-
timeout: 5000
|
|
588
|
-
|
|
589
|
-
# For PostgreSQL
|
|
590
|
-
production:
|
|
591
|
-
# ... your main database ...
|
|
592
|
-
rails_pulse:
|
|
593
|
-
adapter: postgresql
|
|
594
|
-
database: myapp_rails_pulse_production
|
|
595
|
-
username: rails_pulse_user
|
|
596
|
-
password: <%= Rails.application.credentials.dig(:rails_pulse, :database_password) %>
|
|
597
|
-
host: localhost
|
|
598
|
-
migrations_paths: db/rails_pulse_migrate
|
|
599
|
-
pool: 5
|
|
600
|
-
|
|
601
|
-
# For MySQL
|
|
602
|
-
production:
|
|
603
|
-
# ... your main database ...
|
|
604
|
-
rails_pulse:
|
|
605
|
-
adapter: mysql2
|
|
606
|
-
database: myapp_rails_pulse_production
|
|
607
|
-
username: rails_pulse_user
|
|
608
|
-
password: <%= Rails.application.credentials.dig(:rails_pulse, :database_password) %>
|
|
609
|
-
host: localhost
|
|
610
|
-
migrations_paths: db/rails_pulse_migrate
|
|
611
|
-
pool: 5
|
|
612
|
-
```
|
|
613
|
-
|
|
614
|
-
### Installation Steps
|
|
615
|
-
|
|
616
|
-
**For separate database setup:**
|
|
617
|
-
|
|
618
|
-
1. **Generate installation files:**
|
|
619
|
-
```bash
|
|
620
|
-
rails generate rails_pulse:install --database=separate
|
|
621
|
-
```
|
|
622
|
-
|
|
623
|
-
2. **Configure `config/database.yml`** (see examples above)
|
|
624
|
-
|
|
625
|
-
3. **Create and load the schema:**
|
|
626
|
-
```bash
|
|
627
|
-
rails db:prepare
|
|
628
|
-
```
|
|
629
|
-
This automatically creates the database and loads the Rails Pulse schema.
|
|
630
|
-
|
|
631
|
-
**Schema Management:**
|
|
632
|
-
|
|
633
|
-
The schema file `db/rails_pulse_schema.rb` serves as your single source of truth for the database structure. It:
|
|
634
|
-
- Defines all Rails Pulse tables in one place
|
|
635
|
-
- Is loaded by the installation migration
|
|
636
|
-
- Should not be deleted or modified
|
|
637
|
-
- Future updates will provide migrations in `db/rails_pulse_migrate/`
|
|
638
|
-
|
|
639
|
-
## Performance Impact
|
|
640
|
-
|
|
641
|
-
Rails Pulse uses **fiber-based async tracking** for minimal performance overhead:
|
|
107
|
+
Authentication guide: [railspulse.com/documentation/authentication](https://railspulse.com/documentation/authentication)
|
|
642
108
|
|
|
643
|
-
|
|
644
|
-
- **Database writes:** Non-blocking, handled in background fibers
|
|
645
|
-
- **Memory allocation:** Minimal, ~200 KB per request (temporary)
|
|
646
|
-
- **Thread safety:** Proper connection pooling with isolated database connections
|
|
647
|
-
|
|
648
|
-
This is handled automatically and requires no configuration.
|
|
649
|
-
|
|
650
|
-
## Standalone Dashboard Deployment
|
|
651
|
-
|
|
652
|
-
For production environments, you can run the Rails Pulse dashboard as a standalone application, separate from your main Rails app. This provides several benefits:
|
|
653
|
-
|
|
654
|
-
- **Dashboard remains accessible when main app is under heavy load**
|
|
655
|
-
- **Separate resource allocation** for monitoring vs application
|
|
656
|
-
- **Enhanced security** - isolate dashboard access from public app
|
|
657
|
-
- **Independent scaling** - dashboard doesn't scale with app instances
|
|
658
|
-
|
|
659
|
-
**Quick Setup:**
|
|
660
|
-
|
|
661
|
-
```bash
|
|
662
|
-
# Option 1: Set DATABASE_URL environment variable (recommended for production)
|
|
663
|
-
export DATABASE_URL="postgresql://user:pass@host/db"
|
|
664
|
-
bundle exec rails_pulse_server
|
|
665
|
-
|
|
666
|
-
# Option 2: Use config/database.yml (recommended for development)
|
|
667
|
-
# Looks for 'rails_pulse' connection, falls back to primary
|
|
668
|
-
# No environment variable needed - automatically reads from config/database.yml
|
|
669
|
-
bundle exec rails_pulse_server
|
|
670
|
-
```
|
|
671
|
-
|
|
672
|
-
**Healthcheck Endpoint:**
|
|
673
|
-
|
|
674
|
-
The standalone server includes a `/health` endpoint that verifies database connectivity:
|
|
675
|
-
|
|
676
|
-
```bash
|
|
677
|
-
curl http://localhost:3001/health
|
|
678
|
-
# Returns: {"status":"ok","mode":"dashboard","database":"connected","timestamp":"..."}
|
|
679
|
-
```
|
|
680
|
-
|
|
681
|
-
**Deployment Options:**
|
|
682
|
-
|
|
683
|
-
1. **Separate subdomain (recommended):**
|
|
684
|
-
```nginx
|
|
685
|
-
server {
|
|
686
|
-
server_name pulse.myapp.com;
|
|
687
|
-
location / {
|
|
688
|
-
proxy_pass http://localhost:3001;
|
|
689
|
-
proxy_set_header Host $host;
|
|
690
|
-
proxy_set_header X-Real-IP $remote_addr;
|
|
691
|
-
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
692
|
-
proxy_set_header X-Forwarded-Proto $scheme;
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
```
|
|
696
|
-
|
|
697
|
-
2. **Kamal Deployment:**
|
|
698
|
-
Deploy the dashboard as an accessory
|
|
699
|
-
|
|
700
|
-
```yaml
|
|
701
|
-
# config/deploy.yml
|
|
702
|
-
accessories:
|
|
703
|
-
rails_pulse:
|
|
704
|
-
image: your-app-image # Same image as your main app
|
|
705
|
-
host: your-server
|
|
706
|
-
cmd: bundle exec rails_pulse_server
|
|
707
|
-
env:
|
|
708
|
-
clear:
|
|
709
|
-
DATABASE_URL: "postgresql://user:pass@host/db"
|
|
710
|
-
RAILS_ENV: production
|
|
711
|
-
SECRET_KEY_BASE: <%= ENV.fetch("SECRET_KEY_BASE") %>
|
|
712
|
-
port: "3001:3001"
|
|
713
|
-
healthcheck:
|
|
714
|
-
path: /health
|
|
715
|
-
port: 3001
|
|
716
|
-
interval: 10s
|
|
717
|
-
timeout: 5s
|
|
718
|
-
```
|
|
719
|
-
|
|
720
|
-
**Note:** When running standalone, the dashboard is read-only and doesn't track its own requests (tracking is automatically disabled).
|
|
721
|
-
|
|
722
|
-
For detailed deployment instructions, see [docs/deployment-modes.md](docs/deployment-modes.md).
|
|
723
|
-
|
|
724
|
-
## Testing
|
|
725
|
-
|
|
726
|
-
Rails Pulse includes a comprehensive test suite designed for speed and reliability across multiple databases and Rails versions.
|
|
727
|
-
|
|
728
|
-
### Running the Complete Test Suite
|
|
729
|
-
|
|
730
|
-
```bash
|
|
731
|
-
# Run all tests (unit, functional, integration, instrumentation)
|
|
732
|
-
rails test:all
|
|
733
|
-
```
|
|
734
|
-
|
|
735
|
-
### Running Individual Test Types
|
|
736
|
-
|
|
737
|
-
```bash
|
|
738
|
-
# Unit tests (models, helpers, utilities)
|
|
739
|
-
rails test:unit
|
|
740
|
-
|
|
741
|
-
# Functional tests (controllers, views)
|
|
742
|
-
rails test:functional
|
|
743
|
-
|
|
744
|
-
# Integration tests (end-to-end workflows)
|
|
745
|
-
rails test:integration
|
|
746
|
-
```
|
|
747
|
-
|
|
748
|
-
### Running Individual Test Files
|
|
749
|
-
|
|
750
|
-
```bash
|
|
751
|
-
# Run a specific test file
|
|
752
|
-
rails test test/models/rails_pulse/request_test.rb
|
|
753
|
-
```
|
|
754
|
-
|
|
755
|
-
### Multi-Database and Rails Version Testing
|
|
756
|
-
|
|
757
|
-
Test against multiple databases and Rails versions using the matrix task:
|
|
758
|
-
|
|
759
|
-
```bash
|
|
760
|
-
# Test all database and Rails version combinations locally
|
|
761
|
-
rails test:matrix
|
|
762
|
-
```
|
|
763
|
-
|
|
764
|
-
This command tests all combinations locally:
|
|
765
|
-
- **Databases**: SQLite3, PostgreSQL, MySQL2 (local testing only)
|
|
766
|
-
- **Rails versions**: 7.2, 8.0, 8.1
|
|
767
|
-
|
|
768
|
-
**Note**: CI only tests SQLite3 + PostgreSQL for reliability. MySQL is available for local testing but excluded from CI due to flakiness.
|
|
769
|
-
|
|
770
|
-
### Development Environment Setup
|
|
771
|
-
|
|
772
|
-
1. **Copy the environment template:**
|
|
773
|
-
```bash
|
|
774
|
-
cp .env.example .env
|
|
775
|
-
```
|
|
776
|
-
|
|
777
|
-
2. **Configure your database credentials in `.env` (for local multi-database testing):**
|
|
778
|
-
```bash
|
|
779
|
-
# PostgreSQL Configuration (used in CI + local)
|
|
780
|
-
POSTGRES_USERNAME=your_username
|
|
781
|
-
POSTGRES_PASSWORD=your_password
|
|
782
|
-
POSTGRES_HOST=localhost
|
|
783
|
-
POSTGRES_PORT=5432
|
|
784
|
-
|
|
785
|
-
# MySQL Configuration (local testing only)
|
|
786
|
-
MYSQL_USERNAME=root
|
|
787
|
-
MYSQL_PASSWORD=your_password
|
|
788
|
-
MYSQL_HOST=localhost
|
|
789
|
-
MYSQL_PORT=3306
|
|
790
|
-
```
|
|
791
|
-
|
|
792
|
-
3. **Create test databases:**
|
|
793
|
-
```bash
|
|
794
|
-
# PostgreSQL
|
|
795
|
-
createdb rails_pulse_test
|
|
796
|
-
|
|
797
|
-
# MySQL
|
|
798
|
-
mysql -u root -p -e "CREATE DATABASE rails_pulse_test;"
|
|
799
|
-
```
|
|
800
|
-
|
|
801
|
-
### Manual Database Testing
|
|
802
|
-
|
|
803
|
-
Test individual databases locally:
|
|
804
|
-
|
|
805
|
-
```bash
|
|
806
|
-
# Test with SQLite (default)
|
|
807
|
-
rails test:all
|
|
109
|
+
## Features
|
|
808
110
|
|
|
809
|
-
|
|
810
|
-
|
|
111
|
+
- **Request monitoring** — every request is timed and stored with its route, status, SQL count, and duration. Slow requests are flagged automatically based on thresholds you control.
|
|
112
|
+
- **Query analysis** — captures the queries behind each request, detects N+1 patterns, and tracks normalized SQL across requests so you can see which queries are hurting you in production, not just in development.
|
|
113
|
+
- **Job tracking** — monitors background job duration, queue wait time, and failure rates. Works with any Active Job adapter.
|
|
114
|
+
- **System health bar** — at-a-glance dashboard summary showing healthy, slow, and critical counts across your routes, queries, jobs, and storage. Lets you see the overall state of your app before drilling into specifics.
|
|
115
|
+
- **No data leaves your app** — everything is stored in your own database. No third-party cloud, no SaaS subscription, no outbound connections.
|
|
116
|
+
- **Low overhead** — tracking is async and uses a thread-local flag to skip recording Rails Pulse's own internal requests.
|
|
811
117
|
|
|
812
|
-
|
|
813
|
-
DB=mysql2 FORCE_DB_CONFIG=true rails test:all
|
|
814
|
-
```
|
|
118
|
+
## Contributing
|
|
815
119
|
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
GitHub Actions CI automatically tests:
|
|
819
|
-
- **Databases**: SQLite3, PostgreSQL only (MySQL excluded for reliability)
|
|
820
|
-
- **Rails versions**: 7.2, 8.0, 8.1
|
|
821
|
-
- **Environment**: Uses memory SQLite and PostgreSQL service
|
|
822
|
-
|
|
823
|
-
**Local vs CI differences**:
|
|
824
|
-
- **Local**: Can test all 3 databases (SQLite3, PostgreSQL, MySQL2)
|
|
825
|
-
- **CI**: Only SQLite3 + PostgreSQL for fast, reliable builds
|
|
826
|
-
- **Database switching**: Requires `FORCE_DB_CONFIG=true` locally
|
|
827
|
-
|
|
828
|
-
## Technology Stack
|
|
829
|
-
|
|
830
|
-
Rails Pulse is built using modern, battle-tested technologies that ensure reliability, performance, and maintainability:
|
|
831
|
-
|
|
832
|
-
### **Frontend Technologies**
|
|
833
|
-
- **[CSS Zero](https://github.com/lazaronixon/css-zero)** - Modern utility-first CSS framework bundled for asset independence
|
|
834
|
-
- **[Stimulus](https://stimulus.hotwired.dev/)** - Progressive JavaScript framework for enhanced interactivity
|
|
835
|
-
- **Fetch API + DOMParser** - Lightweight partial page updates with CSP-safe DOM manipulation
|
|
836
|
-
|
|
837
|
-
### **Data Visualization**
|
|
838
|
-
- **[Apache ECharts](https://echarts.apache.org/)** - Powerful, interactive charting library
|
|
839
|
-
- **[Lucide Icons](https://lucide.dev/)** - Beautiful, consistent iconography with pre-compiled SVG bundle
|
|
840
|
-
|
|
841
|
-
### **Asset Management**
|
|
842
|
-
- **Pre-compiled Assets** - All CSS, JavaScript, and icons bundled into the gem
|
|
843
|
-
- **CSP-Safe Implementation** - Secure DOM methods and nonce-based asset loading
|
|
844
|
-
- **Build System** - Node.js-based build process for asset compilation
|
|
845
|
-
- **Zero External Dependencies** - Self-contained assets work with any Rails build system
|
|
846
|
-
|
|
847
|
-
### **Performance & Optimization**
|
|
848
|
-
- **[Request Store](https://github.com/steveklabnik/request_store)** - Thread-safe request-scoped storage for performance data
|
|
849
|
-
- **[Rails Caching](https://guides.rubyonrails.org/caching_with_rails.html)** - Fragment caching with smart invalidation strategies
|
|
850
|
-
- **[ActiveRecord Instrumentation](https://guides.rubyonrails.org/active_support_instrumentation.html)** - Built-in Rails performance monitoring hooks
|
|
851
|
-
|
|
852
|
-
### **Development & Testing**
|
|
853
|
-
- **[Rails Generators](https://guides.rubyonrails.org/generators.html)** - Automated installation and configuration
|
|
854
|
-
- **[Omakase Ruby Styling](https://github.com/rails/rubocop-rails-omakase)** - Consistent code formatting and style
|
|
855
|
-
|
|
856
|
-
## Advantages Over Other Solutions
|
|
857
|
-
|
|
858
|
-
### **vs. Application Performance Monitoring (APM) Services**
|
|
859
|
-
- **No External Dependencies**: Everything runs in your Rails application with pre-compiled assets
|
|
860
|
-
- **Zero Monthly Costs**: No subscription fees or usage-based pricing
|
|
861
|
-
- **Data Privacy**: All performance data stays in your database(s)
|
|
862
|
-
- **Customizable**: Full control over metrics, thresholds, and interface
|
|
863
|
-
- **Asset Independence**: Works with any Rails build system (Sprockets, esbuild, Webpack, Vite)
|
|
864
|
-
|
|
865
|
-
### **vs. Custom Monitoring Solutions**
|
|
866
|
-
- **Batteries Included**: Complete monitoring solution out of the box
|
|
867
|
-
- **Proven Architecture**: Built on Rails best practices
|
|
868
|
-
- **Community Driven**: Open source with active development
|
|
869
|
-
- **Professional Design**: Production-ready interface
|
|
870
|
-
|
|
871
|
-
### **Key Differentiators**
|
|
872
|
-
- **Rails-Native**: Designed specifically for Rails applications
|
|
873
|
-
- **Developer Experience**: Optimized for debugging and development
|
|
874
|
-
- **Positive Focus**: Celebrates good performance alongside problem identification
|
|
875
|
-
- **Contextual Insights**: Deep Rails framework integration for meaningful metrics
|
|
876
|
-
- **Security First**: CSP-compliant by default with secure asset handling
|
|
877
|
-
- **Zero Build Dependencies**: Pre-compiled assets work with any Rails setup
|
|
878
|
-
- **Flexible Data Storage**: Support for multiple database backends (SQLite, PostgreSQL, MySQL)
|
|
120
|
+
Bug reports and pull requests are welcome on [GitHub](https://github.com/railspulse/rails_pulse).
|
|
879
121
|
|
|
880
122
|
## License
|
|
881
123
|
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
---
|
|
885
|
-
|
|
886
|
-
<div align="center">
|
|
887
|
-
<strong>Built with ❤️ for the Rails community</strong>
|
|
888
|
-
|
|
889
|
-
[Issues](https://github.com/railspulse/rails_pulse/issues) •
|
|
890
|
-
[Discussions](https://github.com/railspulse/rails_pulse/discussions)
|
|
891
|
-
</div>
|
|
124
|
+
Available as open source under the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
CHANGED
|
@@ -186,7 +186,7 @@ end
|
|
|
186
186
|
|
|
187
187
|
desc "Test all database and Rails version combinations"
|
|
188
188
|
task :test_matrix do
|
|
189
|
-
databases = %w[
|
|
189
|
+
databases = %w[mysql2 postgresql sqlite3]
|
|
190
190
|
rails_versions = %w[rails-7-2 rails-8-0 rails-8-1]
|
|
191
191
|
|
|
192
192
|
failed_combinations = []
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -40,8 +40,8 @@ RailsPulse::Schema ||= lambda do |connection|
|
|
|
40
40
|
|
|
41
41
|
unless connection.table_exists?(:rails_pulse_queries)
|
|
42
42
|
connection.create_table :rails_pulse_queries do |t|
|
|
43
|
-
t.string :hashed_sql, limit: 32, null: false, comment: "MD5 hash of normalized SQL for
|
|
44
|
-
t.text :normalized_sql, null: false, comment: "
|
|
43
|
+
t.string :hashed_sql, limit: 32, null: false, comment: "MD5 hash of normalized SQL for fast lookups and uniqueness"
|
|
44
|
+
t.text :normalized_sql, null: false, comment: "Full normalized SQL query string (e.g., SELECT * FROM users WHERE id = ?)"
|
|
45
45
|
t.datetime :analyzed_at, comment: "When query analysis was last performed"
|
|
46
46
|
t.text :explain_plan, comment: "EXPLAIN output from actual SQL execution"
|
|
47
47
|
t.text :issues, comment: "JSON array of detected performance issues"
|
|
@@ -68,6 +68,7 @@ RailsPulse::Schema ||= lambda do |connection|
|
|
|
68
68
|
t.string :controller_action, comment: "Controller and action handling the request (e.g., PostsController#show)"
|
|
69
69
|
t.timestamp :occurred_at, null: false, comment: "When the request started"
|
|
70
70
|
t.text :tags, comment: "JSON array of tags for filtering and categorization"
|
|
71
|
+
t.integer :response_size_bytes, comment: "HTTP response body size in bytes"
|
|
71
72
|
t.timestamps
|
|
72
73
|
end
|
|
73
74
|
|
|
@@ -131,6 +132,10 @@ RailsPulse::Schema ||= lambda do |connection|
|
|
|
131
132
|
t.string :codebase_location, comment: "File and line number (e.g., app/models/user.rb:25)"
|
|
132
133
|
t.float :start_time, null: false, default: 0.0, comment: "Operation start time in milliseconds"
|
|
133
134
|
t.timestamp :occurred_at, null: false, comment: "When the request started"
|
|
135
|
+
t.integer :row_count, comment: "Number of rows returned (SQL operations, Rails 7.1+)"
|
|
136
|
+
t.boolean :cache_hit, comment: "Whether a cache_read operation hit the cache"
|
|
137
|
+
t.text :repeated_query_group, comment: "Normalized SQL key identifying an N+1 group"
|
|
138
|
+
t.integer :repetition_count, comment: "Number of times this query pattern repeated in the request"
|
|
134
139
|
t.timestamps
|
|
135
140
|
end
|
|
136
141
|
|
|
@@ -154,7 +159,7 @@ RailsPulse::Schema ||= lambda do |connection|
|
|
|
154
159
|
t.string :period_type, null: false, comment: "Aggregation period type: hour, day, week, month"
|
|
155
160
|
|
|
156
161
|
# Polymorphic association to handle both routes and queries
|
|
157
|
-
t.references :summarizable, polymorphic: true, null: false, index:
|
|
162
|
+
t.references :summarizable, polymorphic: true, null: false, index: true, comment: "Link to Route or Query"
|
|
158
163
|
# This creates summarizable_type (e.g., 'RailsPulse::Route', 'RailsPulse::Query')
|
|
159
164
|
# and summarizable_id (route_id or query_id)
|
|
160
165
|
|
data/lib/rails_pulse/version.rb
CHANGED
data/lib/rails_pulse.rb
CHANGED
|
@@ -16,7 +16,11 @@ module RailsPulse
|
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def logger
|
|
19
|
-
|
|
19
|
+
if defined?(Rails) && Rails.respond_to?(:logger) && Rails.logger
|
|
20
|
+
@logger ||= ActiveSupport::TaggedLogging.new(Rails.logger).tagged("RailsPulse")
|
|
21
|
+
else
|
|
22
|
+
Logger.new($stdout)
|
|
23
|
+
end
|
|
20
24
|
end
|
|
21
25
|
|
|
22
26
|
def clear_metric_cache!
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rails_pulse
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
|
-
-
|
|
7
|
+
- Scott Harvey
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-05-06 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|
|
@@ -190,9 +190,9 @@ dependencies:
|
|
|
190
190
|
- - ">="
|
|
191
191
|
- !ruby/object:Gem::Version
|
|
192
192
|
version: '0'
|
|
193
|
-
description:
|
|
194
|
-
|
|
195
|
-
|
|
193
|
+
description: Self-hosted performance monitoring engine for Rails apps. Tracks slow
|
|
194
|
+
requests, N+1 queries, and SQL performance. All data stays in your own database
|
|
195
|
+
— no third-party cloud required.
|
|
196
196
|
email:
|
|
197
197
|
- hey@railspulse.com
|
|
198
198
|
executables:
|
|
@@ -204,8 +204,11 @@ files:
|
|
|
204
204
|
- README.md
|
|
205
205
|
- Rakefile
|
|
206
206
|
- app/assets/images/rails_pulse/dashboard.png
|
|
207
|
+
- app/assets/images/rails_pulse/query-show.png
|
|
207
208
|
- app/assets/images/rails_pulse/rails-pulse-logo.png
|
|
209
|
+
- app/assets/images/rails_pulse/request-show.png
|
|
208
210
|
- app/assets/images/rails_pulse/request.png
|
|
211
|
+
- app/assets/images/rails_pulse/route-show.png
|
|
209
212
|
- app/assets/stylesheets/rails_pulse/application.css
|
|
210
213
|
- app/assets/stylesheets/rails_pulse/components/alert.css
|
|
211
214
|
- app/assets/stylesheets/rails_pulse/components/badge.css
|
|
@@ -433,7 +436,7 @@ files:
|
|
|
433
436
|
- config/routes.rb
|
|
434
437
|
- db/rails_pulse_migrate/20260417000001_add_diagnostic_fields.rb
|
|
435
438
|
- db/rails_pulse_migrate/20260419000001_add_p95_p99_duration_to_rails_pulse_jobs.rb
|
|
436
|
-
- db/rails_pulse_migrate/
|
|
439
|
+
- db/rails_pulse_migrate/20260420000001_expand_normalized_query_column.rb
|
|
437
440
|
- db/rails_pulse_schema.rb
|
|
438
441
|
- exe/rails_pulse_server
|
|
439
442
|
- lib/generators/rails_pulse/base_methods.rb
|
|
@@ -498,13 +501,15 @@ files:
|
|
|
498
501
|
- vendor/css-zero/utilities.css
|
|
499
502
|
- vendor/css-zero/variables.css
|
|
500
503
|
- vendor/flatpickr.css
|
|
501
|
-
homepage: https://
|
|
504
|
+
homepage: https://railspulse.com
|
|
502
505
|
licenses:
|
|
503
506
|
- MIT
|
|
504
507
|
metadata:
|
|
505
508
|
allowed_push_host: https://rubygems.org
|
|
506
|
-
homepage_uri: https://
|
|
509
|
+
homepage_uri: https://railspulse.com
|
|
507
510
|
source_code_uri: https://github.com/railspulse/rails_pulse
|
|
511
|
+
changelog_uri: https://github.com/railspulse/rails_pulse/blob/main/CHANGELOG.md
|
|
512
|
+
documentation_uri: https://railspulse.com/documentation/installation
|
|
508
513
|
post_install_message:
|
|
509
514
|
rdoc_options: []
|
|
510
515
|
require_paths:
|
|
@@ -523,5 +528,5 @@ requirements: []
|
|
|
523
528
|
rubygems_version: 3.5.22
|
|
524
529
|
signing_key:
|
|
525
530
|
specification_version: 4
|
|
526
|
-
summary:
|
|
531
|
+
summary: Self-hosted performance monitoring engine for Rails apps.
|
|
527
532
|
test_files: []
|