scout_apm 2.5.1 → 5.3.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 +68 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +5 -5
- data/CHANGELOG.markdown +176 -3
- data/Gemfile +1 -7
- data/LICENSE.md +21 -28
- data/gems/README.md +28 -0
- data/gems/instruments.gemfile +6 -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/gems/sidekiq.gemfile +4 -0
- data/gems/typhoeus.gemfile +3 -0
- data/lib/scout_apm/agent/preconditions.rb +3 -3
- data/lib/scout_apm/agent.rb +22 -0
- data/lib/scout_apm/agent_context.rb +21 -2
- data/lib/scout_apm/app_server_load.rb +7 -2
- 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 +174 -0
- data/lib/scout_apm/auto_instrument.rb +5 -0
- data/lib/scout_apm/background_job_integrations/delayed_job.rb +1 -1
- data/lib/scout_apm/background_job_integrations/faktory.rb +103 -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/shoryuken.rb +2 -0
- data/lib/scout_apm/background_job_integrations/sidekiq.rb +15 -10
- data/lib/scout_apm/background_job_integrations/sneakers.rb +11 -11
- data/lib/scout_apm/config.rb +54 -6
- data/lib/scout_apm/detailed_trace.rb +3 -2
- data/lib/scout_apm/environment.rb +18 -1
- data/lib/scout_apm/error.rb +27 -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/error_service.rb +34 -0
- data/lib/scout_apm/exceptions.rb +12 -0
- data/lib/scout_apm/extensions/transaction_callback_payload.rb +1 -1
- data/lib/scout_apm/external_service_metric_set.rb +97 -0
- data/lib/scout_apm/external_service_metric_stats.rb +85 -0
- data/lib/scout_apm/fake_store.rb +3 -0
- data/lib/scout_apm/framework_integrations/rails_3_or_4.rb +7 -2
- data/lib/scout_apm/git_revision.rb +9 -0
- data/lib/scout_apm/ignored_uris.rb +3 -1
- data/lib/scout_apm/instant/middleware.rb +4 -1
- data/lib/scout_apm/instrument_manager.rb +22 -1
- data/lib/scout_apm/instruments/action_controller_rails_2.rb +1 -1
- data/lib/scout_apm/instruments/action_controller_rails_3_rails4.rb +53 -29
- data/lib/scout_apm/instruments/action_view.rb +30 -9
- data/lib/scout_apm/instruments/active_record.rb +69 -19
- data/lib/scout_apm/instruments/elasticsearch.rb +93 -42
- data/lib/scout_apm/instruments/grape.rb +1 -1
- data/lib/scout_apm/instruments/http.rb +68 -0
- data/lib/scout_apm/instruments/http_client.rb +33 -14
- data/lib/scout_apm/instruments/influxdb.rb +2 -2
- data/lib/scout_apm/instruments/memcached.rb +58 -0
- data/lib/scout_apm/instruments/middleware_detailed.rb +1 -1
- data/lib/scout_apm/instruments/middleware_summary.rb +1 -1
- data/lib/scout_apm/instruments/mongoid.rb +10 -5
- data/lib/scout_apm/instruments/moped.rb +44 -19
- data/lib/scout_apm/instruments/net_http.rb +51 -16
- data/lib/scout_apm/instruments/rails_router.rb +1 -1
- data/lib/scout_apm/instruments/redis.rb +27 -12
- data/lib/scout_apm/instruments/redis5.rb +59 -0
- data/lib/scout_apm/instruments/sinatra.rb +3 -1
- data/lib/scout_apm/instruments/typhoeus.rb +90 -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 +5 -2
- data/lib/scout_apm/layer_children_set.rb +9 -8
- data/lib/scout_apm/layer_converters/external_service_converter.rb +65 -0
- data/lib/scout_apm/layer_converters/find_layer_by_type.rb +4 -0
- data/lib/scout_apm/layer_converters/request_queue_time_converter.rb +2 -0
- data/lib/scout_apm/layer_converters/trace_converter.rb +7 -4
- data/lib/scout_apm/logger.rb +5 -1
- 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/external_service_serializer_to_json.rb +15 -0
- data/lib/scout_apm/serializers/payload_serializer.rb +4 -3
- data/lib/scout_apm/serializers/payload_serializer_to_json.rb +10 -3
- 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/store.rb +31 -1
- data/lib/scout_apm/tracer.rb +2 -2
- data/lib/scout_apm/tracked_request.rb +35 -4
- 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 +47 -7
- data/lib/scout_apm/version.rb +1 -1
- data/lib/scout_apm.rb +46 -1
- data/scout_apm.gemspec +14 -9
- data/test/test_helper.rb +2 -2
- data/test/tmp/README.md +17 -0
- data/test/unit/agent_context_test.rb +29 -0
- data/test/unit/auto_instrument/anonymous_block_value.rb +7 -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/hanging_method.rb +6 -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 +62 -0
- data/test/unit/background_job_integrations/sidekiq_test.rb +17 -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/external_service_metric_set_test.rb +67 -0
- data/test/unit/external_service_metric_stats_test.rb +106 -0
- data/test/unit/ignored_uris_test.rb +6 -0
- data/test/unit/instruments/active_record_test.rb +40 -0
- data/test/unit/instruments/http_client_test.rb +24 -0
- data/test/unit/instruments/http_test.rb +24 -0
- data/test/unit/instruments/moped_test.rb +24 -0
- data/test/unit/instruments/net_http_test.rb +11 -1
- data/test/unit/instruments/redis_test.rb +24 -0
- data/test/unit/instruments/typhoeus_test.rb +42 -0
- data/test/unit/layer_children_set_test.rb +9 -0
- data/test/unit/remote/{test_message.rb → message_test.rb} +0 -0
- data/test/unit/remote/{test_router.rb → route_test.rb} +0 -0
- data/test/unit/remote/{test_server.rb → server_test.rb} +4 -1
- data/test/unit/request_histograms_test.rb +17 -0
- data/test/unit/serializers/payload_serializer_test.rb +39 -3
- data/test/unit/slow_request_policy_test.rb +41 -13
- data/test/unit/sql_sanitizer_test.rb +106 -0
- data/test/unit/tracer_test.rb +25 -0
- metadata +118 -60
- data/.travis.yml +0 -25
- data/lib/scout_apm/instruments/.DS_Store +0 -0
- data/lib/scout_apm/slow_job_policy.rb +0 -111
- data/lib/scout_apm/utils/sql_sanitizer_regex.rb +0 -25
- data/lib/scout_apm/utils/sql_sanitizer_regex_1_8_7.rb +0 -26
- data/test/unit/instruments/active_record_instruments_test.rb +0 -5
- data/test/unit/slow_job_policy_test.rb +0 -6
@@ -0,0 +1,90 @@
|
|
1
|
+
module ScoutApm
|
2
|
+
module Utils
|
3
|
+
class Error < StandardError; end
|
4
|
+
|
5
|
+
class InstanceVar
|
6
|
+
attr_reader :name
|
7
|
+
attr_reader :obj
|
8
|
+
|
9
|
+
def initialize(name, obj, parent)
|
10
|
+
@name = name
|
11
|
+
@obj = obj
|
12
|
+
@parent = parent
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
"#{@name} - #{obj.class}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def history
|
20
|
+
(@parent.nil? ? [] : @parent.history) + [to_s]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class MarshalLogging
|
25
|
+
def initialize(base_obj)
|
26
|
+
@base_obj = base_obj
|
27
|
+
end
|
28
|
+
|
29
|
+
def dive
|
30
|
+
to_investigate = [InstanceVar.new('Root', @base_obj, nil)]
|
31
|
+
max_to_check = 10000
|
32
|
+
checked = 0
|
33
|
+
|
34
|
+
while (var = to_investigate.shift)
|
35
|
+
checked += 1
|
36
|
+
if checked > max_to_check
|
37
|
+
return "Limiting Checks (max = #{max_to_check})"
|
38
|
+
end
|
39
|
+
|
40
|
+
obj = var.obj
|
41
|
+
|
42
|
+
if offending_hash?(obj)
|
43
|
+
return "Found undumpable object: #{var.history}"
|
44
|
+
end
|
45
|
+
|
46
|
+
if !dumps?(obj)
|
47
|
+
if obj.is_a? Hash
|
48
|
+
keys = obj.keys
|
49
|
+
keys.each do |key|
|
50
|
+
to_investigate.push(
|
51
|
+
InstanceVar.new(key.to_s, obj[key], var)
|
52
|
+
)
|
53
|
+
end
|
54
|
+
elsif obj.is_a? Array
|
55
|
+
obj.each_with_index do |value, idx|
|
56
|
+
to_investigate.push(
|
57
|
+
InstanceVar.new("Index #{idx}", value, var)
|
58
|
+
)
|
59
|
+
end
|
60
|
+
else
|
61
|
+
symbols = obj.instance_variables
|
62
|
+
if !symbols.any?
|
63
|
+
return "Found undumpable object: #{var.history}"
|
64
|
+
end
|
65
|
+
|
66
|
+
symbols.each do |sym|
|
67
|
+
to_investigate.push(
|
68
|
+
InstanceVar.new(sym, obj.instance_variable_get(sym), var)
|
69
|
+
)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
true
|
76
|
+
end
|
77
|
+
|
78
|
+
def dumps?(obj)
|
79
|
+
Marshal.dump(obj)
|
80
|
+
true
|
81
|
+
rescue TypeError
|
82
|
+
false
|
83
|
+
end
|
84
|
+
|
85
|
+
def offending_hash?(obj)
|
86
|
+
obj.is_a?(Hash) && !obj.default_proc.nil?
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
|
1
3
|
require 'scout_apm/environment'
|
2
4
|
|
3
5
|
# Removes actual values from SQL. Used to both obfuscate the SQL and group
|
@@ -5,12 +7,37 @@ require 'scout_apm/environment'
|
|
5
7
|
module ScoutApm
|
6
8
|
module Utils
|
7
9
|
class SqlSanitizer
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
MULTIPLE_SPACES = %r|\s+|.freeze
|
11
|
+
MULTIPLE_QUESTIONS = /\?(,\?)+/.freeze
|
12
|
+
|
13
|
+
PSQL_VAR_INTERPOLATION = %r|\[\[.*\]\]\s*\z|.freeze
|
14
|
+
PSQL_REMOVE_STRINGS = /'(?:[^']|'')*'/.freeze
|
15
|
+
PSQL_REMOVE_JSON_STRINGS = /:"(?:[^"]|"")*"/.freeze
|
16
|
+
PSQL_REMOVE_INTEGERS = /(?<!LIMIT )\b\d+\b/.freeze
|
17
|
+
PSQL_AFTER_SELECT = /(?:SELECT\s+).*?(?:WHERE|FROM\z)/im.freeze # Should be everything between a FROM and a WHERE
|
18
|
+
PSQL_PLACEHOLDER = /\$\d+/.freeze
|
19
|
+
PSQL_IN_CLAUSE = /IN\s+\(\?[^\)]*\)/.freeze
|
20
|
+
PSQL_AFTER_FROM = /(?:FROM\s+).*?(?:WHERE|\z)/im.freeze # Should be everything between a FROM and a WHERE
|
21
|
+
PSQL_AFTER_FROM_AS = /(?:FROM\s+).*?(?:AS|\z)/im.freeze # Should be everything between a FROM and AS without WHERE
|
22
|
+
PSQL_AFTER_JOIN = /(?:JOIN\s+).*?\z/im.freeze
|
23
|
+
PSQL_AFTER_WHERE = /(?:WHERE\s+).*?(?:SELECT|\z)/im.freeze
|
24
|
+
PSQL_AFTER_SET = /(?:SET\s+).*?(?:WHERE|\z)/im.freeze
|
25
|
+
|
26
|
+
MYSQL_VAR_INTERPOLATION = %r|\[\[.*\]\]\s*$|.freeze
|
27
|
+
MYSQL_REMOVE_INTEGERS = /(?<!LIMIT )\b\d+\b/.freeze
|
28
|
+
MYSQL_REMOVE_SINGLE_QUOTE_STRINGS = %r{'(?:\\'|[^']|'')*'}.freeze
|
29
|
+
MYSQL_REMOVE_DOUBLE_QUOTE_STRINGS = %r{"(?:\\"|[^"]|"")*"}.freeze
|
30
|
+
MYSQL_IN_CLAUSE = /IN\s+\(\?[^\)]*\)/.freeze
|
31
|
+
|
32
|
+
SQLITE_VAR_INTERPOLATION = %r|\[\[.*\]\]\s*$|.freeze
|
33
|
+
SQLITE_REMOVE_STRINGS = /'(?:[^']|'')*'/.freeze
|
34
|
+
SQLITE_REMOVE_INTEGERS = /(?<!LIMIT )\b\d+\b/.freeze
|
35
|
+
|
36
|
+
# => "EXEC sp_executesql N'SELECT [users].* FROM [users] WHERE (age > 50) ORDER BY [users].[id] ASC OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY', N'@0 int', @0 = 10"
|
37
|
+
SQLSERVER_REMOVE_EXECUTESQL = /EXEC sp_executesql (N')?/.freeze
|
38
|
+
SQLSERVER_REMOVE_STRINGS = /'(?:[^']|'')*'/.freeze
|
39
|
+
SQLSERVER_REMOVE_INTEGERS = /(?<!LIMIT )\b(?<!@)\d+\b/.freeze
|
40
|
+
SQLSERVER_IN_CLAUSE = /IN\s+\(\?[^\)]*\)/.freeze
|
14
41
|
|
15
42
|
attr_accessor :database_engine
|
16
43
|
|
@@ -34,15 +61,28 @@ module ScoutApm
|
|
34
61
|
when :postgres then to_s_postgres
|
35
62
|
when :mysql then to_s_mysql
|
36
63
|
when :sqlite then to_s_sqlite
|
64
|
+
when :sqlserver then to_s_sqlserver
|
37
65
|
end
|
38
66
|
end
|
39
67
|
|
40
68
|
private
|
41
69
|
|
70
|
+
def to_s_sqlserver
|
71
|
+
sql.gsub!(SQLSERVER_REMOVE_EXECUTESQL, '')
|
72
|
+
sql.gsub!(SQLSERVER_REMOVE_STRINGS, '?')
|
73
|
+
sql.gsub!(SQLSERVER_REMOVE_INTEGERS, '?')
|
74
|
+
sql.gsub!(SQLSERVER_IN_CLAUSE, 'IN (?)')
|
75
|
+
sql
|
76
|
+
end
|
77
|
+
|
42
78
|
def to_s_postgres
|
43
79
|
sql.gsub!(PSQL_PLACEHOLDER, '?')
|
44
80
|
sql.gsub!(PSQL_VAR_INTERPOLATION, '')
|
45
|
-
sql.gsub!(PSQL_REMOVE_STRINGS, '?')
|
81
|
+
# sql.gsub!(PSQL_REMOVE_STRINGS, '?')
|
82
|
+
sql.gsub!(PSQL_AFTER_WHERE) {|c| c.gsub(PSQL_REMOVE_STRINGS, '?')}
|
83
|
+
sql.gsub!(PSQL_AFTER_FROM_AS) {|c| c.gsub(PSQL_REMOVE_JSON_STRINGS, ':"?"')}
|
84
|
+
sql.gsub!(PSQL_AFTER_JOIN) {|c| c.gsub(PSQL_REMOVE_STRINGS, '?')}
|
85
|
+
sql.gsub!(PSQL_AFTER_SET) {|c| c.gsub(PSQL_REMOVE_STRINGS, '?')}
|
46
86
|
sql.gsub!(PSQL_REMOVE_INTEGERS, '?')
|
47
87
|
sql.gsub!(PSQL_IN_CLAUSE, 'IN (?)')
|
48
88
|
sql.gsub!(MULTIPLE_SPACES, ' ')
|
data/lib/scout_apm/version.rb
CHANGED
data/lib/scout_apm.rb
CHANGED
@@ -27,6 +27,7 @@ require 'rusage'
|
|
27
27
|
#####################################
|
28
28
|
require 'scout_apm/version'
|
29
29
|
|
30
|
+
require 'scout_apm/exceptions'
|
30
31
|
require 'scout_apm/debug'
|
31
32
|
require 'scout_apm/tracked_request'
|
32
33
|
require 'scout_apm/layer'
|
@@ -42,6 +43,7 @@ require 'scout_apm/layer_converters/job_converter'
|
|
42
43
|
require 'scout_apm/layer_converters/slow_job_converter'
|
43
44
|
require 'scout_apm/layer_converters/metric_converter'
|
44
45
|
require 'scout_apm/layer_converters/database_converter'
|
46
|
+
require 'scout_apm/layer_converters/external_service_converter'
|
45
47
|
require 'scout_apm/layer_converters/slow_request_converter'
|
46
48
|
require 'scout_apm/layer_converters/request_queue_time_converter'
|
47
49
|
require 'scout_apm/layer_converters/allocation_metric_converter'
|
@@ -58,10 +60,13 @@ require 'scout_apm/server_integrations/webrick'
|
|
58
60
|
require 'scout_apm/server_integrations/null'
|
59
61
|
|
60
62
|
require 'scout_apm/background_job_integrations/sidekiq'
|
63
|
+
require 'scout_apm/background_job_integrations/faktory'
|
61
64
|
require 'scout_apm/background_job_integrations/delayed_job'
|
62
65
|
require 'scout_apm/background_job_integrations/resque'
|
63
66
|
require 'scout_apm/background_job_integrations/shoryuken'
|
64
67
|
require 'scout_apm/background_job_integrations/sneakers'
|
68
|
+
require 'scout_apm/background_job_integrations/que'
|
69
|
+
require 'scout_apm/background_job_integrations/legacy_sneakers'
|
65
70
|
|
66
71
|
require 'scout_apm/framework_integrations/rails_2'
|
67
72
|
require 'scout_apm/framework_integrations/rails_3_or_4'
|
@@ -76,9 +81,13 @@ require 'scout_apm/histogram'
|
|
76
81
|
|
77
82
|
require 'scout_apm/instruments/net_http'
|
78
83
|
require 'scout_apm/instruments/http_client'
|
84
|
+
require 'scout_apm/instruments/http'
|
85
|
+
require 'scout_apm/instruments/typhoeus'
|
79
86
|
require 'scout_apm/instruments/moped'
|
80
87
|
require 'scout_apm/instruments/mongoid'
|
88
|
+
require 'scout_apm/instruments/memcached'
|
81
89
|
require 'scout_apm/instruments/redis'
|
90
|
+
require 'scout_apm/instruments/redis5'
|
82
91
|
require 'scout_apm/instruments/influxdb'
|
83
92
|
require 'scout_apm/instruments/elasticsearch'
|
84
93
|
require 'scout_apm/instruments/active_record'
|
@@ -110,6 +119,7 @@ require 'scout_apm/utils/time'
|
|
110
119
|
require 'scout_apm/utils/unique_id'
|
111
120
|
require 'scout_apm/utils/numbers'
|
112
121
|
require 'scout_apm/utils/gzip_helper'
|
122
|
+
require 'scout_apm/utils/marshal_logging'
|
113
123
|
|
114
124
|
require 'scout_apm/config'
|
115
125
|
require 'scout_apm/environment'
|
@@ -124,6 +134,7 @@ require 'scout_apm/bucket_name_splitter'
|
|
124
134
|
require 'scout_apm/stack_item'
|
125
135
|
require 'scout_apm/metric_set'
|
126
136
|
require 'scout_apm/db_query_metric_set'
|
137
|
+
require 'scout_apm/external_service_metric_set'
|
127
138
|
require 'scout_apm/store'
|
128
139
|
require 'scout_apm/fake_store'
|
129
140
|
require 'scout_apm/tracer'
|
@@ -136,12 +147,18 @@ require 'scout_apm/synchronous_recorder'
|
|
136
147
|
require 'scout_apm/metric_meta'
|
137
148
|
require 'scout_apm/metric_stats'
|
138
149
|
require 'scout_apm/db_query_metric_stats'
|
150
|
+
require 'scout_apm/external_service_metric_stats'
|
139
151
|
require 'scout_apm/slow_transaction'
|
140
152
|
require 'scout_apm/slow_job_record'
|
141
153
|
require 'scout_apm/detailed_trace'
|
142
154
|
require 'scout_apm/scored_item_set'
|
155
|
+
|
143
156
|
require 'scout_apm/slow_request_policy'
|
144
|
-
require 'scout_apm/
|
157
|
+
require 'scout_apm/slow_policy/age_policy'
|
158
|
+
require 'scout_apm/slow_policy/speed_policy'
|
159
|
+
require 'scout_apm/slow_policy/percent_policy'
|
160
|
+
require 'scout_apm/slow_policy/percentile_policy'
|
161
|
+
|
145
162
|
require 'scout_apm/job_record'
|
146
163
|
require 'scout_apm/request_histograms'
|
147
164
|
require 'scout_apm/transaction_time_consumed'
|
@@ -156,6 +173,7 @@ require 'scout_apm/serializers/slow_jobs_serializer_to_json'
|
|
156
173
|
require 'scout_apm/serializers/metrics_to_json_serializer'
|
157
174
|
require 'scout_apm/serializers/histograms_serializer_to_json'
|
158
175
|
require 'scout_apm/serializers/db_query_serializer_to_json'
|
176
|
+
require 'scout_apm/serializers/external_service_serializer_to_json'
|
159
177
|
require 'scout_apm/serializers/directive_serializer'
|
160
178
|
require 'scout_apm/serializers/app_server_load_serializer'
|
161
179
|
|
@@ -182,6 +200,17 @@ require 'scout_apm/tasks/support'
|
|
182
200
|
require 'scout_apm/extensions/config'
|
183
201
|
require 'scout_apm/extensions/transaction_callback_payload'
|
184
202
|
|
203
|
+
require 'scout_apm/error'
|
204
|
+
require 'scout_apm/error_service'
|
205
|
+
require 'scout_apm/error_service/middleware'
|
206
|
+
require 'scout_apm/error_service/notifier'
|
207
|
+
require 'scout_apm/error_service/sidekiq'
|
208
|
+
require 'scout_apm/error_service/ignored_exceptions'
|
209
|
+
require 'scout_apm/error_service/error_buffer'
|
210
|
+
require 'scout_apm/error_service/error_record'
|
211
|
+
require 'scout_apm/error_service/periodic_work'
|
212
|
+
require 'scout_apm/error_service/payload'
|
213
|
+
|
185
214
|
if defined?(Rails) && defined?(Rails::VERSION) && defined?(Rails::VERSION::MAJOR) && Rails::VERSION::MAJOR >= 3 && defined?(Rails::Railtie)
|
186
215
|
module ScoutApm
|
187
216
|
class Railtie < Rails::Railtie
|
@@ -194,6 +223,22 @@ if defined?(Rails) && defined?(Rails::VERSION) && defined?(Rails::VERSION::MAJOR
|
|
194
223
|
# Attempt to start right away, this will work best for preloading apps, Unicorn & Puma & similar
|
195
224
|
ScoutApm::Agent.instance.install
|
196
225
|
|
226
|
+
if ScoutApm::Agent.instance.context.config.value("auto_instruments")
|
227
|
+
if defined?(Parser::TreeRewriter)
|
228
|
+
ScoutApm::Agent.instance.context.logger.debug("AutoInstruments is enabled.")
|
229
|
+
require 'scout_apm/auto_instrument'
|
230
|
+
else # AutoInstruments is turned on, but we don't he the prerequisites to use it
|
231
|
+
ScoutApm::Agent.instance.context.logger.debug("AutoInstruments is enabled, but Parser::TreeRewriter is missing. Update 'parser' gem to >= 2.5.0.")
|
232
|
+
end
|
233
|
+
else
|
234
|
+
ScoutApm::Agent.instance.context.logger.debug("AutoInstruments is disabled.")
|
235
|
+
end
|
236
|
+
|
237
|
+
if ScoutApm::Agent.instance.context.config.value("errors_enabled")
|
238
|
+
app.config.middleware.insert_after ActionDispatch::DebugExceptions, ScoutApm::ErrorService::Middleware
|
239
|
+
ScoutApm::ErrorService::Sidekiq.new.install
|
240
|
+
end
|
241
|
+
|
197
242
|
# Install the middleware every time in development mode.
|
198
243
|
# The middleware is a noop if dev_trace is not enabled in config
|
199
244
|
if Rails.env.development?
|
data/scout_apm.gemspec
CHANGED
@@ -10,9 +10,7 @@ Gem::Specification.new do |s|
|
|
10
10
|
s.homepage = "https://github.com/scoutapp/scout_apm_ruby"
|
11
11
|
s.summary = "Ruby application performance monitoring"
|
12
12
|
s.description = "Monitors Ruby apps and reports detailed metrics on performance to Scout."
|
13
|
-
s.license = "
|
14
|
-
|
15
|
-
s.rubyforge_project = "scout_apm"
|
13
|
+
s.license = "MIT"
|
16
14
|
|
17
15
|
s.files = `git ls-files`.split("\n")
|
18
16
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
@@ -21,6 +19,8 @@ Gem::Specification.new do |s|
|
|
21
19
|
s.extensions << 'ext/allocations/extconf.rb'
|
22
20
|
s.extensions << 'ext/rusage/extconf.rb'
|
23
21
|
|
22
|
+
s.required_ruby_version = '>= 2.1'
|
23
|
+
|
24
24
|
s.add_development_dependency "minitest"
|
25
25
|
s.add_development_dependency "mocha"
|
26
26
|
s.add_development_dependency "pry"
|
@@ -28,11 +28,16 @@ Gem::Specification.new do |s|
|
|
28
28
|
s.add_development_dependency "rake-compiler"
|
29
29
|
s.add_development_dependency "addressable"
|
30
30
|
s.add_development_dependency "activesupport"
|
31
|
+
s.add_runtime_dependency "parser"
|
32
|
+
|
33
|
+
# These are general development dependencies which are used in instrumentation
|
34
|
+
# tests. Specific versions are pulled in using specific gemfiles, e.g.
|
35
|
+
# `gems/rails3.gemfile`.
|
36
|
+
s.add_development_dependency "activerecord"
|
37
|
+
s.add_development_dependency "sqlite3"
|
31
38
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
s.add_development_dependency "m"
|
37
|
-
end
|
39
|
+
s.add_development_dependency "rubocop"
|
40
|
+
s.add_development_dependency "guard"
|
41
|
+
s.add_development_dependency "guard-minitest"
|
42
|
+
s.add_development_dependency "m"
|
38
43
|
end
|
data/test/test_helper.rb
CHANGED
@@ -5,7 +5,7 @@ SimpleCov.start
|
|
5
5
|
require 'minitest/autorun'
|
6
6
|
require 'minitest/unit'
|
7
7
|
require 'minitest/pride'
|
8
|
-
require 'mocha/
|
8
|
+
require 'mocha/minitest'
|
9
9
|
require 'pry'
|
10
10
|
|
11
11
|
|
@@ -100,7 +100,7 @@ class Minitest::Test
|
|
100
100
|
end
|
101
101
|
|
102
102
|
def agent_context
|
103
|
-
ScoutApm::
|
103
|
+
ScoutApm::Agent.instance.context
|
104
104
|
end
|
105
105
|
|
106
106
|
DATA_FILE_DIR = File.dirname(__FILE__) + '/tmp'
|
data/test/tmp/README.md
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# Temporary Data
|
2
|
+
|
3
|
+
Use this directory for temporary test files.
|
4
|
+
|
5
|
+
## Usage
|
6
|
+
|
7
|
+
The `DATA_FILE_DIR` constant points at this directory:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
class MyTest < Minitest::Test
|
11
|
+
def database_path
|
12
|
+
File.expand_path('test.sqlite3', DATA_FILE_DIR)
|
13
|
+
end
|
14
|
+
|
15
|
+
# ... tests
|
16
|
+
end
|
17
|
+
```
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
require "scout_apm/agent_context"
|
4
|
+
|
5
|
+
class AgentContextTest < Minitest::Test
|
6
|
+
def test_has_error_service_ignored_exceptions
|
7
|
+
context = ScoutApm::AgentContext.new
|
8
|
+
assert ScoutApm::ErrorService::IgnoredExceptions, context.ignored_exceptions.class
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_has_error_buffer
|
12
|
+
context = ScoutApm::AgentContext.new
|
13
|
+
assert ScoutApm::ErrorService::ErrorBuffer, context.error_buffer.class
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
class TestPolicy
|
18
|
+
def call(req); 1; end
|
19
|
+
def stored!(req); end
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_customize_slow_request_policy
|
23
|
+
context = ScoutApm::AgentContext.new
|
24
|
+
assert 4, context.slow_request_policy.policies
|
25
|
+
|
26
|
+
context.slow_request_policy.add(TestPolicy.new)
|
27
|
+
assert 5, context.slow_request_policy.policies
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
|
2
|
+
class Assignments
|
3
|
+
def test_op_asgn
|
4
|
+
foo.bar += ::ScoutApm::AutoInstrument("User.size",["ROOT/test/unit/auto_instrument/assignments.rb:4:in `test_op_asgn'"]){User.size}
|
5
|
+
foo.bar -= ::ScoutApm::AutoInstrument("User.size",["ROOT/test/unit/auto_instrument/assignments.rb:5:in `test_op_asgn'"]){User.size}
|
6
|
+
end
|
7
|
+
|
8
|
+
def nested_assignment
|
9
|
+
@email ||= if (email = ::ScoutApm::AutoInstrument("session[\"email\"]",["ROOT/test/unit/auto_instrument/assignments.rb:9:in `nested_assignment'"]){session["email"]}).present?
|
10
|
+
::ScoutApm::AutoInstrument("User.where(email: email).first",["ROOT/test/unit/auto_instrument/assignments.rb:10:in `nested_assignment'"]){User.where(email: email).first}
|
11
|
+
else
|
12
|
+
nil
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def paginate_collection(coll)
|
17
|
+
page = (::ScoutApm::AutoInstrument("params[:page].present?",["ROOT/test/unit/auto_instrument/assignments.rb:17:in `paginate_collection'"]){params[:page].present?} ? ::ScoutApm::AutoInstrument("params[:page].to_i",["ROOT/test/unit/auto_instrument/assignments.rb:17:in `paginate_collection'"]){params[:page].to_i} : 1)
|
18
|
+
per_page = (::ScoutApm::AutoInstrument("params[:per_page].present?",["ROOT/test/unit/auto_instrument/assignments.rb:18:in `paginate_collection'"]){params[:per_page].present?} ? ::ScoutApm::AutoInstrument("params[:per_page].to_i",["ROOT/test/unit/auto_instrument/assignments.rb:18:in `paginate_collection'"]){params[:per_page].to_i} : 20)
|
19
|
+
pagination, self.collection = ::ScoutApm::AutoInstrument("pagy(...",["ROOT/test/unit/auto_instrument/assignments.rb:19:in `paginate_collection'"]){pagy(
|
20
|
+
coll,
|
21
|
+
items: per_page,
|
22
|
+
page: page
|
23
|
+
)}
|
24
|
+
::ScoutApm::AutoInstrument("headers[PAGINATION_TOTAL_HEADER] = pagination.count.to_s",["ROOT/test/unit/auto_instrument/assignments.rb:24:in `paginate_collection'"]){headers[PAGINATION_TOTAL_HEADER] = pagination.count.to_s}
|
25
|
+
::ScoutApm::AutoInstrument("headers[PAGINATION_TOTAL_PAGES_HEADER] = pagination.pages.to_s",["ROOT/test/unit/auto_instrument/assignments.rb:25:in `paginate_collection'"]){headers[PAGINATION_TOTAL_PAGES_HEADER] = pagination.pages.to_s}
|
26
|
+
::ScoutApm::AutoInstrument("headers[PAGINATION_PER_PAGE_HEADER] = per_page.to_s",["ROOT/test/unit/auto_instrument/assignments.rb:26:in `paginate_collection'"]){headers[PAGINATION_PER_PAGE_HEADER] = per_page.to_s}
|
27
|
+
::ScoutApm::AutoInstrument("headers[PAGINATION_PAGE_HEADER] = pagination.page.to_s",["ROOT/test/unit/auto_instrument/assignments.rb:27:in `paginate_collection'"]){headers[PAGINATION_PAGE_HEADER] = pagination.page.to_s}
|
28
|
+
::ScoutApm::AutoInstrument("headers[PAGINATION_NEXT_PAGE_HEADER] = pagination.next.to_s",["ROOT/test/unit/auto_instrument/assignments.rb:28:in `paginate_collection'"]){headers[PAGINATION_NEXT_PAGE_HEADER] = pagination.next.to_s}
|
29
|
+
::ScoutApm::AutoInstrument("collection",["ROOT/test/unit/auto_instrument/assignments.rb:29:in `paginate_collection'"]){collection}
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
|
2
|
+
class Assignments
|
3
|
+
def test_op_asgn
|
4
|
+
foo.bar += User.size
|
5
|
+
foo.bar -= User.size
|
6
|
+
end
|
7
|
+
|
8
|
+
def nested_assignment
|
9
|
+
@email ||= if (email = session["email"]).present?
|
10
|
+
User.where(email: email).first
|
11
|
+
else
|
12
|
+
nil
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def paginate_collection(coll)
|
17
|
+
page = (params[:page].present? ? params[:page].to_i : 1)
|
18
|
+
per_page = (params[:per_page].present? ? params[:per_page].to_i : 20)
|
19
|
+
pagination, self.collection = pagy(
|
20
|
+
coll,
|
21
|
+
items: per_page,
|
22
|
+
page: page
|
23
|
+
)
|
24
|
+
headers[PAGINATION_TOTAL_HEADER] = pagination.count.to_s
|
25
|
+
headers[PAGINATION_TOTAL_PAGES_HEADER] = pagination.pages.to_s
|
26
|
+
headers[PAGINATION_PER_PAGE_HEADER] = per_page.to_s
|
27
|
+
headers[PAGINATION_PAGE_HEADER] = pagination.page.to_s
|
28
|
+
headers[PAGINATION_NEXT_PAGE_HEADER] = pagination.next.to_s
|
29
|
+
collection
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
s(:class,
|
2
|
+
s(:const, nil, :ClientsController),
|
3
|
+
s(:const, nil, :ApplicationController),
|
4
|
+
s(:begin,
|
5
|
+
s(:send, nil, :before_action,
|
6
|
+
s(:sym, :check_authorization)),
|
7
|
+
s(:def, :index,
|
8
|
+
s(:args),
|
9
|
+
s(:if,
|
10
|
+
s(:send,
|
11
|
+
s(:send,
|
12
|
+
s(:send, nil, :params), :[],
|
13
|
+
s(:sym, :status)), :==,
|
14
|
+
s(:str, "activated")),
|
15
|
+
s(:ivasgn, :@clients,
|
16
|
+
s(:send,
|
17
|
+
s(:const, nil, :Client), :activated)),
|
18
|
+
s(:ivasgn, :@clients,
|
19
|
+
s(:send,
|
20
|
+
s(:const, nil, :Client), :inactivated)))),
|
21
|
+
s(:def, :create,
|
22
|
+
s(:args),
|
23
|
+
s(:begin,
|
24
|
+
s(:ivasgn, :@client,
|
25
|
+
s(:send,
|
26
|
+
s(:const, nil, :Client), :new,
|
27
|
+
s(:send,
|
28
|
+
s(:send, nil, :params), :[],
|
29
|
+
s(:sym, :client)))),
|
30
|
+
s(:if,
|
31
|
+
s(:send,
|
32
|
+
s(:ivar, :@client), :save),
|
33
|
+
s(:send, nil, :redirect_to,
|
34
|
+
s(:ivar, :@client)),
|
35
|
+
s(:send, nil, :render,
|
36
|
+
s(:str, "new"))))),
|
37
|
+
s(:def, :edit,
|
38
|
+
s(:args),
|
39
|
+
s(:begin,
|
40
|
+
s(:ivasgn, :@client,
|
41
|
+
s(:send,
|
42
|
+
s(:const, nil, :Client), :new,
|
43
|
+
s(:send,
|
44
|
+
s(:send, nil, :params), :[],
|
45
|
+
s(:sym, :client)))),
|
46
|
+
s(:if,
|
47
|
+
s(:send,
|
48
|
+
s(:send, nil, :request), :post?),
|
49
|
+
s(:block,
|
50
|
+
s(:send,
|
51
|
+
s(:ivar, :@client), :transaction),
|
52
|
+
s(:args),
|
53
|
+
s(:send,
|
54
|
+
s(:ivar, :@client), :update_attributes,
|
55
|
+
s(:send,
|
56
|
+
s(:send, nil, :params), :[],
|
57
|
+
s(:sym, :client)))), nil)))))
|
@@ -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
|