appsignal 0.12.beta.31 → 0.12.beta.32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +23 -0
  3. data/Rakefile +1 -0
  4. data/benchmark.rake +20 -20
  5. data/ext/appsignal_extension.c +31 -23
  6. data/gemfiles/padrino.gemfile +7 -0
  7. data/lib/appsignal.rb +50 -27
  8. data/lib/appsignal/capistrano.rb +2 -1
  9. data/lib/appsignal/config.rb +94 -39
  10. data/lib/appsignal/event_formatter/active_record/sql_formatter.rb +12 -17
  11. data/lib/appsignal/integrations/padrino.rb +65 -0
  12. data/lib/appsignal/integrations/rails.rb +4 -2
  13. data/lib/appsignal/integrations/rake.rb +30 -0
  14. data/lib/appsignal/integrations/sidekiq.rb +2 -2
  15. data/lib/appsignal/integrations/sinatra.rb +0 -1
  16. data/lib/appsignal/js_exception_transaction.rb +4 -9
  17. data/lib/appsignal/params_sanitizer.rb +8 -5
  18. data/lib/appsignal/rack/rails_instrumentation.rb +41 -0
  19. data/lib/appsignal/rack/sinatra_instrumentation.rb +31 -24
  20. data/lib/appsignal/subscriber.rb +2 -9
  21. data/lib/appsignal/transaction.rb +86 -75
  22. data/lib/appsignal/transmitter.rb +30 -3
  23. data/lib/appsignal/version.rb +2 -2
  24. data/spec/lib/appsignal/cli_spec.rb +1 -1
  25. data/spec/lib/appsignal/config_spec.rb +38 -131
  26. data/spec/lib/appsignal/event_formatter/active_record/sql_formatter_spec.rb +27 -29
  27. data/spec/lib/appsignal/extension_spec.rb +11 -29
  28. data/spec/lib/appsignal/integrations/padrino_spec.rb +191 -0
  29. data/spec/lib/appsignal/integrations/rails_spec.rb +3 -4
  30. data/spec/lib/appsignal/integrations/rake_spec.rb +78 -0
  31. data/spec/lib/appsignal/integrations/resque_spec.rb +2 -2
  32. data/spec/lib/appsignal/integrations/sequel_spec.rb +2 -3
  33. data/spec/lib/appsignal/integrations/sidekiq_spec.rb +22 -5
  34. data/spec/lib/appsignal/integrations/sinatra_spec.rb +0 -6
  35. data/spec/lib/appsignal/js_exception_transaction_spec.rb +4 -6
  36. data/spec/lib/appsignal/params_sanitizer_spec.rb +27 -11
  37. data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +79 -0
  38. data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +71 -71
  39. data/spec/lib/appsignal/subscriber_spec.rb +3 -37
  40. data/spec/lib/appsignal/transaction_spec.rb +290 -155
  41. data/spec/lib/appsignal/transmitter_spec.rb +10 -0
  42. data/spec/lib/appsignal_spec.rb +80 -47
  43. data/spec/spec_helper.rb +21 -2
  44. data/spec/support/helpers/env_helpers.rb +31 -0
  45. data/spec/support/helpers/notification_helpers.rb +1 -30
  46. data/spec/support/helpers/transaction_helpers.rb +7 -7
  47. data/spec/support/project_fixture/config/appsignal.yml +2 -0
  48. metadata +14 -8
  49. data/lib/appsignal/rack/instrumentation.rb +0 -32
  50. data/lib/appsignal/rack/listener.rb +0 -32
  51. data/spec/lib/appsignal/rack/instrumentation_spec.rb +0 -72
  52. data/spec/lib/appsignal/rack/listener_spec.rb +0 -104
@@ -4,13 +4,12 @@ module Appsignal
4
4
  class SqlFormatter < Appsignal::EventFormatter
5
5
  register 'sql.active_record'
6
6
 
