appsignal 0.12.rc.7 → 0.12.rc.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/ext/agent.yml +7 -7
  3. data/lib/appsignal.rb +3 -15
  4. data/lib/appsignal/hooks.rb +61 -0
  5. data/lib/appsignal/hooks/celluloid.rb +29 -0
  6. data/lib/appsignal/hooks/delayed_job.rb +18 -0
  7. data/lib/appsignal/hooks/net_http.rb +31 -0
  8. data/lib/appsignal/hooks/passenger.rb +21 -0
  9. data/lib/appsignal/hooks/puma.rb +20 -0
  10. data/lib/appsignal/hooks/rake.rb +42 -0
  11. data/lib/appsignal/hooks/redis.rb +24 -0
  12. data/lib/appsignal/hooks/resque.rb +28 -0
  13. data/lib/appsignal/hooks/sequel.rb +38 -0
  14. data/lib/appsignal/hooks/sidekiq.rb +68 -0
  15. data/lib/appsignal/hooks/unicorn.rb +39 -0
  16. data/lib/appsignal/integrations/capistrano/capistrano_2_tasks.rb +27 -29
  17. data/lib/appsignal/integrations/delayed_job_plugin.rb +39 -0
  18. data/lib/appsignal/integrations/railtie.rb +41 -0
  19. data/lib/appsignal/transaction.rb +9 -4
  20. data/lib/appsignal/version.rb +1 -1
  21. data/spec/lib/appsignal/{integrations/capistrano2_spec.rb → capistrano2_spec.rb} +1 -1
  22. data/spec/lib/appsignal/{integrations/capistrano3_spec.rb → capistrano3_spec.rb} +0 -0
  23. data/spec/lib/appsignal/{integrations → hooks}/celluloid_spec.rb +8 -11
  24. data/spec/lib/appsignal/{integrations → hooks}/delayed_job_spec.rb +7 -10
  25. data/spec/lib/appsignal/hooks/net_http_spec.rb +55 -0
  26. data/spec/lib/appsignal/hooks/passenger_spec.rb +24 -0
  27. data/spec/lib/appsignal/hooks/puma_spec.rb +50 -0
  28. data/spec/lib/appsignal/{integrations → hooks}/rake_spec.rb +4 -3
  29. data/spec/lib/appsignal/hooks/redis_spec.rb +59 -0
  30. data/spec/lib/appsignal/{integrations → hooks}/resque_spec.rb +5 -11
  31. data/spec/lib/appsignal/{instrumentations → hooks}/sequel_spec.rb +1 -3
  32. data/spec/lib/appsignal/{integrations → hooks}/sidekiq_spec.rb +20 -20
  33. data/spec/lib/appsignal/hooks/unicorn_spec.rb +46 -0
  34. data/spec/lib/appsignal/hooks_spec.rb +76 -0
  35. data/spec/lib/appsignal/integrations/{rails_spec.rb → railtie_spec.rb} +0 -0
  36. data/spec/lib/appsignal/transaction_spec.rb +3 -3
  37. data/spec/lib/appsignal_spec.rb +0 -33
  38. metadata +46 -42
  39. data/lib/appsignal/instrumentations/net_http.rb +0 -17
  40. data/lib/appsignal/instrumentations/redis.rb +0 -13
  41. data/lib/appsignal/instrumentations/sequel.rb +0 -31
  42. data/lib/appsignal/integrations/celluloid.rb +0 -19
  43. data/lib/appsignal/integrations/delayed_job.rb +0 -44
  44. data/lib/appsignal/integrations/passenger.rb +0 -11
  45. data/lib/appsignal/integrations/puma.rb +0 -10
  46. data/lib/appsignal/integrations/rails.rb +0 -43
  47. data/lib/appsignal/integrations/rake.rb +0 -30
  48. data/lib/appsignal/integrations/resque.rb +0 -22
  49. data/lib/appsignal/integrations/sidekiq.rb +0 -62
  50. data/lib/appsignal/integrations/unicorn.rb +0 -28
  51. data/spec/lib/appsignal/instrumentations/net_http_spec.rb +0 -40
  52. data/spec/lib/appsignal/instrumentations/redis_spec.rb +0 -45
  53. data/spec/lib/appsignal/integrations/passenger_spec.rb +0 -22
  54. data/spec/lib/appsignal/integrations/puma_spec.rb +0 -52
  55. data/spec/lib/appsignal/integrations/unicorn_spec.rb +0 -48
