appsignal 2.9.2.alpha.1 → 2.9.18.beta.2
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 +5 -5
- data/.github/ISSUE_TEMPLATE/bug_report.md +31 -0
- data/.github/ISSUE_TEMPLATE/chore.md +14 -0
- data/.gitignore +1 -2
- data/.rubocop.yml +3 -0
- data/.travis.yml +25 -27
- data/CHANGELOG.md +632 -535
- data/README.md +8 -3
- data/Rakefile +118 -122
- data/SUPPORT.md +16 -0
- data/appsignal.gemspec +14 -4
- data/build_matrix.yml +16 -8
- data/ext/Rakefile +2 -3
- data/ext/agent.yml +40 -37
- data/ext/base.rb +37 -14
- data/ext/extconf.rb +3 -4
- data/gemfiles/capistrano2.gemfile +5 -0
- data/gemfiles/capistrano3.gemfile +5 -0
- data/gemfiles/grape.gemfile +5 -0
- data/gemfiles/no_dependencies.gemfile +5 -0
- data/gemfiles/padrino.gemfile +5 -0
- data/gemfiles/que.gemfile +5 -0
- data/gemfiles/que_beta.gemfile +10 -0
- data/gemfiles/rails-3.2.gemfile +5 -0
- data/gemfiles/rails-4.0.gemfile +5 -0
- data/gemfiles/rails-4.1.gemfile +5 -0
- data/gemfiles/rails-4.2.gemfile +5 -0
- data/gemfiles/rails-6.0.gemfile +1 -1
- data/gemfiles/resque.gemfile +5 -0
- data/lib/appsignal.rb +1 -4
- data/lib/appsignal/cli/demo.rb +5 -2
- data/lib/appsignal/cli/diagnose/utils.rb +2 -0
- data/lib/appsignal/cli/install.rb +34 -10
- data/lib/appsignal/cli/notify_of_deploy.rb +10 -0
- data/lib/appsignal/config.rb +5 -2
- data/lib/appsignal/event_formatter/action_view/render_formatter.rb +10 -8
- data/lib/appsignal/helpers/instrumentation.rb +18 -9
- data/lib/appsignal/helpers/metrics.rb +0 -1
- data/lib/appsignal/hooks.rb +3 -1
- data/lib/appsignal/hooks/active_support_notifications.rb +2 -5
- data/lib/appsignal/hooks/puma.rb +15 -13
- data/lib/appsignal/hooks/sequel.rb +1 -1
- data/lib/appsignal/hooks/sidekiq.rb +33 -8
- data/lib/appsignal/integrations/que.rb +9 -8
- data/lib/appsignal/minutely.rb +38 -19
- data/lib/appsignal/transaction.rb +5 -0
- data/lib/appsignal/utils/rails_helper.rb +4 -0
- data/lib/appsignal/version.rb +1 -1
- data/lib/puma/plugin/appsignal.rb +26 -0
- data/spec/lib/appsignal/cli/diagnose/utils_spec.rb +40 -0
- data/spec/lib/appsignal/cli/install_spec.rb +51 -7
- data/spec/lib/appsignal/cli/notify_of_deploy_spec.rb +10 -0
- data/spec/lib/appsignal/config_spec.rb +13 -8
- data/spec/lib/appsignal/event_formatter/action_view/render_formatter_spec.rb +38 -28
- data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +104 -25
- data/spec/lib/appsignal/hooks/puma_spec.rb +69 -39
- data/spec/lib/appsignal/hooks/sidekiq_spec.rb +65 -3
- data/spec/lib/appsignal/hooks_spec.rb +4 -0
- data/spec/lib/appsignal/minutely_spec.rb +150 -88
- data/spec/lib/appsignal/transaction_spec.rb +27 -4
- data/spec/lib/appsignal_spec.rb +62 -11
- data/spec/lib/puma/appsignal_spec.rb +91 -0
- data/spec/support/{project_fixture → fixtures/projects/valid}/config/application.rb +0 -0
- data/spec/support/{project_fixture → fixtures/projects/valid}/config/appsignal.yml +0 -0
- data/spec/support/{project_fixture → fixtures/projects/valid}/config/environments/development.rb +0 -0
- data/spec/support/{project_fixture → fixtures/projects/valid}/config/environments/production.rb +0 -0
- data/spec/support/{project_fixture → fixtures/projects/valid}/config/environments/test.rb +0 -0
- data/spec/support/{project_fixture → fixtures/projects/valid}/log/.gitkeep +0 -0
- data/spec/support/helpers/config_helpers.rb +1 -1
- data/spec/support/helpers/wait_for_helper.rb +28 -0
- data/spec/support/mocks/mock_probe.rb +11 -0
- metadata +38 -30
- data/spec/support/fixtures/containers/cgroups/docker +0 -14
- data/spec/support/fixtures/containers/cgroups/docker_systemd +0 -8
- data/spec/support/fixtures/containers/cgroups/lxc +0 -10
- data/spec/support/fixtures/containers/cgroups/no_permission +0 -0
- data/spec/support/fixtures/containers/cgroups/none +0 -1
data/lib/appsignal/version.rb
CHANGED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
APPSIGNAL_PUMA_PLUGIN_LOADED = true
|
|
2
|
+
|
|
3
|
+
# AppSignal Puma plugin
|
|
4
|
+
#
|
|
5
|
+
# This plugin ensures the minutely probe thread is started with the Puma
|
|
6
|
+
# minutely probe in the Puma master process.
|
|
7
|
+
#
|
|
8
|
+
# The constant {APPSIGNAL_PUMA_PLUGIN_LOADED} is here to mark the Plugin as
|
|
9
|
+
# loaded by the rest of the AppSignal gem. This ensures that the Puma minutely
|
|
10
|
+
# probe is not also started in every Puma workers, which was the old behavior.
|
|
11
|
+
# See {Appsignal::Hooks::PumaHook#install} for more information.
|
|
12
|
+
#
|
|
13
|
+
# For even more information:
|
|
14
|
+
# https://docs.appsignal.com/ruby/integrations/puma.html
|
|
15
|
+
Puma::Plugin.create do
|
|
16
|
+
def start(launcher = nil)
|
|
17
|
+
launcher.events.on_booted do
|
|
18
|
+
require "appsignal"
|
|
19
|
+
if ::Puma.respond_to?(:stats)
|
|
20
|
+
Appsignal::Minutely.probes.register :puma, Appsignal::Hooks::PumaProbe
|
|
21
|
+
end
|
|
22
|
+
Appsignal.start
|
|
23
|
+
Appsignal.start_logger
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -1,6 +1,46 @@
|
|
|
1
1
|
require "appsignal/cli/diagnose/utils"
|
|
2
2
|
|
|
3
3
|
describe Appsignal::CLI::Diagnose::Utils do
|
|
4
|
+
describe ".username_for_uid" do
|
|
5
|
+
subject { described_class.username_for_uid(uid) }
|
|
6
|
+
|
|
7
|
+
context "when user with id exists" do
|
|
8
|
+
let(:uid) { 0 }
|
|
9
|
+
|
|
10
|
+
it "returns username" do
|
|
11
|
+
is_expected.to be_kind_of(String)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
context "when user with id does not exist" do
|
|
16
|
+
let(:uid) { -1 }
|
|
17
|
+
|
|
18
|
+
it "returns nil" do
|
|
19
|
+
is_expected.to be_nil
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
describe ".group_for_gid" do
|
|
25
|
+
subject { described_class.group_for_gid(uid) }
|
|
26
|
+
|
|
27
|
+
context "when group with id exists" do
|
|
28
|
+
let(:uid) { 0 }
|
|
29
|
+
|
|
30
|
+
it "returns group name" do
|
|
31
|
+
is_expected.to be_kind_of(String)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
context "when group with id does not exist" do
|
|
36
|
+
let(:uid) { -3 }
|
|
37
|
+
|
|
38
|
+
it "returns nil" do
|
|
39
|
+
is_expected.to be_nil
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
4
44
|
describe ".read_file_content" do
|
|
5
45
|
let(:path) { File.join(spec_system_tmp_dir, "test_file.txt") }
|
|
6
46
|
let(:bytes_to_read) { 100 }
|
|
@@ -16,6 +16,10 @@ describe Appsignal::CLI::Install do
|
|
|
16
16
|
allow(described_class).to receive(:press_any_key)
|
|
17
17
|
allow(Appsignal::Demo).to receive(:transmit).and_return(true)
|
|
18
18
|
end
|
|
19
|
+
after do
|
|
20
|
+
FileUtils.rm_rf(tmp_dir)
|
|
21
|
+
FileUtils.mkdir_p(tmp_dir)
|
|
22
|
+
end
|
|
19
23
|
around do |example|
|
|
20
24
|
original_stdin = $stdin
|
|
21
25
|
$stdin = StringIO.new
|
|
@@ -157,16 +161,10 @@ describe Appsignal::CLI::Install do
|
|
|
157
161
|
shared_examples "capistrano install" do
|
|
158
162
|
let(:capfile) { File.join(tmp_dir, "Capfile") }
|
|
159
163
|
before do
|
|
160
|
-
FileUtils.mkdir_p(tmp_dir)
|
|
161
|
-
|
|
162
164
|
enter_app_name "foo"
|
|
163
165
|
add_cli_input "n"
|
|
164
166
|
choose_environment_config
|
|
165
167
|
end
|
|
166
|
-
after do
|
|
167
|
-
FileUtils.rm_rf(tmp_dir)
|
|
168
|
-
FileUtils.mkdir_p(tmp_dir)
|
|
169
|
-
end
|
|
170
168
|
|
|
171
169
|
context "without Capfile" do
|
|
172
170
|
it "does nothing" do
|
|
@@ -260,7 +258,6 @@ describe Appsignal::CLI::Install do
|
|
|
260
258
|
FileUtils.touch(File.join(environments_dir, "development.rb"))
|
|
261
259
|
FileUtils.touch(File.join(environments_dir, "staging.rb"))
|
|
262
260
|
FileUtils.touch(File.join(environments_dir, "production.rb"))
|
|
263
|
-
enter_app_name app_name
|
|
264
261
|
end
|
|
265
262
|
|
|
266
263
|
describe "environments" do
|
|
@@ -410,6 +407,53 @@ describe Appsignal::CLI::Install do
|
|
|
410
407
|
end
|
|
411
408
|
end
|
|
412
409
|
end
|
|
410
|
+
|
|
411
|
+
context "when there is no Rails application.rb file" do
|
|
412
|
+
before do
|
|
413
|
+
# Do not detect it as another framework for testing
|
|
414
|
+
allow(described_class).to receive(:framework_available?).and_call_original
|
|
415
|
+
allow(described_class).to receive(:framework_available?).with("sinatra").and_return(false)
|
|
416
|
+
|
|
417
|
+
File.delete(File.join(config_dir, "application.rb"))
|
|
418
|
+
expect(File.exist?(File.join(config_dir, "application.rb"))).to eql(false)
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
it "fails the installation" do
|
|
422
|
+
run
|
|
423
|
+
|
|
424
|
+
expect(output).to include("We could not detect which framework you are using.")
|
|
425
|
+
expect(output).to_not include("Installing for Ruby on Rails")
|
|
426
|
+
expect(output).to include_complete_install
|
|
427
|
+
|
|
428
|
+
expect(File.exist?(config_file_path)).to be(false)
|
|
429
|
+
end
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
context "when failed to load the Rails application.rb file" do
|
|
433
|
+
before do
|
|
434
|
+
File.open(File.join(config_dir, "application.rb"), "w") do |file|
|
|
435
|
+
file.write("I am invalid code")
|
|
436
|
+
end
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
it "prompts the user to fill in an app name" do
|
|
440
|
+
enter_app_name app_name
|
|
441
|
+
choose_config_file
|
|
442
|
+
run
|
|
443
|
+
|
|
444
|
+
expect(output).to include("Installing for Ruby on Rails")
|
|
445
|
+
expect(output).to include("Unable to automatically detect your Rails app's name.")
|
|
446
|
+
expect(output).to include("Choose your app's display name for AppSignal.com:")
|
|
447
|
+
expect(output).to include_file_config
|
|
448
|
+
expect(output).to include_complete_install
|
|
449
|
+
|
|
450
|
+
expect(config_file).to configure_app_name(app_name)
|
|
451
|
+
expect(config_file).to configure_push_api_key(push_api_key)
|
|
452
|
+
expect(config_file).to configure_environment("development")
|
|
453
|
+
expect(config_file).to configure_environment("staging")
|
|
454
|
+
expect(config_file).to configure_environment("production")
|
|
455
|
+
end
|
|
456
|
+
end
|
|
413
457
|
end
|
|
414
458
|
end
|
|
415
459
|
|
|
@@ -116,6 +116,9 @@ describe Appsignal::CLI::NotifyOfDeploy do
|
|
|
116
116
|
|
|
117
117
|
context "with required options" do
|
|
118
118
|
let(:options) { { :environment => "production", :revision => "aaaaa", :user => "thijs" } }
|
|
119
|
+
let(:log_stream) { std_stream }
|
|
120
|
+
let(:log) { log_contents(log_stream) }
|
|
121
|
+
before { Appsignal.logger = test_logger(log_stream) }
|
|
119
122
|
|
|
120
123
|
it "notifies of a deploy" do
|
|
121
124
|
run
|
|
@@ -124,6 +127,13 @@ describe Appsignal::CLI::NotifyOfDeploy do
|
|
|
124
127
|
expect(output).to include_deploy_notification_with(options)
|
|
125
128
|
end
|
|
126
129
|
|
|
130
|
+
it "prints a deprecation message" do
|
|
131
|
+
run
|
|
132
|
+
deprecation_message = "This command (appsignal notify_of_deploy) has been deprecated"
|
|
133
|
+
expect(output).to include("appsignal WARNING: #{deprecation_message}")
|
|
134
|
+
expect(log).to contains_log :warn, deprecation_message
|
|
135
|
+
end
|
|
136
|
+
|
|
127
137
|
context "with no app name configured" do
|
|
128
138
|
before { ENV["APPSIGNAL_APP_NAME"] = "" }
|
|
129
139
|
|
|
@@ -134,6 +134,7 @@ describe Appsignal::Config do
|
|
|
134
134
|
:ca_file_path => File.join(resources_dir, "cacert.pem"),
|
|
135
135
|
:dns_servers => [],
|
|
136
136
|
:files_world_accessible => true,
|
|
137
|
+
:transaction_debug_mode => false,
|
|
137
138
|
:revision => "v2.5.1",
|
|
138
139
|
:request_headers => []
|
|
139
140
|
)
|
|
@@ -202,14 +203,16 @@ describe Appsignal::Config do
|
|
|
202
203
|
context "with a config file" do
|
|
203
204
|
let(:config) { project_fixture_config("production") }
|
|
204
205
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
206
|
+
context "with valid config" do
|
|
207
|
+
it "is valid and active" do
|
|
208
|
+
expect(config.valid?).to be_truthy
|
|
209
|
+
expect(config.active?).to be_truthy
|
|
210
|
+
end
|
|
209
211
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
212
|
+
it "does not log an error" do
|
|
213
|
+
log = capture_logs { config }
|
|
214
|
+
expect(log).to_not contains_log(:error)
|
|
215
|
+
end
|
|
213
216
|
end
|
|
214
217
|
|
|
215
218
|
it "sets the file_config" do
|
|
@@ -471,13 +474,14 @@ describe Appsignal::Config do
|
|
|
471
474
|
config[:filter_parameters] = %w[password confirm_password]
|
|
472
475
|
config[:running_in_container] = false
|
|
473
476
|
config[:dns_servers] = ["8.8.8.8", "8.8.4.4"]
|
|
477
|
+
config[:transaction_debug_mode] = true
|
|
474
478
|
config[:revision] = "v2.5.1"
|
|
475
479
|
config.write_to_environment
|
|
476
480
|
end
|
|
477
481
|
|
|
478
482
|
it "writes the current config to environment variables" do
|
|
479
483
|
expect(ENV["_APPSIGNAL_ACTIVE"]).to eq "true"
|
|
480
|
-
expect(ENV["_APPSIGNAL_APP_PATH"]).to end_with("spec/support/
|
|
484
|
+
expect(ENV["_APPSIGNAL_APP_PATH"]).to end_with("spec/support/fixtures/projects/valid")
|
|
481
485
|
expect(ENV["_APPSIGNAL_AGENT_PATH"]).to end_with("/ext")
|
|
482
486
|
expect(ENV["_APPSIGNAL_DEBUG_LOGGING"]).to eq "false"
|
|
483
487
|
expect(ENV["_APPSIGNAL_LOG"]).to eq "stdout"
|
|
@@ -498,6 +502,7 @@ describe Appsignal::Config do
|
|
|
498
502
|
expect(ENV["_APPSIGNAL_CA_FILE_PATH"]).to eq File.join(resources_dir, "cacert.pem")
|
|
499
503
|
expect(ENV["_APPSIGNAL_DNS_SERVERS"]).to eq "8.8.8.8,8.8.4.4"
|
|
500
504
|
expect(ENV["_APPSIGNAL_FILES_WORLD_ACCESSIBLE"]).to eq "true"
|
|
505
|
+
expect(ENV["_APPSIGNAL_TRANSACTION_DEBUG_MODE"]).to eq "true"
|
|
501
506
|
expect(ENV["_APP_REVISION"]).to eq "v2.5.1"
|
|
502
507
|
expect(ENV).to_not have_key("_APPSIGNAL_WORKING_DIR_PATH")
|
|
503
508
|
expect(ENV).to_not have_key("_APPSIGNAL_WORKING_DIRECTORY_PATH")
|
|
@@ -1,43 +1,53 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
describe Appsignal::EventFormatter::ActionView::RenderFormatter do
|
|
2
|
+
let(:klass) { Appsignal::EventFormatter::ActionView::RenderFormatter }
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
let(:klass) { Appsignal::EventFormatter::ActionView::RenderFormatter }
|
|
7
|
-
let(:formatter) { klass.new }
|
|
4
|
+
if DependencyHelper.rails_present?
|
|
5
|
+
require "action_view"
|
|
8
6
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
context "when in a Rails app" do
|
|
8
|
+
let(:formatter) { klass.new }
|
|
9
|
+
before { allow(Rails.root).to receive(:to_s).and_return("/var/www/app/20130101") }
|
|
10
|
+
|
|
11
|
+
it "registers render_partial.action_view and render_template.action_view" do
|
|
12
|
+
expect(Appsignal::EventFormatter.registered?("render_partial.action_view", klass)).to be_truthy
|
|
13
|
+
expect(Appsignal::EventFormatter.registered?("render_template.action_view", klass)).to be_truthy
|
|
14
|
+
end
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
describe "#root_path" do
|
|
17
|
+
subject { formatter.root_path }
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
it "returns Rails root path" do
|
|
20
|
+
is_expected.to eq "/var/www/app/20130101/"
|
|
21
|
+
end
|
|
19
22
|
end
|
|
20
|
-
end
|
|
21
23
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
+
describe "#format" do
|
|
25
|
+
subject { formatter.format(payload) }
|
|
24
26
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
context "with an identifier" do
|
|
28
|
+
let(:payload) { { :identifier => "/var/www/app/20130101/app/views/home/index/html.erb" } }
|
|
27
29
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
it { is_expected.to eq ["app/views/home/index/html.erb", nil] }
|
|
31
|
+
end
|
|
30
32
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
context "with a frozen identifier" do
|
|
34
|
+
let(:payload) { { :identifier => "/var/www/app/20130101/app/views/home/index/html.erb".freeze } }
|
|
33
35
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
+
it { is_expected.to eq ["app/views/home/index/html.erb", nil] }
|
|
37
|
+
end
|
|
36
38
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
context "without an identifier" do
|
|
40
|
+
let(:payload) { {} }
|
|
39
41
|
|
|
40
|
-
|
|
42
|
+
it { is_expected.to be_nil }
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
else
|
|
47
|
+
context "when not in a Rails app" do
|
|
48
|
+
it "does not register the event formatter" do
|
|
49
|
+
expect(Appsignal::EventFormatter.registered?("render_partial.action_view", klass)).to be_falsy
|
|
50
|
+
expect(Appsignal::EventFormatter.registered?("render_template.action_view", klass)).to be_falsy
|
|
41
51
|
end
|
|
42
52
|
end
|
|
43
53
|
end
|
|
@@ -2,12 +2,14 @@ describe Appsignal::Hooks::ActiveSupportNotificationsHook do
|
|
|
2
2
|
if active_support_present?
|
|
3
3
|
let(:notifier) { ActiveSupport::Notifications::Fanout.new }
|
|
4
4
|
let(:as) { ActiveSupport::Notifications }
|
|
5
|
+
let!(:transaction) do
|
|
6
|
+
Appsignal::Transaction.create("uuid", Appsignal::Transaction::HTTP_REQUEST, "test")
|
|
7
|
+
end
|
|
5
8
|
before :context do
|
|
6
9
|
start_agent
|
|
7
10
|
end
|
|
8
11
|
before do
|
|
9
12
|
as.notifier = notifier
|
|
10
|
-
Appsignal::Transaction.create("uuid", Appsignal::Transaction::HTTP_REQUEST, "test")
|
|
11
13
|
end
|
|
12
14
|
|
|
13
15
|
describe "#dependencies_present?" do
|
|
@@ -17,27 +19,71 @@ describe Appsignal::Hooks::ActiveSupportNotificationsHook do
|
|
|
17
19
|
end
|
|
18
20
|
|
|
19
21
|
it "instruments an ActiveSupport::Notifications.instrument event" do
|
|
20
|
-
expect(Appsignal::Transaction.current).to receive(:start_event)
|
|
21
|
-
.at_least(:once)
|
|
22
|
-
expect(Appsignal::Transaction.current).to receive(:finish_event)
|
|
23
|
-
.at_least(:once)
|
|
24
|
-
.with("sql.active_record", nil, "SQL", 1)
|
|
25
|
-
|
|
26
22
|
return_value = as.instrument("sql.active_record", :sql => "SQL") do
|
|
27
23
|
"value"
|
|
28
24
|
end
|
|
29
25
|
|
|
30
26
|
expect(return_value).to eq "value"
|
|
27
|
+
expect(transaction.to_h["events"]).to match([
|
|
28
|
+
{
|
|
29
|
+
"allocation_count" => kind_of(Integer),
|
|
30
|
+
"body" => "SQL",
|
|
31
|
+
"body_format" => Appsignal::EventFormatter::SQL_BODY_FORMAT,
|
|
32
|
+
"child_allocation_count" => kind_of(Integer),
|
|
33
|
+
"child_duration" => kind_of(Float),
|
|
34
|
+
"child_gc_duration" => kind_of(Float),
|
|
35
|
+
"count" => 1,
|
|
36
|
+
"duration" => kind_of(Float),
|
|
37
|
+
"gc_duration" => kind_of(Float),
|
|
38
|
+
"name" => "sql.active_record",
|
|
39
|
+
"start" => kind_of(Float),
|
|
40
|
+
"title" => ""
|
|
41
|
+
}
|
|
42
|
+
])
|
|
31
43
|
end
|
|
32
44
|
|
|
33
|
-
it "
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
45
|
+
it "instruments an ActiveSupport::Notifications.instrument event with no registered formatter" do
|
|
46
|
+
return_value = as.instrument("no-registered.formatter", :key => "something") do
|
|
47
|
+
"value"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
expect(return_value).to eq "value"
|
|
51
|
+
expect(transaction.to_h["events"]).to match([
|
|
52
|
+
{
|
|
53
|
+
"allocation_count" => kind_of(Integer),
|
|
54
|
+
"body" => "",
|
|
55
|
+
"body_format" => Appsignal::EventFormatter::DEFAULT,
|
|
56
|
+
"child_allocation_count" => kind_of(Integer),
|
|
57
|
+
"child_duration" => kind_of(Float),
|
|
58
|
+
"child_gc_duration" => kind_of(Float),
|
|
59
|
+
"count" => 1,
|
|
60
|
+
"duration" => kind_of(Float),
|
|
61
|
+
"gc_duration" => kind_of(Float),
|
|
62
|
+
"name" => "no-registered.formatter",
|
|
63
|
+
"start" => kind_of(Float),
|
|
64
|
+
"title" => ""
|
|
65
|
+
}
|
|
66
|
+
])
|
|
67
|
+
end
|
|
39
68
|
|
|
69
|
+
it "converts non-string names to strings" do
|
|
40
70
|
as.instrument(:not_a_string) {}
|
|
71
|
+
expect(transaction.to_h["events"]).to match([
|
|
72
|
+
{
|
|
73
|
+
"allocation_count" => kind_of(Integer),
|
|
74
|
+
"body" => "",
|
|
75
|
+
"body_format" => Appsignal::EventFormatter::DEFAULT,
|
|
76
|
+
"child_allocation_count" => kind_of(Integer),
|
|
77
|
+
"child_duration" => kind_of(Float),
|
|
78
|
+
"child_gc_duration" => kind_of(Float),
|
|
79
|
+
"count" => 1,
|
|
80
|
+
"duration" => kind_of(Float),
|
|
81
|
+
"gc_duration" => kind_of(Float),
|
|
82
|
+
"name" => "not_a_string",
|
|
83
|
+
"start" => kind_of(Float),
|
|
84
|
+
"title" => ""
|
|
85
|
+
}
|
|
86
|
+
])
|
|
41
87
|
end
|
|
42
88
|
|
|
43
89
|
it "does not instrument events whose name starts with a bang" do
|
|
@@ -53,33 +99,66 @@ describe Appsignal::Hooks::ActiveSupportNotificationsHook do
|
|
|
53
99
|
|
|
54
100
|
context "when an error is raised in an instrumented block" do
|
|
55
101
|
it "instruments an ActiveSupport::Notifications.instrument event" do
|
|
56
|
-
expect(Appsignal::Transaction.current).to receive(:start_event)
|
|
57
|
-
.at_least(:once)
|
|
58
|
-
expect(Appsignal::Transaction.current).to receive(:finish_event)
|
|
59
|
-
.at_least(:once)
|
|
60
|
-
.with("sql.active_record", nil, "SQL", 1)
|
|
61
|
-
|
|
62
102
|
expect do
|
|
63
103
|
as.instrument("sql.active_record", :sql => "SQL") do
|
|
64
104
|
raise ExampleException, "foo"
|
|
65
105
|
end
|
|
66
106
|
end.to raise_error(ExampleException, "foo")
|
|
107
|
+
|
|
108
|
+
expect(transaction.to_h["events"]).to match([
|
|
109
|
+
{
|
|
110
|
+
"allocation_count" => kind_of(Integer),
|
|
111
|
+
"body" => "SQL",
|
|
112
|
+
"body_format" => Appsignal::EventFormatter::SQL_BODY_FORMAT,
|
|
113
|
+
"child_allocation_count" => kind_of(Integer),
|
|
114
|
+
"child_duration" => kind_of(Float),
|
|
115
|
+
"child_gc_duration" => kind_of(Float),
|
|
116
|
+
"count" => 1,
|
|
117
|
+
"duration" => kind_of(Float),
|
|
118
|
+
"gc_duration" => kind_of(Float),
|
|
119
|
+
"name" => "sql.active_record",
|
|
120
|
+
"start" => kind_of(Float),
|
|
121
|
+
"title" => ""
|
|
122
|
+
}
|
|
123
|
+
])
|
|
67
124
|
end
|
|
68
125
|
end
|
|
69
126
|
|
|
70
127
|
context "when a message is thrown in an instrumented block" do
|
|
71
128
|
it "instruments an ActiveSupport::Notifications.instrument event" do
|
|
72
|
-
expect(Appsignal::Transaction.current).to receive(:start_event)
|
|
73
|
-
.at_least(:once)
|
|
74
|
-
expect(Appsignal::Transaction.current).to receive(:finish_event)
|
|
75
|
-
.at_least(:once)
|
|
76
|
-
.with("sql.active_record", nil, "SQL", 1)
|
|
77
|
-
|
|
78
129
|
expect do
|
|
79
130
|
as.instrument("sql.active_record", :sql => "SQL") do
|
|
80
131
|
throw :foo
|
|
81
132
|
end
|
|
82
133
|
end.to throw_symbol(:foo)
|
|
134
|
+
|
|
135
|
+
expect(transaction.to_h["events"]).to match([
|
|
136
|
+
{
|
|
137
|
+
"allocation_count" => kind_of(Integer),
|
|
138
|
+
"body" => "SQL",
|
|
139
|
+
"body_format" => Appsignal::EventFormatter::SQL_BODY_FORMAT,
|
|
140
|
+
"child_allocation_count" => kind_of(Integer),
|
|
141
|
+
"child_duration" => kind_of(Float),
|
|
142
|
+
"child_gc_duration" => kind_of(Float),
|
|
143
|
+
"count" => 1,
|
|
144
|
+
"duration" => kind_of(Float),
|
|
145
|
+
"gc_duration" => kind_of(Float),
|
|
146
|
+
"name" => "sql.active_record",
|
|
147
|
+
"start" => kind_of(Float),
|
|
148
|
+
"title" => ""
|
|
149
|
+
}
|
|
150
|
+
])
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
context "when a transaction is completed in an instrumented block" do
|
|
155
|
+
it "does not complete the ActiveSupport::Notifications.instrument event" do
|
|
156
|
+
expect(transaction).to receive(:complete)
|
|
157
|
+
as.instrument("sql.active_record", :sql => "SQL") do
|
|
158
|
+
Appsignal::Transaction.complete_current!
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
expect(transaction.to_h["events"]).to match([])
|
|
83
162
|
end
|
|
84
163
|
end
|
|
85
164
|
else
|