appsignal 2.11.0.beta.4-java → 2.11.2-java
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/.semaphore/semaphore.yml +254 -1
- data/CHANGELOG.md +27 -0
- data/README.md +20 -5
- data/Rakefile +27 -9
- data/appsignal.gemspec +1 -1
- data/build_matrix.yml +15 -2
- data/ext/Rakefile +2 -0
- data/ext/agent.yml +17 -25
- data/ext/appsignal_extension.c +1 -1
- data/ext/base.rb +19 -9
- data/ext/extconf.rb +2 -0
- data/gemfiles/no_dependencies.gemfile +7 -0
- data/gemfiles/resque-2.gemfile +0 -1
- data/gemfiles/webmachine.gemfile +1 -0
- data/lib/appsignal.rb +1 -0
- data/lib/appsignal/auth_check.rb +4 -2
- data/lib/appsignal/cli/diagnose.rb +1 -1
- data/lib/appsignal/cli/diagnose/utils.rb +8 -11
- data/lib/appsignal/cli/install.rb +5 -8
- data/lib/appsignal/config.rb +82 -17
- data/lib/appsignal/extension.rb +6 -5
- data/lib/appsignal/extension/jruby.rb +6 -5
- data/lib/appsignal/helpers/instrumentation.rb +32 -0
- data/lib/appsignal/hooks.rb +24 -0
- data/lib/appsignal/hooks/action_mailer.rb +22 -0
- data/lib/appsignal/hooks/active_job.rb +32 -9
- data/lib/appsignal/hooks/active_support_notifications.rb +72 -0
- data/lib/appsignal/hooks/puma.rb +0 -1
- data/lib/appsignal/hooks/sidekiq.rb +0 -1
- data/lib/appsignal/probes.rb +7 -0
- data/lib/appsignal/probes/puma.rb +1 -1
- data/lib/appsignal/probes/sidekiq.rb +3 -1
- data/lib/appsignal/transaction.rb +30 -2
- data/lib/appsignal/utils/deprecation_message.rb +1 -1
- data/lib/appsignal/version.rb +1 -1
- data/spec/lib/appsignal/auth_check_spec.rb +23 -0
- 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 +42 -0
- data/spec/lib/appsignal/config_spec.rb +39 -1
- data/spec/lib/appsignal/extension/jruby_spec.rb +31 -28
- data/spec/lib/appsignal/extension_install_failure_spec.rb +23 -0
- data/spec/lib/appsignal/hooks/action_mailer_spec.rb +54 -0
- data/spec/lib/appsignal/hooks/active_support_notifications/finish_with_state_shared_examples.rb +35 -0
- data/spec/lib/appsignal/hooks/active_support_notifications/instrument_shared_examples.rb +145 -0
- data/spec/lib/appsignal/hooks/active_support_notifications/start_finish_shared_examples.rb +69 -0
- data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +9 -137
- data/spec/lib/appsignal/hooks/activejob_spec.rb +44 -1
- data/spec/lib/appsignal/hooks/resque_spec.rb +10 -2
- data/spec/lib/appsignal/hooks/sidekiq_spec.rb +4 -2
- data/spec/lib/appsignal/hooks_spec.rb +57 -0
- data/spec/lib/appsignal/marker_spec.rb +1 -1
- data/spec/lib/appsignal/transaction_spec.rb +55 -0
- data/spec/lib/appsignal_spec.rb +30 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/support/helpers/config_helpers.rb +3 -2
- data/spec/support/helpers/dependency_helper.rb +4 -0
- data/spec/support/helpers/transaction_helpers.rb +1 -1
- data/spec/support/testing.rb +19 -19
- metadata +17 -5
data/lib/appsignal/hooks/puma.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
module Appsignal
|
2
2
|
module Probes
|
3
|
-
# @api private
|
4
3
|
class SidekiqProbe
|
4
|
+
# @api private
|
5
5
|
attr_reader :config
|
6
6
|
|
7
|
+
# @api private
|
7
8
|
def self.dependencies_present?
|
8
9
|
Gem::Version.new(::Redis::VERSION) >= Gem::Version.new("3.3.5")
|
9
10
|
end
|
@@ -16,6 +17,7 @@ module Appsignal
|
|
16
17
|
require "sidekiq/api"
|
17
18
|
end
|
18
19
|
|
20
|
+
# @api private
|
19
21
|
def call
|
20
22
|
track_redis_info
|
21
23
|
track_stats
|
@@ -11,6 +11,7 @@ module Appsignal
|
|
11
11
|
BLANK = "".freeze
|
12
12
|
ALLOWED_TAG_KEY_TYPES = [Symbol, String].freeze
|
13
13
|
ALLOWED_TAG_VALUE_TYPES = [Symbol, String, Integer].freeze
|
14
|
+
BREADCRUMB_LIMIT = 20
|
14
15
|
|
15
16
|
class << self
|
16
17
|
def create(id, namespace, request, options = {})
|
@@ -58,7 +59,7 @@ module Appsignal
|
|
58
59
|
end
|
59
60
|
end
|
60
61
|
|
61
|
-
attr_reader :ext, :transaction_id, :action, :namespace, :request, :paused, :tags, :options, :discarded
|
62
|
+
attr_reader :ext, :transaction_id, :action, :namespace, :request, :paused, :tags, :options, :discarded, :breadcrumbs
|
62
63
|
|
63
64
|
# @!attribute params
|
64
65
|
# Attribute for parameters of the transaction.
|
@@ -80,6 +81,7 @@ module Appsignal
|
|
80
81
|
@paused = false
|
81
82
|
@discarded = false
|
82
83
|
@tags = {}
|
84
|
+
@breadcrumbs = []
|
83
85
|
@store = Hash.new({})
|
84
86
|
@options = options
|
85
87
|
@options[:params_method] ||= :params
|
@@ -156,6 +158,31 @@ module Appsignal
|
|
156
158
|
@tags.merge!(given_tags)
|
157
159
|
end
|
158
160
|
|
161
|
+
# Add breadcrumbs to the transaction.
|
162
|
+
#
|
163
|
+
# @param category [String] category of breadcrumb
|
164
|
+
# e.g. "UI", "Network", "Navigation", "Console".
|
165
|
+
# @param action [String] name of breadcrumb
|
166
|
+
# e.g "The user clicked a button", "HTTP 500 from http://blablabla.com"
|
167
|
+
# @option message [String] optional message in string format
|
168
|
+
# @option metadata [Hash<String,String>] key/value metadata in <string, string> format
|
169
|
+
# @option time [Time] time of breadcrumb, should respond to `.to_i` defaults to `Time.now.utc`
|
170
|
+
# @return [void]
|
171
|
+
#
|
172
|
+
# @see Appsignal.add_breadcrumb
|
173
|
+
# @see http://docs.appsignal.com/ruby/instrumentation/breadcrumbs.html
|
174
|
+
# Breadcrumb reference
|
175
|
+
def add_breadcrumb(category, action, message = "", metadata = {}, time = Time.now.utc)
|
176
|
+
@breadcrumbs.push(
|
177
|
+
:time => time.to_i,
|
178
|
+
:category => category,
|
179
|
+
:action => action,
|
180
|
+
:message => message,
|
181
|
+
:metadata => metadata
|
182
|
+
)
|
183
|
+
@breadcrumbs = @breadcrumbs.last(BREADCRUMB_LIMIT)
|
184
|
+
end
|
185
|
+
|
159
186
|
# Set an action name for the transaction.
|
160
187
|
#
|
161
188
|
# An action name is used to identify the location of a certain sample;
|
@@ -287,7 +314,8 @@ module Appsignal
|
|
287
314
|
:environment => sanitized_environment,
|
288
315
|
:session_data => sanitized_session_data,
|
289
316
|
:metadata => metadata,
|
290
|
-
:tags => sanitized_tags
|
317
|
+
:tags => sanitized_tags,
|
318
|
+
:breadcrumbs => breadcrumbs
|
291
319
|
}.each do |key, data|
|
292
320
|
set_sample_data(key, data)
|
293
321
|
end
|
data/lib/appsignal/version.rb
CHANGED
@@ -28,6 +28,29 @@ describe Appsignal::AuthCheck do
|
|
28
28
|
end.join("&")
|
29
29
|
end
|
30
30
|
|
31
|
+
describe ".new" do
|
32
|
+
describe "with logger argument" do
|
33
|
+
let(:err_stream) { std_stream }
|
34
|
+
let(:stderr) { err_stream.read }
|
35
|
+
let(:log_stream) { std_stream }
|
36
|
+
let(:log) { log_contents(log_stream) }
|
37
|
+
|
38
|
+
it "logs and prints a deprecation message" do
|
39
|
+
Appsignal.logger = test_logger(log_stream)
|
40
|
+
|
41
|
+
capture_std_streams(std_stream, err_stream) do
|
42
|
+
Appsignal::AuthCheck.new(config, Appsignal.logger)
|
43
|
+
end
|
44
|
+
|
45
|
+
deprecation_message =
|
46
|
+
"`Appsignal::AuthCheck.new`'s `logger` argument " \
|
47
|
+
"will be removed in the next major version."
|
48
|
+
expect(stderr).to include "appsignal WARNING: #{deprecation_message}"
|
49
|
+
expect(log).to contains_log :warn, deprecation_message
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
31
54
|
describe "#perform" do
|
32
55
|
subject { auth_check.perform }
|
33
56
|
|
@@ -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, "main")
|
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, "main")
|
19
19
|
c.set(:deploy_to, "/home/username/app")
|
20
20
|
c.set(:current_release, "")
|
21
21
|
c.set(:current_revision, "503ce0923ed177a3ce000005")
|
@@ -290,6 +290,8 @@ 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",
|
293
295
|
"Language details",
|
294
296
|
" Implementation: #{jruby ? "jruby" : "ruby"}",
|
295
297
|
" Ruby version: #{"#{rbconfig["ruby_version"]}-p#{rbconfig["PATCHLEVEL"]}"}",
|
@@ -310,6 +312,46 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
|
|
310
312
|
)
|
311
313
|
end
|
312
314
|
|
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
|
+
|
313
355
|
context "without install report" do
|
314
356
|
let(:error) { RuntimeError.new("foo") }
|
315
357
|
before do
|
@@ -1,4 +1,18 @@
|
|
1
1
|
describe Appsignal::Config do
|
2
|
+
describe "config keys" do
|
3
|
+
it "all config keys have an environment variable version registered" do
|
4
|
+
config = Appsignal::Config
|
5
|
+
mapped_env_keys = config::ENV_TO_KEY_MAPPING.keys.sort
|
6
|
+
configured_env_keys = (
|
7
|
+
config::ENV_STRING_KEYS +
|
8
|
+
config::ENV_BOOLEAN_KEYS +
|
9
|
+
config::ENV_ARRAY_KEYS
|
10
|
+
).sort
|
11
|
+
|
12
|
+
expect(mapped_env_keys).to eql(configured_env_keys)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
2
16
|
describe "#initialize" do
|
3
17
|
describe "environment" do
|
4
18
|
context "when environment is nil" do
|
@@ -244,6 +258,27 @@ describe Appsignal::Config do
|
|
244
258
|
end
|
245
259
|
end
|
246
260
|
|
261
|
+
context "with an overriden config file" do
|
262
|
+
let(:config) do
|
263
|
+
project_fixture_config("production", {}, Appsignal.logger, File.join(project_fixture_path, "config", "appsignal.yml"))
|
264
|
+
end
|
265
|
+
|
266
|
+
it "is valid and active" do
|
267
|
+
expect(config.valid?).to be_truthy
|
268
|
+
expect(config.active?).to be_truthy
|
269
|
+
end
|
270
|
+
|
271
|
+
context "with an invalid overriden config file" do
|
272
|
+
let(:config) do
|
273
|
+
project_fixture_config("production", {}, Appsignal.logger, File.join(project_fixture_path, "config", "missing.yml"))
|
274
|
+
end
|
275
|
+
|
276
|
+
it "is not valid" do
|
277
|
+
expect(config.valid?).to be_falsy
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
247
282
|
context "with the config file causing an error" do
|
248
283
|
let(:config_path) do
|
249
284
|
File.expand_path(
|
@@ -397,6 +432,7 @@ describe Appsignal::Config do
|
|
397
432
|
:debug => true
|
398
433
|
)
|
399
434
|
end
|
435
|
+
let(:working_directory_path) { File.join(tmp_dir, "test_working_directory_path") }
|
400
436
|
let(:env_config) do
|
401
437
|
{
|
402
438
|
:running_in_container => true,
|
@@ -413,7 +449,8 @@ describe Appsignal::Config do
|
|
413
449
|
:files_world_accessible => false,
|
414
450
|
:request_headers => %w[accept accept-charset],
|
415
451
|
:revision => "v2.5.1",
|
416
|
-
:send_environment_metadata => false
|
452
|
+
:send_environment_metadata => false,
|
453
|
+
:working_directory_path => working_directory_path
|
417
454
|
}
|
418
455
|
end
|
419
456
|
before do
|
@@ -431,6 +468,7 @@ describe Appsignal::Config do
|
|
431
468
|
ENV["APPSIGNAL_FILES_WORLD_ACCESSIBLE"] = "false"
|
432
469
|
ENV["APPSIGNAL_REQUEST_HEADERS"] = "accept,accept-charset"
|
433
470
|
ENV["APPSIGNAL_SEND_ENVIRONMENT_METADATA"] = "false"
|
471
|
+
ENV["APPSIGNAL_WORKING_DIRECTORY_PATH"] = working_directory_path
|
434
472
|
ENV["APP_REVISION"] = "v2.5.1"
|
435
473
|
end
|
436
474
|
|
@@ -1,42 +1,45 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
describe "JRuby extension", :jruby do
|
2
|
+
let(:extension) { Appsignal::Extension }
|
3
|
+
let(:jruby_module) { Appsignal::Extension::Jruby }
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
# Tests if the conversions between the conversions without breaking on
|
9
|
-
# NULL terminated strings in C.
|
10
|
-
string = "Merry Christmas! \u0000 🎄"
|
5
|
+
it "creates a JRuby extension module" do
|
6
|
+
expect(Appsignal::Extension::Jruby).to be_kind_of(Module)
|
7
|
+
end
|
11
8
|
|
12
|
-
|
13
|
-
|
9
|
+
describe "string conversions" do
|
10
|
+
it "keeps the same value during string type conversions" do
|
11
|
+
# UTF-8 string with NULL
|
12
|
+
# Tests if the conversions between the conversions without breaking on
|
13
|
+
# NULL terminated strings in C.
|
14
|
+
string = "Merry Christmas! \u0000 🎄"
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
end
|
16
|
+
appsignal_string = extension.make_appsignal_string(string)
|
17
|
+
ruby_string = extension.make_ruby_string(appsignal_string)
|
18
18
|
|
19
|
-
|
20
|
-
expect(described_class.ffi_libraries.map(&:name).first).to include "libappsignal"
|
19
|
+
expect(ruby_string).to eq("Merry Christmas! \u0000 🎄")
|
21
20
|
end
|
21
|
+
end
|
22
22
|
|
23
|
-
|
24
|
-
|
23
|
+
it "loads libappsignal with FFI" do
|
24
|
+
expect(jruby_module.ffi_libraries.map(&:name).first).to include "libappsignal"
|
25
|
+
end
|
26
|
+
|
27
|
+
describe ".lib_extension" do
|
28
|
+
subject { jruby_module.lib_extension }
|
25
29
|
|
26
|
-
|
27
|
-
|
30
|
+
context "when on a darwin system" do
|
31
|
+
before { expect(Appsignal::System).to receive(:agent_platform).and_return("darwin") }
|
28
32
|
|
29
|
-
|
30
|
-
|
31
|
-
end
|
33
|
+
it "returns the extension for darwin" do
|
34
|
+
is_expected.to eq "dylib"
|
32
35
|
end
|
36
|
+
end
|
33
37
|
|
34
|
-
|
35
|
-
|
38
|
+
context "when on a linux system" do
|
39
|
+
before { expect(Appsignal::System).to receive(:agent_platform).and_return("linux") }
|
36
40
|
|
37
|
-
|
38
|
-
|
39
|
-
end
|
41
|
+
it "returns the lib extension for linux" do
|
42
|
+
is_expected.to eq "so"
|
40
43
|
end
|
41
44
|
end
|
42
45
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
describe Appsignal::Extension, :extension_installation_failure do
|
2
|
+
context "when the extension library cannot be loaded" do
|
3
|
+
# This test breaks the installation on purpose and is not run by default.
|
4
|
+
# See `rake test:failure`. If this test was run, run `rake
|
5
|
+
# extension:install` again to fix the extension installation.
|
6
|
+
it "prints and logs an error" do
|
7
|
+
# ENV var to make sure installation fails on purpurse
|
8
|
+
ENV["_TEST_APPSIGNAL_EXTENSION_FAILURE"] = "true"
|
9
|
+
`rake extension:install` # Run installation
|
10
|
+
|
11
|
+
require "open3"
|
12
|
+
_stdout, stderr, _status = Open3.capture3("bin/appsignal --version")
|
13
|
+
expect(stderr).to include("ERROR: AppSignal failed to load extension")
|
14
|
+
error_message =
|
15
|
+
if DependencyHelper.running_jruby?
|
16
|
+
"cannot open shared object file"
|
17
|
+
else
|
18
|
+
"LoadError: cannot load such file"
|
19
|
+
end
|
20
|
+
expect(stderr).to include(error_message)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
describe Appsignal::Hooks::ActionMailerHook do
|
2
|
+
if DependencyHelper.action_mailer_present? &&
|
3
|
+
DependencyHelper.rails_version >= Gem::Version.new("4.0.0")
|
4
|
+
context "with ActionMailer" do
|
5
|
+
require "action_mailer"
|
6
|
+
|
7
|
+
class UserMailer < ActionMailer::Base
|
8
|
+
default :from => "test@example.com"
|
9
|
+
|
10
|
+
def welcome
|
11
|
+
mail(:to => "test@example.com", :subject => "ActionMailer test", :content_type => "text/html") do |format|
|
12
|
+
format.html { render :html => "This is a test" }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
UserMailer.delivery_method = :test
|
17
|
+
|
18
|
+
describe ".dependencies_present?" do
|
19
|
+
subject { described_class.new.dependencies_present? }
|
20
|
+
|
21
|
+
it "returns true" do
|
22
|
+
is_expected.to be_truthy
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe ".install" do
|
27
|
+
before do
|
28
|
+
start_agent
|
29
|
+
expect(Appsignal.active?).to be_truthy
|
30
|
+
end
|
31
|
+
|
32
|
+
it "is subscribed to 'process.action_mailer' and processes instrumentation" do
|
33
|
+
expect(Appsignal).to receive(:increment_counter).with(
|
34
|
+
:action_mailer_process,
|
35
|
+
1,
|
36
|
+
:mailer => "UserMailer", :action => :welcome
|
37
|
+
)
|
38
|
+
|
39
|
+
UserMailer.welcome.deliver_now
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
else
|
44
|
+
context "without ActionMailer" do
|
45
|
+
describe ".dependencies_present?" do
|
46
|
+
subject { described_class.new.dependencies_present? }
|
47
|
+
|
48
|
+
it "returns false" do
|
49
|
+
is_expected.to be_falsy
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|