rails_error_dashboard 0.4.0 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a69809a78e932510ab0212e0abd6021c925a28a7c5d80d69942ef1c80a7476db
4
- data.tar.gz: 4e62ac66ce28cd4a3c34ac4df4ac682a42656fe157b7918d044fddd3a9779f4e
3
+ metadata.gz: af7cf1b00931ba21cc10e507128ce90183cd2c0c707e47b16c2833ada7108fa7
4
+ data.tar.gz: e59567ed413e58003c45336006239562eeffdfd11330515a1faef711b7143f46
5
5
  SHA512:
6
- metadata.gz: a99bb20a9479fe2669426f6798ff368812834084a6c02a2db9739789a7b5a5a724bb08916e3891ee23a1de2d3df5539aed43f64e2791d4275c62de6c364ea5b9
7
- data.tar.gz: cb6a155bf3d4a62c21f51d7a7f878d5f5676947fcd441bfda08f36877e37e795093dc756f13d4318b8dcb4cc2ecacfac1e2cfcdcaf1df86481ed5f3fd9f70578
6
+ metadata.gz: 7446d9a051e2fa804b5090294217c0a678123fd8b1eb8720fff4b5ef8bf0bde48f87245333119b9b1c4101e036f3665b85b33b867ba8b2666182d6e2f7768cd7
7
+ data.tar.gz: 9b7d7140f5acebbc5c15c218716a81e03309e7590880b9648e5ac9b35276ecccd210fbfbc4837ae8bd88a75f936b12873f81f170b9c85b9da8997d5641602126
data/README.md CHANGED
@@ -22,7 +22,7 @@ gem 'rails_error_dashboard'
22
22
 
