scout_apm 3.0.0.pre26 → 4.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/workflows/test.yml +49 -0
- data/.gitignore +1 -1
- data/.rubocop.yml +5 -5
- data/.travis.yml +19 -14
- data/CHANGELOG.markdown +143 -4
- data/Gemfile +1 -7
- data/README.markdown +13 -4
- data/Rakefile +1 -1
- data/ext/allocations/allocations.c +2 -0
- data/gems/README.md +28 -0
- data/gems/octoshark.gemfile +4 -0
- data/gems/rails3.gemfile +5 -0
- data/gems/rails4.gemfile +4 -0
- data/gems/rails5.gemfile +4 -0
- data/gems/rails6.gemfile +4 -0
- data/lib/scout_apm.rb +39 -9
- data/lib/scout_apm/agent.rb +29 -10
- data/lib/scout_apm/agent/exit_handler.rb +0 -1
- data/lib/scout_apm/agent_context.rb +22 -3
- data/lib/scout_apm/app_server_load.rb +7 -2
- data/lib/scout_apm/attribute_arranger.rb +0 -2
- data/lib/scout_apm/auto_instrument.rb +5 -0
- data/lib/scout_apm/auto_instrument/instruction_sequence.rb +31 -0
- data/lib/scout_apm/auto_instrument/layer.rb +23 -0
- data/lib/scout_apm/auto_instrument/parser.rb +27 -0
- data/lib/scout_apm/auto_instrument/rails.rb +175 -0
- data/lib/scout_apm/background_job_integrations/legacy_sneakers.rb +55 -0
- data/lib/scout_apm/background_job_integrations/que.rb +134 -0
- data/lib/scout_apm/background_job_integrations/resque.rb +6 -2
- data/lib/scout_apm/background_job_integrations/shoryuken.rb +124 -0
- data/lib/scout_apm/background_job_integrations/sidekiq.rb +5 -19
- data/lib/scout_apm/background_job_integrations/sneakers.rb +87 -0
- data/lib/scout_apm/config.rb +45 -8
- data/lib/scout_apm/detailed_trace.rb +217 -0
- data/lib/scout_apm/environment.rb +19 -1
- data/lib/scout_apm/error.rb +27 -0
- data/lib/scout_apm/error_service.rb +32 -0
- data/lib/scout_apm/error_service/error_buffer.rb +39 -0
- data/lib/scout_apm/error_service/error_record.rb +211 -0
- data/lib/scout_apm/error_service/ignored_exceptions.rb +66 -0
- data/lib/scout_apm/error_service/middleware.rb +32 -0
- data/lib/scout_apm/error_service/notifier.rb +33 -0
- data/lib/scout_apm/error_service/payload.rb +47 -0
- data/lib/scout_apm/error_service/periodic_work.rb +17 -0
- data/lib/scout_apm/error_service/railtie.rb +11 -0
- data/lib/scout_apm/error_service/sidekiq.rb +80 -0
- data/lib/scout_apm/extensions/transaction_callback_payload.rb +1 -1
- data/lib/scout_apm/fake_store.rb +3 -0
- data/lib/scout_apm/framework_integrations/rails_2.rb +2 -1
- data/lib/scout_apm/framework_integrations/rails_3_or_4.rb +3 -1
- data/lib/scout_apm/git_revision.rb +6 -3
- data/lib/scout_apm/instant/middleware.rb +2 -1
- data/lib/scout_apm/instrument_manager.rb +9 -7
- data/lib/scout_apm/instruments/action_controller_rails_2.rb +3 -1
- data/lib/scout_apm/instruments/action_controller_rails_3_rails4.rb +56 -55
- data/lib/scout_apm/instruments/action_view.rb +126 -26
- data/lib/scout_apm/instruments/active_record.rb +66 -18
- data/lib/scout_apm/instruments/http.rb +48 -0
- data/lib/scout_apm/instruments/memcached.rb +43 -0
- data/lib/scout_apm/instruments/mongoid.rb +9 -4
- data/lib/scout_apm/instruments/net_http.rb +8 -1
- data/lib/scout_apm/instruments/typhoeus.rb +87 -0
- data/lib/scout_apm/job_record.rb +4 -2
- data/lib/scout_apm/layaway_file.rb +4 -0
- data/lib/scout_apm/layer.rb +6 -57
- data/lib/scout_apm/layer_children_set.rb +9 -8
- data/lib/scout_apm/layer_converters/converter_base.rb +15 -30
- data/lib/scout_apm/layer_converters/database_converter.rb +2 -15
- data/lib/scout_apm/layer_converters/slow_job_converter.rb +12 -2
- data/lib/scout_apm/layer_converters/slow_request_converter.rb +14 -4
- data/lib/scout_apm/layer_converters/trace_converter.rb +184 -0
- data/lib/scout_apm/limited_layer.rb +0 -7
- data/lib/scout_apm/metric_stats.rb +0 -8
- data/lib/scout_apm/middleware.rb +1 -1
- data/lib/scout_apm/periodic_work.rb +19 -0
- data/lib/scout_apm/remote/message.rb +4 -0
- data/lib/scout_apm/remote/server.rb +13 -1
- data/lib/scout_apm/reporter.rb +8 -3
- data/lib/scout_apm/reporting.rb +2 -1
- data/lib/scout_apm/request_histograms.rb +8 -0
- data/lib/scout_apm/serializers/app_server_load_serializer.rb +4 -0
- data/lib/scout_apm/serializers/directive_serializer.rb +4 -0
- data/lib/scout_apm/serializers/payload_serializer.rb +2 -2
- data/lib/scout_apm/serializers/payload_serializer_to_json.rb +30 -15
- data/lib/scout_apm/slow_job_record.rb +5 -1
- data/lib/scout_apm/slow_policy/age_policy.rb +33 -0
- data/lib/scout_apm/slow_policy/percent_policy.rb +22 -0
- data/lib/scout_apm/slow_policy/percentile_policy.rb +24 -0
- data/lib/scout_apm/slow_policy/policy.rb +21 -0
- data/lib/scout_apm/slow_policy/speed_policy.rb +16 -0
- data/lib/scout_apm/slow_request_policy.rb +18 -77
- data/lib/scout_apm/slow_transaction.rb +3 -1
- data/lib/scout_apm/store.rb +12 -8
- data/lib/scout_apm/tracked_request.rb +39 -30
- data/lib/scout_apm/utils/active_record_metric_name.rb +16 -3
- data/lib/scout_apm/utils/backtrace_parser.rb +3 -0
- data/lib/scout_apm/utils/marshal_logging.rb +90 -0
- data/lib/scout_apm/utils/sql_sanitizer.rb +10 -1
- data/lib/scout_apm/utils/sql_sanitizer_regex.rb +8 -1
- data/lib/scout_apm/utils/sql_sanitizer_regex_1_8_7.rb +6 -0
- data/lib/scout_apm/utils/unique_id.rb +27 -0
- data/lib/scout_apm/version.rb +1 -1
- data/scout_apm.gemspec +13 -7
- data/test/test_helper.rb +2 -2
- data/test/unit/agent_context_test.rb +29 -0
- data/test/unit/auto_instrument/assignments-instrumented.rb +31 -0
- data/test/unit/auto_instrument/assignments.rb +31 -0
- data/test/unit/auto_instrument/controller-ast.txt +57 -0
- data/test/unit/auto_instrument/controller-instrumented.rb +49 -0
- data/test/unit/auto_instrument/controller.rb +49 -0
- data/test/unit/auto_instrument/rescue_from-instrumented.rb +13 -0
- data/test/unit/auto_instrument/rescue_from.rb +13 -0
- data/test/unit/auto_instrument_test.rb +54 -0
- data/test/unit/environment_test.rb +2 -2
- data/test/unit/error_service/error_buffer_test.rb +25 -0
- data/test/unit/error_service/ignored_exceptions_test.rb +49 -0
- data/test/unit/instruments/active_record_test.rb +40 -0
- data/test/unit/layer_children_set_test.rb +9 -0
- data/test/unit/request_histograms_test.rb +17 -0
- data/test/unit/serializers/payload_serializer_test.rb +39 -5
- data/test/unit/slow_request_policy_test.rb +41 -13
- data/test/unit/sql_sanitizer_test.rb +78 -0
- data/test/unit/utils/active_record_metric_name_test.rb +10 -2
- metadata +100 -18
- data/ext/stacks/extconf.rb +0 -37
- data/ext/stacks/scout_atomics.h +0 -86
- data/ext/stacks/stacks.c +0 -814
- data/lib/scout_apm/slow_job_policy.rb +0 -111
- data/lib/scout_apm/trace_compactor.rb +0 -312
- data/lib/scout_apm/utils/fake_stacks.rb +0 -88
- data/test/unit/instruments/active_record_instruments_test.rb +0 -5
- data/test/unit/slow_job_policy_test.rb +0 -6
- data/tester.rb +0 -53
@@ -0,0 +1,49 @@
|
|
1
|
+
|
2
|
+
class ClientsController < ApplicationController
|
3
|
+
before_action :check_authorization
|
4
|
+
|
5
|
+
def index
|
6
|
+
if ::ScoutApm::AutoInstrument("params[:status] == \"activated\"",["ROOT/test/unit/auto_instrument/controller.rb:6:in `index'"]){params[:status] == "activated"}
|
7
|
+
@clients = ::ScoutApm::AutoInstrument("Client.activated",["ROOT/test/unit/auto_instrument/controller.rb:7:in `index'"]){Client.activated}
|
8
|
+
else
|
9
|
+
@clients = ::ScoutApm::AutoInstrument("Client.inactivated",["ROOT/test/unit/auto_instrument/controller.rb:9:in `index'"]){Client.inactivated}
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def create
|
14
|
+
@client = ::ScoutApm::AutoInstrument("Client.new(params[:client])",["ROOT/test/unit/auto_instrument/controller.rb:14:in `create'"]){Client.new(params[:client])}
|
15
|
+
if ::ScoutApm::AutoInstrument("@client.save",["ROOT/test/unit/auto_instrument/controller.rb:15:in `create'"]){@client.save}
|
16
|
+
::ScoutApm::AutoInstrument("redirect_to @client",["ROOT/test/unit/auto_instrument/controller.rb:16:in `create'"]){redirect_to @client}
|
17
|
+
else
|
18
|
+
# This line overrides the default rendering behavior, which
|
19
|
+
# would have been to render the "create" view.
|
20
|
+
::ScoutApm::AutoInstrument("render \"new\"",["ROOT/test/unit/auto_instrument/controller.rb:20:in `create'"]){render "new"}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def edit
|
25
|
+
@client = ::ScoutApm::AutoInstrument("Client.new(params[:client])",["ROOT/test/unit/auto_instrument/controller.rb:25:in `edit'"]){Client.new(params[:client])}
|
26
|
+
|
27
|
+
if ::ScoutApm::AutoInstrument("request.post?",["ROOT/test/unit/auto_instrument/controller.rb:27:in `edit'"]){request.post?}
|
28
|
+
::ScoutApm::AutoInstrument("@client.transaction do...",["ROOT/test/unit/auto_instrument/controller.rb:28:in `edit'"]){@client.transaction do
|
29
|
+
@client.update_attributes(params[:client])
|
30
|
+
end}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def data
|
35
|
+
@clients = ::ScoutApm::AutoInstrument("Client.all",["ROOT/test/unit/auto_instrument/controller.rb:35:in `data'"]){Client.all}
|
36
|
+
|
37
|
+
formatter = ::ScoutApm::AutoInstrument("proc do |row|...",["ROOT/test/unit/auto_instrument/controller.rb:37:in `data'"]){proc do |row|
|
38
|
+
row.to_json
|
39
|
+
end}
|
40
|
+
|
41
|
+
::ScoutApm::AutoInstrument("respond_with @clients.each(&formatter).join(\"\\n\"), :content_type => 'application/json; boundary=NL'",["ROOT/test/unit/auto_instrument/controller.rb:41:in `data'"]){respond_with @clients.each(&formatter).join("\n"), :content_type => 'application/json; boundary=NL'}
|
42
|
+
end
|
43
|
+
|
44
|
+
def things
|
45
|
+
x = {}
|
46
|
+
x[:this] ||= 'foo'
|
47
|
+
x[:that] &&= ::ScoutApm::AutoInstrument("'foo'.size",["ROOT/test/unit/auto_instrument/controller.rb:47:in `things'"]){'foo'.size}
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
|
2
|
+
class ClientsController < ApplicationController
|
3
|
+
before_action :check_authorization
|
4
|
+
|
5
|
+
def index
|
6
|
+
if params[:status] == "activated"
|
7
|
+
@clients = Client.activated
|
8
|
+
else
|
9
|
+
@clients = Client.inactivated
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def create
|
14
|
+
@client = Client.new(params[:client])
|
15
|
+
if @client.save
|
16
|
+
redirect_to @client
|
17
|
+
else
|
18
|
+
# This line overrides the default rendering behavior, which
|
19
|
+
# would have been to render the "create" view.
|
20
|
+
render "new"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def edit
|
25
|
+
@client = Client.new(params[:client])
|
26
|
+
|
27
|
+
if request.post?
|
28
|
+
@client.transaction do
|
29
|
+
@client.update_attributes(params[:client])
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def data
|
35
|
+
@clients = Client.all
|
36
|
+
|
37
|
+
formatter = proc do |row|
|
38
|
+
row.to_json
|
39
|
+
end
|
40
|
+
|
41
|
+
respond_with @clients.each(&formatter).join("\n"), :content_type => 'application/json; boundary=NL'
|
42
|
+
end
|
43
|
+
|
44
|
+
def things
|
45
|
+
x = {}
|
46
|
+
x[:this] ||= 'foo'
|
47
|
+
x[:that] &&= 'foo'.size
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
|
2
|
+
class BrokenController < ApplicationController
|
3
|
+
rescue_from Exception do |e|
|
4
|
+
if e.is_a? Pundit::NotAuthorizedError
|
5
|
+
unauthorized_error
|
6
|
+
elsif e.is_a? ActionController::ParameterMissing
|
7
|
+
error(status: 422, message: e.message)
|
8
|
+
else
|
9
|
+
log_error(e)
|
10
|
+
error message: 'Internal error', exception: e
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
|
2
|
+
class BrokenController < ApplicationController
|
3
|
+
rescue_from Exception do |e|
|
4
|
+
if e.is_a? Pundit::NotAuthorizedError
|
5
|
+
unauthorized_error
|
6
|
+
elsif e.is_a? ActionController::ParameterMissing
|
7
|
+
error(status: 422, message: e.message)
|
8
|
+
else
|
9
|
+
log_error(e)
|
10
|
+
error message: 'Internal error', exception: e
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
require 'scout_apm/auto_instrument'
|
4
|
+
|
5
|
+
class AutoInstrumentTest < Minitest::Test
|
6
|
+
ROOT = File.expand_path("../../", __dir__)
|
7
|
+
|
8
|
+
def source_path(name)
|
9
|
+
File.expand_path("auto_instrument/#{name}.rb", __dir__)
|
10
|
+
end
|
11
|
+
|
12
|
+
def instrumented_path(name)
|
13
|
+
File.expand_path("auto_instrument/#{name}-instrumented.rb", __dir__)
|
14
|
+
end
|
15
|
+
|
16
|
+
def instrumented_source(name)
|
17
|
+
File.read(instrumented_path(name))
|
18
|
+
end
|
19
|
+
|
20
|
+
# Autoinstruments adds a backtrace to each created layer. This is the full path to the
|
21
|
+
# test controller.rb file, which will be different on different environments.
|
22
|
+
# This normalizes backtraces across environments.
|
23
|
+
def normalize_backtrace(string)
|
24
|
+
string.gsub(ROOT, "ROOT")
|
25
|
+
end
|
26
|
+
|
27
|
+
# Use this to automatically update the test fixtures.
|
28
|
+
def update_instrumented_source(name)
|
29
|
+
source = ::ScoutApm::AutoInstrument::Rails.rewrite(source_path(name))
|
30
|
+
source = normalize_backtrace(source)
|
31
|
+
File.write(instrumented_path(name),source)
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_controller_rewrite
|
35
|
+
# update_instrumented_source("controller")
|
36
|
+
|
37
|
+
assert_equal instrumented_source("controller"),
|
38
|
+
normalize_backtrace(::ScoutApm::AutoInstrument::Rails.rewrite(source_path("controller")))
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_rescue_from_rewrite
|
42
|
+
# update_instrumented_source("rescue_from")
|
43
|
+
|
44
|
+
assert_equal instrumented_source("rescue_from"),
|
45
|
+
normalize_backtrace(::ScoutApm::AutoInstrument::Rails.rewrite(source_path("rescue_from")))
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_assignments_rewrite
|
49
|
+
# update_instrumented_source("assignments")
|
50
|
+
|
51
|
+
assert_equal instrumented_source("assignments"),
|
52
|
+
normalize_backtrace(::ScoutApm::AutoInstrument::Rails.rewrite(source_path("assignments")))
|
53
|
+
end
|
54
|
+
end if defined? ScoutApm::AutoInstrument
|
@@ -44,8 +44,8 @@ class EnvironmentTest < Minitest::Test
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def clean_fake_rails
|
47
|
-
Kernel.
|
48
|
-
Kernel.
|
47
|
+
Kernel.send(:remove_const, "Rails") if defined?(Kernel::Rails)
|
48
|
+
Kernel.send(:remove_const, "ActionController") if defined?(Kernel::ActionController)
|
49
49
|
end
|
50
50
|
|
51
51
|
def fake_sinatra
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class ErrorBufferTest < Minitest::Test
|
4
|
+
class FakeError < StandardError
|
5
|
+
end
|
6
|
+
|
7
|
+
def test_captures_and_stores_exceptions_and_env
|
8
|
+
eb = ScoutApm::ErrorService::ErrorBuffer.new(context)
|
9
|
+
eb.capture(ex, env)
|
10
|
+
end
|
11
|
+
|
12
|
+
#### Helpers
|
13
|
+
|
14
|
+
def context
|
15
|
+
ScoutApm::AgentContext.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def env
|
19
|
+
{}
|
20
|
+
end
|
21
|
+
|
22
|
+
def ex(msg="Whoops")
|
23
|
+
FakeError.new(msg)
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class IgnoredExceptionsTest < Minitest::Test
|
4
|
+
class FakeError < StandardError
|
5
|
+
end
|
6
|
+
|
7
|
+
class SubclassFakeError < FakeError
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_ignores_with_string_match
|
11
|
+
ig = ScoutApm::ErrorService::IgnoredExceptions.new(context, ["RuntimeError"])
|
12
|
+
assert ig.ignored?(RuntimeError.new("something went wrong"))
|
13
|
+
assert !ig.ignored?(FakeError.new("something went wrong"))
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_ignores_with_block
|
17
|
+
ig = ScoutApm::ErrorService::IgnoredExceptions.new(context, [])
|
18
|
+
ig.add_callback { |e| e.message == "ignore me" }
|
19
|
+
|
20
|
+
should_ignore = RuntimeError.new("ignore me")
|
21
|
+
should_not_ignore = RuntimeError.new("super legit")
|
22
|
+
|
23
|
+
assert ig.ignored?(should_ignore)
|
24
|
+
assert !ig.ignored?(should_not_ignore)
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_ignores_subclasses
|
28
|
+
ig = ScoutApm::ErrorService::IgnoredExceptions.new(context, ["IgnoredExceptionsTest::FakeError"])
|
29
|
+
assert ig.ignored?(SubclassFakeError.new("Subclass"))
|
30
|
+
end
|
31
|
+
|
32
|
+
# Check that a bad exception in the list doesn't stop the whole thing from working
|
33
|
+
def test_does_not_consider_unknown_errors
|
34
|
+
ig = ScoutApm::ErrorService::IgnoredExceptions.new(context, ["ThisDoesNotExist", "IgnoredExceptionsTest::FakeError"])
|
35
|
+
assert ig.ignored?(FakeError.new("ignore this one"))
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_add_module
|
39
|
+
ig = ScoutApm::ErrorService::IgnoredExceptions.new(context, [])
|
40
|
+
ig.add(IgnoredExceptionsTest::FakeError)
|
41
|
+
assert ig.ignored?(FakeError.new("ignore this one"))
|
42
|
+
end
|
43
|
+
|
44
|
+
#### Helpers
|
45
|
+
|
46
|
+
def context
|
47
|
+
ScoutApm::AgentContext.new
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'sqlite3'
|
3
|
+
require 'active_record'
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'octoshark'
|
7
|
+
rescue LoadError
|
8
|
+
# Ignore
|
9
|
+
end
|
10
|
+
|
11
|
+
class ActiveRecordTest < Minitest::Test
|
12
|
+
def database_path
|
13
|
+
File.expand_path('test.sqlite3', DATA_FILE_DIR)
|
14
|
+
end
|
15
|
+
|
16
|
+
def setup
|
17
|
+
database = SQLite3::Database.new(database_path)
|
18
|
+
database.execute("DROP TABLE IF EXISTS users;")
|
19
|
+
database.execute("CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(100));")
|
20
|
+
|
21
|
+
ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => database_path)
|
22
|
+
end
|
23
|
+
|
24
|
+
class User < ActiveRecord::Base
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_instrumentation
|
28
|
+
recorder = FakeRecorder.new
|
29
|
+
agent_context.recorder = recorder
|
30
|
+
|
31
|
+
instrument = ScoutApm::Instruments::ActiveRecord.new(agent_context)
|
32
|
+
instrument.install
|
33
|
+
|
34
|
+
ScoutApm::Tracer.instrument("Controller", "foo/bar") do
|
35
|
+
user = User.create
|
36
|
+
end
|
37
|
+
|
38
|
+
assert 1, recorder.requests.size
|
39
|
+
end
|
40
|
+
end
|
@@ -71,6 +71,15 @@ class LayerChildrenSetTest < Minitest::Test
|
|
71
71
|
limited_layers.each { |ml| assert_equal 5, ml.count }
|
72
72
|
end
|
73
73
|
|
74
|
+
def test_works_with_marshal
|
75
|
+
s = SET.new(5)
|
76
|
+
10.times do
|
77
|
+
s << make_layer("LayerType", "LayerName")
|
78
|
+
end
|
79
|
+
|
80
|
+
Marshal.dump(s)
|
81
|
+
end
|
82
|
+
|
74
83
|
#############
|
75
84
|
# Helpers #
|
76
85
|
#############
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
require 'scout_apm/request_histograms'
|
4
|
+
|
5
|
+
class RequestHistogramsTest < Minitest::Test
|
6
|
+
def test_as_json_without_activesupport
|
7
|
+
rh = ScoutApm::RequestHistograms.new
|
8
|
+
|
9
|
+
rh.add("foo", 1)
|
10
|
+
rh.add("foo", 2)
|
11
|
+
rh.add("bar", 3)
|
12
|
+
|
13
|
+
j = rh.as_json
|
14
|
+
assert_equal 2, j.size
|
15
|
+
assert_equal ["bar", "foo"], j.keys.sort
|
16
|
+
end
|
17
|
+
end
|
@@ -8,7 +8,7 @@ class PayloadSerializerTest < Minitest::Test
|
|
8
8
|
:unique_id => "unique_idz",
|
9
9
|
:agent_version => 123
|
10
10
|
}
|
11
|
-
payload = ScoutApm::Serializers::PayloadSerializerToJson.serialize(metadata, {}, {}, [], [], [], {})
|
11
|
+
payload = ScoutApm::Serializers::PayloadSerializerToJson.serialize(metadata, {}, {}, [], [], [], {}, [])
|
12
12
|
|
13
13
|
# symbol keys turn to strings
|
14
14
|
formatted_metadata = {
|
@@ -49,7 +49,7 @@ class PayloadSerializerTest < Minitest::Test
|
|
49
49
|
stats.total_exclusive_time = 0.078132088
|
50
50
|
}
|
51
51
|
}
|
52
|
-
payload = ScoutApm::Serializers::PayloadSerializerToJson.serialize({}, metrics, {}, [], [], [], {})
|
52
|
+
payload = ScoutApm::Serializers::PayloadSerializerToJson.serialize({}, metrics, {}, [], [], [], {}, [])
|
53
53
|
formatted_metrics = [
|
54
54
|
{
|
55
55
|
"key" => {
|
@@ -69,7 +69,6 @@ class PayloadSerializerTest < Minitest::Test
|
|
69
69
|
"min_call_time" => 0.000613518,
|
70
70
|
"total_call_time" => 0.033245704,
|
71
71
|
"total_exclusive_time" => 0.033245704,
|
72
|
-
"traces" => []
|
73
72
|
},
|
74
73
|
{
|
75
74
|
"key" => {
|
@@ -84,7 +83,6 @@ class PayloadSerializerTest < Minitest::Test
|
|
84
83
|
"min_call_time" => 0.034881757,
|
85
84
|
"total_call_time" => 0.113403176,
|
86
85
|
"total_exclusive_time" => 0.078132088,
|
87
|
-
"traces" => []
|
88
86
|
}
|
89
87
|
]
|
90
88
|
assert_equal formatted_metrics,
|
@@ -96,7 +94,7 @@ class PayloadSerializerTest < Minitest::Test
|
|
96
94
|
:quotie => "here are some \"quotes\"",
|
97
95
|
:payload_version => 2,
|
98
96
|
}
|
99
|
-
payload = ScoutApm::Serializers::PayloadSerializerToJson.serialize(metadata, {}, {}, [], [], [], {})
|
97
|
+
payload = ScoutApm::Serializers::PayloadSerializerToJson.serialize(metadata, {}, {}, [], [], [], {}, [])
|
100
98
|
|
101
99
|
# symbol keys turn to strings
|
102
100
|
formatted_metadata = {
|
@@ -110,4 +108,40 @@ class PayloadSerializerTest < Minitest::Test
|
|
110
108
|
json = { "foo" => "\bbar\nbaz\r" }
|
111
109
|
assert_equal json, JSON.parse(ScoutApm::Serializers::PayloadSerializerToJson.jsonify_hash(json))
|
112
110
|
end
|
111
|
+
|
112
|
+
def test_escapes_escaped_quotes
|
113
|
+
# Some escapes haven't ever worked on 1.8.7, and is not the issue I'm
|
114
|
+
# fixing now. Remove this when we drop support for ancient ruby
|
115
|
+
skip if RUBY_VERSION == "1.8.7"
|
116
|
+
|
117
|
+
json = {"foo" => %q|`additional_details` = '{\"amount\":1}'|}
|
118
|
+
result = ScoutApm::Serializers::PayloadSerializerToJson.jsonify_hash(json)
|
119
|
+
assert_equal json, JSON.parse(result)
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_escapes_various_special_characters
|
123
|
+
# Some escapes haven't ever worked on 1.8.7, and is not the issue I'm
|
124
|
+
# fixing now. Remove this when we drop support for ancient ruby
|
125
|
+
skip if RUBY_VERSION == "1.8.7"
|
126
|
+
|
127
|
+
json = {"foo" => [
|
128
|
+
%Q|\fbar|,
|
129
|
+
%Q|\rbar|,
|
130
|
+
%Q|\nbar|,
|
131
|
+
%Q|\tbar|,
|
132
|
+
%Q|"bar|,
|
133
|
+
%Q|'bar|,
|
134
|
+
%Q|{bar|,
|
135
|
+
%Q|}bar|,
|
136
|
+
%Q|\\bar|,
|
137
|
+
if RUBY_VERSION == '1.8.7'
|
138
|
+
""
|
139
|
+
else
|
140
|
+
%Q|\\\nbar|
|
141
|
+
end,
|
142
|
+
]}
|
143
|
+
|
144
|
+
result = ScoutApm::Serializers::PayloadSerializerToJson.jsonify_hash(json)
|
145
|
+
assert_equal json, JSON.parse(result)
|
146
|
+
end
|
113
147
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
3
|
require 'scout_apm/slow_request_policy'
|
4
|
+
require 'scout_apm/slow_policy/policy'
|
4
5
|
require 'scout_apm/layer'
|
5
6
|
|
6
7
|
class FakeRequest
|
@@ -16,35 +17,62 @@ class FakeRequest
|
|
16
17
|
end
|
17
18
|
end
|
18
19
|
|
20
|
+
class FixedPolicy < ScoutApm::SlowPolicy::Policy
|
21
|
+
attr_reader :stored
|
22
|
+
|
23
|
+
def initialize(x)
|
24
|
+
@x = x
|
25
|
+
end
|
26
|
+
|
27
|
+
def call(req)
|
28
|
+
@x
|
29
|
+
end
|
30
|
+
|
31
|
+
def stored!(req)
|
32
|
+
@stored = true
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
19
36
|
class SlowRequestPolicyTest < Minitest::Test
|
20
37
|
def setup
|
21
38
|
@context = ScoutApm::AgentContext.new
|
22
39
|
end
|
23
40
|
|
24
|
-
def
|
41
|
+
def test_age_policy_stored_records_current_time
|
25
42
|
test_start = Time.now
|
26
|
-
policy = ScoutApm::
|
43
|
+
policy = ScoutApm::SlowPolicy::AgePolicy.new(@context)
|
27
44
|
request = FakeRequest.new("users/index")
|
28
45
|
|
29
46
|
policy.stored!(request)
|
30
47
|
assert policy.last_seen[request.unique_name] > test_start
|
31
48
|
end
|
32
49
|
|
33
|
-
def
|
50
|
+
def test_sums_up_score
|
34
51
|
policy = ScoutApm::SlowRequestPolicy.new(@context)
|
35
52
|
request = FakeRequest.new("users/index")
|
36
53
|
|
37
|
-
|
38
|
-
policy.
|
39
|
-
@context.request_histograms.add(request.unique_name, 1)
|
40
|
-
@context.transaction_time_consumed.add(request.unique_name, 1)
|
54
|
+
policy.add(FixedPolicy.new(1))
|
55
|
+
policy.add(FixedPolicy.new(2))
|
41
56
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
57
|
+
assert_equal 3, policy.score(request)
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_calls_store_on_policies
|
61
|
+
policy = ScoutApm::SlowRequestPolicy.new(@context)
|
62
|
+
request = FakeRequest.new("users/index")
|
63
|
+
|
64
|
+
policy.add(fp1 = FixedPolicy.new(1))
|
65
|
+
policy.add(fp2 = FixedPolicy.new(2))
|
66
|
+
policy.stored!(request)
|
67
|
+
|
68
|
+
assert_equal true, fp1.stored
|
69
|
+
assert_equal true, fp2.stored
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_checks_new_policy_api
|
73
|
+
policy = ScoutApm::SlowRequestPolicy.new(@context)
|
46
74
|
|
47
|
-
|
48
|
-
|
75
|
+
assert_raises { policy.add(Object.new) }
|
76
|
+
assert_raises { policy.add(->(req){1}) } # only implements call
|
49
77
|
end
|
50
78
|
end
|