callstacking-rails 0.1.2 → 0.1.3
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/LICENSE +621 -0
- data/README.md +49 -6
- data/app/assets/config/callstacking_rails_manifest.js +1 -0
- data/app/assets/stylesheets/{checkpoint → callstacking}/rails/application.css +0 -0
- data/app/controllers/{checkpoint → callstacking}/rails/application_controller.rb +1 -1
- data/app/helpers/{checkpoint → callstacking}/rails/application_helper.rb +1 -1
- data/app/jobs/{checkpoint → callstacking}/rails/application_job.rb +1 -1
- data/app/mailers/{checkpoint → callstacking}/rails/application_mailer.rb +1 -1
- data/app/models/{checkpoint → callstacking}/rails/application_record.rb +1 -1
- data/config/routes.rb +1 -1
- data/exe/callstacking-rails +32 -0
- data/lib/{checkpoint → callstacking}/rails/client/authenticate.rb +2 -1
- data/lib/{checkpoint → callstacking}/rails/client/base.rb +3 -3
- data/lib/{checkpoint → callstacking}/rails/client/trace.rb +3 -1
- data/lib/callstacking/rails/engine.rb +49 -0
- data/lib/{checkpoint → callstacking}/rails/env.rb +3 -1
- data/lib/callstacking/rails/instrument.rb +100 -0
- data/lib/callstacking/rails/loader.rb +29 -0
- data/lib/{checkpoint → callstacking}/rails/settings.rb +13 -5
- data/lib/callstacking/rails/setup.rb +115 -0
- data/lib/callstacking/rails/spans.rb +53 -0
- data/lib/callstacking/rails/trace.rb +126 -0
- data/lib/{checkpoint → callstacking}/rails/traces_helper.rb +20 -7
- data/lib/callstacking/rails/version.rb +5 -0
- data/lib/callstacking/rails.rb +7 -0
- metadata +32 -40
- data/MIT-LICENSE +0 -20
- data/app/assets/config/checkpoint_rails_manifest.js +0 -1
- data/app/controllers/checkpoint/rails/traces_controller.rb +0 -6
- data/lib/checkpoint/rails/engine.rb +0 -34
- data/lib/checkpoint/rails/setup.rb +0 -93
- data/lib/checkpoint/rails/traceable.rb +0 -210
- data/lib/checkpoint/rails/version.rb +0 -5
- data/lib/checkpoint/rails.rb +0 -7
@@ -0,0 +1,126 @@
|
|
1
|
+
require "rails"
|
2
|
+
require "active_support/concern"
|
3
|
+
require "callstacking/rails/client/base"
|
4
|
+
require "callstacking/rails/client/authenticate"
|
5
|
+
require "callstacking/rails/client/trace"
|
6
|
+
require "callstacking/rails/settings"
|
7
|
+
|
8
|
+
module Callstacking
|
9
|
+
module Rails
|
10
|
+
class Trace
|
11
|
+
include Callstacking::Rails::Settings
|
12
|
+
|
13
|
+
attr_accessor :spans, :client, :lock
|
14
|
+
cattr_accessor :current_request_id
|
15
|
+
|
16
|
+
def initialize(spans)
|
17
|
+
@traces = []
|
18
|
+
@spans = spans
|
19
|
+
|
20
|
+
@lock = Mutex.new
|
21
|
+
@client = Callstacking::Rails::Client::Trace.new
|
22
|
+
end
|
23
|
+
|
24
|
+
def tracing
|
25
|
+
read_settings
|
26
|
+
|
27
|
+
trace_id = nil
|
28
|
+
|
29
|
+
ActiveSupport::Notifications.subscribe("start_processing.action_controller") do |name, start, finish, id, payload|
|
30
|
+
request_id = payload[:request].request_id
|
31
|
+
Callstacking::Rails::Trace.current_request_id = request_id
|
32
|
+
|
33
|
+
trace_id, _interval = client.create(payload[:method], payload[:controller],
|
34
|
+
payload[:action], payload[:format],
|
35
|
+
::Rails.root, payload[:request].original_url,
|
36
|
+
request_id, payload[:headers],
|
37
|
+
payload[:params])
|
38
|
+
|
39
|
+
puts "#{settings[:url] || Callstacking::Rails::Settings::PRODUCTION_URL}/traces/#{trace_id}"
|
40
|
+
|
41
|
+
create_message(start_request_message(payload), spans.increment_order_num, @traces)
|
42
|
+
end
|
43
|
+
|
44
|
+
@spans.on_call_entry do |nesting_level, order_num, klass, method_name, arguments, path, line_no|
|
45
|
+
create_call_entry(nesting_level, order_num, klass, method_name, arguments, path, line_no, @traces)
|
46
|
+
end
|
47
|
+
|
48
|
+
@spans.on_call_return do |coupled_callee, nesting_level, order_num, klass, method_name, path, line_no, return_val|
|
49
|
+
create_call_return(coupled_callee, nesting_level, order_num, klass, method_name, path, line_no, return_val, @traces)
|
50
|
+
end
|
51
|
+
|
52
|
+
ActiveSupport::Notifications.subscribe("process_action.action_controller") do |name, start, finish, id, payload|
|
53
|
+
create_message(completed_request_message(payload), spans.increment_order_num, @traces)
|
54
|
+
send_traces!(trace_id, @traces)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def completed_request_message(payload)
|
61
|
+
"Completed request: #{payload[:method]} #{payload[:controller]}##{payload[:action]} as #{payload[:format]}"
|
62
|
+
end
|
63
|
+
|
64
|
+
def start_request_message(payload)
|
65
|
+
"Started request: #{payload[:method]} #{payload[:controller]}##{payload[:action]} as #{payload[:format]}"
|
66
|
+
end
|
67
|
+
|
68
|
+
def create_call_return(coupled_callee, nesting_level, order_num, klass, method_name, path, line_no, return_val, traces)
|
69
|
+
lock.synchronize do
|
70
|
+
traces << { trace_entry: { trace_entryable_type: 'TraceCallReturn',
|
71
|
+
order_num: order_num,
|
72
|
+
nesting_level: nesting_level,
|
73
|
+
trace_entryable_attributes: {
|
74
|
+
local_variables: {},
|
75
|
+
klass: klass_name(klass),
|
76
|
+
line_number: line_no,
|
77
|
+
path: path,
|
78
|
+
method_name: method_name,
|
79
|
+
return_value: return_val.inspect,
|
80
|
+
coupled_callee: coupled_callee,
|
81
|
+
} } }
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def create_call_entry(nesting_level, order_num, klass, method_name, arguments, path, line_no, traces)
|
86
|
+
lock.synchronize do
|
87
|
+
traces << { trace_entry: { trace_entryable_type: 'TraceCallEntry',
|
88
|
+
order_num: order_num,
|
89
|
+
nesting_level: nesting_level,
|
90
|
+
trace_entryable_attributes: {
|
91
|
+
args: arguments,
|
92
|
+
klass: klass_name(klass),
|
93
|
+
line_number: line_no,
|
94
|
+
path: path,
|
95
|
+
method_name: method_name,
|
96
|
+
} } }
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def create_message(message, order_num, traces)
|
101
|
+
lock.synchronize do
|
102
|
+
traces << { trace_entry: { trace_entryable_type: 'TraceMessage',
|
103
|
+
order_num: order_num,
|
104
|
+
nesting_level: 0,
|
105
|
+
trace_entryable_attributes: {
|
106
|
+
message: message
|
107
|
+
} } }
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def send_traces!(trace_id, traces)
|
112
|
+
lock.synchronize do
|
113
|
+
return if traces.empty?
|
114
|
+
|
115
|
+
client.upsert(trace_id, { traces: traces })
|
116
|
+
traces.clear
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
private
|
121
|
+
def klass_name(klass)
|
122
|
+
(klass.is_a?(Class) ? klass.name : klass.class.name)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -1,25 +1,26 @@
|
|
1
|
-
require "action_view/helpers/tag_helper
|
1
|
+
require "action_view/helpers/tag_helper"
|
2
2
|
require "action_view/context.rb"
|
3
3
|
|
4
|
-
module
|
4
|
+
module Callstacking
|
5
5
|
module Rails
|
6
6
|
module TracesHelper
|
7
7
|
include ActionView::Helpers::TagHelper
|
8
|
+
include ActionView::Helpers::JavaScriptHelper
|
8
9
|
include ActionView::Context
|
9
|
-
include
|
10
|
+
include Callstacking::Rails::Settings
|
10
11
|
|
11
12
|
def hud
|
12
13
|
read_settings
|
13
14
|
|
14
|
-
frame_url = "#{url ||
|
15
|
+
frame_url = "#{url || Callstacking::Rails::Settings::PRODUCTION_URL}/traces/#{Callstacking::Rails::Trace.current_request_id}/print"
|
15
16
|
|
16
17
|
body = []
|
17
18
|
body << (content_tag( :div, data: { turbo:false },
|
18
|
-
style: '
|
19
|
-
padding:
|
19
|
+
style: 'top: 50%; right: 10px; font-size: 24pt; :hover{text-shadow: 1px 1px 2px #000000};
|
20
|
+
padding: 0px; position: fixed; height: 50px; width: 40px; cursor: pointer;',
|
20
21
|
onclick: 'document.getElementById("callstacking-debugger").style.display = "unset";
|
21
22
|
document.getElementById("callstacking-close").style.display = "unset";') do
|
22
|
-
"
|
23
|
+
"💥"
|
23
24
|
end)
|
24
25
|
|
25
26
|
body << (content_tag(:iframe, src: frame_url, id: 'callstacking-debugger', data: { turbo:false },
|
@@ -27,6 +28,18 @@ module Checkpoint
|
|
27
28
|
z-index: 99; opacity: 1.0; background-color: #FFF; color: #000; border: 1px solid;
|
28
29
|
margin: 0; padding: 0; box-shadow: 5px 5px; display: none;") do
|
29
30
|
end)
|
31
|
+
|
32
|
+
body << (javascript_tag('
|
33
|
+
document.onkeyup = function(e) {
|
34
|
+
// Mac - option-d Win - alt-d
|
35
|
+
if (e.altKey && e.which == 68) {
|
36
|
+
if (document.getElementById("callstacking-debugger").style.display === "none") {
|
37
|
+
document.getElementById("callstacking-debugger").style.display = "block";
|
38
|
+
} else {
|
39
|
+
document.getElementById("callstacking-debugger").style.display = "none";
|
40
|
+
}
|
41
|
+
}
|
42
|
+
};'))
|
30
43
|
|
31
44
|
body.join
|
32
45
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: callstacking-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jim Jones
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-01-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -52,54 +52,45 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
-
|
56
|
-
|
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.
|
55
|
+
description: Quickly visualize which methods call which, their parameters, and return
|
56
|
+
values.
|
70
57
|
email:
|
71
58
|
- jim.jones1@gmail.com
|
72
|
-
executables:
|
59
|
+
executables:
|
60
|
+
- callstacking-rails
|
73
61
|
extensions: []
|
74
62
|
extra_rdoc_files: []
|
75
63
|
files:
|
76
|
-
-
|
64
|
+
- LICENSE
|
77
65
|
- README.md
|
78
66
|
- Rakefile
|
79
|
-
- app/assets/config/
|
80
|
-
- app/assets/stylesheets/
|
81
|
-
- app/controllers/
|
82
|
-
- app/
|
83
|
-
- app/
|
84
|
-
- app/
|
85
|
-
- app/
|
86
|
-
- app/models/checkpoint/rails/application_record.rb
|
67
|
+
- app/assets/config/callstacking_rails_manifest.js
|
68
|
+
- app/assets/stylesheets/callstacking/rails/application.css
|
69
|
+
- app/controllers/callstacking/rails/application_controller.rb
|
70
|
+
- app/helpers/callstacking/rails/application_helper.rb
|
71
|
+
- app/jobs/callstacking/rails/application_job.rb
|
72
|
+
- app/mailers/callstacking/rails/application_mailer.rb
|
73
|
+
- app/models/callstacking/rails/application_record.rb
|
87
74
|
- config/routes.rb
|
88
|
-
-
|
89
|
-
- lib/
|
90
|
-
- lib/
|
91
|
-
- lib/
|
92
|
-
- lib/
|
93
|
-
- lib/
|
94
|
-
- lib/
|
95
|
-
- lib/
|
96
|
-
- lib/
|
97
|
-
- lib/
|
98
|
-
- lib/
|
75
|
+
- exe/callstacking-rails
|
76
|
+
- lib/callstacking/rails.rb
|
77
|
+
- lib/callstacking/rails/client/authenticate.rb
|
78
|
+
- lib/callstacking/rails/client/base.rb
|
79
|
+
- lib/callstacking/rails/client/trace.rb
|
80
|
+
- lib/callstacking/rails/engine.rb
|
81
|
+
- lib/callstacking/rails/env.rb
|
82
|
+
- lib/callstacking/rails/instrument.rb
|
83
|
+
- lib/callstacking/rails/loader.rb
|
84
|
+
- lib/callstacking/rails/settings.rb
|
85
|
+
- lib/callstacking/rails/setup.rb
|
86
|
+
- lib/callstacking/rails/spans.rb
|
87
|
+
- lib/callstacking/rails/trace.rb
|
88
|
+
- lib/callstacking/rails/traces_helper.rb
|
89
|
+
- lib/callstacking/rails/version.rb
|
99
90
|
- lib/tasks/checkpoint/rails_tasks.rake
|
100
91
|
homepage: https://github.com/callstacking/callstacking-rails
|
101
92
|
licenses:
|
102
|
-
-
|
93
|
+
- GPL-3.0-or-later
|
103
94
|
metadata:
|
104
95
|
homepage_uri: https://github.com/callstacking/callstacking-rails
|
105
96
|
source_code_uri: https://github.com/callstacking/callstacking-rails
|
@@ -121,5 +112,6 @@ requirements: []
|
|
121
112
|
rubygems_version: 3.3.7
|
122
113
|
signing_key:
|
123
114
|
specification_version: 4
|
124
|
-
summary:
|
115
|
+
summary: Quickly visualize which methods call which, their parameters, and return
|
116
|
+
values.
|
125
117
|
test_files: []
|
data/MIT-LICENSE
DELETED
@@ -1,20 +0,0 @@
|
|
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.
|
@@ -1 +0,0 @@
|
|
1
|
-
//= link_directory ../stylesheets/checkpoint/rails .css
|
@@ -1,34 +0,0 @@
|
|
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
|
@@ -1,93 +0,0 @@
|
|
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
|
@@ -1,210 +0,0 @@
|
|
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
|