appsignal 2.1.0.alpha.3 → 2.1.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (133) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +43 -0
  4. data/.rubocop_todo.yml +289 -0
  5. data/.travis.yml +4 -0
  6. data/CHANGELOG.md +11 -1
  7. data/Gemfile +1 -1
  8. data/LICENSE +1 -1
  9. data/appsignal.gemspec +1 -0
  10. data/bin/appsignal +2 -2
  11. data/ext/agent.yml +11 -11
  12. data/ext/extconf.rb +33 -33
  13. data/gemfiles/rails-4.2.gemfile +4 -0
  14. data/gemfiles/resque.gemfile +4 -0
  15. data/lib/appsignal.rb +58 -54
  16. data/lib/appsignal/auth_check.rb +15 -16
  17. data/lib/appsignal/capistrano.rb +4 -4
  18. data/lib/appsignal/cli.rb +28 -28
  19. data/lib/appsignal/cli/diagnose.rb +11 -11
  20. data/lib/appsignal/cli/helpers.rb +1 -1
  21. data/lib/appsignal/cli/install.rb +38 -38
  22. data/lib/appsignal/cli/notify_of_deploy.rb +1 -1
  23. data/lib/appsignal/config.rb +73 -71
  24. data/lib/appsignal/event_formatter.rb +8 -8
  25. data/lib/appsignal/event_formatter/action_view/render_formatter.rb +4 -4
  26. data/lib/appsignal/event_formatter/active_record/instantiation_formatter.rb +1 -1
  27. data/lib/appsignal/event_formatter/active_record/sql_formatter.rb +1 -1
  28. data/lib/appsignal/event_formatter/elastic_search/search_formatter.rb +9 -7
  29. data/lib/appsignal/event_formatter/faraday/request_formatter.rb +1 -1
  30. data/lib/appsignal/event_formatter/mongo_ruby_driver/query_formatter.rb +6 -6
  31. data/lib/appsignal/event_formatter/moped/query_formatter.rb +56 -43
  32. data/lib/appsignal/extension.rb +5 -5
  33. data/lib/appsignal/hooks.rb +28 -26
  34. data/lib/appsignal/hooks/active_support_notifications.rb +2 -2
  35. data/lib/appsignal/hooks/celluloid.rb +1 -1
  36. data/lib/appsignal/hooks/data_mapper.rb +2 -2
  37. data/lib/appsignal/hooks/delayed_job.rb +1 -1
  38. data/lib/appsignal/hooks/mongo_ruby_driver.rb +1 -1
  39. data/lib/appsignal/hooks/net_http.rb +4 -4
  40. data/lib/appsignal/hooks/passenger.rb +2 -2
  41. data/lib/appsignal/hooks/puma.rb +4 -4
  42. data/lib/appsignal/hooks/rake.rb +1 -1
  43. data/lib/appsignal/hooks/redis.rb +1 -1
  44. data/lib/appsignal/hooks/sequel.rb +2 -2
  45. data/lib/appsignal/hooks/shoryuken.rb +8 -8
  46. data/lib/appsignal/hooks/sidekiq.rb +16 -15
  47. data/lib/appsignal/hooks/unicorn.rb +1 -1
  48. data/lib/appsignal/hooks/webmachine.rb +1 -1
  49. data/lib/appsignal/integrations/capistrano/capistrano_2_tasks.rb +6 -6
  50. data/lib/appsignal/integrations/data_mapper.rb +2 -3
  51. data/lib/appsignal/integrations/delayed_job_plugin.rb +5 -5
  52. data/lib/appsignal/integrations/mongo_ruby_driver.rb +6 -6
  53. data/lib/appsignal/integrations/padrino.rb +8 -8
  54. data/lib/appsignal/integrations/railtie.rb +5 -5
  55. data/lib/appsignal/integrations/resque.rb +4 -5
  56. data/lib/appsignal/integrations/resque_active_job.rb +3 -6
  57. data/lib/appsignal/integrations/sinatra.rb +2 -2
  58. data/lib/appsignal/integrations/webmachine.rb +2 -3
  59. data/lib/appsignal/js_exception_transaction.rb +10 -10
  60. data/lib/appsignal/marker.rb +3 -3
  61. data/lib/appsignal/rack/generic_instrumentation.rb +10 -9
  62. data/lib/appsignal/rack/js_exception_catcher.rb +7 -6
  63. data/lib/appsignal/rack/rails_instrumentation.rb +9 -8
  64. data/lib/appsignal/rack/sinatra_instrumentation.rb +19 -17
  65. data/lib/appsignal/rack/streaming_listener.rb +9 -8
  66. data/lib/appsignal/system.rb +19 -17
  67. data/lib/appsignal/transaction.rb +97 -40
  68. data/lib/appsignal/transmitter.rb +23 -30
  69. data/lib/appsignal/utils.rb +3 -3
  70. data/lib/appsignal/utils/params_sanitizer.rb +1 -1
  71. data/lib/appsignal/utils/query_params_sanitizer.rb +1 -1
  72. data/lib/appsignal/version.rb +2 -2
  73. data/spec/.rubocop.yml +4 -0
  74. data/spec/lib/appsignal/auth_check_spec.rb +7 -7
  75. data/spec/lib/appsignal/capistrano2_spec.rb +41 -41
  76. data/spec/lib/appsignal/capistrano3_spec.rb +43 -44
  77. data/spec/lib/appsignal/cli/notify_of_deploy_spec.rb +9 -11
  78. data/spec/lib/appsignal/cli_spec.rb +9 -9
  79. data/spec/lib/appsignal/config_spec.rb +88 -86
  80. data/spec/lib/appsignal/event_formatter/action_view/render_formatter_spec.rb +9 -9
  81. data/spec/lib/appsignal/event_formatter/active_record/instantiation_formatter_spec.rb +4 -4
  82. data/spec/lib/appsignal/event_formatter/active_record/sql_formatter_spec.rb +4 -4
  83. data/spec/lib/appsignal/event_formatter/elastic_search/search_formatter_spec.rb +12 -12
  84. data/spec/lib/appsignal/event_formatter/faraday/request_formatter_spec.rb +4 -4
  85. data/spec/lib/appsignal/event_formatter/mongo_ruby_driver/query_formatter_spec.rb +23 -23
  86. data/spec/lib/appsignal/event_formatter/moped/query_formatter_spec.rb +29 -30
  87. data/spec/lib/appsignal/event_formatter_spec.rb +28 -28
  88. data/spec/lib/appsignal/extension_spec.rb +15 -15
  89. data/spec/lib/appsignal/garbage_collection_profiler_spec.rb +6 -5
  90. data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +12 -12
  91. data/spec/lib/appsignal/hooks/delayed_job_spec.rb +34 -34
  92. data/spec/lib/appsignal/hooks/mongo_ruby_driver_spec.rb +3 -3
  93. data/spec/lib/appsignal/hooks/net_http_spec.rb +10 -10
  94. data/spec/lib/appsignal/hooks/rake_spec.rb +7 -7
  95. data/spec/lib/appsignal/hooks/redis_spec.rb +6 -6
  96. data/spec/lib/appsignal/hooks/shoryuken_spec.rb +21 -22
  97. data/spec/lib/appsignal/hooks/sidekiq_spec.rb +48 -45
  98. data/spec/lib/appsignal/hooks/webmachine_spec.rb +2 -2
  99. data/spec/lib/appsignal/hooks_spec.rb +16 -17
  100. data/spec/lib/appsignal/integrations/data_mapper_spec.rb +7 -8
  101. data/spec/lib/appsignal/integrations/mongo_ruby_driver_spec.rb +19 -19
  102. data/spec/lib/appsignal/integrations/object_spec.rb +3 -3
  103. data/spec/lib/appsignal/integrations/padrino_spec.rb +44 -44
  104. data/spec/lib/appsignal/integrations/railtie_spec.rb +13 -13
  105. data/spec/lib/appsignal/integrations/resque_active_job_spec.rb +7 -7
  106. data/spec/lib/appsignal/integrations/resque_spec.rb +8 -8
  107. data/spec/lib/appsignal/integrations/sinatra_spec.rb +7 -7
  108. data/spec/lib/appsignal/integrations/webmachine_spec.rb +15 -15
  109. data/spec/lib/appsignal/js_exception_transaction_spec.rb +23 -23
  110. data/spec/lib/appsignal/marker_spec.rb +8 -8
  111. data/spec/lib/appsignal/minutely_spec.rb +6 -6
  112. data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +7 -7
  113. data/spec/lib/appsignal/rack/js_exception_catcher_spec.rb +13 -13
  114. data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +11 -11
  115. data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +21 -21
  116. data/spec/lib/appsignal/rack/streaming_listener_spec.rb +36 -36
  117. data/spec/lib/appsignal/system/container_spec.rb +1 -1
  118. data/spec/lib/appsignal/transaction_spec.rb +213 -184
  119. data/spec/lib/appsignal/transmitter_spec.rb +20 -20
  120. data/spec/lib/appsignal/utils/params_sanitizer_spec.rb +19 -19
  121. data/spec/lib/appsignal/utils/query_params_sanitizer_spec.rb +41 -41
  122. data/spec/lib/appsignal/utils_spec.rb +41 -37
  123. data/spec/lib/appsignal_spec.rb +150 -142
  124. data/spec/spec_helper.rb +18 -18
  125. data/spec/support/delegate_matcher.rb +6 -6
  126. data/spec/support/helpers/api_request_helper.rb +2 -2
  127. data/spec/support/helpers/config_helpers.rb +3 -3
  128. data/spec/support/helpers/dependency_helper.rb +13 -13
  129. data/spec/support/helpers/directory_helper.rb +5 -5
  130. data/spec/support/helpers/env_helpers.rb +14 -14
  131. data/spec/support/helpers/system_helpers.rb +3 -3
  132. data/spec/support/helpers/transaction_helpers.rb +10 -10
  133. metadata +20 -2