7
- SINGLE_QUOTE = /\\'/.freeze
8
- DOUBLE_QUOTE = /\\"/.freeze
9
- QUOTED_DATA = /(?:"[^"]+"|'[^']+')/.freeze
10
- SINGLE_QUOTED_DATA = /(?:'[^']+')/.freeze
11
- IN_ARRAY = /(IN \()[^\)]+(\))/.freeze
12
- NUMERIC_DATA = /\b\d+\b/.freeze
13
- SANITIZED_VALUE = '\1?\2'.freeze
7
+ SINGLE_QUOTED_STRING = /'(.?|[^'])*'/.freeze
8
+ DOUBLE_QUOTED_STRING = /"(.?|[^"])*"/.freeze
9
+ IN_OPERATOR_CONTENT = /(IN \()[^\)]+(\))/.freeze
10
+ NUMERIC = /\d*\.?\d+/.freeze
11
+ REPLACEMENT = '\1?\2'.freeze
12
+ SCHEMA = 'SCHEMA'.freeze
14
13
 
15
14
  attr_reader :adapter_uses_double_quoted_table_names
16
15
 
@@ -25,23 +24,19 @@ module Appsignal
25
24
  def format(payload)
26
25
  return nil if schema_query?(payload) || !payload[:sql]
27
26
  sql_string = payload[:sql].dup
28
- if adapter_uses_double_quoted_table_names
29
- sql_string.gsub!(SINGLE_QUOTE, SANITIZED_VALUE)
30
- sql_string.gsub!(SINGLE_QUOTED_DATA, SANITIZED_VALUE)
31
- else
32
- sql_string.gsub!(SINGLE_QUOTE, SANITIZED_VALUE)
33
- sql_string.gsub!(DOUBLE_QUOTE, SANITIZED_VALUE)
34
- sql_string.gsub!(QUOTED_DATA, SANITIZED_VALUE)
27
+ unless adapter_uses_double_quoted_table_names
28
+ sql_string.gsub!(DOUBLE_QUOTED_STRING, REPLACEMENT)
35
29
  end
36
- sql_string.gsub!(IN_ARRAY, SANITIZED_VALUE)
37
- sql_string.gsub!(NUMERIC_DATA, SANITIZED_VALUE)
30
+ sql_string.gsub!(SINGLE_QUOTED_STRING, REPLACEMENT)
31
+ sql_string.gsub!(IN_OPERATOR_CONTENT, REPLACEMENT)
32
+ sql_string.gsub!(NUMERIC, REPLACEMENT)
38
33
  [payload[:name], sql_string]
39
34
  end
40
35
 
41
36
  protected
42
37
 
43
38
  def schema_query?(payload)
44
- payload[:name] == 'SCHEMA'
39
+ payload[:name] == SCHEMA
45
40
  end
46
41
 
47
42
  def connection_config
@@ -0,0 +1,65 @@
1
+ require 'appsignal'
2
+
3
+ module Appsignal::Integrations
4
+ module PadrinoPlugin
5
+ def self.init
6
+ Appsignal.logger.info("Loading Padrino (#{Padrino::VERSION}) integration")
7
+
8
+ root = Padrino.mounted_root
9
+ Appsignal.config = Appsignal::Config.new(root, Padrino.env)
10
+
11
+ Appsignal.start_logger(File.join(root, 'log'))
12
+ Appsignal.start
13
+ end
14
+ end
15
+ end
16
+
17
+ module Padrino::Routing::InstanceMethods
18
+ alias route_without_appsignal route!
19
+
20
+ def route!(base=settings, pass_block=nil)
21
+ if !Appsignal.active? || env['sinatra.static_file']
22
+ route_without_appsignal(base, pass_block)
23
+ return
24
+ end
25
+
26
+ transaction = Appsignal::Transaction.create(
27
+ SecureRandom.uuid,
28
+ Appsignal::Transaction::HTTP_REQUEST,
29
+ request
30
+ )
31
+ begin
32
+ ActiveSupport::Notifications.instrument('process_action.padrino') do
33
+ route_without_appsignal(base, pass_block)
34
+ end
35
+ rescue => error
36
+ transaction.set_error(error)
37
+ raise error
38
+ ensure
39
+ transaction.set_action(get_payload_action(request))
40
+ transaction.set_metadata('path', request.path)
41
+ transaction.set_metadata('method', request.request_method)
42
+ transaction.set_http_or_background_queue_start
43
+ Appsignal::Transaction.complete_current!
44
+ end
45
+ end
46
+
47
+ def get_payload_action(request)
48
+ # Short-circut is there's no request object to obtain information from
49
+ return "#{settings.name}" if request.nil?
50
+
51
+ # Older versions of Padrino work with a route object
52
+ route_obj = defined?(request.route_obj) && request.route_obj
53
+ if route_obj && route_obj.respond_to?(:original_path)
54
+ return "#{settings.name}:#{request.route_obj.original_path}"
55
+ end
56
+
57
+ # Newer versions expose the action / controller on the request class
58
+ request_data = request.respond_to?(:action) ? request.action : request.fullpath
59
+ "#{settings.name}:#{request.controller}##{request_data}"
60
+ end
61
+ end
62
+
63
+ Padrino.after_load do
64
+ Appsignal::Integrations::PadrinoPlugin.init
65
+ end
@@ -1,6 +1,8 @@
1
1
  if defined?(::Rails)
