appsignal 2.4.0.alpha.1 → 2.4.0

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 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 => '../'