@@ -1,18 +1,17 @@
1
1
  module Appsignal::Integrations
2
2
  module WebmachinePlugin
3
3
  module FSM
4
-
5
4
  def run_with_appsignal
6
5
  transaction = Appsignal::Transaction.create(
7
6
  SecureRandom.uuid,
8
7
  Appsignal::Transaction::HTTP_REQUEST,
9
8
  request,
10
- {:params_method => :query}
9
+ :params_method => :query
11
10
  )
12
11
 
13
12
  transaction.set_action("#{resource.class.name}##{request.method}")
14
13
 
15
- Appsignal.instrument('process_action.webmachine') do
14
+ Appsignal.instrument("process_action.webmachine") do
16
15
  run_without_appsignal
17
16
  end
18
17
 
@@ -14,29 +14,29 @@ module Appsignal
14
14
  end
15
15
 
16
16
  def set_action
17
- @ext.set_action(@data['action']) if @data['action']
17
+ @ext.set_action(@data["action"]) if @data["action"]
18
18
  end
19
19
 
20
20
  def set_metadata
21
21
  @ext.set_metadata(
22
- 'path', @data['path']
23
- ) if @data['path']
22
+ "path", @data["path"]
23
+ ) if @data["path"]
24
24
  end
25
25
 
26
26
  def set_error
