pg_reports 0.5.4 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +69 -0
  3. data/README.md +123 -370
  4. data/app/controllers/pg_reports/dashboard_controller.rb +21 -21
  5. data/app/views/layouts/pg_reports/application.html.erb +135 -69
  6. data/app/views/pg_reports/dashboard/_show_modals.html.erb +22 -22
  7. data/app/views/pg_reports/dashboard/_show_scripts.html.erb +105 -55
  8. data/app/views/pg_reports/dashboard/_show_styles.html.erb +49 -11
  9. data/app/views/pg_reports/dashboard/index.html.erb +123 -114
  10. data/app/views/pg_reports/dashboard/show.html.erb +30 -26
  11. data/config/locales/en.yml +597 -0
  12. data/config/locales/ru.yml +562 -0
  13. data/config/locales/uk.yml +607 -0
  14. data/lib/pg_reports/compatibility.rb +63 -0
  15. data/lib/pg_reports/configuration.rb +2 -0
  16. data/lib/pg_reports/dashboard/reports_registry.rb +112 -5
  17. data/lib/pg_reports/definitions/indexes/fk_without_indexes.yml +30 -0
  18. data/lib/pg_reports/definitions/indexes/index_correlation.yml +31 -0
  19. data/lib/pg_reports/definitions/indexes/inefficient_indexes.yml +45 -0
  20. data/lib/pg_reports/definitions/queries/temp_file_queries.yml +39 -0
  21. data/lib/pg_reports/definitions/schema_analysis/always_null_columns.yml +31 -0
  22. data/lib/pg_reports/definitions/schema_analysis/unused_columns.yml +32 -0
  23. data/lib/pg_reports/definitions/system/wraparound_risk.yml +31 -0
  24. data/lib/pg_reports/definitions/tables/tables_without_pk.yml +28 -0
  25. data/lib/pg_reports/definitions/tables/unused_tables.yml +30 -0
  26. data/lib/pg_reports/definitions/tables/update_hotspots.yml +32 -0
  27. data/lib/pg_reports/engine.rb +6 -0
  28. data/lib/pg_reports/module_generator.rb +2 -1
  29. data/lib/pg_reports/modules/indexes.rb +3 -0
  30. data/lib/pg_reports/modules/queries.rb +1 -0
  31. data/lib/pg_reports/modules/schema_analysis.rb +261 -2
  32. data/lib/pg_reports/modules/system.rb +27 -0
  33. data/lib/pg_reports/modules/tables.rb +1 -0
  34. data/lib/pg_reports/query_monitor.rb +64 -36
  35. data/lib/pg_reports/report_definition.rb +20 -24
  36. data/lib/pg_reports/sql/indexes/fk_without_indexes.sql +23 -0
  37. data/lib/pg_reports/sql/indexes/index_correlation.sql +27 -0
  38. data/lib/pg_reports/sql/indexes/inefficient_indexes.sql +22 -0
  39. data/lib/pg_reports/sql/queries/temp_file_queries.sql +16 -0
  40. data/lib/pg_reports/sql/schema_analysis/always_null_columns.sql +25 -0
  41. data/lib/pg_reports/sql/schema_analysis/unused_columns.sql +36 -0
  42. data/lib/pg_reports/sql/system/checkpoint_stats.sql +20 -0
  43. data/lib/pg_reports/sql/system/checkpoint_stats_legacy.sql +19 -0
  44. data/lib/pg_reports/sql/system/wraparound_risk.sql +21 -0
  45. data/lib/pg_reports/sql/tables/tables_without_pk.sql +20 -0
  46. data/lib/pg_reports/sql/tables/unused_tables.sql +19 -0
  47. data/lib/pg_reports/sql/tables/update_hotspots.sql +26 -0
  48. data/lib/pg_reports/version.rb +1 -1
  49. data/lib/pg_reports.rb +5 -0
  50. metadata +24 -1
data/README.md CHANGED
@@ -24,165 +24,124 @@ A comprehensive PostgreSQL monitoring and analysis library for Rails application
24
24
  - 📊 **EXPLAIN ANALYZE** - Advanced query plan analyzer with problem detection and recommendations
25
25
  - 🔍 **SQL Query Monitoring** - Real-time monitoring of all executed SQL queries with source location tracking
