scout_apm 3.0.0.pre25 → 4.0.1
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 +148 -4
- data/Gemfile +1 -7
- data/README.markdown +30 -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 +38 -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 +17 -6
- 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 +8 -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 +70 -19
- 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/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 +15 -6
- 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 -63
- 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
data/lib/scout_apm/config.rb
CHANGED
@@ -6,10 +6,11 @@ require 'scout_apm/environment'
|
|
6
6
|
# Valid Config Options:
|
7
7
|
#
|
8
8
|
# This list is complete, but some are old and unused, or for developers of
|
9
|
-
# scout_apm itself. See the documentation at
|
9
|
+
# scout_apm itself. See the documentation at https://docs.scoutapm.com for
|
10
10
|
# customer-focused documentation.
|
11
11
|
#
|
12
12
|
# application_root - override the detected directory of the application
|
13
|
+
# collect_remote_ip - automatically capture user's IP into a Trace's Context
|
13
14
|
# compress_payload - true/false to enable gzipping of payload
|
14
15
|
# data_file - override the default temporary storage location. Must be a location in a writable directory
|
15
16
|
# dev_trace - true or false. Enables always-on tracing in development environmen only
|
@@ -30,6 +31,10 @@ require 'scout_apm/environment'
|
|
30
31
|
# uri_reporting - 'path' or 'full_path' default is 'full_path', which reports URL params as well as the path.
|
31
32
|
# remote_agent_host - Internal: What host to bind to, and also send messages to for remote. Default: 127.0.0.1.
|
32
33
|
# remote_agent_port - What port to bind the remote webserver to
|
34
|
+
# start_resque_server_instrument - Used in special situations with certain Resque installs
|
35
|
+
# timeline_traces - true/false to enable sending of of the timeline trace format.
|
36
|
+
# auto_instruments - true/false whether to install autoinstruments. Only installed if on a supported Ruby version.
|
37
|
+
# auto_instruments_ignore - An array of file names to exclude from autoinstruments (Ex: ['application_controller']).
|
33
38
|
#
|
34
39
|
# Any of these config settings can be set with an environment variable prefixed
|
35
40
|
# by SCOUT_ and uppercasing the key: SCOUT_LOG_LEVEL for instance.
|
@@ -39,6 +44,7 @@ module ScoutApm
|
|
39
44
|
KNOWN_CONFIG_OPTIONS = [
|
40
45
|
'application_root',
|
41
46
|
'async_recording',
|
47
|
+
'collect_remote_ip',
|
42
48
|
'compress_payload',
|
43
49
|
'config_file',
|
44
50
|
'data_file',
|
@@ -66,9 +72,21 @@ module ScoutApm
|
|
66
72
|
'remote_agent_host',
|
67
73
|
'remote_agent_port',
|
68
74
|
'report_format',
|
75
|
+
'revision_sha',
|
69
76
|
'scm_subdirectory',
|
77
|
+
'start_resque_server_instrument',
|
78
|
+
'ssl_cert_file',
|
70
79
|
'uri_reporting',
|
71
80
|
'instrument_http_url_length',
|
81
|
+
'timeline_traces',
|
82
|
+
'auto_instruments',
|
83
|
+
'auto_instruments_ignore',
|
84
|
+
|
85
|
+
# Error Service Related Configuration
|
86
|
+
'errors_enabled',
|
87
|
+
'errors_ignored_exceptions',
|
88
|
+
'errors_filtered_params',
|
89
|
+
'errors_host',
|
72
90
|
]
|
73
91
|
|
74
92
|
################################################################################
|
@@ -148,16 +166,25 @@ module ScoutApm
|
|
148
166
|
|
149
167
|
|
150
168
|
SETTING_COERCIONS = {
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
169
|
+
'async_recording' => BooleanCoercion.new,
|
170
|
+
'detailed_middleware' => BooleanCoercion.new,
|
171
|
+
'dev_trace' => BooleanCoercion.new,
|
172
|
+
'enable_background_jobs' => BooleanCoercion.new,
|
173
|
+
'ignore' => JsonCoercion.new,
|
174
|
+
'max_traces' => IntegerCoercion.new,
|
175
|
+
'monitor' => BooleanCoercion.new,
|
176
|
+
'collect_remote_ip' => BooleanCoercion.new,
|
177
|
+
'compress_payload' => BooleanCoercion.new,
|
158
178
|
'database_metric_limit' => IntegerCoercion.new,
|
159
179
|
'database_metric_report_limit' => IntegerCoercion.new,
|
160
180
|
'instrument_http_url_length' => IntegerCoercion.new,
|
181
|
+
'start_resque_server_instrument' => BooleanCoercion.new,
|
182
|
+
'timeline_traces' => BooleanCoercion.new,
|
183
|
+
'auto_instruments' => BooleanCoercion.new,
|
184
|
+
'auto_instruments_ignore' => JsonCoercion.new,
|
185
|
+
'errors_enabled' => BooleanCoercion.new,
|
186
|
+
'errors_ignored_exceptions' => JsonCoercion.new,
|
187
|
+
'errors_filtered_params' => JsonCoercion.new,
|
161
188
|
}
|
162
189
|
|
163
190
|
|
@@ -263,6 +290,16 @@ module ScoutApm
|
|
263
290
|
'database_metric_limit' => 5000, # The hard limit on db metrics
|
264
291
|
'database_metric_report_limit' => 1000,
|
265
292
|
'instrument_http_url_length' => 300,
|
293
|
+
'start_resque_server_instrument' => true, # still only starts if Resque is detected
|
294
|
+
'collect_remote_ip' => true,
|
295
|
+
'timeline_traces' => true,
|
296
|
+
'auto_instruments' => false,
|
297
|
+
'auto_instruments_ignore' => [],
|
298
|
+
'ssl_cert_file' => File.join( File.dirname(__FILE__), *%w[.. .. data cacert.pem] ),
|
299
|
+
'errors_enabled' => false,
|
300
|
+
'errors_ignored_exceptions' => %w(ActiveRecord::RecordNotFound ActionController::RoutingError),
|
301
|
+
'errors_filtered_params' => %w(password s3-key),
|
302
|
+
'errors_host' => 'https://errors.scoutapm.com',
|
266
303
|
}.freeze
|
267
304
|
|
268
305
|
def value(key)
|
@@ -0,0 +1,217 @@
|
|
1
|
+
# DetailedTrace contains all details about a certain transaction, spans with
|
2
|
+
# start & stop times, tags, etc.
|
3
|
+
|
4
|
+
# {
|
5
|
+
# "version": 1,
|
6
|
+
# "identity": {
|
7
|
+
# "transaction_id": "req-....",
|
8
|
+
# "revision": "abcdef",
|
9
|
+
# "start_instant": "01-01-01T00:00:00.0000Z",
|
10
|
+
# "stop_instant": "01-01-01T00:00:01.0000Z",
|
11
|
+
# "type": "Web",
|
12
|
+
# "naming": {
|
13
|
+
# "path": "/users",
|
14
|
+
# "code": "UsersController#index",
|
15
|
+
# },
|
16
|
+
# "score": {
|
17
|
+
# "total": 10.5,
|
18
|
+
# "percentile": 4.5,
|
19
|
+
# "age": 2.0,
|
20
|
+
# "memory_delta": 3,
|
21
|
+
# "allocations": 1
|
22
|
+
# }
|
23
|
+
# },
|
24
|
+
#
|
25
|
+
# "tags": {
|
26
|
+
# "allocations": 1000
|
27
|
+
# },
|
28
|
+
#
|
29
|
+
# "spans": [
|
30
|
+
# ...
|
31
|
+
# ]
|
32
|
+
|
33
|
+
class DetailedTrace
|
34
|
+
attr_reader :spans
|
35
|
+
attr_reader :tags
|
36
|
+
|
37
|
+
attr_reader :transaction_id
|
38
|
+
attr_reader :revision
|
39
|
+
attr_reader :start_instant
|
40
|
+
attr_reader :stop_instant
|
41
|
+
attr_reader :duration
|
42
|
+
attr_reader :type # "Web" or "Job"
|
43
|
+
attr_reader :host
|
44
|
+
|
45
|
+
attr_reader :path # /users/1
|
46
|
+
attr_reader :code # UsersController#show or similar
|
47
|
+
|
48
|
+
attr_reader :total_score
|
49
|
+
attr_reader :percentile_score
|
50
|
+
attr_reader :age_score
|
51
|
+
attr_reader :memory_delta_score
|
52
|
+
attr_reader :memory_allocations_score
|
53
|
+
|
54
|
+
VERSION = 1
|
55
|
+
|
56
|
+
def initialize(transaction_id, revision, host, start_instant, stop_instant, type, path, code, spans, tags)
|
57
|
+
@spans = spans
|
58
|
+
@tags = DetailedTraceTags(tags)
|
59
|
+
|
60
|
+
@transaction_id = transaction_id
|
61
|
+
@revision = revision
|
62
|
+
@host = host
|
63
|
+
@start_instant = start_instant
|
64
|
+
@stop_instant = stop_instant
|
65
|
+
@type = type
|
66
|
+
|
67
|
+
@path = path
|
68
|
+
@code = code
|
69
|
+
|
70
|
+
@total_score = 0
|
71
|
+
@percentile_score = 0
|
72
|
+
@age_score = 0
|
73
|
+
@memory_delta_score = 0
|
74
|
+
@memory_allocations_score = 0
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
def as_json(*)
|
79
|
+
{
|
80
|
+
:version => VERSION,
|
81
|
+
:identity => {
|
82
|
+
:transaction_id => transaction_id,
|
83
|
+
:revision => revision,
|
84
|
+
:host => host,
|
85
|
+
:start_instant => start_instant.iso8601(6),
|
86
|
+
:stop_instant => stop_instant.iso8601(6),
|
87
|
+
:type => type,
|
88
|
+
:naming => {
|
89
|
+
:path => path,
|
90
|
+
:code => code,
|
91
|
+
},
|
92
|
+
:score => {
|
93
|
+
:total => total_score,
|
94
|
+
:percentile => percentile_score,
|
95
|
+
:age => age_score,
|
96
|
+
:memory_delta => memory_delta_score,
|
97
|
+
:allocations => memory_allocations_score,
|
98
|
+
}
|
99
|
+
},
|
100
|
+
:tags => tags.as_json,
|
101
|
+
:spans => spans.map{|span| span.as_json},
|
102
|
+
}
|
103
|
+
end
|
104
|
+
|
105
|
+
########################
|
106
|
+
# Scorable interface
|
107
|
+
#
|
108
|
+
# Needed so we can merge ScoredItemSet instances
|
109
|
+
def call
|
110
|
+
self
|
111
|
+
end
|
112
|
+
|
113
|
+
def name
|
114
|
+
code
|
115
|
+
end
|
116
|
+
|
117
|
+
def score
|
118
|
+
@total_score
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
##########
|
124
|
+
# SPAN #
|
125
|
+
##########
|
126
|
+
|
127
|
+
#
|
128
|
+
# {
|
129
|
+
# "type": "Standard",
|
130
|
+
# "identity": {
|
131
|
+
# "id": "....",
|
132
|
+
# "parent_id": "....",
|
133
|
+
# "start_time": "01-01-01T00:00:00.0000Z",
|
134
|
+
# "stop_time": "01-01-01T00:00:00.0001Z",
|
135
|
+
# "operation": "SQL/User/find"
|
136
|
+
# },
|
137
|
+
# "tags": {
|
138
|
+
# "allocations": 1000,
|
139
|
+
# "db.statement": "SELECT * FROM users where id = 1",
|
140
|
+
# "db.rows": 1,
|
141
|
+
# "backtrace": [ {
|
142
|
+
# "file": "app/controllers/users_controller.rb",
|
143
|
+
# "line": 10,
|
144
|
+
# "function": "index"
|
145
|
+
# } ]
|
146
|
+
# }
|
147
|
+
class DetailedTraceSpan
|
148
|
+
attr_reader :tags
|
149
|
+
|
150
|
+
attr_reader :span_type
|
151
|
+
attr_reader :span_id, :parent_id
|
152
|
+
attr_reader :start_instant, :stop_instant
|
153
|
+
|
154
|
+
# What is the "name" of this span.
|
155
|
+
#
|
156
|
+
# Examples:
|
157
|
+
# SQL/User/find
|
158
|
+
# Controller/Users/index
|
159
|
+
# HTTP/GET/example.com
|
160
|
+
attr_reader :operation
|
161
|
+
|
162
|
+
def initialize(span_id, parent_id, start_instant, stop_instant, operation, tags)
|
163
|
+
# This will be dynamic when we implement limited spans
|
164
|
+
@span_type = "Standard"
|
165
|
+
|
166
|
+
@span_id = span_id
|
167
|
+
@parent_id = parent_id
|
168
|
+
|
169
|
+
@start_instant = start_instant
|
170
|
+
@stop_instant = stop_instant
|
171
|
+
@operation = operation
|
172
|
+
@tags = DetailedTraceTags(tags)
|
173
|
+
end
|
174
|
+
|
175
|
+
def as_json(*)
|
176
|
+
{
|
177
|
+
:type => @span_type,
|
178
|
+
:identity => {
|
179
|
+
:id => span_id,
|
180
|
+
:parent_id => parent_id,
|
181
|
+
:start_instant => start_instant.iso8601(6),
|
182
|
+
:stop_instant => stop_instant.iso8601(6),
|
183
|
+
:operation => operation,
|
184
|
+
},
|
185
|
+
:tags => @tags.as_json,
|
186
|
+
}
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
|
191
|
+
#############
|
192
|
+
# content #
|
193
|
+
#############
|
194
|
+
|
195
|
+
# Tags for either a request, or a span
|
196
|
+
class DetailedTraceTags
|
197
|
+
attr_reader :tags
|
198
|
+
|
199
|
+
def initialize(hash)
|
200
|
+
@tags = hash
|
201
|
+
end
|
202
|
+
|
203
|
+
# @tags is already a hash, so no conversion needed
|
204
|
+
def as_json(*)
|
205
|
+
@tags
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
# Converter function to turn an input into a DetailedTraceTags object
|
210
|
+
def DetailedTraceTags(arg)
|
211
|
+
if DetailedTraceTags === arg
|
212
|
+
arg
|
213
|
+
elsif Hash === arg
|
214
|
+
DetailedTraceTags.new(arg)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
@@ -26,7 +26,10 @@ module ScoutApm
|
|
26
26
|
BACKGROUND_JOB_INTEGRATIONS = [
|
27
27
|
ScoutApm::BackgroundJobIntegrations::Resque.new,
|
28
28
|
ScoutApm::BackgroundJobIntegrations::Sidekiq.new,
|
29
|
+
ScoutApm::BackgroundJobIntegrations::Shoryuken.new,
|
30
|
+
ScoutApm::BackgroundJobIntegrations::Sneakers.new,
|
29
31
|
ScoutApm::BackgroundJobIntegrations::DelayedJob.new,
|
32
|
+
ScoutApm::BackgroundJobIntegrations::Que.new,
|
30
33
|
]
|
31
34
|
|
32
35
|
FRAMEWORK_INTEGRATIONS = [
|
@@ -179,9 +182,24 @@ module ScoutApm
|
|
179
182
|
@ruby_2 = defined?(RUBY_VERSION) && RUBY_VERSION.match(/^2/)
|
180
183
|
end
|
181
184
|
|
185
|
+
def ruby_3?
|
186
|
+
return @ruby_3 if defined?(@ruby_3)
|
187
|
+
@ruby_3 = defined?(RUBY_VERSION) && RUBY_VERSION.match(/^3/)
|
188
|
+
end
|
189
|
+
|
190
|
+
def ruby_minor
|
191
|
+
return @ruby_minor if defined?(@ruby_minor)
|
192
|
+
@ruby_minor = defined?(RUBY_VERSION) && RUBY_VERSION.split(".")[1].to_i
|
193
|
+
end
|
194
|
+
|
182
195
|
# Returns true if this Ruby version supports Module#prepend.
|
183
196
|
def supports_module_prepend?
|
184
|
-
ruby_2?
|
197
|
+
ruby_2? || ruby_3?
|
198
|
+
end
|
199
|
+
|
200
|
+
# Returns true if this Ruby version supports Module#prepend.
|
201
|
+
def supports_kwarg_delegation?
|
202
|
+
ruby_3? || (ruby_2? && ruby_minor >= 7)
|
185
203
|
end
|
186
204
|
|
187
205
|
# Returns a string representation of the OS (ex: darwin, linux)
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# Public API for the Scout Error Monitoring service
|
2
|
+
#
|
3
|
+
# See-Also ScoutApm::Transaction and ScoutApm::Tracing for APM related APIs
|
4
|
+
module ScoutApm
|
5
|
+
module Error
|
6
|
+
# Capture an exception, optionally with an environment hash. This may be a
|
7
|
+
# Rack environment, but is not required.
|
8
|
+
def self.capture(exception, env={})
|
9
|
+
context = ScoutApm::Agent.instance.context
|
10
|
+
|
11
|
+
# Skip if error monitoring isn't enabled at all
|
12
|
+
if ! context.config.value("errors_enabled")
|
13
|
+
return false
|
14
|
+
end
|
15
|
+
|
16
|
+
# Skip if this one error is ignored
|
17
|
+
if context.ignored_exceptions.ignored?(exception)
|
18
|
+
return false
|
19
|
+
end
|
20
|
+
|
21
|
+
# Capture the error for further processing and shipping
|
22
|
+
context.error_buffer.capture(exception, env)
|
23
|
+
|
24
|
+
return true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "net/http"
|
2
|
+
require "net/https"
|
3
|
+
require "uri"
|
4
|
+
|
5
|
+
module ScoutApm
|
6
|
+
module ErrorService
|
7
|
+
API_VERSION = "1"
|
8
|
+
|
9
|
+
HEADERS = {
|
10
|
+
"Content-type" => "application/json",
|
11
|
+
"Accept" => "application/json"
|
12
|
+
}
|
13
|
+
|
14
|
+
# Public API to force a given exception to be captured.
|
15
|
+
# Still obeys the ignore list
|
16
|
+
# Used internally by SidekiqException
|
17
|
+
def self.capture(exception, params = {})
|
18
|
+
return if disabled?
|
19
|
+
return if ScoutApm::Agent.instance.context.ignored_exceptions.ignore?(exception)
|
20
|
+
|
21
|
+
context.errors_buffer.capture(exception, env)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.enabled?
|
25
|
+
ScoutApm::Agent.instance.context.config.value("errors_enabled")
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.disabled?
|
29
|
+
!enabled?
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# Holds onto exceptions, and moves them forward to shipping when appropriate
|
2
|
+
module ScoutApm
|
3
|
+
module ErrorService
|
4
|
+
class ErrorBuffer
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
attr_reader :agent_context
|
8
|
+
|
9
|
+
def initialize(agent_context)
|
10
|
+
@agent_context = agent_context
|
11
|
+
@error_records = []
|
12
|
+
@mutex = Monitor.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def capture(exception, env)
|
16
|
+
context = ScoutApm::Context.current
|
17
|
+
|
18
|
+
@mutex.synchronize {
|
19
|
+
@error_records << ErrorRecord.new(agent_context, exception, env, context)
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
def get_and_reset_error_records
|
24
|
+
@mutex.synchronize {
|
25
|
+
ret = @error_records
|
26
|
+
@error_records = []
|
27
|
+
ret
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
# Enables enumerable - for count and each and similar methods
|
32
|
+
def each
|
33
|
+
@error_records.each do |error_record|
|
34
|
+
yield error_record
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|