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,150 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
describe Appsignal::Utils do
|
|
4
|
+
describe ".data_generate" do
|
|
5
|
+
subject { Appsignal::Utils.data_generate(body) }
|
|
6
|
+
|
|
7
|
+
context "with a valid hash body" do
|
|
8
|
+
let(:body) do
|
|
9
|
+
{
|
|
10
|
+
"the" => "payload",
|
|
11
|
+
"int" => 1, # Fixnum
|
|
12
|
+
"int61" => 1 << 61, # Fixnum
|
|
13
|
+
"int62" => 1 << 62, # Bignum, this one still works
|
|
14
|
+
"int63" => 1 << 63, # Bignum, turnover point for C, too big for long
|
|
15
|
+
"int64" => 1 << 64, # Bignum
|
|
16
|
+
"float" => 1.0,
|
|
17
|
+
1 => true,
|
|
18
|
+
nil => "test",
|
|
19
|
+
:foo => [1, 2, "three", { "foo" => "bar" }],
|
|
20
|
+
"bar" => nil,
|
|
21
|
+
"baz" => { "foo" => "bʊr", "arr" => [1, 2] }
|
|
22
|
+
}
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it { is_expected.to eq Appsignal::Utils.data_generate(body) }
|
|
26
|
+
it { is_expected.to_not eq Appsignal::Utils.data_generate({}) }
|
|
27
|
+
|
|
28
|
+
describe "#to_s" do
|
|
29
|
+
it "returns a serialized hash" do
|
|
30
|
+
expect(subject.to_s).to eq %({"":"test",) +
|
|
31
|
+
%("1":true,) +
|
|
32
|
+
%("bar":null,) +
|
|
33
|
+
%("baz":{"arr":[1,2],"foo":"bʊr"},) +
|
|
34
|
+
%("float":1.0,) +
|
|
35
|
+
%("foo":[1,2,"three",{"foo":"bar"}],) +
|
|
36
|
+
%("int":1,) +
|
|
37
|
+
%("int61":#{1 << 61},) +
|
|
38
|
+
%("int62":#{1 << 62},) +
|
|
39
|
+
%("int63":"bigint:#{1 << 63}",) +
|
|
40
|
+
%("int64":"bigint:#{1 << 64}",) +
|
|
41
|
+
%("the":"payload"})
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
context "with a valid array body" do
|
|
47
|
+
let(:body) do
|
|
48
|
+
[
|
|
49
|
+
nil,
|
|
50
|
+
true,
|
|
51
|
+
false,
|
|
52
|
+
"string",
|
|
53
|
+
1, # Fixnum
|
|
54
|
+
1.0, # Float
|
|
55
|
+
1 << 61, # Fixnum
|
|
56
|
+
1 << 62, # Bignum, this one still works
|
|
57
|
+
1 << 63, # Bignum, turnover point for C, too big for long
|
|
58
|
+
1 << 64, # Bignum
|
|
59
|
+
{ "arr" => [1, 2, "three"], "foo" => "bʊr" }
|
|
60
|
+
]
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it { is_expected.to eq Appsignal::Utils.data_generate(body) }
|
|
64
|
+
it { is_expected.to_not eq Appsignal::Utils.data_generate({}) }
|
|
65
|
+
|
|
66
|
+
describe "#to_s" do
|
|
67
|
+
it "returns a serialized array" do
|
|
68
|
+
expect(subject.to_s).to eq %([null,) +
|
|
69
|
+
%(true,) +
|
|
70
|
+
%(false,) +
|
|
71
|
+
%(\"string\",) +
|
|
72
|
+
%(1,) +
|
|
73
|
+
%(1.0,) +
|
|
74
|
+
%(#{1 << 61},) +
|
|
75
|
+
%(#{1 << 62},) +
|
|
76
|
+
%("bigint:#{1 << 63}",) +
|
|
77
|
+
%("bigint:#{1 << 64}",) +
|
|
78
|
+
%({\"arr\":[1,2,\"three\"],\"foo\":\"bʊr\"}])
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
context "with a body that contains strings with invalid utf-8 content" do
|
|
84
|
+
let(:string_with_invalid_utf8) { [0x61, 0x61, 0x85].pack("c*") }
|
|
85
|
+
let(:body) do
|
|
86
|
+
{
|
|
87
|
+
"field_one" => [0x61, 0x61].pack("c*"),
|
|
88
|
+
:field_two => string_with_invalid_utf8,
|
|
89
|
+
"field_three" => [
|
|
90
|
+
"one", string_with_invalid_utf8
|
|
91
|
+
],
|
|
92
|
+
"field_four" => {
|
|
93
|
+
"one" => string_with_invalid_utf8
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
describe "#to_s" do
|
|
99
|
+
it { expect(subject.to_s).to eq %({"field_four":{"one":"aa�"},"field_one":"aa","field_three":["one","aa�"],"field_two":"aa�"}) }
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
context "with an invalid body" do
|
|
104
|
+
let(:body) { "body" }
|
|
105
|
+
|
|
106
|
+
it "should raise a type error" do
|
|
107
|
+
expect do
|
|
108
|
+
subject
|
|
109
|
+
end.to raise_error TypeError
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
describe ".json_generate" do
|
|
115
|
+
subject { Appsignal::Utils.json_generate(body) }
|
|
116
|
+
|
|
117
|
+
context "with a valid body" do
|
|
118
|
+
let(:body) do
|
|
119
|
+
{
|
|
120
|
+
"the" => "payload",
|
|
121
|
+
1 => true,
|
|
122
|
+
nil => "test",
|
|
123
|
+
:foo => [1, 2, "three"],
|
|
124
|
+
"bar" => nil,
|
|
125
|
+
"baz" => { "foo" => "bar" }
|
|
126
|
+
}
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
it { is_expected.to eq %({"the":"payload","1":true,"":"test","foo":[1,2,"three"],"bar":null,"baz":{"foo":"bar"}}) }
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
context "with a body that contains strings with invalid utf-8 content" do
|
|
133
|
+
let(:string_with_invalid_utf8) { [0x61, 0x61, 0x85].pack("c*") }
|
|
134
|
+
let(:body) do
|
|
135
|
+
{
|
|
136
|
+
"field_one" => [0x61, 0x61].pack("c*"),
|
|
137
|
+
:field_two => string_with_invalid_utf8,
|
|
138
|
+
"field_three" => [
|
|
139
|
+
"one", string_with_invalid_utf8
|
|
140
|
+
],
|
|
141
|
+
"field_four" => {
|
|
142
|
+
"one" => string_with_invalid_utf8
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
it { is_expected.to eq %({"field_one":"aa","field_two":"aa�","field_three":["one","aa�"],"field_four":{"one":"aa�"}}) }
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
@@ -0,0 +1,1049 @@
|
|
|
1
|
+
describe Appsignal do
|
|
2
|
+
before do
|
|
3
|
+
# Make sure we have a clean state because we want to test
|
|
4
|
+
# initialization here.
|
|
5
|
+
Appsignal.config = nil
|
|
6
|
+
Appsignal.extensions.clear
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
let(:transaction) { http_request_transaction }
|
|
10
|
+
|
|
11
|
+
describe ".config=" do
|
|
12
|
+
it "should set the config" do
|
|
13
|
+
config = project_fixture_config
|
|
14
|
+
expect(Appsignal.logger).to_not receive(:level=)
|
|
15
|
+
|
|
16
|
+
Appsignal.config = config
|
|
17
|
+
expect(Appsignal.config).to eq config
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
describe ".extensions" do
|
|
22
|
+
it "should keep a list of extensions" do
|
|
23
|
+
expect(Appsignal.extensions).to be_empty
|
|
24
|
+
Appsignal.extensions << Appsignal::MockExtension
|
|
25
|
+
expect(Appsignal.extensions.size).to eq(1)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
describe ".start" do
|
|
30
|
+
context "with no config set beforehand" do
|
|
31
|
+
it "should do nothing when config is not set and there is no valid config in the env" do
|
|
32
|
+
expect(Appsignal.logger).to receive(:error).with(
|
|
33
|
+
"Push api key not set after loading config"
|
|
34
|
+
).once
|
|
35
|
+
expect(Appsignal.logger).to receive(:error).with(
|
|
36
|
+
"Not starting, no valid config for this environment"
|
|
37
|
+
).once
|
|
38
|
+
expect(Appsignal::Extension).to_not receive(:start)
|
|
39
|
+
Appsignal.start
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "should create a config from the env" do
|
|
43
|
+
ENV["APPSIGNAL_PUSH_API_KEY"] = "something"
|
|
44
|
+
expect(Appsignal::Extension).to receive(:start)
|
|
45
|
+
expect(Appsignal.logger).not_to receive(:error)
|
|
46
|
+
silence { Appsignal.start }
|
|
47
|
+
expect(Appsignal.config[:push_api_key]).to eq("something")
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
context "when config is loaded" do
|
|
52
|
+
before { Appsignal.config = project_fixture_config }
|
|
53
|
+
|
|
54
|
+
it "should initialize logging" do
|
|
55
|
+
Appsignal.start
|
|
56
|
+
expect(Appsignal.logger.level).to eq Logger::INFO
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "should start native" do
|
|
60
|
+
expect(Appsignal::Extension).to receive(:start)
|
|
61
|
+
Appsignal.start
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "should initialize formatters" do
|
|
65
|
+
expect(Appsignal::EventFormatter).to receive(:initialize_formatters)
|
|
66
|
+
Appsignal.start
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
context "with an extension" do
|
|
70
|
+
before { Appsignal.extensions << Appsignal::MockExtension }
|
|
71
|
+
|
|
72
|
+
it "should call the extension's initializer" do
|
|
73
|
+
expect(Appsignal::MockExtension).to receive(:initializer)
|
|
74
|
+
Appsignal.start
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
context "when allocation tracking and gc instrumentation have been enabled" do
|
|
79
|
+
before do
|
|
80
|
+
allow(GC::Profiler).to receive(:enable)
|
|
81
|
+
Appsignal.config.config_hash[:enable_allocation_tracking] = true
|
|
82
|
+
Appsignal.config.config_hash[:enable_gc_instrumentation] = true
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it "should enable Ruby's GC::Profiler" do
|
|
86
|
+
expect(GC::Profiler).to receive(:enable)
|
|
87
|
+
Appsignal.start
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
unless Appsignal::System.jruby?
|
|
91
|
+
it "installs the allocation event hook" do
|
|
92
|
+
expect(Appsignal::Extension).to receive(:install_allocation_event_hook)
|
|
93
|
+
Appsignal.start
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
it "should add the gc probe to minutely" do
|
|
98
|
+
expect(Appsignal::Minutely).to receive(:add_gc_probe)
|
|
99
|
+
Appsignal.start
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
context "when allocation tracking and gc instrumentation have been disabled" do
|
|
104
|
+
before do
|
|
105
|
+
Appsignal.config.config_hash[:enable_allocation_tracking] = false
|
|
106
|
+
Appsignal.config.config_hash[:enable_gc_instrumentation] = false
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it "should not enable Ruby's GC::Profiler" do
|
|
110
|
+
expect(GC::Profiler).not_to receive(:enable)
|
|
111
|
+
Appsignal.start
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
it "should not install the allocation event hook" do
|
|
115
|
+
expect(Appsignal::Minutely).not_to receive(:install_allocation_event_hook)
|
|
116
|
+
Appsignal.start
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
it "should not add the gc probe to minutely" do
|
|
120
|
+
expect(Appsignal::Minutely).not_to receive(:add_gc_probe)
|
|
121
|
+
Appsignal.start
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
context "when minutely metrics has been enabled" do
|
|
126
|
+
before do
|
|
127
|
+
Appsignal.config.config_hash[:enable_minutely_probes] = true
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
it "should start minutely" do
|
|
131
|
+
expect(Appsignal::Minutely).to receive(:start)
|
|
132
|
+
Appsignal.start
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
context "when minutely metrics has been disabled" do
|
|
137
|
+
before do
|
|
138
|
+
Appsignal.config.config_hash[:enable_minutely_probes] = false
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
it "should not start minutely" do
|
|
142
|
+
expect(Appsignal::Minutely).to_not receive(:start)
|
|
143
|
+
Appsignal.start
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
context "with debug logging" do
|
|
149
|
+
before { Appsignal.config = project_fixture_config("test") }
|
|
150
|
+
|
|
151
|
+
it "should change the log level" do
|
|
152
|
+
Appsignal.start
|
|
153
|
+
expect(Appsignal.logger.level).to eq Logger::DEBUG
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
describe ".forked" do
|
|
159
|
+
context "when not active" do
|
|
160
|
+
it "should should do nothing" do
|
|
161
|
+
expect(Appsignal::Extension).to_not receive(:start)
|
|
162
|
+
|
|
163
|
+
Appsignal.forked
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
context "when active" do
|
|
168
|
+
before do
|
|
169
|
+
Appsignal.config = project_fixture_config
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
it "should resubscribe and start the extension" do
|
|
173
|
+
expect(Appsignal).to receive(:start_logger)
|
|
174
|
+
expect(Appsignal::Extension).to receive(:start)
|
|
175
|
+
|
|
176
|
+
Appsignal.forked
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
describe ".stop" do
|
|
182
|
+
it "should call stop on the extension" do
|
|
183
|
+
expect(Appsignal.logger).to receive(:debug).with("Stopping appsignal")
|
|
184
|
+
expect(Appsignal::Extension).to receive(:stop)
|
|
185
|
+
Appsignal.stop
|
|
186
|
+
expect(Appsignal.active?).to be_falsy
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
context "with context specified" do
|
|
190
|
+
it "should log the context" do
|
|
191
|
+
expect(Appsignal.logger).to receive(:debug).with("Stopping appsignal (something)")
|
|
192
|
+
expect(Appsignal::Extension).to receive(:stop)
|
|
193
|
+
Appsignal.stop("something")
|
|
194
|
+
expect(Appsignal.active?).to be_falsy
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
describe ".active?" do
|
|
200
|
+
subject { Appsignal.active? }
|
|
201
|
+
|
|
202
|
+
context "without config" do
|
|
203
|
+
before do
|
|
204
|
+
Appsignal.config = nil
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
it { is_expected.to be_falsy }
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
context "with inactive config" do
|
|
211
|
+
before do
|
|
212
|
+
Appsignal.config = project_fixture_config("nonsense")
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
it { is_expected.to be_falsy }
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
context "with active config" do
|
|
219
|
+
before do
|
|
220
|
+
Appsignal.config = project_fixture_config
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
it { is_expected.to be_truthy }
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
describe ".add_exception" do
|
|
228
|
+
it "should alias this method" do
|
|
229
|
+
expect(Appsignal).to respond_to(:add_exception)
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
describe ".get_server_state" do
|
|
234
|
+
it "should call server state on the extension" do
|
|
235
|
+
expect(Appsignal::Extension).to receive(:get_server_state).with("key")
|
|
236
|
+
|
|
237
|
+
Appsignal.get_server_state("key")
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
it "should get nil by default" do
|
|
241
|
+
expect(Appsignal.get_server_state("key")).to be_nil
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
context "not active" do
|
|
246
|
+
describe ".monitor_transaction" do
|
|
247
|
+
it "should do nothing but still yield the block" do
|
|
248
|
+
expect(Appsignal::Transaction).to_not receive(:create)
|
|
249
|
+
expect(Appsignal).to_not receive(:instrument)
|
|
250
|
+
object = double
|
|
251
|
+
expect(object).to receive(:some_method).and_return(1)
|
|
252
|
+
|
|
253
|
+
expect do
|
|
254
|
+
expect(Appsignal.monitor_transaction("perform_job.nothing") do
|
|
255
|
+
object.some_method
|
|
256
|
+
end).to eq 1
|
|
257
|
+
end.to_not raise_error
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
describe ".listen_for_error" do
|
|
262
|
+
it "does not record anyhing" do
|
|
263
|
+
error = RuntimeError.new("specific error")
|
|
264
|
+
expect do
|
|
265
|
+
Appsignal.listen_for_error do
|
|
266
|
+
raise error
|
|
267
|
+
end
|
|
268
|
+
end.to raise_error(error)
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
describe ".send_error" do
|
|
273
|
+
it "should do nothing" do
|
|
274
|
+
expect do
|
|
275
|
+
Appsignal.send_error(RuntimeError.new)
|
|
276
|
+
end.to_not raise_error
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
describe ".set_error" do
|
|
281
|
+
it "should do nothing" do
|
|
282
|
+
expect do
|
|
283
|
+
Appsignal.set_error(RuntimeError.new)
|
|
284
|
+
end.to_not raise_error
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
describe ".set_namespace" do
|
|
289
|
+
it "should do nothing" do
|
|
290
|
+
expect do
|
|
291
|
+
Appsignal.set_namespace("custom")
|
|
292
|
+
end.to_not raise_error
|
|
293
|
+
end
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
describe ".tag_request" do
|
|
297
|
+
it "should do nothing" do
|
|
298
|
+
expect do
|
|
299
|
+
Appsignal.tag_request(:tag => "tag")
|
|
300
|
+
end.to_not raise_error
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
context "with config and started" do
|
|
306
|
+
before do
|
|
307
|
+
Appsignal.config = project_fixture_config
|
|
308
|
+
Appsignal.start
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
describe ".monitor_transaction" do
|
|
312
|
+
context "with a successful call" do
|
|
313
|
+
it "should instrument and complete for a background job" do
|
|
314
|
+
expect(Appsignal).to receive(:instrument).with(
|
|
315
|
+
"perform_job.something"
|
|
316
|
+
).and_yield
|
|
317
|
+
expect(Appsignal::Transaction).to receive(:complete_current!)
|
|
318
|
+
object = double
|
|
319
|
+
expect(object).to receive(:some_method).and_return(1)
|
|
320
|
+
|
|
321
|
+
expect(Appsignal.monitor_transaction(
|
|
322
|
+
"perform_job.something",
|
|
323
|
+
background_env_with_data
|
|
324
|
+
) do
|
|
325
|
+
current = Appsignal::Transaction.current
|
|
326
|
+
expect(current.namespace).to eq Appsignal::Transaction::BACKGROUND_JOB
|
|
327
|
+
expect(current.request).to be_a(Appsignal::Transaction::GenericRequest)
|
|
328
|
+
object.some_method
|
|
329
|
+
end).to eq 1
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
it "should instrument and complete for a http request" do
|
|
333
|
+
expect(Appsignal).to receive(:instrument).with(
|
|
334
|
+
"process_action.something"
|
|
335
|
+
).and_yield
|
|
336
|
+
expect(Appsignal::Transaction).to receive(:complete_current!)
|
|
337
|
+
object = double
|
|
338
|
+
expect(object).to receive(:some_method)
|
|
339
|
+
|
|
340
|
+
Appsignal.monitor_transaction(
|
|
341
|
+
"process_action.something",
|
|
342
|
+
http_request_env_with_data
|
|
343
|
+
) do
|
|
344
|
+
current = Appsignal::Transaction.current
|
|
345
|
+
expect(current.namespace).to eq Appsignal::Transaction::HTTP_REQUEST
|
|
346
|
+
expect(current.request).to be_a(::Rack::Request)
|
|
347
|
+
object.some_method
|
|
348
|
+
end
|
|
349
|
+
end
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
context "with an erroring call" do
|
|
353
|
+
let(:error) { ExampleException.new }
|
|
354
|
+
|
|
355
|
+
it "should add the error to the current transaction and complete" do
|
|
356
|
+
expect_any_instance_of(Appsignal::Transaction).to receive(:set_error).with(error)
|
|
357
|
+
expect(Appsignal::Transaction).to receive(:complete_current!)
|
|
358
|
+
|
|
359
|
+
expect do
|
|
360
|
+
Appsignal.monitor_transaction("perform_job.something") do
|
|
361
|
+
raise error
|
|
362
|
+
end
|
|
363
|
+
end.to raise_error(error)
|
|
364
|
+
end
|
|
365
|
+
end
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
describe ".monitor_single_transaction" do
|
|
369
|
+
context "with a successful call" do
|
|
370
|
+
it "should call monitor_transaction and stop" do
|
|
371
|
+
expect(Appsignal).to receive(:monitor_transaction).with(
|
|
372
|
+
"perform_job.something",
|
|
373
|
+
:key => :value
|
|
374
|
+
).and_yield
|
|
375
|
+
expect(Appsignal).to receive(:stop)
|
|
376
|
+
|
|
377
|
+
Appsignal.monitor_single_transaction("perform_job.something", :key => :value) do
|
|
378
|
+
# nothing
|
|
379
|
+
end
|
|
380
|
+
end
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
context "with an erroring call" do
|
|
384
|
+
let(:error) { ExampleException.new }
|
|
385
|
+
|
|
386
|
+
it "should call monitor_transaction and stop and then raise the error" do
|
|
387
|
+
expect(Appsignal).to receive(:monitor_transaction).with(
|
|
388
|
+
"perform_job.something",
|
|
389
|
+
:key => :value
|
|
390
|
+
).and_yield
|
|
391
|
+
expect(Appsignal).to receive(:stop)
|
|
392
|
+
|
|
393
|
+
expect do
|
|
394
|
+
Appsignal.monitor_single_transaction("perform_job.something", :key => :value) do
|
|
395
|
+
raise error
|
|
396
|
+
end
|
|
397
|
+
end.to raise_error(error)
|
|
398
|
+
end
|
|
399
|
+
end
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
describe ".tag_request" do
|
|
403
|
+
before { allow(Appsignal::Transaction).to receive(:current).and_return(transaction) }
|
|
404
|
+
|
|
405
|
+
context "with transaction" do
|
|
406
|
+
let(:transaction) { double }
|
|
407
|
+
it "should call set_tags on transaction" do
|
|
408
|
+
expect(transaction).to receive(:set_tags).with("a" => "b")
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
after { Appsignal.tag_request("a" => "b") }
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
context "without transaction" do
|
|
415
|
+
let(:transaction) { nil }
|
|
416
|
+
|
|
417
|
+
it "should call set_tags on transaction" do
|
|
418
|
+
expect(Appsignal.tag_request).to be_falsy
|
|
419
|
+
end
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
it "should also listen to tag_job" do
|
|
423
|
+
expect(Appsignal).to respond_to(:tag_job)
|
|
424
|
+
end
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
describe "custom stats" do
|
|
428
|
+
describe ".set_gauge" do
|
|
429
|
+
it "should call set_gauge on the extension with a string key and float" do
|
|
430
|
+
expect(Appsignal::Extension).to receive(:set_gauge).with("key", 0.1)
|
|
431
|
+
Appsignal.set_gauge("key", 0.1)
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
it "should call set_gauge on the extension with a symbol key and int" do
|
|
435
|
+
expect(Appsignal::Extension).to receive(:set_gauge).with("key", 1.0)
|
|
436
|
+
Appsignal.set_gauge(:key, 1)
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
it "should not raise an exception when out of range" do
|
|
440
|
+
expect(Appsignal::Extension).to receive(:set_gauge).with("key", 10).and_raise(RangeError)
|
|
441
|
+
expect(Appsignal.logger).to receive(:warn).with("Gauge value 10 for key 'key' is too big")
|
|
442
|
+
expect do
|
|
443
|
+
Appsignal.set_gauge("key", 10)
|
|
444
|
+
end.to_not raise_error
|
|
445
|
+
end
|
|
446
|
+
end
|
|
447
|
+
|
|
448
|
+
describe ".set_host_gauge" do
|
|
449
|
+
it "should call set_host_gauge on the extension with a string key and float" do
|
|
450
|
+
expect(Appsignal::Extension).to receive(:set_host_gauge).with("key", 0.1)
|
|
451
|
+
Appsignal.set_host_gauge("key", 0.1)
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
it "should call set_host_gauge on the extension with a symbol key and int" do
|
|
455
|
+
expect(Appsignal::Extension).to receive(:set_host_gauge).with("key", 1.0)
|
|
456
|
+
Appsignal.set_host_gauge(:key, 1)
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
it "should not raise an exception when out of range" do
|
|
460
|
+
expect(Appsignal::Extension).to receive(:set_host_gauge).with("key", 10).and_raise(RangeError)
|
|
461
|
+
expect(Appsignal.logger).to receive(:warn).with("Host gauge value 10 for key 'key' is too big")
|
|
462
|
+
expect do
|
|
463
|
+
Appsignal.set_host_gauge("key", 10)
|
|
464
|
+
end.to_not raise_error
|
|
465
|
+
end
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
describe ".set_process_gauge" do
|
|
469
|
+
it "should call set_process_gauge on the extension with a string key and float" do
|
|
470
|
+
expect(Appsignal::Extension).to receive(:set_process_gauge).with("key", 0.1)
|
|
471
|
+
Appsignal.set_process_gauge("key", 0.1)
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
it "should call set_process_gauge on the extension with a symbol key and int" do
|
|
475
|
+
expect(Appsignal::Extension).to receive(:set_process_gauge).with("key", 1.0)
|
|
476
|
+
Appsignal.set_process_gauge(:key, 1)
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
it "should not raise an exception when out of range" do
|
|
480
|
+
expect(Appsignal::Extension).to receive(:set_process_gauge).with("key", 10).and_raise(RangeError)
|
|
481
|
+
expect(Appsignal.logger).to receive(:warn).with("Process gauge value 10 for key 'key' is too big")
|
|
482
|
+
expect do
|
|
483
|
+
Appsignal.set_process_gauge("key", 10)
|
|
484
|
+
end.to_not raise_error
|
|
485
|
+
end
|
|
486
|
+
end
|
|
487
|
+
|
|
488
|
+
describe ".increment_counter" do
|
|
489
|
+
it "should call increment_counter on the extension with a string key" do
|
|
490
|
+
expect(Appsignal::Extension).to receive(:increment_counter).with("key", 1)
|
|
491
|
+
Appsignal.increment_counter("key")
|
|
492
|
+
end
|
|
493
|
+
|
|
494
|
+
it "should call increment_counter on the extension with a symbol key" do
|
|
495
|
+
expect(Appsignal::Extension).to receive(:increment_counter).with("key", 1)
|
|
496
|
+
Appsignal.increment_counter(:key)
|
|
497
|
+
end
|
|
498
|
+
|
|
499
|
+
it "should call increment_counter on the extension with a count" do
|
|
500
|
+
expect(Appsignal::Extension).to receive(:increment_counter).with("key", 5)
|
|
501
|
+
Appsignal.increment_counter("key", 5)
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
it "should not raise an exception when out of range" do
|
|
505
|
+
expect(Appsignal::Extension).to receive(:increment_counter).with("key", 10).and_raise(RangeError)
|
|
506
|
+
expect(Appsignal.logger).to receive(:warn).with("Counter value 10 for key 'key' is too big")
|
|
507
|
+
expect do
|
|
508
|
+
Appsignal.increment_counter("key", 10)
|
|
509
|
+
end.to_not raise_error
|
|
510
|
+
end
|
|
511
|
+
end
|
|
512
|
+
|
|
513
|
+
describe ".add_distribution_value" do
|
|
514
|
+
it "should call add_distribution_value on the extension with a string key and float" do
|
|
515
|
+
expect(Appsignal::Extension).to receive(:add_distribution_value).with("key", 0.1)
|
|
516
|
+
Appsignal.add_distribution_value("key", 0.1)
|
|
517
|
+
end
|
|
518
|
+
|
|
519
|
+
it "should call add_distribution_value on the extension with a symbol key and int" do
|
|
520
|
+
expect(Appsignal::Extension).to receive(:add_distribution_value).with("key", 1.0)
|
|
521
|
+
Appsignal.add_distribution_value(:key, 1)
|
|
522
|
+
end
|
|
523
|
+
|
|
524
|
+
it "should not raise an exception when out of range" do
|
|
525
|
+
expect(Appsignal::Extension).to receive(:add_distribution_value).with("key", 10).and_raise(RangeError)
|
|
526
|
+
expect(Appsignal.logger).to receive(:warn).with("Distribution value 10 for key 'key' is too big")
|
|
527
|
+
expect do
|
|
528
|
+
Appsignal.add_distribution_value("key", 10)
|
|
529
|
+
end.to_not raise_error
|
|
530
|
+
end
|
|
531
|
+
end
|
|
532
|
+
end
|
|
533
|
+
|
|
534
|
+
describe ".logger" do
|
|
535
|
+
subject { Appsignal.logger }
|
|
536
|
+
|
|
537
|
+
it { is_expected.to be_a Logger }
|
|
538
|
+
end
|
|
539
|
+
|
|
540
|
+
describe ".start_logger" do
|
|
541
|
+
let(:out_stream) { std_stream }
|
|
542
|
+
let(:output) { out_stream.read }
|
|
543
|
+
let(:log_path) { File.join(tmp_dir, "log") }
|
|
544
|
+
let(:log_file) { File.join(log_path, "appsignal.log") }
|
|
545
|
+
|
|
546
|
+
before do
|
|
547
|
+
FileUtils.mkdir_p(log_path)
|
|
548
|
+
|
|
549
|
+
Appsignal.logger.error("Log in memory")
|
|
550
|
+
Appsignal.config = project_fixture_config(
|
|
551
|
+
"production",
|
|
552
|
+
:log_path => log_path
|
|
553
|
+
)
|
|
554
|
+
end
|
|
555
|
+
after { FileUtils.rm_rf(log_path) }
|
|
556
|
+
|
|
557
|
+
context "when the log path is writable" do
|
|
558
|
+
context "when the log file is writable" do
|
|
559
|
+
let(:log_file_contents) { File.open(log_file).read }
|
|
560
|
+
|
|
561
|
+
before do
|
|
562
|
+
capture_stdout(out_stream) do
|
|
563
|
+
Appsignal.start_logger
|
|
564
|
+
Appsignal.logger.error("Log to file")
|
|
565
|
+
end
|
|
566
|
+
end
|
|
567
|
+
|
|
568
|
+
it "logs to file" do
|
|
569
|
+
expect(File.exist?(log_file)).to be_truthy
|
|
570
|
+
expect(log_file_contents).to include "[ERROR] Log to file"
|
|
571
|
+
expect(output).to be_empty
|
|
572
|
+
end
|
|
573
|
+
|
|
574
|
+
it "amends in memory log to log file" do
|
|
575
|
+
expect(log_file_contents).to include "[ERROR] appsignal: Log in memory"
|
|
576
|
+
end
|
|
577
|
+
end
|
|
578
|
+
|
|
579
|
+
context "when the log file is not writable" do
|
|
580
|
+
before do
|
|
581
|
+
FileUtils.touch log_file
|
|
582
|
+
FileUtils.chmod 0o444, log_file
|
|
583
|
+
|
|
584
|
+
capture_stdout(out_stream) do
|
|
585
|
+
Appsignal.start_logger
|
|
586
|
+
Appsignal.logger.error("Log to not writable log file")
|
|
587
|
+
end
|
|
588
|
+
end
|
|
589
|
+
|
|
590
|
+
it "logs to stdout" do
|
|
591
|
+
expect(File.writable?(log_file)).to be_falsy
|
|
592
|
+
expect(output).to include "[ERROR] appsignal: Log to not writable log file"
|
|
593
|
+
end
|
|
594
|
+
|
|
595
|
+
it "amends in memory log to stdout" do
|
|
596
|
+
expect(output).to include "[ERROR] appsignal: Log in memory"
|
|
597
|
+
end
|
|
598
|
+
|
|
599
|
+
it "outputs a warning" do
|
|
600
|
+
expect(output).to include \
|
|
601
|
+
"[WARN] appsignal: Unable to start logger with log path '#{log_file}'.",
|
|
602
|
+
"[WARN] appsignal: Permission denied"
|
|
603
|
+
end
|
|
604
|
+
end
|
|
605
|
+
end
|
|
606
|
+
|
|
607
|
+
context "when the log path and fallback path are not writable" do
|
|
608
|
+
before do
|
|
609
|
+
FileUtils.chmod 0o444, log_path
|
|
610
|
+
FileUtils.chmod 0o444, Appsignal::Config.system_tmp_dir
|
|
611
|
+
|
|
612
|
+
capture_stdout(out_stream) do
|
|
613
|
+
Appsignal.start_logger
|
|
614
|
+
Appsignal.logger.error("Log to not writable log path")
|
|
615
|
+
end
|
|
616
|
+
end
|
|
617
|
+
after do
|
|
618
|
+
FileUtils.chmod 0o755, Appsignal::Config.system_tmp_dir
|
|
619
|
+
end
|
|
620
|
+
|
|
621
|
+
it "logs to stdout" do
|
|
622
|
+
expect(File.writable?(log_path)).to be_falsy
|
|
623
|
+
expect(output).to include "[ERROR] appsignal: Log to not writable log path"
|
|
624
|
+
end
|
|
625
|
+
|
|
626
|
+
it "amends in memory log to stdout" do
|
|
627
|
+
expect(output).to include "[ERROR] appsignal: Log in memory"
|
|
628
|
+
end
|
|
629
|
+
|
|
630
|
+
it "outputs a warning" do
|
|
631
|
+
expect(output).to include \
|
|
632
|
+
"appsignal: Unable to log to '#{log_path}' "\
|
|
633
|
+
"or the '#{Appsignal::Config.system_tmp_dir}' fallback."
|
|
634
|
+
end
|
|
635
|
+
end
|
|
636
|
+
|
|
637
|
+
context "when on Heroku" do
|
|
638
|
+
before do
|
|
639
|
+
capture_stdout(out_stream) do
|
|
640
|
+
Appsignal.start_logger
|
|
641
|
+
Appsignal.logger.error("Log to stdout")
|
|
642
|
+
end
|
|
643
|
+
end
|
|
644
|
+
around { |example| recognize_as_heroku { example.run } }
|
|
645
|
+
|
|
646
|
+
it "logs to stdout" do
|
|
647
|
+
expect(output).to include "[ERROR] appsignal: Log to stdout"
|
|
648
|
+
end
|
|
649
|
+
|
|
650
|
+
it "amends in memory log to stdout" do
|
|
651
|
+
expect(output).to include "[ERROR] appsignal: Log in memory"
|
|
652
|
+
end
|
|
653
|
+
end
|
|
654
|
+
|
|
655
|
+
describe "#logger#level" do
|
|
656
|
+
subject { Appsignal.logger.level }
|
|
657
|
+
|
|
658
|
+
context "when there is no config" do
|
|
659
|
+
before do
|
|
660
|
+
Appsignal.config = nil
|
|
661
|
+
capture_stdout(out_stream) do
|
|
662
|
+
Appsignal.start_logger
|
|
663
|
+
end
|
|
664
|
+
end
|
|
665
|
+
|
|
666
|
+
it "sets the log level to info" do
|
|
667
|
+
expect(subject).to eq Logger::INFO
|
|
668
|
+
end
|
|
669
|
+
end
|
|
670
|
+
|
|
671
|
+
context "when there is a config" do
|
|
672
|
+
context "when log level is configured to debug" do
|
|
673
|
+
before do
|
|
674
|
+
Appsignal.config.config_hash[:debug] = true
|
|
675
|
+
capture_stdout(out_stream) do
|
|
676
|
+
Appsignal.start_logger
|
|
677
|
+
end
|
|
678
|
+
end
|
|
679
|
+
|
|
680
|
+
it "sets the log level to debug" do
|
|
681
|
+
expect(subject).to eq Logger::DEBUG
|
|
682
|
+
end
|
|
683
|
+
end
|
|
684
|
+
end
|
|
685
|
+
end
|
|
686
|
+
end
|
|
687
|
+
|
|
688
|
+
describe ".log_formatter" do
|
|
689
|
+
subject { Appsignal.log_formatter.call("Debug", Time.parse("2015-07-08"), nil, "log line") }
|
|
690
|
+
|
|
691
|
+
it "formats a log" do
|
|
692
|
+
expect(subject).to eq "[2015-07-08T00:00:00 (process) ##{Process.pid}][Debug] log line\n"
|
|
693
|
+
end
|
|
694
|
+
|
|
695
|
+
context "with prefix" do
|
|
696
|
+
subject do
|
|
697
|
+
Appsignal.log_formatter("prefix").call("Debug", Time.parse("2015-07-08"), nil, "log line")
|
|
698
|
+
end
|
|
699
|
+
|
|
700
|
+
it "adds a prefix" do
|
|
701
|
+
expect(subject)
|
|
702
|
+
.to eq "[2015-07-08T00:00:00 (process) ##{Process.pid}][Debug] prefix: log line\n"
|
|
703
|
+
end
|
|
704
|
+
end
|
|
705
|
+
end
|
|
706
|
+
|
|
707
|
+
describe ".config" do
|
|
708
|
+
subject { Appsignal.config }
|
|
709
|
+
|
|
710
|
+
it { is_expected.to be_a Appsignal::Config }
|
|
711
|
+
it "should return configuration" do
|
|
712
|
+
expect(subject[:endpoint]).to eq "https://push.appsignal.com"
|
|
713
|
+
end
|
|
714
|
+
end
|
|
715
|
+
|
|
716
|
+
describe ".send_error" do
|
|
717
|
+
let(:transaction) do
|
|
718
|
+
Appsignal::Transaction.new(
|
|
719
|
+
SecureRandom.uuid,
|
|
720
|
+
Appsignal::Transaction::HTTP_REQUEST,
|
|
721
|
+
Appsignal::Transaction::GenericRequest.new({})
|
|
722
|
+
)
|
|
723
|
+
end
|
|
724
|
+
let(:error) { ExampleException.new }
|
|
725
|
+
|
|
726
|
+
it "sends the error to AppSignal" do
|
|
727
|
+
expect(Appsignal::Transaction).to receive(:new).with(
|
|
728
|
+
kind_of(String),
|
|
729
|
+
Appsignal::Transaction::HTTP_REQUEST,
|
|
730
|
+
kind_of(Appsignal::Transaction::GenericRequest)
|
|
731
|
+
).and_return(transaction)
|
|
732
|
+
expect(transaction).to receive(:set_error).with(error)
|
|
733
|
+
expect(transaction).to_not receive(:set_tags)
|
|
734
|
+
expect(transaction).to receive(:complete)
|
|
735
|
+
|
|
736
|
+
Appsignal.send_error(error)
|
|
737
|
+
end
|
|
738
|
+
|
|
739
|
+
context "when given error is not an Exception" do
|
|
740
|
+
let(:error) { double }
|
|
741
|
+
|
|
742
|
+
it "logs an error message" do
|
|
743
|
+
expect(Appsignal.logger).to receive(:error)
|
|
744
|
+
.with("Can't send error, given value is not an exception")
|
|
745
|
+
end
|
|
746
|
+
|
|
747
|
+
it "does not send the error" do
|
|
748
|
+
expect(Appsignal::Transaction).to_not receive(:create)
|
|
749
|
+
end
|
|
750
|
+
|
|
751
|
+
after { Appsignal.send_error(error) }
|
|
752
|
+
end
|
|
753
|
+
|
|
754
|
+
context "with tags" do
|
|
755
|
+
let(:tags) { { :a => "a", :b => "b" } }
|
|
756
|
+
before do
|
|
757
|
+
allow(Appsignal::Transaction).to receive(:new).and_return(transaction)
|
|
758
|
+
end
|
|
759
|
+
|
|
760
|
+
it "tags the request before sending it" do
|
|
761
|
+
expect(transaction).to receive(:set_tags).with(tags).and_call_original
|
|
762
|
+
expect(transaction).to receive(:complete)
|
|
763
|
+
|
|
764
|
+
Appsignal.send_error(error, tags)
|
|
765
|
+
end
|
|
766
|
+
end
|
|
767
|
+
|
|
768
|
+
context "with namespace" do
|
|
769
|
+
let(:namespace) { "admin" }
|
|
770
|
+
|
|
771
|
+
it "sets the namespace on the transaction" do
|
|
772
|
+
expect(Appsignal::Transaction).to receive(:new).with(
|
|
773
|
+
kind_of(String),
|
|
774
|
+
"admin",
|
|
775
|
+
kind_of(Appsignal::Transaction::GenericRequest)
|
|
776
|
+
).and_call_original
|
|
777
|
+
end
|
|
778
|
+
|
|
779
|
+
after { Appsignal.send_error(error, nil, namespace) }
|
|
780
|
+
end
|
|
781
|
+
end
|
|
782
|
+
|
|
783
|
+
describe ".listen_for_error" do
|
|
784
|
+
it "records the error and re-raise it" do
|
|
785
|
+
expect(Appsignal).to receive(:send_error).with(
|
|
786
|
+
kind_of(ExampleException),
|
|
787
|
+
nil,
|
|
788
|
+
Appsignal::Transaction::HTTP_REQUEST
|
|
789
|
+
)
|
|
790
|
+
expect do
|
|
791
|
+
Appsignal.listen_for_error do
|
|
792
|
+
raise ExampleException, "I am an exception"
|
|
793
|
+
end
|
|
794
|
+
end.to raise_error(ExampleException, "I am an exception")
|
|
795
|
+
end
|
|
796
|
+
|
|
797
|
+
context "with tags" do
|
|
798
|
+
it "adds tags to the transaction" do
|
|
799
|
+
expect(Appsignal).to receive(:send_error).with(
|
|
800
|
+
kind_of(ExampleException),
|
|
801
|
+
{ "foo" => "bar" },
|
|
802
|
+
Appsignal::Transaction::HTTP_REQUEST
|
|
803
|
+
)
|
|
804
|
+
expect do
|
|
805
|
+
Appsignal.listen_for_error("foo" => "bar") do
|
|
806
|
+
raise ExampleException, "I am an exception"
|
|
807
|
+
end
|
|
808
|
+
end.to raise_error(ExampleException, "I am an exception")
|
|
809
|
+
end
|
|
810
|
+
end
|
|
811
|
+
|
|
812
|
+
context "with a custom namespace" do
|
|
813
|
+
it "adds the namespace to the transaction" do
|
|
814
|
+
expect(Appsignal).to receive(:send_error).with(
|
|
815
|
+
kind_of(ExampleException),
|
|
816
|
+
nil,
|
|
817
|
+
"custom_namespace"
|
|
818
|
+
)
|
|
819
|
+
expect do
|
|
820
|
+
Appsignal.listen_for_error(nil, "custom_namespace") do
|
|
821
|
+
raise ExampleException, "I am an exception"
|
|
822
|
+
end
|
|
823
|
+
end.to raise_error(ExampleException, "I am an exception")
|
|
824
|
+
end
|
|
825
|
+
end
|
|
826
|
+
end
|
|
827
|
+
|
|
828
|
+
describe ".set_error" do
|
|
829
|
+
before { allow(Appsignal::Transaction).to receive(:current).and_return(transaction) }
|
|
830
|
+
let(:error) { RuntimeError.new("I am an exception") }
|
|
831
|
+
|
|
832
|
+
context "when there is an active transaction" do
|
|
833
|
+
it "adds the error to the active transaction" do
|
|
834
|
+
expect(transaction).to receive(:set_error).with(error)
|
|
835
|
+
expect(transaction).to_not receive(:set_tags)
|
|
836
|
+
expect(transaction).to_not receive(:set_namespace)
|
|
837
|
+
|
|
838
|
+
Appsignal.set_error(error)
|
|
839
|
+
end
|
|
840
|
+
|
|
841
|
+
context "when the error is nil" do
|
|
842
|
+
it "does nothing" do
|
|
843
|
+
expect(transaction).to_not receive(:set_error)
|
|
844
|
+
expect(transaction).to_not receive(:set_tags)
|
|
845
|
+
expect(transaction).to_not receive(:set_namespace)
|
|
846
|
+
|
|
847
|
+
Appsignal.set_error(nil)
|
|
848
|
+
end
|
|
849
|
+
end
|
|
850
|
+
|
|
851
|
+
context "with tags" do
|
|
852
|
+
let(:tags) { { "foo" => "bar" } }
|
|
853
|
+
|
|
854
|
+
it "sets the tags on the transaction" do
|
|
855
|
+
expect(transaction).to receive(:set_error).with(error)
|
|
856
|
+
expect(transaction).to receive(:set_tags).with(tags)
|
|
857
|
+
expect(transaction).to_not receive(:set_namespace)
|
|
858
|
+
|
|
859
|
+
Appsignal.set_error(error, tags)
|
|
860
|
+
end
|
|
861
|
+
end
|
|
862
|
+
|
|
863
|
+
context "with namespace" do
|
|
864
|
+
let(:namespace) { "admin" }
|
|
865
|
+
|
|
866
|
+
it "sets the namespace on the transaction" do
|
|
867
|
+
expect(transaction).to receive(:set_error).with(error)
|
|
868
|
+
expect(transaction).to_not receive(:set_tags)
|
|
869
|
+
expect(transaction).to receive(:set_namespace).with(namespace)
|
|
870
|
+
|
|
871
|
+
Appsignal.set_error(error, nil, namespace)
|
|
872
|
+
end
|
|
873
|
+
end
|
|
874
|
+
end
|
|
875
|
+
|
|
876
|
+
context "when there is no active transaction" do
|
|
877
|
+
it "does nothing" do
|
|
878
|
+
allow(Appsignal::Transaction).to receive(:current).and_return(nil)
|
|
879
|
+
|
|
880
|
+
expect(transaction).to_not receive(:set_error)
|
|
881
|
+
|
|
882
|
+
Appsignal.set_error(error)
|
|
883
|
+
end
|
|
884
|
+
end
|
|
885
|
+
end
|
|
886
|
+
|
|
887
|
+
describe ".set_action" do
|
|
888
|
+
before { allow(Appsignal::Transaction).to receive(:current).and_return(transaction) }
|
|
889
|
+
|
|
890
|
+
it "should set the namespace to the current transaction" do
|
|
891
|
+
expect(transaction).to receive(:set_action).with("custom")
|
|
892
|
+
|
|
893
|
+
Appsignal.set_action("custom")
|
|
894
|
+
end
|
|
895
|
+
|
|
896
|
+
it "should do nothing if there is no current transaction" do
|
|
897
|
+
allow(Appsignal::Transaction).to receive(:current).and_return(nil)
|
|
898
|
+
|
|
899
|
+
expect(transaction).to_not receive(:set_action)
|
|
900
|
+
|
|
901
|
+
Appsignal.set_action("custom")
|
|
902
|
+
end
|
|
903
|
+
|
|
904
|
+
it "should do nothing if the error is nil" do
|
|
905
|
+
expect(transaction).to_not receive(:set_action)
|
|
906
|
+
|
|
907
|
+
Appsignal.set_action(nil)
|
|
908
|
+
end
|
|
909
|
+
end
|
|
910
|
+
|
|
911
|
+
describe ".set_namespace" do
|
|
912
|
+
before { allow(Appsignal::Transaction).to receive(:current).and_return(transaction) }
|
|
913
|
+
|
|
914
|
+
it "should set the namespace to the current transaction" do
|
|
915
|
+
expect(transaction).to receive(:set_namespace).with("custom")
|
|
916
|
+
|
|
917
|
+
Appsignal.set_namespace("custom")
|
|
918
|
+
end
|
|
919
|
+
|
|
920
|
+
it "should do nothing if there is no current transaction" do
|
|
921
|
+
allow(Appsignal::Transaction).to receive(:current).and_return(nil)
|
|
922
|
+
|
|
923
|
+
expect(transaction).to_not receive(:set_namespace)
|
|
924
|
+
|
|
925
|
+
Appsignal.set_namespace("custom")
|
|
926
|
+
end
|
|
927
|
+
|
|
928
|
+
it "should do nothing if the error is nil" do
|
|
929
|
+
expect(transaction).to_not receive(:set_namespace)
|
|
930
|
+
|
|
931
|
+
Appsignal.set_namespace(nil)
|
|
932
|
+
end
|
|
933
|
+
end
|
|
934
|
+
|
|
935
|
+
describe ".instrument" do
|
|
936
|
+
it_behaves_like "instrument helper" do
|
|
937
|
+
let(:instrumenter) { Appsignal }
|
|
938
|
+
before do
|
|
939
|
+
expect(Appsignal::Transaction).to receive(:current).at_least(:once).and_return(transaction)
|
|
940
|
+
end
|
|
941
|
+
end
|
|
942
|
+
end
|
|
943
|
+
|
|
944
|
+
describe ".instrument_sql" do
|
|
945
|
+
before do
|
|
946
|
+
expect(Appsignal::Transaction).to receive(:current).at_least(:once).and_return(transaction)
|
|
947
|
+
end
|
|
948
|
+
|
|
949
|
+
it "creates an SQL event on the transaction" do
|
|
950
|
+
expect(transaction).to receive(:start_event)
|
|
951
|
+
expect(transaction).to receive(:finish_event)
|
|
952
|
+
.with("name", "title", "body", Appsignal::EventFormatter::SQL_BODY_FORMAT)
|
|
953
|
+
|
|
954
|
+
result = Appsignal.instrument_sql "name", "title", "body" do
|
|
955
|
+
"return value"
|
|
956
|
+
end
|
|
957
|
+
expect(result).to eq "return value"
|
|
958
|
+
end
|
|
959
|
+
end
|
|
960
|
+
|
|
961
|
+
describe ".without_instrumentation" do
|
|
962
|
+
let(:transaction) { double }
|
|
963
|
+
before { allow(Appsignal::Transaction).to receive(:current).and_return(transaction) }
|
|
964
|
+
|
|
965
|
+
it "should pause and unpause the transaction around the block" do
|
|
966
|
+
expect(transaction).to receive(:pause!)
|
|
967
|
+
expect(transaction).to receive(:resume!)
|
|
968
|
+
end
|
|
969
|
+
|
|
970
|
+
context "without transaction" do
|
|
971
|
+
let(:transaction) { nil }
|
|
972
|
+
|
|
973
|
+
it "should not crash" do
|
|
974
|
+
# just execute the after block
|
|
975
|
+
end
|
|
976
|
+
end
|
|
977
|
+
|
|
978
|
+
after do
|
|
979
|
+
Appsignal.without_instrumentation do
|
|
980
|
+
# nothing
|
|
981
|
+
end
|
|
982
|
+
end
|
|
983
|
+
end
|
|
984
|
+
|
|
985
|
+
describe ".is_ignored_error?" do
|
|
986
|
+
let(:error) { StandardError.new }
|
|
987
|
+
let(:err_stream) { std_stream }
|
|
988
|
+
let(:stderr) { err_stream.read }
|
|
989
|
+
before do
|
|
990
|
+
allow(Appsignal).to receive(:config).and_return(:ignore_errors => ["StandardError"])
|
|
991
|
+
end
|
|
992
|
+
|
|
993
|
+
subject do
|
|
994
|
+
capture_std_streams(std_stream, err_stream) do
|
|
995
|
+
Appsignal.is_ignored_error?(error)
|
|
996
|
+
end
|
|
997
|
+
end
|
|
998
|
+
|
|
999
|
+
it "should return true if it's in the ignored list" do
|
|
1000
|
+
is_expected.to be_truthy
|
|
1001
|
+
end
|
|
1002
|
+
|
|
1003
|
+
it "outputs deprecated warning" do
|
|
1004
|
+
subject
|
|
1005
|
+
expect(stderr).to include("Appsignal.is_ignored_error? is deprecated with no replacement.")
|
|
1006
|
+
end
|
|
1007
|
+
|
|
1008
|
+
context "when error is not in the ignored list" do
|
|
1009
|
+
let(:error) { Object.new }
|
|
1010
|
+
|
|
1011
|
+
it "should return false" do
|
|
1012
|
+
is_expected.to be_falsy
|
|
1013
|
+
end
|
|
1014
|
+
end
|
|
1015
|
+
end
|
|
1016
|
+
|
|
1017
|
+
describe ".is_ignored_action?" do
|
|
1018
|
+
let(:action) { "TestController#isup" }
|
|
1019
|
+
let(:err_stream) { std_stream }
|
|
1020
|
+
let(:stderr) { err_stream.read }
|
|
1021
|
+
before do
|
|
1022
|
+
allow(Appsignal).to receive(:config).and_return(:ignore_actions => "TestController#isup")
|
|
1023
|
+
end
|
|
1024
|
+
|
|
1025
|
+
subject do
|
|
1026
|
+
capture_std_streams(std_stream, err_stream) do
|
|
1027
|
+
Appsignal.is_ignored_action?(action)
|
|
1028
|
+
end
|
|
1029
|
+
end
|
|
1030
|
+
|
|
1031
|
+
it "should return true if it's in the ignored list" do
|
|
1032
|
+
is_expected.to be_truthy
|
|
1033
|
+
end
|
|
1034
|
+
|
|
1035
|
+
it "outputs deprecated warning" do
|
|
1036
|
+
subject
|
|
1037
|
+
expect(stderr).to include("Appsignal.is_ignored_action? is deprecated with no replacement.")
|
|
1038
|
+
end
|
|
1039
|
+
|
|
1040
|
+
context "when action is not in the ingore list" do
|
|
1041
|
+
let(:action) { "TestController#other_action" }
|
|
1042
|
+
|
|
1043
|
+
it "should return false" do
|
|
1044
|
+
is_expected.to be_falsy
|
|
1045
|
+
end
|
|
1046
|
+
end
|
|
1047
|
+
end
|
|
1048
|
+
end
|
|
1049
|
+
end
|