stackify-ruby-apm 1.4.0 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|