appsignal 2.11.0.beta.5-java → 2.11.3-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.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/.semaphore/semaphore.yml +197 -0
  3. data/CHANGELOG.md +18 -0
  4. data/README.md +16 -1
  5. data/Rakefile +11 -5
  6. data/build_matrix.yml +13 -0
  7. data/ext/agent.yml +17 -25
  8. data/ext/appsignal_extension.c +1 -1
  9. data/ext/base.rb +12 -9
  10. data/gemfiles/no_dependencies.gemfile +7 -0
  11. data/gemfiles/resque-2.gemfile +0 -1
  12. data/gemfiles/webmachine.gemfile +1 -0
  13. data/lib/appsignal/cli/diagnose/utils.rb +8 -11
  14. data/lib/appsignal/cli/install.rb +5 -8
  15. data/lib/appsignal/config.rb +47 -15
  16. data/lib/appsignal/helpers/instrumentation.rb +32 -0
  17. data/lib/appsignal/hooks.rb +1 -0
  18. data/lib/appsignal/hooks/action_mailer.rb +22 -0
  19. data/lib/appsignal/hooks/active_support_notifications.rb +72 -0
  20. data/lib/appsignal/hooks/shoryuken.rb +43 -4
  21. data/lib/appsignal/transaction.rb +30 -2
  22. data/lib/appsignal/version.rb +1 -1
  23. data/spec/lib/appsignal/config_spec.rb +18 -1
  24. data/spec/lib/appsignal/hooks/action_mailer_spec.rb +54 -0
  25. data/spec/lib/appsignal/hooks/active_support_notifications/finish_with_state_shared_examples.rb +35 -0
  26. data/spec/lib/appsignal/hooks/active_support_notifications/instrument_shared_examples.rb +145 -0
  27. data/spec/lib/appsignal/hooks/active_support_notifications/start_finish_shared_examples.rb +69 -0
  28. data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +9 -137
  29. data/spec/lib/appsignal/hooks/resque_spec.rb +10 -2
  30. data/spec/lib/appsignal/hooks/shoryuken_spec.rb +151 -104
  31. data/spec/lib/appsignal/hooks/sidekiq_spec.rb +4 -2
  32. data/spec/lib/appsignal/transaction_spec.rb +55 -0
  33. data/spec/lib/appsignal_spec.rb +30 -0
  34. data/spec/support/helpers/dependency_helper.rb +4 -0
  35. metadata +14 -5
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Appsignal
4
- VERSION = "2.11.0.beta.5".freeze
4
+ VERSION = "2.11.3".freeze
5
5
  end
@@ -1,4 +1,18 @@
1
1
  describe Appsignal::Config do
2
+ describe "config keys" do
3
+ it "all config keys have an environment variable version registered" do
4
+ config = Appsignal::Config
5
+ mapped_env_keys = config::ENV_TO_KEY_MAPPING.keys.sort
6
+ configured_env_keys = (
7
+ config::ENV_STRING_KEYS +
8
+ config::ENV_BOOLEAN_KEYS +
9
+ config::ENV_ARRAY_KEYS
10
+ ).sort
11
+
12
+ expect(mapped_env_keys).to eql(configured_env_keys)
13
+ end
14
+ end
15
+
2
16
  describe "#initialize" do
3
17
  describe "environment" do
4
18
  context "when environment is nil" do
@@ -418,6 +432,7 @@ describe Appsignal::Config do
418
432
  :debug => true
419
433
  )
420
434
  end
435
+ let(:working_directory_path) { File.join(tmp_dir, "test_working_directory_path") }
421
436
  let(:env_config) do
422
437
  {
423
438
  :running_in_container => true,
@@ -434,7 +449,8 @@ describe Appsignal::Config do
434
449
  :files_world_accessible => false,
435
450
  :request_headers => %w[accept accept-charset],
436
451
  :revision => "v2.5.1",
437
- :send_environment_metadata => false
452
+ :send_environment_metadata => false,
453
+ :working_directory_path => working_directory_path
438
454
  }
