appsignal 2.10.12-java → 2.11.0.alpha.1-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.semaphore/semaphore.yml +1 -1
- data/CHANGELOG.md +3 -12
- data/README.md +4 -4
- data/appsignal.gemspec +1 -1
- data/build_matrix.yml +2 -2
- data/ext/agent.yml +19 -19
- data/ext/appsignal_extension.c +10 -1
- data/lib/appsignal.rb +21 -1
- data/lib/appsignal/capistrano.rb +2 -0
- data/lib/appsignal/cli/diagnose.rb +1 -1
- data/lib/appsignal/config.rb +8 -38
- data/lib/appsignal/environment.rb +126 -0
- data/lib/appsignal/extension/jruby.rb +10 -0
- data/lib/appsignal/hooks/net_http.rb +2 -0
- data/lib/appsignal/hooks/redis.rb +2 -0
- data/lib/appsignal/hooks/sequel.rb +2 -0
- data/lib/appsignal/integrations/object.rb +4 -0
- data/lib/appsignal/integrations/resque_active_job.rb +2 -0
- data/lib/appsignal/rack/js_exception_catcher.rb +2 -5
- data/lib/appsignal/transaction.rb +22 -7
- data/lib/appsignal/version.rb +1 -1
- data/spec/lib/appsignal/capistrano2_spec.rb +1 -1
- data/spec/lib/appsignal/capistrano3_spec.rb +1 -1
- data/spec/lib/appsignal/cli/diagnose_spec.rb +0 -42
- data/spec/lib/appsignal/config_spec.rb +5 -24
- data/spec/lib/appsignal/environment_spec.rb +167 -0
- data/spec/lib/appsignal/marker_spec.rb +1 -1
- data/spec/lib/appsignal/rack/js_exception_catcher_spec.rb +4 -9
- data/spec/lib/appsignal/transaction_spec.rb +30 -13
- data/spec/lib/appsignal_spec.rb +22 -0
- data/spec/support/helpers/config_helpers.rb +2 -3
- data/spec/support/helpers/env_helpers.rb +1 -1
- data/spec/support/helpers/environment_metdata_helper.rb +16 -0
- metadata +10 -5
@@ -60,6 +60,9 @@ module Appsignal
|
|
60
60
|
[:appsignal_string],
|
61
61
|
:appsignal_string
|
62
62
|
attach_function :appsignal_running_in_container, [], :bool
|
63
|
+
attach_function :appsignal_set_environment_metadata,
|
64
|
+
[:appsignal_string, :appsignal_string],
|
65
|
+
:void
|
63
66
|
|
64
67
|
# Metrics methods
|
65
68
|
attach_function :appsignal_set_gauge,
|
@@ -224,6 +227,13 @@ module Appsignal
|
|
224
227
|
appsignal_running_in_container
|
225
228
|
end
|
226
229
|
|
230
|
+
def set_environment_metadata(key, value)
|
231
|
+
appsignal_set_environment_metadata(
|
232
|
+
make_appsignal_string(key),
|
233
|
+
make_appsignal_string(value)
|
234
|
+
)
|
235
|
+
end
|
236
|
+
|
227
237
|
def set_gauge(key, value, tags)
|
228
238
|
appsignal_set_gauge(make_appsignal_string(key), value, tags.pointer)
|
229
239
|
end
|
@@ -29,11 +29,8 @@ module Appsignal
|
|
29
29
|
Appsignal.logger.debug \
|
30
30
|
"Initializing Appsignal::Rack::JSExceptionCatcher"
|
31
31
|
deprecation_message "The Appsignal::Rack::JSExceptionCatcher is " \
|
32
|
-
"deprecated
|
33
|
-
"
|
34
|
-
"`enable_frontend_error_catching` in your configuration and " \
|
35
|
-
"installing AppSignal for JavaScript instead. " \
|
36
|
-
"(https://docs.appsignal.com/front-end/)"
|
32
|
+
"deprecated. Please use the official AppSignal JavaScript " \
|
33
|
+
"integration instead. https://docs.appsignal.com/front-end/"
|
37
34
|
@app = app
|
38
35
|
end
|
39
36
|
|
@@ -228,12 +228,27 @@ module Appsignal
|
|
228
228
|
Appsignal.logger.warn("Queue start value #{start} is too big")
|
229
229
|
end
|
230
230
|
|
231
|
+
# Set the queue time based on the HTTP header or `:queue_start` env key
|
232
|
+
# value.
|
233
|
+
#
|
234
|
+
# This method will first try to read the queue time from the HTTP headers
|
235
|
+
# `X-Request-Start` or `X-Queue-Start`. Which are parsed by Rack as
|
236
|
+
# `HTTP_X_QUEUE_START` and `HTTP_X_REQUEST_START`.
|
237
|
+
# The header value is parsed by AppSignal as either milliseconds or
|
238
|
+
# microseconds.
|
239
|
+
#
|
240
|
+
# If no headers are found, or the value could not be parsed, it falls back
|
241
|
+
# on the `:queue_start` env key on this Transaction's {request} environment
|
242
|
+
# (called like `request.env[:queue_start]`). This value is parsed by
|
243
|
+
# AppSignal as seconds.
|
244
|
+
#
|
245
|
+
# @see https://docs.appsignal.com/ruby/instrumentation/request-queue-time.html
|
246
|
+
# @return [void]
|
231
247
|
def set_http_or_background_queue_start
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
end
|
248
|
+
start = http_queue_start || background_queue_start
|
249
|
+
return unless start
|
250
|
+
|
251
|
+
set_queue_start(start)
|
237
252
|
end
|
238
253
|
|
239
254
|
def set_metadata(key, value)
|
@@ -346,14 +361,14 @@ module Appsignal
|
|
346
361
|
#
|
347
362
|
# @return [nil] if no {#environment} is present.
|
348
363
|
# @return [nil] if there is no `:queue_start` in the {#environment}.
|
349
|
-
# @return [Integer]
|
364
|
+
# @return [Integer] `:queue_start` time (in seconds) converted to milliseconds
|
350
365
|
def background_queue_start
|
351
366
|
env = environment
|
352
367
|
return unless env
|
353
368
|
queue_start = env[:queue_start]
|
354
369
|
return unless queue_start
|
355
370
|
|
356
|
-
(queue_start.to_f * 1000.0).to_i
|
371
|
+
(queue_start.to_f * 1000.0).to_i # Convert seconds to milliseconds
|
357
372
|
end
|
358
373
|
|
359
374
|
# Returns HTTP queue start time in milliseconds.
|
data/lib/appsignal/version.rb
CHANGED
@@ -10,7 +10,7 @@ if DependencyHelper.capistrano2_present?
|
|
10
10
|
let(:capistrano_config) do
|
11
11
|
Capistrano::Configuration.new.tap do |c|
|
12
12
|
c.set(:rails_env, "production")
|
13
|
-
c.set(:repository, "
|
13
|
+
c.set(:repository, "master")
|
14
14
|
c.set(:deploy_to, "/home/username/app")
|
15
15
|
c.set(:current_release, "")
|
16
16
|
c.set(:current_revision, "503ce0923ed177a3ce000005")
|
@@ -15,7 +15,7 @@ if DependencyHelper.capistrano3_present?
|
|
15
15
|
c.set(:log_level, :error)
|
16
16
|
c.set(:logger, logger)
|
17
17
|
c.set(:rails_env, "production")
|
18
|
-
c.set(:repository, "
|
18
|
+
c.set(:repository, "master")
|
19
19
|
c.set(:deploy_to, "/home/username/app")
|
20
20
|
c.set(:current_release, "")
|
21
21
|
c.set(:current_revision, "503ce0923ed177a3ce000005")
|
@@ -290,8 +290,6 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
|
|
290
290
|
jruby = Appsignal::System.jruby?
|
291
291
|
expect(output).to include(
|
292
292
|
"Extension installation report",
|
293
|
-
"Installation result",
|
294
|
-
" Status: success",
|
295
293
|
"Language details",
|
296
294
|
" Implementation: #{jruby ? "jruby" : "ruby"}",
|
297
295
|
" Ruby version: #{"#{rbconfig["ruby_version"]}-p#{rbconfig["PATCHLEVEL"]}"}",
|
@@ -312,46 +310,6 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
|
|
312
310
|
)
|
313
311
|
end
|
314
312
|
|
315
|
-
context "with error in install report" do
|
316
|
-
let(:error) { RuntimeError.new("some error") }
|
317
|
-
before do
|
318
|
-
allow(File).to receive(:read).and_call_original
|
319
|
-
expect(File).to receive(:read)
|
320
|
-
.with(File.expand_path("../../../../../ext/install.report", __FILE__))
|
321
|
-
.and_return(
|
322
|
-
YAML.dump(
|
323
|
-
"result" => {
|
324
|
-
"status" => "error",
|
325
|
-
"error" => "RuntimeError: some error",
|
326
|
-
"backtrace" => error.backtrace
|
327
|
-
}
|
328
|
-
)
|
329
|
-
)
|
330
|
-
end
|
331
|
-
|
332
|
-
it "sends an error" do
|
333
|
-
run
|
334
|
-
expect(received_report["installation"]).to match(
|
335
|
-
"result" => {
|
336
|
-
"status" => "error",
|
337
|
-
"error" => "RuntimeError: some error",
|
338
|
-
"backtrace" => error.backtrace
|
339
|
-
}
|
340
|
-
)
|
341
|
-
end
|
342
|
-
|
343
|
-
it "prints the error" do
|
344
|
-
run
|
345
|
-
|
346
|
-
expect(output).to include(
|
347
|
-
"Extension installation report",
|
348
|
-
"Installation result",
|
349
|
-
"Status: error\n Error: RuntimeError: some error"
|
350
|
-
)
|
351
|
-
expect(output).to_not include("Raw report:")
|
352
|
-
end
|
353
|
-
end
|
354
|
-
|
355
313
|
context "without install report" do
|
356
314
|
let(:error) { RuntimeError.new("foo") }
|
357
315
|
before do
|
@@ -148,6 +148,7 @@ describe Appsignal::Config do
|
|
148
148
|
:instrument_redis => true,
|
149
149
|
:instrument_sequel => true,
|
150
150
|
:skip_session_data => false,
|
151
|
+
:send_environment_metadata => true,
|
151
152
|
:send_params => true,
|
152
153
|
:endpoint => "https://push.appsignal.com",
|
153
154
|
:push_api_key => "abc",
|
@@ -243,27 +244,6 @@ describe Appsignal::Config do
|
|
243
244
|
end
|
244
245
|
end
|
245
246
|
|
246
|
-
context "with an overriden config file" do
|
247
|
-
let(:config) do
|
248
|
-
project_fixture_config("production", {}, Appsignal.logger, File.join(project_fixture_path, "config", "appsignal.yml"))
|
249
|
-
end
|
250
|
-
|
251
|
-
it "is valid and active" do
|
252
|
-
expect(config.valid?).to be_truthy
|
253
|
-
expect(config.active?).to be_truthy
|
254
|
-
end
|
255
|
-
|
256
|
-
context "with an invalid overriden config file" do
|
257
|
-
let(:config) do
|
258
|
-
project_fixture_config("production", {}, Appsignal.logger, File.join(project_fixture_path, "config", "missing.yml"))
|
259
|
-
end
|
260
|
-
|
261
|
-
it "is not valid" do
|
262
|
-
expect(config.valid?).to be_falsy
|
263
|
-
end
|
264
|
-
end
|
265
|
-
end
|
266
|
-
|
267
247
|
context "with the config file causing an error" do
|
268
248
|
let(:config_path) do
|
269
249
|
File.expand_path(
|
@@ -417,7 +397,6 @@ describe Appsignal::Config do
|
|
417
397
|
:debug => true
|
418
398
|
)
|
419
399
|
end
|
420
|
-
let(:working_directory_path) { File.join(tmp_dir, "test_working_directory_path") }
|
421
400
|
let(:env_config) do
|
422
401
|
{
|
423
402
|
:running_in_container => true,
|
@@ -434,7 +413,7 @@ describe Appsignal::Config do
|
|
434
413
|
:files_world_accessible => false,
|
435
414
|
:request_headers => %w[accept accept-charset],
|
436
415
|
:revision => "v2.5.1",
|
437
|
-
:
|
416
|
+
:send_environment_metadata => false
|
438
417
|
}
|
439
418
|
end
|
440
419
|
before do
|
@@ -451,7 +430,7 @@ describe Appsignal::Config do
|
|
451
430
|
ENV["APPSIGNAL_INSTRUMENT_SEQUEL"] = "false"
|
452
431
|
ENV["APPSIGNAL_FILES_WORLD_ACCESSIBLE"] = "false"
|
453
432
|
ENV["APPSIGNAL_REQUEST_HEADERS"] = "accept,accept-charset"
|
454
|
-
ENV["
|
433
|
+
ENV["APPSIGNAL_SEND_ENVIRONMENT_METADATA"] = "false"
|
455
434
|
ENV["APP_REVISION"] = "v2.5.1"
|
456
435
|
end
|
457
436
|
|
@@ -551,6 +530,7 @@ describe Appsignal::Config do
|
|
551
530
|
config[:running_in_container] = false
|
552
531
|
config[:dns_servers] = ["8.8.8.8", "8.8.4.4"]
|
553
532
|
config[:transaction_debug_mode] = true
|
533
|
+
config[:send_environment_metadata] = false
|
554
534
|
config[:revision] = "v2.5.1"
|
555
535
|
config.write_to_environment
|
556
536
|
end
|
@@ -579,6 +559,7 @@ describe Appsignal::Config do
|
|
579
559
|
expect(ENV["_APPSIGNAL_DNS_SERVERS"]).to eq "8.8.8.8,8.8.4.4"
|
580
560
|
expect(ENV["_APPSIGNAL_FILES_WORLD_ACCESSIBLE"]).to eq "true"
|
581
561
|
expect(ENV["_APPSIGNAL_TRANSACTION_DEBUG_MODE"]).to eq "true"
|
562
|
+
expect(ENV["_APPSIGNAL_SEND_ENVIRONMENT_METADATA"]).to eq "false"
|
582
563
|
expect(ENV["_APP_REVISION"]).to eq "v2.5.1"
|
583
564
|
expect(ENV).to_not have_key("_APPSIGNAL_WORKING_DIR_PATH")
|
584
565
|
expect(ENV).to_not have_key("_APPSIGNAL_WORKING_DIRECTORY_PATH")
|
@@ -0,0 +1,167 @@
|
|
1
|
+
describe Appsignal::Environment do
|
2
|
+
include EnvironmentMetadataHelper
|
3
|
+
|
4
|
+
before(:context) { start_agent }
|
5
|
+
before { capture_environment_metadata_report_calls }
|
6
|
+
|
7
|
+
def report(key, &value_block)
|
8
|
+
described_class.report(key, &value_block)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe ".report" do
|
12
|
+
it "sends environment metadata to the extension" do
|
13
|
+
logs =
|
14
|
+
capture_logs do
|
15
|
+
report("_test_ruby_version") { "1.0.0" }
|
16
|
+
expect_environment_metadata("_test_ruby_version", "1.0.0")
|
17
|
+
end
|
18
|
+
expect(logs).to be_empty
|
19
|
+
end
|
20
|
+
|
21
|
+
context "when the key is a non String type" do
|
22
|
+
it "does not set the value" do
|
23
|
+
logs =
|
24
|
+
capture_logs do
|
25
|
+
report(:_test_symbol) { "1.0.0" }
|
26
|
+
expect_not_environment_metadata(:_test_symbol)
|
27
|
+
expect_not_environment_metadata("_test_symbol")
|
28
|
+
end
|
29
|
+
expect(logs).to contains_log(
|
30
|
+
:error,
|
31
|
+
"Unable to report on environment metadata: Unsupported value type for :_test_symbol"
|
32
|
+
)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context "when the key is nil" do
|
37
|
+
it "does not set the value" do
|
38
|
+
logs =
|
39
|
+
capture_logs do
|
40
|
+
report(nil) { "1" }
|
41
|
+
expect_not_environment_metadata(nil)
|
42
|
+
end
|
43
|
+
expect(logs).to contains_log(
|
44
|
+
:error,
|
45
|
+
"Unable to report on environment metadata: Unsupported value type for nil"
|
46
|
+
)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "when the value is true or false" do
|
51
|
+
it "reports true or false as Strings" do
|
52
|
+
logs =
|
53
|
+
capture_logs do
|
54
|
+
report("_test_true") { true }
|
55
|
+
report("_test_false") { false }
|
56
|
+
expect_environment_metadata("_test_true", "true")
|
57
|
+
expect_environment_metadata("_test_false", "false")
|
58
|
+
end
|
59
|
+
expect(logs).to be_empty
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context "when the value is nil" do
|
64
|
+
it "does not set the value" do
|
65
|
+
logs =
|
66
|
+
capture_logs do
|
67
|
+
report("_test_ruby_version") { nil }
|
68
|
+
expect_not_environment_metadata("_test_ruby_version")
|
69
|
+
end
|
70
|
+
expect(logs).to contains_log(
|
71
|
+
:error,
|
72
|
+
"Unable to report on environment metadata \"_test_ruby_version\": " \
|
73
|
+
"Unsupported value type for nil"
|
74
|
+
)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context "when the value block raises an error" do
|
79
|
+
it "does not re-raise the error and writes it to the log" do
|
80
|
+
logs =
|
81
|
+
capture_logs do
|
82
|
+
report("_test_error") { raise "uh oh" }
|
83
|
+
expect_not_environment_metadata("_test_error")
|
84
|
+
end
|
85
|
+
expect(logs).to contains_log(
|
86
|
+
:error,
|
87
|
+
"Unable to report on environment metadata \"_test_error\":\n" \
|
88
|
+
"RuntimeError: uh oh"
|
89
|
+
)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
context "when something unforseen errors" do
|
94
|
+
it "does not re-raise the error and writes it to the log" do
|
95
|
+
klass = Class.new do
|
96
|
+
def inspect
|
97
|
+
raise "inspect error"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
logs =
|
102
|
+
capture_logs do
|
103
|
+
report(klass.new) { raise "value error" }
|
104
|
+
expect(Appsignal::Extension).to_not have_received(:set_environment_metadata)
|
105
|
+
end
|
106
|
+
expect(logs).to contains_log(
|
107
|
+
:error,
|
108
|
+
"Unable to report on environment metadata:\n" \
|
109
|
+
"RuntimeError: inspect error"
|
110
|
+
)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe ".report_supported_gems" do
|
116
|
+
it "reports about all AppSignal supported gems in the bundle" do
|
117
|
+
logs = capture_logs { described_class.report_supported_gems }
|
118
|
+
|
119
|
+
expect(logs).to be_empty
|
120
|
+
|
121
|
+
bundle_gem_specs = ::Bundler.rubygems.all_specs
|
122
|
+
rack_spec = bundle_gem_specs.find { |s| s.name == "rack" }
|
123
|
+
rake_spec = bundle_gem_specs.find { |s| s.name == "rake" }
|
124
|
+
expect_environment_metadata("ruby_rack_version", rack_spec.version.to_s)
|
125
|
+
expect_environment_metadata("ruby_rake_version", rake_spec.version.to_s)
|
126
|
+
expect(rack_spec.version.to_s).to_not be_empty
|
127
|
+
expect(rake_spec.version.to_s).to_not be_empty
|
128
|
+
end
|
129
|
+
|
130
|
+
context "when something unforseen errors" do
|
131
|
+
it "does not re-raise the error and writes it to the log" do
|
132
|
+
expect(Bundler).to receive(:rubygems).and_raise(RuntimeError, "bundler error")
|
133
|
+
|
134
|
+
logs = capture_logs { described_class.report_supported_gems }
|
135
|
+
expect(logs).to contains_log(
|
136
|
+
:error,
|
137
|
+
"Unable to report supported gems:\nRuntimeError: bundler error"
|
138
|
+
)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
describe ".report_enabled" do
|
144
|
+
it "reports a feature being enabled" do
|
145
|
+
logs = capture_logs { described_class.report_enabled("a_test") }
|
146
|
+
|
147
|
+
expect(logs).to be_empty
|
148
|
+
expect_environment_metadata("ruby_a_test_enabled", "true")
|
149
|
+
end
|
150
|
+
|
151
|
+
context "when something unforseen errors" do
|
152
|
+
it "does not re-raise the error and writes it to the log" do
|
153
|
+
klass = Class.new do
|
154
|
+
def to_s
|
155
|
+
raise "to_s error"
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
logs = capture_logs { described_class.report_enabled(klass.new) }
|
160
|
+
expect(logs).to contains_log(
|
161
|
+
:error,
|
162
|
+
"Unable to report integration enabled:\nRuntimeError: to_s error"
|
163
|
+
)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|