appsignal 2.4.0.alpha.1 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d33d7ecbdd7ba0817888cd6b6347f2e9289a627b
4
- data.tar.gz: f9c435c47c4403295da1ff78f89d9c1ac45b67f9
3
+ metadata.gz: 73a704494489e09f2d92ffc41f9628aef70e9974
4
+ data.tar.gz: 267fe55728850ffe4802ea0761a748c809235de5
5
5
  SHA512:
6
- metadata.gz: 957c20fa113f260bbd401e3eb95f9266b4edd03f7986a555046e86cb2266e274939691ddd8cc8583406241a06bb3cbf0201b811dbfb0f65990f8972137f8cea8
7
- data.tar.gz: be4355279b8fffbfd45ebaf86f0b180e0311887f37051e9aed6ee69137f71c99fdb79907f18a45fc36404127f652daad51a9ee21a537a8f2e701c253dfbeb24b
6
+ metadata.gz: cd3aa5683ed5c745a828caa4b4971cc1795056c91d990d114cd8e95737ce9bc02419b5255c91761cb3b5bec4aa1fdee9c59b47c6588f52a3f27679342ca2a14e
7
+ data.tar.gz: d2f42c59c32fc1dcfe7be0e64466d0afafc81e4d355b26c5b9618436ed9946b67e8988a960d689ada112798551833c4cc81fe6038a0de9c80487164f00ac3fc5
@@ -30,7 +30,6 @@ gemfile:
30
30
  - "gemfiles/resque.gemfile"
31
31
  - "gemfiles/sequel.gemfile"
32
32
  - "gemfiles/sequel-435.gemfile"
33
- - "gemfiles/sidekiq.gemfile"
34
33
  - "gemfiles/sinatra.gemfile"
35
34
  - "gemfiles/grape.gemfile"
36
35
  - "gemfiles/webmachine.gemfile"
@@ -46,12 +45,6 @@ matrix:
46
45
  - rvm: "jruby-19mode"
47
46
 
48
47
  # Rails 5 doesn't support Ruby < 2.2
49
- - rvm: "2.0.0"
50
- gemfile: "gemfiles/sidekiq.gemfile"
51
- - rvm: "2.1.8"
52
- gemfile: "gemfiles/sidekiq.gemfile"
53
- - rvm: "jruby-19mode"
54
- gemfile: "gemfiles/sidekiq.gemfile"
55
48
  - rvm: "2.0.0"
56
49
  gemfile: "gemfiles/rails-5.0.gemfile"
57
50
  - rvm: "2.1.8"
@@ -1,4 +1,4 @@
1
- # 2.4.0 (alpha)
1
+ # 2.4.0
2
2
  - Add separate GNU linux build. PR #351 and
3
3
  Commit d1763f4dcb685608468a73f3192226f60f66b217
4
4
  - Add separate FreeBSD build
@@ -8,7 +8,11 @@
8
8
  Commit d1763f4dcb685608468a73f3192226f60f66b217
9
9
  - Auto restart agent when none is running
10
10
  Commit d1763f4dcb685608468a73f3192226f60f66b217
11
+ - Add `appsignal_user` Capistrano config option. PR #355
11
12
  - Track Exception-level exceptions. PR #356
13
+ - Add tags and namespace arguments to `Appsignal.listen_for_error`. PR #357
14
+ - Revert Sidekiq delayed extension job action names fix.
15
+ Commit 9b84a098604de5ef5e52645ba7fcb09d84f66eaa
12
16
 
13
17
  # 2.3.7
14
18
  * Support Sidekiq delayed extension job action names better. Now action names