439
455
  end
440
456
  before do
@@ -452,6 +468,7 @@ describe Appsignal::Config do
452
468
  ENV["APPSIGNAL_FILES_WORLD_ACCESSIBLE"] = "false"
453
469
  ENV["APPSIGNAL_REQUEST_HEADERS"] = "accept,accept-charset"
454
470
  ENV["APPSIGNAL_SEND_ENVIRONMENT_METADATA"] = "false"
471
+ ENV["APPSIGNAL_WORKING_DIRECTORY_PATH"] = working_directory_path
455
472
  ENV["APP_REVISION"] = "v2.5.1"
456
473
  end
457
474
 
@@ -0,0 +1,54 @@
1
+ describe Appsignal::Hooks::ActionMailerHook do
2
+ if DependencyHelper.action_mailer_present? &&
3
+ DependencyHelper.rails_version >= Gem::Version.new("4.0.0")
4
+ context "with ActionMailer" do
5
+ require "action_mailer"
6
+
7
+ class UserMailer < ActionMailer::Base
8
+ default :from => "test@example.com"
9
+
10
+ def welcome
11
+ mail(:to => "test@example.com", :subject => "ActionMailer test", :content_type => "text/html") do |format|
12
+ format.html { render :html => "This is a test" }
13
+ end
14
+ end
15
+ end
16
+ UserMailer.delivery_method = :test
17
+
18
+ describe ".dependencies_present?" do
19
+ subject { described_class.new.dependencies_present? }
20
+
21
+ it "returns true" do
22
+ is_expected.to be_truthy
23
+ end
24
+ end
25
+
26
+ describe ".install" do
27
+ before do
28
+ start_agent
29
+ expect(Appsignal.active?).to be_truthy
30
+ end
31
+
32
+ it "is subscribed to 'process.action_mailer' and processes instrumentation" do
33
+ expect(Appsignal).to receive(:increment_counter).with(
34
+ :action_mailer_process,
35
+ 1,
36
+ :mailer => "UserMailer", :action => :welcome
37
+ )
38
+
39
+ UserMailer.welcome.deliver_now
40
+ end
41
+ end
42
+ end
43
+ else
44
+ context "without ActionMailer" do
45
+ describe ".dependencies_present?" do
46
+ subject { described_class.new.dependencies_present? }
47
+
48
+ it "returns false" do
49
+ is_expected.to be_falsy
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,35 @@
1
+ shared_examples "activesupport finish_with_state override" do
2
+ let(:instrumenter) { as.instrumenter }
3
+
4
+ it "instruments an ActiveSupport::Notifications.start/finish event with payload on finish" do
5
+ listeners_state = instrumenter.start("sql.active_record", {})
6
+ instrumenter.finish_with_state(listeners_state, "sql.active_record", :sql => "SQL")
7
+
8
+ expect(transaction.to_h["events"]).to match([
9
+ {
10
+ "allocation_count" => kind_of(Integer),
11
+ "body" => "SQL",
12
+ "body_format" => Appsignal::EventFormatter::SQL_BODY_FORMAT,
13
+ "child_allocation_count" => kind_of(Integer),
14
+ "child_duration" => kind_of(Float),
15
+ "child_gc_duration" => kind_of(Float),
16
+ "count" => 1,
17
+ "duration" => kind_of(Float),
18
+ "gc_duration" => kind_of(Float),
19
+ "name" => "sql.active_record",
20
+ "start" => kind_of(Float),
21
+ "title" => ""
22
+ }
23
+ ])
24
+ end
25
+
26
+ it "does not instrument events whose name starts with a bang" do
27
+ expect(Appsignal::Transaction.current).not_to receive(:start_event)
28
+ expect(Appsignal::Transaction.current).not_to receive(:finish_event)
29
+
30
+ listeners_state = instrumenter.start("!sql.active_record", {})
31
+ instrumenter.finish_with_state(listeners_state, "!sql.active_record", :sql => "SQL")
32
+
33
+ expect(transaction.to_h["events"]).to be_empty
34
+ end
35
+ end
@@ -0,0 +1,145 @@
1
+ shared_examples "activesupport instrument override" do
2
+ it "instruments an ActiveSupport::Notifications.instrument event" do
3
+ return_value = as.instrument("sql.active_record", :sql => "SQL") do
4
+ "value"
5
+ end
6
+
7
+ expect(return_value).to eq "value"
8
+ expect(transaction.to_h["events"]).to match([
9
+ {
10
+ "allocation_count" => kind_of(Integer),
11
+ "body" => "SQL",
12
+ "body_format" => Appsignal::EventFormatter::SQL_BODY_FORMAT,
13
+ "child_allocation_count" => kind_of(Integer),
14
+ "child_duration" => kind_of(Float),
15
+ "child_gc_duration" => kind_of(Float),
16
+ "count" => 1,
17
+ "duration" => kind_of(Float),
18
+ "gc_duration" => kind_of(Float),
19
+ "name" => "sql.active_record",
20
+ "start" => kind_of(Float),
21
+ "title" => ""
22
+ }
23
+ ])
24
+ end
25
+
26
+ it "instruments an ActiveSupport::Notifications.instrument event with no registered formatter" do
27
+ return_value = as.instrument("no-registered.formatter", :key => "something") do
28
+ "value"
29
+ end
30
+
31
+ expect(return_value).to eq "value"
32
+ expect(transaction.to_h["events"]).to match([
33
+ {
34
+ "allocation_count" => kind_of(Integer),
35
+ "body" => "",
36
+ "body_format" => Appsignal::EventFormatter::DEFAULT,
37
+ "child_allocation_count" => kind_of(Integer),
38
+ "child_duration" => kind_of(Float),
39
+ "child_gc_duration" => kind_of(Float),
40
+ "count" => 1,
41
+ "duration" => kind_of(Float),
42
+ "gc_duration" => kind_of(Float),
43
+ "name" => "no-registered.formatter",
44
+ "start" => kind_of(Float),
45
+ "title" => ""
46
+ }
47
+ ])
48
+ end
49
+
50
+ it "converts non-string names to strings" do
51
+ as.instrument(:not_a_string) {}
52
+ expect(transaction.to_h["events"]).to match([
53
+ {
54
+ "allocation_count" => kind_of(Integer),
55
+ "body" => "",
56
+ "body_format" => Appsignal::EventFormatter::DEFAULT,
57
+ "child_allocation_count" => kind_of(Integer),
58
+ "child_duration" => kind_of(Float),
59
+ "child_gc_duration" => kind_of(Float),
60
+ "count" => 1,
61
+ "duration" => kind_of(Float),
62
+ "gc_duration" => kind_of(Float),
63
+ "name" => "not_a_string",
64
+ "start" => kind_of(Float),
65
+ "title" => ""
66
+ }
67
+ ])
68
+ end
69
+
70
+ it "does not instrument events whose name starts with a bang" do
71
+ expect(Appsignal::Transaction.current).not_to receive(:start_event)
72
+ expect(Appsignal::Transaction.current).not_to receive(:finish_event)
73
+
74
+ return_value = as.instrument("!sql.active_record", :sql => "SQL") do
75
+ "value"
76
+ end
77
+
78
+ expect(return_value).to eq "value"
79
+ end
80
+
81
+ context "when an error is raised in an instrumented block" do
82
+ it "instruments an ActiveSupport::Notifications.instrument event" do
83
+ expect do
84
+ as.instrument("sql.active_record", :sql => "SQL") do
85
+ raise ExampleException, "foo"
86
+ end
87
+ end.to raise_error(ExampleException, "foo")
88
+
89
+ expect(transaction.to_h["events"]).to match([
90
+ {
91
+ "allocation_count" => kind_of(Integer),
92
+ "body" => "SQL",
93
+ "body_format" => Appsignal::EventFormatter::SQL_BODY_FORMAT,
94
+ "child_allocation_count" => kind_of(Integer),
95
+ "child_duration" => kind_of(Float),
96
+ "child_gc_duration" => kind_of(Float),
97
+ "count" => 1,
98
+ "duration" => kind_of(Float),
99
+ "gc_duration" => kind_of(Float),
100
+ "name" => "sql.active_record",
101
+ "start" => kind_of(Float),
102
+ "title" => ""
103
+ }
104
+ ])
105
+ end
106
+ end
107
+
108
+ context "when a message is thrown in an instrumented block" do
109
+ it "instruments an ActiveSupport::Notifications.instrument event" do
110
+ expect do
111
+ as.instrument("sql.active_record", :sql => "SQL") do
112
+ throw :foo
113
+ end
114
+ end.to throw_symbol(:foo)
115
+
116
+ expect(transaction.to_h["events"]).to match([
117
+ {
118
+ "allocation_count" => kind_of(Integer),
119
+ "body" => "SQL",
120
+ "body_format" => Appsignal::EventFormatter::SQL_BODY_FORMAT,
121
+ "child_allocation_count" => kind_of(Integer),
122
+ "child_duration" => kind_of(Float),
123
+ "child_gc_duration" => kind_of(Float),
124
+ "count" => 1,
125
+ "duration" => kind_of(Float),
126
+ "gc_duration" => kind_of(Float),
127
+ "name" => "sql.active_record",
128
+ "start" => kind_of(Float),
129
+ "title" => ""
130
+ }
131
+ ])
132
+ end
133
+ end
134
+
135
+ context "when a transaction is completed in an instrumented block" do
136
+ it "does not complete the ActiveSupport::Notifications.instrument event" do
137
+ expect(transaction).to receive(:complete)
138
+ as.instrument("sql.active_record", :sql => "SQL") do
139
+ Appsignal::Transaction.complete_current!
140
+ end
141
+
142
+ expect(transaction.to_h["events"]).to match([])
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,69 @@
1
+ shared_examples "activesupport start finish override" do
2
+ let(:instrumenter) { as.instrumenter }
3
+
4
+ it "instruments an ActiveSupport::Notifications.start/finish event with payload on start ignores payload" do
5
+ instrumenter.start("sql.active_record", :sql => "SQL")
6
+ instrumenter.finish("sql.active_record", {})
7
+
8
+ expect(transaction.to_h["events"]).to match([
9
+ {
10
+ "allocation_count" => kind_of(Integer),
11
+ "body" => "",
12
+ "body_format" => Appsignal::EventFormatter::SQL_BODY_FORMAT,
13
+ "child_allocation_count" => kind_of(Integer),
14
+ "child_duration" => kind_of(Float),
15
+ "child_gc_duration" => kind_of(Float),
16
+ "count" => 1,
17
+ "duration" => kind_of(Float),
18
+ "gc_duration" => kind_of(Float),
19
+ "name" => "sql.active_record",
20
+ "start" => kind_of(Float),
21
+ "title" => ""
22
+ }
23
+ ])
24
+ end
25
+
26
+ it "instruments an ActiveSupport::Notifications.start/finish event with payload on finish" do
27
+ instrumenter.start("sql.active_record", {})
28
+ instrumenter.finish("sql.active_record", :sql => "SQL")
29
+
30
+ expect(transaction.to_h["events"]).to match([
31
+ {
32
+ "allocation_count" => kind_of(Integer),
33
+ "body" => "SQL",
34
+ "body_format" => Appsignal::EventFormatter::SQL_BODY_FORMAT,
35
+ "child_allocation_count" => kind_of(Integer),
36
+ "child_duration" => kind_of(Float),
37
+ "child_gc_duration" => kind_of(Float),
38
+ "count" => 1,
39
+ "duration" => kind_of(Float),
40
+ "gc_duration" => kind_of(Float),
41
+ "name" => "sql.active_record",
42
+ "start" => kind_of(Float),
43
+ "title" => ""
44
+ }
45
+ ])
46
+ end
47
+
48
+ it "does not instrument events whose name starts with a bang" do
49
+ expect(Appsignal::Transaction.current).not_to receive(:start_event)
50
+ expect(Appsignal::Transaction.current).not_to receive(:finish_event)
51
+
52
+ instrumenter.start("!sql.active_record", {})
53
+ instrumenter.finish("!sql.active_record", {})
54
+
55
+ expect(transaction.to_h["events"]).to be_empty
56
+ end
57
+
58
+ context "when a transaction is completed in an instrumented block" do
59
+ it "does not complete the ActiveSupport::Notifications.instrument event" do
60
+ expect(transaction).to receive(:complete)
61
+
62
+ instrumenter.start("sql.active_record", {})
63
+ Appsignal::Transaction.complete_current!
64
+ instrumenter.finish("sql.active_record", {})
65
+
66
+ expect(transaction.to_h["events"]).to match([])
67
+ end
68
+ end
69
+ end
@@ -1,3 +1,5 @@
1
+ require_relative "./active_support_notifications/instrument_shared_examples"
2
+
1
3
  describe Appsignal::Hooks::ActiveSupportNotificationsHook do
