stackify-ruby-apm 1.1.1 → 1.2.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 9cdc4202c1c0062af195e5385b43fee272208e7e
4
- data.tar.gz: 3983a54aee8710f485551e0f5c24fce5e940bbd9
2
+ SHA256:
3
+ metadata.gz: c797df00561661da936aeef53e4064ac64a7742156b7c83c6ba770880202f53f
4
+ data.tar.gz: 32f9a06b9f3b0ab131c552d7cbfa3e22dd074b5689e67ed5d42cb3edd99c43a0
5
5
  SHA512:
6
- metadata.gz: 7ee08ddb0772686f93ba2546807762f2c780f7c15c2c039a41b09a3f3589f5bf3d180d3f8989de4922d16e8b802a0a7739025000062b925908eae30cb9ae1e01
7
- data.tar.gz: 9ab46ee1da02e93377974ae4ab020a66b8a7b89069fee2f32d1e673dc4372397f5f784f86195c41220c7e06dc56004927739546f17eab1a6d912e7a7581bc659
6
+ metadata.gz: 8ca79814064746539fb96db7d3e5ff5241c8213973a9fba444fc69507756e60d138e4335202bc73d0ca5a6e2df1984afeeb6836b98681f64bf06f7337523b28f
7
+ data.tar.gz: 824820eb08bd65189a0292d3c0f6d8138923aff31552828bc788a072ad781d7bb660c51fe7439eb00891a8a9597713ed92178f7133fe9a13fb7d86a0becf6952
@@ -0,0 +1,8 @@
1
+ test
2
+ spec
3
+ features
4
+ docs
5
+ docker
6
+ docker-compose.xml
7
+ deploy-*.sh
8
+ run-*.sh
data/README.md CHANGED
@@ -3,6 +3,8 @@
3
3
 
4
4
  ## Installation Guide
5
5
 
6
+ ### Rails Guide
7
+
6
8
  1. Install **Stackify Linux Agent**.
7
9
 
8
10
  2. Check that your setup meets our system requirements.
@@ -21,5 +23,33 @@
21
23
  application_name: 'Ruby Application'
22
24
  environment_name: 'Production'