27
27
  @ext.set_error(
28
- @data['name'],
29
- @data['message'] || '',
30
- Appsignal::Utils.data_generate(@data['backtrace'] || [])
28
+ @data["name"],
29
+ @data["message"] || "",
30
+ Appsignal::Utils.data_generate(@data["backtrace"] || [])
31
31
  )
32
32
  end
33
33
 
34
34
  def set_sample_data
35
35
  {
36
- :params => @data['params'],
37
- :session_data => @data['session_data'],
38
- :environment => @data['environment'],
39
- :tags => @data['tags']
36
+ :params => @data["params"],
37
+ :session_data => @data["session_data"],
38
+ :environment => @data["environment"],
39
+ :tags => @data["tags"]
40
40
  }.each do |key, data|
41
41
  next unless data.is_a?(Array) || data.is_a?(Hash)
42
42
  @ext.set_sample_data(
@@ -1,7 +1,7 @@
1
1
  module Appsignal
2
2
  class Marker
3
3
  attr_reader :marker_data, :config
4
- ACTION = 'markers'
4
+ ACTION = "markers"
5
5
 
6
6
  def initialize(marker_data, config)
7
7
  @marker_data = marker_data
@@ -14,8 +14,8 @@ module Appsignal
14
14
  "revision: #{marker_data[:revision]}, user: #{marker_data[:user]}"
15
15
 
16
16
  result = transmitter.transmit(marker_data)
17
- if result == '200'
18
- puts 'AppSignal has been notified of this deploy!'
17
+ if result == "200"
18
+ puts "AppSignal has been notified of this deploy!"
19
19
  else
20
20
  raise "#{result} at #{transmitter.uri}"
21
21
  end
@@ -1,11 +1,12 @@
1
- require 'rack'
1
+ require "rack"
2
2
 
3
3
  module Appsignal
4
4
  module Rack
5
5
  class GenericInstrumentation
6
6
  def initialize(app, options = {})
7
- Appsignal.logger.debug 'Initializing Appsignal::Rack::GenericInstrumentation'
8
- @app, @options = app, options
7
+ Appsignal.logger.debug "Initializing Appsignal::Rack::GenericInstrumentation"
8
+ @app = app
9
+ @options = options
9
10
  end
10
11
 
11
12
  def call(env)
@@ -24,20 +25,20 @@ module Appsignal
24
25
  request
25
26
  )
26
27
  begin
