appsignal 2.5.0.alpha.1-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (211) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +33 -0
  3. data/.rspec +4 -0
  4. data/.rubocop.yml +66 -0
  5. data/.rubocop_todo.yml +124 -0
  6. data/.travis.yml +72 -0
  7. data/.yardopts +8 -0
  8. data/CHANGELOG.md +639 -0
  9. data/Gemfile +3 -0
  10. data/LICENSE +20 -0
  11. data/README.md +264 -0
  12. data/Rakefile +214 -0
  13. data/appsignal.gemspec +42 -0
  14. data/benchmark.rake +77 -0
  15. data/bin/appsignal +13 -0
  16. data/ext/Rakefile +27 -0
  17. data/ext/agent.yml +64 -0
  18. data/ext/appsignal_extension.c +692 -0
  19. data/ext/base.rb +79 -0
  20. data/ext/extconf.rb +35 -0
  21. data/gemfiles/capistrano2.gemfile +7 -0
  22. data/gemfiles/capistrano3.gemfile +7 -0
  23. data/gemfiles/grape.gemfile +7 -0
  24. data/gemfiles/no_dependencies.gemfile +5 -0
  25. data/gemfiles/padrino.gemfile +7 -0
  26. data/gemfiles/que.gemfile +5 -0
  27. data/gemfiles/rails-3.2.gemfile +6 -0
  28. data/gemfiles/rails-4.0.gemfile +6 -0
  29. data/gemfiles/rails-4.1.gemfile +6 -0
  30. data/gemfiles/rails-4.2.gemfile +10 -0
  31. data/gemfiles/rails-5.0.gemfile +5 -0
  32. data/gemfiles/rails-5.1.gemfile +5 -0
  33. data/gemfiles/resque.gemfile +12 -0
  34. data/gemfiles/sequel-435.gemfile +11 -0
  35. data/gemfiles/sequel.gemfile +11 -0
  36. data/gemfiles/sinatra.gemfile +6 -0
  37. data/gemfiles/webmachine.gemfile +5 -0
  38. data/lib/appsignal.rb +804 -0
  39. data/lib/appsignal/auth_check.rb +65 -0
  40. data/lib/appsignal/capistrano.rb +10 -0
  41. data/lib/appsignal/cli.rb +108 -0
  42. data/lib/appsignal/cli/demo.rb +63 -0
  43. data/lib/appsignal/cli/diagnose.rb +500 -0
  44. data/lib/appsignal/cli/helpers.rb +72 -0
  45. data/lib/appsignal/cli/install.rb +277 -0
  46. data/lib/appsignal/cli/notify_of_deploy.rb +113 -0
  47. data/lib/appsignal/config.rb +287 -0
  48. data/lib/appsignal/demo.rb +107 -0
  49. data/lib/appsignal/event_formatter.rb +74 -0
  50. data/lib/appsignal/event_formatter/action_view/render_formatter.rb +24 -0
  51. data/lib/appsignal/event_formatter/active_record/instantiation_formatter.rb +14 -0
  52. data/lib/appsignal/event_formatter/active_record/sql_formatter.rb +14 -0
  53. data/lib/appsignal/event_formatter/elastic_search/search_formatter.rb +32 -0
  54. data/lib/appsignal/event_formatter/faraday/request_formatter.rb +19 -0
  55. data/lib/appsignal/event_formatter/mongo_ruby_driver/query_formatter.rb +89 -0
  56. data/lib/appsignal/event_formatter/moped/query_formatter.rb +80 -0
  57. data/lib/appsignal/extension.rb +63 -0
  58. data/lib/appsignal/extension/jruby.rb +460 -0
  59. data/lib/appsignal/garbage_collection_profiler.rb +48 -0
  60. data/lib/appsignal/hooks.rb +105 -0
  61. data/lib/appsignal/hooks/action_cable.rb +113 -0
  62. data/lib/appsignal/hooks/active_support_notifications.rb +52 -0
  63. data/lib/appsignal/hooks/celluloid.rb +30 -0
  64. data/lib/appsignal/hooks/data_mapper.rb +18 -0
  65. data/lib/appsignal/hooks/delayed_job.rb +19 -0
  66. data/lib/appsignal/hooks/mongo_ruby_driver.rb +21 -0
  67. data/lib/appsignal/hooks/net_http.rb +29 -0
  68. data/lib/appsignal/hooks/passenger.rb +22 -0
  69. data/lib/appsignal/hooks/puma.rb +35 -0
  70. data/lib/appsignal/hooks/que.rb +21 -0
  71. data/lib/appsignal/hooks/rake.rb +39 -0
  72. data/lib/appsignal/hooks/redis.rb +30 -0
  73. data/lib/appsignal/hooks/sequel.rb +60 -0
  74. data/lib/appsignal/hooks/shoryuken.rb +43 -0
  75. data/lib/appsignal/hooks/sidekiq.rb +144 -0
  76. data/lib/appsignal/hooks/unicorn.rb +40 -0
  77. data/lib/appsignal/hooks/webmachine.rb +23 -0
  78. data/lib/appsignal/integrations/capistrano/appsignal.cap +39 -0
  79. data/lib/appsignal/integrations/capistrano/capistrano_2_tasks.rb +52 -0
  80. data/lib/appsignal/integrations/data_mapper.rb +33 -0
  81. data/lib/appsignal/integrations/delayed_job_plugin.rb +54 -0
  82. data/lib/appsignal/integrations/grape.rb +53 -0
  83. data/lib/appsignal/integrations/mongo_ruby_driver.rb +55 -0
  84. data/lib/appsignal/integrations/object.rb +35 -0
  85. data/lib/appsignal/integrations/padrino.rb +84 -0
  86. data/lib/appsignal/integrations/que.rb +43 -0
  87. data/lib/appsignal/integrations/railtie.rb +41 -0
  88. data/lib/appsignal/integrations/rake.rb +2 -0
  89. data/lib/appsignal/integrations/resque.rb +20 -0
  90. data/lib/appsignal/integrations/resque_active_job.rb +30 -0
  91. data/lib/appsignal/integrations/sinatra.rb +17 -0
  92. data/lib/appsignal/integrations/webmachine.rb +38 -0
  93. data/lib/appsignal/js_exception_transaction.rb +54 -0
  94. data/lib/appsignal/marker.rb +63 -0
  95. data/lib/appsignal/minutely.rb +42 -0
  96. data/lib/appsignal/rack/generic_instrumentation.rb +49 -0
  97. data/lib/appsignal/rack/js_exception_catcher.rb +70 -0
  98. data/lib/appsignal/rack/rails_instrumentation.rb +51 -0
  99. data/lib/appsignal/rack/sinatra_instrumentation.rb +99 -0
  100. data/lib/appsignal/rack/streaming_listener.rb +73 -0
  101. data/lib/appsignal/system.rb +81 -0
  102. data/lib/appsignal/transaction.rb +498 -0
  103. data/lib/appsignal/transmitter.rb +107 -0
  104. data/lib/appsignal/utils.rb +127 -0
  105. data/lib/appsignal/utils/params_sanitizer.rb +59 -0
  106. data/lib/appsignal/utils/query_params_sanitizer.rb +55 -0
  107. data/lib/appsignal/version.rb +3 -0
  108. data/lib/sequel/extensions/appsignal_integration.rb +3 -0
  109. data/resources/appsignal.yml.erb +39 -0
  110. data/resources/cacert.pem +3866 -0
  111. data/spec/.rubocop.yml +7 -0
  112. data/spec/lib/appsignal/auth_check_spec.rb +80 -0
  113. data/spec/lib/appsignal/capistrano2_spec.rb +224 -0
  114. data/spec/lib/appsignal/capistrano3_spec.rb +237 -0
  115. data/spec/lib/appsignal/cli/demo_spec.rb +67 -0
  116. data/spec/lib/appsignal/cli/diagnose_spec.rb +988 -0
  117. data/spec/lib/appsignal/cli/helpers_spec.rb +171 -0
  118. data/spec/lib/appsignal/cli/install_spec.rb +632 -0
  119. data/spec/lib/appsignal/cli/notify_of_deploy_spec.rb +168 -0
  120. data/spec/lib/appsignal/cli_spec.rb +56 -0
  121. data/spec/lib/appsignal/config_spec.rb +637 -0
  122. data/spec/lib/appsignal/demo_spec.rb +87 -0
  123. data/spec/lib/appsignal/event_formatter/action_view/render_formatter_spec.rb +44 -0
  124. data/spec/lib/appsignal/event_formatter/active_record/instantiation_formatter_spec.rb +21 -0
  125. data/spec/lib/appsignal/event_formatter/active_record/sql_formatter_spec.rb +21 -0
  126. data/spec/lib/appsignal/event_formatter/elastic_search/search_formatter_spec.rb +52 -0
  127. data/spec/lib/appsignal/event_formatter/faraday/request_formatter_spec.rb +21 -0
  128. data/spec/lib/appsignal/event_formatter/mongo_ruby_driver/query_formatter_spec.rb +113 -0
  129. data/spec/lib/appsignal/event_formatter/moped/query_formatter_spec.rb +112 -0
  130. data/spec/lib/appsignal/event_formatter_spec.rb +100 -0
  131. data/spec/lib/appsignal/extension/jruby_spec.rb +43 -0
  132. data/spec/lib/appsignal/extension_spec.rb +137 -0
  133. data/spec/lib/appsignal/garbage_collection_profiler_spec.rb +66 -0
  134. data/spec/lib/appsignal/hooks/action_cable_spec.rb +370 -0
  135. data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +92 -0
  136. data/spec/lib/appsignal/hooks/celluloid_spec.rb +35 -0
  137. data/spec/lib/appsignal/hooks/data_mapper_spec.rb +39 -0
  138. data/spec/lib/appsignal/hooks/delayed_job_spec.rb +358 -0
  139. data/spec/lib/appsignal/hooks/mongo_ruby_driver_spec.rb +44 -0
  140. data/spec/lib/appsignal/hooks/net_http_spec.rb +53 -0
  141. data/spec/lib/appsignal/hooks/passenger_spec.rb +30 -0
  142. data/spec/lib/appsignal/hooks/puma_spec.rb +80 -0
  143. data/spec/lib/appsignal/hooks/que_spec.rb +19 -0
  144. data/spec/lib/appsignal/hooks/rake_spec.rb +73 -0
  145. data/spec/lib/appsignal/hooks/redis_spec.rb +55 -0
  146. data/spec/lib/appsignal/hooks/sequel_spec.rb +46 -0
  147. data/spec/lib/appsignal/hooks/shoryuken_spec.rb +192 -0
  148. data/spec/lib/appsignal/hooks/sidekiq_spec.rb +419 -0
  149. data/spec/lib/appsignal/hooks/unicorn_spec.rb +52 -0
  150. data/spec/lib/appsignal/hooks/webmachine_spec.rb +35 -0
  151. data/spec/lib/appsignal/hooks_spec.rb +195 -0
  152. data/spec/lib/appsignal/integrations/data_mapper_spec.rb +65 -0
  153. data/spec/lib/appsignal/integrations/grape_spec.rb +225 -0
  154. data/spec/lib/appsignal/integrations/mongo_ruby_driver_spec.rb +127 -0
  155. data/spec/lib/appsignal/integrations/object_spec.rb +249 -0
  156. data/spec/lib/appsignal/integrations/padrino_spec.rb +323 -0
  157. data/spec/lib/appsignal/integrations/que_spec.rb +174 -0
  158. data/spec/lib/appsignal/integrations/railtie_spec.rb +129 -0
  159. data/spec/lib/appsignal/integrations/resque_active_job_spec.rb +83 -0
  160. data/spec/lib/appsignal/integrations/resque_spec.rb +92 -0
  161. data/spec/lib/appsignal/integrations/sinatra_spec.rb +73 -0
  162. data/spec/lib/appsignal/integrations/webmachine_spec.rb +69 -0
  163. data/spec/lib/appsignal/js_exception_transaction_spec.rb +128 -0
  164. data/spec/lib/appsignal/marker_spec.rb +51 -0
  165. data/spec/lib/appsignal/minutely_spec.rb +50 -0
  166. data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +90 -0
  167. data/spec/lib/appsignal/rack/js_exception_catcher_spec.rb +147 -0
  168. data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +117 -0
  169. data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +213 -0
  170. data/spec/lib/appsignal/rack/streaming_listener_spec.rb +161 -0
  171. data/spec/lib/appsignal/system_spec.rb +131 -0
  172. data/spec/lib/appsignal/transaction_spec.rb +1146 -0
  173. data/spec/lib/appsignal/transmitter_spec.rb +152 -0
  174. data/spec/lib/appsignal/utils/params_sanitizer_spec.rb +136 -0
  175. data/spec/lib/appsignal/utils/query_params_sanitizer_spec.rb +192 -0
  176. data/spec/lib/appsignal/utils_spec.rb +150 -0
  177. data/spec/lib/appsignal_spec.rb +1049 -0
  178. data/spec/spec_helper.rb +116 -0
  179. data/spec/support/fixtures/containers/cgroups/docker +14 -0
  180. data/spec/support/fixtures/containers/cgroups/docker_systemd +8 -0
  181. data/spec/support/fixtures/containers/cgroups/lxc +10 -0
  182. data/spec/support/fixtures/containers/cgroups/no_permission +0 -0
  183. data/spec/support/fixtures/containers/cgroups/none +1 -0
  184. data/spec/support/fixtures/generated_config.yml +24 -0
  185. data/spec/support/fixtures/uploaded_file.txt +0 -0
  186. data/spec/support/helpers/api_request_helper.rb +19 -0
  187. data/spec/support/helpers/cli_helpers.rb +26 -0
  188. data/spec/support/helpers/config_helpers.rb +21 -0
  189. data/spec/support/helpers/dependency_helper.rb +73 -0
  190. data/spec/support/helpers/directory_helper.rb +27 -0
  191. data/spec/support/helpers/env_helpers.rb +33 -0
  192. data/spec/support/helpers/example_exception.rb +13 -0
  193. data/spec/support/helpers/example_standard_error.rb +13 -0
  194. data/spec/support/helpers/log_helpers.rb +22 -0
  195. data/spec/support/helpers/std_streams_helper.rb +66 -0
  196. data/spec/support/helpers/system_helpers.rb +8 -0
  197. data/spec/support/helpers/time_helpers.rb +11 -0
  198. data/spec/support/helpers/transaction_helpers.rb +37 -0
  199. data/spec/support/matchers/contains_log.rb +7 -0
  200. data/spec/support/mocks/fake_gc_profiler.rb +19 -0
  201. data/spec/support/mocks/mock_extension.rb +6 -0
  202. data/spec/support/project_fixture/config/application.rb +0 -0
  203. data/spec/support/project_fixture/config/appsignal.yml +32 -0
  204. data/spec/support/project_fixture/config/environments/development.rb +0 -0
  205. data/spec/support/project_fixture/config/environments/production.rb +0 -0
  206. data/spec/support/project_fixture/config/environments/test.rb +0 -0
  207. data/spec/support/project_fixture/log/.gitkeep +0 -0
  208. data/spec/support/rails/my_app.rb +6 -0
  209. data/spec/support/shared_examples/instrument.rb +43 -0
  210. data/spec/support/stubs/delayed_job.rb +0 -0
  211. metadata +483 -0
