callstacking-rails 0.1.30 → 0.1.32
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/lib/callstacking/rails/client/base.rb +1 -3
- data/lib/callstacking/rails/client/trace.rb +5 -0
- data/lib/callstacking/rails/engine.rb +51 -16
- data/lib/callstacking/rails/instrument.rb +23 -8
- data/lib/callstacking/rails/loader.rb +25 -8
- data/lib/callstacking/rails/logger.rb +18 -0
- data/lib/callstacking/rails/settings.rb +5 -7
- data/lib/callstacking/rails/trace.rb +14 -4
- data/lib/callstacking/rails/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 002a4d9f1b5077534ba5ea5dfc3b418fa77325a4028cd4ed9322803cb0200fb5
|
4
|
+
data.tar.gz: e9eb4f9d680d978e66f38f754b8c8e251e243628b8317dfa004df95545661048
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 70c5b03becd0e1e054a5d7142130dfce3ae8e7310a9a249ea6742a95f45b5f3f52a8f59832820c1cd981fbd556ede7f2b672de1ad56cc61e16a978a216fd0b55
|
7
|
+
data.tar.gz: 54719e4784c2c945e05eafdbc202de21c4bf425a5d0a4ce1c9403e9154851ba18a63883e2bf32712d23342cb5f9c0257d65bfd02630b9cb6bd4b58f878479baf
|
@@ -21,8 +21,6 @@ module Callstacking
|
|
21
21
|
# https://github.com/lostisland/awesome-faraday
|
22
22
|
@connection ||= Faraday.new(url) do |c|
|
23
23
|
c.response :json
|
24
|
-
c.use Faraday::Response::Logger, Logger.new('/tmp/callstacking-rails.log')
|
25
|
-
# c.use Faraday::Response::Logger, nil, { headers: false, bodies: false }
|
26
24
|
c.response :follow_redirects
|
27
25
|
c.use Faraday::Response::RaiseError # raise exceptions on 40x, 50x responses
|
28
26
|
c.request :json # This will set the "Content-Type" header to application/json and call .to_json on the body
|
@@ -35,7 +33,7 @@ module Callstacking
|
|
35
33
|
end
|
36
34
|
end
|
37
35
|
|
38
|
-
def get(url, params = {})
|
36
|
+
def get(url, params = {}, headers = {})
|
39
37
|
if async
|
40
38
|
threads << Thread.new do
|
41
39
|
connection.get(url, params, headers)
|
@@ -6,6 +6,7 @@ module Callstacking
|
|
6
6
|
class Trace < Base
|
7
7
|
CREATE_URL = "/api/v1/traces.json"
|
8
8
|
UPDATE_URL = "/api/v1/traces/:id.json"
|
9
|
+
SHOW_URL = "/api/v1/traces/:id.json"
|
9
10
|
|
10
11
|
def initialize(url, auth_token)
|
11
12
|
super
|
@@ -37,6 +38,10 @@ module Callstacking
|
|
37
38
|
def upsert(trace_id, traces)
|
38
39
|
patch(UPDATE_URL.gsub(':id', trace_id), {}, traces)
|
39
40
|
end
|
41
|
+
|
42
|
+
def show(trace_id, params = {})
|
43
|
+
get(SHOW_URL.gsub(':id', trace_id), params)
|
44
|
+
end
|
40
45
|
end
|
41
46
|
end
|
42
47
|
end
|
@@ -13,46 +13,81 @@ require "callstacking/rails/client/trace"
|
|
13
13
|
require "callstacking/rails/cli"
|
14
14
|
require "callstacking/rails/time_based_uuid"
|
15
15
|
require "callstacking/rails/helpers/instrument_helper"
|
16
|
+
require "callstacking/rails/logger"
|
16
17
|
|
17
18
|
module Callstacking
|
18
19
|
module Rails
|
19
20
|
class Engine < ::Rails::Engine
|
20
|
-
EXCLUDED_TEST_CLASSES = %w[test/dummy/app/models/salutation.rb
|
21
|
+
EXCLUDED_TEST_CLASSES = %w[test/dummy/app/models/salutation.rb
|
22
|
+
test/dummy/app/controllers/application_controller.rb].freeze
|
21
23
|
|
22
|
-
cattr_accessor :spans, :
|
24
|
+
cattr_accessor :spans, :traces, :settings, :instrumenter, :loader, :lock
|
23
25
|
|
24
26
|
isolate_namespace Callstacking::Rails
|
25
27
|
|
28
|
+
@@spans||={}
|
29
|
+
@@traces||={}
|
30
|
+
@@lock||=Mutex.new
|
31
|
+
@@instrumenter||=Instrument.new
|
26
32
|
@@settings||=Callstacking::Rails::Settings.new
|
27
|
-
@@spans||=Spans.new
|
28
|
-
@@trace||=Trace.new(@@spans)
|
29
|
-
@@instrumenter||=Instrument.new(@@spans)
|
30
33
|
|
31
34
|
initializer "engine_name.assets.precompile" do |app|
|
32
35
|
app.config.assets.precompile << "checkpoint_rails_manifest.js"
|
33
36
|
end
|
34
37
|
|
35
38
|
config.after_initialize do
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
39
|
+
Logger.log "Call Stacking loading (#{Callstacking::Rails::Env.environment})"
|
40
|
+
|
41
|
+
spans[Thread.current.object_id]||=Spans.new
|
42
|
+
instrumenter.add_span(spans[Thread.current.object_id])
|
43
|
+
|
44
|
+
@@loader = Callstacking::Rails::Loader.new(instrumenter,
|
45
|
+
excluded: settings.excluded + EXCLUDED_TEST_CLASSES)
|
46
|
+
loader.on_load
|
40
47
|
end
|
41
48
|
|
49
|
+
# Serialize all tracing requests for now.
|
50
|
+
# Can enable parallel tracing later.
|
42
51
|
def self.start_tracing(controller)
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
52
|
+
Logger.log("Callstacking::Rails::Engine.start_tracing")
|
53
|
+
|
54
|
+
settings.enable!
|
55
|
+
|
56
|
+
lock.synchronize do
|
57
|
+
spans[Thread.current.object_id]||=Spans.new
|
58
|
+
span = spans[Thread.current.object_id]
|
59
|
+
|
60
|
+
instrumenter.add_span(span)
|
61
|
+
|
62
|
+
if instrumenter.instrumentation_required?
|
63
|
+
loader.reset!
|
64
|
+
instrumenter.enable!(loader.klasses.to_a)
|
65
|
+
end
|
66
|
+
|
67
|
+
traces[Thread.current.object_id] = Trace.new(span)
|
68
|
+
trace = traces[Thread.current.object_id]
|
69
|
+
|
70
|
+
trace.begin_trace(controller)
|
71
|
+
end
|
47
72
|
|
48
73
|
true
|
49
74
|
end
|
50
75
|
|
51
76
|
def self.stop_tracing(controller)
|
52
|
-
|
53
|
-
|
54
|
-
|
77
|
+
Logger.log("Callstacking::Rails::Engine.stop_tracing")
|
78
|
+
|
79
|
+
settings.disable!
|
80
|
+
|
81
|
+
trace = nil
|
82
|
+
lock.synchronize do
|
83
|
+
trace = traces.delete(Thread.current.object_id)
|
84
|
+
if traces.empty?
|
85
|
+
instrumenter.disable!
|
86
|
+
end
|
87
|
+
end
|
55
88
|
|
89
|
+
trace&.end_trace(controller)
|
90
|
+
|
56
91
|
true
|
57
92
|
end
|
58
93
|
end
|
@@ -7,8 +7,8 @@ module Callstacking
|
|
7
7
|
attr_accessor :spans
|
8
8
|
attr_reader :settings, :span_modules
|
9
9
|
|
10
|
-
def initialize
|
11
|
-
@spans =
|
10
|
+
def initialize
|
11
|
+
@spans = {}
|
12
12
|
@span_modules = Set.new
|
13
13
|
@settings = Callstacking::Rails::Settings.new
|
14
14
|
end
|
@@ -34,6 +34,9 @@ module Callstacking
|
|
34
34
|
new_method = nil
|
35
35
|
if RUBY_VERSION < "2.7.8"
|
36
36
|
new_method = tmp_module.define_method(method_name) do |*args, &block|
|
37
|
+
settings = tmp_module.instance_variable_get(:@settings)
|
38
|
+
return super(*args, &block) if settings.disabled?
|
39
|
+
|
37
40
|
method_name = __method__
|
38
41
|
|
39
42
|
path = method(__method__).super_method.source_location.first
|
@@ -42,19 +45,23 @@ module Callstacking
|
|
42
45
|
p, l = caller.find { |c| c.to_s =~ /#{::Rails.root.to_s}/}&.split(':')
|
43
46
|
|
44
47
|
spans = tmp_module.instance_variable_get(:@spans)
|
48
|
+
span = spans[Thread.current.object_id]
|
45
49
|
klass = tmp_module.instance_variable_get(:@klass)
|
46
50
|
|
47
51
|
arguments = Callstacking::Rails::Instrument.arguments_for(method(__method__).super_method, args)
|
48
52
|
|
49
|
-
|
53
|
+
span.call_entry(klass, method_name, arguments, p || path, l || line_no)
|
50
54
|
return_val = super(*args, &block)
|
51
|
-
|
55
|
+
span.call_return(klass, method_name, p || path, l || line_no, return_val)
|
52
56
|
|
53
57
|
return_val
|
54
58
|
end
|
55
59
|
new_method.ruby2_keywords if new_method.respond_to?(:ruby2_keywords)
|
56
60
|
else
|
57
61
|
new_method = tmp_module.define_method(method_name) do |*args, **kwargs, &block|
|
62
|
+
settings = tmp_module.instance_variable_get(:@settings)
|
63
|
+
return super(*args, **kwargs, &block) if settings.disabled?
|
64
|
+
|
58
65
|
method_name = __method__
|
59
66
|
|
60
67
|
path = method(__method__).super_method.source_location.first
|
@@ -63,13 +70,14 @@ module Callstacking
|
|
63
70
|
p, l = caller.find { |c| c.to_s =~ /#{::Rails.root.to_s}/}&.split(':')
|
64
71
|
|
65
72
|
spans = tmp_module.instance_variable_get(:@spans)
|
73
|
+
span = spans[Thread.current.object_id]
|
66
74
|
klass = tmp_module.instance_variable_get(:@klass)
|
67
75
|
|
68
76
|
arguments = Callstacking::Rails::Instrument.arguments_for(method(__method__).super_method, args)
|
69
77
|
|
70
|
-
|
78
|
+
span.call_entry(klass, method_name, arguments, p || path, l || line_no)
|
71
79
|
return_val = super(*args, **kwargs, &block)
|
72
|
-
|
80
|
+
span.call_return(klass, method_name, p || path, l || line_no, return_val)
|
73
81
|
|
74
82
|
return_val
|
75
83
|
end
|
@@ -80,8 +88,6 @@ module Callstacking
|
|
80
88
|
end
|
81
89
|
|
82
90
|
def enable!(klasses)
|
83
|
-
reset!
|
84
|
-
|
85
91
|
Array.wrap(klasses).each do |klass|
|
86
92
|
instrument_klass(klass, application_level: true)
|
87
93
|
end
|
@@ -97,6 +103,10 @@ module Callstacking
|
|
97
103
|
reset!
|
98
104
|
end
|
99
105
|
|
106
|
+
def instrumentation_required?
|
107
|
+
span_modules.empty?
|
108
|
+
end
|
109
|
+
|
100
110
|
def reset!
|
101
111
|
span_modules.clear
|
102
112
|
end
|
@@ -120,6 +130,10 @@ module Callstacking
|
|
120
130
|
f.filter h
|
121
131
|
end
|
122
132
|
|
133
|
+
def add_span(span)
|
134
|
+
spans[Thread.current.object_id] ||= span
|
135
|
+
end
|
136
|
+
|
123
137
|
private
|
124
138
|
def find_or_initialize_module(klass)
|
125
139
|
name = klass&.name rescue nil
|
@@ -137,6 +151,7 @@ module Callstacking
|
|
137
151
|
|
138
152
|
new_module.instance_variable_set("@klass", klass)
|
139
153
|
new_module.instance_variable_set("@spans", spans)
|
154
|
+
new_module.instance_variable_set("@settings", settings)
|
140
155
|
|
141
156
|
klass.prepend new_module
|
142
157
|
klass.singleton_class.prepend new_module if klass.class == Module
|
@@ -1,13 +1,21 @@
|
|
1
1
|
require "rails"
|
2
|
+
require "callstacking/rails/logger"
|
2
3
|
|
3
4
|
module Callstacking
|
4
5
|
module Rails
|
5
6
|
class Loader
|
6
|
-
attr_accessor :instrumenter, :klasses, :excluded
|
7
|
+
attr_accessor :instrumenter, :klasses, :excluded, :settings
|
7
8
|
def initialize(instrumenter, excluded: [])
|
8
9
|
@excluded = excluded
|
9
10
|
@instrumenter = instrumenter
|
10
11
|
@klasses = Set.new
|
12
|
+
@settings = Callstacking::Rails::Settings.new
|
13
|
+
|
14
|
+
preloaded_klasses
|
15
|
+
end
|
16
|
+
|
17
|
+
def preloaded_klasses
|
18
|
+
ObjectSpace.each_object(Module){|ob| filter_klass(ob, (Object.const_source_location(ob.to_s)&.first rescue nil))}
|
11
19
|
end
|
12
20
|
|
13
21
|
def on_load
|
@@ -15,13 +23,7 @@ module Callstacking
|
|
15
23
|
klass = tp.self
|
16
24
|
path = tp.path
|
17
25
|
|
18
|
-
|
19
|
-
|
20
|
-
if path =~ /#{::Rails.root.to_s}/ &&
|
21
|
-
!klasses.include?(klass) &&
|
22
|
-
!excluded_klass
|
23
|
-
klasses << klass
|
24
|
-
end
|
26
|
+
filter_klass(klass, path)
|
25
27
|
end
|
26
28
|
|
27
29
|
trace.enable
|
@@ -31,6 +33,21 @@ module Callstacking
|
|
31
33
|
instrumenter.instrument_method(ActionView::PartialRenderer, :render, application_level: false)
|
32
34
|
instrumenter.instrument_method(ActionView::TemplateRenderer, :render, application_level: false)
|
33
35
|
end
|
36
|
+
|
37
|
+
private
|
38
|
+
def filter_klass(klass, path)
|
39
|
+
return if klass.nil? || path.nil?
|
40
|
+
return if path == false
|
41
|
+
|
42
|
+
excluded_klass = excluded.any? { |ex| path =~ /#{ex}/ }
|
43
|
+
|
44
|
+
if path =~ /#{::Rails.root.to_s}/ &&
|
45
|
+
!klasses.include?(klass) &&
|
46
|
+
!excluded_klass
|
47
|
+
instrumenter.instrument_klass(klass) if settings.enabled?
|
48
|
+
klasses << klass
|
49
|
+
end
|
50
|
+
end
|
34
51
|
end
|
35
52
|
end
|
36
53
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Callstacking
|
2
|
+
module Rails
|
3
|
+
class Logger
|
4
|
+
def self.log(message)
|
5
|
+
puts message
|
6
|
+
|
7
|
+
if ENV['GITHUB_OUTPUT'].present?
|
8
|
+
File.open(ENV['GITHUB_OUTPUT'], 'a') do |file|
|
9
|
+
# Write your progress output to the file
|
10
|
+
# This could be inside a loop or condition, depending on your needs
|
11
|
+
file.puts "::set-output name=progress_output::#{message}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
@@ -35,14 +35,14 @@ module Callstacking
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def self.enable!
|
38
|
-
|
38
|
+
Thread.current[CACHE_KEY] = true
|
39
39
|
end
|
40
40
|
def enable!
|
41
41
|
self.class.enable!
|
42
42
|
end
|
43
43
|
|
44
44
|
def self.disable!
|
45
|
-
|
45
|
+
Thread.current[CACHE_KEY] = false
|
46
46
|
end
|
47
47
|
|
48
48
|
def disable!
|
@@ -50,11 +50,9 @@ module Callstacking
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def enabled?
|
53
|
-
return ::
|
54
|
-
return
|
55
|
-
|
56
|
-
|
57
|
-
settings[:enabled]
|
53
|
+
return ActiveRecord::Type::Boolean.new.cast(ENV[ENV_KEY]) if ENV[ENV_KEY].present?
|
54
|
+
return Thread.current[CACHE_KEY] if Thread.current[CACHE_KEY].present?
|
55
|
+
false
|
58
56
|
end
|
59
57
|
|
60
58
|
def excluded
|
@@ -7,18 +7,22 @@ module Callstacking
|
|
7
7
|
class Trace
|
8
8
|
include Callstacking::Rails::Helpers::HeadsUpDisplayHelper
|
9
9
|
|
10
|
-
attr_accessor :spans, :client, :lock
|
10
|
+
attr_accessor :spans, :client, :lock, :traces
|
11
11
|
attr_reader :settings
|
12
12
|
cattr_accessor :current_trace_id
|
13
13
|
cattr_accessor :current_tuid
|
14
|
+
cattr_accessor :trace_log
|
14
15
|
|
15
16
|
ICON = '💥'
|
16
17
|
MAX_TRACE_ENTRIES = 3000
|
18
|
+
|
19
|
+
@@trace_log||={}
|
17
20
|
|
18
21
|
def initialize(spans)
|
19
|
-
|
20
|
-
@
|
21
|
-
@
|
22
|
+
|
23
|
+
@traces = []
|
24
|
+
@spans = spans
|
25
|
+
@settings = Callstacking::Rails::Settings.new
|
22
26
|
|
23
27
|
@lock = Mutex.new
|
24
28
|
@client = Callstacking::Rails::Client::Trace.new(settings.url, settings.auth_token)
|
@@ -29,6 +33,8 @@ module Callstacking
|
|
29
33
|
|
30
34
|
def begin_trace(controller)
|
31
35
|
@trace_id, @tuid = init_uuids(controller.request&.request_id || SecureRandom.uuid, TimeBasedUUID.generate)
|
36
|
+
trace_log[@trace_id] = controller.request&.original_url
|
37
|
+
|
32
38
|
init_callbacks(@tuid)
|
33
39
|
|
34
40
|
start_request(@trace_id, @tuid,
|
@@ -50,6 +56,10 @@ module Callstacking
|
|
50
56
|
inject_hud(@settings, controller.request, controller.response)
|
51
57
|
end
|
52
58
|
|
59
|
+
def self.trace_log_clear
|
60
|
+
trace_log.clear
|
61
|
+
end
|
62
|
+
|
53
63
|
private
|
54
64
|
|
55
65
|
def init_callbacks(tuid)
|
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.32
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jim Jones
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-05-
|
11
|
+
date: 2023-05-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -112,6 +112,7 @@ files:
|
|
112
112
|
- lib/callstacking/rails/helpers/instrument_helper.rb
|
113
113
|
- lib/callstacking/rails/instrument.rb
|
114
114
|
- lib/callstacking/rails/loader.rb
|
115
|
+
- lib/callstacking/rails/logger.rb
|
115
116
|
- lib/callstacking/rails/settings.rb
|
116
117
|
- lib/callstacking/rails/setup.rb
|
117
118
|
- lib/callstacking/rails/spans.rb
|