27
- Appsignal.instrument('process_action.generic') do
28
+ Appsignal.instrument("process_action.generic") do
28
29
  @app.call(env)
29
30
  end
30
31
  rescue => error
31
32
  transaction.set_error(error)
32
33
  raise error
33
34
  ensure
34
- if env['appsignal.route']
35
- transaction.set_action(env['appsignal.route'])
35
+ if env["appsignal.route"]
36
+ transaction.set_action(env["appsignal.route"])
36
37
  else
37
- transaction.set_action('unknown')
38
+ transaction.set_action("unknown")
38
39
  end
39
- transaction.set_metadata('path', request.path)
40
- transaction.set_metadata('method', request.request_method)
40
+ transaction.set_metadata("path", request.path)
41
+ transaction.set_metadata("method", request.request_method)
41
42
  transaction.set_http_or_background_queue_start
42
43
  Appsignal::Transaction.complete_current!
43
44
  end
@@ -2,15 +2,16 @@ module Appsignal
2
2
  module Rack
3
3
  class JSExceptionCatcher
4
4
  def initialize(app, options = {})
5
- Appsignal.logger.debug 'Initializing Appsignal::Rack::JSExceptionCatcher'
6
- @app, @options = app, options
5
+ Appsignal.logger.debug "Initializing Appsignal::Rack::JSExceptionCatcher"
6
+ @app = app
7
+ @options = options
7
8
  end
8
9
 
9
10
  def call(env)
10
- if env['PATH_INFO'] == Appsignal.config[:frontend_error_catching_path]
11
- body = JSON.parse(env['rack.input'].read)
11
+ if env["PATH_INFO"] == Appsignal.config[:frontend_error_catching_path]
12
+ body = JSON.parse(env["rack.input"].read)
12
13
 
13
- if body['name'].is_a?(String) && body['name'].length > 0
14
+ if body["name"].is_a?(String) && !body["name"].empty?
14
15
  transaction = JSExceptionTransaction.new(body)
15
16
  transaction.complete!
16
17
  code = 200
@@ -19,7 +20,7 @@ module Appsignal
19
20
  code = 422
20
21
  end
21
22
 
22
- return [code, {}, []]
23
+ [code, {}, []]
23
24
  else
24
25
  @app.call(env)
25
26
  end
@@ -1,11 +1,12 @@
1
- require 'rack'
1
+ require "rack"
2
2
 
3
3
  module Appsignal
4
4
  module Rack
5
5
  class RailsInstrumentation
6
6
  def initialize(app, options = {})
7
- Appsignal.logger.debug 'Initializing Appsignal::Rack::RailsInstrumentation'
8
- @app, @options = app, options
7
+ Appsignal.logger.debug "Initializing Appsignal::Rack::RailsInstrumentation"
8
+ @app = app
9
+ @options = options
9
10
  end
10
11
 
11
12
  def call(env)
@@ -30,19 +31,19 @@ module Appsignal
30
31
  transaction.set_error(error)
31
32
  raise error
32
33
  ensure
33
- controller = env['action_controller.instance']
34
+ controller = env["action_controller.instance"]
34
35
  if controller
35
- transaction.set_action("#{controller.class.to_s}##{controller.action_name}")
36
+ transaction.set_action("#{controller.class}##{controller.action_name}")
36
37
  end
37
38
  transaction.set_http_or_background_queue_start
38
- transaction.set_metadata('path', request.path)
39
- transaction.set_metadata('method', request.request_method)
39
+ transaction.set_metadata("path", request.path)
40
+ transaction.set_metadata("method", request.request_method)
40
41
  Appsignal::Transaction.complete_current!
41
42
  end
42
43
  end
43
44
 
44
45
  def request_id(env)
45
- env['action_dispatch.request_id'] || SecureRandom.uuid
46
+ env["action_dispatch.request_id"] || SecureRandom.uuid
46
47
  end
47
48
  end
48
49
  end
@@ -1,4 +1,4 @@
1
- require 'rack'
1
+ require "rack"
2
2
 
3
3
  module Appsignal
4
4
  module Rack
@@ -9,9 +9,10 @@ module Appsignal
9
9
  # `use Appsignal::Rack::SinatraBaseInstrumentation` automatically.
10
10
  class SinatraInstrumentation
11
11
  def initialize(app, options = {})
12
- @app, @options = app, options
13
- Appsignal.logger.warn 'Please remove Appsignal::Rack::SinatraInstrumentation '\
14
- 'from your Sinatra::Base class. This is no longer needed.'
12
+ @app = app
13
+ @options = options
14
+ Appsignal.logger.warn "Please remove Appsignal::Rack::SinatraInstrumentation "\
15
+ "from your Sinatra::Base class. This is no longer needed."
15
16
  end