2
4
  if active_support_present?
3
5
  let(:notifier) { ActiveSupport::Notifications::Fanout.new }
@@ -18,148 +20,18 @@ describe Appsignal::Hooks::ActiveSupportNotificationsHook do
18
20
  it { is_expected.to be_truthy }
19
21
  end
20
22
 
21
- it "instruments an ActiveSupport::Notifications.instrument event" do
22
- return_value = as.instrument("sql.active_record", :sql => "SQL") do
23
- "value"
24
- end
25
-
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
- ])
43
- end
44
-
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
68
-
69
- it "converts non-string names to strings" do
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
- ])
87
- end
88
-
89
- it "does not instrument events whose name starts with a bang" do
90
- expect(Appsignal::Transaction.current).not_to receive(:start_event)
91
- expect(Appsignal::Transaction.current).not_to receive(:finish_event)
92
-
93
- return_value = as.instrument("!sql.active_record", :sql => "SQL") do
94
- "value"
95
- end
96
-
97
- expect(return_value).to eq "value"
98
- end
99
-
100
- context "when an error is raised in an instrumented block" do
101
- it "instruments an ActiveSupport::Notifications.instrument event" do
102
- expect do
103
- as.instrument("sql.active_record", :sql => "SQL") do
104
- raise ExampleException, "foo"
105
- end
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
- ])
124
- end
125
- end
23
+ it_behaves_like "activesupport instrument override"
126
24
 
127
- context "when a message is thrown in an instrumented block" do
128
- it "instruments an ActiveSupport::Notifications.instrument event" do
129
- expect do
130
- as.instrument("sql.active_record", :sql => "SQL") do
131
- throw :foo
132
- end
133
- end.to throw_symbol(:foo)
25
+ if ::ActiveSupport::Notifications::Instrumenter.method_defined?(:start)
26
+ require_relative "./active_support_notifications/start_finish_shared_examples"
134
27
 
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
28
+ it_behaves_like "activesupport start finish override"
152
29
  end
153
30
 
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
31
+ if ::ActiveSupport::Notifications::Instrumenter.method_defined?(:finish_with_state)
32
+ require_relative "./active_support_notifications/finish_with_state_shared_examples"
160
33
 
161
- expect(transaction.to_h["events"]).to match([])
162
- end
34
+ it_behaves_like "activesupport finish_with_state override"
163
35
  end
164
36
  else
165
37
  describe "#dependencies_present?" do