stackify-ruby-apm 1.11.0 → 1.14.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/lib/stackify_apm/config.rb +36 -6
  3. data/lib/stackify_apm/context.rb +4 -1
  4. data/lib/stackify_apm/context/prefix.rb +30 -0
  5. data/lib/stackify_apm/context/request/headers.rb +30 -0
  6. data/lib/stackify_apm/context_builder.rb +1 -0
  7. data/lib/stackify_apm/helper/database_helper.rb +39 -0
  8. data/lib/stackify_apm/instrumenter_helper.rb +87 -0
  9. data/lib/stackify_apm/logger/logger_high_version.rb +5 -1
  10. data/lib/stackify_apm/logger/logger_lower_version.rb +5 -1
  11. data/lib/stackify_apm/middleware.rb +23 -3
  12. data/lib/stackify_apm/normalizers/active_record.rb +27 -8
  13. data/lib/stackify_apm/root_info.rb +6 -0
  14. data/lib/stackify_apm/serializers/transactions.rb +5 -0
  15. data/lib/stackify_apm/span/context.rb +42 -1
  16. data/lib/stackify_apm/spies.rb +4 -2
  17. data/lib/stackify_apm/spies/action_dispatch.rb +6 -1
  18. data/lib/stackify_apm/spies/curb.rb +41 -20
  19. data/lib/stackify_apm/spies/curb/easy.rb +220 -92
  20. data/lib/stackify_apm/spies/curb/multi.rb +26 -12
  21. data/lib/stackify_apm/spies/custom_instrumenter.rb +25 -4
  22. data/lib/stackify_apm/spies/dynamo_db.rb +51 -0
  23. data/lib/stackify_apm/spies/faraday.rb +87 -0
  24. data/lib/stackify_apm/spies/httparty.rb +45 -24
  25. data/lib/stackify_apm/spies/httpclient.rb +41 -20
  26. data/lib/stackify_apm/spies/httprb.rb +39 -18
  27. data/lib/stackify_apm/spies/log4r.rb +60 -0
  28. data/lib/stackify_apm/spies/logger.rb +117 -0
  29. data/lib/stackify_apm/spies/logging.rb +66 -0
  30. data/lib/stackify_apm/spies/mongo.rb +3 -1
  31. data/lib/stackify_apm/spies/net_http.rb +38 -20
  32. data/lib/stackify_apm/spies/redis.rb +39 -30
  33. data/lib/stackify_apm/spies/sequel.rb +28 -11
  34. data/lib/stackify_apm/spies/sinatra_activerecord/mysql_adapter.rb +48 -25
  35. data/lib/stackify_apm/spies/sinatra_activerecord/postgresql_adapter.rb +35 -24
  36. data/lib/stackify_apm/spies/sinatra_activerecord/sqlite_adapter.rb +18 -8
  37. data/lib/stackify_apm/spies/stackify_logger.rb +28 -16
  38. data/lib/stackify_apm/spies/sucker_punch.rb +39 -0
  39. data/lib/stackify_apm/spies/yell.rb +65 -0
  40. data/lib/stackify_apm/util.rb +10 -0
  41. data/lib/stackify_apm/version.rb +1 -1
  42. metadata +11 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c11dd1bfd73ddd45923cd58ee7672b9a6e0bc872ca07e92d10558b2b826f3f7b
4
- data.tar.gz: '018b2653259a17ada4fbc55aa117ac0300c2f0a0e4804e129ea2f3f24f4cb34e'
3
+ metadata.gz: 4db351752b697f408b2c683f6d6e82bb406f4b1acedd9cc8136bd38de622f613
4
+ data.tar.gz: baa9790e6ecbec16c9c27a68b7e60cdf3955ad60ab75b19fdd6f232efbec26b4
5
5
  SHA512:
6
- metadata.gz: 508a7a1213e03e3adfac74f4a1868b441cf878ad607a10911c7662f72665ae6715a5cbe562e0143f1a0199ea08f51340b7c74c90a457e7f32ae1f268077978be
7
- data.tar.gz: 8e10efe82d70b1728dc1661e896b3138e5dfd4a2bbeb5f77a3e2324b090e91554117039fb45de140e21bdb391caeade87ce7eee57c5c1f1b5b5a60c9c7fdb4c6
6
+ metadata.gz: 611d7584183fc9491055c5dc86f3141a4e6d72fc408e18a7e8b4d54fa1ee598a5ca6197b30ecd047793e1a5a139de89a18f0a6e4006605e0d17a2800558b871e
7
+ data.tar.gz: 3ce7f56cbabf25ac2c55d049eba7f76b86a056f8e8a248b7625d6762ec0717a680a4f28b03b9b84fb0be49eb074f19ca6f4c54ad9390dfca5812cd3500aa3a03
@@ -26,7 +26,7 @@ module StackifyRubyAPM
26
26
  environment_name: ENV['RAILS_ENV'] || ENV['RACK_ENV'],