16
17
 
17
18
  def call(env)
@@ -27,8 +28,9 @@ module Appsignal
27
28
  attr_reader :raise_errors_on
28
29
 
29
30
  def initialize(app, options = {})
30
- Appsignal.logger.debug 'Initializing Appsignal::Rack::SinatraInstrumentation'
31
- @app, @options = app, options
31
+ Appsignal.logger.debug "Initializing Appsignal::Rack::SinatraInstrumentation"
32
+ @app = app
33
+ @options = options
32
34
  @raise_errors_on = raise_errors?(@app)
33
35
  end
34
36
 
@@ -49,10 +51,10 @@ module Appsignal
49
51
  SecureRandom.uuid,
50
52
  Appsignal::Transaction::HTTP_REQUEST,
51
53
  request,
52
- {:force => @options.include?(:force) && @options[:force]}
54
+ :force => @options.include?(:force) && @options[:force]
53
55
  )
54
56
  begin
55
- Appsignal.instrument('process_action.sinatra') do
57
+ Appsignal.instrument("process_action.sinatra") do
56
58
  @app.call(env)
57
59
  end
58
60
  rescue => error
@@ -61,25 +63,25 @@ module Appsignal
61
63
  ensure
62
64
  # If raise_error is off versions of Sinatra don't raise errors, but store
63
65
  # them in the sinatra.error env var.
64
- if !@raise_errors_on && env['sinatra.error'] && !env['sinatra.skip_appsignal_error']
65
- transaction.set_error(env['sinatra.error'])
66
+ if !@raise_errors_on && env["sinatra.error"] && !env["sinatra.skip_appsignal_error"]
67
+ transaction.set_error(env["sinatra.error"])
66
68
  end
67
69
  transaction.set_action(action_name(env))
68
- transaction.set_metadata('path', request.path)
69
- transaction.set_metadata('method', request.request_method)
70
+ transaction.set_metadata("path", request.path)
71
+ transaction.set_metadata("method", request.request_method)
70
72
  transaction.set_http_or_background_queue_start
71
73
  Appsignal::Transaction.complete_current!
72
74
  end
73
75
  end
74
76
 
75
77
  def action_name(env)
76
- return unless env['sinatra.route']
78
+ return unless env["sinatra.route"]
77
79
 
78
- if env['SCRIPT_NAME']
79
- method, route = env['sinatra.route'].split(" ")
80
- "#{method} #{env['SCRIPT_NAME']}#{route}"
80
+ if env["SCRIPT_NAME"]
81
+ method, route = env["sinatra.route"].split(" ")
82
+ "#{method} #{env["SCRIPT_NAME"]}#{route}"
81
83
  else
82
- env['sinatra.route']
84
+ env["sinatra.route"]
83
85
  end
84
86
  end
85
87
 
@@ -3,8 +3,9 @@ module Appsignal
3
3
  module Rack
4
4
  class StreamingListener
5
5
  def initialize(app, options = {})
6
- Appsignal.logger.debug 'Initializing Appsignal::Rack::StreamingListener'
7
- @app, @options = app, options
6
+ Appsignal.logger.debug "Initializing Appsignal::Rack::StreamingListener"
7
+ @app = app
8
+ @options = options
8
9
  end
9
10
 
10
11
  def call(env)
@@ -25,16 +26,16 @@ module Appsignal
25
26
 
26
27
  # Instrument a `process_action`, to set params/action name
27
28
  status, headers, body =
28
- Appsignal.instrument('process_action.rack') do
29
+ Appsignal.instrument("process_action.rack") do
29
30
  begin
30
31
  @app.call(env)
31
32
  rescue Exception => e
32
33
  transaction.set_error(e)
33
34
  raise e
34
35
  ensure
35
- transaction.set_action(env['appsignal.action'])
36
- transaction.set_metadata('path', request.path)
37
- transaction.set_metadata('method', request.request_method)
36
+ transaction.set_action(env["appsignal.action"])
37
+ transaction.set_metadata("path", request.path)
38
+ transaction.set_metadata("method", request.request_method)
38
39
  transaction.set_http_or_background_queue_start
39
40
  end
40
41
  end
@@ -47,8 +48,8 @@ module Appsignal
47
48
 
48
49
  class StreamWrapper
49
50
  def initialize(stream, transaction)
50
- @stream = stream
51
- @transaction = transaction
51
+ @stream = stream
52
+ @transaction = transaction
52
53
  end
53
54
 
54
55
  def each
@@ -5,31 +5,33 @@ module Appsignal
5
5
  end