@@ -0,0 +1,44 @@
1
+ describe Appsignal::Hooks::MongoRubyDriverHook do
2
+ require "appsignal/integrations/mongo_ruby_driver"
3
+
4
+ context "with mongo ruby driver" do
5
+ let(:subscriber) { Appsignal::Hooks::MongoMonitorSubscriber.new }
6
+ before { allow(Appsignal::Hooks::MongoMonitorSubscriber).to receive(:new).and_return(subscriber) }
7
+
8
+ before(:context) do
9
+ module Mongo
10
+ module Monitoring
11
+ COMMAND = "command".freeze
12
+
13
+ class Global
14
+ def subscribe
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ after(:context) { Object.send(:remove_const, :Mongo) }
21
+
22
+ describe "#dependencies_present?" do
23
+ subject { described_class.new.dependencies_present? }
24
+
25
+ it { is_expected.to be_truthy }
26
+ end
27
+
28
+ it "adds a subscriber to Mongo::Monitoring" do
29
+ expect(Mongo::Monitoring::Global).to receive(:subscribe)
30
+ .with("command", subscriber)
31
+ .at_least(:once)
32
+
33
+ Appsignal::Hooks::MongoRubyDriverHook.new.install
34
+ end
35
+ end
36
+
37
+ context "without mongo ruby driver" do
38
+ describe "#dependencies_present?" do
39
+ subject { described_class.new.dependencies_present? }
40
+
41
+ it { is_expected.to be_falsy }
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,53 @@
1
+ describe Appsignal::Hooks::NetHttpHook do
2
+ before :context do
3
+ start_agent
4
+ end
5
+
6
+ context "with Net::HTTP instrumentation enabled" do
7
+ describe "#dependencies_present?" do
8
+ subject { described_class.new.dependencies_present? }
9
+
10
+ it { is_expected.to be_truthy }
11
+ end
12
+
13
+ it "should instrument a http request" do
14
+ Appsignal::Transaction.create("uuid", Appsignal::Transaction::HTTP_REQUEST, "test")
15
+ expect(Appsignal::Transaction.current).to receive(:start_event)
16
+ .at_least(:once)
17
+ expect(Appsignal::Transaction.current).to receive(:finish_event)
18
+ .at_least(:once)
19
+ .with("request.net_http", "GET http://www.google.com", nil, 0)
20
+
21
+ stub_request(:any, "http://www.google.com/")
22
+
23
+ Net::HTTP.get_response(URI.parse("http://www.google.com"))
24
+ end
25
+
26
+ it "should instrument a https request" do
27
+ Appsignal::Transaction.create("uuid", Appsignal::Transaction::HTTP_REQUEST, "test")
28
+ expect(Appsignal::Transaction.current).to receive(:start_event)
29
+ .at_least(:once)
30
+ expect(Appsignal::Transaction.current).to receive(:finish_event)
31
+ .at_least(:once)
32
+ .with("request.net_http", "GET https://www.google.com", nil, 0)
33
+
34
+ stub_request(:any, "https://www.google.com/")
35
+
36
+ uri = URI.parse("https://www.google.com")
37
+ http = Net::HTTP.new(uri.host, uri.port)
38
+ http.use_ssl = true
39
+ http.get(uri.request_uri)
40
+ end
41
+ end
42
+
43
+ context "with Net::HTTP instrumentation disabled" do
44
+ before { Appsignal.config.config_hash[:instrument_net_http] = false }
45
+ after { Appsignal.config.config_hash[:instrument_net_http] = true }
46
+
47
+ describe "#dependencies_present?" do
48
+ subject { described_class.new.dependencies_present? }
49
+
50
+ it { is_expected.to be_falsy }
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,30 @@
1
+ describe Appsignal::Hooks::PassengerHook do
2
+ context "with passenger" do
3
+ before(:context) do
4
+ module PhusionPassenger
5
+ end
6
+ end
7
+ after(:context) { Object.send(:remove_const, :PhusionPassenger) }
8
+
9
+ describe "#dependencies_present?" do
10
+ subject { described_class.new.dependencies_present? }
11
+
12
+ it { is_expected.to be_truthy }
13
+ end
14
+
15
+ it "adds behavior to stopping_worker_process and starting_worker_process" do
16
+ expect(PhusionPassenger).to receive(:on_event).with(:starting_worker_process)
17
+ expect(PhusionPassenger).to receive(:on_event).with(:stopping_worker_process)
18
+
19
+ Appsignal::Hooks::PassengerHook.new.install
20
+ end
21
+ end
22
+
23
+ context "without passenger" do
24
+ describe "#dependencies_present?" do
25
+ subject { described_class.new.dependencies_present? }
26
+
27
+ it { is_expected.to be_falsy }
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,80 @@
1
+ describe Appsignal::Hooks::PumaHook do
2
+ context "with puma" do
3
+ before(:context) do
4
+ class Puma
5
+ def self.cli_config
6
+ @cli_config ||= CliConfig.new
7
+ end
8
+
9
+ class Cluster
10
+ def stop_workers
11
+ end
12
+ end
13
+ end
14
+
15
+ class CliConfig
16
+ attr_accessor :options
17
+
18
+ def initialize
19
+ @options = {}
20
+ end
21
+ end
22
+ end
23
+ after(:context) { Object.send(:remove_const, :Puma) }
24
+
25
+ describe "#dependencies_present?" do
26
+ subject { described_class.new.dependencies_present? }
27
+
28
+ it { is_expected.to be_truthy }
29
+ end
30
+
31
+ context "when installed" do
32
+ before do
33
+ Appsignal::Hooks::PumaHook.new.install
34
+ end
35
+
36
+ it "adds behavior to Unicorn::Worker#close" do
37
+ cluster = Puma::Cluster.new
38
+
39
+ expect(Appsignal).to receive(:stop)
40
+ expect(cluster).to receive(:stop_workers_without_appsignal)
41
+
42
+ cluster.stop_workers
43
+ end
44
+ end
45
+
46
+ context "with nil hooks" do
47
+ before do
48
+ Puma.cli_config.options.delete(:before_worker_boot)
49
+ Puma.cli_config.options.delete(:before_worker_shutdown)
50
+ Appsignal::Hooks::PumaHook.new.install
51
+ end
52
+
53
+ it "should add a before shutdown worker callback" do
54
+ expect(Puma.cli_config.options[:before_worker_boot].first).to be_a(Proc)
55
+ expect(Puma.cli_config.options[:before_worker_shutdown].first).to be_a(Proc)
56
+ end
57
+ end
58
+
59
+ context "with existing hooks" do
60
+ before do
61
+ Puma.cli_config.options[:before_worker_boot] = []
62
+ Puma.cli_config.options[:before_worker_shutdown] = []
63
+ Appsignal::Hooks::PumaHook.new.install
64
+ end
65
+
66
+ it "should add a before shutdown worker callback" do
67
+ expect(Puma.cli_config.options[:before_worker_boot].first).to be_a(Proc)
68
+ expect(Puma.cli_config.options[:before_worker_shutdown].first).to be_a(Proc)
69
+ end
70
+ end
71
+ end
72
+
73
+ context "without puma" do
74
+ describe "#dependencies_present?" do
75
+ subject { described_class.new.dependencies_present? }
76
+
77
+ it { is_expected.to be_falsy }
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,19 @@
1
+ describe Appsignal::Hooks::QueHook do
2
+ if DependencyHelper.que_present?
3
+ describe "#dependencies_present?" do
4
+ subject { described_class.new.dependencies_present? }
5
+
6
+ it { is_expected.to be_truthy }
7
+ end
8
+
9
+ it "installs the QuePlugin" do
10
+ expect(Que::Job.included_modules).to include(Appsignal::Integrations::QuePlugin)
11
+ end
12
+ else
13
+ describe "#dependencies_present?" do
14
+ subject { described_class.new.dependencies_present? }
15
+
16
+ it { is_expected.to be_falsy }
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,73 @@
1
+ require "rake"
2
+
3
+ describe Appsignal::Hooks::RakeHook do
4
+ let(:task) { Rake::Task.new("task:name", Rake::Application.new) }
5
+ let(:arguments) { Rake::TaskArguments.new(["foo"], ["bar"]) }
6
+ let(:generic_request) { Appsignal::Transaction::GenericRequest.new({}) }
7
+ before(:context) do
8
+ Appsignal.config = project_fixture_config
9
+ expect(Appsignal.active?).to be_truthy
10
+ Appsignal::Hooks.load_hooks
11
+ end
12
+
13
+ describe "#execute" do
14
+ context "without error" do
15
+ it "creates no transaction" do
16
+ expect(Appsignal::Transaction).to_not receive(:create)
17
+ end
18
+
19
+ it "calls the original task" do
20
+ expect(task).to receive(:execute_without_appsignal).with("foo")
21
+ end
22
+
23
+ after { task.execute("foo") }
24
+ end
25
+
26
+ context "with error" do
27
+ let(:error) { ExampleException }
28
+ let(:transaction) { background_job_transaction }
29
+ before do
30
+ task.enhance { raise error }
31
+
32
+ expect(Appsignal::Transaction).to receive(:create).with(
33
+ kind_of(String),
34
+ Appsignal::Transaction::BACKGROUND_JOB,
35
+ kind_of(Appsignal::Transaction::GenericRequest)
36
+ ).and_return(transaction)
37
+ end
38
+
39
+ it "sets the action" do
40
+ expect(transaction).to receive(:set_action).with("task:name")
41
+ end
42
+
43
+ it "sets the error" do
44
+ expect(transaction).to receive(:set_error).with(error)
45
+ end
46
+
47
+ it "completes the transaction and stops" do
48
+ expect(transaction).to receive(:complete).ordered
49
+ expect(Appsignal).to receive(:stop).with("rake").ordered
50
+ end
51
+
52
+ it "adds the task arguments to the request" do
53
+ expect(Appsignal::Transaction::GenericRequest).to receive(:new)
54
+ .with(:params => { :foo => "bar" })
55
+ .and_return(generic_request)
56
+ end
57
+
58
+ context "when first argument is not a `Rake::TaskArguments`" do
59
+ let(:arguments) { nil }
60
+
61
+ it "adds the first argument regardless" do
62
+ expect(Appsignal::Transaction::GenericRequest).to receive(:new)
63
+ .with(:params => nil)
64
+ .and_return(generic_request)
65
+ end
66
+ end
67
+
68
+ after do
69
+ expect { task.execute(arguments) }.to raise_error ExampleException
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,55 @@
1
+ describe Appsignal::Hooks::RedisHook do
2
+ before do
3
+ Appsignal.config = project_fixture_config
4
+ Appsignal::Hooks.load_hooks
5
+ end
6
+
7
+ if DependencyHelper.redis_present?
8
+ context "with redis" do
9
+ context "with instrumentation enabled" do
10
+ before do
11
+ Appsignal.config.config_hash[:instrument_redis] = true
12
+ allow_any_instance_of(Redis::Client).to receive(:process_without_appsignal).and_return(1)
13
+ end
14
+
15
+ describe "#dependencies_present?" do
16
+ subject { described_class.new.dependencies_present? }
17
+
18
+ it { is_expected.to be_truthy }
19
+ end
20
+
21
+ it "should instrument a redis call" do
22
+ Appsignal::Transaction.create("uuid", Appsignal::Transaction::HTTP_REQUEST, "test")
23
+ expect(Appsignal::Transaction.current).to receive(:start_event)
24
+ .at_least(:once)
25
+ expect(Appsignal::Transaction.current).to receive(:finish_event)
26
+ .at_least(:once)
27
+ .with("query.redis", "redis://127.0.0.1:6379/0", "get ?", 0)
28
+
29
+ client = Redis::Client.new
30
+ expect(client.process([[:get, "key"]])).to eq 1
31
+ end
32
+ end
33
+
34
+ context "with instrumentation disabled" do
35
+ before do
36
+ Appsignal.config.config_hash[:instrument_redis] = false
37
+ end
38
+
39
+ describe "#dependencies_present?" do
40
+ subject { described_class.new.dependencies_present? }
41
+
42
+ it { is_expected.to be_falsy }
43
+ end
44
+ end
45
+ end
46
+ else
47
+ context "without redis" do
48
+ describe "#dependencies_present?" do
49
+ subject { described_class.new.dependencies_present? }
50
+
51
+ it { is_expected.to be_falsy }
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,46 @@
1
+ describe Appsignal::Hooks::SequelHook do
2
+ if DependencyHelper.sequel_present?
3
+ let(:db) do
4
+ if Appsignal::System.jruby?
5
+ Sequel.connect("jdbc:sqlite::memory:")
6
+ else
7
+ Sequel.sqlite
8
+ end
9
+ end
10
+
11
+ before :context do
12
+ start_agent
13
+ end
14
+
15
+ describe "#dependencies_present?" do
16
+ subject { described_class.new.dependencies_present? }
17
+
18
+ it { is_expected.to be_truthy }
19
+ end
20
+
21
+ context "with a transaction" do
22
+ let(:transaction) { Appsignal::Transaction.current }
23
+ before do
24
+ Appsignal::Transaction.create("uuid", Appsignal::Transaction::HTTP_REQUEST, "test")
25
+ db.logger = Logger.new($stdout) # To test #log_duration call
26
+ end
27
+
28
+ it "should instrument queries" do
29
+ expect(transaction).to receive(:start_event).at_least(:once)
30
+ expect(transaction).to receive(:finish_event)
31
+ .at_least(:once)
32
+ .with("sql.sequel", nil, kind_of(String), 1)
33
+
34
+ expect(db).to receive(:log_duration).at_least(:once)
35
+
36
+ db["SELECT 1"].all.to_a
37
+ end
38
+ end
39
+ else
40
+ describe "#dependencies_present?" do
41
+ subject { described_class.new.dependencies_present? }
42
+
43
+ it { is_expected.to be_falsy }
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,192 @@
1
+ describe Appsignal::Hooks::ShoryukenMiddleware do
2
+ let(:current_transaction) { background_job_transaction }
3
+
4
+ class DemoShoryukenWorker
5
+ end
6
+
7
+ let(:worker_instance) { DemoShoryukenWorker.new }
8
+ let(:queue) { double }
9
+ let(:sqs_msg) { double(:attributes => {}) }
10
+ let(:body) { {} }
11
+
12
+ before do
13
+ allow(Appsignal::Transaction).to receive(:current).and_return(current_transaction)
14
+ start_agent
15
+ end
16
+
17
+ context "with a performance call" do
18
+ let(:queue) { "some-funky-queue-name" }
19
+ let(:sqs_msg) do
20
+ double(:attributes => { "SentTimestamp" => Time.parse("1976-11-18 0:00:00UTC").to_i * 1000 })
21
+ end
22
+
23
+ context "with complex argument" do
24
+ let(:body) do
25
+ {
26
+ :foo => "Foo",
27
+ :bar => "Bar"
28
+ }
29
+ end
30
+ after do
31
+ Timecop.freeze(Time.parse("01-01-2001 10:01:00UTC")) do
32
+ Appsignal::Hooks::ShoryukenMiddleware.new.call(worker_instance, queue, sqs_msg, body) do
33
+ # nothing
34
+ end
35
+ end
36
+ end
37
+
38
+ it "wraps the job in a transaction with the correct params" do
39
+ expect(Appsignal).to receive(:monitor_transaction).with(
40
+ "perform_job.shoryuken",
41
+ :class => "DemoShoryukenWorker",
42
+ :method => "perform",
43
+ :metadata => {
44
+ :queue => "some-funky-queue-name",
45
+ "SentTimestamp" => 217_123_200_000
46
+ },
47
+ :params => {
48
+ :foo => "Foo",
49
+ :bar => "Bar"
50
+ },
51
+ :queue_start => Time.parse("1976-11-18 0:00:00UTC").utc
52
+ )
53
+ end
54
+
55
+ context "with parameter filtering" do
56
+ before do
57
+ Appsignal.config = project_fixture_config("production")
58
+ Appsignal.config[:filter_parameters] = ["foo"]
59
+ end
60
+
61
+ it "filters selected arguments" do
62
+ expect(Appsignal).to receive(:monitor_transaction).with(
63
+ "perform_job.shoryuken",
64
+ :class => "DemoShoryukenWorker",
65
+ :method => "perform",
66
+ :metadata => {
67
+ :queue => "some-funky-queue-name",
68
+ "SentTimestamp" => 217_123_200_000
69
+ },
70
+ :params => {
71
+ :foo => "[FILTERED]",
72
+ :bar => "Bar"
73
+ },
74
+ :queue_start => Time.parse("1976-11-18 0:00:00UTC").utc
75
+ )
76
+ end
77
+ end
78
+ end
79
+
80
+ context "with a string as an argument" do
81
+ let(:body) { "foo bar" }
82
+
83
+ it "handles string arguments" do
84
+ expect(Appsignal).to receive(:monitor_transaction).with(
85
+ "perform_job.shoryuken",
86
+ :class => "DemoShoryukenWorker",
87
+ :method => "perform",
88
+ :metadata => {
89
+ :queue => "some-funky-queue-name",
90
+ "SentTimestamp" => 217_123_200_000
91
+ },
92
+ :params => { :params => body },
93
+ :queue_start => Time.parse("1976-11-18 0:00:00UTC").utc
94
+ )
95
+
96
+ Timecop.freeze(Time.parse("01-01-2001 10:01:00UTC")) do
97
+ Appsignal::Hooks::ShoryukenMiddleware.new.call(worker_instance, queue, sqs_msg, body) do
98
+ # nothing
99
+ end
100
+ end
101
+ end
102
+ end
103
+
104
+ context "with primitive type as argument" do
105
+ let(:body) { 1 }
106
+
107
+ it "handles primitive types as arguments" do
108
+ expect(Appsignal).to receive(:monitor_transaction).with(
109
+ "perform_job.shoryuken",
110
+ :class => "DemoShoryukenWorker",
111
+ :method => "perform",
112
+ :metadata => {
113
+ :queue => "some-funky-queue-name",
114
+ "SentTimestamp" => 217_123_200_000
115
+ },
116
+ :params => { :params => body },
117
+ :queue_start => Time.parse("1976-11-18 0:00:00UTC").utc
118
+ )
119
+
120
+ Timecop.freeze(Time.parse("01-01-2001 10:01:00UTC")) do
121
+ Appsignal::Hooks::ShoryukenMiddleware.new.call(worker_instance, queue, sqs_msg, body) do
122
+ # nothing
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
128
+
129
+ context "with exception" do
130
+ let(:transaction) do
131
+ Appsignal::Transaction.new(
132
+ SecureRandom.uuid,
133
+ Appsignal::Transaction::BACKGROUND_JOB,
134
+ Appsignal::Transaction::GenericRequest.new({})
135
+ )
136
+ end
137
+
138
+ before do
139
+ allow(Appsignal::Transaction).to receive(:current).and_return(transaction)
140
+ expect(Appsignal::Transaction).to receive(:create)
141
+ .with(
142
+ kind_of(String),
143
+ Appsignal::Transaction::BACKGROUND_JOB,
144
+ kind_of(Appsignal::Transaction::GenericRequest)
145
+ ).and_return(transaction)
146
+ end
147
+
148
+ it "sets the exception on the transaction" do
149
+ expect(transaction).to receive(:set_error).with(ExampleException)
150
+ end
151
+
152
+ after do
153
+ expect do
154
+ Timecop.freeze(Time.parse("01-01-2001 10:01:00UTC")) do
155
+ Appsignal::Hooks::ShoryukenMiddleware.new.call(worker_instance, queue, sqs_msg, body) do
156
+ raise ExampleException
157
+ end
158
+ end
159
+ end.to raise_error(ExampleException)
160
+ end
161
+ end
162
+ end
163
+
164
+ describe Appsignal::Hooks::ShoryukenHook do
165
+ context "with shoryuken" do
166
+ before(:context) do
167
+ module Shoryuken
168
+ def self.configure_server
169
+ end
170
+ end
171
+ Appsignal::Hooks::ShoryukenHook.new.install
172
+ end
173
+
174
+ after(:context) do
175
+ Object.send(:remove_const, :Shoryuken)
176
+ end
177
+
178
+ describe "#dependencies_present?" do
179
+ subject { described_class.new.dependencies_present? }
180
+
181
+ it { is_expected.to be_truthy }
182
+ end
183
+ end
184
+
185
+ context "without shoryuken" do
186
+ describe "#dependencies_present?" do
187
+ subject { described_class.new.dependencies_present? }
188
+
189
+ it { is_expected.to be_falsy }
190
+ end
191
+ end
192
+ end