callstacking-rails 0.1.1 → 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/MIT-LICENSE +20 -0
- data/README.md +6 -49
- data/app/assets/config/checkpoint_rails_manifest.js +1 -0
- data/app/assets/stylesheets/{callstacking → checkpoint}/rails/application.css +0 -0
- data/app/controllers/{callstacking → checkpoint}/rails/application_controller.rb +1 -1
- data/app/controllers/checkpoint/rails/traces_controller.rb +6 -0
- data/app/helpers/{callstacking → checkpoint}/rails/application_helper.rb +1 -1
- data/app/jobs/{callstacking → checkpoint}/rails/application_job.rb +1 -1
- data/app/mailers/{callstacking → checkpoint}/rails/application_mailer.rb +1 -1
- data/app/models/{callstacking → checkpoint}/rails/application_record.rb +1 -1
- data/config/routes.rb +1 -1
- data/lib/{callstacking → checkpoint}/rails/client/authenticate.rb +1 -2
- data/lib/{callstacking → checkpoint}/rails/client/base.rb +3 -3
- data/lib/{callstacking → checkpoint}/rails/client/trace.rb +1 -3
- data/lib/checkpoint/rails/engine.rb +34 -0
- data/lib/{callstacking → checkpoint}/rails/env.rb +1 -3
- data/lib/{callstacking → checkpoint}/rails/settings.rb +5 -13
- data/lib/checkpoint/rails/setup.rb +93 -0
- data/lib/checkpoint/rails/traceable.rb +210 -0
- data/lib/{callstacking → checkpoint}/rails/traces_helper.rb +7 -7
- data/lib/checkpoint/rails/version.rb +5 -0
- data/lib/checkpoint/rails.rb +7 -0
- metadata +40 -32
- data/LICENSE +0 -621
- data/app/assets/config/callstacking_rails_manifest.js +0 -1
- data/exe/callstacking-rails +0 -32
- data/lib/callstacking/rails/engine.rb +0 -49
- data/lib/callstacking/rails/instrument.rb +0 -100
- data/lib/callstacking/rails/loader.rb +0 -29
- data/lib/callstacking/rails/setup.rb +0 -115
- data/lib/callstacking/rails/spans.rb +0 -53
- data/lib/callstacking/rails/trace.rb +0 -126
- data/lib/callstacking/rails/version.rb +0 -5
- data/lib/callstacking/rails.rb +0 -7
@@ -1,49 +0,0 @@
|
|
1
|
-
require "rails"
|
2
|
-
require "callstacking/rails/trace"
|
3
|
-
require "callstacking/rails/instrument"
|
4
|
-
require 'callstacking/rails/spans'
|
5
|
-
require "callstacking/rails/setup"
|
6
|
-
require "callstacking/rails/settings"
|
7
|
-
require "callstacking/rails/loader"
|
8
|
-
require "callstacking/rails/client/base"
|
9
|
-
require "callstacking/rails/client/authenticate"
|
10
|
-
require "callstacking/rails/client/trace"
|
11
|
-
require "callstacking/rails/traces_helper"
|
12
|
-
|
13
|
-
module Callstacking
|
14
|
-
module Rails
|
15
|
-
class Engine < ::Rails::Engine
|
16
|
-
include Settings
|
17
|
-
isolate_namespace Callstacking::Rails
|
18
|
-
|
19
|
-
read_settings
|
20
|
-
|
21
|
-
spans = Spans.new
|
22
|
-
trace = Trace.new(spans)
|
23
|
-
|
24
|
-
initializer "engine_name.assets.precompile" do |app|
|
25
|
-
app.config.assets.precompile << "checkpoint_rails_manifest.js"
|
26
|
-
end
|
27
|
-
|
28
|
-
initializer 'local_helper.action_controller' do
|
29
|
-
ActiveSupport.on_load :action_controller do
|
30
|
-
helper Callstacking::Rails::TracesHelper
|
31
|
-
include Callstacking::Rails::TracesHelper
|
32
|
-
end
|
33
|
-
|
34
|
-
Callstacking::Rails::Loader.new.on_load(spans) if enabled?
|
35
|
-
end
|
36
|
-
|
37
|
-
initializer :append_before_action do
|
38
|
-
ActionController::Base.send :after_action, :inject_hud
|
39
|
-
end
|
40
|
-
|
41
|
-
if enabled?
|
42
|
-
puts "Callstacking enabled (#{Callstacking::Rails::Env.environment})"
|
43
|
-
trace.tracing
|
44
|
-
else
|
45
|
-
puts "Callstacking disabled (#{Callstacking::Rails::Env.environment})"
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
@@ -1,100 +0,0 @@
|
|
1
|
-
require 'rails'
|
2
|
-
|
3
|
-
# https://stackoverflow.com/q/52932516
|
4
|
-
module Callstacking
|
5
|
-
module Rails
|
6
|
-
class Instrument
|
7
|
-
attr_accessor :spans, :klass
|
8
|
-
attr_reader :root
|
9
|
-
|
10
|
-
def initialize(spans, klass)
|
11
|
-
@spans = spans
|
12
|
-
@klass = klass
|
13
|
-
@root = Regexp.new(::Rails.root.to_s)
|
14
|
-
end
|
15
|
-
|
16
|
-
def instrument_method(method_name, application_level: true)
|
17
|
-
method_path = (klass.instance_method(method_name).source_location.first rescue nil) ||
|
18
|
-
(klass.method(method_name).source_location.first rescue nil)
|
19
|
-
|
20
|
-
# Application level method definitions
|
21
|
-
return unless method_path =~ root if application_level
|
22
|
-
|
23
|
-
tmp_module = find_or_initialize_module
|
24
|
-
|
25
|
-
return if tmp_module.instance_methods.include?(method_name) ||
|
26
|
-
tmp_module.singleton_methods.include?(method_name)
|
27
|
-
|
28
|
-
tmp_module.define_method(method_name) do |*args, &block|
|
29
|
-
method_name = __method__
|
30
|
-
|
31
|
-
path = method(__method__).super_method.source_location.first
|
32
|
-
line_no = method(__method__).super_method.source_location.last
|
33
|
-
|
34
|
-
p, l = caller.find { |c| c.to_s =~ /#{::Rails.root.to_s}/}&.split(':')
|
35
|
-
|
36
|
-
spans = tmp_module.instance_variable_get(:@spans)
|
37
|
-
klass = tmp_module.instance_variable_get(:@klass)
|
38
|
-
|
39
|
-
arguments = Callstacking::Rails::Instrument.arguments_for(method(__method__).super_method, args)
|
40
|
-
|
41
|
-
spans.call_entry(klass, method_name, arguments, p || path, l || line_no)
|
42
|
-
return_val = super(*args, &block)
|
43
|
-
spans.call_return(klass, method_name, p || path, l || line_no, return_val)
|
44
|
-
|
45
|
-
return_val
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def find_or_initialize_module
|
50
|
-
module_name = "#{klass.name.gsub('::', '')}Span"
|
51
|
-
module_index = klass.ancestors.map(&:to_s).index(module_name)
|
52
|
-
|
53
|
-
unless module_index
|
54
|
-
new_module = Object.const_set(module_name, Module.new)
|
55
|
-
|
56
|
-
new_module.instance_variable_set("@klass", klass)
|
57
|
-
new_module.instance_variable_set("@spans", spans)
|
58
|
-
|
59
|
-
klass.prepend new_module
|
60
|
-
klass.singleton_class.prepend new_module if klass.class == Module
|
61
|
-
|
62
|
-
return find_or_initialize_module
|
63
|
-
end
|
64
|
-
|
65
|
-
klass.ancestors[module_index]
|
66
|
-
end
|
67
|
-
|
68
|
-
def instrument_klass(application_level: true)
|
69
|
-
relevant = all_methods - filtered
|
70
|
-
relevant.each { |method| instrument_method(method, application_level: application_level) }
|
71
|
-
end
|
72
|
-
|
73
|
-
def self.arguments_for(m, args)
|
74
|
-
param_names = m.parameters&.map(&:last)
|
75
|
-
return {} if param_names.nil?
|
76
|
-
|
77
|
-
param_names.map.with_index do |param, index|
|
78
|
-
next if [:&, :*, :**].include?(param)
|
79
|
-
[param, args[index]]
|
80
|
-
end.compact.to_h
|
81
|
-
end
|
82
|
-
|
83
|
-
private
|
84
|
-
|
85
|
-
def all_methods
|
86
|
-
@all_methods ||= (klass.instance_methods +
|
87
|
-
klass.private_instance_methods(false) +
|
88
|
-
klass.protected_instance_methods(false) +
|
89
|
-
klass.methods +
|
90
|
-
klass.singleton_methods).uniq
|
91
|
-
end
|
92
|
-
|
93
|
-
def filtered
|
94
|
-
@filtered ||= (Object.instance_methods + Object.private_instance_methods +
|
95
|
-
Object.protected_instance_methods + Object.methods(false)).uniq
|
96
|
-
end
|
97
|
-
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
require "rails"
|
2
|
-
|
3
|
-
module Callstacking
|
4
|
-
module Rails
|
5
|
-
class Loader
|
6
|
-
attr_accessor :loader, :root, :once
|
7
|
-
def initialize
|
8
|
-
@root = Regexp.new(::Rails.root.to_s)
|
9
|
-
end
|
10
|
-
|
11
|
-
def on_load(spans)
|
12
|
-
trace = TracePoint.new(:end) do |tp|
|
13
|
-
klass = tp.self
|
14
|
-
path = tp.path
|
15
|
-
|
16
|
-
Instrument.new(spans, klass).instrument_klass if path =~ root
|
17
|
-
end
|
18
|
-
|
19
|
-
trace.enable
|
20
|
-
|
21
|
-
Instrument.new(spans, ActionView::PartialRenderer).instrument_method(:render,
|
22
|
-
application_level: false)
|
23
|
-
|
24
|
-
Instrument.new(spans, ActionView::TemplateRenderer).instrument_method( :render,
|
25
|
-
application_level: false)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
@@ -1,115 +0,0 @@
|
|
1
|
-
require 'yaml'
|
2
|
-
require "callstacking/rails/settings"
|
3
|
-
require "callstacking/rails/client/authenticate"
|
4
|
-
require "callstacking/rails/env"
|
5
|
-
|
6
|
-
module Callstacking
|
7
|
-
module Rails
|
8
|
-
class Setup
|
9
|
-
include ::Callstacking::Rails::Settings
|
10
|
-
extend ::Callstacking::Rails::Settings
|
11
|
-
|
12
|
-
attr_accessor :client
|
13
|
-
|
14
|
-
def initialize
|
15
|
-
read_settings
|
16
|
-
end
|
17
|
-
|
18
|
-
def client
|
19
|
-
@client = Callstacking::Rails::Client::Authenticate.new
|
20
|
-
end
|
21
|
-
|
22
|
-
def start
|
23
|
-
email = prompt("Enter email:")
|
24
|
-
password = prompt("Enter password:")
|
25
|
-
|
26
|
-
url = if Callstacking::Rails::Env.production? && ENV['CHECKPOINT_RAILS_LOCAL_TEST'].nil?
|
27
|
-
PRODUCTION_URL
|
28
|
-
else
|
29
|
-
prompt("Enter URL for #{Callstacking::Rails::Env.environment} API calls [#{PRODUCTION_URL}]:") || PRODUCTION_URL
|
30
|
-
end
|
31
|
-
|
32
|
-
save(email, password, url)
|
33
|
-
|
34
|
-
puts "Authentication successful."
|
35
|
-
puts "Settings saved to #{SETTINGS_FILE}"
|
36
|
-
rescue StandardError => e
|
37
|
-
puts "Problem authenticating: #{e.message}"
|
38
|
-
end
|
39
|
-
|
40
|
-
def enable_disable(enabled: true)
|
41
|
-
settings[:enabled] = enabled
|
42
|
-
|
43
|
-
props = { Callstacking::Rails::Env.environment => {
|
44
|
-
settings: settings
|
45
|
-
} }
|
46
|
-
|
47
|
-
write_settings(complete_settings.merge(props))
|
48
|
-
end
|
49
|
-
|
50
|
-
def prompt(label)
|
51
|
-
puts label
|
52
|
-
value = STDIN.gets.chomp
|
53
|
-
puts
|
54
|
-
|
55
|
-
return nil if value == ''
|
56
|
-
value
|
57
|
-
end
|
58
|
-
|
59
|
-
def token(email, password)
|
60
|
-
client.login(email, password)
|
61
|
-
end
|
62
|
-
|
63
|
-
def save(email, password, url)
|
64
|
-
props = { auth_token: '',
|
65
|
-
url: url,
|
66
|
-
enabled: true
|
67
|
-
}
|
68
|
-
|
69
|
-
props = { Callstacking::Rails::Env.environment => {
|
70
|
-
settings: props
|
71
|
-
} }
|
72
|
-
|
73
|
-
write_settings(complete_settings.merge(props))
|
74
|
-
|
75
|
-
props[Callstacking::Rails::Env.environment][:settings][:auth_token] = token(email, password)
|
76
|
-
|
77
|
-
write_settings(complete_settings.merge(props))
|
78
|
-
|
79
|
-
read_settings
|
80
|
-
end
|
81
|
-
|
82
|
-
def self.instructions
|
83
|
-
read_settings
|
84
|
-
puts "loading environment #{Callstacking::Rails::Env.environment}"
|
85
|
-
puts
|
86
|
-
puts "Usage: "
|
87
|
-
puts
|
88
|
-
puts " > callstacking-rails enable"
|
89
|
-
puts
|
90
|
-
puts " Enables the callstacking tracing."
|
91
|
-
puts
|
92
|
-
puts " > callstacking-rails disable"
|
93
|
-
puts
|
94
|
-
puts " Disables the callstacking tracing."
|
95
|
-
puts
|
96
|
-
puts " > callstacking-rails register"
|
97
|
-
puts
|
98
|
-
puts " Opens a browser window to register as a callstacking.com user."
|
99
|
-
puts
|
100
|
-
puts " > callstacking-rails setup"
|
101
|
-
puts
|
102
|
-
puts " Interactively prompts you for your callstacking.com username/password."
|
103
|
-
puts " Stores auth details in #{SETTINGS_FILE}"
|
104
|
-
puts
|
105
|
-
puts " You can have multiple environments."
|
106
|
-
puts " The default is #{Callstacking::Rails::Env::DEFAULT_ENVIRONMENT}."
|
107
|
-
puts
|
108
|
-
puts " The #{Callstacking::Rails::Env.environment}: section in the #{SETTINGS_FILE} contains your credentials."
|
109
|
-
puts " By setting the RAILS_ENV environment you can maintain multiple settings."
|
110
|
-
puts
|
111
|
-
puts "Questions? Create an issue: https://github.com/callstacking/callstacking-rails/issues"
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
@@ -1,53 +0,0 @@
|
|
1
|
-
module Callstacking
|
2
|
-
module Rails
|
3
|
-
class Spans
|
4
|
-
attr_accessor :order_num, :nesting_level, :previous_entry
|
5
|
-
attr_accessor :call_entry_callback, :call_return_callback
|
6
|
-
|
7
|
-
def initialize
|
8
|
-
@nesting_level = -1
|
9
|
-
@order_num = -1
|
10
|
-
@previous_entry = nil
|
11
|
-
end
|
12
|
-
|
13
|
-
def increment_order_num
|
14
|
-
@order_num+=1
|
15
|
-
@order_num
|
16
|
-
end
|
17
|
-
|
18
|
-
def increment_nesting_level
|
19
|
-
@nesting_level+=1
|
20
|
-
@nesting_level
|
21
|
-
end
|
22
|
-
|
23
|
-
def call_entry(klass, method_name, arguments, path, line_no)
|
24
|
-
@nesting_level+=1
|
25
|
-
@previous_entry = previous_event(klass, method_name)
|
26
|
-
@call_entry_callback.call(@nesting_level, increment_order_num, klass, method_name, arguments, path, line_no)
|
27
|
-
end
|
28
|
-
|
29
|
-
def call_return(klass, method_name, path, line_no, return_val)
|
30
|
-
@call_return_callback.call(coupled_callee(klass, method_name), @nesting_level,
|
31
|
-
increment_order_num, klass, method_name, path, line_no, return_val)
|
32
|
-
@nesting_level-=1
|
33
|
-
end
|
34
|
-
|
35
|
-
def on_call_entry(&block)
|
36
|
-
@call_entry_callback = block
|
37
|
-
end
|
38
|
-
|
39
|
-
def on_call_return(&block)
|
40
|
-
@call_return_callback = block
|
41
|
-
end
|
42
|
-
|
43
|
-
private
|
44
|
-
def previous_event(klass, method_name)
|
45
|
-
"#{klass}:#{method_name}"
|
46
|
-
end
|
47
|
-
|
48
|
-
def coupled_callee(klass, method_name)
|
49
|
-
previous_entry == previous_event(klass, method_name)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
@@ -1,126 +0,0 @@
|
|
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
|