27
27
  already_instrumented_flag: false,
28
28
  rum_auto_injection: false,
29
- rum_enabled: false,
29
+ rum_enabled: true,
30
30
  rum_cookie_path: '/',
31
31
  rum_cookie_name: '.Stackify.Rum',
32
32
  transport: StackifyRubyAPM::TRACE_LOG,
@@ -70,7 +70,8 @@ module StackifyRubyAPM
70
70
  transport_http_endpoint: 'https://localhost:10601',
71
71
 
72
72
  queue: true,
73
- lambda_handler: ''
73
+ lambda_handler: '',
74
+ prefix_enabled: false
74
75
  }.freeze
75
76
 
76
77
  ENV_TO_KEY = {
@@ -97,7 +98,8 @@ module StackifyRubyAPM
97
98
  'STACKIFY_FLUSH_INTERVAL' => 'flush_interval_seconds',
98
99
  'STACKIFY_DISABLED_SPIES' => [:list, 'disabled_spies'],
99
100
  'STACKIFY_QUEUE' => [:bool, 'queue'],
100
- 'STACKIFY_LAMBDA_HANDLER' => 'lambda_handler'
101
+ 'STACKIFY_LAMBDA_HANDLER' => 'lambda_handler',
102
+ 'STACKIFY_PREFIX_ENABLED' => [:bool, 'prefix_enabled']
101
103
  }.freeze
102
104
 
103
105
  def initialize(options = {})
@@ -105,6 +107,7 @@ module StackifyRubyAPM
105
107
  set_from_args(options)
106
108
  set_from_config_file
107
109
  set_from_env
110
+ set_prefix_paths if @prefix_enabled
108
111
  yield self if block_given?
109
112
  debug_logger
110
113
  StackifyRubyAPM::Util.host_os == 'WINDOWS' ? load_stackify_props_windows : load_stackify_props_linux
@@ -170,6 +173,7 @@ module StackifyRubyAPM
170
173
 
171
174
  attr_accessor :queue
172
175
  attr_accessor :lambda_handler
176
+ attr_accessor :prefix_enabled
173
177
 
174
178
  attr_reader :client_id
175
179
  attr_reader :device_id
@@ -210,7 +214,20 @@ module StackifyRubyAPM
210
214
  httparty
211
215
  stackify_logger
212
216
  sidekiq
213
- delayed_job
217
+ delayed_job
218
+ faraday
219
+ sucker_punch
220
+ dynamo_db
221
+ ]
222
+ end
223
+
224
+ def prefix_spies
225
+ return [] unless @prefix_enabled
226
+ %w[
227
+ logger
228
+ logging
229
+ log4r
230
+ yell
214
231
  ]
215
232
  end
216
233
 
@@ -233,7 +250,7 @@ module StackifyRubyAPM
233
250
  available_spies
234
251
  end
235
252
 
236
- new_available_spies - disabled_spies
253
+ new_available_spies + prefix_spies - disabled_spies
237
254
  end
238
255
 
239
256
  # Default Transport
@@ -254,7 +271,11 @@ module StackifyRubyAPM
254
271
 
255
272
  def assign(options)
256
273
  options.each do |key, value|
257
- send("#{key}=", value)
274
+ begin
275
+ send("#{key}=", value)
276
+ rescue Exception => e
277
+ info "[Config] Key: '#{key}' doesn't exist."
278
+ end
258
279
  end
259
280
  end
260
281
 
@@ -295,6 +316,14 @@ module StackifyRubyAPM
295
316
  assign(YAML.load_file(config_file) || {})
296
317
  end
297
318
 