2
2
  Appsignal.logger.info("Loading Rails (#{Rails.version}) integration")
3
3
 
4
+ require 'appsignal/rack/rails_instrumentation'
5
+
4
6
  module Appsignal
5
7
  module Integrations
6
8
  class Railtie < ::Rails::Railtie
@@ -21,13 +23,13 @@ if defined?(::Rails)
21
23
 
22
24
  app.middleware.insert_before(
23
25
  ActionDispatch::RemoteIp,
24
- Appsignal::Rack::Listener
26
+ Appsignal::Rack::RailsInstrumentation
25
27
  )
26
28
 
27
29
  if Appsignal.config.active? &&
28
30
  Appsignal.config[:enable_frontend_error_catching] == true
29
31
  app.middleware.insert_before(
30
- Appsignal::Rack::Listener,
32
+ Appsignal::Rack::RailsInstrumentation,
31
33
  Appsignal::Rack::JSExceptionCatcher,
32
34
  )
33
35
  end
@@ -0,0 +1,30 @@
1
+ module Rake
2
+ class Task
3
+ alias_method :invoke_without_appsignal, :invoke
4
+
5
+ def invoke(*args)
6
+ if Appsignal.active?
7
+ invoke_with_appsignal(*args)
8
+ else
9
+ invoke_without_appsignal(*args)
10
+ end
11
+ end
12
+
13
+ def invoke_with_appsignal(*args)
14
+ invoke_without_appsignal(*args)
15
+ rescue => error
16
+ transaction = Appsignal::Transaction.create(
17
+ SecureRandom.uuid,
18
+ Appsignal::Transaction::BACKGROUND_JOB,
19
+ Appsignal::Transaction::GenericRequest.new(
20
+ :params => args
21
+ )
22
+ )
23
+ transaction.set_action(name)
24
+ transaction.set_error(error)
25
+ transaction.complete!
26
+ sleep 0.5 # Give us some time to flush to the agent
27
+ raise error
28
+ end
29
+ end
30
+ end
@@ -15,7 +15,7 @@ if defined?(::Sidekiq)
15
15
  def call(worker, item, queue)