26
26
  - 🔌 **Connection Pool Analytics** - Monitor pool usage, wait times, saturation warnings, and connection churn
27
+ - 🤖 **AI Prompt Export** - Copy a ready-to-paste prompt for Claude Code, Cursor, or Codex with problem context and report data
27
28
  - 🗑️ **Migration Generator** - Generate Rails migrations to drop unused indexes
28
29
 
29
30
  ## Installation
30
31
 
31
- Add to your Gemfile:
32
-
33
32
  ```ruby
33
+ # Gemfile
34
34
  gem "pg_reports"
35
-
36
- # Optional: for Telegram support
37
- gem "telegram-bot-ruby"
35
+ gem "telegram-bot-ruby" # optional, for Telegram delivery
38
36
  ```
39
37
 
40
- Run:
41
-
42
38
  ```bash
43
39
  bundle install
44
40
  ```
45
41
 
46
- ## Quick Start
47
-
48
- ### Mount the Dashboard
49
-
50
- Add to your `config/routes.rb`:
42
+ Mount the dashboard:
51
43
 
52
44
  ```ruby
45
+ # config/routes.rb
53
46
  Rails.application.routes.draw do
54
- # Mount in development only (recommended)
55
47
  if Rails.env.development?
56
48
  mount PgReports::Engine, at: "/pg_reports"
57
49
  end
58
50
 
59
- # Or with authentication
60
- authenticate :user, ->(u) { u.admin? } do
61
- mount PgReports::Engine, at: "/pg_reports"
62
- end
51
+ # Or with authentication:
52
+ # authenticate :user, ->(u) { u.admin? } do
53
+ # mount PgReports::Engine, at: "/pg_reports"
54
+ # end
63
55
  end
64
56
  ```
65
57
 