319
+ # set log paths to prefix path if prefix_enabled is true
320
+ def set_prefix_paths
321
+ all_user_profile = ENV['ALLUSERSPROFILE'] || "C:\\ProgramData"
322
+
323
+ @log_path = StackifyRubyAPM::Util.host_os == 'WINDOWS' ? "#{all_user_profile}\\Stackify\\Agent\\debug\\stackify-ruby-apm-1.log" : "/usr/local/prefix/debug/stackify-ruby-apm-1.log"
324
+ @log_trace_path = StackifyRubyAPM::Util.host_os == 'WINDOWS' ? "#{all_user_profile}\\Stackify\\Agent\\log\\" : '/usr/local/prefix/log/'
325
+ end
326
+
298
327
  # rubocop:disable Naming/AccessorMethodName
299
328
  def set_rails(app)
300
329
  self.application_name ||= format_name(application_name || app.class.parent_name).strip
@@ -382,6 +411,7 @@ module StackifyRubyAPM
382
411
  info '[Config] environment_name must be String type.' unless @environment_name.is_a?(String) && defined?(@environment_name)
383
412
  info '[Config] transport must be String type.' unless @transport.is_a?(String) && defined?(@transport)
384
413
  info '[Config] Transport should be one of these values: [agent_socket, default, agent_http]. Should be a String.' if defined?(@transport) && !%w[agent_socket default agent_http].include?(@transport.downcase)
414
+ info '[Config] prefix_enabled must be Boolean type: true/false.' unless [TrueClass, FalseClass].include?(@prefix_enabled.class) && defined?(@prefix_enabled)
385
415
  end
386
416
  # rubocop:enable Metrics/CyclomaticComplexity
387
417
  # rubocop:enable Metrics/PerceivedComplexity
@@ -2,7 +2,9 @@
2
2
 
3
3
  # This class initializes the parameters and variables for the context of Transaction/Span
4
4
 
5
+ require 'stackify_apm/context/prefix'
5
6
  require 'stackify_apm/context/request'
7
+ require 'stackify_apm/context/request/headers'
6
8
  require 'stackify_apm/context/request/socket'
7
9
  require 'stackify_apm/context/request/url'
8
10
  require 'stackify_apm/context/response'
@@ -12,12 +14,13 @@ module StackifyRubyAPM
12
14
  class Context
13
15
  include NaivelyHashable
14
16
 
15
- attr_accessor :request, :response, :aws, :category
17
+ attr_accessor :request, :response, :aws, :category, :prefix
16
18
  attr_reader :custom, :tags
17
19
 
18
20
  def initialize
19
21
  @custom = {}
20
22
  @tags = {}
23
+ @prefix = Context::Prefix.new
21
24
  end
22
25
 
23
26
  # add aws context to context instance
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StackifyRubyAPM
4
+ class Context
5
+ # @api private
6
+ class Prefix
7
+ include NaivelyHashable
8
+
9
+ attr_accessor :response_body, :request_body
10
+ attr_reader :response_headers, :request_headers
11
+
12
+ def request_headers=(headers)
13
+ @request_headers = to_json_list(headers)
14
+ end
15
+
16
+ def response_headers=(headers)
17
+ @response_headers = to_json_list(headers)
18
+ end
19
+
20
+ private
21
+ def to_json_list(header)
22
+ list_header = []
23
+ header.each do |key, value|
24
+ list_header << {key => value}
25
+ end
26
+ list_header.to_json
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StackifyRubyAPM
4
+ # @api private
5
+ class Context
6
+ # @api private
7
+ class Request
8
+ # @api private
9
+ class Headers
10
+ include NaivelyHashable
11
+
12
+ def initialize(req)
13
+ @values = build_headers req
14
+ end
15
+
16
+ attr_reader :values
17
+
18
+ def build_headers req
19
+ env = req.env
20
+ headers = Hash[*env.select {|k,v| k.start_with? 'HTTP_'}
21
+ .collect {|k,v| [k.sub(/^HTTP_/, ''), v]}
22
+ .collect {|k,v| [k.split('_').collect(&:capitalize).join('-'), v]}
23
+ .sort
24
+ .flatten]
25
+ return headers
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -27,6 +27,7 @@ module StackifyRubyAPM
27
27
  request.method = req.request_method
28
28
  request.url = Context::Request::Url.new(req).to_h
29
29
  request.body = get_body(req)
30
+ request.headers = Context::Request::Headers.new(req).values
30
31
 
31
32
  context
32
33
  end
@@ -23,5 +23,44 @@ module DatabaseHelper
23
23
  end