23
25
  ```
24
- 5. Build/Deploy your application:
26
+ 5. Build/Deploy your application
27
+
28
+ ### Non-Rails Guide
29
+
30
+ 1. Install **Stackify Linux Agent**.
31
+
32
+ 2. Check that your setup meets our system requirements.
33
+ * Ruby version 2.0+
34
+ * Frameworks
35
+ * Rack 1+
36
+ * Sinatra 1.4+
37
+ * Operating System
38
+ * Linux
39
+
40
+ 3. Add `gem 'stackify-ruby-apm'` to your `Gemfile`.
41
+
42
+ 4. In the root folder of your Rails app create a file `config/stackify_apm.yml` and then add this configuration
43
+ ```yaml
44
+ application_name: 'Ruby Application'
45
+ environment_name: 'Production'
46
+ ```
47
+
48
+ 5. In the `config.ru` add the following lines:
49
+
50
+ ``` use StackifyRubyAPM::Middleware
51
+ StackifyRubyAPM.start
52
+ at_exit { StackifyRubyAPM.stop }
53
+ ```
25
54
 
55
+ 6. Build/Deploy your application
@@ -98,6 +98,7 @@ module StackifyRubyAPM
98
98
  return false unless @config.instrument
99
99
  config.enabled_spies.each do |lib|
100
100
  spies_name = spies_name + ', ' + lib.inspect.to_s
101
+
101
102
  require "stackify_apm/spies/#{lib}"
102
103
  end
103
104
 
@@ -13,8 +13,14 @@ module StackifyRubyAPM
13
13
  include Log
14
14
  DEFAULTS = {
15
15
  config_file: 'config/stackify_apm.yml',
16
+ json_config_file: 'config/stackify.json',
17
+ rum_script_src: 'https://stckjs.azureedge.net/stckjs.js',
18
+ application_name: 'Ruby Application',
16
19
  environment_name: ENV['RAILS_ENV'] || ENV['RACK_ENV'],
20
+ already_instrumented_flag: false,
21
+ rum_auto_injection: false,
17
22
  instrument: true,
23
+ debug_logging: false,
18
24
  log_path: '/usr/local/stackify/stackify-ruby-apm/log/stackify-ruby-apm.log',
19
25
  log_level: Logger::INFO,
20
26
  log_trace_path: '/usr/local/stackify/stackify-ruby-apm/log/',
@@ -50,6 +56,10 @@ module StackifyRubyAPM
50
56
 
51
57
  ENV_TO_KEY = {
52
58
  'STACKIFY_APM_ENVIRONMENT_NAME' => 'environment_name',
59
+ 'STACKIFY_APM_RUM_SCRIPT_SRC' => 'rum_script_src',
60
+ 'STACKIFY_APM_RUM_AUTO_INJECTION' => 'rum_auto_injection',
61
+ 'STACKIFY_ALREADY_INSTRUMENTED_FLAG' => 'already_instrumented_flag',
62
+ 'STACKIFY_APM_DEBUG_LOGGING' => 'debug_logging',
53
63
  'STACKIFY_APM_INSTRUMENT' => [:bool, 'instrument'],
54
64
  'STACKIFY_APM_HOSTNAME' => 'hostname',
55
65
  'STACKIFY_APM_LOG_PATH' => 'log_path',
@@ -79,7 +89,12 @@ module StackifyRubyAPM
79
89
  end
80
90
 
81
91
  attr_accessor :config_file
92
+ attr_accessor :json_config_file
82
93
  attr_accessor :environment_name
94
+ attr_accessor :rum_script_src
95
+ attr_accessor :rum_auto_injection
96
+ attr_accessor :already_instrumented_flag
97
+ attr_accessor :rum_script_injected
83
98
  attr_accessor :instrument
84
99
  attr_accessor :enabled_environments
85
100
  attr_accessor :stackify_properties_file
@@ -90,6 +105,7 @@ module StackifyRubyAPM
90
105
  attr_accessor :log_path
91
106
  attr_accessor :log_level
92
107
  attr_accessor :logger
108
+ attr_accessor :debug_logging
93
109
  attr_accessor :logger_byte_size
94
110
  attr_accessor :filenum_rotate
95
111
  attr_accessor :debugger_byte_size
@@ -123,6 +139,7 @@ module StackifyRubyAPM
123
139
  attr_reader :client_id
124
140
  attr_reader :device_id
125
141
  attr_reader :apm_disabled_in_rake
142
+ attr_reader :client_run_domain
126
143
 
127
144
  def app=(app)
128
145
  case app_type?(app)
@@ -150,6 +167,7 @@ module StackifyRubyAPM
150
167
  action_dispatch
151
168
  mongo
152
169
  net_http
170
+ custom_instrumenter
153
171
  httpclient
154
172
  redis
155
173
  sequel
@@ -250,9 +268,11 @@ module StackifyRubyAPM
250
268
  str.gsub('::', '_')
251
269
  end
252
270
 
271
+ # rubocop:disable Metrics/CyclomaticComplexity
253
272
  def load_stackify_props
254
273
  @client_id = nil
255
274
  @device_id = nil
275
+ @client_run_domain = nil
256
276
  begin
257
277
  info 'Reading the stackify.properties file'
258
278
  IO.foreach(@stackify_properties_file) do |line|
@@ -261,6 +281,8 @@ module StackifyRubyAPM
261
281
  @client_id = line.split('=')[1].strip
262
282
  when /deviceid=\d+/
263
283
  @device_id = line.split('=')[1].strip
284
+ when /clientrumdomain=([\w\s\d\"\']+)+/i
285
+ @client_run_domain = line.split('=')[1].strip
264
286
  end
265
287
  end
266
288
  info "stackify.properties: clientId=#{@client_id}, deviceId=#{@device_id}"
@@ -271,5 +293,6 @@ module StackifyRubyAPM
271
293
  info 'No clientId found from stackify.properties file.' if @client_id.nil?
272
294
  info 'No deviceId found from stackify.properties file.' if @device_id.nil?
273
295
  end
296
+ # rubocop:enable Metrics/CyclomaticComplexity
274
297
  end
275
298
  end
@@ -18,23 +18,55 @@
18
18
  # -> transaction will be stored in queue by Agent
19
19
  # -> worker will constantly execute transaction sending to APM
20
20
  #
21
+ require 'stackify_apm/response_manipulator'
21
22
 
22
23
  module StackifyRubyAPM
23
24
  # @api private
24
25
  class Middleware
26
+ attr_accessor :rack_body, :rack_headers, :rack_status, :configuration
27
+
28
+ CONTENT_TYPE_REGEX = %r{text\/html|application\/xhtml\+xml/}
29
+ CONTENT_DISPOSITION = 'Content-Disposition'.freeze
30
+ ATTACHMENT = 'attachment'.freeze
31
+
25
32
  def initialize(app)
26
33
  @app = app
27
34
  end
28
35
 
29
36
  # This is where the requests are received, built into a transaction, and then submitted
30
37
  #
38
+ # rubocop:disable Metrics/CyclomaticComplexity
39
+ # rubocop:disable Metrics/PerceivedComplexity
31
40
  def call(env)
32
41
  begin
33
- # if running? && !path_ignored?(env)
34
42
  transaction = build_transaction(env) if running?
35
-
36
43
  resp = @app.call env
37
44
 
45
+ @rack_status = resp[0].to_i
46
+ @rack_headers = resp[1]
47
+ @rack_body = resp[2]
48
+ @configuration = config
49
+ response_manupulate = StackifyRubyAPM::ResponseManipulator.new(env, resp, @configuration)
50
+
51
+ if okay_to_modify?
52
+ @configuration.already_instrumented_flag = true
53
+ if StackifyRubyAPM.rum_script_inject
54
+ resp
55
+ else
56
+ if @configuration.rum_auto_injection
57
+ response_string = response_manupulate.call_manipulate
58
+ end
59
+ if response_string
60
+ response = Rack::Response.new(response_string, @rack_status, @rack_headers)
61
+ resp = response.finish
62
+ else
63
+ resp
64
+ end
65
+ end
66
+ else
67
+ resp
68
+ end
69
+
38
70
  submit_transaction(transaction, *resp) if transaction
39
71
  rescue InternalError
40
72
  raise # Don't report StackifyRubyAPM errors
@@ -47,6 +79,8 @@ module StackifyRubyAPM
47
79
 
48
80
  resp
49
81
  end
82
+ # rubocop:enable Metrics/PerceivedComplexity
83
+ # rubocop:enable Metrics/CyclomaticComplexity
50
84
 
51
85
  def submit_transaction(transaction, status, headers, _body)
52
86
  result = status.to_i
@@ -66,5 +100,31 @@ module StackifyRubyAPM
66
100
  def config
67
101
  StackifyRubyAPM.agent.config
68
102
  end
103
+
104
+ def okay_to_modify?
105
+ return false if xhr?
106
+ return false unless modifiable_content_type?
107
+ return false if @rack_status == 404 || @rack_status == 501
108
+ return false if attachment?
109
+ true
110
+ end
111
+
112
+ def modifiable_content_type?
113
+ @rack_headers['Content-Type'] =~ self.class::CONTENT_TYPE_REGEX
114
+ end
115
+
116
+ def attachment?
117
+ @rack_headers[CONTENT_DISPOSITION] && @rack_headers[CONTENT_DISPOSITION].include?(ATTACHMENT)
118
+ end
119
+
120
+ def streaming?(env)
121
+ return false unless defined?(ActionController::Live)
122
+
123
+ env['action_controller.instance'].class.included_modules.include?(ActionController::Live)
124
+ end
125
+
126
+ def xhr?
127
+ @rack_headers['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'
128
+ end
69
129
  end
70
130
  end
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # This class will manupulate the html page d: e.g., call(env)
5
+ #
6
+ #
7
+ module StackifyRubyAPM
8
+ # an abstraction for manipulating the HTML we capture in the middleware
9
+ class ResponseManipulator
10
+ attr_reader :rack_response, :jsfile_to_inject
11
+ attr_reader :rack_status, :rack_headers, :rack_body, :Rack_flagger
12
+ attr_reader :env
13
+
14
+ # examine in order to look for a RUM insertion point.
15
+ SCAN_LIMIT = 50_000
16
+ HEAD_START = '<head'.freeze
17
+ HEAD_END = '</head'.freeze
18
+ RUM_SCRIPT_VARIABLE = '[RUM_SCRIPT_VARIABLE'.freeze
19
+ BRKT = ']'.freeze
20
+ GT = '>'.freeze
21
+ CHARSET_RE = /<\s*meta[^>]+charset\s*=[^>]*>/
22
+ X_UA_COMPATIBLE_RE = /<\s*meta[^>]+http-equiv\s*=\s*['"]x-ua-compatible['"][^>]*>/
23
+
24
+ def initialize(env, rack_response, config)
25
+ @env = env
26
+ @rack_response = rack_response
27
+
28
+ @rack_status = rack_response[0]
29
+ @rack_headers = rack_response[1]
30
+ @rack_body = rack_response[2]
31
+ @rack_flagger = nil
32
+ @config = config
33
+ end
34
+
35
+ def call_manipulate
36
+ if check_rumscript_variable
37
+ adjust_pagehtml_response(true)
38
+ else
39
+ adjust_pagehtml_response
40
+ end
41
+ end
42
+
43
+ def check_rumscript_variable
44
+ response = @rack_body
45
+ source = gather_source(response)
46
+ close_old_response(response)
47
+ return false unless source
48
+
49
+ return true if source.include?(RUM_SCRIPT_VARIABLE)
50
+ false
51
+ end
52
+
53
+ def rebuild_rack_response
54
+ [rack_status, rack_headers, rack_body]
55
+ end
56
+
57
+ # rubocop:disable Metrics/CyclomaticComplexity
58
+ # rubocop:disable Metrics/PerceivedComplexity
59
+ def adjust_pagehtml_response(rum_variable_script = false)
60
+ response = @rack_body
61
+ source = gather_source(response)
62
+ close_old_response(response)
63
+ return nil unless source
64
+
65
+ client_id = @config.client_id
66
+ device_id = @config.device_id
67
+ client_rundomain = @config.client_run_domain
68
+ transaction_id = defined?(StackifyRubyAPM.current_transaction.id) ? StackifyRubyAPM.current_transaction.id : nil
69
+ data_request_id = 'V2|' + transaction_id + '|C' + client_id + '|' + device_id
70
+ inject_flag = false
71
+
72
+ if client_rundomain != '' && StackifyRubyAPM.check_isdomain(client_rundomain)
73
+ inject_flag = true
74
+ else
75
+ warn 'ClientRumDomain might be empty or Invalid URL stackify.properties.'
76
+ end
77
+
78
+ jsfile_to_inject = '<script src="' + @config.rum_script_src + '" data-host="' + client_rundomain + '"
79
+ data-requestId="' + data_request_id + '"
80
+ data-a="' + @config.application_name + '"
81
+ data-e="' + @config.environment_name + '"
82
+ data-enableInternalLogging="' + @config.debug_logging.to_s + '" type="text/javascript" async></script>'
83
+
84
+ # Only scan the first 50k (roughly) then give up.
85
+ beginning_of_source = source[0..SCAN_LIMIT]
86
+
87
+ meta_tag_positions = [
88
+ find_x_ua_compatible_position(beginning_of_source),
89
+ find_charset_position(beginning_of_source)
90
+ ].compact
91
+
92
+ insertion_index = if !meta_tag_positions.empty?
93
+ meta_tag_positions.max
94
+ else
95
+ find_end_of_head_open(beginning_of_source)
96
+ end
97
+
98
+ if insertion_index && inject_flag
99
+ source = source[0...insertion_index] <<
100
+ jsfile_to_inject <<
101
+ source[insertion_index..-1]
102
+ source = source.gsub('[RUM_SCRIPT_VARIABLE]', '') if rum_variable_script
103
+ end
104
+ source
105
+ end
106
+ # rubocop:enable Metrics/CyclomaticComplexity
107
+ # rubocop:enable Metrics/PerceivedComplexity
108
+
109
+ def find_end_of_head_open(beginning_of_source)
110
+ head_open = beginning_of_source.index(HEAD_END)
111
+ beginning_of_source.index(GT, head_open) - 6 if head_open
112
+ end
113
+
114
+ def find_rum_script_variable_index(beginning_of_source)
115
+ head_open = beginning_of_source.index(RUM_SCRIPT_VARIABLE)
116
+ beginning_of_source.index(BRKT, head_open) - 20 if head_open
117
+ end
118
+
119
+ def find_x_ua_compatible_position(beginning_of_source)
120
+ match = X_UA_COMPATIBLE_RE.match(beginning_of_source)
121
+ match.end(0) if match
122
+ end
123
+
124
+ def find_charset_position(beginning_of_source)
125
+ match = CHARSET_RE.match(beginning_of_source)
126
+ match.end(0) if match
127
+ end
128
+
129
+ def gather_source(response)
130
+ source = nil
131
+ response.each { |fragment| source ? (source << fragment.to_s) : (source = fragment.to_s) }
132
+ source
133
+ end
134
+
135
+ def close_old_response(response)
136
+ response.close if response.respond_to?(:close)
137
+ end
138
+ end
139
+ end
@@ -26,7 +26,8 @@ module StackifyRubyAPM
26
26
  :CACHEKEY,
27
27
  :CACHENAME,
28
28
  :THREAD_ID,
29
- :ID
29
+ :ID,
30
+ :TRACKED_FUNC
30
31
  end
31
32
  end
32
33
  end
@@ -65,6 +65,26 @@ module StackifyRubyAPM
65
65
  def self.safe_defined?(const_name)
66
66
  Util::Inflector.safe_constantize(const_name)
67
67
  end
68
+
69
+ def self.parse_json_config(file)
70
+ jsondata = {}
71
+ if ENV['STACKIFY_RUBY_ENV'] == 'rspec'
72
+ file = 'spec/integration/stackify.json'
73
+ end
74
+ return unless File.exist?(file)
75
+
76
+ File.open(file) do |f|
77
+ jsondata = JSON.parse(f.read)
78
+ end
79
+ jsondata
80
+ end
81
+
82
+ def self.class_exists?(class_name)
83
+ klass = Module.const_get(class_name)
84
+ return klass.is_a?(Class)
85
+ rescue NameError
86
+ return false
87
+ end
68
88
  end
69
89
  end
70
90
 
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Monkey patch for the custom instrumentation any values from config/stackify.json will be loop and will
4
+ # register as a spy.
5
+ #
6
+ require 'stackify_apm/config'
7
+ require 'json'
8
+
9
+ module StackifyRubyAPM
10
+ # @api private
11
+ module Spies
12
+ def self.m_class(tracked_func, current_class, current_method, tracked_function_name)
13
+ Module.const_get(current_class.to_s).class_eval <<-RUBY
14
+ alias :"__without_apm_#{current_method}" :"#{current_method}"
15
+
16
+ def #{current_method}(*args, &block)
17
+ return __without_apm_#{current_method}(*args, &block) unless StackifyRubyAPM.current_transaction
18
+ name = "Custom Instrument"
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
48
+
49
+ name = "Custom Instrument"
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
66
+
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
+ to_instrument['instrumentation'].each do |custom_spy|
77
+ current_class = custom_spy['class']
78
+ current_method = custom_spy['method']
79
+ tracked_func = custom_spy['trackedFunction']
80
+ tracked_func_name = if defined?(custom_spy['trackedFunctionName'])
81
+ custom_spy['trackedFunctionName']
82
+ end
83
+
84
+ tracked_function_tpl = if tracked_func_name.nil?
85
+ '{{ClassName}}.{{MethodName}}'
86
+ else
87
+ tracked_func_name
88
+ end
89
+
90
+ tracked_function_name = tracked_function_tpl.gsub '{{ClassName}}', current_class
91
+ tracked_function_name = tracked_function_name.gsub '{{MethodName}}', current_method
92
+
93
+ # rubocop:disable Style/Next
94
+ if class_exists?(current_class)
95
+ mod_constant = Module.const_get(current_class.to_s)
96
+ klass_method_flag = mod_constant.method_defined?(current_method.to_s)
97
+ singleton_method_flag = mod_constant.respond_to?(current_method.to_s)
98
+ if klass_method_flag
99
+ StackifyRubyAPM::Spies.m_class(tracked_func, current_class, current_method, tracked_function_name)
100
+ elsif singleton_method_flag
101
+ StackifyRubyAPM::Spies.m_singleton(tracked_func, current_class, current_method, tracked_function_name)
102
+ end
103
+ end
104
+ # rubocop:enable Style/Next
105
+ end
106
+ end
107
+ end
108
+ end
@@ -2,5 +2,5 @@
2
2
 
3
3
  # Sets the version of the APM
4
4
  module StackifyRubyAPM
5
- VERSION = '1.1.1'.freeze
5
+ VERSION = '1.2.4'.freeze
6
6
  end
@@ -25,7 +25,6 @@ require 'stackify_apm/context'
25
25
  require 'stackify_apm/instrumenter'
26
26
  require 'stackify_apm/internal_error'
27
27
  require 'stackify_apm/util'
28
-
29
28
  require 'stackify_apm/middleware'
30
29
 
31
30
  # Checks if the framework using is Rails
@@ -41,6 +40,27 @@ module StackifyRubyAPM
41
40
  Agent.start config
42
41
  end
43
42
 
43
+ def self.inject_rum_script
44
+ config = StackifyRubyAPM::Config.new
45
+ client_id = config.client_id
46
+ device_id = config.device_id
47
+ client_rundomain = config.client_run_domain
48
+ transaction_id = defined?(StackifyRubyAPM.current_transaction.id) ? StackifyRubyAPM.current_transaction.id : nil
49
+ data_request_id = 'V2|' + transaction_id + '|C' + client_id + '|' + device_id
50
+ inject_flag = false
51
+
52
+ if client_rundomain != '' && check_isdomain(client_rundomain)
53
+ inject_flag = true
54
+ else
55
+ warn 'ClientRumDomain might be empty or Invalid URL stackify.properties.'
56
+ end
57
+
58
+ return unless inject_flag
59
+ @rum_script_injected = true
60
+ "<script src=\"#{config.rum_script_src}\" data-host=\"#{client_rundomain}\" data-requestId=\"#{data_request_id}\"
61
+ data-a=\"#{config.application_name}\" data-e=\"#{config.environment_name}\" data-enableInternalLogging=\"#{config.debug_logging}\" type=\"text/javascript\" async></script>"
62
+ end
63
+
44
64
  # Stops the StackifyRubyAPM Agent
45
65
  def self.stop
46
66
  Agent.stop
@@ -126,4 +146,19 @@ module StackifyRubyAPM
126
146
  def self.report_message(message, **attrs)
127
147
  agent && agent.report_message(message, backtrace: caller, **attrs)
128
148
  end
149
+
150
+ # Check if the URL is a domain
151
+ #
152
+ # @param message [String] The message
153
+ # @return TRUE/FALASE
154
+ def self.check_isdomain(url)
155
+ url =~ %r{^(http|https):\/\/|[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,6}(:[0-9]{1,5})?(\/.*)?$}
156
+ end
157
+
158
+ # Check if the RUM Script is Injected
159
+ #
160
+ # @return TRUE/FALASE
161
+ def self.rum_script_inject
162
+ @rum_script_injected
163
+ end
129
164
  end
@@ -13,12 +13,10 @@ Gem::Specification.new do |spec|
13
13
  spec.homepage = 'http://www.stackify.com'
14
14
  spec.license = 'Stackify'
15
15
 
16
- # Specify which files should be added to the gem when it is released.
17
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
16
+ git_tracked_files = `git ls-files -z`.split("\x0")
17
+ gem_ignored_files = `git ls-files -i -X .gemignore -z`.split("\x0")
18
+ spec.files = git_tracked_files - gem_ignored_files
18
19
 
19
- spec.files = Dir.chdir(File.expand_path(__dir__)) do
20
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|docs)/}) }
21
- end
22
20
  spec.bindir = 'exe'
23
21
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
22
  spec.require_paths = ['lib']
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.1.1
4
+ version: 1.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stackify
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-03-08 00:00:00.000000000 Z
11
+ date: 2019-03-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -101,6 +101,7 @@ executables: []
101
101
  extensions: []
102
102
  extra_rdoc_files: []
103
103
  files:
104
+ - ".gemignore"
104
105
  - ".gitignore"
105
106
  - ".rspec"
106
107
  - ".rubocop.yml"
@@ -111,9 +112,6 @@ files:
111
112
  - README.md
112
113
  - Rakefile
113
114
  - docker-compose.yml
114
- - docker/stackify-ruby
115
- - docker/stackify-ruby-rvm
116
- - docker/stackify-ruby-test
117
115
  - lib/stackify-ruby-apm.rb
118
116
  - lib/stackify_apm/agent.rb
119
117
  - lib/stackify_apm/config.rb
@@ -142,6 +140,7 @@ files:
142
140
  - lib/stackify_apm/normalizers/action_view.rb
143
141
  - lib/stackify_apm/normalizers/active_record.rb
144
142
  - lib/stackify_apm/railtie.rb
143
+ - lib/stackify_apm/response_manipulator.rb
145
144
  - lib/stackify_apm/root_info.rb
146
145
  - lib/stackify_apm/serializers.rb
147
146
  - lib/stackify_apm/serializers/errors.rb
@@ -153,6 +152,7 @@ files:
153
152
  - lib/stackify_apm/spies/curb.rb
154
153
  - lib/stackify_apm/spies/curb/easy.rb
155
154
  - lib/stackify_apm/spies/curb/multi.rb
155
+ - lib/stackify_apm/spies/custom_instrumenter.rb
156
156
  - lib/stackify_apm/spies/httpclient.rb
157
157
  - lib/stackify_apm/spies/httprb.rb
158
158
  - lib/stackify_apm/spies/mongo.rb
@@ -180,8 +180,6 @@ files:
180
180
  - lib/stackify_apm/version.rb
181
181
  - lib/stackify_apm/worker.rb
182
182
  - lib/stackify_ruby_apm.rb
183
- - run-test-docker.sh
184
- - run-test.sh
185
183
  - stackify-ruby-apm.gemspec
186
184
  homepage: http://www.stackify.com
187
185
  licenses:
@@ -202,8 +200,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
202
200
  - !ruby/object:Gem::Version
203
201
  version: '0'
204
202
  requirements: []
205
- rubyforge_project:
206
- rubygems_version: 2.5.2.3
203
+ rubygems_version: 3.0.1
207
204
  signing_key:
208
205
  specification_version: 4
209
206
  summary: Stackify APM for Ruby
@@ -1,8 +0,0 @@
1
- FROM stackify-ruby-rvm:latest
2
-
3
- ARG version
4
-
5
- RUN rvm install $version && rvm --version
6
-
7
-
8
-
@@ -1,10 +0,0 @@
1
- FROM ubuntu:18.04
2
-
3
- RUN \
4
- export DEBIAN_FRONTEND=noninteractiv && \
5
- apt-get update && \
6
- apt-get install -y curl git libcurl4-gnutls-dev libmysqlclient-dev libmysqld-dev libpq-dev tzdata && \
7
- curl -L https://get.rvm.io | bash -s stable
8
-
9
- ENV PATH /usr/local/rvm/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
10
-
@@ -1,28 +0,0 @@
1
- ARG from_version
2
-
3
- FROM stackify-ruby-${from_version}:latest
4
-
5
- ARG version
6
-
7
- RUN mkdir -p /usr/local/stackify/stackify-ruby-apm/log
8
- RUN mkdir /build
9
- COPY . /build/
10
-
11
- RUN /bin/bash --login -c "\
12
- echo $version && \
13
- rvm use ruby-$version && \
14
- ruby -v && \
15
- gem install bundler -v '~> 1.16' && \
16
- gem install tzinfo-data && \
17
- cd build && \
18
- ls -l && \
19
- bundle install \
20
- "
21
- CMD /bin/bash --login -c "\
22
- echo $version && \
23
- echo ${version} && \
24
- rvm use ruby-$version && \
25
- ruby -v && \
26
- cd build && \
27
- bundle exec rspec spec/ --format documentation --fail-fast \
28
- "
@@ -1,50 +0,0 @@
1
- #!/bin/bash
2
-
3
- function startContainers() {
4
- echo "Starting up containers..."
5
- docker-compose up -d -V --remove-orphans --force-recreate
6
- }
7
-
8
- function stopContainers() {
9
- echo "Stopping Containers..."
10
- docker-compose down --remove-orphans
11
-
12
- # delete volumes
13
- echo "Delete Volumes..."
14
- docker volume rm stackify-ruby-apm_postgresdata &> /dev/null
15
- docker volume rm stackify-ruby-apm_mysqldata &> /dev/null
16
- docker volume rm stackify-ruby-apm_mongodata &> /dev/null
17
- docker volume rm stackify-ruby-apm_mongodata_config &> /dev/null
18
- echo "Deleted Volumes"
19
- }
20
-
21
- if [[ "$(docker images -q stackify-ruby-rvm:latest 2> /dev/null)" == "" ]]; then
22
- docker build --file docker/stackify-ruby-rvm . -t stackify-ruby-rvm:latest
23
- fi
24
-
25
- RUBY_VERSIONS=('2.0.0-p648' '2.1.10' '2.2.10' '2.3.7' '2.4.0' '2.5.1' '2.6.0-preview3')
26
-
27
- for ver in "${RUBY_VERSIONS[@]}"
28
- do
29
-
30
- echo "Testing Ruby Version ${RUBY_VERSIONS}"
31
-
32
- if [[ "$(docker images -q stackify-ruby-$ver:latest 2> /dev/null)" == "" ]]; then
33
- docker build --build-arg version=${ver} --file docker/stackify-ruby . -t stackify-ruby-$ver:latest
34
- fi
35
-
36
- docker build --build-arg from_version=${ver} --build-arg version=${ver} --file docker/stackify-ruby-test . -t stackify-ruby-$ver-test:latest
37
-
38
- startContainers
39
- docker run -e version=${ver} --network="host" --name "stackify-ruby-${ver}-test" stackify-ruby-$ver-test:latest
40
- stopContainers
41
-
42
- docker rm "stackify-ruby-${ver}-test"
43
-
44
- done
45
-
46
-
47
-
48
-
49
-
50
-
@@ -1,73 +0,0 @@
1
- #!/bin/bash
2
-
3
- function startContainers() {
4
- echo "Starting up containers..."
5
- docker-compose up -d -V --remove-orphans --force-recreate
6
- }
7
-
8
- function waitForContainers() {
9
- echo 'Waiting for container startup 10s...'
10
- sleep 5
11
- echo 'Waiting for container startup 5s...'
12
- sleep 5
13
- }
14
-
15
- function stopContainers() {
16
- echo "Stopping Containers..."
17
- docker-compose down --remove-orphans
18
-
19
- # delete volumes
20
- echo "Delete Volumes..."
21
- docker volume rm stackify-ruby-apm_postgresdata &> /dev/null
22
- docker volume rm stackify-ruby-apm_mysqldata &> /dev/null
23
- docker volume rm stackify-ruby-apm_mongodata &> /dev/null
24
- docker volume rm stackify-ruby-apm_mongodata_config &> /dev/null
25
- echo "Deleted Volumes"
26
- }
27
-
28
- function rspec_on_multiple_versions(){
29
- # test against multiple ruby versions
30
- set -e
31
-
32
- RUBY_VERSIONS=('2.0.0-p648' '2.1.10' '2.2.10' '2.3.7' '2.4.0' '2.5.1' '2.6.0-preview3')
33
-
34
- for ver in "${RUBY_VERSIONS[@]}"
35
- do
36
- if ! rbenv versions | grep -w $ver; then
37
- # remove stale rbenv shim before rehashing
38
- SHIM=/home/$USER/.rbenv/shims/.rbenv-shim
39
- if [ -f $SHIM ]; then
40
- rm $SHIM
41
- fi
42
-
43
- rbenv install --verbose $ver
44
- rbenv rehash
45
- rbenv local $ver
46
- gem install bundler -v '~> 1.16'
47
- fi
48
-
49
- rbenv local $ver
50
- rbenv exec bundle update
51
-
52
- echo "====================================================="
53
- echo "$ver: Start Test"
54
- echo "====================================================="
55
-
56
- if ! bundle exec rspec spec/ --format documentation --fail-fast; then
57
- echo ">>>Unit Test Error on Version: $ver<<<"
58
- stopContainers
59
- exit 1
60
- else
61
- echo "====================================================="
62
- echo "$ver: End Test"
63
- echo "====================================================="
64
- fi
65
- done
66
- }
67
-
68
-
69
- startContainers
70
- waitForContainers
71
-
72
- rspec_on_multiple_versions
73
- stopContainers