@@ -1,17 +0,0 @@
1
- require 'net/http'
2
-
3
- Net::HTTP.class_eval do
4
- alias request_without_appsignal request
5
-
6
- def request(request, body=nil, &block)
7
- ActiveSupport::Notifications.instrument(
8
- 'request.net_http',
9
- :protocol => use_ssl? ? 'https' : 'http',
10
- :domain => request['host'] || self.address,
11
- :path => request.path,
12
- :method => request.method
13
- ) do
14
- request_without_appsignal(request, body, &block)
15
- end
16
- end
17
- end
@@ -1,13 +0,0 @@
1
- if defined?(::Redis)
2
- Appsignal.logger.info("Loading Redis (#{ Redis::VERSION }) integration")
3
-
4
- ::Redis::Client.class_eval do
5
- alias process_without_appsignal process
6
-
7
- def process(commands, &block)
8
- ActiveSupport::Notifications.instrument('query.redis') do
9
- process_without_appsignal(commands, &block)
10
- end
11
- end
12
- end
13
- end
@@ -1,31 +0,0 @@
1
- if defined?(::Sequel)
2
- Appsignal.logger.info("Loading Sequel (#{ Sequel::VERSION }) integration")
3
-
4
- module Appsignal
5
- module Integrations
6
- module Sequel
7
- # Add query instrumentation
8
- def log_yield(sql, args = nil)
9
-
10
- # We'd like to get full sql queries in the payloads as well. To do
11
- # that we need to find out a way to ask Sequel which quoting strategy
12
- # is used by the adapter. We can then do something similar to the AR
13
- # formatter.
14
-
15
- ActiveSupport::Notifications.instrument('sql.sequel') do
16
- yield
17
- end
18
- end
19
- end # Sequel
20
- end # Integrations
21
- end # Appsignal
22
-
23
- # Register the extension...
24
- Sequel::Database.register_extension(
25
- :appsignal_integration,
26
- Appsignal::Integrations::Sequel
27
- )
28
-
29
- # ... and automatically add it to future instances.
30
- Sequel::Database.extension(:appsignal_integration)
31
- end
@@ -1,19 +0,0 @@
1
- if defined?(::Celluloid)
2
- Appsignal.logger.info('Loading Celluloid integration')
3
-
4
- # Some versions of Celluloid have race conditions while exiting
5
- # that can result in a dead lock. We stop appsignal before shutting
6
- # down Celluloid so we're sure our thread does not aggravate this situation.
7
- # This way we also make sure any outstanding transactions get flushed.
8
-
9
- ::Celluloid.class_eval do
10
- class << self
11
- alias shutdown_without_appsignal shutdown
12
-
13
- def shutdown
14
- Appsignal.stop
15
- shutdown_without_appsignal
16
- end
17
- end
18
- end
19
- end
@@ -1,44 +0,0 @@
1
- if defined?(::Delayed::Plugin)
2
- Appsignal.logger.info('Loading Delayed Job integration')
3
-
4
- module Appsignal
5
- module Integrations
6
- class DelayedPlugin < ::Delayed::Plugin
7
- callbacks do |lifecycle|
8
- lifecycle.around(:invoke_job) do |job, &block|
9
- invoke_with_instrumentation(job, block)
10
- end
11
-
12
- lifecycle.after(:loop) do |loop|
13
- Appsignal.stop
14
- end
15
- end
16
-
17
- def self.invoke_with_instrumentation(job, block)
18
- class_and_method_name = if job.payload_object.respond_to?(:appsignal_name)
19
- job.payload_object.appsignal_name
20
- else
21
- job.name
22
- end
23
- class_name, method_name = class_and_method_name.split('#')
24
-
25
- Appsignal.monitor_transaction(
26
- 'perform_job.delayed_job',
27
- :class => class_name,
28
- :method => method_name,
29
- :metadata => {
30
- :id => job.id,
31
- :queue => job.queue,
32
- :priority => job.priority || 0,
33
- :attempts => job.attempts || 0
34
- },
35
- :queue_start => job.created_at
36
- ) do
37
- block.call(job)
38
- end
39
- end
40
- end
41
- end
42
- end
43
- ::Delayed::Worker.plugins << Appsignal::Integrations::DelayedPlugin
44
- end
@@ -1,11 +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.forked
6
- end
7
-
8
- ::PhusionPassenger.on_event(:stopping_worker_process) do
9
- Appsignal.stop
10
- end
11
- end
@@ -1,10 +0,0 @@
1
- if defined?(::Puma) && ::Puma.respond_to?(:cli_config)
2
- Appsignal.logger.info('Loading Puma integration')
3
-
4
- if ::Puma.cli_config
5
- ::Puma.cli_config.options[:before_worker_shutdown] ||= []
6
- ::Puma.cli_config.options[:before_worker_shutdown] << Proc.new do |id|
7
- Appsignal.stop
8
- end
9
- end
10
- end
@@ -1,43 +0,0 @@
1
- if defined?(::Rails)
2
- Appsignal.logger.info("Loading Rails (#{Rails.version}) integration")
3
-
4
- require 'appsignal/rack/rails_instrumentation'
5
-
6
- module Appsignal
7
- module Integrations
8
- class Railtie < ::Rails::Railtie
9
- initializer 'appsignal.configure_rails_initialization' do |app|
10
- Appsignal::Integrations::Railtie.initialize_appsignal(app)
11
- end
12
-
13
- def self.initialize_appsignal(app)
14
- # Load config
15
- Appsignal.config = Appsignal::Config.new(
16
- Rails.root,
17
- ENV.fetch('APPSIGNAL_APP_ENV', Rails.env),
18
- :name => Rails.application.class.parent_name,
19
- :log_file_path => Rails.root.join('log/appsignal.log')
20
- )
21
-
22
- # Start logger
23
- Appsignal.start_logger
24
-
25
- app.middleware.insert_before(
26
- ActionDispatch::RemoteIp,
27
- Appsignal::Rack::RailsInstrumentation
28
- )
29
-
30
- if Appsignal.config.active? &&
31
- Appsignal.config[:enable_frontend_error_catching] == true
32
- app.middleware.insert_before(
33
- Appsignal::Rack::RailsInstrumentation,
34
- Appsignal::Rack::JSExceptionCatcher,
35
- )
36
- end
37
-
38
- Appsignal.start
39
- end
40
- end
41
- end
42
- end
43
- end
@@ -1,30 +0,0 @@
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
- Appsignal.stop
27
- raise error
28
- end
29
- end
30
- end
@@ -1,22 +0,0 @@
1
- if defined?(::Resque)
2
- Appsignal.logger.info('Loading Resque integration')
3
-
4
- module Appsignal
5
- module Integrations
6
- module ResquePlugin
7
- def around_perform_resque_plugin(*args)
8
- Appsignal.monitor_single_transaction(
9
- 'perform_job.resque',
10
- :class => self.to_s,
11
- :method => 'perform'
12
- ) do
13
- yield
14
- end
15
- end
16
- end
17
- end
18
- end
19
-
20
- # Extend the default job class with AppSignal instrumentation
21
- Resque::Job.send(:extend, Appsignal::Integrations::ResquePlugin)
22
- end
@@ -1,62 +0,0 @@
1
- if defined?(::Sidekiq)
2
- Appsignal.logger.info('Loading Sidekiq integration')
3
-
4
- module Appsignal
5
- module Integrations
6
- class SidekiqPlugin
7
- def job_keys
8
- @job_keys ||= Set.new(%w(
9
- class args retried_at failed_at
10
- error_message error_class backtrace
11
- error_backtrace enqueued_at retry
12
- ))
13
- end
14
-
15
- def call(worker, item, queue)
16
- Appsignal.monitor_transaction(
17
- 'perform_job.sidekiq',
18
- :class => item['wrapped'] || item['class'],
19
- :method => 'perform',
20
- :metadata => formatted_metadata(item),
21
- :params => format_args(item['args']),
22
- :queue_start => item['enqueued_at']
23
- ) do
24
- yield
25
- end
26
- end
27
-
28
- def formatted_metadata(item)
29
- {}.tap do |hsh|
30
- item.each do |key, val|
31
- hsh[key] = truncate(string_or_inspect(val)) unless job_keys.include?(key)
32
- end
33
- end
34
- end
35
-
36
- def string_or_inspect(string_or_other)
37
- if string_or_other.is_a?(String)
38
- string_or_other
39
- else
40
- string_or_other.inspect
41
- end
42
- end
43
-
44
- def format_args(args)
45
- args.map do |arg|
46
- truncate(string_or_inspect(arg))
47
- end
48
- end
49
-
50
- def truncate(text)
51
- text.size > 200 ? "#{text[0...197]}..." : text
52
- end
53
- end
54
- end
55
- end
56
-
57
- Sidekiq.configure_server do |config|
58
- config.server_middleware do |chain|
59
- chain.add Appsignal::Integrations::SidekiqPlugin
60
- end
61
- end
62
- end
@@ -1,28 +0,0 @@
1
- if defined?(::Unicorn)
2
- Appsignal.logger.info('Loading Unicorn integration')
3
-
4
- # Make sure the appsignal is started and the last transaction
5
- # in a worker gets flushed.
6
- #
7
- # We'd love to be able to hook this into Unicorn in a less
8
- # intrusive way, but this is the best we can do given the
9
- # options we have.
10
-
11
- class Unicorn::HttpServer
12
- alias_method :original_worker_loop, :worker_loop
13
-
14
- def worker_loop(worker)
15
- Appsignal.forked
16
- original_worker_loop(worker)
17
- end
18
- end
19
-
20
- class Unicorn::Worker
21
- alias_method :original_close, :close
22
-
23
- def close
24
- Appsignal.stop
25
- original_close
26
- end
27
- end
28
- end
@@ -1,40 +0,0 @@
1
- require 'spec_helper'
2
- require File.expand_path('lib/appsignal/instrumentations/net_http')
3
-
4
- describe "Net::HTTP instrumentation" do
5
- let(:events) { [] }
6
- before do
7
- ActiveSupport::Notifications.subscribe(/^[^!]/) do |*args|
8
- events << ActiveSupport::Notifications::Event.new(*args)
9
- end
10
- end
11
-
12
- it "should generate an event for a http request" do
13
- stub_request(:any, 'http://www.google.com/')
14
-
15
- Net::HTTP.get_response(URI.parse('http://www.google.com'))
16
-
17
- event = events.last
18
- event.name.should == 'request.net_http'
19
- event.payload[:protocol].should == 'http'
20
- event.payload[:domain].should == 'www.google.com'
21
- event.payload[:path].should == '/'
22
- event.payload[:method].should == 'GET'
23
- end
24
-
25
- it "should generate an event for a https request" do
26
- stub_request(:any, 'https://www.google.com/')
27
-
28
- uri = URI.parse('https://www.google.com')
29
- http = Net::HTTP.new(uri.host, uri.port)
30
- http.use_ssl = true
31
- http.get(uri.request_uri)
32
-
33
- event = events.last
34
- event.name.should == 'request.net_http'
35
- event.payload[:protocol].should == 'https'
36
- event.payload[:domain].should == 'www.google.com'
37
- event.payload[:path].should == '/'
38
- event.payload[:method].should == 'GET'
39
- end
40
- end
@@ -1,45 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe "Net::HTTP instrumentation" do
4
- let(:file) { File.expand_path('lib/appsignal/instrumentations/redis.rb') }
5
-
6
- let(:events) { [] }
7
- before do
8
- ActiveSupport::Notifications.subscribe(/^[^!]/) do |*args|
9
- events << ActiveSupport::Notifications::Event.new(*args)
10
- end
11
- end
12
-
13
- context "with redis" do
14
- before :all do
15
- module Redis
16
- class Client
17
- def process(commands, &block)
18
- 1
19
- end
20
- end
21
- VERSION = '1.0'
22
- end
23
- end
24
-
25
- before do
26
- load file
27
- end
28
-
29
- it "should generate an event for a redis call" do
30
- client = Redis::Client.new
31
-
32
- client.process([]).should == 1
33
-
34
- event = events.last
35
- event.name.should == 'query.redis'
36
- end
37
- end
38
-
39
- context "without redis" do
40
- before(:all) { Object.send(:remove_const, :Redis) }
41
-
42
- specify { expect { ::Redis }.to raise_error(NameError) }
43
- specify { expect { load file }.to_not raise_error }
44
- end
45
- end
@@ -1,22 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe "Passenger integration" do
4
- let(:file) { File.expand_path('lib/appsignal/integrations/passenger.rb') }
5
- before(:all) do
6
- module PhusionPassenger
7
- end
8
- end
9
-
10
- it "adds behavior to stopping_worker_process and starting_worker_process" do
11
- PhusionPassenger.should_receive(:on_event).with(:starting_worker_process)
12
- PhusionPassenger.should_receive(:on_event).with(:stopping_worker_process)
13
- load file
14
- end
15
-
16
- context "without passenger" do
17
- before(:all) { Object.send(:remove_const, :PhusionPassenger) }
18
-
19
- specify { expect { PhusionPassenger }.to raise_error(NameError) }
20
- specify { expect { load file }.to_not raise_error }
21
- end
22
- end