6
6
 
7
7
  def self.heroku?
8
- ENV.key? 'DYNO'.freeze
8
+ ENV.key? "DYNO".freeze
9
9
  end
10
10
 
11
11
  module Container
12
- CGROUP_FILE = '/proc/self/cgroup'.freeze
12
+ CGROUP_FILE = "/proc/self/cgroup".freeze
13
13
 
14
- def self.id
15
- case cgroups
16
- when %r{docker[-|/]([0-9a-f]+)}
17
- $1
18
- when %r{lxc/([0-9a-f-]+)$} # LXC / Heroku
19
- $1
14
+ class << self
15
+ def id
16
+ case cgroups
17
+ when %r{docker[-|/]([0-9a-f]+)}
18
+ $1
19
+ when %r{lxc/([0-9a-f-]+)$} # LXC / Heroku
20
+ $1
21
+ end
20
22
  end
21
- end
22
23
 
23
- private
24
+ private
24
25
 
25
- def self.cgroups
26
- file = CGROUP_FILE
27
- return unless File.exist? file
26
+ def cgroups
27
+ file = CGROUP_FILE
28
+ return unless File.exist? file
28
29
 
29
- File.read(file)
30
- rescue SystemCallError => e
31
- Appsignal.logger.debug "Unable to read '#{file}' to determine cgroup"
32
- Appsignal.logger.debug e
30
+ File.read(file)
31
+ rescue SystemCallError => e
32
+ Appsignal.logger.debug "Unable to read '#{file}' to determine cgroup"
33
+ Appsignal.logger.debug e
34
+ end
33
35
  end
34
36
  end
35
37
  end
@@ -1,26 +1,29 @@
1
- require 'json'
1
+ require "json"
2
2
 
3
3
  module Appsignal
4
4
  class Transaction
5
- HTTP_REQUEST = 'http_request'.freeze
6
- BACKGROUND_JOB = 'background_job'.freeze
7
- FRONTEND = 'frontend'.freeze
8
- BLANK = ''.freeze
5
+ HTTP_REQUEST = "http_request".freeze
6
+ BACKGROUND_JOB = "background_job".freeze
7
+ FRONTEND = "frontend".freeze
8
+ BLANK = "".freeze
9
9
 
10
10
  # Based on what Rails uses + some variables we'd like to show
11
- ENV_METHODS = %w(CONTENT_LENGTH AUTH_TYPE GATEWAY_INTERFACE
12
- PATH_TRANSLATED REMOTE_HOST REMOTE_IDENT REMOTE_USER REMOTE_ADDR
13
- REQUEST_METHOD SERVER_NAME SERVER_PORT SERVER_PROTOCOL REQUEST_URI PATH_INFO
14
-
15
- HTTP_X_REQUEST_START HTTP_X_MIDDLEWARE_START HTTP_X_QUEUE_START
16
- HTTP_X_QUEUE_TIME HTTP_X_HEROKU_QUEUE_WAIT_TIME HTTP_X_APPLICATION_START
17
- HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_ACCEPT_ENCODING HTTP_ACCEPT_LANGUAGE
18
- HTTP_CACHE_CONTROL HTTP_CONNECTION HTTP_USER_AGENT HTTP_FROM HTTP_NEGOTIATE
19
- HTTP_PRAGMA HTTP_REFERER HTTP_X_FORWARDED_FOR HTTP_CLIENT_IP HTTP_RANGE
20
- HTTP_X_AUTH_TOKEN)
11
+ ENV_METHODS = %w(
12
+ CONTENT_LENGTH AUTH_TYPE GATEWAY_INTERFACE
13
+ PATH_TRANSLATED REMOTE_HOST REMOTE_IDENT REMOTE_USER REMOTE_ADDR
14
+ REQUEST_METHOD SERVER_NAME SERVER_PORT SERVER_PROTOCOL REQUEST_URI
15
+ PATH_INFO
16
+
17
+ HTTP_X_REQUEST_START HTTP_X_MIDDLEWARE_START HTTP_X_QUEUE_START
18
+ HTTP_X_QUEUE_TIME HTTP_X_HEROKU_QUEUE_WAIT_TIME HTTP_X_APPLICATION_START
19
+ HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_ACCEPT_ENCODING HTTP_ACCEPT_LANGUAGE
20
+ HTTP_CACHE_CONTROL HTTP_CONNECTION HTTP_USER_AGENT HTTP_FROM
21
+ HTTP_NEGOTIATE HTTP_PRAGMA HTTP_REFERER HTTP_X_FORWARDED_FOR
22
+ HTTP_CLIENT_IP HTTP_RANGE HTTP_X_AUTH_TOKEN
23
+ )
21
24
 
