callstacking-rails 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: f4bc78186fe09232889a12dea985d128878de745f00a7f6761fd2d6bdc1bc6e0
4
+ data.tar.gz: 113fe92740e5260af527603445de8c0ec5ce49262a332dff1620382bb584dfa3
5
+ SHA512:
6
+ metadata.gz: db7b809625176d70d726b202d11d26d55c73809281af0e569431f9c884ad81ce7868e29fa685a0527a48ffc0ba8fd52cf4e35b4ae0e83bd6cf64684663bc5e31
7
+ data.tar.gz: 74cf19f86b7ad4da4c67eb1a83af54f51e843d324e067b6d05cf81eede3a1bc14a05903e252ed73359c01d0cf58a35e98940e13688fa2423abd61616ca302c6a
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2022 Jim Jones
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,52 @@
1
+ # Checkpoint::Rails
2
+
3
+ Callstacking is a rolling, checkpoint debugger for Rails. It records all of the critical method calls within your app, along with their important context (param/argument/return/local variable values).
4
+
5
+ You no longer need to debug with `binding.pry` or `puts` statements, as the entire callstack for a given request is captured.
6
+
7
+ Demo video:
8
+ [![Watch the video](https://user-images.githubusercontent.com/4600/190929740-fc68e18f-9572-41be-9719-cc6a8077e97f.png)](https://www.youtube.com/watch?v=NGqnwcNWv_k)
9
+
10
+ Class method calls are labeled. Return values for those calls are denoted with ↳
11
+
12
+ Arguments for a method will be listed along with their calling values.
13
+
14
+ For method returns ↳, the final values of the local variables will be listed when you hover over the entry.
15
+
16
+ <img width="1695" alt="CleanShot 2022-09-17 at 21 10 32@2x" src="https://user-images.githubusercontent.com/4600/190882603-a99e9358-9754-4cbf-ac68-a41d53afe747.png">
17
+
18
+ Subsequent calls within a method are visibly nested.
19
+
20
+ Checkpoint is a Rails engine that you mount within your Rails app.
21
+
22
+ Here's a sample debugging sessions recorded from a Jumpstart Rails based app I've been working on. This is a request for the main page ( https://smartk.id/ ).
23
+
24
+ ![image](https://user-images.githubusercontent.com/4600/190882432-58092e38-7ee2-4138-b13a-f45ff2b09227.png)
25
+
26
+ Checkpoint Rails records all of the critical method calls within your app, along with their important context (param/argument/return/local variable values).
27
+
28
+ All in a rolling panel, so that you can debug your call chains from any point in the stack.
29
+
30
+ You'll never have to debug with `puts` statements ever again.
31
+
32
+ Calls are visibly nested so that it's easy to see which calls are issued from which parent methods.
33
+
34
+ ## Installation
35
+ Add this line to your application's Gemfile:
36
+
37
+ ```ruby
38
+ gem "callstacking-rails"
39
+ ```
40
+
41
+ And then execute:
42
+ ```bash
43
+ $ bundle
44
+ ```
45
+
46
+ ## Usage
47
+ When you open a page for your app, once the page has rendered, you will see an arrow on the right hand side.
48
+
49
+ Click the arrow, and observe the full callstack context.
50
+
51
+ ## License
52
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/setup"
2
+
3
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
4
+ load "rails/tasks/engine.rake"
5
+
6
+ load "rails/tasks/statistics.rake"
7
+
8
+ require "bundler/gem_tasks"
@@ -0,0 +1 @@
1
+ //= link_directory ../stylesheets/checkpoint/rails .css
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,6 @@
1
+ module Checkpoint
2
+ module Rails
3
+ class ApplicationController < ActionController::Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Checkpoint::Rails
2
+ class TracesController < ApplicationController
3
+ def index
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Checkpoint
2
+ module Rails
3
+ module ApplicationHelper
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Checkpoint
2
+ module Rails
3
+ class ApplicationJob < ActiveJob::Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,8 @@
1
+ module Checkpoint
2
+ module Rails
3
+ class ApplicationMailer < ActionMailer::Base
4
+ default from: "from@example.com"
5
+ layout "mailer"
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,7 @@
1
+ module Checkpoint
2
+ module Rails
3
+ class ApplicationRecord < ActiveRecord::Base
4
+ self.abstract_class = true
5
+ end
6
+ end
7
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,4 @@
1
+ Checkpoint::Rails::Engine.routes.draw do
2
+ resources :traces
3
+ root to: "traces#index"
4
+ end
@@ -0,0 +1,22 @@
1
+ require 'json'
2
+
3
+ module Checkpoint
4
+ module Rails
5
+ module Client
6
+ class Error < StandardError; end
7
+
8
+ class Authenticate < Base
9
+ URL = "/api/v1/auth.json"
10
+
11
+ def login(email, password)
12
+ resp = post(URL, email: email, password: password)
13
+
14
+ raise Faraday::UnauthorizedError if resp&.body.nil?
15
+
16
+ body = resp&.body || {}
17
+ body["token"]
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,56 @@
1
+ require 'faraday'
2
+ require 'faraday/follow_redirects'
3
+ require "checkpoint/rails/settings"
4
+
5
+ module Checkpoint
6
+ module Rails
7
+ module Client
8
+ class Error < StandardError; end
9
+
10
+ class Base
11
+ include Checkpoint::Rails::Settings
12
+
13
+ def initialize
14
+ read_settings
15
+ end
16
+
17
+ def connection
18
+ # https://github.com/lostisland/awesome-faraday
19
+ @connection ||= Faraday.new(url) do |c|
20
+ c.response :json
21
+ c.use Faraday::Response::Logger, Logger.new('/tmp/callstacking-rails.log')
22
+ # c.use Faraday::Response::Logger, nil, { headers: false, bodies: false }
23
+ c.response :follow_redirects
24
+ c.use Faraday::Response::RaiseError # raise exceptions on 40x, 50x responses
25
+ c.request :json # This will set the "Content-Type" header to application/json and call .to_json on the body
26
+ c.adapter Faraday.default_adapter
27
+
28
+ if auth_token?
29
+ c.request :authorization, :Bearer, auth_token
30
+ end
31
+ end
32
+ end
33
+
34
+ def get(url, params = {})
35
+ connection.get(url, params, headers)
36
+ end
37
+
38
+ def post(url, params = {}, body = {}, headers_ext = {})
39
+ r(:post, url, params, body, headers_ext)
40
+ end
41
+
42
+ def patch(url, params = {}, body = {}, headers_ext = {})
43
+ r(:patch, url, params, body, headers_ext)
44
+ end
45
+
46
+ def r(action, url, params = {}, body = {}, _headers_ext = {})
47
+ connection.send(action, url) do |req|
48
+ req.params.merge!(params)
49
+ req.body = body
50
+ end
51
+ end
52
+
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,33 @@
1
+ module Checkpoint
2
+ module Rails
3
+ module Client
4
+ class Trace < Base
5
+ CREATE_URL = "/api/v1/traces.json"
6
+ UPDATE_URL = "/api/v1/traces/:id.json"
7
+
8
+ def create(method_name, klass, action_name, format_name, root_path, url, request_id, headers, params)
9
+ resp = post(CREATE_URL,
10
+ {},
11
+ { method_name: method_name,
12
+ klass: klass,
13
+ action_name: action_name,
14
+ format_name: format_name,
15
+ root_path: root_path,
16
+ url: url,
17
+ request_id: request_id,
18
+ h: headers.to_h,
19
+ p: params.to_h,
20
+ })
21
+
22
+ return resp.body["trace_id"], resp.body["pulse_interval"]
23
+ end
24
+
25
+ def upsert(trace_id, traces)
26
+ resp = patch(UPDATE_URL.gsub(':id', trace_id), {}, traces)
27
+
28
+ resp.status
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,34 @@
1
+ require "checkpoint/rails/traceable"
2
+ require "checkpoint/rails/setup"
3
+ require "checkpoint/rails/settings"
4
+ require "checkpoint/rails/client/base"
5
+ require "checkpoint/rails/client/authenticate"
6
+ require "checkpoint/rails/client/trace"
7
+ require "checkpoint/rails/traces_helper"
8
+
9
+ module Checkpoint
10
+ module Rails
11
+ class Engine < ::Rails::Engine
12
+ isolate_namespace Checkpoint::Rails
13
+
14
+ include ::Checkpoint::Rails::Traceable
15
+
16
+ initializer "engine_name.assets.precompile" do |app|
17
+ app.config.assets.precompile << "checkpoint_rails_manifest.js"
18
+ end
19
+
20
+ initializer 'local_helper.action_controller' do
21
+ ActiveSupport.on_load :action_controller do
22
+ helper Checkpoint::Rails::TracesHelper
23
+ include Checkpoint::Rails::TracesHelper
24
+ end
25
+ end
26
+
27
+ initializer :append_before_action do
28
+ ActionController::Base.send :after_action, :inject_hud
29
+ end
30
+
31
+ set_trace
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,15 @@
1
+ module Checkpoint
2
+ module Rails
3
+ class Env
4
+ DEFAULT_ENVIRONMENT = "development"
5
+
6
+ cattr_accessor :environment
7
+
8
+ @@environment = (ENV['RAILS_ENV'] || DEFAULT_ENVIRONMENT).parameterize(separator: '_').to_sym
9
+
10
+ def self.production?
11
+ @@environment == DEFAULT_ENVIRONMENT.parameterize(separator: '_').to_sym
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,46 @@
1
+ require "active_support/concern"
2
+ require "active_support/core_ext/class/attribute_accessors"
3
+ require "checkpoint/rails/env"
4
+
5
+ module Checkpoint
6
+ module Rails
7
+ module Settings
8
+ extend ActiveSupport::Concern
9
+
10
+ included do |base|
11
+ attr_accessor :settings
12
+ end
13
+
14
+ SETTINGS_FILE = "#{Dir.home}/.callstacking-rails"
15
+ PRODUCTION_URL = "https://callstacking.com"
16
+
17
+ def url
18
+ settings[:url]
19
+ end
20
+
21
+ def auth_token
22
+ settings[:auth_token]
23
+ end
24
+
25
+ def auth_token?
26
+ auth_token.present?
27
+ end
28
+
29
+ def write_settings(new_settings)
30
+ File.write(SETTINGS_FILE, new_settings.to_yaml)
31
+ end
32
+
33
+ def read_settings
34
+ @@settings = @settings = complete_settings.dig(::Checkpoint::Rails::Env.environment, :settings)
35
+ rescue StandardError => e
36
+ puts e.full_message
37
+ puts e.backtrace.join("\n")
38
+ return {}
39
+ end
40
+
41
+ def complete_settings
42
+ YAML.load(File.read(Checkpoint::Rails::Client::Base::SETTINGS_FILE)) rescue {}
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,93 @@
1
+ require 'yaml'
2
+ require "checkpoint/rails/settings"
3
+
4
+ module Checkpoint
5
+ module Rails
6
+ class Setup
7
+ include ::Checkpoint::Rails::Settings
8
+ extend ::Checkpoint::Rails::Settings
9
+
10
+ attr_accessor :client
11
+
12
+ def initialize
13
+ read_settings
14
+ end
15
+
16
+ def client
17
+ @client = Checkpoint::Rails::Client::Authenticate.new
18
+ end
19
+
20
+ def start
21
+ email = prompt("Enter email:")
22
+ password = prompt("Enter password:")
23
+
24
+ url = if Rails::Checkpoint::Env.production? && ENV['CHECKPOINT_RAILS_LOCAL_TEST'].nil?
25
+ PRODUCTION_URL
26
+ else
27
+ prompt("Enter URL for #{Checkpoint::Rails::Env.environment} API calls [#{PRODUCTION_URL}]:") || PRODUCTION_URL
28
+ end
29
+
30
+ save(email, password, url)
31
+
32
+ puts "Authentication successful."
33
+ puts "Settings saved to #{SETTINGS_FILE}"
34
+ rescue StandardError => e
35
+ puts "Problem authenticating: #{e.message}"
36
+ end
37
+
38
+ def prompt(label)
39
+ puts label
40
+ value = STDIN.gets.chomp
41
+ puts
42
+
43
+ return nil if value == ''
44
+ value
45
+ end
46
+
47
+ def token(email, password)
48
+ client.login(email, password)
49
+ end
50
+
51
+ def save(email, password, url)
52
+ props = { auth_token: '',
53
+ url: url,
54
+ }
55
+
56
+ props = { Checkpoint::Rails::Env.environment => {
57
+ settings: props
58
+ } }
59
+
60
+ write_settings(complete_settings.merge(props))
61
+
62
+ props[Checkpoint::Rails::Env.environment][:settings][:auth_token] = token(email, password)
63
+
64
+ write_settings(complete_settings.merge(props))
65
+
66
+ read_settings
67
+ end
68
+
69
+ def self.instructions
70
+ read_settings
71
+ puts "loading environment #{Checkpoint::Rails::Env.environment}"
72
+ puts
73
+ puts "Usage: "
74
+ puts
75
+ puts " callstacking-rails register"
76
+ puts " Opens a browser window to register as a Callstacking user."
77
+ puts
78
+ puts " callstacking-rails setup"
79
+ puts " Interactively prompts you for your Callstacking username/password, "
80
+ puts " Stores auth details in #{SETTINGS_FILE} "
81
+ puts
82
+ puts " You can have multiple environments."
83
+ puts " Default is #{Rails::Checkpoint::Env::DEFAULT_ENVIRONMENT}."
84
+ puts
85
+ puts " The #{Checkpoint::Rails::Env.environment}: section in the #{SETTINGS_FILE} contains your credentials."
86
+ puts " By setting the RAILS_ENV environment you can maintain"
87
+ puts " multiple settings."
88
+ puts
89
+ puts "Questions? Create an issue: https://github.com/callstacking/callstacking-rails/issues"
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,210 @@
1
+ require "active_support/concern"
2
+ require "checkpoint/rails/client/base"
3
+ require "checkpoint/rails/client/authenticate"
4
+ require "checkpoint/rails/client/trace"
5
+ require "checkpoint/rails/settings"
6
+
7
+ module Checkpoint
8
+ module Rails
9
+ module Traceable
10
+ extend ActiveSupport::Concern
11
+ include Checkpoint::Rails::Settings
12
+
13
+ TARGET_DIV = 'traces'
14
+
15
+ mattr_accessor :current_request_id
16
+
17
+ def set_trace
18
+ read_settings
19
+
20
+ client = Checkpoint::Rails::Client::Trace.new
21
+
22
+ trace_points = {}
23
+ params = {}
24
+ prev_event = ''
25
+ order_num = 0
26
+ trace_id = nil
27
+ traces = []
28
+ lock = Mutex.new
29
+ task = nil
30
+
31
+ ActiveSupport::Notifications.subscribe("start_processing.action_controller") do |name, start, finish, id, payload|
32
+ next if payload[:controller] == 'Checkpoint::Rails::TracesController'
33
+
34
+ key = request_key(payload)
35
+ params[key] = payload[:params]
36
+
37
+ nesting_level = -1
38
+
39
+ request_id = payload[:request].request_id
40
+ Checkpoint::Rails::Traceable.current_request_id = request_id
41
+
42
+ trace_id, _interval = client.create(payload[:method], payload[:controller],
43
+ payload[:action], payload[:format],
44
+ ::Rails.root, payload[:request].original_url,
45
+ request_id,
46
+ payload[:headers], params[key])
47
+
48
+
49
+ puts "#{settings[:url] || Checkpoint::Rails::Settings::PRODUCTION_URL}/traces/#{trace_id}"
50
+
51
+ task = Concurrent::TimerTask.new(execution_interval: 1, timeout_interval: 60) {
52
+ send_traces!(trace_id, traces, lock, client)
53
+ }
54
+
55
+ task.execute
56
+
57
+ create_message(start_request_message(payload), order_num, traces, lock)
58
+
59
+ trace_points[key]&.disable
60
+ trace_point = TracePoint.new(:call, :return) do |t|
61
+ trace = caller[0]
62
+
63
+ next unless trace.match?(Dir.pwd)
64
+
65
+ order_num += 1
66
+
67
+ if t.event == :call
68
+ nesting_level += 1
69
+
70
+ prev_event = previous_event(t)
71
+
72
+ create_call_entry(nesting_level, order_num, t, traces, lock)
73
+ elsif t.event == :return
74
+ coupled_callee = false
75
+ coupled_callee = true if prev_event == previous_event(t)
76
+
77
+ prev_event = previous_event(t)
78
+ return_value = t.return_value.inspect
79
+
80
+ create_call_return(coupled_callee, nesting_level, order_num, return_value, t, traces, lock)
81
+
82
+ nesting_level -= 1
83
+ end
84
+ end
85
+
86
+ trace_point.enable
87
+ trace_points[key] = trace_point
88
+ end
89
+
90
+ ActiveSupport::Notifications.subscribe("process_action.action_controller") do |name, start, finish, id, payload|
91
+ trace_points[request_key(payload)]&.disable
92
+ task&.shutdown
93
+
94
+ create_message(completed_request_message(payload), order_num, traces, lock)
95
+ send_traces!(trace_id, traces, lock, client)
96
+ end
97
+ end
98
+
99
+ private
100
+
101
+ def completed_request_message(payload)
102
+ "Completed request: #{payload[:method]} #{payload[:controller]}##{payload[:action]} as #{payload[:format]}"
103
+ end
104
+
105
+ def start_request_message(payload)
106
+ puts "start request message - "
107
+ "Request: #{payload[:method]} #{payload[:controller]}##{payload[:action]} as #{payload[:format]}"
108
+ end
109
+
110
+ def create_call_return(coupled_callee, nesting_level, order_num, return_value, t, traces, lock)
111
+ lock.synchronize do
112
+ traces << { trace_entry: { trace_entryable_type: 'TraceCallReturn',
113
+ order_num: order_num,
114
+ nesting_level: nesting_level,
115
+ trace_entryable_attributes: {
116
+ local_variables: locals_for(t),
117
+ klass: t.binding.receiver.class.name.to_s,
118
+ line_number: t.lineno,
119
+ path: t.path,
120
+ method_name: t.method_id,
121
+ return_value: return_value,
122
+ coupled_callee: coupled_callee,
123
+ } } }
124
+ end
125
+ end
126
+
127
+ def create_call_entry(nesting_level, order_num, t, traces, lock)
128
+ lock.synchronize do
129
+ traces << { trace_entry: { trace_entryable_type: 'TraceCallEntry',
130
+ order_num: order_num,
131
+ nesting_level: nesting_level,
132
+ trace_entryable_attributes: {
133
+ args: arguments_for(t),
134
+ klass: t.binding.receiver.class.name.to_s,
135
+ line_number: t.lineno,
136
+ path: t.path,
137
+ method_name: t.method_id,
138
+ } } }
139
+ end
140
+ end
141
+
142
+ def create_message(message, order_num, traces, lock)
143
+ lock.synchronize do
144
+ traces << { trace_entry: { trace_entryable_type: 'TraceMessage',
145
+ order_num: order_num,
146
+ nesting_level: 0,
147
+ trace_entryable_attributes: {
148
+ message: message
149
+ } } }
150
+ end
151
+ end
152
+
153
+ def send_traces!(trace_id, traces, lock, client)
154
+ lock.synchronize do
155
+ return if traces.empty?
156
+
157
+ client.upsert(trace_id, { traces: traces })
158
+ traces.clear
159
+ end
160
+ end
161
+
162
+ def caller_key(t)
163
+ "#{t.binding.receiver.class.name.to_s}##{t.method_id}"
164
+ end
165
+
166
+ def request_key(payload)
167
+ "#{payload[:controller]}##{payload[:action]}"
168
+ end
169
+
170
+ def previous_event(t)
171
+ "#{t.binding.receiver.class.name.to_s}:#{t.method_id}"
172
+ end
173
+
174
+ def view_rendered?(t)
175
+ t.path.to_s =~ /view/
176
+ end
177
+
178
+ def partial_rendered?(t)
179
+ view_rendered?(t) && Pathname.new(t.path).basename.to_s =~ /^_/
180
+ end
181
+
182
+ def layout_rendered?(t)
183
+ view_rendered?(t) && t.path =~ /layouts/
184
+ end
185
+
186
+ def template_rendered?(t)
187
+ view_rendered?(t) && !partial_rendered?(t) && !layout_rendered?(t)
188
+ end
189
+
190
+ def arguments_for(trace)
191
+ param_names = trace&.parameters&.map(&:last)
192
+ return {} if param_names.nil?
193
+
194
+ param_names.map do |param|
195
+ next if [:&, :*, :**].include?(param)
196
+ [param, trace.binding.local_variable_get(param.to_s)]
197
+ end.compact.to_h
198
+ end
199
+
200
+ def locals_for(trace)
201
+ local_names = trace&.binding&.local_variables
202
+ return {} if local_names.nil?
203
+
204
+ local_names.map do |local|
205
+ [local, trace.binding.local_variable_get(local)]
206
+ end.to_h
207
+ end
208
+ end
209
+ end
210
+ end
@@ -0,0 +1,39 @@
1
+ require "action_view/helpers/tag_helper.rb"
2
+ require "action_view/context.rb"
3
+
4
+ module Checkpoint
5
+ module Rails
6
+ module TracesHelper
7
+ include ActionView::Helpers::TagHelper
8
+ include ActionView::Context
9
+ include Checkpoint::Rails::Settings
10
+
11
+ def hud
12
+ read_settings
13
+
14
+ frame_url = "#{url || Checkpoint::Rails::Settings::PRODUCTION_URL}/traces/#{Checkpoint::Rails::Traceable.current_request_id}/print"
15
+
16
+ body = []
17
+ body << (content_tag( :div, data: { turbo:false },
18
+ style: 'background-color: #FFF; color: #0000FF; font-size: 20pt; top: 50%; right: 20px;
19
+ padding: 30px 10px 0px 10px; position: fixed; height: 100px; width: 40px; cursor: pointer;',
20
+ onclick: 'document.getElementById("callstacking-debugger").style.display = "unset";
21
+ document.getElementById("callstacking-close").style.display = "unset";') do
22
+ "⇐"
23
+ end)
24
+
25
+ body << (content_tag(:iframe, src: frame_url, id: 'callstacking-debugger', data: { turbo:false },
26
+ style: "width: 50%; height: 100%; overflow: scroll; top: 20px; right: 20px; position: fixed;
27
+ z-index: 99; opacity: 1.0; background-color: #FFF; color: #000; border: 1px solid;
28
+ margin: 0; padding: 0; box-shadow: 5px 5px; display: none;") do
29
+ end)
30
+
31
+ body.join
32
+ end
33
+
34
+ def inject_hud
35
+ response.body = response.body.sub(/<\/body>/i, "#{hud}</body>")
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,5 @@
1
+ module Checkpoint
2
+ module Rails
3
+ VERSION = "0.1.2"
4
+ end
5
+ end
@@ -0,0 +1,7 @@
1
+ require "checkpoint/rails/version"
2
+ require "checkpoint/rails/engine"
3
+
4
+ module Checkpoint
5
+ module Rails
6
+ end
7
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :checkpoint_rails do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,125 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: callstacking-rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ platform: ruby
6
+ authors:
7
+ - Jim Jones
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2022-11-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '4'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '4'
27
+ - !ruby/object:Gem::Dependency
28
+ name: faraday
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.5'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.5'
41
+ - !ruby/object:Gem::Dependency
42
+ name: faraday-follow_redirects
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: concurrent-ruby
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Rolling debugger that shows the full state of each call.
70
+ email:
71
+ - jim.jones1@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - MIT-LICENSE
77
+ - README.md
78
+ - Rakefile
79
+ - app/assets/config/checkpoint_rails_manifest.js
80
+ - app/assets/stylesheets/checkpoint/rails/application.css
81
+ - app/controllers/checkpoint/rails/application_controller.rb
82
+ - app/controllers/checkpoint/rails/traces_controller.rb
83
+ - app/helpers/checkpoint/rails/application_helper.rb
84
+ - app/jobs/checkpoint/rails/application_job.rb
85
+ - app/mailers/checkpoint/rails/application_mailer.rb
86
+ - app/models/checkpoint/rails/application_record.rb
87
+ - config/routes.rb
88
+ - lib/checkpoint/rails.rb
89
+ - lib/checkpoint/rails/client/authenticate.rb
90
+ - lib/checkpoint/rails/client/base.rb
91
+ - lib/checkpoint/rails/client/trace.rb
92
+ - lib/checkpoint/rails/engine.rb
93
+ - lib/checkpoint/rails/env.rb
94
+ - lib/checkpoint/rails/settings.rb
95
+ - lib/checkpoint/rails/setup.rb
96
+ - lib/checkpoint/rails/traceable.rb
97
+ - lib/checkpoint/rails/traces_helper.rb
98
+ - lib/checkpoint/rails/version.rb
99
+ - lib/tasks/checkpoint/rails_tasks.rake
100
+ homepage: https://github.com/callstacking/callstacking-rails
101
+ licenses:
102
+ - MIT
103
+ metadata:
104
+ homepage_uri: https://github.com/callstacking/callstacking-rails
105
+ source_code_uri: https://github.com/callstacking/callstacking-rails
106
+ post_install_message:
107
+ rdoc_options: []
108
+ require_paths:
109
+ - lib
110
+ required_ruby_version: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ required_rubygems_version: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ requirements: []
121
+ rubygems_version: 3.3.7
122
+ signing_key:
123
+ specification_version: 4
124
+ summary: Rolling debugger that shows the full state of each call per request.
125
+ test_files: []