24
24
  # rubocop:enable Metrics/CyclomaticComplexity
25
25
  # rubocop:enable Metrics/PerceivedComplexity
26
+
27
+ # Check the prepared statement by placeholder if its valid
28
+ # placeholder - contains the prepared statement pattern.
29
+ # Placeholder for mysql, sqlite, jdbc oracle, db2 is ?, example "SELECT * FROM posts WHERE author = ? and id = ?"
30
+ # Placeholder for postgres is $1, $2,...$n, example "SELECT * FROM posts WHERE author = $1 and id = $2"
31
+ # statement - contains the db properties such as SQL, PROVIDER, etc.
32
+ # So if there's payload value we append PREFIX_SQL_PARAMETERS to the existing object properties.
33
+ # payload - contains the payload[:binds] which is the payload value/data of the placeholder.
34
+ # Example payload: {:sql=>"SELECT * FROM posts WHERE author = ? and id = ?", :db_adapter=>"mysql2::client", :binds=>["J.K. Rowling", 1]}
35
+ def check_prepared_stmt_by_placeholder(placeholder, statement, payload)
36
+ sqlParam = []
37
+ unless payload[:binds].nil?
38
+ payload[:binds].each_with_index do |record, idx|
39
+ if record && defined?(record.value)
40
+ StackifyRubyAPM::Util.pushToAryIndex(sqlParam, idx, record.value[0..999])
41
+ elsif ((record && record.instance_of?(Array)) && defined?(record[1]))
42
+ StackifyRubyAPM::Util.pushToAryIndex(sqlParam, idx, record[1][0..999])
43
+ else
44
+ StackifyRubyAPM::Util.pushToAryIndex(sqlParam, idx, record[0..999])
45
+ end
46
+ end
47
+ statement[:PREFIX_SQL_PARAMETERS] = sqlParam[0..99].to_json if sqlParam.count > 0
48
+ statement[:PREFIX_SQL_PARAMETER_COUNT] = sqlParam.length.to_s if sqlParam.count > 0
49
+ true
50
+ else
51
+ false
52
+ end
53
+ end
54
+
55
+ # Common DB span properties shared to sequel, activerecord, etc.
56
+ def get_common_db_properties
57
+ {
58
+ CATEGORY: 'Database',
59
+ SUBCATEGORY: 'Execute',
60
+ COMPONENT_CATEGORY: 'DB Query',
61
+ COMPONENT_DETAIL: 'Execute SQL Query',
62
+ PROVIDER: 'generic'
63
+ }
64
+ end
26
65
  end
27
66
  include DatabaseHelper
@@ -189,6 +189,93 @@ module StackifyRubyAPM
189
189
  @custom_class_info[current_class.to_s]['controller'] = true if class_path && class_path.include?('controllers')
190
190
  @custom_class_info[current_class.to_s]['model'] = true if class_path && class_path.include?('models')
191
191
  end
