appsignal 0.8.15 → 0.9.0.alpha.1

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 (36) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -2
  3. data/README.md +4 -0
  4. data/Rakefile +8 -0
  5. data/appsignal.gemspec +0 -1
  6. data/gemfiles/capistrano2.gemfile +5 -0
  7. data/gemfiles/capistrano3.gemfile +5 -0
  8. data/lib/appsignal.rb +10 -4
  9. data/lib/appsignal/agent.rb +5 -10
  10. data/lib/appsignal/capistrano.rb +8 -1
  11. data/lib/appsignal/config.rb +2 -1
  12. data/lib/appsignal/instrumentations/net_http.rb +15 -0
  13. data/lib/appsignal/integrations/capistrano/appsignal.cap +27 -0
  14. data/lib/appsignal/integrations/{capistrano.rb → capistrano/capistrano_2_tasks.rb} +2 -4
  15. data/lib/appsignal/integrations/capistrano/careful_logger.rb +1 -1
  16. data/lib/appsignal/integrations/delayed_job.rb +2 -4
  17. data/lib/appsignal/integrations/resque.rb +2 -4
  18. data/lib/appsignal/integrations/sidekiq.rb +2 -4
  19. data/lib/appsignal/marker.rb +1 -1
  20. data/lib/appsignal/rack/instrumentation.rb +1 -0
  21. data/lib/appsignal/rack/listener.rb +3 -4
  22. data/lib/appsignal/transaction.rb +16 -4
  23. data/lib/appsignal/version.rb +1 -1
  24. data/spec/lib/appsignal/agent_spec.rb +1 -23
  25. data/spec/lib/appsignal/config_spec.rb +2 -0
  26. data/spec/lib/appsignal/instrumentations/net_http_spec.rb +26 -0
  27. data/spec/lib/appsignal/integrations/capistrano2_spec.rb +178 -0
  28. data/spec/lib/appsignal/integrations/capistrano3_spec.rb +169 -0
  29. data/spec/lib/appsignal/integrations/resque_spec.rb +1 -1
  30. data/spec/lib/appsignal/marker_spec.rb +13 -10
  31. data/spec/lib/appsignal/transaction_spec.rb +34 -13
  32. data/spec/lib/appsignal_spec.rb +35 -0
  33. data/spec/lib/generators/appsignal/appsignal_generator_spec.rb +13 -14
  34. data/spec/spec_helper.rb +14 -0
  35. metadata +15 -21
  36. data/spec/lib/appsignal/integrations/capistrano_spec.rb +0 -151
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 14c00518e40685c71256e3fb07a80568198e3660
4
- data.tar.gz: dc8a116a4c5541feb03e2df238554253e9284ab5
3
+ metadata.gz: 5027037bb3729ff0670c601fbe27fc5d84382ef4
4
+ data.tar.gz: 886a06cd1a10ca255c4b40d7f302a2e364e8f07e
5
5
  SHA512:
6
- metadata.gz: a2aa00e17ba12ffd245e83174e6c35e3bced66796fd42e2335cdb38b0099733f09847e769551140b940565e23eabccae7d20fd8361578f0c3e1f9b01ce1494f9
7
- data.tar.gz: ce94868b73e6867ebd738f285b2b596ea9b3fdf95cb844c9fd2a5d68c11c57370a34715bc7e6bfb78dfd7fd9b509489d07439afc1d46cbcc3842fe4cf4abe9ca
6
+ metadata.gz: db483be432d3e87ebfb4152806d17c0452e5d90e213f390a15a4c68df70fab1df9e002784e0d524180b047a8832f98f68e95bc76164e36cefebf14b765bdf1a6
7
+ data.tar.gz: e63378b1777d0681bce0bc304bb455dbc97722ebecc97f5be122945f6ebdb8d68f5ff819f98cdde8e8215ffc386d2a67bf553c590e86cfe3ca191e30051a7d53
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
- # 0.8.15
2
- * Exception logging in agent thread
1
+ # 0.9.0
2
+ * Add option to override Capistrano revision
3
+ * Expanded deploy message in Capistrano
4
+ * Refactor of usage of Thread.local
5
+ * Net::HTTP instrumentation
6
+ * Capistrano 3 support
3
7
 