data/README.md CHANGED
@@ -72,7 +72,8 @@ instrumentation anywhere in your code.
72
72
  ```ruby
73
73
  # Simple instrumentation
74
74
  Appsignal.instrument("array_to_hash.expensive_logic", "Complex calculations") do
75
- Hash[["a", 1], ["b", 2], ["c", 3]]
75
+ array = [["a", 1], ["b", 2], ["c", 3]]
76
+ Hash[array]
76
77
  end
77
78
 
78
79
  # Add the query that you're monitoring
@@ -150,7 +151,7 @@ currently. Be sure to check it out!
150
151
  ## Supported systems
151
152
 
152
153
  Currently the AppSignal agent works on most Unix-like operating systems, such
153
- as most Linux distributions and macOS, excluding FreeBSD and Windows.
154
+ as most Linux distributions, FreeBSD, macOS, excluding Microsoft Windows.
154
155
 
155
156
  For more detailed information please visit our [Supported
156
157
  systems][supported-systems] page.
data/Rakefile CHANGED
@@ -14,7 +14,6 @@ GEMFILES = %w(
14
14
  resque
15
15
  sequel
16
16
  sequel-435
17
- sidekiq
18
17
  sinatra
19
18
  grape
20
19
  webmachine
@@ -217,10 +217,37 @@ module Appsignal
217
217
  stop("monitor_single_transaction")
218
218
  end
219
219
 
220
- def listen_for_error
220
+ # Listen for an error to occur and send it to AppSignal.
221
+ #
222
+ # Uses {.send_error} to directly send the error in a separate transaction.
223
+ # Does not add the error to the current transaction.
224
+ #
225
+ # Make sure that AppSignal is integrated in your application beforehand.
226
+ # AppSignal won't record errors unless {Config#active?} is `true`.
227
+ #
228
+ # @example
229
+ # # my_app.rb
230
+ # # setup AppSignal beforehand
231
+ #
232
+ # Appsignal.listen_for_error do
233
+ # # my code
234
+ # raise "foo"
235
+ # end
236
+ #
237
+ # @see Transaction.set_tags
238
+ # @see Transaction.set_namespace
239
+ # @see .send_error
240
+ # @see https://docs.appsignal.com/ruby/instrumentation/integrating-appsignal.html
241
+ # AppSignal integration guide
242
+ #
243
+ # @param tags [Hash, nil]
244
+ # @param namespace [String] the namespace for this error.
245
+ # @yield yields the given block.
246
+ # @return [Object] returns the return value of the given block.
247
+ def listen_for_error(tags = nil, namespace = Appsignal::Transaction::HTTP_REQUEST)
221
248
  yield
222
249
  rescue Exception => error # rubocop:disable Lint/RescueException
223
- send_error(error)
250
+ send_error(error, tags, namespace)
224
251
  raise error
225
252
  end
226
253
  alias :listen_for_exception :listen_for_error
@@ -14,78 +14,32 @@ module Appsignal
14
14
  end
15
15
 
16
16
  def call(_worker, item, _queue)
17
- job = fetch_sidekiq_job { ::Sidekiq::Job.new(item) }
18
- job_metadata = call_and_log_on_error(job, &:item)
19
-
20
- job_action_name = parse_action_name(job)
21
- params = Appsignal::Utils::ParamsSanitizer.sanitize(
22
- call_and_log_on_error(job, &:display_args),
23
- :filter_parameters => Appsignal.config[:filter_parameters]
24
- )
25
-
26
- transaction = Appsignal::Transaction.create(
27
- SecureRandom.uuid,
28
- Appsignal::Transaction::BACKGROUND_JOB,
29
- Appsignal::Transaction::GenericRequest.new(
30
- :queue_start => call_and_log_on_error(job, &:enqueued_at),
31
- :queue_time => call_and_log_on_error(job) { |j| j.latency.to_f * 1000 }
32
- )
33
- )
34
-
35
- Appsignal.instrument "perform_job.sidekiq" do
36
- begin
37
- yield
38
- rescue Exception => exception # rubocop:disable Lint/RescueException
39
- transaction.set_error(exception)
40
- raise exception
17
+ args =
18
+ if item["class"] == "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper"
19
+ item["args"].first["arguments"]
20
+ else
21
+ item["args"]
41
22
  end
42
- end
43
- ensure
44
- if transaction
45
- transaction.set_action_if_nil(job_action_name)
46
- transaction.params = params
47
- formatted_metadata(job_metadata).each do |key, value|
48
- transaction.set_metadata key, value
49
- end
50
- transaction.set_http_or_background_queue_start
51
- Appsignal::Transaction.complete_current!
52
- end
53
- end
54
-
55
- private
56
-
57
- def fetch_sidekiq_job
58
- yield
59
- rescue NameError => e
60
- Appsignal.logger.error("Problem parsing the Sidekiq job data: #{e.inspect}")
61
- nil
62
- end
63
-
64
- def call_and_log_on_error(job)
65
- yield job if job
66
- rescue NameError => e
67
- Appsignal.logger.error("Problem parsing the Sidekiq job data: #{e.inspect}")
68
- nil
69
- end
23
+ params = Appsignal::Utils::ParamsSanitizer.sanitize args,
24
+ :filter_parameters => Appsignal.config[:filter_parameters]
70
25
 
71
- def parse_action_name(job)
72
- # `job.display_class` needs to be called before `job.display_args`,
73
- # see https://github.com/appsignal/appsignal-ruby/pull/348#issuecomment-333629065
74
- action_name = call_and_log_on_error(job, &:display_class)
75
- if action_name =~ /[\.#]+/
76
- action_name
77
- else
78
- # Add `#perform` as default method name for job names without a
79
- # method name
80
- "#{action_name}#perform"
26
+ Appsignal.monitor_transaction(
27
+ "perform_job.sidekiq",
28
+ :class => item["wrapped"] || item["class"],
29
+ :method => "perform",
30
+ :metadata => formatted_metadata(item),
31
+ :params => params,
32
+ :queue_start => item["enqueued_at"],
33
+ :queue_time => (Time.now.to_f - item["enqueued_at"].to_f) * 1000
34
+ ) do
35
+ yield
81
36
  end
