scout_apm 5.6.4 → 5.6.5
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/CHANGELOG.markdown +5 -0
- data/lib/scout_apm/error.rb +65 -11
- data/lib/scout_apm/error_service/error_record.rb +4 -0
- data/lib/scout_apm/error_service/payload.rb +2 -0
- data/lib/scout_apm/sampling.rb +1 -1
- data/lib/scout_apm/version.rb +1 -1
- data/test/unit/error_test.rb +69 -0
- data/test/unit/sampling_test.rb +2 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1a45c15600501200c54adb79600c0ff8c2c7229c6f4c8c6292804f2f10c716e2
|
4
|
+
data.tar.gz: d068883fec42f88524e0ccac0d84da6941a8c981c6eecb5b7e525affddb3ea77
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 92c538b493815dd07fed71cf43bf610c109b988a8aa597647e5b0d5c854120c13c9d8f96b8c04740ece120b952327ac920d41d18589422cfd23fe84ee1cded38
|
7
|
+
data.tar.gz: f69b0f43b36cc020600f91c97aafe3ed523225ac87bb9b62b2764d797e8d40380381b08032303a2d1c54d5a2f02164a8086a1b55bc7ad20d12e5ccf189db2921
|
data/CHANGELOG.markdown
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
# Unreleased
|
2
2
|
|
3
|
+
# 5.6.5
|
4
|
+
- Improve error capture API (#555)
|
5
|
+
- Add git sha and agent time tracking to error payloads (#554)
|
6
|
+
- Add support for named spaced jobs in sampling (#549)
|
7
|
+
|
3
8
|
# 5.6.4
|
4
9
|
- Use new ActiveJob class name and timestamp units for Sidekiq 8+ (#544)
|
5
10
|
|
data/lib/scout_apm/error.rb
CHANGED
@@ -5,23 +5,77 @@ module ScoutApm
|
|
5
5
|
module Error
|
6
6
|
# Capture an exception, optionally with an environment hash. This may be a
|
7
7
|
# Rack environment, but is not required.
|
8
|
-
|
9
|
-
|
8
|
+
class ScoutDefined < Exception; end
|
9
|
+
class Custom < ScoutDefined; end
|
10
|
+
|
11
|
+
class << self
|
12
|
+
def capture(exception, env={}, name: "ScoutApm::Error::Custom")
|
13
|
+
context = ScoutApm::Agent.instance.context
|
10
14
|
|
11
|
-
|
12
|
-
|
13
|
-
|
15
|
+
# Skip if error monitoring isn't enabled at all
|
16
|
+
if ! context.config.value("errors_enabled")
|
17
|
+
return false
|
18
|
+
end
|
19
|
+
|
20
|
+
exception = validate_or_create_exception(exception, name)
|
21
|
+
return false unless exception
|
22
|
+
|
23
|
+
# Skip if this one error is ignored
|
24
|
+
if context.ignored_exceptions.ignored?(exception)
|
25
|
+
return false
|
26
|
+
end
|
27
|
+
|
28
|
+
# Capture the error for further processing and shipping
|
29
|
+
context.error_buffer.capture(exception, env)
|
30
|
+
|
31
|
+
return true
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def get_caller_location
|
37
|
+
caller_locations(0, 10)
|
38
|
+
.reject { |loc| loc.absolute_path == __FILE__ }
|
39
|
+
.map(&:to_s)
|
40
|
+
end
|
41
|
+
|
42
|
+
def define_error_class(name_str)
|
43
|
+
# e.g., "some_error" → "SomeError", "some error" → "SomeError"
|
44
|
+
class_name = name_str.gsub(/(?:^|[_\s])([a-zA-Z])/) { $1.upcase }
|
45
|
+
|
46
|
+
if Object.const_defined?(class_name)
|
47
|
+
klass = Object.const_get(class_name)
|
48
|
+
return klass if klass.ancestors.include?(ScoutApm::Error::ScoutDefined)
|
49
|
+
|
50
|
+
log_warning("Error class name '#{class_name}' is already defined. Falling back to ScoutApm::Error::Custom.")
|
51
|
+
return Custom
|
52
|
+
else
|
53
|
+
Object.const_set(class_name, Class.new(ScoutDefined))
|
54
|
+
end
|
14
55
|
end
|
15
56
|
|
16
|
-
|
17
|
-
|
18
|
-
return false
|
57
|
+
def log_warning(message)
|
58
|
+
ScoutApm::Agent.instance.context.logger.warn(message)
|
19
59
|
end
|
20
60
|
|
21
|
-
|
22
|
-
|
61
|
+
def validate_or_create_exception(exception, name)
|
62
|
+
return exception if exception.is_a?(Exception) && exception.backtrace
|
23
63
|
|
24
|
-
|
64
|
+
if exception.is_a?(Exception)
|
65
|
+
exception.tap do |e|
|
66
|
+
e.set_backtrace(get_caller_location)
|
67
|
+
end
|
68
|
+
|
69
|
+
elsif exception.is_a?(String)
|
70
|
+
define_error_class(name).new(exception).tap do |e|
|
71
|
+
e.set_backtrace(get_caller_location)
|
72
|
+
end
|
73
|
+
|
74
|
+
else
|
75
|
+
log_warning("Invalid exception type: #{exception.class}. Expected Exception or String.")
|
76
|
+
nil
|
77
|
+
end
|
78
|
+
end
|
25
79
|
end
|
26
80
|
end
|
27
81
|
end
|
@@ -12,6 +12,8 @@ module ScoutApm
|
|
12
12
|
attr_reader :trace
|
13
13
|
attr_reader :request_components
|
14
14
|
attr_reader :context
|
15
|
+
attr_reader :agent_time
|
16
|
+
attr_reader :git_sha
|
15
17
|
|
16
18
|
def initialize(agent_context, exception, env, context=nil)
|
17
19
|
@agent_context = agent_context
|
@@ -30,6 +32,8 @@ module ScoutApm
|
|
30
32
|
@environment = clean_params(strip_env(env))
|
31
33
|
@trace = clean_backtrace(exception.backtrace)
|
32
34
|
@request_components = components(env)
|
35
|
+
@agent_time = Time.now.iso8601
|
36
|
+
@git_sha = @agent_context.environment.git_revision.sha.to_s
|
33
37
|
end
|
34
38
|
|
35
39
|
# TODO: This is rails specific
|
data/lib/scout_apm/sampling.rb
CHANGED
@@ -58,7 +58,7 @@ module ScoutApm
|
|
58
58
|
# config looks like ['/foo:50','/bar:100']. parse it into hash of string: integer
|
59
59
|
sample_hash = {}
|
60
60
|
sampling_config.each do |sample|
|
61
|
-
path, rate = sample.
|
61
|
+
path, _, rate = sample.rpartition(':')
|
62
62
|
sample_hash[path] = rate.to_i
|
63
63
|
end
|
64
64
|
sample_hash
|
data/lib/scout_apm/version.rb
CHANGED
@@ -0,0 +1,69 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class ErrorTest < Minitest::Test
|
4
|
+
class FakeError < StandardError
|
5
|
+
end
|
6
|
+
|
7
|
+
def test_captures_and_stores_exceptions_and_env
|
8
|
+
config = make_fake_config(
|
9
|
+
'errors_enabled' => true,
|
10
|
+
)
|
11
|
+
test_context = ScoutApm::AgentContext.new().tap{|c| c.config = config }
|
12
|
+
ScoutApm::Agent.instance.stub(:context, test_context) do
|
13
|
+
exwbt = ex.tap do |e|
|
14
|
+
e.set_backtrace(["/path/to/file.rb:10:in `method_name'"])
|
15
|
+
end
|
16
|
+
assert_equal true, ScoutApm::Error.capture("Oh no an error") # Will be of type ScoutApm::Error::Custom
|
17
|
+
assert_equal true, ScoutApm::Error.capture("Oh no another error") # Will be of type ScoutApm::Error::Custom
|
18
|
+
assert_equal true, ScoutApm::Error.capture("Something went boom", {"boom" => "yes"}, name: "boom_error")
|
19
|
+
assert_equal true, ScoutApm::Error.capture("No env", name: "another error")
|
20
|
+
assert_equal true, ScoutApm::Error.capture(ex, env)
|
21
|
+
assert_equal true, ScoutApm::Error.capture(exwbt, env)
|
22
|
+
assert_equal false, ScoutApm::Error.capture(Class, env)
|
23
|
+
assert_equal true, ScoutApm::Error.capture("Name collision, but", env, name: "ScoutApm")
|
24
|
+
|
25
|
+
begin
|
26
|
+
raise StandardError, "Whoops"
|
27
|
+
rescue StandardError => e
|
28
|
+
assert_equal true, ScoutApm::Error.capture(e, env)
|
29
|
+
end
|
30
|
+
|
31
|
+
exceptions = ScoutApm::Agent.instance.context.error_buffer.instance_variable_get(:@error_records)
|
32
|
+
|
33
|
+
assert_equal 8, exceptions.length
|
34
|
+
assert_equal "Oh no an error", exceptions[0].message
|
35
|
+
assert_equal "ScoutApm::Error::Custom", exceptions[0].exception_class
|
36
|
+
|
37
|
+
# Ensure we capture time and git sha
|
38
|
+
refute_nil exceptions[0].git_sha
|
39
|
+
assert exceptions[0].agent_time.is_a?(String)
|
40
|
+
|
41
|
+
assert_equal "Oh no another error", exceptions[1].message
|
42
|
+
assert_equal "ScoutApm::Error::Custom", exceptions[1].exception_class
|
43
|
+
|
44
|
+
assert_equal "Something went boom", exceptions[2].message
|
45
|
+
assert_equal "BoomError", exceptions[2].exception_class
|
46
|
+
|
47
|
+
assert_equal "No env", exceptions[3].message
|
48
|
+
assert_equal "AnotherError", exceptions[3].exception_class
|
49
|
+
|
50
|
+
assert_equal "Whoops", exceptions[4].message
|
51
|
+
assert_equal "ErrorTest::FakeError", exceptions[4].exception_class
|
52
|
+
|
53
|
+
assert_equal "/path/to/file.rb:10:in `method_name'", exceptions[5].trace.first
|
54
|
+
|
55
|
+
assert_equal "ScoutApm::Error::Custom", exceptions[6].exception_class
|
56
|
+
|
57
|
+
assert_equal "StandardError", exceptions[7].exception_class
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
#### Helpers
|
62
|
+
def env
|
63
|
+
{}
|
64
|
+
end
|
65
|
+
|
66
|
+
def ex(msg="Whoops")
|
67
|
+
FakeError.new(msg)
|
68
|
+
end
|
69
|
+
end
|
data/test/unit/sampling_test.rb
CHANGED
@@ -15,7 +15,7 @@ class SamplingTest < Minitest::Test
|
|
15
15
|
{
|
16
16
|
'sample_endpoints' => ['/foo/bar:100', '/foo:50', '/bar/zap:80'],
|
17
17
|
'ignore_endpoints' => ['/baz'],
|
18
|
-
'sample_jobs' => ['joba:50'],
|
18
|
+
'sample_jobs' => ['joba:50', 'Foo::BarJob:95'],
|
19
19
|
'ignore_jobs' => 'jobb,jobc',
|
20
20
|
}
|
21
21
|
)
|
@@ -59,6 +59,7 @@ class SamplingTest < Minitest::Test
|
|
59
59
|
def test_job_sample
|
60
60
|
sampling = ScoutApm::Sampling.new(@individual_config)
|
61
61
|
assert_equal 50, sampling.job_sample_rate('joba')
|
62
|
+
assert_equal 95, sampling.job_sample_rate('Foo::BarJob')
|
62
63
|
assert_nil sampling.job_sample_rate('jobb')
|
63
64
|
end
|
64
65
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: scout_apm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.6.
|
4
|
+
version: 5.6.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Derek Haynes
|
8
8
|
- Andre Lewis
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -443,6 +443,7 @@ files:
|
|
443
443
|
- test/unit/environment_test.rb
|
444
444
|
- test/unit/error_service/error_buffer_test.rb
|
445
445
|
- test/unit/error_service/ignored_exceptions_test.rb
|
446
|
+
- test/unit/error_test.rb
|
446
447
|
- test/unit/extensions/periodic_callbacks_test.rb
|
447
448
|
- test/unit/extensions/transaction_callbacks_test.rb
|
448
449
|
- test/unit/external_service_metric_set_test.rb
|
@@ -508,7 +509,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
508
509
|
- !ruby/object:Gem::Version
|
509
510
|
version: '0'
|
510
511
|
requirements: []
|
511
|
-
rubygems_version: 3.6.
|
512
|
+
rubygems_version: 3.6.9
|
512
513
|
specification_version: 4
|
513
514
|
summary: Ruby application performance monitoring
|
514
515
|
test_files: []
|