4
8
  # 0.8.14
5
9
  * Few tweaks in logging
data/README.md CHANGED
@@ -59,6 +59,8 @@ end
59
59
  Run rake bundle or, or run bundle install for all Gemfiles:
60
60
 
61
61
  ```
62
+ bundle --gemfile gemfiles/capistrano2.gemfile
63
+ bundle --gemfile gemfiles/capistrano3.gemfile
62
64
  bundle --gemfile gemfiles/no_dependencies.gemfile
63
65
  bundle --gemfile gemfiles/rails-3.0.gemfile
64
66
  bundle --gemfile gemfiles/rails-3.1.gemfile
@@ -71,6 +73,8 @@ bundle --gemfile gemfiles/sinatra.gemfile
71
73
  To run the spec suite with a specific Gemfile:
72
74
 
73
75
  ```
76
+ BUNDLE_GEMFILE=gemfiles/capistrano2.gemfile bundle exec rspec
77
+ BUNDLE_GEMFILE=gemfiles/capistrano3.gemfile bundle exec rspec
74
78
  BUNDLE_GEMFILE=gemfiles/no_dependencies.gemfile bundle exec rspec
75
79
  BUNDLE_GEMFILE=gemfiles/rails-3.0.gemfile bundle exec rspec
76
80
  BUNDLE_GEMFILE=gemfiles/rails-3.1.gemfile bundle exec rspec
data/Rakefile CHANGED
@@ -59,6 +59,8 @@ task :publish do
59
59
  end
60
60
 
61
61
  task :bundle do
62
+ system 'bundle --gemfile gemfiles/capistrano2.gemfile'
63
+ system 'bundle --gemfile gemfiles/capistrano3.gemfile'
62
64
  system 'bundle --gemfile gemfiles/no_dependencies.gemfile'
63
65
  system 'bundle --gemfile gemfiles/rails-3.0.gemfile'
64
66
  system 'bundle --gemfile gemfiles/rails-3.1.gemfile'
@@ -69,6 +71,12 @@ task :bundle do
69
71
  end
70
72
 
71
73
  task :spec do
74
+ puts 'Running capistrano2'
75
+ system 'env BUNDLE_GEMFILE=gemfiles/capistrano2.gemfile bundle exec rspec'
76
+
77
+ puts 'Running capistrano3'
78
+ system 'env BUNDLE_GEMFILE=gemfiles/capistrano3.gemfile bundle exec rspec'
79
+
72
80
  puts 'Running no dependencies'
73
81
  system 'env BUNDLE_GEMFILE=gemfiles/no_dependencies.gemfile bundle exec rspec'
74
82
 
data/appsignal.gemspec CHANGED
@@ -30,7 +30,6 @@ Gem::Specification.new do |gem|
30
30
 
31
31
  gem.add_development_dependency 'rake'
32
32
  gem.add_development_dependency 'rspec'
33
- gem.add_development_dependency 'capistrano', '< 3.0'
34
33
  gem.add_development_dependency 'pry'
35
34
  gem.add_development_dependency 'timecop'
36
35
 
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'capistrano', '< 3.0'
4
+
5
+ gemspec :path => '../'
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'capistrano', '>= 3.0'
4
+
5
+ gemspec :path => '../'
data/lib/appsignal.rb CHANGED
@@ -17,6 +17,10 @@ module Appsignal
17
17
  require 'appsignal/integrations/resque'
18
18
  end
19
19
 
20
+ def load_instrumentations
21
+ require 'appsignal/instrumentations/net_http' if config[:instrument_net_http]
22
+ end
23
+
20
24
  def extensions
21
25
  @extensions ||= []
22
26
  end
@@ -38,6 +42,7 @@ module Appsignal
38
42
  end
39
43
  logger.info("Starting appsignal-#{Appsignal::VERSION}")
40
44
  load_integrations
45
+ load_instrumentations
41
46
  initialize_extensions
42
47
  @agent = Appsignal::Agent.new
43
48
  at_exit { @agent.shutdown(true) }
@@ -74,10 +79,11 @@ module Appsignal
74
79
  end
75
80
 
76
81
  def add_exception(exception)