22
25
  class << self
23
- def create(id, namespace, request, options={})
26
+ def create(id, namespace, request, options = {})
24
27
  # Allow middleware to force a new transaction
25
28
  if options.include?(:force) && options[:force]
26
29
  Thread.current[:appsignal_transaction] = nil
@@ -58,7 +61,7 @@ module Appsignal
58
61
 
59
62
  attr_reader :ext, :transaction_id, :namespace, :request, :paused, :tags, :options, :discarded
60
63
 
61
- def initialize(transaction_id, namespace, request, options={})
64
+ def initialize(transaction_id, namespace, request, options = {})
62
65
  @transaction_id = transaction_id
63
66
  @namespace = namespace
64
67
  @request = request
@@ -82,7 +85,7 @@ module Appsignal
82
85
 
83
86
  def complete
84
87
  if discarded?
85
- Appsignal.logger.debug('Skipping transaction because it was manually discarded.'.freeze)
88
+ Appsignal.logger.debug("Skipping transaction because it was manually discarded.".freeze)
86
89
  return
87
90
  end
88
91
  if @ext.finish(self.class.garbage_collection_profiler.total_time)
@@ -119,7 +122,7 @@ module Appsignal
119
122
  @store[key]
120
123
  end
121
124
 
122
- def set_tags(given_tags={})
125
+ def set_tags(given_tags = {})
123
126
  @tags.merge!(given_tags)
124
127
  end
125
128
 
@@ -128,13 +131,13 @@ module Appsignal
128
131
  @ext.set_action(action)
129
132
  end
130
133
 
131
- def set_http_or_background_action(from=request.params)
134
+ def set_http_or_background_action(from = request.params)
132
135
  return unless from
133
136
  group_and_action = [
134
137
  from[:controller] || from[:class],
135
138
  from[:action] || from[:method]
136
139
  ]
137
- set_action(group_and_action.compact.join('#'))
140
+ set_action(group_and_action.compact.join("#"))
138
141
  end
139
142
 
140
143
  def set_queue_start(start)
@@ -182,7 +185,6 @@ module Appsignal
182
185
  def set_error(error)
183
186
  return unless error
184
187
  return unless Appsignal.active?
185
- return if Appsignal.is_ignored_error?(error)
186
188
 
187
189
  backtrace = cleaned_backtrace(error.backtrace)