82
37
  end
83
38
 
84
39
  def formatted_metadata(item)
85
- {}.tap do |hash|
86
- (item || {}).each do |key, value|
87
- next if job_keys.include?(key)
88
- hash[key] = truncate(string_or_inspect(value))
40
+ {}.tap do |hsh|
41
+ item.each do |key, val|
42
+ hsh[key] = truncate(string_or_inspect(val)) unless job_keys.include?(key)
89
43
  end
90
44
  end
91
45
  end
@@ -99,7 +53,6 @@ module Appsignal
99
53
  end
100
54
 
101
55
  def install
102
- require "sidekiq/api"
103
56
  ::Sidekiq.configure_server do |config|
104
57
  config.server_middleware do |chain|
105
58
  chain.add Appsignal::Hooks::SidekiqPlugin
@@ -1,7 +1,7 @@
1
1
  namespace :appsignal do
2
2
  task :deploy do
3
3
  appsignal_env = fetch(:appsignal_env, fetch(:stage, fetch(:rails_env, fetch(:rack_env, "production"))))
4
- user = ENV["USER"] || ENV["USERNAME"]
4
+ user = fetch(:appsignal_user, ENV["USER"] || ENV["USERNAME"])
5
5
  revision = fetch(:appsignal_revision, fetch(:current_revision))
6
6
 