77
- return if !active? || Appsignal::Transaction.current.nil? || exception.nil?
78
- unless is_ignored_exception?(exception)
79
- Appsignal::Transaction.current.add_exception(exception)
80
- end
82
+ return if !active? ||
83
+ Appsignal::Transaction.current.nil? ||
84
+ exception.nil? ||
85
+ is_ignored_exception?(exception)
86
+ Appsignal::Transaction.current.add_exception(exception)
81
87
  end
82
88
 
83
89
  def tag_request(params={})
@@ -24,16 +24,11 @@ module Appsignal
24
24
  def start_thread
25
25
  Appsignal.logger.debug('Starting agent thread')
26
26
  @thread = Thread.new do
27
- begin
28
- sleep(rand(sleep_time))
29
- loop do
30
- send_queue if aggregator.has_transactions?
31
- Appsignal.logger.debug("Sleeping #{sleep_time}")
32
- sleep(sleep_time)
33
- end
34
- rescue Exception=>ex
35
- Appsignal.logger.error "#{ex.class} in agent thread: '#{ex.message}'"
36
- Appsignal.logger.error ex.backtrace.join('\n')
27
+ sleep(rand(sleep_time))
28
+ loop do
29
+ send_queue if aggregator.has_transactions?
30
+ Appsignal.logger.debug("Sleeping #{sleep_time}")
31
+ sleep(sleep_time)
37
32
  end
38
33
  end
39
34
  end
@@ -1,2 +1,9 @@
1
1
  require 'appsignal'
2
- require 'appsignal/integrations/capistrano'
2
+
3
+ if defined?(Capistrano::VERSION)
4
+ # Capistrano 3+
5
+ load File.expand_path('../integrations/capistrano/appsignal.cap', __FILE__)
6
+ else
7
+ # Capistrano 2
8
+ require 'appsignal/integrations/capistrano/capistrano_2_tasks'
9
+ end
@@ -10,7 +10,8 @@ module Appsignal
10
10
  :ignore_exceptions => [],
11
11
  :send_params => true,
12
12
  :endpoint => 'https://push.appsignal.com/1',
13
- :slow_request_threshold => 200
13
+ :slow_request_threshold => 200,
14
+ :instrument_net_http => true
14
15
  }.freeze
15
16
 
16
17
  attr_reader :root_path, :env, :initial_config, :config_hash
@@ -0,0 +1,15 @@
1
+ Net::HTTP.class_eval do
2
+ alias request_without_appsignal request
3
+
4
+ def request(request, body=nil, &block)
5
+ ActiveSupport::Notifications.instrument(
6
+ 'request.net_http',
7
+ :host => request['host'],
8
+ :scheme => use_ssl? ? 'https' : 'http',
9
+ :path => request.path,
10
+ :method => request.method
11
+ ) do
12
+ request_without_appsignal(request, body, &block)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,27 @@
1
+ namespace :appsignal do
2
+ task :deploy do
3
+ env = fetch(:rails_env, fetch(:rack_env, 'production'))
4
+ user = ENV['USER'] || ENV['USERNAME']
5
+ revision = fetch(:appsignal_revision, fetch(:current_revision))
6
+ logger = fetch(:logger, Logger.new($stdout))
7
+
8
+ appsignal_config = Appsignal::Config.new(
9
+ ENV['PWD'],
10
+ env,
11
+ fetch(:appsignal_config, {}),
12
+ logger
13
+ )
14
+
15
+ if appsignal_config && appsignal_config.active?
16
+ marker_data = {
17
+ :revision => revision,
18
+ :user => user
19
+ }
20
+
21
+ marker = Appsignal::Marker.new(marker_data, appsignal_config, logger)
22
+ marker.transmit
23
+ end
24
+ end
25
+ end
26
+
27
+ after 'deploy:finished', 'appsignal:deploy'
@@ -1,5 +1,3 @@
1
- require 'capistrano'
2
-
3
1
  module Appsignal
4
2
  module Integrations
5
3
  class Capistrano
@@ -12,6 +10,7 @@ module Appsignal
12
10
  task :deploy do
13
11
  env = fetch(:rails_env, fetch(:rack_env, 'production'))
