appsignal 2.5.0.alpha.1-java
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.
- checksums.yaml +7 -0
- data/.gitignore +33 -0
- data/.rspec +4 -0
- data/.rubocop.yml +66 -0
- data/.rubocop_todo.yml +124 -0
- data/.travis.yml +72 -0
- data/.yardopts +8 -0
- data/CHANGELOG.md +639 -0
- data/Gemfile +3 -0
- data/LICENSE +20 -0
- data/README.md +264 -0
- data/Rakefile +214 -0
- data/appsignal.gemspec +42 -0
- data/benchmark.rake +77 -0
- data/bin/appsignal +13 -0
- data/ext/Rakefile +27 -0
- data/ext/agent.yml +64 -0
- data/ext/appsignal_extension.c +692 -0
- data/ext/base.rb +79 -0
- data/ext/extconf.rb +35 -0
- data/gemfiles/capistrano2.gemfile +7 -0
- data/gemfiles/capistrano3.gemfile +7 -0
- data/gemfiles/grape.gemfile +7 -0
- data/gemfiles/no_dependencies.gemfile +5 -0
- data/gemfiles/padrino.gemfile +7 -0
- data/gemfiles/que.gemfile +5 -0
- data/gemfiles/rails-3.2.gemfile +6 -0
- data/gemfiles/rails-4.0.gemfile +6 -0
- data/gemfiles/rails-4.1.gemfile +6 -0
- data/gemfiles/rails-4.2.gemfile +10 -0
- data/gemfiles/rails-5.0.gemfile +5 -0
- data/gemfiles/rails-5.1.gemfile +5 -0
- data/gemfiles/resque.gemfile +12 -0
- data/gemfiles/sequel-435.gemfile +11 -0
- data/gemfiles/sequel.gemfile +11 -0
- data/gemfiles/sinatra.gemfile +6 -0
- data/gemfiles/webmachine.gemfile +5 -0
- data/lib/appsignal.rb +804 -0
- data/lib/appsignal/auth_check.rb +65 -0
- data/lib/appsignal/capistrano.rb +10 -0
- data/lib/appsignal/cli.rb +108 -0
- data/lib/appsignal/cli/demo.rb +63 -0
- data/lib/appsignal/cli/diagnose.rb +500 -0
- data/lib/appsignal/cli/helpers.rb +72 -0
- data/lib/appsignal/cli/install.rb +277 -0
- data/lib/appsignal/cli/notify_of_deploy.rb +113 -0
- data/lib/appsignal/config.rb +287 -0
- data/lib/appsignal/demo.rb +107 -0
- data/lib/appsignal/event_formatter.rb +74 -0
- data/lib/appsignal/event_formatter/action_view/render_formatter.rb +24 -0
- data/lib/appsignal/event_formatter/active_record/instantiation_formatter.rb +14 -0
- data/lib/appsignal/event_formatter/active_record/sql_formatter.rb +14 -0
- data/lib/appsignal/event_formatter/elastic_search/search_formatter.rb +32 -0
- data/lib/appsignal/event_formatter/faraday/request_formatter.rb +19 -0
- data/lib/appsignal/event_formatter/mongo_ruby_driver/query_formatter.rb +89 -0
- data/lib/appsignal/event_formatter/moped/query_formatter.rb +80 -0
- data/lib/appsignal/extension.rb +63 -0
- data/lib/appsignal/extension/jruby.rb +460 -0
- data/lib/appsignal/garbage_collection_profiler.rb +48 -0
- data/lib/appsignal/hooks.rb +105 -0
- data/lib/appsignal/hooks/action_cable.rb +113 -0
- data/lib/appsignal/hooks/active_support_notifications.rb +52 -0
- data/lib/appsignal/hooks/celluloid.rb +30 -0
- data/lib/appsignal/hooks/data_mapper.rb +18 -0
- data/lib/appsignal/hooks/delayed_job.rb +19 -0
- data/lib/appsignal/hooks/mongo_ruby_driver.rb +21 -0
- data/lib/appsignal/hooks/net_http.rb +29 -0
- data/lib/appsignal/hooks/passenger.rb +22 -0
- data/lib/appsignal/hooks/puma.rb +35 -0
- data/lib/appsignal/hooks/que.rb +21 -0
- data/lib/appsignal/hooks/rake.rb +39 -0
- data/lib/appsignal/hooks/redis.rb +30 -0
- data/lib/appsignal/hooks/sequel.rb +60 -0
- data/lib/appsignal/hooks/shoryuken.rb +43 -0
- data/lib/appsignal/hooks/sidekiq.rb +144 -0
- data/lib/appsignal/hooks/unicorn.rb +40 -0
- data/lib/appsignal/hooks/webmachine.rb +23 -0
- data/lib/appsignal/integrations/capistrano/appsignal.cap +39 -0
- data/lib/appsignal/integrations/capistrano/capistrano_2_tasks.rb +52 -0
- data/lib/appsignal/integrations/data_mapper.rb +33 -0
- data/lib/appsignal/integrations/delayed_job_plugin.rb +54 -0
- data/lib/appsignal/integrations/grape.rb +53 -0
- data/lib/appsignal/integrations/mongo_ruby_driver.rb +55 -0
- data/lib/appsignal/integrations/object.rb +35 -0
- data/lib/appsignal/integrations/padrino.rb +84 -0
- data/lib/appsignal/integrations/que.rb +43 -0
- data/lib/appsignal/integrations/railtie.rb +41 -0
- data/lib/appsignal/integrations/rake.rb +2 -0
- data/lib/appsignal/integrations/resque.rb +20 -0
- data/lib/appsignal/integrations/resque_active_job.rb +30 -0
- data/lib/appsignal/integrations/sinatra.rb +17 -0
- data/lib/appsignal/integrations/webmachine.rb +38 -0
- data/lib/appsignal/js_exception_transaction.rb +54 -0
- data/lib/appsignal/marker.rb +63 -0
- data/lib/appsignal/minutely.rb +42 -0
- data/lib/appsignal/rack/generic_instrumentation.rb +49 -0
- data/lib/appsignal/rack/js_exception_catcher.rb +70 -0
- data/lib/appsignal/rack/rails_instrumentation.rb +51 -0
- data/lib/appsignal/rack/sinatra_instrumentation.rb +99 -0
- data/lib/appsignal/rack/streaming_listener.rb +73 -0
- data/lib/appsignal/system.rb +81 -0
- data/lib/appsignal/transaction.rb +498 -0
- data/lib/appsignal/transmitter.rb +107 -0
- data/lib/appsignal/utils.rb +127 -0
- data/lib/appsignal/utils/params_sanitizer.rb +59 -0
- data/lib/appsignal/utils/query_params_sanitizer.rb +55 -0
- data/lib/appsignal/version.rb +3 -0
- data/lib/sequel/extensions/appsignal_integration.rb +3 -0
- data/resources/appsignal.yml.erb +39 -0
- data/resources/cacert.pem +3866 -0
- data/spec/.rubocop.yml +7 -0
- data/spec/lib/appsignal/auth_check_spec.rb +80 -0
- data/spec/lib/appsignal/capistrano2_spec.rb +224 -0
- data/spec/lib/appsignal/capistrano3_spec.rb +237 -0
- data/spec/lib/appsignal/cli/demo_spec.rb +67 -0
- data/spec/lib/appsignal/cli/diagnose_spec.rb +988 -0
- data/spec/lib/appsignal/cli/helpers_spec.rb +171 -0
- data/spec/lib/appsignal/cli/install_spec.rb +632 -0
- data/spec/lib/appsignal/cli/notify_of_deploy_spec.rb +168 -0
- data/spec/lib/appsignal/cli_spec.rb +56 -0
- data/spec/lib/appsignal/config_spec.rb +637 -0
- data/spec/lib/appsignal/demo_spec.rb +87 -0
- data/spec/lib/appsignal/event_formatter/action_view/render_formatter_spec.rb +44 -0
- data/spec/lib/appsignal/event_formatter/active_record/instantiation_formatter_spec.rb +21 -0
- data/spec/lib/appsignal/event_formatter/active_record/sql_formatter_spec.rb +21 -0
- data/spec/lib/appsignal/event_formatter/elastic_search/search_formatter_spec.rb +52 -0
- data/spec/lib/appsignal/event_formatter/faraday/request_formatter_spec.rb +21 -0
- data/spec/lib/appsignal/event_formatter/mongo_ruby_driver/query_formatter_spec.rb +113 -0
- data/spec/lib/appsignal/event_formatter/moped/query_formatter_spec.rb +112 -0
- data/spec/lib/appsignal/event_formatter_spec.rb +100 -0
- data/spec/lib/appsignal/extension/jruby_spec.rb +43 -0
- data/spec/lib/appsignal/extension_spec.rb +137 -0
- data/spec/lib/appsignal/garbage_collection_profiler_spec.rb +66 -0
- data/spec/lib/appsignal/hooks/action_cable_spec.rb +370 -0
- data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +92 -0
- data/spec/lib/appsignal/hooks/celluloid_spec.rb +35 -0
- data/spec/lib/appsignal/hooks/data_mapper_spec.rb +39 -0
- data/spec/lib/appsignal/hooks/delayed_job_spec.rb +358 -0
- data/spec/lib/appsignal/hooks/mongo_ruby_driver_spec.rb +44 -0
- data/spec/lib/appsignal/hooks/net_http_spec.rb +53 -0
- data/spec/lib/appsignal/hooks/passenger_spec.rb +30 -0
- data/spec/lib/appsignal/hooks/puma_spec.rb +80 -0
- data/spec/lib/appsignal/hooks/que_spec.rb +19 -0
- data/spec/lib/appsignal/hooks/rake_spec.rb +73 -0
- data/spec/lib/appsignal/hooks/redis_spec.rb +55 -0
- data/spec/lib/appsignal/hooks/sequel_spec.rb +46 -0
- data/spec/lib/appsignal/hooks/shoryuken_spec.rb +192 -0
- data/spec/lib/appsignal/hooks/sidekiq_spec.rb +419 -0
- data/spec/lib/appsignal/hooks/unicorn_spec.rb +52 -0
- data/spec/lib/appsignal/hooks/webmachine_spec.rb +35 -0
- data/spec/lib/appsignal/hooks_spec.rb +195 -0
- data/spec/lib/appsignal/integrations/data_mapper_spec.rb +65 -0
- data/spec/lib/appsignal/integrations/grape_spec.rb +225 -0
- data/spec/lib/appsignal/integrations/mongo_ruby_driver_spec.rb +127 -0
- data/spec/lib/appsignal/integrations/object_spec.rb +249 -0
- data/spec/lib/appsignal/integrations/padrino_spec.rb +323 -0
- data/spec/lib/appsignal/integrations/que_spec.rb +174 -0
- data/spec/lib/appsignal/integrations/railtie_spec.rb +129 -0
- data/spec/lib/appsignal/integrations/resque_active_job_spec.rb +83 -0
- data/spec/lib/appsignal/integrations/resque_spec.rb +92 -0
- data/spec/lib/appsignal/integrations/sinatra_spec.rb +73 -0
- data/spec/lib/appsignal/integrations/webmachine_spec.rb +69 -0
- data/spec/lib/appsignal/js_exception_transaction_spec.rb +128 -0
- data/spec/lib/appsignal/marker_spec.rb +51 -0
- data/spec/lib/appsignal/minutely_spec.rb +50 -0
- data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +90 -0
- data/spec/lib/appsignal/rack/js_exception_catcher_spec.rb +147 -0
- data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +117 -0
- data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +213 -0
- data/spec/lib/appsignal/rack/streaming_listener_spec.rb +161 -0
- data/spec/lib/appsignal/system_spec.rb +131 -0
- data/spec/lib/appsignal/transaction_spec.rb +1146 -0
- data/spec/lib/appsignal/transmitter_spec.rb +152 -0
- data/spec/lib/appsignal/utils/params_sanitizer_spec.rb +136 -0
- data/spec/lib/appsignal/utils/query_params_sanitizer_spec.rb +192 -0
- data/spec/lib/appsignal/utils_spec.rb +150 -0
- data/spec/lib/appsignal_spec.rb +1049 -0
- data/spec/spec_helper.rb +116 -0
- data/spec/support/fixtures/containers/cgroups/docker +14 -0
- data/spec/support/fixtures/containers/cgroups/docker_systemd +8 -0
- data/spec/support/fixtures/containers/cgroups/lxc +10 -0
- data/spec/support/fixtures/containers/cgroups/no_permission +0 -0
- data/spec/support/fixtures/containers/cgroups/none +1 -0
- data/spec/support/fixtures/generated_config.yml +24 -0
- data/spec/support/fixtures/uploaded_file.txt +0 -0
- data/spec/support/helpers/api_request_helper.rb +19 -0
- data/spec/support/helpers/cli_helpers.rb +26 -0
- data/spec/support/helpers/config_helpers.rb +21 -0
- data/spec/support/helpers/dependency_helper.rb +73 -0
- data/spec/support/helpers/directory_helper.rb +27 -0
- data/spec/support/helpers/env_helpers.rb +33 -0
- data/spec/support/helpers/example_exception.rb +13 -0
- data/spec/support/helpers/example_standard_error.rb +13 -0
- data/spec/support/helpers/log_helpers.rb +22 -0
- data/spec/support/helpers/std_streams_helper.rb +66 -0
- data/spec/support/helpers/system_helpers.rb +8 -0
- data/spec/support/helpers/time_helpers.rb +11 -0
- data/spec/support/helpers/transaction_helpers.rb +37 -0
- data/spec/support/matchers/contains_log.rb +7 -0
- data/spec/support/mocks/fake_gc_profiler.rb +19 -0
- data/spec/support/mocks/mock_extension.rb +6 -0
- data/spec/support/project_fixture/config/application.rb +0 -0
- data/spec/support/project_fixture/config/appsignal.yml +32 -0
- data/spec/support/project_fixture/config/environments/development.rb +0 -0
- data/spec/support/project_fixture/config/environments/production.rb +0 -0
- data/spec/support/project_fixture/config/environments/test.rb +0 -0
- data/spec/support/project_fixture/log/.gitkeep +0 -0
- data/spec/support/rails/my_app.rb +6 -0
- data/spec/support/shared_examples/instrument.rb +43 -0
- data/spec/support/stubs/delayed_job.rb +0 -0
- metadata +483 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
require "appsignal/integrations/mongo_ruby_driver"
|
|
2
|
+
describe Appsignal::Hooks::MongoMonitorSubscriber do
|
|
3
|
+
let(:subscriber) { Appsignal::Hooks::MongoMonitorSubscriber.new }
|
|
4
|
+
|
|
5
|
+
context "with transaction" do
|
|
6
|
+
let!(:transaction) do
|
|
7
|
+
Appsignal::Transaction.create("1", "http_request", {}, {})
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
describe "#started" do
|
|
11
|
+
let(:event) do
|
|
12
|
+
double(
|
|
13
|
+
:request_id => 1,
|
|
14
|
+
:command_name => "find",
|
|
15
|
+
:command => { "foo" => "bar" }
|
|
16
|
+
)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "should sanitize command" do
|
|
20
|
+
expect(Appsignal::EventFormatter::MongoRubyDriver::QueryFormatter)
|
|
21
|
+
.to receive(:format).with("find", "foo" => "bar")
|
|
22
|
+
|
|
23
|
+
subscriber.started(event)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "should store command on the transaction" do
|
|
27
|
+
subscriber.started(event)
|
|
28
|
+
|
|
29
|
+
expect(transaction.store("mongo_driver")).to eq(1 => { "foo" => "?" })
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "should start an event in the extension" do
|
|
33
|
+
expect(transaction).to receive(:start_event)
|
|
34
|
+
|
|
35
|
+
subscriber.started(event)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
describe "#succeeded" do
|
|
40
|
+
let(:event) { double }
|
|
41
|
+
|
|
42
|
+
it "should finish the event" do
|
|
43
|
+
expect(subscriber).to receive(:finish).with("SUCCEEDED", event)
|
|
44
|
+
|
|
45
|
+
subscriber.succeeded(event)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
describe "#failed" do
|
|
50
|
+
let(:event) { double }
|
|
51
|
+
|
|
52
|
+
it "should finish the event" do
|
|
53
|
+
expect(subscriber).to receive(:finish).with("FAILED", event)
|
|
54
|
+
|
|
55
|
+
subscriber.failed(event)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
describe "#finish" do
|
|
60
|
+
let(:command) { { "foo" => "?" } }
|
|
61
|
+
let(:event) do
|
|
62
|
+
double(
|
|
63
|
+
:request_id => 2,
|
|
64
|
+
:command_name => :find,
|
|
65
|
+
:database_name => "test"
|
|
66
|
+
)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
before do
|
|
70
|
+
store = transaction.store("mongo_driver")
|
|
71
|
+
store[2] = command
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it "should get the query from the store" do
|
|
75
|
+
expect(transaction).to receive(:store).with("mongo_driver").and_return(command)
|
|
76
|
+
|
|
77
|
+
subscriber.finish("SUCCEEDED", event)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it "should finish the transaction in the extension" do
|
|
81
|
+
expect(transaction).to receive(:finish_event).with(
|
|
82
|
+
"query.mongodb",
|
|
83
|
+
"find | test | SUCCEEDED",
|
|
84
|
+
Appsignal::Utils.data_generate("foo" => "?"),
|
|
85
|
+
0
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
subscriber.finish("SUCCEEDED", event)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
context "without transaction" do
|
|
94
|
+
before do
|
|
95
|
+
allow(Appsignal::Transaction).to receive(:current).and_return(Appsignal::Transaction::NilTransaction.new)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it "should not attempt to start an event" do
|
|
99
|
+
expect(Appsignal::Extension).to_not receive(:start_event)
|
|
100
|
+
|
|
101
|
+
subscriber.started(double)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
it "should not attempt to finish an event" do
|
|
105
|
+
expect(Appsignal::Extension).to_not receive(:finish_event)
|
|
106
|
+
|
|
107
|
+
subscriber.finish("SUCCEEDED", double)
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
context "when appsignal is paused" do
|
|
112
|
+
let(:transaction) { double(:paused? => true, :nil_transaction? => false) }
|
|
113
|
+
before { allow(Appsignal::Transaction).to receive(:current).and_return(transaction) }
|
|
114
|
+
|
|
115
|
+
it "should not attempt to start an event" do
|
|
116
|
+
expect(Appsignal::Extension).to_not receive(:start_event)
|
|
117
|
+
|
|
118
|
+
subscriber.started(double)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it "should not attempt to finish an event" do
|
|
122
|
+
expect(Appsignal::Extension).to_not receive(:finish_event)
|
|
123
|
+
|
|
124
|
+
subscriber.finish("SUCCEEDED", double)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
require "appsignal/integrations/object"
|
|
2
|
+
|
|
3
|
+
describe Object do
|
|
4
|
+
describe "#instrument_method" do
|
|
5
|
+
context "with instance method" do
|
|
6
|
+
let(:klass) do
|
|
7
|
+
Class.new do
|
|
8
|
+
def foo
|
|
9
|
+
1
|
|
10
|
+
end
|
|
11
|
+
appsignal_instrument_method :foo
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
let(:instance) { klass.new }
|
|
15
|
+
|
|
16
|
+
context "when active" do
|
|
17
|
+
let(:transaction) { http_request_transaction }
|
|
18
|
+
before do
|
|
19
|
+
expect(Appsignal::Transaction).to receive(:current).at_least(:once).and_return(transaction)
|
|
20
|
+
Appsignal.config = project_fixture_config
|
|
21
|
+
end
|
|
22
|
+
after { Appsignal.config = nil }
|
|
23
|
+
|
|
24
|
+
context "with anonymous class" do
|
|
25
|
+
it "instruments the method and calls it" do
|
|
26
|
+
expect(Appsignal.active?).to be_truthy
|
|
27
|
+
expect(transaction).to receive(:start_event)
|
|
28
|
+
expect(transaction).to receive(:finish_event).with \
|
|
29
|
+
"foo.AnonymousClass.other", nil, nil, Appsignal::EventFormatter::DEFAULT
|
|
30
|
+
expect(instance.foo).to eq(1)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
context "with named class" do
|
|
35
|
+
before do
|
|
36
|
+
class NamedClass
|
|
37
|
+
def foo
|
|
38
|
+
1
|
|
39
|
+
end
|
|
40
|
+
appsignal_instrument_method :foo
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
after { Object.send(:remove_const, :NamedClass) }
|
|
44
|
+
let(:klass) { NamedClass }
|
|
45
|
+
|
|
46
|
+
it "instruments the method and calls it" do
|
|
47
|
+
expect(Appsignal.active?).to be_truthy
|
|
48
|
+
expect(transaction).to receive(:start_event)
|
|
49
|
+
expect(transaction).to receive(:finish_event).with \
|
|
50
|
+
"foo.NamedClass.other", nil, nil, Appsignal::EventFormatter::DEFAULT
|
|
51
|
+
expect(instance.foo).to eq(1)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
context "with nested named class" do
|
|
56
|
+
before do
|
|
57
|
+
module MyModule
|
|
58
|
+
module NestedModule
|
|
59
|
+
class NamedClass
|
|
60
|
+
def bar
|
|
61
|
+
2
|
|
62
|
+
end
|
|
63
|
+
appsignal_instrument_method :bar
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
after { Object.send(:remove_const, :MyModule) }
|
|
69
|
+
let(:klass) { MyModule::NestedModule::NamedClass }
|
|
70
|
+
|
|
71
|
+
it "instruments the method and calls it" do
|
|
72
|
+
expect(Appsignal.active?).to be_truthy
|
|
73
|
+
expect(transaction).to receive(:start_event)
|
|
74
|
+
expect(transaction).to receive(:finish_event).with \
|
|
75
|
+
"bar.NamedClass.NestedModule.MyModule.other", nil, nil,
|
|
76
|
+
Appsignal::EventFormatter::DEFAULT
|
|
77
|
+
expect(instance.bar).to eq(2)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
context "with custom name" do
|
|
82
|
+
let(:klass) do
|
|
83
|
+
Class.new do
|
|
84
|
+
def foo
|
|
85
|
+
1
|
|
86
|
+
end
|
|
87
|
+
appsignal_instrument_method :foo, :name => "my_method.group"
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it "instruments with custom name" do
|
|
92
|
+
expect(Appsignal.active?).to be_truthy
|
|
93
|
+
expect(transaction).to receive(:start_event)
|
|
94
|
+
expect(transaction).to receive(:finish_event).with \
|
|
95
|
+
"my_method.group", nil, nil, Appsignal::EventFormatter::DEFAULT
|
|
96
|
+
expect(instance.foo).to eq(1)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
context "with a method given a block" do
|
|
101
|
+
let(:klass) do
|
|
102
|
+
Class.new do
|
|
103
|
+
def foo
|
|
104
|
+
yield
|
|
105
|
+
end
|
|
106
|
+
appsignal_instrument_method :foo
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
it "should yield the block" do
|
|
111
|
+
expect(instance.foo { 42 }).to eq(42)
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
context "when not active" do
|
|
117
|
+
let(:transaction) { Appsignal::Transaction.current }
|
|
118
|
+
|
|
119
|
+
it "should not instrument, but still call the method" do
|
|
120
|
+
expect(Appsignal.active?).to be_falsy
|
|
121
|
+
expect(transaction).to_not receive(:start_event)
|
|
122
|
+
expect(instance.foo).to eq(1)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
context "with class method" do
|
|
128
|
+
let(:klass) do
|
|
129
|
+
Class.new do
|
|
130
|
+
def self.bar
|
|
131
|
+
2
|
|
132
|
+
end
|
|
133
|
+
appsignal_instrument_class_method :bar
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
context "when active" do
|
|
138
|
+
let(:transaction) { http_request_transaction }
|
|
139
|
+
before do
|
|
140
|
+
expect(Appsignal::Transaction).to receive(:current).at_least(:once)
|
|
141
|
+
.and_return(transaction)
|
|
142
|
+
Appsignal.config = project_fixture_config
|
|
143
|
+
end
|
|
144
|
+
after { Appsignal.config = nil }
|
|
145
|
+
|
|
146
|
+
context "with anonymous class" do
|
|
147
|
+
it "instruments the method and calls it" do
|
|
148
|
+
expect(Appsignal.active?).to be_truthy
|
|
149
|
+
expect(transaction).to receive(:start_event)
|
|
150
|
+
expect(transaction).to receive(:finish_event).with \
|
|
151
|
+
"bar.class_method.AnonymousClass.other", nil, nil, Appsignal::EventFormatter::DEFAULT
|
|
152
|
+
expect(klass.bar).to eq(2)
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
context "with named class" do
|
|
157
|
+
before do
|
|
158
|
+
class NamedClass
|
|
159
|
+
def self.bar
|
|
160
|
+
2
|
|
161
|
+
end
|
|
162
|
+
appsignal_instrument_class_method :bar
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
after { Object.send(:remove_const, :NamedClass) }
|
|
166
|
+
let(:klass) { NamedClass }
|
|
167
|
+
|
|
168
|
+
it "instruments the method and calls it" do
|
|
169
|
+
expect(Appsignal.active?).to be_truthy
|
|
170
|
+
expect(transaction).to receive(:start_event)
|
|
171
|
+
expect(transaction).to receive(:finish_event).with \
|
|
172
|
+
"bar.class_method.NamedClass.other", nil, nil, Appsignal::EventFormatter::DEFAULT
|
|
173
|
+
expect(klass.bar).to eq(2)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
context "with nested named class" do
|
|
177
|
+
before do
|
|
178
|
+
module MyModule
|
|
179
|
+
module NestedModule
|
|
180
|
+
class NamedClass
|
|
181
|
+
def self.bar
|
|
182
|
+
2
|
|
183
|
+
end
|
|
184
|
+
appsignal_instrument_class_method :bar
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
after { Object.send(:remove_const, :MyModule) }
|
|
190
|
+
let(:klass) { MyModule::NestedModule::NamedClass }
|
|
191
|
+
|
|
192
|
+
it "instruments the method and calls it" do
|
|
193
|
+
expect(Appsignal.active?).to be_truthy
|
|
194
|
+
expect(transaction).to receive(:start_event)
|
|
195
|
+
expect(transaction).to receive(:finish_event).with \
|
|
196
|
+
"bar.class_method.NamedClass.NestedModule.MyModule.other", nil, nil,
|
|
197
|
+
Appsignal::EventFormatter::DEFAULT
|
|
198
|
+
expect(klass.bar).to eq(2)
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
context "with custom name" do
|
|
204
|
+
let(:klass) do
|
|
205
|
+
Class.new do
|
|
206
|
+
def self.bar
|
|
207
|
+
2
|
|
208
|
+
end
|
|
209
|
+
appsignal_instrument_class_method :bar, :name => "my_method.group"
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
it "instruments with custom name" do
|
|
214
|
+
expect(Appsignal.active?).to be_truthy
|
|
215
|
+
expect(transaction).to receive(:start_event)
|
|
216
|
+
expect(transaction).to receive(:finish_event).with \
|
|
217
|
+
"my_method.group", nil, nil, Appsignal::EventFormatter::DEFAULT
|
|
218
|
+
expect(klass.bar).to eq(2)
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
context "with a method given a block" do
|
|
223
|
+
let(:klass) do
|
|
224
|
+
Class.new do
|
|
225
|
+
def self.bar
|
|
226
|
+
yield
|
|
227
|
+
end
|
|
228
|
+
appsignal_instrument_class_method :bar
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
it "should yield the block" do
|
|
233
|
+
expect(klass.bar { 42 }).to eq(42)
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
context "when not active" do
|
|
239
|
+
let(:transaction) { Appsignal::Transaction.current }
|
|
240
|
+
|
|
241
|
+
it "should not instrument, but still call the method" do
|
|
242
|
+
expect(Appsignal.active?).to be_falsy
|
|
243
|
+
expect(transaction).to_not receive(:start_event)
|
|
244
|
+
expect(klass.bar).to eq(2)
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
end
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
if DependencyHelper.padrino_present?
|
|
2
|
+
describe "Padrino integration" do
|
|
3
|
+
require "appsignal/integrations/padrino"
|
|
4
|
+
|
|
5
|
+
before do
|
|
6
|
+
allow(Appsignal).to receive(:active?).and_return(true)
|
|
7
|
+
allow(Appsignal).to receive(:start).and_return(true)
|
|
8
|
+
allow(Appsignal).to receive(:start_logger).and_return(true)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe Appsignal::Integrations::PadrinoPlugin do
|
|
12
|
+
it "starts AppSignal on init" do
|
|
13
|
+
expect(Appsignal).to receive(:start)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "starts the logger on init" do
|
|
17
|
+
expect(Appsignal).to receive(:start_logger)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
context "when not active" do
|
|
21
|
+
before { allow(Appsignal).to receive(:active?).and_return(false) }
|
|
22
|
+
|
|
23
|
+
it "does not add the listener middleware to the stack" do
|
|
24
|
+
expect(Padrino).to_not receive(:use)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
context "when APPSIGNAL_APP_ENV ENV var is provided" do
|
|
29
|
+
it "uses this as the environment" do
|
|
30
|
+
ENV["APPSIGNAL_APP_ENV"] = "custom"
|
|
31
|
+
|
|
32
|
+
# Reset the plugin to pull down the latest data
|
|
33
|
+
Appsignal::Integrations::PadrinoPlugin.init
|
|
34
|
+
|
|
35
|
+
expect(Appsignal.config.env).to eq("custom")
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
context "when APPSIGNAL_APP_ENV ENV var is not provided" do
|
|
40
|
+
it "uses the Padrino environment" do
|
|
41
|
+
# Reset the plugin to pull down the latest data
|
|
42
|
+
Appsignal::Integrations::PadrinoPlugin.init
|
|
43
|
+
|
|
44
|
+
expect(Padrino.env.to_s).to eq("test")
|
|
45
|
+
expect(Appsignal.config.env).to eq(Padrino.env.to_s)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
after { Appsignal::Integrations::PadrinoPlugin.init }
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
describe Padrino::Routing::InstanceMethods do
|
|
53
|
+
class PadrinoClassWithRouter
|
|
54
|
+
include Padrino::Routing
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
let(:base) { double }
|
|
58
|
+
let(:router) { PadrinoClassWithRouter.new }
|
|
59
|
+
let(:env) { {} }
|
|
60
|
+
# TODO: use an instance double
|
|
61
|
+
let(:settings) { double(:name => "TestApp") }
|
|
62
|
+
|
|
63
|
+
describe "routes" do
|
|
64
|
+
let(:transaction) do
|
|
65
|
+
instance_double "Appsignal::Transaction",
|
|
66
|
+
:set_http_or_background_action => nil,
|
|
67
|
+
:set_http_or_background_queue_start => nil,
|
|
68
|
+
:set_metadata => nil,
|
|
69
|
+
:set_action => nil,
|
|
70
|
+
:set_action_if_nil => nil,
|
|
71
|
+
:set_error => nil,
|
|
72
|
+
:start_event => nil,
|
|
73
|
+
:finish_event => nil,
|
|
74
|
+
:complete => nil
|
|
75
|
+
end
|
|
76
|
+
let(:request_kind) { kind_of(Sinatra::Request) }
|
|
77
|
+
let(:env) do
|
|
78
|
+
{
|
|
79
|
+
"REQUEST_METHOD" => "GET",
|
|
80
|
+
"PATH_INFO" => path,
|
|
81
|
+
"REQUEST_PATH" => path,
|
|
82
|
+
"rack.input" => StringIO.new
|
|
83
|
+
}
|
|
84
|
+
end
|
|
85
|
+
let(:app) do
|
|
86
|
+
Class.new(Padrino::Application) do
|
|
87
|
+
def self.name
|
|
88
|
+
"PadrinoTestApp"
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
let(:response) { app.call(env) }
|
|
93
|
+
before do
|
|
94
|
+
allow(Appsignal::Transaction).to receive(:create).and_return(transaction)
|
|
95
|
+
allow(Appsignal::Transaction).to receive(:current).and_return(transaction)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
RSpec::Matchers.define :match_response do |expected_status, expected_content|
|
|
99
|
+
match do |response|
|
|
100
|
+
status, _headers, content = response
|
|
101
|
+
status == expected_status && content == [expected_content].compact
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def expect_a_transaction_to_be_created
|
|
106
|
+
expect(Appsignal::Transaction).to receive(:create).with(
|
|
107
|
+
kind_of(String),
|
|
108
|
+
Appsignal::Transaction::HTTP_REQUEST,
|
|
109
|
+
request_kind
|
|
110
|
+
).and_return(transaction)
|
|
111
|
+
|
|
112
|
+
expect(Appsignal).to receive(:instrument)
|
|
113
|
+
.at_least(:once)
|
|
114
|
+
.with("process_action.padrino")
|
|
115
|
+
.and_call_original
|
|
116
|
+
expect(transaction).to receive(:set_metadata).with("path", path)
|
|
117
|
+
expect(transaction).to receive(:set_metadata).with("method", "GET")
|
|
118
|
+
expect(transaction).to receive(:complete)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def expect_no_transaction_to_be_created
|
|
122
|
+
expect(Appsignal::Transaction).to_not receive(:create)
|
|
123
|
+
expect(Appsignal).to_not receive(:instrument)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
context "when AppSignal is not active" do
|
|
127
|
+
before { allow(Appsignal).to receive(:active?).and_return(false) }
|
|
128
|
+
let(:path) { "/foo" }
|
|
129
|
+
before { app.controllers { get(:foo) { "content" } } }
|
|
130
|
+
after { expect(response).to match_response(200, "content") }
|
|
131
|
+
|
|
132
|
+
it "does not instrument the request" do
|
|
133
|
+
expect_no_transaction_to_be_created
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
context "when AppSignal is active" do
|
|
138
|
+
context "with not existing route" do
|
|
139
|
+
let(:path) { "/404" }
|
|
140
|
+
|
|
141
|
+
it "instruments the request" do
|
|
142
|
+
expect_a_transaction_to_be_created
|
|
143
|
+
# Uses path for action name
|
|
144
|
+
expect(transaction).to receive(:set_action_if_nil).with("PadrinoTestApp:#/404")
|
|
145
|
+
expect(response).to match_response(404, "<h1>Not Found</h1>")
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
context "when Sinatra tells us it's a static file" do
|
|
150
|
+
let(:path) { "/static" }
|
|
151
|
+
before do
|
|
152
|
+
env["sinatra.static_file"] = true
|
|
153
|
+
expect_any_instance_of(app)
|
|
154
|
+
.to receive(:route_without_appsignal).and_return([200, {}, ["foo"]])
|
|
155
|
+
end
|
|
156
|
+
after { expect(response).to match_response(200, "foo") }
|
|
157
|
+
|
|
158
|
+
it "does not instrument the request" do
|
|
159
|
+
expect_no_transaction_to_be_created
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Older Padrino versions don't support `action` (v11.0+)
|
|
164
|
+
context "without #action on Sinatra::Request" do
|
|
165
|
+
let(:path) { "/my_original_path" }
|
|
166
|
+
let(:request_kind) do
|
|
167
|
+
double(
|
|
168
|
+
:params => {},
|
|
169
|
+
:path => path,
|
|
170
|
+
:path_info => path,
|
|
171
|
+
:request_method => "GET",
|
|
172
|
+
:head? => false,
|
|
173
|
+
:route_obj => double(:original_path => "original_path method"),
|
|
174
|
+
:route_obj= => nil # Make sure route_obj doesn't get overwritten
|
|
175
|
+
)
|
|
176
|
+
end
|
|
177
|
+
before do
|
|
178
|
+
expect(Sinatra::Request).to receive(:new).and_return(request_kind)
|
|
179
|
+
app.controllers { get(:my_original_path) { "content" } }
|
|
180
|
+
end
|
|
181
|
+
after { expect(response).to match_response(200, "content") }
|
|
182
|
+
|
|
183
|
+
it "falls back on Sinatra::Request#route_obj.original_path" do
|
|
184
|
+
expect_a_transaction_to_be_created
|
|
185
|
+
expect(transaction)
|
|
186
|
+
.to receive(:set_action_if_nil).with("PadrinoTestApp:original_path method")
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
context "without Sinatra::Request#route_obj.original_path" do
|
|
191
|
+
let(:path) { "/my_original_path" }
|
|
192
|
+
let(:request_kind) do
|
|
193
|
+
double(
|
|
194
|
+
:params => {},
|
|
195
|
+
:path => path,
|
|
196
|
+
:path_info => path,
|
|
197
|
+
:request_method => "GET",
|
|
198
|
+
:head? => false,
|
|
199
|
+
:route_obj= => nil # Make sure route_obj doesn't get overwritten
|
|
200
|
+
)
|
|
201
|
+
end
|
|
202
|
+
before do
|
|
203
|
+
expect(Sinatra::Request).to receive(:new).and_return(request_kind)
|
|
204
|
+
app.controllers { get(:my_original_path) { "content" } }
|
|
205
|
+
end
|
|
206
|
+
after { expect(response).to match_response(200, "content") }
|
|
207
|
+
|
|
208
|
+
it "falls back on app name" do
|
|
209
|
+
expect_a_transaction_to_be_created
|
|
210
|
+
expect(transaction).to receive(:set_action_if_nil).with("PadrinoTestApp")
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
context "with existing route" do
|
|
215
|
+
context "with an exception in the controller" do
|
|
216
|
+
let(:path) { "/exception" }
|
|
217
|
+
before do
|
|
218
|
+
app.controllers { get(:exception) { raise ExampleException } }
|
|
219
|
+
expect_a_transaction_to_be_created
|
|
220
|
+
end
|
|
221
|
+
after do
|
|
222
|
+
expect { response }.to raise_error(ExampleException)
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
it "sets the action name based on the app name and action name" do
|
|
226
|
+
expect(transaction).to receive(:set_action_if_nil).with("PadrinoTestApp:#exception")
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
it "sets the error on the transaction" do
|
|
230
|
+
expect(transaction).to receive(:set_error).with(ExampleException)
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
context "without an exception in the controller" do
|
|
235
|
+
let(:path) { "/" }
|
|
236
|
+
after { expect(response).to match_response(200, "content") }
|
|
237
|
+
|
|
238
|
+
context "with action name as symbol" do
|
|
239
|
+
context "with :index helper" do
|
|
240
|
+
before do
|
|
241
|
+
# :index == "/"
|
|
242
|
+
app.controllers { get(:index) { "content" } }
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
it "sets the action with the app name and action name" do
|
|
246
|
+
expect_a_transaction_to_be_created
|
|
247
|
+
expect(transaction).to receive(:set_action_if_nil).with("PadrinoTestApp:#index")
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
context "with custom action name" do
|
|
252
|
+
let(:path) { "/foo" }
|
|
253
|
+
before do
|
|
254
|
+
app.controllers { get(:foo) { "content" } }
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
it "sets the action with the app name and action name" do
|
|
258
|
+
expect_a_transaction_to_be_created
|
|
259
|
+
expect(transaction).to receive(:set_action_if_nil).with("PadrinoTestApp:#foo")
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
context "with an action defined with a path" do
|
|
265
|
+
context "with root path" do
|
|
266
|
+
before do
|
|
267
|
+
# :index == "/"
|
|
268
|
+
app.controllers { get("/") { "content" } }
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
it "sets the action with the app name and action path" do
|
|
272
|
+
expect_a_transaction_to_be_created
|
|
273
|
+
expect(transaction).to receive(:set_action_if_nil).with("PadrinoTestApp:#/")
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
context "with custom path" do
|
|
278
|
+
let(:path) { "/foo" }
|
|
279
|
+
before do
|
|
280
|
+
app.controllers { get("/foo") { "content" } }
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
it "sets the action with the app name and action path" do
|
|
284
|
+
expect_a_transaction_to_be_created
|
|
285
|
+
expect(transaction).to receive(:set_action_if_nil).with("PadrinoTestApp:#/foo")
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
context "with controller" do
|
|
291
|
+
let(:path) { "/my_controller" }
|
|
292
|
+
|
|
293
|
+
context "with controller as name" do
|
|
294
|
+
before do
|
|
295
|
+
# :index == "/"
|
|
296
|
+
app.controllers(:my_controller) { get(:index) { "content" } }
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
it "sets the action with the app name, controller name and action name" do
|
|
300
|
+
expect_a_transaction_to_be_created
|
|
301
|
+
expect(transaction).to receive(:set_action_if_nil).with("PadrinoTestApp:my_controller#index")
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
context "with controller as path" do
|
|
306
|
+
before do
|
|
307
|
+
# :index == "/"
|
|
308
|
+
app.controllers("/my_controller") { get(:index) { "content" } }
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
it "sets the action with the app name, controller name and action path" do
|
|
312
|
+
expect_a_transaction_to_be_created
|
|
313
|
+
expect(transaction).to receive(:set_action_if_nil).with("PadrinoTestApp:/my_controller#index")
|
|
314
|
+
end
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
end
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
end
|