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.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +6 -49
  4. data/app/assets/config/checkpoint_rails_manifest.js +1 -0
  5. data/app/assets/stylesheets/{callstacking → checkpoint}/rails/application.css +0 -0
  6. data/app/controllers/{callstacking → checkpoint}/rails/application_controller.rb +1 -1
  7. data/app/controllers/checkpoint/rails/traces_controller.rb +6 -0
  8. data/app/helpers/{callstacking → checkpoint}/rails/application_helper.rb +1 -1
  9. data/app/jobs/{callstacking → checkpoint}/rails/application_job.rb +1 -1
  10. data/app/mailers/{callstacking → checkpoint}/rails/application_mailer.rb +1 -1
  11. data/app/models/{callstacking → checkpoint}/rails/application_record.rb +1 -1
  12. data/config/routes.rb +1 -1
  13. data/lib/{callstacking → checkpoint}/rails/client/authenticate.rb +1 -2
  14. data/lib/{callstacking → checkpoint}/rails/client/base.rb +3 -3
  15. data/lib/{callstacking → checkpoint}/rails/client/trace.rb +1 -3
  16. data/lib/checkpoint/rails/engine.rb +34 -0
  17. data/lib/{callstacking → checkpoint}/rails/env.rb +1 -3
  18. data/lib/{callstacking → checkpoint}/rails/settings.rb +5 -13
  19. data/lib/checkpoint/rails/setup.rb +93 -0
  20. data/lib/checkpoint/rails/traceable.rb +210 -0
  21. data/lib/{callstacking → checkpoint}/rails/traces_helper.rb +7 -7
  22. data/lib/checkpoint/rails/version.rb +5 -0
  23. data/lib/checkpoint/rails.rb +7 -0
  24. metadata +40 -32
  25. data/LICENSE +0 -621
  26. data/app/assets/config/callstacking_rails_manifest.js +0 -1
  27. data/exe/callstacking-rails +0 -32
  28. data/lib/callstacking/rails/engine.rb +0 -49
  29. data/lib/callstacking/rails/instrument.rb +0 -100
  30. data/lib/callstacking/rails/loader.rb +0 -29
  31. data/lib/callstacking/rails/setup.rb +0 -115
  32. data/lib/callstacking/rails/spans.rb +0 -53
  33. data/lib/callstacking/rails/trace.rb +0 -126
  34. data/lib/callstacking/rails/version.rb +0 -5
  35. 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
@@ -1,5 +0,0 @@
1
- module Callstacking
2
- module Rails
3
- VERSION = "0.1.1"
4
- end
5
- end
@@ -1,7 +0,0 @@
1
- require "callstacking/rails/version"
2
- require "callstacking/rails/engine"
3
-
4
- module Callstacking
5
- module Rails
6
- end
7
- end