rails_trace_viewer 0.1.0 → 0.1.2
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 +8 -0
- data/app/channels/rails_trace_viewer/trace_channel.rb +1 -1
- data/app/controllers/rails_trace_viewer/traces_controller.rb +2 -0
- data/app/views/rails_trace_viewer/traces/show.html.erb +59 -26
- data/lib/rails_trace_viewer/engine.rb +34 -17
- data/lib/rails_trace_viewer/subscribers/method_subscriber.rb +6 -0
- data/lib/rails_trace_viewer/subscribers/view_subscriber.rb +49 -22
- data/lib/rails_trace_viewer/version.rb +1 -1
- data/lib/rails_trace_viewer.rb +10 -1
- metadata +4 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5ff338c196864dc973331301d6fbdbbc50de7ab3940ae012458f73bdfe5b0183
|
|
4
|
+
data.tar.gz: b9b535f0575a9972380c9fca35faa82305298b23c64b524182c2ed01df92bc51
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 824699687247af12dc1abf2fd5be2c5bc45e12896606042c531fec5a6d6918a9b4ae06b7c8990b32ce3cbdb1cf77d5e7a6769e34261c633eef3eec8fb413ce22
|
|
7
|
+
data.tar.gz: b140ba6bc597e257e286ed3c1d092660041ca5003b5b278dee51d962436ab54a566e01b4d5d331c4c7a5d444024e66691833800b3589a0d6e861297fcdabc4c6
|
data/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
An educational and debugging tool for Ruby on Rails to visualize the request lifecycle in real-time.
|
|
4
4
|
|
|
5
|
+
[](https://youtu.be/Zwg3rROyaH0)
|
|
6
|
+
|
|
5
7
|
Rails Trace Viewer provides a beautiful, interactive Call Stack Tree that visualizes how your Rails application processes requests. It traces the flow from the Controller through Models, Views, SQL Queries, and even across process boundaries into Sidekiq Background Jobs.
|
|
6
8
|
|
|
7
9
|
---
|
|
@@ -95,6 +97,7 @@ Rails.application.routes.draw do
|
|
|
95
97
|
end
|
|
96
98
|
```
|
|
97
99
|
|
|
100
|
+
**🛑 Need to disable the gem?** Simply comment out the `mount RailsTraceViewer::Engine => '/rails_trace_viewer'` line above. The gem detects this and **shuts down completely** (Zero Overhead).
|
|
98
101
|
---
|
|
99
102
|
|
|
100
103
|
### 3. Configure Action Cable (Redis)
|
|
@@ -197,6 +200,11 @@ The viewer uses specific colors to represent different parts of the call stack:
|
|
|
197
200
|
|
|
198
201
|
## 🛠️ Troubleshooting
|
|
199
202
|
|
|
203
|
+
### **"My app hangs or loads very slowly when the viewer is open."**
|
|
204
|
+
* **Check your Web Server:** Ensure you are using a multi-threaded server like **Puma**.
|
|
205
|
+
* **Why?** This gem uses ActionCable (WebSockets). Single-threaded servers (like **WEBrick**) cannot handle the persistent WebSocket connection and regular HTTP requests at the same time, causing the app to block.
|
|
206
|
+
* **Fix:** Add `gem 'puma'` to your Gemfile and remove `gem 'webrick'`.
|
|
207
|
+
|
|
200
208
|
### **"I see the Enqueue node, but the trace stops there."**
|
|
201
209
|
- Ensure **Sidekiq is running**.
|
|
202
210
|
- Ensure `config/cable.yml` uses **Redis**, not the async adapter.
|
|
@@ -19,9 +19,27 @@
|
|
|
19
19
|
overflow: hidden;
|
|
20
20
|
cursor: grab;
|
|
21
21
|
background: #f8fafc;
|
|
22
|
+
position: relative;
|
|
22
23
|
}
|
|
23
24
|
.trace-container:active { cursor: grabbing; }
|
|
24
25
|
|
|
26
|
+
/* Empty State Styling */
|
|
27
|
+
.empty-state {
|
|
28
|
+
position: absolute;
|
|
29
|
+
top: 50%;
|
|
30
|
+
left: 50%;
|
|
31
|
+
transform: translate(-50%, -50%);
|
|
32
|
+
text-align: center;
|
|
33
|
+
transition: opacity 0.5s ease-out, visibility 0.5s;
|
|
34
|
+
opacity: 1;
|
|
35
|
+
visibility: visible;
|
|
36
|
+
pointer-events: none;
|
|
37
|
+
}
|
|
38
|
+
.empty-state.hidden {
|
|
39
|
+
opacity: 0;
|
|
40
|
+
visibility: hidden;
|
|
41
|
+
}
|
|
42
|
+
|
|
25
43
|
/* Nodes */
|
|
26
44
|
.node rect { rx: 6; ry: 6; stroke-width: 1px; transition: all 0.2s; filter: drop-shadow(0 2px 4px rgb(0 0 0 / 0.05)); }
|
|
27
45
|
.node:hover rect { stroke-width: 2px; stroke: #6366f1; cursor: pointer; transform: translateY(-1px); }
|
|
@@ -95,7 +113,7 @@
|
|
|
95
113
|
<button id="clear-btn" class="px-3 py-2 text-sm font-medium text-red-600 bg-white border border-slate-300 rounded-md hover:bg-red-50 flex items-center gap-2 transition-all active:scale-95">
|
|
96
114
|
<span>🗑</span> Clear
|
|
97
115
|
</button>
|
|
98
|
-
<button id="learn-btn" class="px-3 py-2 text-sm font-medium text-indigo-600 bg-
|
|
116
|
+
<button id="learn-btn" class="px-3 py-2 text-sm font-medium text-indigo-600 bg-white border border-indigo-200 rounded-md hover:bg-indigo-100 flex items-center gap-2 transition-all active:scale-95">
|
|
99
117
|
<span>📖</span> Learn
|
|
100
118
|
</button>
|
|
101
119
|
</div>
|
|
@@ -103,6 +121,13 @@
|
|
|
103
121
|
|
|
104
122
|
<div class="flex h-full">
|
|
105
123
|
<div id="trace-visualization" class="trace-container"></div>
|
|
124
|
+
<div id="empty-state" class="empty-state">
|
|
125
|
+
<div class="mb-4 inline-block p-4 bg-white rounded-full shadow-sm">
|
|
126
|
+
<svg class="w-8 h-8 text-slate-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M13 10V3L4 14h7v7l9-11h-7z"></path></svg>
|
|
127
|
+
</div>
|
|
128
|
+
<h3 class="text-lg font-medium text-slate-700">Waiting for Activity...</h3>
|
|
129
|
+
<p class="text-sm text-slate-400 mt-2">Trigger a web request, a job, a background worker, or a method to see the trace.</p>
|
|
130
|
+
</div>
|
|
106
131
|
<div id="detail-drawer" class="drawer">
|
|
107
132
|
<div class="p-5 border-b border-slate-100 flex justify-between items-center bg-slate-50">
|
|
108
133
|
<h2 class="font-bold text-slate-800 text-lg" id="drawer-title">Details</h2>
|
|
@@ -116,6 +141,7 @@
|
|
|
116
141
|
document.addEventListener("DOMContentLoaded", () => {
|
|
117
142
|
const container = document.getElementById("trace-visualization");
|
|
118
143
|
const drawer = document.getElementById("detail-drawer");
|
|
144
|
+
const emptyState = document.getElementById("empty-state");
|
|
119
145
|
let graphs = {};
|
|
120
146
|
let nodeBuffer = {};
|
|
121
147
|
let verticalOffset = 60;
|
|
@@ -150,6 +176,9 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
150
176
|
received(data) {
|
|
151
177
|
if (!data || !data.node) return;
|
|
152
178
|
if ((data.node.name || "").includes("RailsTraceViewer")) return;
|
|
179
|
+
|
|
180
|
+
emptyState.classList.add("hidden");
|
|
181
|
+
|
|
153
182
|
addNodeToGraph(data.trace_id, data.node);
|
|
154
183
|
|
|
155
184
|
if (this.redrawTimer) clearTimeout(this.redrawTimer);
|
|
@@ -215,7 +244,17 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
215
244
|
|
|
216
245
|
function renderSingleDAG(G, yOffset) {
|
|
217
246
|
const dag = new dagre.graphlib.Graph();
|
|
218
|
-
|
|
247
|
+
|
|
248
|
+
const parentCounts = {};
|
|
249
|
+
G.edges.forEach(e => {
|
|
250
|
+
parentCounts[e.source] = (parentCounts[e.source] || 0) + 1;
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
const maxChildren = Math.max(...Object.values(parentCounts), 0);
|
|
254
|
+
|
|
255
|
+
const dynamicRankSep = Math.min(800, Math.max(60, 40 + (maxChildren * 18)));
|
|
256
|
+
|
|
257
|
+
dag.setGraph({ rankdir: "LR", nodesep: 25, ranksep: dynamicRankSep });
|
|
219
258
|
dag.setDefaultEdgeLabel(() => ({}));
|
|
220
259
|
|
|
221
260
|
Object.values(G.nodes).forEach(n => {
|
|
@@ -229,16 +268,13 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
229
268
|
|
|
230
269
|
if (dag.graph().height) G.height = dag.graph().height;
|
|
231
270
|
|
|
232
|
-
let minX = Infinity, maxX = -Infinity;
|
|
233
|
-
let minY = Infinity, maxY = -Infinity;
|
|
234
|
-
|
|
271
|
+
let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;
|
|
235
272
|
Object.values(G.nodes).forEach(n => {
|
|
236
273
|
const nodeInfo = dag.node(n.id);
|
|
237
274
|
const nx1 = nodeInfo.x - (nodeInfo.width / 2);
|
|
238
275
|
const nx2 = nodeInfo.x + (nodeInfo.width / 2);
|
|
239
276
|
const ny1 = nodeInfo.y - (nodeInfo.height / 2);
|
|
240
277
|
const ny2 = nodeInfo.y + (nodeInfo.height / 2);
|
|
241
|
-
|
|
242
278
|
if (nx1 < minX) minX = nx1;
|
|
243
279
|
if (nx2 > maxX) maxX = nx2;
|
|
244
280
|
if (ny1 < minY) minY = ny1;
|
|
@@ -248,36 +284,28 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
248
284
|
if (minX === Infinity) { minX = 0; maxX = 0; minY = 0; maxY = 0; }
|
|
249
285
|
|
|
250
286
|
G.bounds = {
|
|
251
|
-
minX: minX,
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
maxY: maxY + yOffset,
|
|
255
|
-
width: maxX - minX,
|
|
256
|
-
height: maxY - minY,
|
|
257
|
-
centerX: minX + (maxX - minX) / 2,
|
|
258
|
-
centerY: (minY + yOffset) + (maxY - minY) / 2
|
|
287
|
+
minX: minX, maxX: maxX, minY: minY + yOffset, maxY: maxY + yOffset,
|
|
288
|
+
width: maxX - minX, height: maxY - minY,
|
|
289
|
+
centerX: minX + (maxX - minX) / 2, centerY: (minY + yOffset) + (maxY - minY) / 2
|
|
259
290
|
};
|
|
260
291
|
|
|
261
292
|
g.selectAll(`.link-${G.id}`).data(dag.edges()).enter().append("path")
|
|
262
|
-
.attr("class", "link")
|
|
293
|
+
.attr("class", "link")
|
|
294
|
+
.attr("d", e => {
|
|
263
295
|
const pts = dag.edge(e).points;
|
|
264
|
-
return d3.line().x(d => d.x).y(d => d.y + yOffset).curve(d3.
|
|
296
|
+
return d3.line().x(d => d.x).y(d => d.y + yOffset).curve(d3.curveMonotoneX)(pts);
|
|
265
297
|
});
|
|
266
298
|
|
|
267
299
|
const nodeGroup = g.selectAll(`.node-${G.id}`).data(dag.nodes()).enter().append("g")
|
|
268
300
|
.attr("class", d => `node node-type-${dag.node(d).type}`)
|
|
301
|
+
.attr("id", d => `node-${d}`)
|
|
269
302
|
.attr("transform", d => `translate(${dag.node(d).x}, ${dag.node(d).y + yOffset})`)
|
|
270
303
|
.on("click", (e, d) => { e.stopPropagation(); showDrawer(dag.node(d).fullData); });
|
|
271
304
|
|
|
272
|
-
nodeGroup.append("rect")
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
nodeGroup.append("text")
|
|
276
|
-
.attr("x", 0).attr("y", 0).attr("dy", "0.35em")
|
|
305
|
+
nodeGroup.append("rect").attr("width", NODE_WIDTH).attr("height", NODE_HEIGHT).attr("x", -NODE_WIDTH / 2).attr("y", -NODE_HEIGHT / 2);
|
|
306
|
+
nodeGroup.append("text").attr("x", 0).attr("y", 0).attr("dy", "0.35em")
|
|
277
307
|
.text(d => dag.node(d).label).classed("label-title", true).style("text-anchor", "middle");
|
|
278
|
-
|
|
279
|
-
nodeGroup.append("text")
|
|
280
|
-
.attr("x", (NODE_WIDTH / 2) - 10).attr("y", (NODE_HEIGHT / 2) - 6)
|
|
308
|
+
nodeGroup.append("text").attr("x", (NODE_WIDTH / 2) - 10).attr("y", (NODE_HEIGHT / 2) - 6)
|
|
281
309
|
.text(d => dag.node(d).type.replace(/_/g, " ")).classed("label-type", true).style("text-anchor", "end");
|
|
282
310
|
}
|
|
283
311
|
|
|
@@ -347,9 +375,12 @@ rails s</div>
|
|
|
347
375
|
<div class="flex items-center gap-2"><span class="w-3 h-3 bg-purple-100 border border-purple-300 rounded"></span> Job Enqueue</div>
|
|
348
376
|
<div class="flex items-center gap-2"><span class="w-3 h-3 bg-pink-100 border border-pink-300 rounded"></span> Job Perform</div>
|
|
349
377
|
<div class="flex items-center gap-2"><span class="w-3 h-3 bg-amber-100 border border-amber-300 rounded"></span> SQL Query</div>
|
|
378
|
+
<div class="flex items-center gap-2"><span class="w-3 h-3 bg-emerald-100 border border-emerald-300 rounded"></span> View Render</div>
|
|
350
379
|
</div>
|
|
351
380
|
</div>
|
|
352
381
|
|
|
382
|
+
<div class="help-section"><div class="help-title"><span>📚</span> Resources</div><div class="help-text"><p class="mb-2">To learn more, read the <a href="https://github.com/Aditya-JOSH/rails_trace_viewer/blob/main/README.md" target="_blank" class="text-indigo-600 hover:underline font-medium">Project Documentation</a>.</p><p>Found an issue? Report it on <a href="https://github.com/Aditya-JOSH/rails_trace_viewer/issues" target="_blank" class="text-indigo-600 hover:underline font-medium">GitHub Issues</a>.</p></div></div>
|
|
383
|
+
|
|
353
384
|
<div class="mt-12 pt-6 border-t border-slate-200">
|
|
354
385
|
<div class="text-xs font-bold text-slate-400 uppercase tracking-wider mb-3">Created By</div>
|
|
355
386
|
<a href="https://www.linkedin.com/in/aditya-kolekar-5a54611b5/" target="_blank" class="flex items-center gap-4 p-4 bg-white border border-slate-200 rounded-xl shadow-sm hover:shadow-md hover:border-blue-200 transition-all group text-decoration-none">
|
|
@@ -373,6 +404,7 @@ rails s</div>
|
|
|
373
404
|
redrawAllGraphs();
|
|
374
405
|
drawer.classList.remove("open");
|
|
375
406
|
console.log("🧹 Clearing traces & reconnecting...");
|
|
407
|
+
emptyState.classList.remove("hidden");
|
|
376
408
|
setupSubscription();
|
|
377
409
|
};
|
|
378
410
|
|
|
@@ -393,7 +425,8 @@ rails s</div>
|
|
|
393
425
|
const tX = (viewW / 2) - (G.bounds.centerX * scale);
|
|
394
426
|
const tY = (viewH / 2) - (G.bounds.centerY * scale);
|
|
395
427
|
|
|
396
|
-
svg.transition().duration(
|
|
428
|
+
svg.transition().duration(2500).ease(d3.easeCubicOut)
|
|
429
|
+
.call(zoom.transform, d3.zoomIdentity.translate(tX, tY).scale(scale));
|
|
397
430
|
};
|
|
398
431
|
|
|
399
432
|
document.getElementById("learn-btn").onclick = showLearn;
|
|
@@ -407,4 +440,4 @@ rails s</div>
|
|
|
407
440
|
});
|
|
408
441
|
</script>
|
|
409
442
|
</body>
|
|
410
|
-
</html>
|
|
443
|
+
</html>
|
|
@@ -2,31 +2,48 @@ module RailsTraceViewer
|
|
|
2
2
|
class Engine < ::Rails::Engine
|
|
3
3
|
isolate_namespace RailsTraceViewer
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
config.to_prepare do
|
|
6
|
+
if Rails.application.routes.routes.empty?
|
|
7
|
+
Rails.application.reload_routes!
|
|
8
8
|
end
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
is_mounted = Rails.application.routes.routes.any? do |route|
|
|
11
|
+
app = route.app
|
|
12
|
+
while app.respond_to?(:app) && app != app.app
|
|
13
|
+
app = app.app
|
|
14
|
+
end
|
|
15
|
+
match_class = (app == RailsTraceViewer::Engine) || (app.to_s.include?("RailsTraceViewer::Engine"))
|
|
13
16
|
|
|
14
|
-
|
|
15
|
-
RailsTraceViewer::Subscribers::ViewSubscriber.attach
|
|
16
|
-
end
|
|
17
|
+
path_match = (route.path.spec.to_s rescue "").include?("/rails_trace_viewer")
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
RailsTraceViewer::Subscribers::ActiveJobSubscriber.attach
|
|
19
|
+
match_class || path_match
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
RailsTraceViewer
|
|
22
|
+
if is_mounted
|
|
23
|
+
RailsTraceViewer.enabled = true
|
|
24
|
+
|
|
25
|
+
unless @booted_message_shown
|
|
26
|
+
puts "✅ [RailsTraceViewer] Engine mounted. Tracing is ACTIVE."
|
|
27
|
+
@booted_message_shown = true
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
RailsTraceViewer::Subscribers::ControllerSubscriber.attach
|
|
31
|
+
RailsTraceViewer::Subscribers::SqlSubscriber.attach
|
|
32
|
+
RailsTraceViewer::Subscribers::ViewSubscriber.attach
|
|
33
|
+
RailsTraceViewer::Subscribers::ActiveJobSubscriber.attach
|
|
34
|
+
RailsTraceViewer::Subscribers::SidekiqSubscriber.attach if defined?(Sidekiq)
|
|
24
35
|
RailsTraceViewer::Subscribers::MethodSubscriber.attach
|
|
36
|
+
|
|
37
|
+
RailsTraceViewer::Collector.start_sweeper!
|
|
38
|
+
|
|
39
|
+
else
|
|
40
|
+
RailsTraceViewer.enabled = false
|
|
41
|
+
|
|
42
|
+
unless @booted_message_shown
|
|
43
|
+
puts "🚫 [RailsTraceViewer] Engine route not found. Tracing DISABLED (Zero Overhead)."
|
|
44
|
+
@booted_message_shown = true
|
|
45
|
+
end
|
|
25
46
|
end
|
|
26
47
|
end
|
|
27
|
-
|
|
28
|
-
initializer "rails_trace_viewer.start_sweeper" do
|
|
29
|
-
RailsTraceViewer::Collector.start_sweeper!
|
|
30
|
-
end
|
|
31
48
|
end
|
|
32
49
|
end
|
|
@@ -12,6 +12,12 @@ module RailsTraceViewer
|
|
|
12
12
|
is_app_path = path.start_with?(Rails.root.to_s) &&
|
|
13
13
|
!path.include?("/vendor/") &&
|
|
14
14
|
!path.include?("rails_trace_viewer")
|
|
15
|
+
|
|
16
|
+
is_view_related = path.include?("/app/views/")
|
|
17
|
+
|
|
18
|
+
# Only trace Controllers, Models, Jobs, Services. Skip Views.
|
|
19
|
+
next unless is_app_path && !is_view_related
|
|
20
|
+
|
|
15
21
|
is_active_job = (tp.defined_class < ApplicationJob) rescue false
|
|
16
22
|
is_sidekiq_worker = (tp.defined_class.include?(Sidekiq::Worker)) rescue false
|
|
17
23
|
|
|
@@ -1,32 +1,59 @@
|
|
|
1
1
|
module RailsTraceViewer
|
|
2
2
|
module Subscribers
|
|
3
3
|
class ViewSubscriber
|
|
4
|
-
EVENTS = ["render_template.action_view", "render_partial.action_view"]
|
|
5
|
-
|
|
6
4
|
def self.attach
|
|
7
5
|
return if @attached
|
|
8
6
|
@attached = true
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
8
|
+
subscriber = new
|
|
9
|
+
ActiveSupport::Notifications.subscribe("render_template.action_view", subscriber)
|
|
10
|
+
ActiveSupport::Notifications.subscribe("render_partial.action_view", subscriber)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def start(name, id, payload)
|
|
14
|
+
file = payload[:identifier]
|
|
15
|
+
|
|
16
|
+
return unless file && file.start_with?(Rails.root.to_s)
|
|
17
|
+
|
|
18
|
+
if !RailsTraceViewer::TraceContext.active?
|
|
19
|
+
trace_id = SecureRandom.uuid
|
|
20
|
+
RailsTraceViewer::TraceContext.start!(trace_id)
|
|
21
|
+
RailsTraceViewer::Collector.start_trace(trace_id)
|
|
22
|
+
Thread.current["rtv_view_root_#{id}"] = true
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
trace_id = RailsTraceViewer::TraceContext.trace_id
|
|
26
|
+
parent_id = RailsTraceViewer::TraceContext.parent_id
|
|
27
|
+
node_id = SecureRandom.uuid
|
|
28
|
+
|
|
29
|
+
Thread.current["rtv_view_node_#{id}"] = node_id
|
|
30
|
+
|
|
31
|
+
relative_path = file.sub(Rails.root.to_s, '')
|
|
32
|
+
|
|
33
|
+
node = {
|
|
34
|
+
id: node_id,
|
|
35
|
+
parent_id: parent_id,
|
|
36
|
+
type: "view",
|
|
37
|
+
name: relative_path.split("/").last,
|
|
38
|
+
source: relative_path,
|
|
39
|
+
layout: payload[:layout],
|
|
40
|
+
full_path: file,
|
|
41
|
+
children: []
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
RailsTraceViewer::Collector.add_node(trace_id, node)
|
|
45
|
+
RailsTraceViewer::TraceContext.push(node_id)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def finish(name, id, payload)
|
|
49
|
+
if Thread.current["rtv_view_node_#{id}"]
|
|
50
|
+
RailsTraceViewer::TraceContext.pop
|
|
51
|
+
Thread.current["rtv_view_node_#{id}"] = nil
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
if Thread.current["rtv_view_root_#{id}"]
|
|
55
|
+
RailsTraceViewer::TraceContext.stop!
|
|
56
|
+
Thread.current["rtv_view_root_#{id}"] = nil
|
|
30
57
|
end
|
|
31
58
|
end
|
|
32
59
|
end
|
data/lib/rails_trace_viewer.rb
CHANGED
|
@@ -18,5 +18,14 @@ require "rails_trace_viewer/subscribers/sidekiq_subscriber"
|
|
|
18
18
|
require "rails_trace_viewer/subscribers/method_subscriber"
|
|
19
19
|
|
|
20
20
|
module RailsTraceViewer
|
|
21
|
-
|
|
21
|
+
mattr_accessor :enabled
|
|
22
|
+
self.enabled = true
|
|
23
|
+
|
|
24
|
+
def self.enabled?
|
|
25
|
+
!!self.enabled
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.configure
|
|
29
|
+
yield self
|
|
30
|
+
end
|
|
22
31
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rails_trace_viewer
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Aditya-JOSH
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: rails
|
|
@@ -102,6 +101,7 @@ metadata:
|
|
|
102
101
|
homepage_uri: https://github.com/Aditya-JOSH/rails_trace_viewer
|
|
103
102
|
source_code_uri: https://github.com/Aditya-JOSH/rails_trace_viewer
|
|
104
103
|
changelog_uri: https://github.com/Aditya-JOSH/rails_trace_viewer/blob/main/CHANGELOG.md
|
|
104
|
+
documentation_uri: https://github.com/Aditya-JOSH/rails_trace_viewer/blob/main/README.md
|
|
105
105
|
post_install_message: 'Thanks for installing Rails Trace Viewer! Don''t forget to
|
|
106
106
|
mount the engine in your config/routes.rb: mount RailsTraceViewer::Engine => ''/rails_trace_viewer'''
|
|
107
107
|
rdoc_options: []
|
|
@@ -118,8 +118,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
118
118
|
- !ruby/object:Gem::Version
|
|
119
119
|
version: '0'
|
|
120
120
|
requirements: []
|
|
121
|
-
rubygems_version: 3.
|
|
122
|
-
signing_key:
|
|
121
|
+
rubygems_version: 3.7.2
|
|
123
122
|
specification_version: 4
|
|
124
123
|
summary: Visualize Rails request flow in real-time.
|
|
125
124
|
test_files: []
|