66
- Visit `http://localhost:3000/pg_reports` to access the dashboard.
58
+ Visit `http://localhost:3000/pg_reports`.
59
+
60
+ For query analysis, also enable `pg_stat_statements` — see [setup](#pg_stat_statements-setup) below.
67
61
 
68
- ### Use in Console or Code
62
+ ## Usage
69
63
 
70
64
  ```ruby
71
- # Get slow queries
65
+ # In console or code
72
66
  PgReports.slow_queries.display
67
+ PgReports.unused_indexes.each { |row| puts row["index_name"] }
73
68
 
74
- # Get unused indexes
75
- report = PgReports.unused_indexes
76
- report.each { |row| puts row["index_name"] }
69
+ # Export
70
+ report = PgReports.expensive_queries
71
+ report.to_text
72
+ report.to_csv
73
+ report.to_a
77
74
 
78
- # Export to different formats
79
- report.to_text # Plain text
80
- report.to_csv # CSV
81
- report.to_a # Array of hashes
82
-
83
- # Send to Telegram
84
- PgReports.expensive_queries.send_to_telegram
85
-
86
- # Health report
87
- PgReports.health_report.display
75
+ # Telegram
76
+ PgReports.slow_queries.send_to_telegram
88
77
  ```
89
78
 
90
- ## Configuration
79
+ **[Full list of reports →](docs/reports.md)**
91
80
 
92
- Create an initializer `config/initializers/pg_reports.rb`:
81
+ ## Configuration
93
82
 
94
83
  ```ruby
84
+ # config/initializers/pg_reports.rb
95
85
  PgReports.configure do |config|
96
86
  # Telegram (optional)
97
87
  config.telegram_bot_token = ENV["PG_REPORTS_TELEGRAM_TOKEN"]
98
- config.telegram_chat_id = ENV["PG_REPORTS_TELEGRAM_CHAT_ID"]
88
+ config.telegram_chat_id = ENV["PG_REPORTS_TELEGRAM_CHAT_ID"]
99
89
 
100
- # Query thresholds
101
- config.slow_query_threshold_ms = 100 # Queries slower than this
102
- config.heavy_query_threshold_calls = 1000 # Queries with more calls
103
- config.expensive_query_threshold_ms = 10000 # Total time threshold
90
+ # Thresholds
91
+ config.slow_query_threshold_ms = 100
92
+ config.heavy_query_threshold_calls = 1000
93
+ config.expensive_query_threshold_ms = 10_000
94
+ config.unused_index_threshold_scans = 50
95
+ config.bloat_threshold_percent = 20
96
+ config.dead_rows_threshold = 10_000
104
97
 
105
- # Index thresholds
106
- config.unused_index_threshold_scans = 50 # Index with fewer scans
98
+ # Output
99
+ config.max_query_length = 200
107
100
 
108
- # Table thresholds
109
- config.bloat_threshold_percent = 20 # Tables with more bloat
110
- config.dead_rows_threshold = 10000 # Dead rows needing vacuum
111
-
112
- # Output settings
113
- config.max_query_length = 200 # Truncate queries in text output
114
-
115
- # Dashboard authentication (optional)
116
- config.dashboard_auth = -> {
101
+ # Auth (optional)
102
+ config.dashboard_auth = -> {
117
103
  authenticate_or_request_with_http_basic do |user, pass|
118
- user == "admin" && pass == "secret"
104
+ user == ENV["PG_REPORTS_USER"] && pass == ENV["PG_REPORTS_PASSWORD"]
119
105
  end
120
106
  }
121
107
 
122
- # External fonts (Google Fonts)
123
- # Default: false (no external requests)
124
- config.load_external_fonts = ENV["PG_REPORTS_LOAD_EXTERNAL_FONTS"] == "true"
125
- # or simply:
126
- # config.load_external_fonts = true
127
-
108
+ # Google Fonts (default: false — no external requests)
109
+ config.load_external_fonts = false
128
110
  end
129
111
  ```
130
112
 
131
- ### Query Execution Security
132
-
133
- ⚠️ **Security Warning**: By default, the dashboard **does not allow** executing raw SQL queries via "Execute Query" and "EXPLAIN ANALYZE" buttons. This prevents accidental or malicious query execution in production environments.
113
+ <details>
114
+ <summary><strong>Locale (EN / RU / UK)</strong></summary>
134
115
 
135
- To enable query execution (only in secure environments):
136
-
137
- ```ruby
138
- PgReports.configure do |config|
139
- # Enable query execution from dashboard (default: false)
140
- config.allow_raw_query_execution = true
141
- end
142
- ```
116
+ PgReports follows your application's `I18n.locale`. Set it the way you set it for the rest of the app — there's no PgReports-specific knob. The dashboard supports `en`, `ru`, and `uk` out of the box.
143
117
 
144
- Or via environment variable:
118
+ </details>
145
119
 
146
- ```bash
147
- export PG_REPORTS_ALLOW_RAW_QUERY_EXECUTION=true
148
- ```
120
+ <details>
121
+ <summary><strong>Raw query execution (EXPLAIN ANALYZE / Execute Query)</strong></summary>
149
122
 
150
- **Recommended setup** (only enable in development/staging):
123
+ ⚠️ Disabled by default. The dashboard's "Execute Query" and "EXPLAIN ANALYZE" buttons require this opt-in.
151
124
 
152
125
  ```ruby
153
- # config/initializers/pg_reports.rb
154
126
  PgReports.configure do |config|
155
- # Only allow query execution in development/staging
156
127
  config.allow_raw_query_execution = Rails.env.development? || Rails.env.staging?
157
-
158
- # Combine with authentication for additional security
159
- config.dashboard_auth = -> {
160
- authenticate_or_request_with_http_basic do |user, pass|
161
- user == ENV["PG_REPORTS_USER"] && pass == ENV["PG_REPORTS_PASSWORD"]
162
- end
163
- }
164
128
  end
165
129
  ```
166
130
 
167
- When disabled:
168
- - API endpoints `/execute_query` and `/explain_analyze` return 403 Forbidden
169
- - UI buttons are disabled with explanation tooltips
170
- - Existing safety measures (SELECT/SHOW only, automatic LIMIT) still apply when enabled
131
+ </details>
171
132
 
172
- ## Query Source Tracking
133
+ <details>
134
+ <summary><strong>Query source tracking (Marginalia / Rails query logs)</strong></summary>
173
135
 
174
- PgReports automatically parses query annotations to show **where queries originated**. Works with:
136
+ PgReports parses query annotations to show **where queries originated**.
175
137
 
176
- ### Marginalia (recommended)
177
-
178
- If you use [marginalia](https://github.com/basecamp/marginalia), PgReports will automatically parse and display controller/action info in the **source** column.
138
+ [Marginalia](https://github.com/basecamp/marginalia):
179
139
 
180
140
  ```ruby
181
- # Gemfile
182
- gem 'marginalia'
141
+ gem "marginalia"
183
142
  ```
184
143
 
185
- ### Rails 7+ Query Logs
144
+ Rails 7+ query logs:
186
145
 
187
146
  ```ruby
188
147
  # config/application.rb
@@ -190,98 +149,25 @@ config.active_record.query_log_tags_enabled = true
190
149
  config.active_record.query_log_tags = [:controller, :action]
191
150
  ```
192
151
 
193
- ## Available Reports
194
-
195
- ### Queries (requires pg_stat_statements)
196
-
197
- | Method | Description |
198
- |--------|-------------|
199
- | `slow_queries` | Queries with high mean execution time |
200
- | `heavy_queries` | Most frequently called queries |
201
- | `expensive_queries` | Queries consuming most total time |
202
- | `missing_index_queries` | Queries potentially missing indexes |
203
- | `low_cache_hit_queries` | Queries with poor cache utilization |
204
- | `all_queries` | All query statistics |
205
- | `reset_statistics!` | Reset pg_stat_statements data |
206
-
207
- ### Indexes
208
-
209
- | Method | Description |
210
- |--------|-------------|
211
- | `unused_indexes` | Indexes rarely or never scanned |
212
- | `duplicate_indexes` | Redundant indexes |
213
- | `invalid_indexes` | Indexes that failed to build |
214
- | `missing_indexes` | Tables potentially missing indexes |
215
- | `index_usage` | Index scan statistics |
216
- | `bloated_indexes` | Indexes with high bloat |
217
- | `index_sizes` | Index disk usage |
218
-
219
- ### Tables
220
-
221
- | Method | Description |
222
- |--------|-------------|
223
- | `table_sizes` | Table disk usage |
224
- | `bloated_tables` | Tables with high dead tuple ratio |
225
- | `vacuum_needed` | Tables needing vacuum |
226
- | `row_counts` | Table row counts |
227
- | `cache_hit_ratios` | Table cache statistics |
228
- | `seq_scans` | Tables with high sequential scans |
229
- | `recently_modified` | Tables with recent activity |
230
-
231
- ### Connections
232
-
233
- | Method | Description |
234
- |--------|-------------|
235
- | `active_connections` | Current database connections |
236
- | `connection_stats` | Connection statistics by state |
237
- | `long_running_queries` | Queries running for extended period |
238
- | `blocking_queries` | Queries blocking others |
239
- | `locks` | Current database locks |
240
- | `idle_connections` | Idle connections |
241
- | `pool_usage` | 🆕 Connection pool utilization analysis |
242
- | `pool_wait_times` | 🆕 Resource wait time analysis |
243
- | `pool_saturation` | 🆕 Pool health warnings with recommendations |
244
- | `connection_churn` | 🆕 Connection lifecycle and churn rate analysis |
245
- | `kill_connection(pid)` | Terminate a backend process |
246
- | `cancel_query(pid)` | Cancel a running query |
247
-
248
- ### System
249
-
250
- | Method | Description |
251
- |--------|-------------|
252
- | `database_sizes` | Size of all databases |
253
- | `settings` | PostgreSQL configuration |
254
- | `extensions` | Installed extensions |
255
- | `activity_overview` | Current activity summary |
256
- | `cache_stats` | Database cache statistics |
257
- | `pg_stat_statements_available?` | Check if extension is ready |
258
- | `enable_pg_stat_statements!` | Create the extension |
259
-
260
- ## pg_stat_statements Setup
261
-
262
- For query analysis, you need to enable `pg_stat_statements`:
152
+ Either form is auto-detected; controller/action and file:line appear in the **source** column on report rows.
153
+
154
+ </details>
155
+
156
+ ## pg_stat_statements setup
263
157
 
264
158
  1. Edit `postgresql.conf`:
265
159
  ```
266
160
  shared_preload_libraries = 'pg_stat_statements'
267
161
  pg_stat_statements.track = all
268
162
  ```
163
+ 2. Restart PostgreSQL: `sudo systemctl restart postgresql`
164
+ 3. Create the extension (via dashboard button or `PgReports.enable_pg_stat_statements!`).
269
165
 
270
- 2. Restart PostgreSQL:
271
- ```bash
272
- sudo systemctl restart postgresql
273
- ```
166
+ > PgReports does **not** require the `pg_read_all_settings` role — extension availability is detected directly. Works with CloudnativePG, managed databases, and other restricted environments.
274
167
 
275
- 3. Create extension (via dashboard or console):
276
- ```ruby
277
- PgReports.enable_pg_stat_statements!
278
- ```
168
+ ## Report object
279
169
 
280
- > **Note**: PgReports does **not** require the `pg_read_all_settings` role. It detects `pg_stat_statements` availability by directly querying the extension, making it compatible with CloudnativePG, managed databases, and other environments with restricted permissions.
281
-
282
- ## Report Object
283
-
284
- Every method returns a `PgReports::Report` object:
170
+ Every method returns a `PgReports::Report`:
285
171
 
286
172
  ```ruby
287
173
  report = PgReports.slow_queries
@@ -311,247 +197,114 @@ report.map { |row| row["query"] }
311
197
  report.select { |row| row["calls"] > 100 }
312
198
  ```
313
199
 
314
- ## Web Dashboard
315
-
316
- The dashboard provides:
317
-
318
- - 📊 Overview of all report categories with descriptions
319
- - ⚡ One-click report execution
320
- - 🔍 Filter parameters - adjust thresholds and limits on the fly
321
- - 🔍 Expandable rows for full query text
322
- - 📋 Copy query to clipboard
323
- - 📥 Download in multiple formats (TXT, CSV, JSON)
324
- - 📨 Send to Telegram
325
- - 🔧 pg_stat_statements management
326
- - 🔄 Sortable columns - click headers to sort ascending/descending
327
- - 📌 Save records for comparison - track before/after optimization results
328
- - 📊 EXPLAIN ANALYZE - run query plans directly from the dashboard
329
- - 🗑️ Migration generator - create Rails migrations to drop unused indexes
330
- - 🔗 IDE integration - click source locations to open in your IDE
331
-
332
- ### IDE Integration
200
+ ## Dashboard features
333
201
 
334
- Click on source locations in reports to open the file directly in your IDE. Supported IDEs:
202
+ The dashboard provides one-click execution, sortable columns, expandable rows, filter parameters, multi-format export, Telegram delivery, and pg_stat_statements management.
335
203
 
336
- - **VS Code (WSL)** - for Windows Subsystem for Linux
337
- - **VS Code** - direct path for native Linux/macOS
338
- - **RubyMine**
339
- - **IntelliJ IDEA**
340
- - **Cursor (WSL)** - for Windows Subsystem for Linux
341
- - **Cursor**
204
+ <details>
205
+ <summary><strong>EXPLAIN ANALYZE query plan analyzer</strong></summary>
342
206
 
343
- Use the ⚙️ button to set your default IDE and skip the selection menu.
207
+ Expand a row with a query, click **📊 EXPLAIN ANALYZE**. Shows:
344
208
 
345
- ### Filter Parameters
209
+ - **Status indicator** (🟢🟡🔴) — overall query health
210
+ - **Key metrics** — planning/execution time, cost, rows
211
+ - **Detected problems** — sequential scans on large tables, high-cost ops, sorts spilling to disk, slow sorts (>1s), inaccurate row estimates (>10× off), slow execution
212
+ - **Recommendations** for each issue
213
+ - **Color-coded plan** — node types tinted by performance impact (green: efficient, blue: normal, yellow: potential issue)
214
+ - **Line annotations** highlighting problems on specific plan lines
346
215
 
347
- Each report page includes a collapsible "Параметры фильтрации" (Filter Parameters) section where you can:
216
+ Queries from `pg_stat_statements` with parameter placeholders (`$1`, `$2`) prompt for parameter values before analysis.
348
217
 
349
- 1. **Adjust thresholds** - Override default thresholds (e.g., slow query threshold, unused index scans)
350
- 2. **Change limits** - Set the maximum number of results to display
351
- 3. **Real-time refresh** - Reports automatically refresh when you change parameters
218
+ Requires `config.allow_raw_query_execution = true`.
352
219
 
353
- Parameters show their current configured values and allow you to experiment with different thresholds without changing your configuration file.
220
+ </details>
354
221
 
355
- ### Save Records for Comparison
222
+ <details>
223
+ <summary><strong>SQL Query Monitor — real-time query capture</strong></summary>
356
224
 
357
- When optimizing queries, you can save records to compare before/after results:
225
+ Live capture of all SQL executed by your Rails app. Click **▶ Start Monitoring**, run any operation, watch the queries appear with:
358
226
 
359
- 1. Expand a row and click "📌 Save for Comparison"
360
- 2. Saved records appear above the results table
361
- 3. Click saved records to expand and see all details
362
- 4. Clear all or remove individual saved records
227
+ - SQL with syntax highlighting
228
+ - Duration (color-coded: 🟢 <10ms, 🟡 <100ms, 🔴 >100ms)
229
+ - Source location with click-to-IDE
230
+ - Timestamp
363
231
 
364
- Records are stored in browser localStorage per report type.
365
-
366
- ### EXPLAIN ANALYZE
367
-
368
- The advanced query analyzer provides intelligent problem detection and recommendations:
369
-
370
- 1. Expand a row with a query
371
- 2. Click "📊 EXPLAIN ANALYZE"
372
- 3. View the color-coded execution plan with:
373
- - **🟢🟡🔴 Status indicator** - Overall query health assessment
374
- - **📈 Key metrics** - Planning/Execution time, Cost, Rows
375
- - **⚠️ Detected problems** - Sequential scans, high costs, slow sorts, estimation errors
376
- - **💡 Recommendations** - Actionable advice for each issue
377
- - **🎨 Colored plan** - Node types color-coded by performance impact:
378
- - 🟢 Green: Efficient operations (Index Scan, Hash Join)
379
- - 🔵 Blue: Normal operations (Bitmap Scan, HashAggregate)
380
- - 🟡 Yellow: Potential issues (Seq Scan, Sort, Materialize)
381
- - **Line-by-line annotations** - Problems highlighted on specific plan lines
382
-
383
- **Problem Detection:**
384
- - Sequential scans on large tables (> 1000 rows)
385
- - High-cost operations (> 10,000 cost units)
386
- - Sorts spilling to disk
387
- - Slow sort operations (> 1s)
388
- - Inaccurate row estimates (> 10x off)
389
- - Slow execution/planning times
390
-
391
- > Note: Queries with parameter placeholders ($1, $2) from pg_stat_statements require parameter input before analysis.
392
-
393
- ### SQL Query Monitoring
394
-
395
- Monitor all SQL queries executed in your Rails application in real-time:
396
-
397
- 1. Visit the dashboard at `/pg_reports`
398
- 2. Click **"▶ Start Monitoring"** button in the SQL Query Monitor panel
399
- 3. Execute operations in your application (web requests, console commands, background jobs)
400
- 4. View captured queries in the dashboard with:
401
- - **SQL text** - Formatted with syntax highlighting
402
- - **Execution duration** - Color-coded: 🟢 green (< 10ms), 🟡 yellow (< 100ms), 🔴 red (> 100ms)
403
- - **Source location** - File:line with click-to-open in IDE
404
- - **Timestamp** - When the query was executed
405
- 5. Click **"⏹ Stop Monitoring"** when done
406
-
407
- **Features:**
408
- - Uses Rails' built-in **ActiveSupport::Notifications** (`sql.active_record` events)
409
- - Global monitoring session (shared by all dashboard users)
410
- - Automatically filters internal queries (SCHEMA, CACHE, pg_reports' own queries)
411
- - Keeps last N queries in memory (configurable, default 100)
412
- - 2-second auto-refresh while monitoring is active
413
- - Session-based tracking with unique IDs
414
- - Logged to `log/pg_reports.log` in JSON Lines format
415
-
416
- **Configuration:**
232
+ Built on `ActiveSupport::Notifications` (`sql.active_record`). Filters internal queries (SCHEMA / CACHE / pg_reports' own). Logged to `log/pg_reports.log` (JSON Lines). Configurable buffer size and backtrace filter:
417
233
 
418
234
  ```ruby
419
235
  PgReports.configure do |config|
420
- # Query monitoring
421
236
  config.query_monitor_log_file = Rails.root.join("log", "custom_monitor.log")
422
- config.query_monitor_max_queries = 200 # Keep last 200 queries (default: 100)
423
-
424
- # Custom backtrace filtering to show only application code
425
- config.query_monitor_backtrace_filter = ->(location) {
426
- !location.path.match?(%r{/(gems|ruby|railties)/})
427
- }
237
+ config.query_monitor_max_queries = 200
238
+ config.query_monitor_backtrace_filter = ->(loc) { !loc.path.match?(%r{/(gems|ruby|railties)/}) }
428
239
  end
429
240
  ```
430
241
 
431
- **Log Format:**
242
+ Use cases: debugging N+1, identifying slow queries during feature development, tracking down unexpected queries, teaching ActiveRecord behavior.
432
243
 
433
- The log file uses JSON Lines format (one JSON object per line):
244
+ </details>
434
245
 
435
- ```json
436
- {"type":"session_start","session_id":"550e8400-e29b-41d4-a716-446655440000","timestamp":"2024-02-07T10:30:00Z"}
437
- {"type":"query","session_id":"550e8400-e29b-41d4-a716-446655440000","sql":"SELECT * FROM users WHERE id = 1","duration_ms":2.34,"name":"User Load","source_location":{"file":"app/controllers/users_controller.rb","line":15,"method":"show"},"timestamp":"2024-02-07T10:30:01Z"}
438
- {"type":"session_end","session_id":"550e8400-e29b-41d4-a716-446655440000","timestamp":"2024-02-07T10:35:00Z"}
439
- ```
440
-
441
- **Use Cases:**
442
- - 🐛 Debug N+1 query problems during development
443
- - 🐌 Identify slow queries in real-time
444
- - 🔍 Track down source of unexpected queries
445
- - 📊 Monitor query patterns during feature development
446
- - 📚 Teaching tool for understanding ActiveRecord behavior
447
-
448
- ### Migration Generator
449
-
450
- For unused or invalid indexes, generate Rails migrations:
451
-
452
- 1. Go to Indexes → Unused Indexes
453
- 2. Expand a row and click "🗑️ Generate Migration"
454
- 3. Copy the code or create the file directly
455
- 4. The file opens automatically in your configured IDE
456
-
457
- ### Connection Pool Analytics
246
+ <details>
247
+ <summary><strong>Connection pool analytics</strong></summary>
458
248
 
459
- Monitor your connection pool health with specialized reports:
249
+ Four specialized reports under the **Connections** category:
460
250
 
461
- **Pool Usage** - Real-time utilization metrics:
462
- - Total, active, idle connections per database
463
- - Pool utilization percentage with 🟢🟡🔴 indicators
464
- - Idle in transaction connections (resource waste)
465
- - Available connection capacity
466
-
467
- **Wait Times** - Identify resource bottlenecks:
468
- - Queries waiting for locks, I/O, or network
469
- - Wait event types (ClientRead, Lock, IO)
470
- - Wait duration with severity thresholds
471
- - Helps diagnose contention issues
472
-
473
- **Pool Saturation** - Health warnings with actionable recommendations:
474
- - Overall pool metrics with status indicators
475
- - Automatic severity assessment (Normal/Elevated/Warning/Critical)
476
- - Context-aware recommendations for each metric
477
- - Detects approaching exhaustion, high idle transactions
478
-
479
- **Connection Churn** - Lifecycle analysis:
480
- - Connection age distribution by application
481
- - Short-lived connection detection (< 10 seconds)
482
- - Churn rate percentage calculation
483
- - Identifies missing/misconfigured connection pooling
251
+ - **Pool Usage** total/active/idle per database, utilization %, idle-in-transaction count, available capacity
252
+ - **Wait Times** queries waiting on locks/IO/network with wait event types and severity
253
+ - **Pool Saturation** auto-classified (Normal / Elevated / Warning / Critical) with context-aware recommendations
254
+ - **Connection Churn** age distribution by application, short-lived (<10s) detection, churn-rate calculation, missing-pooling diagnosis
484
255
 
485
256
  ```ruby
486
- # Console usage
487
257
  PgReports.pool_usage.display
488
258
  PgReports.pool_saturation.display
489
259
  PgReports.connection_churn.display
490
260
  ```
491
261
 
492
- ### Authentication
262
+ </details>
493
263
 
494
- ```ruby
495
- PgReports.configure do |config|
496
- # HTTP Basic Auth
497
- config.dashboard_auth = -> {
498
- authenticate_or_request_with_http_basic do |user, pass|
499
- user == ENV["ADMIN_USER"] && pass == ENV["ADMIN_PASS"]
500
- end
501
- }
264
+ <details>
265
+ <summary><strong>IDE integration & migration generator</strong></summary>
502
266
 
503
- # Or use Devise
504
- config.dashboard_auth = -> {
505
- redirect_to main_app.root_path unless current_user&.admin?
506
- }
507
- end
508
- ```
267
+ Click any source location (file:line) in a report to open it in your IDE. Supported: VS Code, VS Code (WSL), RubyMine, IntelliJ IDEA, Cursor, Cursor (WSL). Use the ⚙️ button to set your default and skip the menu.
509
268
 
510
- ### External Fonts
269
+ For unused or invalid indexes, the dashboard generates a Rails migration: expand the row → **🗑️ Generate Migration** → copy the code or create the file directly (opens in your default IDE).
511
270
 
512
- By default, PgReports does **not** load external fonts.
271
+ </details>
513
272
 
514
- ```ruby
515
- PgReports.configure do |config|
516
- # Enable loading Google Fonts (optional)
517
- config.load_external_fonts = true
518
- end
519
- ```
273
+ <details>
274
+ <summary><strong>Save records for comparison</strong></summary>
520
275
 
521
- ## Telegram Integration
276
+ When optimizing queries, click **📌 Save for Comparison** on any expanded row. Saved records persist in browser localStorage per report type and appear above the results table for before/after comparison.
522
277
 
523
- 1. Create a bot via [@BotFather](https://t.me/BotFather)
524
- 2. Get your chat ID (add [@userinfobot](https://t.me/userinfobot) to get it)
525
- 3. Configure:
278
+ </details>
279
+
280
+ <details>
281
+ <summary><strong>AI prompt export</strong></summary>
282
+
283
+ The Export dropdown includes **Copy Prompt** (visible on actionable reports). It assembles a ready-to-paste prompt with problem description, fix instructions, and the actual report data — formatted for Claude Code, Cursor, Codex, or any code-aware AI assistant.
284
+
285
+ </details>
286
+
287
+ ## Telegram
526
288
 
527
289
  ```ruby
528
290
  PgReports.configure do |config|
529
291
  config.telegram_bot_token = "123456:ABC-DEF..."
530
- config.telegram_chat_id = "-1001234567890"
292
+ config.telegram_chat_id = "-1001234567890"
531
293
  end
532
- ```
533
-
534
- 4. Send reports:
535
294
 
536
- ```ruby
537
295
  PgReports.slow_queries.send_to_telegram
538
296
  PgReports.health_report.send_to_telegram_as_file
539
297
  ```
540
298
 
299
+ Get a bot token from [@BotFather](https://t.me/BotFather) and your chat ID from [@userinfobot](https://t.me/userinfobot).
300
+
541
301
  ## Development
542
302
 
543
303
  ```bash
544
- # Clone the repo
545
304
  git clone https://github.com/yourusername/pg_reports
546
305
  cd pg_reports
547
-
548
- # Install dependencies
549
306
  bundle install
550
-
551
- # Run tests
552
307
  bundle exec rspec
553
-
554
- # Run linter
555
308
  bundle exec rubocop
556
309
  ```
557
310
 
@@ -559,14 +312,14 @@ bundle exec rubocop
559
312
 
560
313
  1. Fork it
561
314
  2. Create your feature branch (`git checkout -b feature/my-feature`)
562
- 3. Commit your changes (`git commit -am 'Add my feature'`)
563
- 4. Push to the branch (`git push origin feature/my-feature`)
315
+ 3. Commit your changes
316
+ 4. Push to the branch
564
317
  5. Create a Pull Request
565
318
 
566
319
  ## License
567
320
 
568
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
321
+ MIT. See [LICENSE.txt](LICENSE.txt).
569
322
 
570
323
  ## Acknowledgments
571
324
 
572
- Inspired by [rails-pg-extras](https://github.com/pawurb/rails-pg-extras) and built with ❤️ for the Rails community.
325
+ Inspired by [rails-pg-extras](https://github.com/pawurb/rails-pg-extras). UI built with [Claude](https://www.anthropic.com/claude) by Anthropic.