appsignal 0.11.18 → 0.12.beta.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. data/.gitignore +6 -0
  2. data/CHANGELOG.md +4 -38
  3. data/Rakefile +14 -6
  4. data/appsignal.gemspec +3 -1
  5. data/benchmark.rake +12 -16
  6. data/ext/appsignal_extension.c +183 -0
  7. data/ext/extconf.rb +39 -0
  8. data/gemfiles/capistrano2.gemfile +0 -1
  9. data/gemfiles/capistrano3.gemfile +0 -1
  10. data/gemfiles/rails-4.2.gemfile +1 -1
  11. data/lib/appsignal.rb +23 -61
  12. data/lib/appsignal/capistrano.rb +1 -2
  13. data/lib/appsignal/config.rb +13 -1
  14. data/lib/appsignal/event_formatter.rb +67 -0
  15. data/lib/appsignal/event_formatter/action_view/render_formatter.rb +23 -0
  16. data/lib/appsignal/event_formatter/active_record/sql_formatter.rb +74 -0
  17. data/lib/appsignal/event_formatter/moped/query_formatter.rb +80 -0
  18. data/lib/appsignal/event_formatter/net_http/request_formatter.rb +13 -0
  19. data/lib/appsignal/instrumentations/net_http.rb +6 -4
  20. data/lib/appsignal/integrations/resque.rb +2 -10
  21. data/lib/appsignal/integrations/sidekiq.rb +2 -2
  22. data/lib/appsignal/integrations/sinatra.rb +1 -0
  23. data/lib/appsignal/js_exception_transaction.rb +44 -28
  24. data/lib/appsignal/marker.rb +11 -13
  25. data/lib/appsignal/params_sanitizer.rb +5 -8
  26. data/lib/appsignal/rack/instrumentation.rb +2 -0
  27. data/lib/appsignal/rack/js_exception_catcher.rb +1 -0
  28. data/lib/appsignal/rack/listener.rb +1 -1
  29. data/lib/appsignal/rack/sinatra_instrumentation.rb +2 -12
  30. data/lib/appsignal/subscriber.rb +59 -0
  31. data/lib/appsignal/transaction.rb +117 -174
  32. data/lib/appsignal/transmitter.rb +8 -37
  33. data/lib/appsignal/version.rb +2 -1
  34. data/spec/lib/appsignal/config_spec.rb +25 -4
  35. data/spec/lib/appsignal/event_formatter/action_view/render_formatter_spec.rb +42 -0
  36. data/spec/lib/appsignal/{aggregator/middleware/active_record_sanitizer_spec.rb → event_formatter/active_record/sql_formatter_spec.rb} +61 -61
  37. data/spec/lib/appsignal/{event/moped_event_spec.rb → event_formatter/moped/query_formatter_spec.rb} +32 -78
  38. data/spec/lib/appsignal/event_formatter/net_http/request_formatter_spec.rb +26 -0
  39. data/spec/lib/appsignal/event_formatter_spec.rb +102 -0
  40. data/spec/lib/appsignal/extension_spec.rb +75 -0
  41. data/spec/lib/appsignal/instrumentations/net_http_spec.rb +20 -4
  42. data/spec/lib/appsignal/integrations/delayed_job_spec.rb +3 -2
  43. data/spec/lib/appsignal/integrations/rails_spec.rb +0 -7
  44. data/spec/lib/appsignal/integrations/resque_spec.rb +51 -55
  45. data/spec/lib/appsignal/integrations/sequel_spec.rb +8 -3
  46. data/spec/lib/appsignal/integrations/sidekiq_spec.rb +4 -21
  47. data/spec/lib/appsignal/integrations/sinatra_spec.rb +0 -6
  48. data/spec/lib/appsignal/js_exception_transaction_spec.rb +57 -60
  49. data/spec/lib/appsignal/params_sanitizer_spec.rb +11 -27
  50. data/spec/lib/appsignal/rack/listener_spec.rb +6 -6
  51. data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +2 -43
  52. data/spec/lib/appsignal/subscriber_spec.rb +162 -0
  53. data/spec/lib/appsignal/transaction_spec.rb +283 -615
  54. data/spec/lib/appsignal/transmitter_spec.rb +3 -32
  55. data/spec/lib/appsignal_spec.rb +41 -90
  56. data/spec/lib/generators/appsignal/appsignal_generator_spec.rb +0 -17
  57. data/spec/spec_helper.rb +18 -22
  58. data/spec/support/helpers/notification_helpers.rb +1 -1
  59. data/spec/support/helpers/time_helpers.rb +11 -0
  60. data/spec/support/helpers/transaction_helpers.rb +6 -18
  61. data/spec/support/project_fixture/config/appsignal.yml +1 -2
  62. metadata +68 -78
  63. checksums.yaml +0 -7
  64. data/gemfiles/padrino-0.13.gemfile +0 -7
  65. data/gemfiles/resque.gemfile +0 -5
  66. data/lib/appsignal/agent.rb +0 -217
  67. data/lib/appsignal/aggregator.rb +0 -67
  68. data/lib/appsignal/aggregator/middleware.rb +0 -4
  69. data/lib/appsignal/aggregator/middleware/action_view_sanitizer.rb +0 -23
  70. data/lib/appsignal/aggregator/middleware/active_record_sanitizer.rb +0 -65
  71. data/lib/appsignal/aggregator/middleware/chain.rb +0 -101
  72. data/lib/appsignal/aggregator/middleware/delete_blanks.rb +0 -16
  73. data/lib/appsignal/aggregator/post_processor.rb +0 -32
  74. data/lib/appsignal/event.rb +0 -20
  75. data/lib/appsignal/event/moped_event.rb +0 -90
  76. data/lib/appsignal/integrations/padrino.rb +0 -64
  77. data/lib/appsignal/integrations/passenger.rb +0 -13
  78. data/lib/appsignal/integrations/rake.rb +0 -29
  79. data/lib/appsignal/integrations/unicorn.rb +0 -25
  80. data/lib/appsignal/ipc.rb +0 -68
  81. data/lib/appsignal/transaction/formatter.rb +0 -85
  82. data/lib/appsignal/transaction/params_sanitizer.rb +0 -4
  83. data/lib/appsignal/zipped_payload.rb +0 -37
  84. data/spec/lib/appsignal/agent_spec.rb +0 -592
  85. data/spec/lib/appsignal/aggregator/middleware/action_view_sanitizer_spec.rb +0 -44
  86. data/spec/lib/appsignal/aggregator/middleware/chain_spec.rb +0 -168
  87. data/spec/lib/appsignal/aggregator/middleware/delete_blanks_spec.rb +0 -37
  88. data/spec/lib/appsignal/aggregator/post_processor_spec.rb +0 -99
  89. data/spec/lib/appsignal/aggregator_spec.rb +0 -186
  90. data/spec/lib/appsignal/event_spec.rb +0 -48
  91. data/spec/lib/appsignal/integrations/padrino_spec.rb +0 -171
  92. data/spec/lib/appsignal/integrations/passenger_spec.rb +0 -22
  93. data/spec/lib/appsignal/integrations/rake_spec.rb +0 -92
  94. data/spec/lib/appsignal/integrations/unicorn_spec.rb +0 -48
  95. data/spec/lib/appsignal/ipc_spec.rb +0 -128
  96. data/spec/lib/appsignal/transaction/formatter_spec.rb +0 -247
  97. data/spec/lib/appsignal/zipped_payload_spec.rb +0 -42