16
16
  Appsignal.monitor_transaction(
17
17
  'perform_job.sidekiq',
18
- :class => item['class'],
18
+ :class => item['wrapped'] || item['class'],
19
19
  :method => 'perform',
20
20
  :metadata => formatted_metadata(item),
21
21
  :params => format_args(item['args']),
@@ -48,7 +48,7 @@ if defined?(::Sidekiq)
48
48
  end
49
49
 
50
50
  def truncate(text)
51
- text.size > 100 ? "#{text[0...97]}..." : text
51
+ text.size > 200 ? "#{text[0...197]}..." : text
52
52
  end
53
53
  end
54
54
  end
@@ -14,6 +14,5 @@ Appsignal.start_logger(app_settings.root)
14
14
  Appsignal.start
15
15
 
16
16
  if Appsignal.active?
17
- ::Sinatra::Application.use(Appsignal::Rack::Listener)
18
17
  ::Sinatra::Application.use(Appsignal::Rack::SinatraInstrumentation)
19
18
  end
@@ -5,21 +5,16 @@ module Appsignal
5
5
  def initialize(data)
6
6
  @data = data
7
7
  @uuid = SecureRandom.uuid
8
- @transaction_index = Appsignal::Extension.start_transaction(@uuid)
8
+ @transaction_index = Appsignal::Extension.start_transaction(@uuid, Appsignal::Transaction::FRONTEND)
9
9
 
10
- set_base_data
10
+ set_action
11
11
  set_metadata
12
12
  set_error
13
13
  set_error_data
14
14
  end
15
15
 
16
- def set_base_data
17
- Appsignal::Extension.set_transaction_base_data(
18
- @transaction_index,
19
- 'frontend',
20
- @data['action'],
21
- 0
22
- )
16
+ def set_action
17
+ Appsignal::Extension.set_transaction_action(@transaction_index, @data['action'])
23
18
  end
24
19
 
25
20
  def set_metadata
@@ -25,8 +25,10 @@ module Appsignal
25
25
  sanitize_hash(value)
26
26
  when Array
27
27
  sanitize_array(value)
28
- when Fixnum, String, Symbol
28
+ when Fixnum, String, Symbol, Float
29
29
  unmodified(value)
30
+ when TrueClass, FalseClass
31
+ stringified(value)
30
32
  else
31
33
  inspected(value)
32
34
  end
@@ -46,15 +48,16 @@ module Appsignal
46
48
  target_array
47
49
  end
48
50
 
51
+ def stringified(value)
52
+ value.to_s
53
+ end
54
+
49
55
  def unmodified(value)
50
56
  value
51
57
  end
52
58
 
53
59
  def inspected(value)
54
- value.inspect
55
- rescue
56
- # It turns out that sometimes inspect can fail
57
- "#<#{value.class.to_s}/>"
60
+ "#<#{value.class.to_s}>"
58
61
  end
59
62
  end
60
63
  end
@@ -0,0 +1,41 @@
1
+ require 'rack'
2
+
3
+ module Appsignal
4
+ module Rack
5
+ class RailsInstrumentation
6
+ def initialize(app, options = {})
7
+ Appsignal.logger.debug 'Initializing Appsignal::Rack::RailsInstrumentation'
8
+ @app, @options = app, options
9
+ end
10
+
11
+ def call(env)
12
+ if Appsignal.active?
13
+ call_with_appsignal_monitoring(env)
14
+ else
15
+ @app.call(env)
16
+ end
17
+ end
18
+
19
+ def call_with_appsignal_monitoring(env)
20
+ request = ActionDispatch::Request.new(env)
21
+ transaction = Appsignal::Transaction.create(
22
+ env['action_dispatch.request_id'],
23
+ Appsignal::Transaction::HTTP_REQUEST,
24
+ request
25
+ )
26
+ begin
27
+ @app.call(env)
28
+ rescue => error
29
+ transaction.set_error(error)
30
+ raise error
31
+ ensure
32
+ transaction.set_http_or_background_action
33
+ transaction.set_http_or_background_queue_start
34
+ transaction.set_metadata('path', request.path)
35
+ transaction.set_metadata('method', request.request_method)
36
+ Appsignal::Transaction.complete_current!
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -9,33 +9,40 @@ module Appsignal
9
9
  end
10
10
 
11
11
  def call(env)
12
- ActiveSupport::Notifications.instrument(
13
- 'process_action.sinatra',
14
- raw_payload(env)
15
- ) do |payload|
16
- begin
17
- @app.call(env)
18
- ensure
19
- # This information is available only after the
20
- # request has been processed by Sinatra.
21
- payload[:action] = env['sinatra.route']
22
- end
12
+ if Appsignal.active?
13
+ call_with_appsignal_monitoring(env)
14
+ else
15
+ @app.call(env)
23
16
  end
24
- ensure
25
- # In production newer versions of Sinatra don't raise errors, but store
26
- # them in the sinatra.error env var.
27
- Appsignal::Transaction.current.add_exception(env['sinatra.error']) if env['sinatra.error']
28
17
  end
29
18
 
30
- def raw_payload(env)
31
- request = @options.fetch(:request_class, ::Sinatra::Request).new(env)
32
- params = request.public_send(@options.fetch(:params_method, :params))
33
- {
34
- :params => params,
35
- :session => request.session,
36
- :method => request.request_method,
37
- :path => request.path
38
- }
19
+ def call_with_appsignal_monitoring(env)
20
+ if @options[:params_method]
21
+ env[:params_method] = @options[:params_method]
22
+ end
23
+ request = @options.fetch(:request_class, Sinatra::Request).new(env)
24
+ transaction = Appsignal::Transaction.create(
25
+ SecureRandom.uuid,
26
+ Appsignal::Transaction::HTTP_REQUEST,
27
+ request
28
+ )
29
+ begin
30
+ ActiveSupport::Notifications.instrument('process_action.sinatra') do
31
+ @app.call(env)
32
+ end
33
+ rescue => error
34
+ transaction.set_error(error)
35
+ raise error
36
+ ensure
37
+ # In production newer versions of Sinatra don't raise errors, but store
38
+ # them in the sinatra.error env var.
39
+ transaction.set_error(env['sinatra.error']) if env['sinatra.error']
40
+ transaction.set_action(env['sinatra.route'])
41
+ transaction.set_metadata('path', request.path)
42
+ transaction.set_metadata('method', request.request_method)
43
+ transaction.set_http_or_background_queue_start
44
+ Appsignal::Transaction.complete_current!
45
+ end
39
46
  end
40
47
  end
41
48
  end
@@ -1,8 +1,6 @@
1
1
  module Appsignal
2
2
  class Subscriber
3
- PROCESS_ACTION_PREFIX = 'process_action'.freeze
4
- PERFORM_JOB_PREFIX = 'perform_job'.freeze
5
- BLANK = ''.freeze
3
+ BLANK = ''.freeze
6
4
 
7
5
  def initialize
8
6
  subscribe
@@ -33,18 +31,13 @@ module Appsignal
33
31
 
34
32
  def start(name, id, payload)
35
33
  return unless transaction = Appsignal::Transaction.current
36
-
37
34
  return if transaction.paused?
35
+
38
36
  Appsignal::Extension.start_event(transaction.transaction_index)
39
37
  end
40
38
 
41
39
  def finish(name, id, payload)
42
40
  return unless transaction = Appsignal::Transaction.current
43
-
44
- if name.start_with?(PROCESS_ACTION_PREFIX, PERFORM_JOB_PREFIX)
45
- transaction.set_root_event(name, payload)
46
- end
47
-
48
41
  return if transaction.paused?
49
42
 
50
43
  title, body = Appsignal::EventFormatter.format(name, payload)
@@ -2,6 +2,7 @@ module Appsignal
2
2
  class Transaction
3
3
  HTTP_REQUEST = 'http_request'.freeze
4
4
  BACKGROUND_JOB = 'background_job'.freeze
5
+ FRONTEND = 'frontend'.freeze
5
6
 
6
7
  # Based on what Rails uses + some variables we'd like to show
7
8
  ENV_METHODS = %w(CONTENT_LENGTH AUTH_TYPE GATEWAY_INTERFACE
@@ -15,8 +16,8 @@ module Appsignal
15
16
  HTTP_PRAGMA HTTP_REFERER HTTP_X_FORWARDED_FOR HTTP_CLIENT_IP).freeze
16
17
 
17
18
  class << self
18
- def create(request_id, env)
19
- Thread.current[:appsignal_transaction] = Appsignal::Transaction.new(request_id, env)
19
+ def create(id, namespace, request, options={})
20
+ Thread.current[:appsignal_transaction] = Appsignal::Transaction.new(id, namespace, request, options)
20
21
  end
21
22
 
22
23
  def current
@@ -33,68 +34,74 @@ module Appsignal
33
34
  end
34
35
  end
35
36
 
36
- attr_reader :request_id, :transaction_index, :process_action_event, :action, :exception,
37
- :env, :fullpath, :time, :tags, :kind, :queue_start, :paused, :root_event_payload
37
+ attr_reader :transaction_index, :transaction_id, :namespace, :request, :paused, :tags, :options
38
38
 
39
- def initialize(request_id, env)
40
- @root_event_payload = nil
41
- @request_id = request_id
42
- @process_action_event = nil
43
- @exception = nil
44
- @env = env
45
- @tags = {}
39
+ def initialize(transaction_id, namespace, request, options)
40
+ @transaction_id = transaction_id
41
+ @namespace = namespace
42
+ @request = request
46
43
  @paused = false
47
- @queue_start = -1
48
- @transaction_index = Appsignal::Extension.start_transaction(@request_id)
44
+ @tags = {}
45
+
46
+ @options = options
47
+ @options[:params_method] ||= :params
48
+
49
+ @transaction_index = Appsignal::Extension.start_transaction(@transaction_id, @namespace)
49
50
  end
50
51
 
51
- def sanitized_environment
52
- @sanitized_environment ||= {}
52
+ def pause!
53
+ @paused = true
53
54
  end
54
55
 
55
- def sanitized_session_data
56
- @sanitized_session_data ||= {}
56
+ def resume!
57
+ @paused = false
57
58
  end
58
59
 
59
- def request
60
- @request ||= ::Rack::Request.new(env)
60
+ def paused?
61
+ @paused == true
61
62
  end
62
63
 
63
64
  def set_tags(given_tags={})
64
65
  @tags.merge!(given_tags)
65
66
  end
66
67
 
67
- def set_root_event(name, payload)
68
- @root_event_payload = payload
69
- if name.start_with?(Subscriber::PROCESS_ACTION_PREFIX)
70
- @action = "#{@root_event_payload[:controller]}##{@root_event_payload[:action]}"
71
- @kind = HTTP_REQUEST
72
- set_http_queue_start
73
- set_metadata('path', payload[:path])
74
- set_metadata('request_format', payload[:request_format])
75
- set_metadata('request_method', payload[:request_method])
76
- set_metadata('status', payload[:status].to_s)
77
- elsif name.start_with?(Subscriber::PERFORM_JOB_PREFIX)
78
- @action = "#{@root_event_payload[:class]}##{@root_event_payload[:method]}"
79
- @kind = BACKGROUND_JOB
80
- set_background_queue_start
68
+ def set_action(action)
69
+ return unless action
70
+ Appsignal::Extension.set_transaction_action(transaction_index, action)
71
+ end
72
+
73
+ def set_http_or_background_action(from=request.params)
74
+ return unless from
75
+ group_and_action = [
76
+ from[:controller] || from[:class],
77
+ from[:action] || from[:method]
78
+ ]
79
+ set_action(group_and_action.compact.join('#'))
80
+ end
81
+
82
+ def set_queue_start(start)
83
+ return unless start
84
+ Appsignal::Extension.set_transaction_queue_start(transaction_index, start)
85
+ end
86
+
87
+ def set_http_or_background_queue_start
88
+ if namespace == HTTP_REQUEST
89
+ set_queue_start(http_queue_start)
90
+ elsif namespace == BACKGROUND_JOB
91
+ set_queue_start(background_queue_start)
81
92
  end
82
- Appsignal::Extension.set_transaction_base_data(
83
- transaction_index,
84
- kind,
85
- action,
86
- queue_start
87
- )
88
93
  end
89
94
 
90
95
  def set_metadata(key, value)
91
- return unless value
96
+ return unless key && value
92
97
  Appsignal::Extension.set_transaction_metadata(transaction_index, key, value)
93
98
  end
94
99
 
95
100
  def set_error(error)
96
101
  return unless error
97
- Appsignal.logger.debug("Adding #{error.class.name} to transaction: #{request_id}")
102
+ return if Appsignal.is_ignored_error?(error)
103
+
104
+ Appsignal.logger.debug("Adding #{error.class.name} to transaction: #{transaction_id}")
98
105
  Appsignal::Extension.set_transaction_error(
99
106
  transaction_index,
100
107
  error.class.name,
@@ -122,59 +129,64 @@ module Appsignal
122
129
  end
123
130
  alias_method :add_exception, :set_error
124
131
 
125
- def pause!
126
- @paused = true
127
- end
132
+ class GenericRequest
133
+ attr_reader :env
128
134
 
129
- def resume!
130
- @paused = false
131
- end
135
+ def initialize(env)
136
+ @env = env
137
+ end
132
138
 
133
- def paused?
134
- @paused == true
139
+ def params
140
+ env[:params]
141
+ end
135
142
  end
136
143
 
137
144
  protected
138
145
 
139
- def set_background_queue_start
140
- return unless root_event_payload
141
- queue_start = root_event_payload[:queue_start]
146
+ def background_queue_start
147
+ return unless request.env
148
+ queue_start = request.env[:queue_start]
142
149
  return unless queue_start
143
- @queue_start = (queue_start.to_f * 1000.0).to_i
150
+ (queue_start.to_f * 1000.0).to_i
151
+ end
152
+
153
+ def http_queue_start
154
+ return unless request.env
155
+ return unless env_var = request.env['HTTP_X_QUEUE_START'.freeze] || request.env['HTTP_X_REQUEST_START'.freeze]
156
+ cleaned_value = env_var.tr('^0-9'.freeze, ''.freeze)
157
+ return if cleaned_value.empty?
158
+ value = cleaned_value.to_i
159
+ [1_000_000.0, 1_000.0].each do |factor|
160
+ queue_start = (value / factor).to_i
161
+ return queue_start if queue_start > 946_681_200 # Ok if it's later than 2000
162
+ end
163
+ nil
144
164
  end
145
165
 
146
166
  def sanitized_params
147
- return unless root_event_payload
148
- Appsignal::ParamsSanitizer.sanitize(root_event_payload[:params])
149
- end
150
-
151
- def set_http_queue_start
152
- return unless env
153
- env_var = env['HTTP_X_QUEUE_START'] || env['HTTP_X_REQUEST_START']
154
- if env_var
155
- cleaned_value = env_var.tr('^0-9', '')
156
- unless cleaned_value.empty?
157
- value = cleaned_value.to_i
158
- [1_000_000.0, 1_000.0].each do |factor|
159
- @queue_start = (value / factor).to_i
160
- break if @queue_start > 946_681_200.0 # Ok if it's later than 2000
161
- end
162
- end
167
+ return unless Appsignal.config[:send_params]
168
+ return unless request.respond_to?(options[:params_method])
169
+ return unless params = request.send(options[:params_method])
170
+ if params.is_a?(Hash)
171
+ Appsignal::ParamsSanitizer.sanitize(params)
172
+ elsif params.is_a?(Array)
173
+ params
163
174
  end
164
175
  end
165
176
 
166
177
  def sanitized_environment
167
- return unless env
178
+ return unless request.env
168
179
  {}.tap do |out|
169
180
  ENV_METHODS.each do |key|
170
- out[key] = env[key] if env[key]
181
+ out[key] = request.env[key] if request.env[key]
171
182
  end
172
183
  end
173
184
  end
174
185
 
175
186
  def sanitized_session_data
176
- return if Appsignal.config[:skip_session_data] || !env
177
- Appsignal::ParamsSanitizer.sanitize(request.session.to_hash)
187
+ return if Appsignal.config[:skip_session_data] || !request.respond_to?(:session)
188
+ return unless session = request.session
189
+ Appsignal::ParamsSanitizer.sanitize(session.to_hash)
178
190
  end
179
191
 
180
192
  # Only keep tags if they meet the following criteria:
@@ -189,12 +201,11 @@ module Appsignal
189
201
  end
190
202
 
191
203
  def cleaned_backtrace(backtrace)
192
- if defined?(::Rails)
204
+ if defined?(::Rails) && backtrace
193
205
  ::Rails.backtrace_cleaner.clean(backtrace, nil)
194
206
  else
195
207
  backtrace
196
208
  end
197
209
  end
198
-
199
210
  end
200
211
  end