appsignal 2.11.0.beta.4-java → 2.11.2-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.semaphore/semaphore.yml +254 -1
  3. data/CHANGELOG.md +27 -0
  4. data/README.md +20 -5
  5. data/Rakefile +27 -9
  6. data/appsignal.gemspec +1 -1
  7. data/build_matrix.yml +15 -2
  8. data/ext/Rakefile +2 -0
  9. data/ext/agent.yml +17 -25
  10. data/ext/appsignal_extension.c +1 -1
  11. data/ext/base.rb +19 -9
  12. data/ext/extconf.rb +2 -0
  13. data/gemfiles/no_dependencies.gemfile +7 -0
  14. data/gemfiles/resque-2.gemfile +0 -1
  15. data/gemfiles/webmachine.gemfile +1 -0
  16. data/lib/appsignal.rb +1 -0
  17. data/lib/appsignal/auth_check.rb +4 -2
  18. data/lib/appsignal/cli/diagnose.rb +1 -1
  19. data/lib/appsignal/cli/diagnose/utils.rb +8 -11
  20. data/lib/appsignal/cli/install.rb +5 -8
  21. data/lib/appsignal/config.rb +82 -17
  22. data/lib/appsignal/extension.rb +6 -5
  23. data/lib/appsignal/extension/jruby.rb +6 -5
  24. data/lib/appsignal/helpers/instrumentation.rb +32 -0
  25. data/lib/appsignal/hooks.rb +24 -0
  26. data/lib/appsignal/hooks/action_mailer.rb +22 -0
  27. data/lib/appsignal/hooks/active_job.rb +32 -9
  28. data/lib/appsignal/hooks/active_support_notifications.rb +72 -0
  29. data/lib/appsignal/hooks/puma.rb +0 -1
  30. data/lib/appsignal/hooks/sidekiq.rb +0 -1
  31. data/lib/appsignal/probes.rb +7 -0
  32. data/lib/appsignal/probes/puma.rb +1 -1
  33. data/lib/appsignal/probes/sidekiq.rb +3 -1
  34. data/lib/appsignal/transaction.rb +30 -2
  35. data/lib/appsignal/utils/deprecation_message.rb +1 -1
  36. data/lib/appsignal/version.rb +1 -1
  37. data/spec/lib/appsignal/auth_check_spec.rb +23 -0
  38. data/spec/lib/appsignal/capistrano2_spec.rb +1 -1
  39. data/spec/lib/appsignal/capistrano3_spec.rb +1 -1
  40. data/spec/lib/appsignal/cli/diagnose_spec.rb +42 -0
  41. data/spec/lib/appsignal/config_spec.rb +39 -1
  42. data/spec/lib/appsignal/extension/jruby_spec.rb +31 -28
  43. data/spec/lib/appsignal/extension_install_failure_spec.rb +23 -0
  44. data/spec/lib/appsignal/hooks/action_mailer_spec.rb +54 -0
  45. data/spec/lib/appsignal/hooks/active_support_notifications/finish_with_state_shared_examples.rb +35 -0
  46. data/spec/lib/appsignal/hooks/active_support_notifications/instrument_shared_examples.rb +145 -0
  47. data/spec/lib/appsignal/hooks/active_support_notifications/start_finish_shared_examples.rb +69 -0
  48. data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +9 -137
  49. data/spec/lib/appsignal/hooks/activejob_spec.rb +44 -1
  50. data/spec/lib/appsignal/hooks/resque_spec.rb +10 -2
  51. data/spec/lib/appsignal/hooks/sidekiq_spec.rb +4 -2
  52. data/spec/lib/appsignal/hooks_spec.rb +57 -0
  53. data/spec/lib/appsignal/marker_spec.rb +1 -1
  54. data/spec/lib/appsignal/transaction_spec.rb +55 -0
  55. data/spec/lib/appsignal_spec.rb +30 -0
  56. data/spec/spec_helper.rb +5 -0
  57. data/spec/support/helpers/config_helpers.rb +3 -2
  58. data/spec/support/helpers/dependency_helper.rb +4 -0
  59. data/spec/support/helpers/transaction_helpers.rb +1 -1
  60. data/spec/support/testing.rb +19 -19
  61. metadata +17 -5
@@ -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
@@ -154,9 +154,11 @@ if DependencyHelper.active_job_present?
154
154
  end
155
155
 
156
156
  it "reports the priority as tag on the transaction" do
157
- tags = { :priority => 10, :queue => queue }
157
+ tags = { :queue => queue }
158
158
  expect(Appsignal).to receive(:increment_counter)
159
159
  .with("active_job_queue_job_count", 1, tags.merge(:status => :processed))
160
+ expect(Appsignal).to receive(:increment_counter)
161
+ .with("active_job_queue_priority_job_count", 1, tags.merge(:priority => 10, :status => :processed))
160
162
 
161
163
  perform_job(ActiveJobPriorityTestJob)
162
164
 
@@ -208,6 +210,47 @@ if DependencyHelper.active_job_present?
208
210
  .map { |event| event["name"] }
209
211
  expect(events).to eq(["perform_start.active_job", "perform.active_job"])
210
212
  end
213
+
214
+ if DependencyHelper.rails_version >= Gem::Version.new("5.0.0")
215
+ context "with priority" do
216
+ before do
217
+ class ActiveJobErrorPriorityTestJob < ActiveJob::Base
218
+ queue_with_priority 10
219
+
220
+ def perform(*_args)
221
+ raise "uh oh"
222
+ end
223
+ end
224
+ end
225
+ after do
226
+ Object.send(:remove_const, :ActiveJobErrorPriorityTestJob)
227
+ end
228
+
229
+ it "reports the priority as tag on the transaction" do
230
+ tags = { :queue => queue }
231
+ expect(Appsignal).to receive(:increment_counter)
232
+ .with("active_job_queue_job_count", 1, tags.merge(:status => :processed))
233
+ expect(Appsignal).to receive(:increment_counter)
234
+ .with("active_job_queue_job_count", 1, tags.merge(:status => :failed))
235
+ expect(Appsignal).to receive(:increment_counter)
236
+ .with("active_job_queue_priority_job_count", 1, tags.merge(:priority => 10, :status => :processed))
237
+ expect(Appsignal).to receive(:increment_counter)
238
+ .with("active_job_queue_priority_job_count", 1, tags.merge(:priority => 10, :status => :failed))
239
+
240
+ expect do
241
+ perform_job(ActiveJobErrorPriorityTestJob)
242
+ end.to raise_error(RuntimeError, "uh oh")
243
+
244
+ transaction = last_transaction
245
+ transaction_hash = transaction.to_h
246
+ expect(transaction_hash).to include(
247
+ "sample_data" => hash_including(
248
+ "tags" => hash_including("queue" => queue, "priority" => 10)
249
+ )
250
+ )
251
+ end
252
+ end
253
+ end
211
254
  end
212
255
 
213
256
  context "when wrapped in another transaction" do