23
23
  **[rails-error-dashboard.anjan.dev](https://rails-error-dashboard.anjan.dev)** — Username: `gandalf` · Password: `youshallnotpass`
24
24
 
25
- > **Beta Software** — Functional and tested (2,100+ tests passing), but the API may change before v1.0. Supports Rails 7.0-8.1 and Ruby 3.2-4.0.
25
+ > **Beta Software** — Functional and tested (2,600+ tests passing), but the API may change before v1.0. Supports Rails 7.0-8.1 and Ruby 3.2-4.0.
26
26
 
27
27
  ### Screenshots
28
28
 
@@ -53,6 +53,8 @@ gem 'rails_error_dashboard'
53
53
  | SaaS pricing tiers and usage limits | Unlimited errors, unlimited projects |
54
54
  | Vendor lock-in with proprietary APIs | 100% open source, fully portable |
55
55
  | Complex SDK setup and external services | 5-minute Rails Engine installation |
56
+ | Pay extra for local variable capture (Sentry) | Local + instance variables included free |
57
+ | No tool detects silently rescued exceptions | Swallowed exception detection built in |
56
58
 
57
59
  ---
58
60
 
@@ -85,10 +87,12 @@ config.enable_breadcrumbs = true
85
87
  <details>
86
88
  <summary><strong>System Health Snapshot</strong></summary>
87
89
 
88
- Know your app's runtime state at the moment of failure — GC stats, process memory, thread count, connection pool utilization, and Puma thread stats captured automatically.
90
+ Know your app's runtime state at the moment of failure — GC stats, process memory, thread count, connection pool utilization, Puma thread stats, RubyVM cache health, and YJIT compilation stats captured automatically.
89
91
 
90
92
  - Sub-millisecond total snapshot, every metric individually rescue-wrapped
91
93
  - No ObjectSpace scanning, no Thread backtraces, no subprocess calls
94
+ - RubyVM.stat: constant cache invalidations, shape cache stats
95
+ - YJIT runtime stats: compiled iseqs, invalidation count, code region sizes
92
96
 
93
97
  ```ruby
94
98
  config.enable_system_health = true
@@ -181,6 +185,98 @@ Seven analysis engines built in:
181
185
  [Complete documentation →](docs/FEATURES.md#advanced-analytics-features)
182
186
  </details>
183
187
 
188
+ <details>
189
+ <summary><strong>Local Variable + Instance Variable Capture</strong></summary>
190
+
191
+ See the exact values of local variables and instance variables at the moment an exception was raised — the most valuable debugging context possible.
192
+
193
+ - TracePoint(`:raise`) captures locals and ivars before the stack unwinds
194
+ - Configurable limits: max variable count, nesting depth, string truncation length
195
+ - Sensitive data auto-filtered via Rails `filter_parameters` — passwords, tokens, and PII never stored
196
+ - Never stores Binding objects — values extracted immediately, Binding is GC'd
197
+ - Independent config flags: enable one or both
198
+
199
+ ![Local Variables](docs/images/local-variables.png)
200
+
201
+ ```ruby
202
+ config.enable_local_variables = true
203
+ config.enable_instance_variables = true
204
+ ```
205
+
206
+ [Complete documentation →](docs/FEATURES.md)
207
+ </details>
208
+
209
+ <details>
210
+ <summary><strong>Swallowed Exception Detection</strong></summary>
211
+
212
+ Detect exceptions that are raised but silently rescued — the hardest bugs to find. No other error tracker does this.
213
+
214
+ - Uses TracePoint(`:raise`) + TracePoint(`:rescue`) to track exception lifecycle
215
+ - Identifies code paths where exceptions are caught but never logged or re-raised
216
+ - Dashboard page at `/errors/swallowed_exceptions` shows detection counts, locations, and patterns
217
+ - Memory-bounded aggregation with background flush
218
+ - Requires Ruby 3.3+
219
+
220
+ ![Swallowed Exceptions](docs/images/swallowed-exceptions.png)
221
+
222
+ ```ruby
223
+ config.detect_swallowed_exceptions = true
224
+ ```
225
+
226
+ [Complete documentation →](docs/FEATURES.md)
227
+ </details>
228
+
229
+ <details>
230
+ <summary><strong>On-Demand Diagnostic Dump</strong></summary>
231
+
232
+ Snapshot your app's entire system state on demand — environment, GC stats, threads, connection pool, memory, job queue health, and more.
233
+
234
+ - Trigger via dashboard button or `rake rails_error_dashboard:diagnostic_dump`
235
+ - Dashboard page at `/errors/diagnostic_dumps` with full history
236
+ - Useful for debugging intermittent production issues without reproducing them
237
+
238
+ ![Diagnostic Dumps](docs/images/diagnostic-dumps.png)
239
+
240
+ ```ruby
241
+ config.enable_diagnostic_dump = true
242
+ ```
243
+
244
+ [Complete documentation →](docs/FEATURES.md)
245
+ </details>
246
+
247
+ <details>
248
+ <summary><strong>Rack Attack Event Tracking</strong></summary>
249
+
250
+ Track Rack Attack security events (throttles, blocklists, tracks) as breadcrumbs attached to errors, with a dedicated summary page.
251
+
252
+ - Captures throttle, blocklist, and track events automatically
253
+ - Dashboard page at `/errors/rack_attack_summary` with event breakdown
254
+ - Requires breadcrumbs to be enabled
255
+
256
+ ```ruby
257
+ config.enable_rack_attack_tracking = true
258
+ ```
259
+
260
+ [Complete documentation →](docs/FEATURES.md)
261
+ </details>
262
+
263
+ <details>
264
+ <summary><strong>Process Crash Capture</strong></summary>
265
+
266
+ Capture unhandled exceptions that crash the Ruby process via an `at_exit` hook — the last line of defense.
267
+
268
+ - Disk-based fallback: writes crash data to disk because the database may be unavailable during shutdown
269
+ - Imported automatically on next boot
270
+ - Captures exception details, backtrace, uptime, GC stats, thread count, and cause chain
271
+ - A self-hosted only feature — impossible for SaaS tools
272
+
273
+ ```ruby
274
+ config.enable_crash_capture = true
275
+ ```
276
+
277
+ [Complete documentation →](docs/FEATURES.md)
278
+ </details>
279
+
184
280
  <details>
185
281
  <summary><strong>Plugin System</strong></summary>
186
282
 
@@ -304,7 +400,7 @@ Built with **CQRS (Command/Query Responsibility Segregation)**:
304
400
 
305
401
  ## Testing
306
402
 
307
- 2,100+ tests covering unit, integration, and browser-based system tests.
403
+ 2,600+ tests covering unit, integration, and browser-based system tests.
308
404
 
309
405
  ```bash
310
406
  bundle exec rspec # Full suite
@@ -344,7 +440,7 @@ Built with [Rails](https://rubyonrails.org/) · UI by [Bootstrap 5](https://getb
344
440
 
345
441
  [![Contributors](https://contrib.rocks/image?repo=AnjanJ/rails_error_dashboard)](https://github.com/AnjanJ/rails_error_dashboard/graphs/contributors)
346
442
 
347
- Special thanks to [@bonniesimon](https://github.com/bonniesimon), [@gundestrup](https://github.com/gundestrup), and [@midwire](https://github.com/midwire). See [CONTRIBUTORS.md](CONTRIBUTORS.md) for the full list.
443
+ Special thanks to [@bonniesimon](https://github.com/bonniesimon), [@gundestrup](https://github.com/gundestrup), [@midwire](https://github.com/midwire), and [@RafaelTurtle](https://github.com/RafaelTurtle). See [CONTRIBUTORS.md](CONTRIBUTORS.md) for the full list.
348
444
 
349
445
  ---
350
446
 
@@ -334,6 +334,54 @@
334
334
  </code>
335
335
  </div>
336
336
  <% end %>
337
+
338
+ <% if health[:ruby_vm] %>
339
+ <% vm = health[:ruby_vm] %>
340
+ <div class="mb-1">
341
+ <small class="text-muted">VM Cache Invalidations:</small>
342
+ <% invals = vm[:constant_cache_invalidations].to_i %>
343
+ <code class="ms-1 <%= 'text-danger' if invals > 10_000 %>"><%= begin; number_with_delimiter(invals); rescue; invals; end %></code>
344
+ </div>
345
+ <div class="mb-1">
346
+ <small class="text-muted">VM Cache Misses:</small>
347
+ <code class="ms-1"><%= begin; number_with_delimiter(vm[:constant_cache_misses]); rescue; vm[:constant_cache_misses]; end %></code>
348
+ </div>
349
+ <% if vm[:shape_cache_size] %>
350
+ <div class="mb-1">
351
+ <small class="text-muted">Shape Cache Size:</small>
352
+ <code class="ms-1"><%= begin; number_with_delimiter(vm[:shape_cache_size]); rescue; vm[:shape_cache_size]; end %></code>
353
+ </div>
354
+ <% end %>
355
+ <% end %>
356
+
357
+ <% if health[:yjit] %>
358
+ <% yj = health[:yjit] %>
359
+ <% if yj[:compiled_iseq_count] || yj[:compiled_block_count] %>
360
+ <div class="mb-1">
361
+ <small class="text-muted">YJIT Compiled:</small>
362
+ <code class="ms-1"><%= yj[:compiled_iseq_count] %> iseqs / <%= yj[:compiled_block_count] %> blocks</code>
363
+ </div>
364
+ <% end %>
365
+ <% if yj[:invalidation_count] %>
366
+ <div class="mb-1">
367
+ <small class="text-muted">YJIT Invalidations:</small>
368
+ <% yj_invals = yj[:invalidation_count].to_i %>
369
+ <code class="ms-1 <%= 'text-danger' if yj_invals > 100 %>"><%= yj_invals %></code>
370
+ </div>
371
+ <% end %>
372
+ <% if yj[:code_region_size] %>
373
+ <div class="mb-1">
374
+ <small class="text-muted">YJIT Code Size:</small>
375
+ <code class="ms-1"><%= (yj[:code_region_size].to_f / 1024).round(1) %> KB</code>
376
+ </div>
377
+ <% end %>
378
+ <% if yj[:compile_time_ns] %>
379
+ <div class="mb-1">
380
+ <small class="text-muted">YJIT Compile Time:</small>
381
+ <code class="ms-1"><%= (yj[:compile_time_ns].to_f / 1_000_000).round(2) %> ms</code>
382
+ </div>
383
+ <% end %>
384
+ <% end %>
337
385
  </div>
338
386
  </div>
339
387
  <% end %>
@@ -34,6 +34,8 @@ module RailsErrorDashboard
34
34
  connection_pool: connection_pool_stats,
35
35
  puma: puma_stats,
36
36
  job_queue: job_queue_stats,
37
+ ruby_vm: ruby_vm_stats,
38
+ yjit: yjit_stats,
37
39
  captured_at: Time.current.iso8601
38
40
  }
39
41
  end
@@ -140,6 +142,37 @@ module RailsErrorDashboard
140
142
  rescue => e
141
143
  nil
142
144
  end
145
+
146
+ # RubyVM.stat — constant/method cache invalidation rates
147
+ # Keys vary by Ruby version; pass through full hash for forward-compat
148
+ # Ruby 3.2+: constant_cache_invalidations, constant_cache_misses,
149
+ # global_cvar_state, next_shape_id, shape_cache_size
150
+ def ruby_vm_stats
151
+ return nil unless defined?(RubyVM) && RubyVM.respond_to?(:stat)
152
+ RubyVM.stat
153
+ rescue => e
154
+ nil
155
+ end
156
+
157
+ # RubyVM::YJIT.runtime_stats — JIT compilation health
158
+ # Cherry-picks diagnostic keys (full hash has 30+ entries)
159
+ def yjit_stats
160
+ return nil unless defined?(RubyVM::YJIT) && RubyVM::YJIT.respond_to?(:enabled?) && RubyVM::YJIT.enabled?
161
+ raw = RubyVM::YJIT.runtime_stats
162
+ {
163
+ inline_code_size: raw[:inline_code_size],
164
+ code_region_size: raw[:code_region_size],
165
+ compiled_iseq_count: raw[:compiled_iseq_count],
166
+ compiled_block_count: raw[:compiled_block_count],
167
+ compile_time_ns: raw[:compile_time_ns],
168
+ invalidation_count: raw[:invalidation_count],
169
+ invalidate_method_lookup: raw[:invalidate_method_lookup],
170
+ invalidate_constant_state_bump: raw[:invalidate_constant_state_bump],
171
+ object_shape_count: raw[:object_shape_count]
172
+ }
173
+ rescue => e
174
+ nil
175
+ end
143
176
  end
144
177
  end
145
178
  end
@@ -1,3 +1,3 @@
1
1
  module RailsErrorDashboard
2
- VERSION = "0.4.0"
2
+ VERSION = "0.4.1"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_error_dashboard
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anjan Jagirdar
@@ -457,7 +457,7 @@ metadata:
457
457
  bug_tracker_uri: https://github.com/AnjanJ/rails_error_dashboard/issues
458
458
  funding_uri: https://buymeacoffee.com/anjanj
459
459
  post_install_message: "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n
460
- \ Rails Error Dashboard v0.4.0\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n\U0001F195
460
+ \ Rails Error Dashboard v0.4.1\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n\U0001F195
461
461
  First time? Quick start:\n rails generate rails_error_dashboard:install\n rails
462
462
  db:migrate\n # Add to config/routes.rb:\n mount RailsErrorDashboard::Engine
463
463
  => '/error_dashboard'\n\n\U0001F504 Upgrading from v0.1.x?\n rails db:migrate\n