14
12
  user = ENV['USER'] || ENV['USERNAME']
13
+ revision = fetch(:appsignal_revision, fetch(:current_revision))
15
14
 
16
15
  appsignal_config = Appsignal::Config.new(
17
16
  ENV['PWD'],
@@ -22,8 +21,7 @@ module Appsignal
22
21
 
23
22
  if appsignal_config && appsignal_config.active?
24
23
  marker_data = {
25
- :revision => current_revision,
26
- :repository => repository,
24
+ :revision => revision,
27
25
  :user => user
28
26
  }
29
27
 
@@ -1,6 +1,6 @@
1
1
  module Appsignal
2
2
  module CarefulLogger
3
- # Because Capistrano's logger uses the term important
3
+ # Because Capistrano 2's logger uses the term important
4
4
  # instead of error.
5
5
  def carefully_log_error(message)
6
6
  if @logger.respond_to?(:important)
@@ -26,12 +26,10 @@ if defined?(::Delayed::Plugin)
26
26
  block.call(job)
27
27
  end
28
28
  rescue Exception => exception
29
- unless Appsignal.is_ignored_exception?(exception)
30
- Appsignal::Transaction.current.add_exception(exception)
31
- end
29
+ Appsignal.add_exception(exception)
32
30
  raise exception
33
31
  ensure
34
- Appsignal::Transaction.current.complete!
32
+ Appsignal::Transaction.complete_current!
35
33
  end
36
34
  end
37
35
  end
@@ -15,12 +15,10 @@ if defined?(::Resque)
15
15
  yield
16
16
  end
17
17
  rescue Exception => exception
18
- unless Appsignal.is_ignored_exception?(exception)
19
- Appsignal::Transaction.current.add_exception(exception)
20
- end
18
+ Appsignal.add_exception(exception)
21
19
  raise exception
22
20
  ensure
23
- Appsignal::Transaction.current.complete!
21
+ Appsignal::Transaction.complete_current!
24
22
  end
25
23
 
26
24
  end
@@ -17,12 +17,10 @@ if defined?(::Sidekiq)
17
17
  yield
18
18
  end
19
19
  rescue Exception => exception
20
- unless Appsignal.is_ignored_exception?(exception)
21
- Appsignal::Transaction.current.add_exception(exception)
22
- end
20
+ Appsignal.add_exception(exception)
23
21
  raise exception
24
22
  ensure
25
- Appsignal::Transaction.current.complete!
23
+ Appsignal::Transaction.complete_current!
26
24
  end
27
25
  end
28
26
  end
@@ -16,7 +16,7 @@ module Appsignal
16
16
  def transmit
17
17
  begin
18
18
  transmitter = Transmitter.new(ACTION, config)
19
- logger.info('Notifying Appsignal of deploy...')
19
+ logger.info("Notifying Appsignal of deploy with: revision: #{marker_data[:revision]}, user: #{marker_data[:user]}")
20
20
  result = transmitter.transmit(marker_data)
21
21
  if result == '200'
22
22
  logger.info('Appsignal has been notified of this deploy!')
@@ -2,6 +2,7 @@ module Appsignal
2
2
  module Rack
3
3
  class Instrumentation
4
4
  def initialize(app, options = {})
5
+ Appsignal.logger.debug 'Initializing Appsignal::Rack::Instrumentation'
5
6
  @app, @options = app, options
6
7
  end
7
8
 
@@ -2,6 +2,7 @@ module Appsignal
2
2
  module Rack
3
3
  class Listener
4
4
  def initialize(app, options = {})
5
+ Appsignal.logger.debug 'Initializing Appsignal::Rack::Listener'
5
6
  @app, @options = app, options
6
7
  end
7
8
 
@@ -17,12 +18,10 @@ module Appsignal
17
18
  Appsignal::Transaction.create(request_id(env), env)
18
19
  @app.call(env)
19
20
  rescue Exception => exception
20
- unless Appsignal.is_ignored_exception?(exception)
21
- Appsignal::Transaction.current.add_exception(exception)
22
- end
21
+ Appsignal.add_exception(exception)
23
22
  raise exception
24
23
  ensure
25
- Appsignal::Transaction.current.complete!
24
+ Appsignal::Transaction.complete_current!
26
25
  end
27
26
 
28
27
  def request_id(env)
@@ -11,20 +11,30 @@
11
11
  HTTP_CACHE_CONTROL HTTP_CONNECTION HTTP_USER_AGENT HTTP_FROM HTTP_NEGOTIATE
12
12
  HTTP_PRAGMA HTTP_REFERER HTTP_X_FORWARDED_FOR).freeze