@@ -1,16 +0,0 @@
1
- module Appsignal
2
- class Aggregator
3
- module Middleware
4
- class DeleteBlanks
5
- def call(event)
6
- event.payload.each do |key, value|
7
- if value.respond_to?(:empty?) ? value.empty? : !value
8
- event.payload.delete(key)
9
- end
10
- end
11
- yield
12
- end
13
- end
14
- end
15
- end
16
- end
@@ -1,32 +0,0 @@
1
- module Appsignal
2
- class Aggregator
3
- class PostProcessor
4
- attr_reader :transactions
5
-
6
- def initialize(transactions)
7
- @transactions = transactions
8
- end
9
-
10
- def post_processed_queue!
11
- transactions.map do |transaction|
12
- transaction.events.each do |event|
13
- Appsignal.post_processing_middleware.invoke(event)
14
- end
15
- transaction.to_hash
16
- end
17
- end
18
-
19
- def self.default_middleware
20
- Middleware::Chain.new do |chain|
21
- chain.add Appsignal::Aggregator::Middleware::DeleteBlanks
22
- if defined?(::ActionView)
23
- chain.add Appsignal::Aggregator::Middleware::ActionViewSanitizer
24
- end
25
- if defined?(::ActiveRecord)
26
- chain.add Appsignal::Aggregator::Middleware::ActiveRecordSanitizer
27
- end
28
- end
29
- end
30
- end
31
- end
32
- end
@@ -1,20 +0,0 @@
1
- class Appsignal::Event < ActiveSupport::Notifications::Event
2
- def sanitize!
3
- @payload = Appsignal::ParamsSanitizer.sanitize(@payload)
4
- end
5
-
6
- def truncate!
7
- @payload = {}
8
- end
9
-
10
- def self.event_for_instrumentation(*args)
11
- case args[0]
12
- when 'query.moped'
13
- Appsignal::Event::MopedEvent.new(*args)
14
- else
15
- new(*args)
16
- end
17
- end
18
- end
19
-
20
- require 'appsignal/event/moped_event'
@@ -1,90 +0,0 @@
1
- class Appsignal::Event::MopedEvent < Appsignal::Event
2
- def initialize(name, start, ending, transaction_id, payload)
3
- super(name, start, ending, transaction_id, transform_payload(payload))
4
- end
5
-
6
- def transform_payload(payload)
7
- if payload[:ops] && payload[:ops].length > 0
8
- transformed_ops = [].tap do |arr|
9
- payload[:ops].each do |op|
10
- arr << payload_from_op(op.dup)
11
- end
12
- end
13
- payload[:ops] = transformed_ops
14
- end
15
- payload
16
- end
17
-
18
- def payload_from_op(payload)
19
- case payload.class.to_s
20
- when 'Moped::Protocol::Command'
21
- {
22
- :type => 'Command',
23
- :database => payload.full_collection_name,
24
- :selector => sanitize(payload.selector)
25
- }
26
- when 'Moped::Protocol::Query'
27
- {
28
- :type => 'Query',
29
- :database => payload.full_collection_name,
30
- :selector => sanitize(payload.selector),
31
- :flags => payload.flags,
32
- :limit => payload.limit,
33
- :skip => payload.skip,
34
- :fields => payload.fields
35
- }
36
- when 'Moped::Protocol::Delete'
37
- {
38
- :type => 'Delete',
39
- :database => payload.full_collection_name,
40
- :selector => sanitize(payload.selector),
41
- :flags => payload.flags,
42
- }
43
- when 'Moped::Protocol::Insert'
44
- {
45
- :type => 'Insert',
46
- :database => payload.full_collection_name,
47
- :documents => sanitize(payload.documents),
48
- :flags => payload.flags,
49
- }
50
- when 'Moped::Protocol::Update'
51
- {
52
- :type => 'Update',
53
- :database => payload.full_collection_name,
54
- :selector => sanitize(payload.selector),
55
- :update => sanitize(payload.update),
56
- :flags => payload.flags,
57
- }
58
- when 'Moped::Protocol::KillCursors'
59
- {
60
- :type => 'KillCursors',
61
- :number_of_cursor_ids => payload.number_of_cursor_ids
62
- }
63
- else
64
- {
65
- :type => payload.class.to_s.gsub('Moped::Protocol::', ''),
66
- :database => payload.full_collection_name
67
- }
68
- end
69
- end
70
-
71
- def sanitize(params)
72
- if params.is_a?(Hash)
73
- {}.tap do |hsh|
74
- params.each do |key, val|
75
- hsh[key] = sanitize(val)
76
- end
77
- end
78
- elsif params.is_a?(Array)
79
- if params.first.is_a?(String)
80
- ['?']
81
- else
82
- params.map do |item|
83
- sanitize(item)
84
- end
85
- end
86
- else
87
- '?'
88
- end
89
- end
90
- end
@@ -1,64 +0,0 @@
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
-
14
- if Appsignal.active?
15
- Padrino.use(Appsignal::Rack::Listener)
16
- end
17
- end
18
- end
19
- end
20
-
21
- module Padrino::Routing::InstanceMethods
22
- alias route_without_appsignal route!
23
-
24
- def route!(base = settings, pass_block = nil)
25
- if env['sinatra.static_file']
26
- route_without_appsignal(base, pass_block)
27
- else
28
- request_payload = {
29
- :params => request.params,
30
- :session => request.session,
31
- :method => request.request_method,
32
- :path => request.path
33
- }
34
- ActiveSupport::Notifications.instrument('process_action.padrino', request_payload) do |request_payload|
35
- begin
36
- route_without_appsignal(base, pass_block)
37
- rescue => e
38
- Appsignal.add_exception(e); raise e
39
- ensure
40
- request_payload[:action] = get_payload_action(request)
41
- end
42
- end
43
- end
44
- end
45
-
46
- def get_payload_action(request)
47
- # Short-circut is there's no request object to obtain information from
48
- return "#{settings.name}" if request.nil?
49
-
50
- # Older versions of Padrino work with a route object
51
- route_obj = defined?(request.route_obj) && request.route_obj
52
- if route_obj && route_obj.respond_to?(:original_path)
53
- return "#{settings.name}:#{request.route_obj.original_path}"
54
- end
55
-
56
- # Newer versions expose the action / controller on the request class
57
- request_data = request.respond_to?(:action) ? request.action : request.fullpath
58
- "#{settings.name}:#{request.controller}##{request_data}"
59
- end
60
- end
61
-
62
- Padrino.after_load do
63
- Appsignal::Integrations::PadrinoPlugin.init
64
- end
@@ -1,13 +0,0 @@
1
- if defined?(::PhusionPassenger)
2
- Appsignal.logger.info('Loading Passenger integration')
3
-
4
- ::PhusionPassenger.on_event(:starting_worker_process) do |forked|
5
- Appsignal.logger.debug('starting worker process')
6
- Appsignal.agent.forked!
7
- end
8
-
9
- ::PhusionPassenger.on_event(:stopping_worker_process) do
10
- Appsignal.logger.debug('stopping worker process')
11
- Appsignal.agent.shutdown(true, 'stopping Passenger worker process')
12
- end
13
- end
@@ -1,29 +0,0 @@
1
- module Rake
2
- class Task
3
- alias_method :invoke_without_appsignal, :invoke
4
-
5
- def invoke(*args)
6
- invoke_with_appsignal(*args)
7
- end
8
-
9
- def invoke_with_appsignal(*args)
10
- transaction = Appsignal::Transaction.create(
11
- SecureRandom.uuid,
12
- ENV,
13
- :kind => 'background_job',
14
- :action => name,
15
- :params => args
16
- )
17
-
18
- invoke_without_appsignal(*args)
19
- rescue => exception
20
- unless Appsignal.is_ignored_exception?(exception)
21
- transaction.add_exception(exception)
22
- end
23
- raise exception
24
- ensure
25
- transaction.complete!
26
- Appsignal.agent.send_queue if Appsignal.active?
27
- end
28
- end
29
- end
@@ -1,25 +0,0 @@
1
- if defined?(::Unicorn)
2
- Appsignal.logger.info('Loading Unicorn integration')
3
-
4
- # We'd love to be able to hook this into Unicorn in a less
5
- # intrusive way, but this is the best we can do given the
6
- # options we have.
7
-
8
- class Unicorn::HttpServer
9
- alias_method :original_worker_loop, :worker_loop
10
-
11
- def worker_loop(worker)
12
- Appsignal.agent.forked!
13
- original_worker_loop(worker)
14
- end
15
- end
16
-
17
- class Unicorn::Worker
18
- alias_method :original_close, :close
19
-
20
- def close
21
- Appsignal.agent.shutdown(true, 'stopping Unicorn worker process')
22
- original_close
23
- end
24
- end
25
- end
@@ -1,68 +0,0 @@
1
- require 'drb/drb'
2
-
3
- module Appsignal
4
- class IPC
5
- class << self
6
- def forked!
7
- Server.stop
8
- Client.start
9
- Appsignal.agent.stop_thread
10
- end
11
- end
12
-
13
- class Server
14
- class << self
15
- attr_reader :uri
16
-
17
- def start
18
- local_tmp_path = File.join(Appsignal.config.root_path, 'tmp')
19
- if File.exists?(local_tmp_path)
20
- @uri = 'drbunix:' + File.join(local_tmp_path, "appsignal-#{Process.pid}")
21
- else
22
- @uri = "drbunix:/tmp/appsignal-#{Process.pid}"
23
- end
24
-
25
- Appsignal.logger.info("Starting IPC server, listening on #{uri}")
26
- DRb.start_service(uri, Appsignal::IPC::Server)
27
- end
28
-
29
- def stop
30
- Appsignal.logger.debug('Stopping IPC server')
31
- DRb.stop_service
32
- end
33
-
34
- def enqueue(transaction)
35
- Appsignal.logger.debug("Receiving transaction #{transaction.request_id} in IPC server")
36
- Appsignal.enqueue(transaction)
37
- end
38
- end
39
- end
40
-
41
- class Client
42
- class << self
43
- attr_reader :server
44
-
45
- def start
46
- Appsignal.logger.debug('Starting IPC client')
47
- @server = DRbObject.new_with_uri(Appsignal::IPC::Server.uri)
48
- @active = true
49
- end
50
-
51
- def stop
52
- Appsignal.logger.debug('Stopping IPC client')
53
- @server = nil
54
- @active = false
55
- end
56
-
57
- def enqueue(transaction)
58
- Appsignal.logger.debug("Sending transaction #{transaction.request_id} in IPC client")
59
- @server.enqueue(transaction)
60
- end
61
-
62
- def active?
63
- !! @active
64
- end
65
- end
66
- end
67
- end
68
- end
@@ -1,85 +0,0 @@
1
- require 'delegate'
2
-
3
- module Appsignal
4
- class Transaction
5
- class Formatter < SimpleDelegator
6
- def hash
7
- @hash ||= default_hash
8
- end
9
-
10
- def to_hash
11
- merge_process_action_event_with_log_entry! if process_action_event
12
- add_queue_duration_to_hash!
13
- if exception?
14
- add_exception_to_hash!
15
- add_tags_to_hash!
16
- end
17
- add_events_to_hash! if slow_request?
18
- hash
19
- end
20
-
21
- protected
22
-
23
- def default_hash
24
- {
25
- :request_id => request_id,
26
- :log_entry => {
27
- :path => fullpath,
28
- :kind => kind,
29
- :action => action,
30
- :time => time,
31
- :environment => sanitized_environment,
32
- :session_data => sanitized_session_data,
33
- :params => sanitized_params,
34
- :revision => Appsignal.agent.revision
35
- },
36
- :failed => exception?
37
- }
38
- end
39
-
40
- def merge_process_action_event_with_log_entry!
41
- hash[:log_entry].merge!(event_to_hash(process_action_event))
42
- hash[:log_entry].tap do |o|
43
- o.merge!(o.delete(:payload))
44
- o.delete(:controller)
45
- o.delete(:action)
46
- o.delete(:name)
47
- o.delete(:class)
48
- o.delete(:method)
49
- o.delete(:queue_start)
50
- o.delete(:params) unless Appsignal.config[:send_params]
51
- o[:action] = action
52
- end
53
- end
54
-
55
- def add_queue_duration_to_hash!
56
- return unless queue_start && queue_start > 0
57
- hash[:log_entry][:queue_duration] = 1000.0 * (hash[:log_entry][:time] - queue_start)
58
- end
59
-
60
- def add_tags_to_hash!
61
- hash[:log_entry][:tags] = tags
62
- end
63
-
64
- def add_exception_to_hash!
65
- hash[:exception] = exception
66
- end
67
-
68
- def add_events_to_hash!
69
- hash[:events] = events.map do |event|
70
- event_to_hash(event)
71
- end
72
- end
73
-
74
- def event_to_hash(event)
75
- {
76
- :name => event.name,
77
- :duration => event.duration,
78
- :time => event.time.to_f,
79
- :end => event.end.to_f,
80
- :payload => event.payload
81
- }
82
- end
83
- end
84
- end
85
- end