stackify-ruby-apm 1.4.0 → 1.5.0
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/README.md +21 -1
- data/lib/stackify_apm/config.rb +7 -6
- data/lib/stackify_apm/instrumenter_helper.rb +165 -0
- data/lib/stackify_apm/logger/logger_high_version.rb +1 -0
- data/lib/stackify_apm/logger/logger_lower_version.rb +1 -0
- data/lib/stackify_apm/serializers/transactions.rb +6 -1
- data/lib/stackify_apm/span/context.rb +5 -0
- data/lib/stackify_apm/spies.rb +37 -4
- data/lib/stackify_apm/spies/custom_instrumenter.rb +24 -73
- data/lib/stackify_apm/spies/httparty.rb +61 -0
- data/lib/stackify_apm/spies/net_http.rb +9 -8
- data/lib/stackify_apm/version.rb +1 -1
- data/lib/stackify_ruby_apm.rb +9 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5644c5079318a7c3529770465f45372106c02a8334b4648880cee789495c9a17
|
4
|
+
data.tar.gz: 6309a247094d7795b7abf970bf7ca46c3ea6a499de6aa03cb8b92c22080ee191
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b3ebbe0dc60d749aa5cffde012ac3f5fa815fd3b1a52c110fc9ff213ab7252a69a1d43dc951f3578c725cfdc32e29b3b1a1f59666293357c3f86deabefd6b5f5
|
7
|
+
data.tar.gz: 97a7f413c89124d246d4c499c8fada9e6c2373a21adc3e096fcce9c8dadd1cb0e32e55b300cbe1c4c3a633711444ef3822796596047cf2b25629f7fc00d1b0fa
|
data/README.md
CHANGED
@@ -25,6 +25,14 @@
|
|
25
25
|
```
|
26
26
|
5. Build/Deploy your application
|
27
27
|
|
28
|
+
### Custom Instrumentation in Rails
|
29
|
+
|
30
|
+
In the config/initializer folder of your Rails app create a file `config/initializer/stackify.rb` and then add this configuration
|
31
|
+
|
32
|
+
Rails.configuration.to_prepare do
|
33
|
+
StackifyRubyAPM.run_custom_instrument
|
34
|
+
end
|
35
|
+
|
28
36
|
### Non-Rails Guide
|
29
37
|
|
30
38
|
1. Install **Stackify Linux Agent**.
|
@@ -47,9 +55,21 @@
|
|
47
55
|
|
48
56
|
5. In the `config.ru` add the following lines:
|
49
57
|
|
50
|
-
```
|
58
|
+
```
|
59
|
+
use StackifyRubyAPM::Middleware
|
51
60
|
StackifyRubyAPM.start
|
52
61
|
at_exit { StackifyRubyAPM.stop }
|
53
62
|
```
|
54
63
|
|
55
64
|
6. Build/Deploy your application
|
65
|
+
|
66
|
+
### Custom Instrumentation in Non-Rails
|
67
|
+
|
68
|
+
In `config.ru` file add this line: StackifyRubyAPM.run_custom_instrument
|
69
|
+
|
70
|
+
Example:
|
71
|
+
|
72
|
+
use StackifyRubyAPM::Middleware
|
73
|
+
StackifyRubyAPM.start
|
74
|
+
StackifyRubyAPM.run_custom_instrument
|
75
|
+
at_exit { StackifyRubyAPM.stop }
|
data/lib/stackify_apm/config.rb
CHANGED
@@ -175,6 +175,7 @@ module StackifyRubyAPM
|
|
175
175
|
curb
|
176
176
|
curb/easy
|
177
177
|
curb/multi
|
178
|
+
httparty
|
178
179
|
stackify_logger
|
179
180
|
]
|
180
181
|
end
|
@@ -312,21 +313,21 @@ module StackifyRubyAPM
|
|
312
313
|
@device_id = nil
|
313
314
|
@client_run_domain = nil
|
314
315
|
begin
|
315
|
-
info 'Reading the Stackify props in Environment variables'
|
316
|
+
info '[Config] Reading the Stackify props in Environment variables'
|
316
317
|
@client_run_domain = ENV['STACKIFY_RUM_DOMAIN'] || nil
|
317
318
|
if ENV['STACKIFY_ENV']
|
318
319
|
props = ENV['STACKIFY_ENV'].split('|')
|
319
320
|
@client_id = props[0].to_s if props[0]
|
320
321
|
@device_id = props[1].to_s if props[1]
|
321
|
-
info "stackify.properties: clientId=#{@client_id}, deviceId=#{@device_id}, client_rum_domain=#{@client_run_domain}"
|
322
|
+
info "[Config] stackify.properties: clientId=#{@client_id}, deviceId=#{@device_id}, client_rum_domain=#{@client_run_domain}"
|
322
323
|
end
|
323
324
|
rescue StandardError => e
|
324
|
-
info 'Error occured while reading the Stackify props in Environment variables.'
|
325
|
+
info '[Config] Error occured while reading the Stackify props in Environment variables.'
|
325
326
|
info e.inspect
|
326
327
|
end
|
327
|
-
info 'No clientId found in environment variables.' if @client_id.nil?
|
328
|
-
info 'No deviceId found in environment variables.' if @device_id.nil?
|
329
|
-
info 'No client RUM domain found in environment variables.' if @client_run_domain.nil?
|
328
|
+
info '[Config] No clientId found in environment variables.' if @client_id.nil?
|
329
|
+
info '[Config] No deviceId found in environment variables.' if @device_id.nil?
|
330
|
+
info '[Config] No client RUM domain found in environment variables.' if @client_run_domain.nil?
|
330
331
|
end
|
331
332
|
# rubocop:enable Metrics/CyclomaticComplexity
|
332
333
|
# rubocop:enable Metrics/PerceivedComplexity
|
@@ -0,0 +1,165 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# This class will custom instrument a class and method
|
4
|
+
|
5
|
+
module StackifyRubyAPM
|
6
|
+
# @api private
|
7
|
+
class InstrumenterHelper
|
8
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
9
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
10
|
+
# rubocop:disable Lint/UselessAssignment
|
11
|
+
# rubocop:disable Security/Eval
|
12
|
+
attr_accessor :custom_instrumented, :custom_class_info
|
13
|
+
@custom_instrumented = {}
|
14
|
+
@custom_class_info = {}
|
15
|
+
|
16
|
+
def self.custom_instrumented_reset
|
17
|
+
@custom_instrumented.each do |custom_instrument, values|
|
18
|
+
current_class = custom_instrument
|
19
|
+
module_consget = Module.const_get(current_class)
|
20
|
+
values.each_key do |current_method|
|
21
|
+
is_method_exists = StackifyRubyAPM::Spies.ismethod_exists(current_class, current_method)
|
22
|
+
if is_method_exists
|
23
|
+
@custom_instrumented[current_class.to_s][current_method.to_s] = false
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.m_class(tracked_func, current_class, class_path, current_method, tracked_function_name)
|
30
|
+
module_consget = Module.const_get(current_class)
|
31
|
+
classspyitem = "#{current_class}Spy"
|
32
|
+
module_consget_spy = Module.const_get(current_class)
|
33
|
+
current_method_without = "_without_apm_#{current_method}"
|
34
|
+
|
35
|
+
unless @custom_instrumented[current_class.to_s]
|
36
|
+
@custom_instrumented[current_class.to_s] = {}
|
37
|
+
end
|
38
|
+
|
39
|
+
unless @custom_instrumented[current_class.to_s][current_method.to_s]
|
40
|
+
@custom_instrumented[current_class.to_s][current_method.to_s] = false
|
41
|
+
end
|
42
|
+
|
43
|
+
unless @custom_class_info[current_class.to_s]
|
44
|
+
@custom_class_info[current_class.to_s] = {}
|
45
|
+
end
|
46
|
+
|
47
|
+
unless @custom_class_info[current_class.to_s]['controller']
|
48
|
+
@custom_class_info[current_class.to_s]['controller'] = false
|
49
|
+
end
|
50
|
+
|
51
|
+
unless @custom_class_info[current_class.to_s]['model']
|
52
|
+
@custom_class_info[current_class.to_s]['model'] = false
|
53
|
+
end
|
54
|
+
|
55
|
+
return unless @custom_instrumented[current_class.to_s][current_method.to_s] == false
|
56
|
+
|
57
|
+
eval <<-RUBY
|
58
|
+
class #{classspyitem}
|
59
|
+
def install
|
60
|
+
#{current_class}.class_eval do
|
61
|
+
alias_method "#{current_method_without}", "#{current_method}"
|
62
|
+
|
63
|
+
def #{current_method}(*args, &block)
|
64
|
+
return #{current_method_without}(*args, &block) unless StackifyRubyAPM.current_transaction
|
65
|
+
|
66
|
+
name = "Custom Instrument"
|
67
|
+
type = "#{current_class}##{current_method}"
|
68
|
+
ctx = if "#{tracked_func}" == 'true'
|
69
|
+
Span::Context.new(
|
70
|
+
CATEGORY: 'Ruby',
|
71
|
+
TRACKED_FUNC: "#{tracked_function_name}"
|
72
|
+
)
|
73
|
+
else
|
74
|
+
Span::Context.new(
|
75
|
+
CATEGORY: 'Ruby'
|
76
|
+
)
|
77
|
+
end
|
78
|
+
|
79
|
+
req = #{current_method_without}(*args, &block)
|
80
|
+
StackifyRubyAPM.span name, type, context: ctx do
|
81
|
+
req
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
StackifyRubyAPM::Spies.register current_class.to_s, class_path.to_s, #{classspyitem}.new, true, "#{current_method}", "#{tracked_func}", "#{tracked_function_name}"
|
88
|
+
RUBY
|
89
|
+
|
90
|
+
@custom_instrumented[current_class.to_s][current_method.to_s] = true
|
91
|
+
@custom_class_info[current_class.to_s]['controller'] = true if class_path && class_path.include?('controllers')
|
92
|
+
@custom_class_info[current_class.to_s]['model'] = true if class_path && class_path.include?('models')
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.m_singleton(tracked_func, current_class, class_path, current_method, tracked_function_name)
|
96
|
+
module_consget = Module.const_get(current_class)
|
97
|
+
classspyitem = "#{current_class}Spy"
|
98
|
+
|
99
|
+
unless @custom_instrumented[current_class.to_s]
|
100
|
+
@custom_instrumented[current_class.to_s] = {}
|
101
|
+
end
|
102
|
+
|
103
|
+
unless @custom_instrumented[current_class.to_s][current_method.to_s]
|
104
|
+
@custom_instrumented[current_class.to_s][current_method.to_s] = false
|
105
|
+
end
|
106
|
+
|
107
|
+
unless @custom_class_info[current_class.to_s]
|
108
|
+
@custom_class_info[current_class.to_s] = {}
|
109
|
+
end
|
110
|
+
|
111
|
+
unless @custom_class_info[current_class.to_s]['controller']
|
112
|
+
@custom_class_info[current_class.to_s]['controller'] = false
|
113
|
+
end
|
114
|
+
|
115
|
+
unless @custom_class_info[current_class.to_s]['model']
|
116
|
+
@custom_class_info[current_class.to_s]['model'] = false
|
117
|
+
end
|
118
|
+
|
119
|
+
return unless @custom_instrumented[current_class.to_s][current_method.to_s] == false
|
120
|
+
|
121
|
+
eval <<-RUBY
|
122
|
+
class #{classspyitem}
|
123
|
+
def install
|
124
|
+
#{current_class}.class_eval do
|
125
|
+
singleton_class.send(:alias_method, :"_self_without_apm_#{current_method}", :"#{current_method}")
|
126
|
+
|
127
|
+
def self.#{current_method}(*args, &block)
|
128
|
+
return _self_without_apm_#{current_method}(*args, &block) unless StackifyRubyAPM.current_transaction
|
129
|
+
|
130
|
+
name = "Custom Instrument"
|
131
|
+
type = "#{current_class}##{current_method}"
|
132
|
+
ctx = if "#{tracked_func}" == 'true'
|
133
|
+
Span::Context.new(
|
134
|
+
CATEGORY: 'Ruby',
|
135
|
+
TRACKED_FUNC: "#{tracked_function_name}"
|
136
|
+
)
|
137
|
+
else
|
138
|
+
Span::Context.new(
|
139
|
+
CATEGORY: 'Ruby'
|
140
|
+
)
|
141
|
+
end
|
142
|
+
req = _self_without_apm_#{current_method}(*args, &block)
|
143
|
+
StackifyRubyAPM.span name, type, context: ctx do
|
144
|
+
req
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def self.get_class_name
|
149
|
+
return self.class.name
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
StackifyRubyAPM::Spies.register current_class.to_s, class_path.to_s, #{classspyitem}.new, true, "#{current_method}", "#{tracked_func}", "#{tracked_function_name}"
|
155
|
+
RUBY
|
156
|
+
@custom_instrumented[current_class.to_s][current_method.to_s] = true
|
157
|
+
@custom_class_info[current_class.to_s]['controller'] = true if class_path && class_path.include?('controllers')
|
158
|
+
@custom_class_info[current_class.to_s]['model'] = true if class_path && class_path.include?('models')
|
159
|
+
end
|
160
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
161
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
162
|
+
# rubocop:enable Lint/UselessAssignment
|
163
|
+
# rubocop:enable Security/Eval
|
164
|
+
end
|
165
|
+
end
|
data/lib/stackify_apm/spies.rb
CHANGED
@@ -13,14 +13,19 @@ module StackifyRubyAPM
|
|
13
13
|
# @api private
|
14
14
|
class Registration
|
15
15
|
extend Forwardable
|
16
|
-
|
17
|
-
def initialize(const_name, require_paths, spy)
|
16
|
+
# rubocop:disable Metrics/ParameterLists
|
17
|
+
def initialize(const_name, require_paths, spy, custom_instrumented = false, custom_method = '', tracked_func = false, tracked_function_name = '')
|
18
18
|
@const_name = const_name
|
19
19
|
@require_paths = Array(require_paths)
|
20
20
|
@spy = spy
|
21
|
+
@custom_instrumented = custom_instrumented
|
22
|
+
@custom_method = custom_method
|
23
|
+
@tracked_func = tracked_func
|
24
|
+
@tracked_function_name = tracked_function_name
|
21
25
|
end
|
26
|
+
# rubocop:enable Metrics/ParameterLists
|
22
27
|
|
23
|
-
attr_reader :const_name, :require_paths
|
28
|
+
attr_reader :const_name, :require_paths, :custom_instrumented, :custom_method, :tracked_func, :tracked_function_name
|
24
29
|
|
25
30
|
def_delegator :@spy, :install
|
26
31
|
end
|
@@ -71,7 +76,6 @@ module StackifyRubyAPM
|
|
71
76
|
if ENV['STACKIFY_RUBY_ENV'] == 'rspec'
|
72
77
|
file = 'spec/integration/stackify_spec.json'
|
73
78
|
end
|
74
|
-
|
75
79
|
return unless File.exist?(file)
|
76
80
|
|
77
81
|
File.open(file) do |f|
|
@@ -86,6 +90,35 @@ module StackifyRubyAPM
|
|
86
90
|
rescue NameError
|
87
91
|
return false
|
88
92
|
end
|
93
|
+
|
94
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
95
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
96
|
+
def self.ismethod_exists(class_name, current_method)
|
97
|
+
module_consget = Module.const_get(class_name)
|
98
|
+
current_method_without_apm = "_without_apm_#{current_method}"
|
99
|
+
self_current_method_without_apm = "_self_without_apm_#{current_method}"
|
100
|
+
|
101
|
+
with_flag = module_consget.instance_methods(false).include?(:"#{current_method_without_apm}")
|
102
|
+
self_with_flag = module_consget.instance_methods(false).include?(:"#{self_current_method_without_apm}")
|
103
|
+
|
104
|
+
current_method_exists = module_consget.instance_methods(false).include?(:"#{current_method}")
|
105
|
+
self_current_method_exists = module_consget.instance_methods(false).include?(:"self.#{current_method}")
|
106
|
+
|
107
|
+
exists = false
|
108
|
+
if (self_with_flag == false && with_flag == false) &&
|
109
|
+
(current_method_exists == true || self_current_method_exists == true)
|
110
|
+
exists = true
|
111
|
+
end
|
112
|
+
|
113
|
+
if (module_consget.methods.include?(:"#{current_method_without_apm}") == false &&
|
114
|
+
module_consget.methods.include?(:"#{self_current_method_without_apm}") == false) &&
|
115
|
+
(module_consget.methods.include?(:"#{current_method}") || module_consget.methods.include?(:"self.#{current_method}"))
|
116
|
+
exists = true
|
117
|
+
end
|
118
|
+
exists
|
119
|
+
end
|
120
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
121
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
89
122
|
end
|
90
123
|
end
|
91
124
|
|
@@ -3,89 +3,31 @@
|
|
3
3
|
# Monkey patch for the custom instrumentation any values from config/stackify.json will be loop and will
|
4
4
|
# register as a spy.
|
5
5
|
#
|
6
|
+
require 'stackify_apm/instrumenter_helper.rb'
|
6
7
|
require 'stackify_apm/config'
|
7
8
|
require 'json'
|
8
|
-
|
9
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
10
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
9
11
|
module StackifyRubyAPM
|
10
12
|
# @api private
|
11
13
|
module Spies
|
12
|
-
def self.
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
type = "#{current_class}##{current_method}"
|
20
|
-
ctx = if "#{tracked_func}" == 'true'
|
21
|
-
Span::Context.new(
|
22
|
-
CATEGORY: 'Ruby',
|
23
|
-
TRACKED_FUNC: "#{tracked_function_name}"
|
24
|
-
)
|
25
|
-
else
|
26
|
-
Span::Context.new(
|
27
|
-
CATEGORY: 'Ruby'
|
28
|
-
)
|
29
|
-
end
|
30
|
-
req = __without_apm_#{current_method}(*args, &block)
|
31
|
-
StackifyRubyAPM.span name, type, context: ctx do
|
32
|
-
req
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def get_class_name
|
37
|
-
return self.class.name
|
38
|
-
end
|
39
|
-
RUBY
|
40
|
-
end
|
41
|
-
|
42
|
-
def self.m_singleton(tracked_func, current_class, current_method, tracked_function_name)
|
43
|
-
Module.const_get(current_class.to_s).class_eval <<-RUBY
|
44
|
-
singleton_class.send(:alias_method, :"__self_without_apm_#{current_method}", :"#{current_method}")
|
45
|
-
|
46
|
-
def self.#{current_method}(*args, &block)
|
47
|
-
return __self_without_apm_#{current_method}(*args, &block) unless StackifyRubyAPM.current_transaction
|
14
|
+
def self.run_custom_instrumentation
|
15
|
+
config = Config.new
|
16
|
+
to_instrument = parse_json_config(config.json_config_file)
|
17
|
+
if config.logger.nil?
|
18
|
+
config.debug_logger
|
19
|
+
config.logger.send(:info, '[StackifyRubyAPM] Error: config/stackify.json does not exist which is required for custom instrumentation!') if to_instrument.nil?
|
20
|
+
end
|
48
21
|
|
49
|
-
|
50
|
-
type = "#{current_class}##{current_method}"
|
51
|
-
ctx = if "#{tracked_func}" == 'true'
|
52
|
-
Span::Context.new(
|
53
|
-
CATEGORY: 'Ruby',
|
54
|
-
TRACKED_FUNC: "#{tracked_function_name}"
|
55
|
-
)
|
56
|
-
else
|
57
|
-
Span::Context.new(
|
58
|
-
CATEGORY: 'Ruby'
|
59
|
-
)
|
60
|
-
end
|
61
|
-
req = __self_without_apm_#{current_method}(*args, &block)
|
62
|
-
StackifyRubyAPM.span name, type, context: ctx do
|
63
|
-
req
|
64
|
-
end
|
65
|
-
end
|
22
|
+
return unless !to_instrument.nil? && !to_instrument.empty? && defined?(to_instrument['instrumentation']) && (to_instrument['instrumentation'].count > 0)
|
66
23
|
|
67
|
-
def self.get_class_name
|
68
|
-
return self.class.name
|
69
|
-
end
|
70
|
-
RUBY
|
71
|
-
end
|
72
|
-
|
73
|
-
config = Config.new
|
74
|
-
to_instrument = parse_json_config(config.json_config_file)
|
75
|
-
if defined?(to_instrument['instrumentation']) && (to_instrument['instrumentation'].count > 0)
|
76
24
|
to_instrument['instrumentation'].each do |custom_spy|
|
77
25
|
current_class = custom_spy['class']
|
78
26
|
current_method = custom_spy['method']
|
79
27
|
tracked_func = custom_spy['trackedFunction']
|
80
|
-
tracked_func_name =
|
81
|
-
custom_spy['trackedFunctionName']
|
82
|
-
end
|
28
|
+
tracked_func_name = defined?(custom_spy['trackedFunctionName']) ? custom_spy['trackedFunctionName'] : ''
|
83
29
|
|
84
|
-
tracked_function_tpl =
|
85
|
-
'{{ClassName}}.{{MethodName}}'
|
86
|
-
else
|
87
|
-
tracked_func_name
|
88
|
-
end
|
30
|
+
tracked_function_tpl = tracked_func_name.nil? ? '{{ClassName}}.{{MethodName}}' : tracked_func_name
|
89
31
|
|
90
32
|
tracked_function_name = tracked_function_tpl.sub '{{ClassName}}', current_class
|
91
33
|
tracked_function_name = tracked_function_name.sub '{{MethodName}}', current_method
|
@@ -95,10 +37,17 @@ module StackifyRubyAPM
|
|
95
37
|
mod_constant = Module.const_get(current_class.to_s)
|
96
38
|
klass_method_flag = mod_constant.method_defined?(current_method.to_s)
|
97
39
|
singleton_method_flag = mod_constant.respond_to?(current_method.to_s)
|
40
|
+
|
41
|
+
class_location = mod_constant.instance_methods(false).map do |m|
|
42
|
+
mod_constant.instance_method(m).source_location.first
|
43
|
+
end.uniq
|
44
|
+
|
45
|
+
class_path = class_location.last
|
46
|
+
|
98
47
|
if klass_method_flag
|
99
|
-
StackifyRubyAPM::
|
48
|
+
StackifyRubyAPM::InstrumenterHelper.m_class(tracked_func, current_class, class_path, current_method, tracked_function_name)
|
100
49
|
elsif singleton_method_flag
|
101
|
-
StackifyRubyAPM::
|
50
|
+
StackifyRubyAPM::InstrumenterHelper.m_singleton(tracked_func, current_class, class_path, current_method, tracked_function_name)
|
102
51
|
end
|
103
52
|
end
|
104
53
|
# rubocop:enable Style/Next
|
@@ -106,3 +55,5 @@ module StackifyRubyAPM
|
|
106
55
|
end
|
107
56
|
end
|
108
57
|
end
|
58
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
59
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Monkey patch for the CurbSpy class for sending & receiving Curb responses.
|
4
|
+
#
|
5
|
+
require 'stackify_apm/config'
|
6
|
+
|
7
|
+
module StackifyRubyAPM
|
8
|
+
# @api private
|
9
|
+
module Spies
|
10
|
+
# @api private
|
11
|
+
class HTTPartySpy
|
12
|
+
def install
|
13
|
+
# puts HTTParty::ClassMethods.instance_methods(false).inspect
|
14
|
+
HTTParty::ClassMethods.module_eval do
|
15
|
+
alias_method 'perform_request_without_apm', 'perform_request'
|
16
|
+
|
17
|
+
# singleton_class.send(:alias_method, :perform_request_without_apm, :perform_request)
|
18
|
+
|
19
|
+
private :perform_request
|
20
|
+
|
21
|
+
def perform_request(http_method, path, options, &block)
|
22
|
+
req = nil
|
23
|
+
return perform_request_without_apm(http_method, path, options, &block) unless StackifyRubyAPM.current_transaction
|
24
|
+
# Data configuration
|
25
|
+
#
|
26
|
+
method = http_method.to_s.gsub('Net::HTTP::', '').upcase
|
27
|
+
uri = path.strip
|
28
|
+
name = "#{method} #{uri}"
|
29
|
+
type = "ext.HTTParty.#{method}"
|
30
|
+
# Submits HTTP request
|
31
|
+
#
|
32
|
+
# req = perform_request_without_apm(http_method, path, options, &block)
|
33
|
+
# Builds span context
|
34
|
+
#
|
35
|
+
# status_code = req.code
|
36
|
+
|
37
|
+
ctx = Span::Context.new(
|
38
|
+
CATEGORY: 'Web External',
|
39
|
+
SUBCATEGORY: 'Execute',
|
40
|
+
URL: uri,
|
41
|
+
STATUS: '',
|
42
|
+
METHOD: method
|
43
|
+
)
|
44
|
+
# Creates new span from HTTP result
|
45
|
+
#
|
46
|
+
# class_info = { 'classname' => 'httparty', 'hostname' => URI.parse(uri).host }
|
47
|
+
StackifyRubyAPM.span name, type, context: ctx do
|
48
|
+
req = perform_request_without_apm(http_method, path, options, &block)
|
49
|
+
status_code = req.code
|
50
|
+
ctx.update_status(status_code)
|
51
|
+
req
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
# Registers CurbSpy spy, go to: /stackify/spies.rb
|
58
|
+
#
|
59
|
+
register 'HTTParty::ClassMethods', 'httparty', HTTPartySpy.new
|
60
|
+
end
|
61
|
+
end
|
@@ -11,9 +11,8 @@ module StackifyRubyAPM
|
|
11
11
|
|
12
12
|
def request(req, body = nil, &block)
|
13
13
|
result = nil
|
14
|
-
unless StackifyRubyAPM.current_transaction
|
15
|
-
|
16
|
-
end
|
14
|
+
return request_without_apm(req, body, &block) unless StackifyRubyAPM.current_transaction
|
15
|
+
return request_without_apm(req, body, &block) if started? && req['span']
|
17
16
|
|
18
17
|
# Data configuration
|
19
18
|
#
|
@@ -25,23 +24,25 @@ module StackifyRubyAPM
|
|
25
24
|
name = "#{method} #{host}"
|
26
25
|
type = "ext.net_http.#{method}"
|
27
26
|
|
28
|
-
# Submits HTTP request
|
29
|
-
#
|
30
|
-
result = request_without_apm(req, body, &block)
|
31
|
-
|
32
27
|
# Builds span context
|
33
28
|
#
|
34
29
|
ctx = Span::Context.new(
|
35
30
|
CATEGORY: 'Web External',
|
36
31
|
SUBCATEGORY: 'Execute',
|
37
32
|
URL: req.uri.nil? ? host : req.uri,
|
38
|
-
STATUS:
|
33
|
+
STATUS: '',
|
39
34
|
METHOD: method
|
40
35
|
)
|
41
36
|
|
42
37
|
# Creates new span from HTTP result
|
43
38
|
#
|
44
39
|
StackifyRubyAPM.span name, type, context: ctx do
|
40
|
+
# Submits HTTP request
|
41
|
+
#
|
42
|
+
req['span'] = true
|
43
|
+
result = request_without_apm(req, body, &block)
|
44
|
+
status_code = result.code.to_i
|
45
|
+
ctx.update_status(status_code)
|
45
46
|
return result
|
46
47
|
end
|
47
48
|
end
|
data/lib/stackify_apm/version.rb
CHANGED
data/lib/stackify_ruby_apm.rb
CHANGED
@@ -16,9 +16,9 @@
|
|
16
16
|
require 'stackify_apm/log'
|
17
17
|
require 'stackify_apm/version'
|
18
18
|
require 'stackify_apm/util/dig'
|
19
|
-
require 'stackify_apm/agent'
|
20
19
|
# Checks ruby version
|
21
20
|
require RUBY_VERSION.to_f >= 2.4 ? 'stackify_apm/logger/logger_high_version' : 'stackify_apm/logger/logger_lower_version'
|
21
|
+
require 'stackify_apm/agent'
|
22
22
|
require 'stackify_apm/helper/database_helper'
|
23
23
|
require 'stackify_apm/util'
|
24
24
|
require 'stackify_apm/config'
|
@@ -27,6 +27,7 @@ require 'stackify_apm/instrumenter'
|
|
27
27
|
require 'stackify_apm/internal_error'
|
28
28
|
# require 'stackify_apm/util'
|
29
29
|
require 'stackify_apm/middleware'
|
30
|
+
require 'stackify_apm/instrumenter_helper'
|
30
31
|
|
31
32
|
# Checks if the framework using is Rails
|
32
33
|
require 'stackify_apm/railtie' if defined?(::Rails::Railtie)
|
@@ -65,6 +66,13 @@ module StackifyRubyAPM
|
|
65
66
|
data-a=\"#{config.application_name}\" data-e=\"#{config.environment_name}\" data-enableInternalLogging=\"#{config.debug_logging}\" type=\"text/javascript\" async></script>"
|
66
67
|
end
|
67
68
|
|
69
|
+
# Run the custom instrument
|
70
|
+
def self.run_custom_instrument
|
71
|
+
return unless running?
|
72
|
+
StackifyRubyAPM::InstrumenterHelper.custom_instrumented_reset
|
73
|
+
StackifyRubyAPM::Spies.run_custom_instrumentation
|
74
|
+
end
|
75
|
+
|
68
76
|
# Stops the StackifyRubyAPM Agent
|
69
77
|
def self.stop
|
70
78
|
Agent.stop
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stackify-ruby-apm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stackify
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-07-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -127,6 +127,7 @@ files:
|
|
127
127
|
- lib/stackify_apm/error_builder.rb
|
128
128
|
- lib/stackify_apm/helper/database_helper.rb
|
129
129
|
- lib/stackify_apm/instrumenter.rb
|
130
|
+
- lib/stackify_apm/instrumenter_helper.rb
|
130
131
|
- lib/stackify_apm/internal_error.rb
|
131
132
|
- lib/stackify_apm/log.rb
|
132
133
|
- lib/stackify_apm/logger/log_device.rb
|
@@ -153,6 +154,7 @@ files:
|
|
153
154
|
- lib/stackify_apm/spies/curb/easy.rb
|
154
155
|
- lib/stackify_apm/spies/curb/multi.rb
|
155
156
|
- lib/stackify_apm/spies/custom_instrumenter.rb
|
157
|
+
- lib/stackify_apm/spies/httparty.rb
|
156
158
|
- lib/stackify_apm/spies/httpclient.rb
|
157
159
|
- lib/stackify_apm/spies/httprb.rb
|
158
160
|
- lib/stackify_apm/spies/mongo.rb
|