13
13
 
14
- def self.create(key, env)
15
- Appsignal.logger.debug("Creating transaction: #{key}")
16
- Thread.current[:appsignal_transaction_id] = key
17
- Appsignal.transactions[key] = Appsignal::Transaction.new(key, env)
14
+ def self.create(request_id, env)
15
+ Appsignal.logger.debug("Creating transaction: #{request_id}")
16
+ Thread.current[:appsignal_transaction_id] = request_id
17
+ Appsignal::Transaction.new(request_id, env)
18
18
  end
19
19
 
20
20
  def self.current
21
21
  Appsignal.transactions[Thread.current[:appsignal_transaction_id]]
22
22
  end
23
23
 
24
+ def self.complete_current!
25
+ if current
26
+ current.complete!
27
+ Thread.current[:appsignal_transaction_id] = nil
28
+ else
29
+ Appsignal.logger.error('Trying to complete current, but no transaction present')
30
+ end
31
+ end
32
+
24
33
  attr_reader :request_id, :events, :process_action_event, :action, :exception,
25
34
  :env, :fullpath, :time, :tags, :kind, :queue_start
26
35
 
27
36
  def initialize(request_id, env)
37
+ Appsignal.transactions[request_id] = self
28
38
  @request_id = request_id
29
39
  @events = []
30
40
  @process_action_event = nil
@@ -128,6 +138,8 @@
128
138
  else
129
139
  Appsignal.logger.debug("Not processing transaction: #{@request_id}")
130
140
  end
141
+ ensure
142
+ Appsignal.transactions.delete(@request_id)
131
143
  end
132
144
 
133
145
  def set_background_queue_start
@@ -1,3 +1,3 @@
1
1
  module Appsignal
2
- VERSION = '0.8.15'
2
+ VERSION = '0.9.0.alpha.1'
3
3
  end
@@ -47,7 +47,7 @@ describe Appsignal::Agent do
47
47
  before do
48
48
  subject.stub(
49
49
  :aggregator => double(:has_transactions? => true),
50
- :sleep_time => 0.1
50
+ :sleep_time => 0.01
51
51
  )
52
52
  end
53
53
 
@@ -58,28 +58,6 @@ describe Appsignal::Agent do
58
58
  sleep 1
59
59
  end
60
60
  end
61
-
62
- context "when an exception occurs in the thread" do
63
- before do
64
- aggregator = double
65
- aggregator.stub(:has_transactions?).and_raise(
66
- RuntimeError.new('error')
67
- )
68
- subject.stub(
69
- :aggregator => aggregator,
70
- :sleep_time => 0.1
71
- )
72
- end
73
-
74
- it "should log the error" do
75
- Appsignal.logger.should_receive(:error).
76
- with("RuntimeError in agent thread: 'error'").
77
- once
78
-
79
- subject.start_thread
80
- sleep 1
81
- end
82
- end
83
61
  end
84
62
 
85
63
  describe "#restart_thread" do
@@ -17,6 +17,7 @@ describe Appsignal::Config do
17
17
  it "should merge with the default config and fill the config hash" do
18
18
  subject.config_hash.should == {
19
19
  :ignore_exceptions => [],
20
+ :instrument_net_http => true,
20
21
  :send_params => true,
21
22
  :endpoint => 'https://push.appsignal.com/1',
22
23
  :slow_request_threshold => 200,
@@ -123,6 +124,7 @@ describe Appsignal::Config do
123
124
  :push_api_key => 'push_api_key',
124
125
  :ignore_exceptions => [],
125
126
  :send_params => true,
127
+ :instrument_net_http => true,
126
128
  :endpoint => 'https://push.appsignal.com/1',
127
129
  :slow_request_threshold => 200,
128
130
  :active => true