7
7
  appsignal_config = Appsignal::Config.new(
@@ -10,7 +10,7 @@ module Appsignal
10
10
  namespace :appsignal do
11
11
  task :deploy do
12
12
  env = fetch(:appsignal_env, fetch(:stage, fetch(:rails_env, fetch(:rack_env, "production"))))
13
- user = ENV["USER"] || ENV["USERNAME"]
13
+ user = fetch(:appsignal_user, ENV["USER"] || ENV["USERNAME"])
14
14
  revision = fetch(:appsignal_revision, fetch(:current_revision))
15
15
 
16
16
  appsignal_config = Appsignal::Config.new(
@@ -54,12 +54,6 @@ module Appsignal
54
54
  rescue => e
55
55
  Appsignal.logger.error("Failed to complete transaction ##{current.transaction_id}. #{e.message}")
56
56
  ensure
57
- clear_current_transaction!
58
- end
59
-
60
- # Remove current transaction from current Thread.
61
- # @api private
62
- def clear_current_transaction!
63
57
  Thread.current[:appsignal_transaction] = nil
64
58
  end
65
59
 
@@ -318,7 +312,6 @@ module Appsignal
318
312
  finish_event(name, title, body, body_format)
319
313
  end
320
314
 
321
- # @api private
322
315
  def to_h
323
316
  JSON.parse(@ext.to_json)
324
317
  end
@@ -1,5 +1,5 @@
1
1
  require "yaml"
2
2
 
3
3
  module Appsignal
4
- VERSION = "2.4.0.alpha.1".freeze
4
+ VERSION = "2.4.0".freeze
5
5
  end
@@ -152,6 +152,20 @@ if DependencyHelper.capistrano2_present?
152
152
  end
153
153
  end
154
154
 
155
+ context "with overridden deploy user" do
156
+ before do
157
+ capistrano_config.set(:appsignal_user, "robin")
158
+ stub_marker_request(:user => "robin").to_return(:status => 200)
159
+ run
160
+ end
161
+
162
+ it "transmits the overriden deploy user" do
163
+ expect(output).to include \
164
+ "Notifying AppSignal of deploy with: revision: 503ce0923ed177a3ce000005, user: robin",
165
+ "AppSignal has been notified of this deploy!"
166
+ end
167
+ end
168
+
155
169
  context "with failed request" do
156
170
  before do
157
171
  stub_marker_request.to_return(:status => 500)
@@ -152,6 +152,20 @@ if DependencyHelper.capistrano3_present?
152
152
  end
153
153
  end
154
154
 
155
+ context "with overridden deploy user" do
156
+ before do
157
+ capistrano_config.set(:appsignal_user, "robin")
158
+ stub_marker_request(:user => "robin").to_return(:status => 200)
159
+ run
160
+ end
161
+
162
+ it "transmits the overriden deploy user" do
163
+ expect(output).to include \
164
+ "Notifying AppSignal of deploy with: revision: 503ce0923ed177a3ce000005, user: robin",
165
+ "AppSignal has been notified of this deploy!"
166
+ end
167
+ end
168
+
155
169
  if Gem::Version.new(Capistrano::VERSION) >= Gem::Version.new("3.5.0")
156
170
  context "when dry run" do
157
171
  before do
@@ -1,101 +1,145 @@
1
- if DependencyHelper.sidekiq_present?
2
- describe Appsignal::Hooks::SidekiqPlugin, :with_sidekiq_error => false do
3
- let(:namespace) { Appsignal::Transaction::BACKGROUND_JOB }
4
- let(:worker) { anything }
5
- let(:queue) { anything }
6
- let(:args) { ["Model", 1] }
7
- let(:job_class) { "TestClass" }
8
- let(:item) do
9
- {
10
- "class" => job_class,
11
- "retry_count" => 0,
12
- "queue" => "default",
13
- "enqueued_at" => Time.parse("01-01-2001 10:00:00UTC").to_f,
14
- "args" => args,
15
- "extra" => "data"
16
- }
17
- end
18
- let(:plugin) { Appsignal::Hooks::SidekiqPlugin.new }
19
- let(:test_store) { {} }
1
+ describe Appsignal::Hooks::SidekiqPlugin do
2
+ let(:worker) { double }
3
+ let(:queue) { double }
4
+ let(:current_transaction) { background_job_transaction }
5
+ let(:args) { ["Model", 1] }
6
+ let(:item) do
7
+ {
8
+ "class" => "TestClass",
9
+ "retry_count" => 0,
10
+ "queue" => "default",
11
+ "enqueued_at" => Time.parse("01-01-2001 10:00:00UTC"),
12
+ "args" => args,
13
+ "extra" => "data"
14
+ }
15
+ end
16
+ let(:plugin) { Appsignal::Hooks::SidekiqPlugin.new }
20
17
 
21
- before :with_sidekiq_error => false do
22
- # Stub calls to extension, because that would remove the transaction
23
- # from the extension.
24
- allow_any_instance_of(Appsignal::Extension::Transaction).to receive(:finish).and_return(true)
25
- allow_any_instance_of(Appsignal::Extension::Transaction).to receive(:complete)
18
+ before do
19
+ allow(Appsignal::Transaction).to receive(:current).and_return(current_transaction)
20
+ start_agent
21
+ end
26
22
 
27
- # Stub removal of current transaction from current thread so we can fetch
28
- # it later.
29
- expect(Appsignal::Transaction).to receive(:clear_current_transaction!).at_least(:once) do
30
- transaction = Thread.current[:appsignal_transaction]
31
- test_store[:transaction] = transaction if transaction
23
+ context "with a performance call" do
24
+ after do
25
+ Timecop.freeze(Time.parse("01-01-2001 10:01:00UTC")) do
26
+ Appsignal::Hooks::SidekiqPlugin.new.call(worker, item, queue) do
27
+ # nothing
28
+ end
32
29
  end
33
30
  end
34
- before do
35
- start_agent
31
+
32
+ it "wraps it in a transaction with the correct params" do
33
+ expect(Appsignal).to receive(:monitor_transaction).with(
34
+ "perform_job.sidekiq",
35
+ :class => "TestClass",
36
+ :method => "perform",
37
+ :metadata => {
38
+ "retry_count" => "0",
39
+ "queue" => "default",
40
+ "extra" => "data"
41
+ },
42
+ :params => ["Model", 1],
43
+ :queue_start => Time.parse("01-01-2001 10:00:00UTC"),
44
+ :queue_time => 60_000.to_f
45
+ )
36
46
  end
37
- after { clear_current_transaction! }
38
47
 
39
- context "when there's a problem with calling the Sidekiq::Job class", :with_sidekiq_error => true do
40
- let(:log) { StringIO.new }
41
- before do
42
- Appsignal.logger = Logger.new(log)
43
- expect(::Sidekiq::Job).to receive(:new).and_raise(NameError, "woops")
44
- perform_job
48
+ context "with more complex arguments" do
49
+ let(:default_params) do
50
+ {
51
+ :class => "TestClass",
52
+ :method => "perform",
53
+ :metadata => {
54
+ "retry_count" => "0",
55
+ "queue" => "default",
56
+ "extra" => "data"
57
+ },
58
+ :params => {
59
+ :foo => "Foo",
60
+ :bar => "Bar"
61
+ },
62
+ :queue_start => Time.parse("01-01-2001 10:00:00UTC"),
63
+ :queue_time => 60_000.to_f
64
+ }
65
+ end
66
+ let(:args) do
67
+ {
68
+ :foo => "Foo",
69
+ :bar => "Bar"
70
+ }
45
71
  end
46
72
 
47
- it "does not record a transaction and logs an error" do
48
- expect(transaction).to be_nil
49
- log.rewind
50
- expect(log.read).to include(
51
- "ERROR",
52
- "Problem parsing the Sidekiq job data: #<NameError: woops>"
73
+ it "adds the more complex arguments" do
74
+ expect(Appsignal).to receive(:monitor_transaction).with(
75
+ "perform_job.sidekiq",
76
+ default_params.merge(
77
+ :params => {
78
+ :foo => "Foo",
79
+ :bar => "Bar"
80
+ }
81
+ )
53
82
  )
54
83
  end
55
- end
56
84
 
57
- context "with a performance call" do
58
- it "creates a transaction with performance events" do
59
- perform_job
85
+ context "with parameter filtering" do
86
+ before do
87
+ Appsignal.config = project_fixture_config("production")
88
+ Appsignal.config[:filter_parameters] = ["foo"]
89
+ end
60
90
 
61
- transaction_hash = transaction.to_h
62
- expect(transaction_hash).to include(
63
- "id" => kind_of(String),
64
- "action" => "TestClass#perform",
65
- "error" => nil,
66
- "namespace" => namespace,
67
- "metadata" => {
68
- "extra" => "data",
69
- "queue" => "default",
70
- "retry_count" => "0"
71
- },
72
- "sample_data" => {
73
- "environment" => {},
74
- "params" => args,
75
- "tags" => {}
76
- }
77
- )
78
- # TODO: Not available in transaction.to_h yet.
79
- # https://github.com/appsignal/appsignal-agent/issues/293
80
- expect(transaction.request.env).to eq(
81
- :queue_start => Time.parse("01-01-2001 10:00:00UTC"),
82
- :queue_time => 60_000.0
83
- )
84
- expect_transaction_to_have_sidekiq_event(transaction_hash)
91
+ it "filters selected arguments" do
92
+ expect(Appsignal).to receive(:monitor_transaction).with(
93
+ "perform_job.sidekiq",
94
+ default_params.merge(
95
+ :params => {
96
+ :foo => "[FILTERED]",
97
+ :bar => "Bar"
98
+ }
99
+ )
100
+ )
101
+ end
85
102
  end
103
+ end
86
104
 
87
- context "when receiving class.method instead of class#method" do
88
- let(:job_class) { "ActionMailer.deliver_message" }
89
-
90
- it "uses the class method action name for the action" do
91
- perform_job
105
+ context "when wrapped by ActiveJob" do
106
+ let(:item) do
107
+ {
108
+ "class" => "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper",
109
+ "wrapped" => "TestClass",
110
+ "queue" => "default",
111
+ "args" => [{
112
+ "job_class" => "TestJob",
113
+ "job_id" => "23e79d48-6966-40d0-b2d4-f7938463a263",
114
+ "queue_name" => "default",
115
+ "arguments" => args
116
+ }],
117
+ "retry" => true,
118
+ "jid" => "efb140489485999d32b5504c",
119
+ "created_at" => Time.parse("01-01-2001 10:00:00UTC").to_f,
120
+ "enqueued_at" => Time.parse("01-01-2001 10:00:00UTC").to_f
121
+ }
122
+ end
123
+ let(:default_params) do
124
+ {
125
+ :class => "TestClass",
126
+ :method => "perform",
127
+ :metadata => {
128
+ "queue" => "default"
129
+ },
130
+ :queue_start => Time.parse("01-01-2001 10:00:00UTC").to_f,
131
+ :queue_time => 60_000.to_f
132
+ }
133
+ end
92
134
 
93
- transaction_hash = transaction.to_h
94
- expect(transaction_hash["action"]).to eq("ActionMailer.deliver_message")
95
- end
135
+ it "wraps it in a transaction with the correct params" do
136
+ expect(Appsignal).to receive(:monitor_transaction).with(
137
+ "perform_job.sidekiq",
138
+ default_params.merge(:params => ["Model", 1])
139
+ )
96
140
  end
97
141
 
98
- context "with more complex job arguments" do
142
+ context "with more complex arguments" do
99
143
  let(:args) do
100
144
  {
101
145
  :foo => "Foo",
@@ -104,14 +148,14 @@ if DependencyHelper.sidekiq_present?
104
148
  end
105
149
 
106
150
  it "adds the more complex arguments" do
107
- perform_job
108
-
109
- transaction_hash = transaction.to_h
110
- expect(transaction_hash["sample_data"]).to include(
111
- "params" => {
112
- "foo" => "Foo",
113
- "bar" => "Bar"
114
- }
151
+ expect(Appsignal).to receive(:monitor_transaction).with(
152
+ "perform_job.sidekiq",
153
+ default_params.merge(
154
+ :params => {
155
+ :foo => "Foo",
156
+ :bar => "Bar"
157
+ }
158
+ )
115
159
  )
116
160
  end
117
161
 
@@ -122,166 +166,90 @@ if DependencyHelper.sidekiq_present?
122
166
  end
123
167
 
124
168
  it "filters selected arguments" do
125
- perform_job
126
-
127
- transaction_hash = transaction.to_h
128
- expect(transaction_hash["sample_data"]).to include(
129
- "params" => {
130
- "foo" => "[FILTERED]",
131
- "bar" => "Bar"
132
- }
133
- )
134
- end
135
- end
136
- end
137
-
138
- context "when job is wrapped by ActiveJob" do
139
- let(:item) do
140
- {
141
- "class" => "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper",
142
- "wrapped" => "TestClass",
143
- "queue" => "default",
144
- "args" => [{
145
- "job_class" => "TestJob",
146
- "job_id" => "23e79d48-6966-40d0-b2d4-f7938463a263",
147
- "queue_name" => "default",
148
- "arguments" => args
149
- }],
150
- "retry" => true,
151
- "jid" => "efb140489485999d32b5504c",
152
- "created_at" => Time.parse("01-01-2001 10:00:00UTC"),
153
- "enqueued_at" => Time.parse("01-01-2001 10:00:00UTC").to_f
154
- }
155
- end
156
-
157
- it "creates a transaction with performance events" do
158
- perform_job
159
-
160
- transaction_hash = transaction.to_h
161
- expect(transaction_hash).to include(
162
- "id" => kind_of(String),
163
- "action" => "TestClass#perform",
164
- "error" => nil,
165
- "namespace" => namespace,
166
- "metadata" => {
167
- "queue" => "default"
168
- },
169
- "sample_data" => {
170
- "environment" => {},
171
- "params" => args,
172
- "tags" => {}
173
- }
174
- )
175
- # TODO: Not available in transaction.to_h yet.
176
- # https://github.com/appsignal/appsignal-agent/issues/293
177
- expect(transaction.request.env).to eq(
178
- :queue_start => Time.parse("01-01-2001 10:00:00UTC"),
179
- :queue_time => 60_000.0
180
- )
181
- expect_transaction_to_have_sidekiq_event(transaction_hash)
182
- end
183
-
184
- context "with more complex arguments" do
185
- let(:args) do
186
- {
187
- :foo => "Foo",
188
- :bar => "Bar"
189
- }
190
- end
191
-
192
- it "adds the more complex arguments" do
193
- perform_job
194
-
195
- transaction_hash = transaction.to_h
196
- expect(transaction_hash["sample_data"]).to include(
197
- "params" => {
198
- "foo" => "Foo",
199
- "bar" => "Bar"
200
- }
201
- )
202
- end
203
-
204
- context "with parameter filtering" do
205
- before do
206
- Appsignal.config = project_fixture_config("production")
207
- Appsignal.config[:filter_parameters] = ["foo"]
208
- end
209
-
210
- it "filters selected arguments" do
211
- perform_job
212
-
213
- transaction_hash = transaction.to_h
214
- expect(transaction_hash["sample_data"]).to include(
215
- "params" => {
216
- "foo" => "[FILTERED]",
217
- "bar" => "Bar"
169
+ expect(Appsignal).to receive(:monitor_transaction).with(
170
+ "perform_job.sidekiq",
171
+ default_params.merge(
172
+ :params => {
173
+ :foo => "[FILTERED]",
174
+ :bar => "Bar"
218
175
  }
219
176
  )
220
- end
177
+ )
221
178
  end
222
179
  end
223
180
  end
224
181
  end
182
+ end
225
183
 
226
- context "with an erroring job" do
227
- let(:error) { ExampleException }
228
- before do
229
- expect do
230
- Timecop.freeze(Time.parse("01-01-2001 10:01:00UTC")) do
231
- plugin.call(worker, item, queue) do
232
- raise error, "uh oh"
233
- end
234
- end
235
- end.to raise_error(error)
236
- end
184
+ context "with an erroring call" do
185
+ let(:error) { ExampleException }
186
+ let(:transaction) do
187
+ Appsignal::Transaction.new(
188
+ SecureRandom.uuid,
189
+ Appsignal::Transaction::BACKGROUND_JOB,
190
+ Appsignal::Transaction::GenericRequest.new({})
191
+ )
192
+ end
193
+ before do
194
+ allow(Appsignal::Transaction).to receive(:current).and_return(transaction)
195
+ expect(Appsignal::Transaction).to receive(:create)
196
+ .with(
197
+ kind_of(String),
198
+ Appsignal::Transaction::BACKGROUND_JOB,
199
+ kind_of(Appsignal::Transaction::GenericRequest)
200
+ ).and_return(transaction)
201
+ end
237
202
 
238
- it "adds the error to the transaction" do
239
- transaction_hash = transaction.to_h
240
- # TODO: backtrace should be an Array of Strings
241
- # https://github.com/appsignal/appsignal-agent/issues/294
242
- expect(transaction_hash["error"]).to include(
243
- "name" => "ExampleException",
244
- "message" => "uh oh",
245
- "backtrace" => kind_of(String)
246
- )
247
- expect_transaction_to_have_sidekiq_event(transaction_hash)
248
- end
203
+ it "adds the error to the transaction" do
204
+ expect(transaction).to receive(:set_error).with(error)
205
+ expect(transaction).to receive(:complete)
249
206
  end
250
207
 
251
- def perform_job
252
- Timecop.freeze(Time.parse("01-01-2001 10:01:00UTC")) do
253
- plugin.call(worker, item, queue) do
254
- # nothing
208
+ after do
209
+ expect do
210
+ Timecop.freeze(Time.parse("01-01-2001 10:01:00UTC")) do
211
+ Appsignal::Hooks::SidekiqPlugin.new.call(worker, item, queue) do
212
+ raise error
213
+ end
255
214
  end
256
- end
215
+ end.to raise_error(error)
257
216
  end
217
+ end
258
218
 
259
- def transaction
260
- test_store[:transaction]
219
+ # TODO: Don't test (what are basically) private methods
220
+ describe "#formatted_data" do
221
+ let(:item) do
222
+ {
223
+ "foo" => "bar",
224
+ "class" => "TestClass"
225
+ }
261
226
  end
262
227
 
263
- def expect_transaction_to_have_sidekiq_event(transaction_hash)
264
- events = transaction_hash["events"]
265
- expect(events.count).to eq(1)
266
- expect(events.first).to include(
267
- "name" => "perform_job.sidekiq",
268
- "title" => "",
269
- "count" => 1,
270
- "body" => "",
271
- "body_format" => Appsignal::EventFormatter::DEFAULT
272
- )
228
+ it "only adds items to the hash that do not appear in JOB_KEYS" do
229
+ expect(plugin.formatted_metadata(item)).to eq("foo" => "bar")
273
230
  end
274
231
  end
275
232
  end
276
233
 
277
234
  describe Appsignal::Hooks::SidekiqHook do
278
- if DependencyHelper.sidekiq_present?
235
+ context "with sidekiq" do
236
+ before :context do
237
+ module Sidekiq
238
+ def self.configure_server
239
+ end
240
+ end
241
+ Appsignal::Hooks::SidekiqHook.new.install
242
+ end
243
+ after(:context) { Object.send(:remove_const, :Sidekiq) }
244
+
279
245
  describe "#dependencies_present?" do
280
246
  subject { described_class.new.dependencies_present? }
281
247
 
282
248
  it { is_expected.to be_truthy }
283
249
  end
284
- else
250
+ end
251
+
252
+ context "without sidekiq" do
285
253
  describe "#dependencies_present?" do
286
254
  subject { described_class.new.dependencies_present? }
287
255
 
@@ -257,7 +257,7 @@ describe Appsignal do
257
257
  end
258
258
 
259
259
  describe ".listen_for_error" do
260
- it "should do nothing" do
260
+ it "does not record anyhing" do
261
261
  error = RuntimeError.new("specific error")
262
262
  expect do
263
263
  Appsignal.listen_for_error do
@@ -779,13 +779,47 @@ describe Appsignal do
779
779
  end
780
780
 
781
781
  describe ".listen_for_error" do
782
- it "should call send_error and re-raise" do
783
- expect(Appsignal).to receive(:send_error).with(kind_of(Exception))
782
+ it "records the error and re-raise it" do
783
+ expect(Appsignal).to receive(:send_error).with(
784
+ kind_of(ExampleException),
785
+ nil,
786
+ Appsignal::Transaction::HTTP_REQUEST
787
+ )
784
788
  expect do
785
789
  Appsignal.listen_for_error do
786
- raise "I am an exception"
790
+ raise ExampleException, "I am an exception"
787
791
  end
788
- end.to raise_error(RuntimeError, "I am an exception")
792
+ end.to raise_error(ExampleException, "I am an exception")
793
+ end
794
+
795
+ context "with tags" do
796
+ it "adds tags to the transaction" do
797
+ expect(Appsignal).to receive(:send_error).with(
798
+ kind_of(ExampleException),
799
+ { "foo" => "bar" },
800
+ Appsignal::Transaction::HTTP_REQUEST
801
+ )
802
+ expect do
803
+ Appsignal.listen_for_error("foo" => "bar") do
804
+ raise ExampleException, "I am an exception"
805
+ end
806
+ end.to raise_error(ExampleException, "I am an exception")
807
+ end
808
+ end
809
+
810
+ context "with a custom namespace" do
811
+ it "adds the namespace to the transaction" do
812
+ expect(Appsignal).to receive(:send_error).with(
813
+ kind_of(ExampleException),
814
+ nil,
815
+ "custom_namespace"
816
+ )
817
+ expect do
818
+ Appsignal.listen_for_error(nil, "custom_namespace") do
819
+ raise ExampleException, "I am an exception"
820
+ end
821
+ end.to raise_error(ExampleException, "I am an exception")
822
+ end
789
823
  end
790
824
  end
791
825
 
@@ -63,10 +63,6 @@ module DependencyHelper
63
63
  Gem.loaded_specs["capistrano"].version >= Gem::Version.new("3.0")
64
64
  end
65
65
 
66
- def sidekiq_present?
67
- dependency_present? "sidekiq"
68
- end
69
-
70
66
  def dependency_present?(dependency_file)
71
67
  Gem.loaded_specs.key? dependency_file
72
68
  end
@@ -28,10 +28,4 @@ module TransactionHelpers
28
28
  }.merge(args))
29
29
  )
30
30
  end
31
-
32
- # Use when {Appsignal::Transaction.clear_current_transaction!} is stubbed to
33
- # clear the current transaction on the current thread.
34
- def clear_current_transaction!
35
- Thread.current[:appsignal_transaction] = nil
36
- end
37
31
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appsignal
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.0.alpha.1
4
+ version: 2.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Beekman
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-10-17 00:00:00.000000000 Z
12
+ date: 2017-10-31 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
@@ -163,7 +163,6 @@ files:
163
163
  - gemfiles/resque.gemfile
164
164
  - gemfiles/sequel-435.gemfile
165
165
  - gemfiles/sequel.gemfile
166
- - gemfiles/sidekiq.gemfile
167
166
  - gemfiles/sinatra.gemfile
168
167
  - gemfiles/webmachine.gemfile
169
168
  - lib/appsignal.rb
@@ -349,9 +348,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
349
348
  version: '1.9'
350
349
  required_rubygems_version: !ruby/object:Gem::Requirement
351
350
  requirements:
352
- - - ">"
351
+ - - ">="
353
352
  - !ruby/object:Gem::Version
354
- version: 1.3.1
353
+ version: '0'
355
354
  requirements: []
356
355
  rubyforge_project:
357
356
  rubygems_version: 2.5.2.1
@@ -1,5 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- gem 'sidekiq'
4
-
5
- gemspec :path => '../'