192
+
193
+ # Monkey patch the single ruby module file.
194
+ #
195
+ # tracked_func - trackedFunction variable in stackify.json
196
+ # current_module - module variable in stackify.json
197
+ # class_path - file_path variable in stackify.json
198
+ # options - other options such as trackedFunctionName
199
+ def self.patched_module(tracked_func, current_module, class_path, **options)
200
+ current_method = options[:current_method] || nil
201
+ tracked_function_name = options[:tracked_function_name] || nil
202
+ transaction = options[:is_transaction] || nil
203
+ mod_spy = "#{current_module}Spy"
204
+
205
+ unless @custom_instrumented[current_module.to_s]
206
+ @custom_instrumented[current_module.to_s] = {}
207
+ end
208
+
209
+ unless @custom_instrumented[current_module.to_s][current_method.to_s]
210
+ @custom_instrumented[current_module.to_s][current_method.to_s] = false
211
+ end
212
+
213
+ unless @custom_class_info[current_module.to_s]
214
+ @custom_class_info[current_module.to_s] = {}
215
+ end
216
+
217
+ unless @custom_class_info[current_module.to_s]['controller']
218
+ @custom_class_info[current_module.to_s]['controller'] = false
219
+ end
220
+
221
+ unless @custom_class_info[current_module.to_s]['model']
222
+ @custom_class_info[current_module.to_s]['model'] = false
223
+ end
224
+
225
+ return unless @custom_instrumented[current_module.to_s][current_method.to_s] == false
226
+
227
+ eval <<-RUBY
228
+ module #{mod_spy}
229
+ def self.install
230
+ #{current_module}.class_eval do
231
+ class<< self
232
+ alias_method "#{current_method}_without_apm", "#{current_method}"
233
+
234
+ def #{current_method}(*args, &block)
235
+ if StackifyRubyAPM.current_transaction.nil? && #{!transaction.nil?}
236
+ t = StackifyRubyAPM.transaction("custom.#{current_module}.#{current_method}", TRACETYPE)
237
+ begin
238
+ req = #{current_method}_without_apm(*args, &block)
239
+ rescue Exception => e
240
+ StackifyRubyAPM.report(e)
241
+ raise e
242
+ ensure
243
+ t.submit
244
+ end
245
+ return req
246
+ elsif StackifyRubyAPM.current_transaction
247
+ name = "Custom Instrument"
248
+ type = "#{current_module}##{current_method}"
249
+ ctx = if "#{tracked_func}" == 'true'
250
+ Span::Context.new(
251
+ CATEGORY: 'Ruby',
252
+ TRACKED_FUNC: "#{tracked_function_name}"
253
+ )
254
+ else
255
+ Span::Context.new(
256
+ CATEGORY: 'Ruby'
257
+ )
258
+ end
259
+
260
+ StackifyRubyAPM.span name, type, context: ctx do
261
+ #{current_method}_without_apm(*args, &block)
262
+ end
263
+ else
264
+ return #{current_method}_without_apm(*args, &block)
265
+ end
266
+ end
267
+ end
268
+ end
269
+ end
270
+ end
271
+
272
+ StackifyRubyAPM::Spies.register current_module.to_s, class_path.to_s, #{mod_spy}, true, "#{current_method}", "#{tracked_func}", "#{tracked_function_name}"
273
+ RUBY
274
+ @custom_instrumented[current_module.to_s][current_method.to_s] = true
275
+ @custom_class_info[current_module.to_s]['controller'] = true if class_path && class_path.include?('controllers')
276
+ @custom_class_info[current_module.to_s]['model'] = true if class_path && class_path.include?('models')
277
+ end
278
+
192
279
  # rubocop:enable Metrics/CyclomaticComplexity
193
280
  # rubocop:enable Metrics/PerceivedComplexity
194
281
  # rubocop:enable Lint/UselessAssignment
@@ -29,7 +29,11 @@ module StackifyRubyAPM
29
29
  temp_filename = logdev.gsub('-1.log', '')
30
30
  new_logdev = temp_filename + '-1.log'
31
31
  end
32
- @logdev = LogDevice.new(new_logdev, shift_size: shift_size)
32
+ begin
33
+ @logdev = LogDevice.new(new_logdev, shift_size: shift_size)
34
+ rescue StandardError => e
35
+ puts "Stackify Profiler unable to access [" + logdev + "]"
36
+ end
33
37
  end
34
38
  end
35
39
  require 'stackify_apm/logger/log_device'
@@ -20,7 +20,11 @@ module StackifyRubyAPM
20
20
  temp_filename = logdev.gsub('-1.log', '')
21
21
  new_logdev = temp_filename + '-1.log'
22
22
  end
23
- @logdev = LogDevice.new(new_logdev, shift_size: shift_size)
23
+ begin
24
+ @logdev = LogDevice.new(new_logdev, shift_size: shift_size)
25
+ rescue StandardError => e
26
+ puts "Stackify Profiler unable to access [" + logdev + "]"
27
+ end
24
28
  end
25
29
  end
26
30
 
@@ -39,7 +39,8 @@ module StackifyRubyAPM
39
39
  # rubocop:disable Metrics/PerceivedComplexity
40
40
  def call(env)
41
41
  begin
42
- transaction = build_transaction(env) if running?
42
+ context = StackifyRubyAPM.build_context(env)
43
+ transaction = build_transaction(env, context) if running?
43
44
  resp = @app.call env
44
45
 
45
46
  @rack_status = resp[0].to_i
@@ -47,9 +48,13 @@ module StackifyRubyAPM
47
48
  @rack_body = resp[2]
48
49
  @configuration = config
49
50
 
51
+ build_prefix_context(transaction, context)
52
+
50
53
  if okay_to_modify?
51
54
  @configuration.already_instrumented_flag = true