188
190
  @ext.set_error(
@@ -197,7 +199,7 @@ module Appsignal
197
199
  @ext.start_event(self.class.garbage_collection_profiler.total_time)
198
200
  end
199
201
 
200
- def finish_event(name, title, body, body_format=Appsignal::EventFormatter::DEFAULT)
202
+ def finish_event(name, title, body, body_format = Appsignal::EventFormatter::DEFAULT)
201
203
  @ext.finish_event(
202
204
  name,
203
205
  title || BLANK,
@@ -207,7 +209,7 @@ module Appsignal
207
209
  )
208
210
  end
209
211
 
210
- def record_event(name, title, body, duration, body_format=Appsignal::EventFormatter::DEFAULT)
212
+ def record_event(name, title, body, duration, body_format = Appsignal::EventFormatter::DEFAULT)
211
213
  @ext.record_event(
212
214
  name,
213
215
  title || BLANK,
@@ -217,7 +219,7 @@ module Appsignal
217
219
  )
218
220
  end
219
221
 
220
- def instrument(name, title=nil, body=nil, body_format=Appsignal::EventFormatter::DEFAULT)
222
+ def instrument(name, title = nil, body = nil, body_format = Appsignal::EventFormatter::DEFAULT)
221
223
  start_event
222
224
  r = yield
223
225
  finish_event(name, title, body, body_format)
@@ -238,23 +240,40 @@ module Appsignal
238
240
 
239
241
  protected
240
242
 
243
+ # Returns calculated background queue start time in milliseconds, based on
244
+ # environment values.
245
+ #
246
+ # @return [nil] if no {#environment} is present.
247
+ # @return [nil] if there is no `:queue_start` in the {#environment}.
248
+ # @return [Integer]
241
249
  def background_queue_start
242
- return unless request.env
243
- return unless queue_start = request.env[:queue_start]
250
+ env = environment
251
+ return unless env
252
+ queue_start = env[:queue_start]
253
+ return unless queue_start
254
+
244
255
  (queue_start.to_f * 1000.0).to_i
245
256
  end
246
257
 
258
+ # Returns HTTP queue start time in milliseconds.
259
+ #
260
+ # @return [nil] if no queue start time is found.
261
+ # @return [nil] if begin time is too low to be plausible.
262
+ # @return [Integer] queue start in milliseconds.
247
263
  def http_queue_start
248
- return unless request.env
249
- return unless env_var = request.env['HTTP_X_QUEUE_START'.freeze] || request.env['HTTP_X_REQUEST_START'.freeze]
250
- cleaned_value = env_var.tr('^0-9'.freeze, ''.freeze)
264
+ env = environment
265
+ return unless env
266
+ env_var = env["HTTP_X_QUEUE_START".freeze] || env["HTTP_X_REQUEST_START".freeze]
267
+ return unless env_var
268
+ cleaned_value = env_var.tr("^0-9".freeze, "".freeze)
251
269
  return if cleaned_value.empty?
270
+
252
271
  value = cleaned_value.to_i
253
272
  if value > 4_102_441_200_000
254
- # Value is in microseconds
273
+ # Value is in microseconds. Transform to milliseconds.
255
274
  value / 1_000
256
275
  elsif value < 946_681_200_000
257
- # Value is to low to be plausible
276
+ # Value is too low to be plausible
258
277
  nil
259
278
  else
260
279
  # Value is in milliseconds
@@ -283,24 +302,62 @@ module Appsignal
283
302
  Appsignal::Utils::ParamsSanitizer.sanitize params, options
284
303
  end
285
304
 
305
+ # Returns sanitized environment for a transaction.
306
+ #
307
+ # The environment of a transaction can contain a lot of information, not
308
+ # all of it useful for debugging.
309
+ #
310
+ # Only the values from the keys specified in `ENV_METHODS` are returned.
311
+ #
312
+ # @return [nil] if no environment is present.
313
+ # @return [Hash<String, Object>]
286
314
  def sanitized_environment
287
- return unless request.env
315
+ env = environment
316
+ return if env.empty?
317
+
288
318
  {}.tap do |out|
289
319
  ENV_METHODS.each do |key|
290
- out[key] = request.env[key] if request.env[key]
320
+ out[key] = env[key] if env[key]
291
321
  end
292
322
  end
293
323
  end
294
324
 
325
+ # Returns sanitized session data.
326
+ #
327
+ # The session data is sanitized by the {Appsignal::Utils::ParamsSanitizer}.
328
+ #
329
+ # @return [nil] if `:skip_session_data` config is set to `true`.
330
+ # @return [nil] if the {#request} object doesn't respond to `#session`.
331
+ # @return [nil] if the {#request} session data is `nil`.
332
+ # @return [Hash<String, Object>]
295
333
  def sanitized_session_data
296
- return if Appsignal.config[:skip_session_data] || !request.respond_to?(:session)
297
- return unless session = request.session
334
+ return if Appsignal.config[:skip_session_data] ||
335
+ !request.respond_to?(:session)
336
+ session = request.session
337
+ return unless session
338
+
298
339
  Appsignal::Utils::ParamsSanitizer.sanitize(session.to_hash)
299
340
  end
300
341
 
342
+ # Returns metadata from the environment.
343
+ #
344
+ # @return [nil] if no `:metadata` key is present in the {#environment}.
345
+ # @return [Hash<String, Object>]
301
346
  def metadata
302
- return unless request.env
303
- request.env[:metadata]
347
+ environment[:metadata]
348
+ end
349
+
350
+ # Returns the environment for a transaction.
351
+ #
352
+ # Returns an empty Hash when the {#request} object doesn't listen to the
353
+ # `#env` method or the `#env` is nil.
354
+ #
355
+ # @return [Hash<String, Object>]
356
+ def environment
357
+ return {} unless request.respond_to?(:env)
358
+ return {} unless request.env
359
+
360
+ request.env
304
361
  end
305
362
 
306
363
  # Only keep tags if they meet the following criteria:
@@ -310,7 +367,7 @@ module Appsignal
310
367
  def sanitized_tags
311
368
  @tags.select do |k, v|
312
369
  (k.is_a?(Symbol) || k.is_a?(String) && k.length <= 100) &&
313
- (((v.is_a?(Symbol) || v.is_a?(String)) && v.length <= 100) || (v.is_a?(Integer)))
370
+ (((v.is_a?(Symbol) || v.is_a?(String)) && v.length <= 100) || v.is_a?(Integer))
314
371
  end
315
372
  end
316
373
 
@@ -329,7 +386,7 @@ module Appsignal
329
386
  end
330
387
 
331
388
  # Instrument should still yield
332
- def instrument(*args)
389
+ def instrument(*_args)
333
390
  yield
334
391
  end
335
392