appsignal 3.1.1 → 3.1.4
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 +4 -4
- data/CHANGELOG.md +40 -0
- data/appsignal.gemspec +5 -1
- data/ext/agent.yml +32 -25
- data/lib/appsignal/config.rb +0 -3
- data/lib/appsignal/garbage_collection.rb +90 -0
- data/lib/appsignal/helpers/instrumentation.rb +8 -5
- data/lib/appsignal/hooks/active_job.rb +5 -5
- data/lib/appsignal/integrations/mongo_ruby_driver.rb +4 -2
- data/lib/appsignal/integrations/sidekiq.rb +18 -15
- data/lib/appsignal/probes/helpers.rb +21 -8
- data/lib/appsignal/probes/mri.rb +18 -18
- data/lib/appsignal/probes/sidekiq.rb +7 -6
- data/lib/appsignal/rack/rails_instrumentation.rb +5 -1
- data/lib/appsignal/transaction.rb +19 -12
- data/lib/appsignal/version.rb +1 -1
- data/lib/appsignal.rb +1 -6
- data/spec/lib/appsignal/config_spec.rb +0 -1
- data/spec/lib/appsignal/{garbage_collection_profiler_spec.rb → garbage_collection_spec.rb} +28 -6
- data/spec/lib/appsignal/probes/mri_spec.rb +66 -3
- data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +79 -35
- data/spec/lib/appsignal/transaction_spec.rb +19 -34
- data/spec/lib/appsignal_spec.rb +10 -23
- data/spec/support/helpers/env_helpers.rb +9 -1
- data/spec/support/helpers/transaction_helpers.rb +6 -0
- data/spec/support/testing.rb +11 -0
- metadata +12 -12
- data/lib/appsignal/garbage_collection_profiler.rb +0 -61
@@ -35,10 +35,24 @@ module Appsignal
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
+
# Returns currently active transaction or a {NilTransaction} if none is
|
39
|
+
# active.
|
40
|
+
#
|
41
|
+
# @see .current?
|
42
|
+
# @return [Boolean]
|
38
43
|
def current
|
39
44
|
Thread.current[:appsignal_transaction] || NilTransaction.new
|
40
45
|
end
|
41
46
|
|
47
|
+
# Returns if any transaction is currently active or not. A
|
48
|
+
# {NilTransaction} is not considered an active transaction.
|
49
|
+
#
|
50
|
+
# @see .current
|
51
|
+
# @return [Boolean]
|
52
|
+
def current?
|
53
|
+
current && !current.nil_transaction?
|
54
|
+
end
|
55
|
+
|
42
56
|
def complete_current!
|
43
57
|
current.complete
|
44
58
|
rescue => e
|
@@ -52,11 +66,6 @@ module Appsignal
|
|
52
66
|
def clear_current_transaction!
|
53
67
|
Thread.current[:appsignal_transaction] = nil
|
54
68
|
end
|
55
|
-
|
56
|
-
def garbage_collection_profiler
|
57
|
-
@garbage_collection_profiler ||=
|
58
|
-
Appsignal.config[:enable_gc_instrumentation] ? Appsignal::GarbageCollectionProfiler.new : NilGarbageCollectionProfiler.new
|
59
|
-
end
|
60
69
|
end
|
61
70
|
|
62
71
|
attr_reader :ext, :transaction_id, :action, :namespace, :request, :paused, :tags, :options, :discarded, :breadcrumbs
|
@@ -89,7 +98,7 @@ module Appsignal
|
|
89
98
|
@ext = Appsignal::Extension.start_transaction(
|
90
99
|
@transaction_id,
|
91
100
|
@namespace,
|
92
|
-
|
101
|
+
0
|
93
102
|
) || Appsignal::Extension::MockTransaction.new
|
94
103
|
end
|
95
104
|
|
@@ -103,9 +112,7 @@ module Appsignal
|
|
103
112
|
"because it was manually discarded."
|
104
113
|
return
|
105
114
|
end
|
106
|
-
if @ext.finish(
|
107
|
-
sample_data
|
108
|
-
end
|
115
|
+
sample_data if @ext.finish(0)
|
109
116
|
@ext.complete
|
110
117
|
end
|
111
118
|
|
@@ -341,7 +348,7 @@ module Appsignal
|
|
341
348
|
|
342
349
|
def start_event
|
343
350
|
return if paused?
|
344
|
-
@ext.start_event(
|
351
|
+
@ext.start_event(0)
|
345
352
|
end
|
346
353
|
|
347
354
|
def finish_event(name, title, body, body_format = Appsignal::EventFormatter::DEFAULT)
|
@@ -351,7 +358,7 @@ module Appsignal
|
|
351
358
|
title || BLANK,
|
352
359
|
body || BLANK,
|
353
360
|
body_format || Appsignal::EventFormatter::DEFAULT,
|
354
|
-
|
361
|
+
0
|
355
362
|
)
|
356
363
|
end
|
357
364
|
|
@@ -363,7 +370,7 @@ module Appsignal
|
|
363
370
|
body || BLANK,
|
364
371
|
body_format || Appsignal::EventFormatter::DEFAULT,
|
365
372
|
duration,
|
366
|
-
|
373
|
+
0
|
367
374
|
)
|
368
375
|
end
|
369
376
|
|
data/lib/appsignal/version.rb
CHANGED
data/lib/appsignal.rb
CHANGED
@@ -115,11 +115,6 @@ module Appsignal
|
|
115
115
|
Appsignal::Environment.report_enabled("allocation_tracking")
|
116
116
|
end
|
117
117
|
|
118
|
-
if config[:enable_gc_instrumentation]
|
119
|
-
GC::Profiler.enable
|
120
|
-
Appsignal::Environment.report_enabled("gc_instrumentation")
|
121
|
-
end
|
122
|
-
|
123
118
|
Appsignal::Minutely.start if config[:enable_minutely_probes]
|
124
119
|
|
125
120
|
collect_environment_metadata
|
@@ -298,7 +293,7 @@ require "appsignal/hooks"
|
|
298
293
|
require "appsignal/probes"
|
299
294
|
require "appsignal/marker"
|
300
295
|
require "appsignal/minutely"
|
301
|
-
require "appsignal/
|
296
|
+
require "appsignal/garbage_collection"
|
302
297
|
require "appsignal/integrations/railtie" if defined?(::Rails)
|
303
298
|
require "appsignal/transaction"
|
304
299
|
require "appsignal/version"
|
@@ -156,7 +156,6 @@ describe Appsignal::Config do
|
|
156
156
|
:debug => false,
|
157
157
|
:dns_servers => [],
|
158
158
|
:enable_allocation_tracking => true,
|
159
|
-
:enable_gc_instrumentation => false,
|
160
159
|
:enable_host_metrics => true,
|
161
160
|
:enable_minutely_probes => true,
|
162
161
|
:enable_statsd => true,
|
@@ -1,11 +1,33 @@
|
|
1
|
-
describe Appsignal::
|
1
|
+
describe Appsignal::GarbageCollection do
|
2
|
+
describe ".profiler" do
|
3
|
+
before do
|
4
|
+
# Unset the internal memoized variable to avoid state leaking
|
5
|
+
described_class.clear_profiler!
|
6
|
+
end
|
7
|
+
|
8
|
+
context "when GC instrumentation is disabled" do
|
9
|
+
it "returns the NilProfiler" do
|
10
|
+
expect(described_class.profiler).to be_a(Appsignal::GarbageCollection::NilProfiler)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context "when GC profiling is enabled" do
|
15
|
+
before { GC::Profiler.enable }
|
16
|
+
after { GC::Profiler.disable }
|
17
|
+
|
18
|
+
it "returns the Profiler" do
|
19
|
+
expect(described_class.profiler).to be_a(Appsignal::GarbageCollection::Profiler)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe Appsignal::GarbageCollection::Profiler do
|
2
26
|
let(:internal_profiler) { FakeGCProfiler.new }
|
3
27
|
let(:profiler) { described_class.new }
|
4
28
|
|
5
29
|
before do
|
6
|
-
|
7
|
-
.to receive(:internal_profiler)
|
8
|
-
.and_return(internal_profiler)
|
30
|
+
stub_const("GC::Profiler", internal_profiler)
|
9
31
|
end
|
10
32
|
|
11
33
|
context "on initialization" do
|
@@ -54,7 +76,7 @@ describe Appsignal::GarbageCollectionProfiler do
|
|
54
76
|
|
55
77
|
2.times do
|
56
78
|
threads << Thread.new do
|
57
|
-
profiler = Appsignal::
|
79
|
+
profiler = Appsignal::GarbageCollection::Profiler.new
|
58
80
|
results << profiler.total_time
|
59
81
|
end
|
60
82
|
end
|
@@ -65,7 +87,7 @@ describe Appsignal::GarbageCollectionProfiler do
|
|
65
87
|
end
|
66
88
|
end
|
67
89
|
|
68
|
-
describe Appsignal::
|
90
|
+
describe Appsignal::GarbageCollection::NilProfiler do
|
69
91
|
let(:profiler) { described_class.new }
|
70
92
|
|
71
93
|
describe "#total_time" do
|
@@ -19,7 +19,8 @@ end
|
|
19
19
|
|
20
20
|
describe Appsignal::Probes::MriProbe do
|
21
21
|
let(:appsignal_mock) { AppsignalMock.new(:hostname => hostname) }
|
22
|
-
let(:
|
22
|
+
let(:gc_profiler_mock) { instance_double("Appsignal::GarbageCollectionProfiler") }
|
23
|
+
let(:probe) { described_class.new(:appsignal => appsignal_mock, :gc_profiler => gc_profiler_mock) }
|
23
24
|
|
24
25
|
describe ".dependencies_present?" do
|
25
26
|
if DependencyHelper.running_jruby? || DependencyHelper.running_ruby_2_0?
|
@@ -36,6 +37,10 @@ describe Appsignal::Probes::MriProbe do
|
|
36
37
|
unless DependencyHelper.running_jruby? || DependencyHelper.running_ruby_2_0?
|
37
38
|
describe "#call" do
|
38
39
|
let(:hostname) { nil }
|
40
|
+
before do
|
41
|
+
allow(gc_profiler_mock).to receive(:total_time)
|
42
|
+
allow(GC::Profiler).to receive(:enabled?).and_return(true)
|
43
|
+
end
|
39
44
|
|
40
45
|
it "should track vm metrics" do
|
41
46
|
probe.call
|
@@ -48,9 +53,56 @@ describe Appsignal::Probes::MriProbe do
|
|
48
53
|
expect_gauge_value("thread_count")
|
49
54
|
end
|
50
55
|
|
51
|
-
it "tracks GC
|
56
|
+
it "tracks GC time between measurements" do
|
57
|
+
expect(gc_profiler_mock).to receive(:total_time).and_return(10, 15)
|
58
|
+
probe.call
|
52
59
|
probe.call
|
53
|
-
expect_gauge_value("
|
60
|
+
expect_gauge_value("gc_time", 5)
|
61
|
+
end
|
62
|
+
|
63
|
+
context "when GC total time overflows" do
|
64
|
+
it "skips one report" do
|
65
|
+
expect(gc_profiler_mock).to receive(:total_time).and_return(10, 15, 0, 10)
|
66
|
+
probe.call # Normal call, create a cache
|
67
|
+
probe.call # Report delta value based on cached value
|
68
|
+
probe.call # The value overflows and reports no value. Then stores 0 in the cache
|
69
|
+
probe.call # Report new value based on cache of 0
|
70
|
+
expect_gauges([["gc_time", 5], ["gc_time", 10]])
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context "when GC profiling is disabled" do
|
75
|
+
it "does not report a gc_time metric" do
|
76
|
+
allow(GC::Profiler).to receive(:enabled?).and_return(false)
|
77
|
+
expect(gc_profiler_mock).to_not receive(:total_time)
|
78
|
+
probe.call # Normal call, create a cache
|
79
|
+
probe.call # Report delta value based on cached value
|
80
|
+
metrics = appsignal_mock.gauges.map { |(key)| key }
|
81
|
+
expect(metrics).to_not include("gc_time")
|
82
|
+
end
|
83
|
+
|
84
|
+
it "does not report a gc_time metric while temporarily disabled" do
|
85
|
+
# While enabled
|
86
|
+
allow(GC::Profiler).to receive(:enabled?).and_return(true)
|
87
|
+
expect(gc_profiler_mock).to receive(:total_time).and_return(10, 15)
|
88
|
+
probe.call # Normal call, create a cache
|
89
|
+
probe.call # Report delta value based on cached value
|
90
|
+
expect_gauges([["gc_time", 5]])
|
91
|
+
|
92
|
+
# While disabled
|
93
|
+
allow(GC::Profiler).to receive(:enabled?).and_return(false)
|
94
|
+
probe.call # Call twice to make sure any caches resets wouldn't mess up the assertion
|
95
|
+
probe.call
|
96
|
+
# Does not include any newly reported metrics
|
97
|
+
expect_gauges([["gc_time", 5]])
|
98
|
+
|
99
|
+
# When enabled after being disabled for a while, it only reports the
|
100
|
+
# newly reported time since it was renabled
|
101
|
+
allow(GC::Profiler).to receive(:enabled?).and_return(true)
|
102
|
+
expect(gc_profiler_mock).to receive(:total_time).and_return(25)
|
103
|
+
probe.call
|
104
|
+
expect_gauges([["gc_time", 5], ["gc_time", 10]])
|
105
|
+
end
|
54
106
|
end
|
55
107
|
|
56
108
|
it "tracks GC run count" do
|
@@ -107,4 +159,15 @@ describe Appsignal::Probes::MriProbe do
|
|
107
159
|
end
|
108
160
|
end
|
109
161
|
end
|
162
|
+
|
163
|
+
def expect_gauges(expected_metrics)
|
164
|
+
default_tags = { :hostname => Socket.gethostname }
|
165
|
+
keys = expected_metrics.map { |(key)| key }
|
166
|
+
metrics = expected_metrics.map do |metric|
|
167
|
+
key, value, tags = metric
|
168
|
+
[key, value, default_tags.merge(tags || {})]
|
169
|
+
end
|
170
|
+
found_gauges = appsignal_mock.gauges.select { |(key)| keys.include? key }
|
171
|
+
expect(found_gauges).to eq(metrics)
|
172
|
+
end
|
110
173
|
end
|
@@ -3,20 +3,37 @@ if DependencyHelper.rails_present?
|
|
3
3
|
end
|
4
4
|
|
5
5
|
describe Appsignal::Rack::RailsInstrumentation do
|
6
|
-
|
6
|
+
let(:log) { StringIO.new }
|
7
|
+
before do
|
7
8
|
start_agent
|
9
|
+
Appsignal.logger = test_logger(log)
|
8
10
|
end
|
9
11
|
|
12
|
+
let(:params) do
|
13
|
+
{
|
14
|
+
"controller" => "blog_posts",
|
15
|
+
"action" => "show",
|
16
|
+
"id" => "1",
|
17
|
+
"my_custom_param" => "my custom secret",
|
18
|
+
"password" => "super secret"
|
19
|
+
}
|
20
|
+
end
|
21
|
+
let(:env_extra) { {} }
|
10
22
|
let(:app) { double(:call => true) }
|
11
23
|
let(:env) do
|
12
|
-
http_request_env_with_data(
|
13
|
-
|
24
|
+
http_request_env_with_data({
|
25
|
+
:params => params,
|
26
|
+
:with_queue_start => true,
|
27
|
+
"action_dispatch.request_id" => "1",
|
28
|
+
"action_dispatch.parameter_filter" => [:my_custom_param, :password],
|
29
|
+
"action_controller.instance" => double(
|
14
30
|
:class => MockController,
|
15
31
|
:action_name => "index"
|
16
32
|
)
|
17
|
-
|
33
|
+
}.merge(env_extra))
|
18
34
|
end
|
19
35
|
let(:middleware) { Appsignal::Rack::RailsInstrumentation.new(app, {}) }
|
36
|
+
around { |example| keep_transactions { example.run } }
|
20
37
|
|
21
38
|
describe "#call" do
|
22
39
|
before do
|
@@ -46,30 +63,62 @@ if DependencyHelper.rails_present?
|
|
46
63
|
after { middleware.call(env) }
|
47
64
|
end
|
48
65
|
|
49
|
-
describe "#call_with_appsignal_monitoring"
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
).
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
66
|
+
describe "#call_with_appsignal_monitoring" do
|
67
|
+
def run
|
68
|
+
middleware.call(env)
|
69
|
+
end
|
70
|
+
|
71
|
+
it "calls the wrapped app" do
|
72
|
+
run
|
73
|
+
expect(app).to have_received(:call).with(env)
|
74
|
+
end
|
75
|
+
|
76
|
+
it "creates one transaction with metadata" do
|
77
|
+
run
|
78
|
+
|
79
|
+
expect(created_transactions.length).to eq(1)
|
80
|
+
transaction_hash = last_transaction.to_h
|
81
|
+
expect(transaction_hash).to include(
|
82
|
+
"namespace" => Appsignal::Transaction::HTTP_REQUEST,
|
83
|
+
"action" => "MockController#index",
|
84
|
+
"metadata" => hash_including(
|
85
|
+
"method" => "GET",
|
86
|
+
"path" => "/blog"
|
87
|
+
)
|
88
|
+
)
|
89
|
+
expect(last_transaction.ext.queue_start).to eq(
|
90
|
+
fixed_time * 1_000.0
|
91
|
+
)
|
92
|
+
end
|
93
|
+
|
94
|
+
it "filter parameters in Rails" do
|
95
|
+
run
|
96
|
+
|
97
|
+
transaction_hash = last_transaction.to_h
|
98
|
+
expect(transaction_hash).to include(
|
99
|
+
"sample_data" => hash_including(
|
100
|
+
"params" => params.merge(
|
101
|
+
"my_custom_param" => "[FILTERED]",
|
102
|
+
"password" => "[FILTERED]"
|
103
|
+
)
|
63
104
|
)
|
64
105
|
)
|
65
106
|
end
|
66
107
|
|
67
|
-
|
68
|
-
|
108
|
+
context "with an invalid HTTP request method" do
|
109
|
+
let(:env_extra) { { :request_method => "FOO", "REQUEST_METHOD" => "FOO" } }
|
110
|
+
|
111
|
+
it "does not store the HTTP request method" do
|
112
|
+
run
|
113
|
+
|
114
|
+
transaction_hash = last_transaction.to_h
|
115
|
+
expect(transaction_hash["metadata"]).to_not have_key("method")
|
116
|
+
expect(log_contents(log)).to contains_log(:error, "Unable to report HTTP request method: '")
|
117
|
+
end
|
69
118
|
end
|
70
119
|
|
71
|
-
context "with an exception"
|
72
|
-
let(:error) { ExampleException }
|
120
|
+
context "with an exception" do
|
121
|
+
let(:error) { ExampleException.new("ExampleException message") }
|
73
122
|
let(:app) do
|
74
123
|
double.tap do |d|
|
75
124
|
allow(d).to receive(:call).and_raise(error)
|
@@ -77,21 +126,16 @@ if DependencyHelper.rails_present?
|
|
77
126
|
end
|
78
127
|
|
79
128
|
it "records the exception" do
|
80
|
-
|
81
|
-
end
|
82
|
-
end
|
129
|
+
expect { run }.to raise_error(error)
|
83
130
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
131
|
+
transaction_hash = last_transaction.to_h
|
132
|
+
expect(transaction_hash["error"]).to include(
|
133
|
+
"name" => "ExampleException",
|
134
|
+
"message" => "ExampleException message",
|
135
|
+
"backtrace" => kind_of(String)
|
136
|
+
)
|
137
|
+
end
|
91
138
|
end
|
92
|
-
|
93
|
-
after(:error => false) { middleware.call(env) }
|
94
|
-
after(:error => true) { expect { middleware.call(env) }.to raise_error(error) }
|
95
139
|
end
|
96
140
|
|
97
141
|
describe "#request_id" do
|
@@ -85,7 +85,9 @@ describe Appsignal::Transaction do
|
|
85
85
|
end
|
86
86
|
|
87
87
|
describe ".current" do
|
88
|
-
|
88
|
+
def current_transaction
|
89
|
+
Appsignal::Transaction.current
|
90
|
+
end
|
89
91
|
|
90
92
|
context "when there is a current transaction" do
|
91
93
|
let!(:transaction) do
|
@@ -93,13 +95,17 @@ describe Appsignal::Transaction do
|
|
93
95
|
end
|
94
96
|
|
95
97
|
it "reads :appsignal_transaction from the current Thread" do
|
96
|
-
expect(
|
97
|
-
expect(
|
98
|
+
expect(current_transaction).to eq Thread.current[:appsignal_transaction]
|
99
|
+
expect(current_transaction).to eq transaction
|
98
100
|
end
|
99
101
|
|
100
102
|
it "is not a NilTransaction" do
|
101
|
-
expect(
|
102
|
-
expect(
|
103
|
+
expect(current_transaction.nil_transaction?).to eq false
|
104
|
+
expect(current_transaction).to be_a Appsignal::Transaction
|
105
|
+
end
|
106
|
+
|
107
|
+
it "returns true for current?" do
|
108
|
+
expect(Appsignal::Transaction.current?).to be(true)
|
103
109
|
end
|
104
110
|
end
|
105
111
|
|
@@ -109,8 +115,12 @@ describe Appsignal::Transaction do
|
|
109
115
|
end
|
110
116
|
|
111
117
|
it "returns a NilTransaction stub" do
|
112
|
-
expect(
|
113
|
-
expect(
|
118
|
+
expect(current_transaction.nil_transaction?).to eq true
|
119
|
+
expect(current_transaction).to be_a Appsignal::Transaction::NilTransaction
|
120
|
+
end
|
121
|
+
|
122
|
+
it "returns false for current?" do
|
123
|
+
expect(Appsignal::Transaction.current?).to be(false)
|
114
124
|
end
|
115
125
|
end
|
116
126
|
end
|
@@ -782,23 +792,6 @@ describe Appsignal::Transaction do
|
|
782
792
|
end
|
783
793
|
end
|
784
794
|
|
785
|
-
describe "#garbage_collection_profiler" do
|
786
|
-
before { Appsignal::Transaction.instance_variable_set(:@garbage_collection_profiler, nil) }
|
787
|
-
|
788
|
-
it "returns the NilGarbageCollectionProfiler" do
|
789
|
-
expect(Appsignal::Transaction.garbage_collection_profiler).to be_a(Appsignal::NilGarbageCollectionProfiler)
|
790
|
-
end
|
791
|
-
|
792
|
-
context "when gc profiling is enabled" do
|
793
|
-
before { Appsignal.config.config_hash[:enable_gc_instrumentation] = true }
|
794
|
-
after { Appsignal.config.config_hash[:enable_gc_instrumentation] = false }
|
795
|
-
|
796
|
-
it "returns the GarbageCollectionProfiler" do
|
797
|
-
expect(Appsignal::Transaction.garbage_collection_profiler).to be_a(Appsignal::GarbageCollectionProfiler)
|
798
|
-
end
|
799
|
-
end
|
800
|
-
end
|
801
|
-
|
802
795
|
describe "#start_event" do
|
803
796
|
it "starts the event in the extension" do
|
804
797
|
expect(transaction.ext).to receive(:start_event).with(0).and_call_original
|
@@ -817,11 +810,7 @@ describe Appsignal::Transaction do
|
|
817
810
|
end
|
818
811
|
|
819
812
|
describe "#finish_event" do
|
820
|
-
let(:fake_gc_time) {
|
821
|
-
before do
|
822
|
-
expect(described_class.garbage_collection_profiler)
|
823
|
-
.to receive(:total_time).at_least(:once).and_return(fake_gc_time)
|
824
|
-
end
|
813
|
+
let(:fake_gc_time) { 0 }
|
825
814
|
|
826
815
|
it "should finish the event in the extension" do
|
827
816
|
expect(transaction.ext).to receive(:finish_event).with(
|
@@ -868,11 +857,7 @@ describe Appsignal::Transaction do
|
|
868
857
|
end
|
869
858
|
|
870
859
|
describe "#record_event" do
|
871
|
-
let(:fake_gc_time) {
|
872
|
-
before do
|
873
|
-
expect(described_class.garbage_collection_profiler)
|
874
|
-
.to receive(:total_time).at_least(:once).and_return(fake_gc_time)
|
875
|
-
end
|
860
|
+
let(:fake_gc_time) { 0 }
|
876
861
|
|
877
862
|
it "should record the event in the extension" do
|
878
863
|
expect(transaction.ext).to receive(:record_event).with(
|
data/spec/lib/appsignal_spec.rb
CHANGED
@@ -54,20 +54,12 @@ describe Appsignal do
|
|
54
54
|
Appsignal.start
|
55
55
|
end
|
56
56
|
|
57
|
-
context "when allocation tracking
|
57
|
+
context "when allocation tracking has been enabled" do
|
58
58
|
before do
|
59
|
-
allow(GC::Profiler).to receive(:enable)
|
60
59
|
Appsignal.config.config_hash[:enable_allocation_tracking] = true
|
61
|
-
Appsignal.config.config_hash[:enable_gc_instrumentation] = true
|
62
60
|
capture_environment_metadata_report_calls
|
63
61
|
end
|
64
62
|
|
65
|
-
it "should enable Ruby's GC::Profiler" do
|
66
|
-
expect(GC::Profiler).to receive(:enable)
|
67
|
-
Appsignal.start
|
68
|
-
expect_environment_metadata("ruby_gc_instrumentation_enabled", "true")
|
69
|
-
end
|
70
|
-
|
71
63
|
unless DependencyHelper.running_jruby?
|
72
64
|
it "installs the allocation event hook" do
|
73
65
|
expect(Appsignal::Extension).to receive(:install_allocation_event_hook)
|
@@ -78,29 +70,17 @@ describe Appsignal do
|
|
78
70
|
end
|
79
71
|
end
|
80
72
|
|
81
|
-
context "when allocation tracking
|
73
|
+
context "when allocation tracking has been disabled" do
|
82
74
|
before do
|
83
75
|
Appsignal.config.config_hash[:enable_allocation_tracking] = false
|
84
|
-
Appsignal.config.config_hash[:enable_gc_instrumentation] = false
|
85
76
|
capture_environment_metadata_report_calls
|
86
77
|
end
|
87
78
|
|
88
|
-
it "should not enable Ruby's GC::Profiler" do
|
89
|
-
expect(GC::Profiler).not_to receive(:enable)
|
90
|
-
Appsignal.start
|
91
|
-
end
|
92
|
-
|
93
79
|
it "should not install the allocation event hook" do
|
94
80
|
expect(Appsignal::Minutely).not_to receive(:install_allocation_event_hook)
|
95
81
|
Appsignal.start
|
96
82
|
expect_not_environment_metadata("ruby_allocation_tracking_enabled")
|
97
83
|
end
|
98
|
-
|
99
|
-
it "should not add the gc probe to minutely" do
|
100
|
-
expect(Appsignal::Minutely).not_to receive(:register_garbage_collection_probe)
|
101
|
-
Appsignal.start
|
102
|
-
expect_not_environment_metadata("ruby_gc_instrumentation_enabled")
|
103
|
-
end
|
104
84
|
end
|
105
85
|
|
106
86
|
context "when minutely metrics has been enabled" do
|
@@ -511,7 +491,14 @@ describe Appsignal do
|
|
511
491
|
before { allow(Appsignal::Transaction).to receive(:current).and_return(transaction) }
|
512
492
|
|
513
493
|
context "with transaction" do
|
514
|
-
let(:transaction) {
|
494
|
+
let(:transaction) { http_request_transaction }
|
495
|
+
around do |example|
|
496
|
+
Appsignal.config = project_fixture_config
|
497
|
+
set_current_transaction transaction do
|
498
|
+
example.run
|
499
|
+
end
|
500
|
+
end
|
501
|
+
|
515
502
|
it "should call add_breadcrumb on transaction" do
|
516
503
|
expect(transaction).to receive(:add_breadcrumb)
|
517
504
|
.with("Network", "http", "User made network request", { :response => 200 }, fixed_time)
|
@@ -1,7 +1,8 @@
|
|
1
1
|
module EnvHelpers
|
2
2
|
def http_request_env_with_data(args = {})
|
3
|
+
with_queue_start = args.delete(:with_queue_start)
|
3
4
|
path = args.delete(:path) || "/blog"
|
4
|
-
Rack::MockRequest.env_for(
|
5
|
+
request = Rack::MockRequest.env_for(
|
5
6
|
path,
|
6
7
|
:params => args[:params] || {
|
7
8
|
"controller" => "blog_posts",
|
@@ -18,6 +19,13 @@ module EnvHelpers
|
|
18
19
|
:db_runtime => 500,
|
19
20
|
:metadata => { :key => "value" }
|
20
21
|
).merge(args)
|
22
|
+
|
23
|
+
# Set default queue value
|
24
|
+
if with_queue_start
|
25
|
+
request["HTTP_X_QUEUE_START"] = "t=#{(fixed_time * 1_000).to_i}" # in milliseconds
|
26
|
+
end
|
27
|
+
|
28
|
+
request
|
21
29
|
end
|
22
30
|
|
23
31
|
def background_env_with_data(args = {})
|
@@ -46,8 +46,14 @@ module TransactionHelpers
|
|
46
46
|
|
47
47
|
# Set current transaction manually.
|
48
48
|
# Cleared by {clear_current_transaction!}
|
49
|
+
#
|
50
|
+
# When a block is given, the current transaction is automatically unset after
|
51
|
+
# the block.
|
49
52
|
def set_current_transaction(transaction) # rubocop:disable Naming/AccessorMethodName
|
50
53
|
Thread.current[:appsignal_transaction] = transaction
|
54
|
+
yield if block_given?
|
55
|
+
ensure
|
56
|
+
clear_current_transaction! if block_given?
|
51
57
|
end
|
52
58
|
|
53
59
|
# Use when {Appsignal::Transaction.clear_current_transaction!} is stubbed to
|
data/spec/support/testing.rb
CHANGED
@@ -50,6 +50,17 @@ module Appsignal
|
|
50
50
|
|
51
51
|
class Extension
|
52
52
|
class Transaction
|
53
|
+
if Appsignal.extension_loaded?
|
54
|
+
attr_reader :queue_start
|
55
|
+
alias original_set_queue_start set_queue_start
|
56
|
+
# Temporary helper until the extension returns this information
|
57
|
+
# https://github.com/appsignal/appsignal-agent/issues/293
|
58
|
+
def set_queue_start(start) # rubocop:disable Naming/AccessorMethodName
|
59
|
+
@queue_start = start
|
60
|
+
original_set_queue_start(start)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
53
64
|
alias original_finish finish if method_defined? :finish
|
54
65
|
|
55
66
|
# Override default {Extension::Transaction#finish} behavior to always
|