52
55
  if @configuration.rum_enabled.is_a?(TrueClass)
56
+ # close old response body proxy to close all db connections
57
+ @rack_body.close if @rack_body.respond_to?(:close)
53
58
  response = Rack::Response.new @rack_body, @rack_status, @rack_headers
54
59
  response.set_cookie(@configuration.rum_cookie_name, value: transaction.id, path: @configuration.rum_cookie_path)
55
60
  resp = response.finish
@@ -92,8 +97,9 @@ module StackifyRubyAPM
92
97
 
93
98
  # Start of transaction building with params: name, type, context
94
99
  #
95
- def build_transaction(env)
96
- StackifyRubyAPM.transaction 'Rack', 'WEBAPP', context: StackifyRubyAPM.build_context(env)
100
+ def build_transaction(env, context=nil)
101
+ context = context || StackifyRubyAPM.build_context(env)
102
+ StackifyRubyAPM.transaction 'Rack', 'WEBAPP', context: context
97
103
  end
98
104
 
99
105
  def running?
@@ -129,5 +135,19 @@ module StackifyRubyAPM
129
135
  def xhr?
130
136
  @rack_headers['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'
131
137
  end
138
+
139
+ # Add prefix instrument data to transaction context if enabled
140
+ def build_prefix_context(transaction, context)
141
+ return nil unless @configuration.prefix_enabled.is_a?(TrueClass)
142
+
143
+ source = nil
144
+ body = @rack_body
145
+ body.each { |fragment| source ? (source << fragment.to_s) : (source = fragment.to_s) }
146
+
147
+ transaction.context.prefix.request_body = context && context.request && context.request.body || ""
148
+ transaction.context.prefix.request_headers = context && context.request && context.request.headers || Hash.new
149
+ transaction.context.prefix.response_body = source || ""
150
+ transaction.context.prefix.response_headers = @rack_headers || Hash.new
151
+ end
132
152
  end
133
153
  end
@@ -20,6 +20,7 @@ module StackifyRubyAPM
20
20
  return :skip if %w[SCHEMA CACHE].include?(payload[:name])
21
21
 
22
22
  statement = query_variables(payload)
23
+ check_prepared_stmt(statement, payload)
23
24
  name = payload[:sql] || payload[:name] || 'Default'
24
25
  context = Span::Context.new(statement)
25
26
  [name, @type, context]
@@ -28,14 +29,14 @@ module StackifyRubyAPM
28
29
  private
29
30
 
30
31
  def query_variables(payload)
31
- {
32
- CATEGORY: 'Database',
33
- SUBCATEGORY: 'Execute',
34
- COMPONENT_CATEGORY: 'DB Query',
35
- COMPONENT_DETAIL: 'Execute SQL Query',
36
- SQL: payload[:sql],
37
- PROVIDER: get_profiler(lookup_adapter)
38
- }
32
+ adapter_config = lookup_adapter_config
33
+ props = get_common_db_properties
34
+ props[:PROVIDER] = get_profiler(lookup_adapter)
35
+ props[:SQL] = payload[:sql]
36
+ if adapter_config
37
+ props[:URL] = "#{adapter_config[:host]}:#{adapter_config[:port]}"
38
+ end
39
+ props
39
40
  end
40
41
 
41
42
  def lookup_adapter
@@ -44,6 +45,24 @@ module StackifyRubyAPM
44
45
  debug '[SqlNormalizer] lookup_adapter err: ' + error.inspect.to_s
45
46
  nil
46
47
  end
48
+
49
+ def lookup_adapter_config
50
+ ::ActiveRecord::Base.connection_config.to_h
51
+ rescue StandardError => error
52
+ debug '[SqlNormalizer] lookup_adapter_config err: ' + error.inspect.to_s
53
+ nil
54
+ end
55
+
56
+ def check_prepared_stmt(statement, payload)
57
+ if StackifyRubyAPM.agent.config.prefix_enabled
58
+ case get_profiler(lookup_adapter)
59
+ when 'generic', 'mysql', 'sqlite', 'oracle', 'db2'
60
+ check_prepared_stmt_by_placeholder(payload[:sql].include?('?'), statement, payload)
61
+ when 'postgresql'
62
+ check_prepared_stmt_by_placeholder(!!payload[:sql].match(/\$\d/), statement, payload)
63
+ end
64
+ end
65
+ end
47
66
  end
48
67
  end
49
68
  end