scout_apm 6.0.2 → 6.1.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: af813ad30f40b8cee3cb1e50c8b6ca311c8347d0431d18c6e5ce0939cda174e5
4
- data.tar.gz: d9baccb3c23a1c45571503349ddbc4dc4de4f0e48fbf10ee7fd40ce7f7b76b2f
3
+ metadata.gz: 38fd4f02052ac68bd1db87d3cc08cd9ce9a5d1cfbe81abac7bfc36cc7a6836b5
4
+ data.tar.gz: 9dd1c1d71c90128ff3d8a8062661668cca4be572ca89ef61d5ec82eede9e0dc6
5
5
  SHA512:
6
- metadata.gz: 1d08de0c4f24ca6d8385a381705134baff6c5b65463f4775d78eae4c03bdc91195acfb24edf666743cf2e3064b20780251f345b6b4e02ac658e7841633986f51
7
- data.tar.gz: ef12b4f094e373c5769e79c55a047b1b90db1a236fdcce4a23aacd657b5703127b662549cc56e92f72172e4e5732c99a8f769376df0a231411dbcf3f7e71d253
6
+ metadata.gz: 8dc047b9af7a065890b91b7635ebcfa12d4604c0344c9e83d98d61b945cdd1d5e39a75edd9283fe0a7a0fcde41f58e8a498327a25a4da0745d90704c5f6a9b94
7
+ data.tar.gz: f204b3e5848a056776f68a54b6a1971a69418477a57200ce6660bc5675778f77f41178533d99321d280ddc8b351548061d0dfc35445da450e8184daef3c05c3e
@@ -55,6 +55,14 @@ jobs:
55
55
  gemfile: gems/sqlite3-v2.gemfile
56
56
  - ruby: 3.4
57
57
  gemfile: gems/sqlite3-v2.gemfile
58
+ - ruby: 4.0
59
+ gemfile: gems/sqlite3-v2.gemfile
60
+ - ruby: 4.0
61
+ prepend: true
62
+ gemfile: gems/sqlite3-v2.gemfile
63
+ - ruby: 4.0
64
+ gemfile: gems/instruments-ruby4.gemfile
65
+ test_features: "instruments"
58
66
  env:
59
67
  BUNDLE_GEMFILE: ${{ matrix.gemfile }}
60
68
  SCOUT_TEST_FEATURES: ${{ matrix.test_features }}
data/CHANGELOG.markdown CHANGED
@@ -1,5 +1,12 @@
1
+ # Pending
2
+
3
+ # 6.1.0
4
+ - Ruby 4 support
5
+ - Update gem metadata
6
+ - Add `backtrace_additional_directories` config option to allow additional directories to be included in the backtrace parser
7
+
1
8
  # 6.0.2
2
- - Fix `endpoint_sample_rate` and `job_sample_rate` to support float values
9
+ - Fix `endpoint_sample_rate` and `job_sample_rate` to support float values
3
10
 
4
11
  # 6.0.1
5
12
  - Fix capturing of job params for non ActiveJob
@@ -17,7 +24,7 @@ sampled at exactly 1%, you must now set `0.01` instead of `1`.**
17
24
  - Add HTTPX instrumentation (#588)
18
25
  - Add ability to automatically capture Sidekiq job args as context
19
26
  - `job_params_capture` - Set to true to enable job argument capturing
20
- - `job_params_filter` - A list of arguments to filter (automatically includes Rails filtered_parameters)
27
+ - `job_params_filter` - A list of arguments to filter (automatically includes Rails filtered_parameters)
21
28
  - Fix user error context being incorrectly flattened (#581)
22
29
  - Handle Delayed Job PerformableMethod jobs for error tracking (#584)
23
30
  - Require 'httpclient' library on instrumentation install (#586)
@@ -0,0 +1,12 @@
1
+ eval_gemfile("../Gemfile")
2
+
3
+ gem 'minitest-mock'
4
+ gem 'ostruct'
5
+ gem "sqlite3", ">= 2.1"
6
+ gem 'httpclient'
7
+ gem 'http'
8
+ gem 'redis'
9
+ gem 'moped'
10
+ gem 'actionpack'
11
+ gem 'actionview'
12
+ gem 'httpx'
@@ -2,3 +2,4 @@ eval_gemfile("../Gemfile")
2
2
 
3
3
  gem "sqlite3", ">= 2.1"
4
4
  gem 'minitest-mock'
5
+ gem 'ostruct'
@@ -120,6 +120,7 @@ module ScoutApm
120
120
  'use_prepend',
121
121
  'alias_method_instruments',
122
122
  'prepend_instruments',
123
+ 'backtrace_additional_directories',
123
124
 
124
125
  # Error Service Related Configuration
125
126
  'errors_enabled',
@@ -267,6 +268,7 @@ module ScoutApm
267
268
  'errors_ignored_exceptions' => JsonCoercion.new,
268
269
  'errors_filtered_params' => JsonCoercion.new,
269
270
  'errors_env_capture' => JsonCoercion.new,
271
+ 'backtrace_additional_directories' => JsonCoercion.new,
270
272
  }
271
273
 
272
274
 
@@ -404,6 +406,7 @@ module ScoutApm
404
406
  'errors_filtered_params' => %w(password s3-key),
405
407
  'errors_env_capture' => %w(),
406
408
  'errors_host' => 'https://errors.scoutapm.com',
409
+ 'backtrace_additional_directories' => [],
407
410
  }.freeze
408
411
 
409
412
  def value(key)
@@ -190,6 +190,16 @@ module ScoutApm
190
190
  @ruby_3 = defined?(RUBY_VERSION) && RUBY_VERSION.match(/^3/)
191
191
  end
192
192
 
193
+ def ruby_4?
194
+ return @ruby_4 if defined?(@ruby_4)
195
+ @ruby_4 = defined?(RUBY_VERSION) && RUBY_VERSION.match(/^4/)
196
+ end
197
+
198
+ def ruby_2_or_above?
199
+ ruby_2? || ruby_3? || ruby_4?
200
+ end
201
+
202
+
193
203
  def ruby_minor
194
204
  return @ruby_minor if defined?(@ruby_minor)
195
205
  @ruby_minor = defined?(RUBY_VERSION) && RUBY_VERSION.split(".")[1].to_i
@@ -197,12 +207,12 @@ module ScoutApm
197
207
 
198
208
  # Returns true if this Ruby version supports Module#prepend.
199
209
  def supports_module_prepend?
200
- ruby_2? || ruby_3?
210
+ ruby_2_or_above?
201
211
  end
202
212
 
203
213
  # Returns true if this Ruby version makes positional and keyword arguments incompatible
204
214
  def supports_kwarg_delegation?
205
- ruby_3? || (ruby_2? && ruby_minor >= 7)
215
+ ruby_4? || ruby_3? || (ruby_2? && ruby_minor >= 7)
206
216
  end
207
217
 
208
218
  # Returns a string representation of the OS (ex: darwin, linux)
@@ -116,7 +116,7 @@ module ScoutApm
116
116
  # In Ruby 2.0+, we can pass the range directly to the caller to reduce the memory footprint.
117
117
  def caller_array
118
118
  # omits the first several callers which are in the ScoutAPM stack.
119
- if ScoutApm::Agent.instance.context.environment.ruby_2? || ScoutApm::Agent.instance.context.environment.ruby_3?
119
+ if ScoutApm::Agent.instance.context.environment.ruby_2_or_above?
120
120
  caller(3...BACKTRACE_CALLER_LIMIT)
121
121
  else
122
122
  caller[3...BACKTRACE_CALLER_LIMIT]
@@ -11,16 +11,20 @@ module ScoutApm
11
11
 
12
12
  attr_reader :call_stack
13
13
 
14
- # call_stack - an +Array+ of calls, typically generated via the +caller+ method.
15
- # Example single line:
14
+ # call_stack - an +Array+ of calls, typically generated via the +caller+ method.
15
+ # Example single line:
16
16
  # "/Users/dlite/.rvm/rubies/ruby-2.4.5/lib/ruby/2.4.0/irb/workspace.rb:87:in `eval'"
17
- def initialize(call_stack, root=ScoutApm::Agent.instance.context.environment.root)
17
+ # additional_dirs - an +Array+ of additional directory names to include beyond lib/, app/, and config/
18
+ def initialize(call_stack, root=ScoutApm::Agent.instance.context.environment.root, additional_dirs=ScoutApm::Agent.instance.context.config.value('backtrace_additional_directories'))
18
19
  @call_stack = call_stack
19
20
  # We can't use a constant as it'd be too early to fetch environment info
20
21
  #
21
22
  # This regex looks for files under the app root, inside lib/, app/, and
22
- # config/ dirs, and captures the path under root.
23
- @@app_dir_regex = %r[#{root}/((?:lib/|app/|config/).*)]
23
+ # config/ dirs (plus any additional configured directories), and captures the path under root.
24
+ base_dirs = %w[lib app config]
25
+ all_dirs = base_dirs + Array(additional_dirs)
26
+ dir_pattern = all_dirs.map { |d| Regexp.escape(d) + "/" }.join("|")
27
+ @@app_dir_regex = %r[#{root}/((?:#{dir_pattern}).*)]
24
28
  end
25
29
 
26
30
  def call
@@ -1,3 +1,3 @@
1
1
  module ScoutApm
2
- VERSION = "6.0.2"
2
+ VERSION = "6.1.0"
3
3
  end
data/scout_apm.gemspec CHANGED
@@ -12,6 +12,12 @@ Gem::Specification.new do |s|
12
12
  s.description = "Monitors Ruby apps and reports detailed metrics on performance to Scout."
13
13
  s.license = "MIT"
14
14
 
15
+ s.metadata = {
16
+ "changelog_uri" => "https://github.com/scoutapp/scout_apm_ruby/blob/master/CHANGELOG.markdown",
17
+ "homepage_uri" => "https://www.scoutapm.com",
18
+ "source_code_uri" => "https://github.com/scoutapp/scout_apm_ruby",
19
+ }
20
+
15
21
  s.files = `git ls-files`.split("\n")
16
22
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
23
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
@@ -21,6 +27,7 @@ Gem::Specification.new do |s|
21
27
 
22
28
  s.required_ruby_version = '>= 2.1'
23
29
 
30
+
24
31
  s.add_development_dependency "minitest"
25
32
  s.add_development_dependency "mocha"
26
33
  s.add_development_dependency "pry"
@@ -34,10 +41,11 @@ Gem::Specification.new do |s|
34
41
  # tests. Specific versions are pulled in using specific gemfiles, e.g.
35
42
  # `gems/rails3.gemfile`.
36
43
  s.add_development_dependency "activerecord"
37
- s.add_development_dependency "sqlite3", "~> 1.4"
44
+ s.add_development_dependency "sqlite3"
38
45
 
39
46
  s.add_development_dependency "rubocop"
40
47
  s.add_development_dependency "guard"
41
48
  s.add_development_dependency "guard-minitest"
42
49
  s.add_development_dependency "m"
50
+
43
51
  end
data/test/test_helper.rb CHANGED
@@ -81,7 +81,10 @@ end
81
81
  def fake_rails(version)
82
82
  remove_rails_namespace if (ENV["SCOUT_TEST_FEATURES"] || "").include?("instruments")
83
83
 
84
- Kernel.const_set("Rails", Module.new)
84
+ Kernel.const_set("Rails", Module.new {
85
+ # ActionView 8.1+ StructuredEventSubscriber calls Rails.try(:root)
86
+ def self.root; nil; end
87
+ })
85
88
  Kernel.const_set("ActionController", Module.new)
86
89
  r = Kernel.const_get("Rails")
87
90
  r.const_set("VERSION", Module.new)
@@ -4,9 +4,22 @@
4
4
 
5
5
  if (ENV["SCOUT_TEST_FEATURES"] || "").include?("instruments")
6
6
  require 'test_helper'
7
- require 'action_view'
7
+
8
+ # Rails 8.1+ ActionView::StructuredEventSubscriber calls Rails.try(:root)
9
+ # https://github.com/rails/rails/blob/3ad79fcede4f9b620f03b9fd76507d9fb3c07e95/actionview/lib/action_view/structured_event_subscriber.rb#L67
10
+ # which raises NameError if Rails is not defined. Define a minimal stub.
11
+ # Maybe this can get fixed at some point.
12
+ unless defined?(Rails)
13
+ module Rails
14
+ def self.root
15
+ nil
16
+ end
17
+ end
18
+ end
19
+
8
20
  require 'action_pack'
9
21
  require 'action_controller'
22
+ require 'action_view'
10
23
 
11
24
  FIXTURE_LOAD_PATH = File.expand_path("fixtures", __dir__)
12
25
 
@@ -62,6 +75,9 @@ if (ENV["SCOUT_TEST_FEATURES"] || "").include?("instruments")
62
75
 
63
76
  def setup
64
77
  super
78
+ # Ensure Rails exists - other tests may have called clean_fake_rails
79
+ fake_rails(8)
80
+
65
81
  @controller.logger = ActiveSupport::Logger.new(nil)
66
82
  ActionView::Base.logger = ActiveSupport::Logger.new(nil)
67
83
 
@@ -75,6 +91,7 @@ if (ENV["SCOUT_TEST_FEATURES"] || "").include?("instruments")
75
91
  ActionView::Base.logger = nil
76
92
 
77
93
  ActionController::Base.view_paths = @old_view_paths
94
+ clean_fake_rails
78
95
  end
79
96
 
80
97
  def test_partial_instrumentation
@@ -68,4 +68,116 @@ class BacktraceParserTest < Minitest::Test
68
68
  assert_equal false, (result[0] =~ %r|app/controllers/users_controller.rb|).nil?
69
69
  assert_equal false, (result[1] =~ %r|config/initializers/inject_something.rb|).nil?
70
70
  end
71
+
72
+ ################################################################################
73
+ # Additional directories tests
74
+
75
+ def test_with_empty_additional_directories
76
+ raw_backtrace = [
77
+ "#{root}/app/controllers/users_controller.rb",
78
+ "#{root}/engines/my_engine/app/models/thing.rb",
79
+ ]
80
+ result = ScoutApm::Utils::BacktraceParser.new(raw_backtrace, root, []).call
81
+
82
+ assert_equal 1, result.length
83
+ assert_equal false, (result[0] =~ %r|app/controllers/users_controller.rb|).nil?
84
+ end
85
+
86
+ def test_with_single_additional_directory
87
+ raw_backtrace = [
88
+ "#{root}/engines/my_engine/app/models/thing.rb",
89
+ "#{root}/app/controllers/users_controller.rb",
90
+ ]
91
+ result = ScoutApm::Utils::BacktraceParser.new(raw_backtrace, root, ['engines']).call
92
+
93
+ assert_equal 2, result.length
94
+ assert_equal false, (result[0] =~ %r|engines/my_engine/app/models/thing.rb|).nil?
95
+ assert_equal false, (result[1] =~ %r|app/controllers/users_controller.rb|).nil?
96
+ end
97
+
98
+ def test_with_multiple_additional_directories
99
+ raw_backtrace = [
100
+ "#{root}/foo/something.rb",
101
+ "#{root}/bar/something_else.rb",
102
+ "#{root}/app/controllers/users_controller.rb",
103
+ ]
104
+ result = ScoutApm::Utils::BacktraceParser.new(raw_backtrace, root, ['foo', 'bar']).call
105
+
106
+ assert_equal 3, result.length
107
+ assert_equal false, (result[0] =~ %r|foo/something.rb|).nil?
108
+ assert_equal false, (result[1] =~ %r|bar/something_else.rb|).nil?
109
+ assert_equal false, (result[2] =~ %r|app/controllers/users_controller.rb|).nil?
110
+ end
111
+
112
+ def test_default_directories_still_work_with_additional_dirs
113
+ raw_backtrace = [
114
+ "#{root}/lib/utilities.rb",
115
+ "#{root}/app/models/user.rb",
116
+ "#{root}/config/initializers/setup.rb",
117
+ "#{root}/engines/core/lib/core.rb",
118
+ ]
119
+ result = ScoutApm::Utils::BacktraceParser.new(raw_backtrace, root, ['engines']).call
120
+
121
+ assert_equal 4, result.length
122
+ assert_equal false, (result[0] =~ %r|lib/utilities.rb|).nil?
123
+ assert_equal false, (result[1] =~ %r|app/models/user.rb|).nil?
124
+ assert_equal false, (result[2] =~ %r|config/initializers/setup.rb|).nil?
125
+ assert_equal false, (result[3] =~ %r|engines/core/lib/core.rb|).nil?
126
+ end
127
+
128
+ def test_additional_directory_with_special_regex_characters
129
+ raw_backtrace = [
130
+ "#{root}/my.engine/lib/something.rb",
131
+ "#{root}/app/controllers/users_controller.rb",
132
+ ]
133
+ result = ScoutApm::Utils::BacktraceParser.new(raw_backtrace, root, ['my.engine']).call
134
+
135
+ assert_equal 2, result.length
136
+ assert_equal false, (result[0] =~ %r|my\.engine/lib/something.rb|).nil?
137
+ assert_equal false, (result[1] =~ %r|app/controllers/users_controller.rb|).nil?
138
+ end
139
+
140
+ def test_additional_directory_does_not_match_similar_names
141
+ # Ensure "my.engine" doesn't match "myXengine" (the dot should be escaped)
142
+ raw_backtrace = [
143
+ "#{root}/myXengine/lib/something.rb",
144
+ "#{root}/app/controllers/users_controller.rb",
145
+ ]
146
+ result = ScoutApm::Utils::BacktraceParser.new(raw_backtrace, root, ['my.engine']).call
147
+
148
+ assert_equal 1, result.length
149
+ assert_equal false, (result[0] =~ %r|app/controllers/users_controller.rb|).nil?
150
+ end
151
+
152
+ def test_backtrace_entirely_within_single_additional_directory
153
+ # Backtrace originates entirely from an additional directory with no default dirs
154
+ raw_backtrace = [
155
+ "#{root}/engines/core/lib/core/base.rb",
156
+ "#{root}/engines/core/app/models/engine_model.rb",
157
+ "#{root}/engines/auth/lib/auth/strategy.rb",
158
+ "#{root}/vendor/bundle/gems/some_gem.rb",
159
+ ]
160
+ result = ScoutApm::Utils::BacktraceParser.new(raw_backtrace, root, ['engines']).call
161
+
162
+ assert_equal 3, result.length
163
+ assert_equal false, (result[0] =~ %r|engines/core/lib/core/base.rb|).nil?
164
+ assert_equal false, (result[1] =~ %r|engines/core/app/models/engine_model.rb|).nil?
165
+ assert_equal false, (result[2] =~ %r|engines/auth/lib/auth/strategy.rb|).nil?
166
+ end
167
+
168
+ def test_backtrace_entirely_within_multiple_additional_directories
169
+ # Backtrace spans multiple additional directories with no default dirs
170
+ raw_backtrace = [
171
+ "#{root}/engines/billing/lib/invoice.rb",
172
+ "#{root}/components/shared/helpers.rb",
173
+ "#{root}/plugins/analytics/tracker.rb",
174
+ "#{root}/vendor/bundle/gems/external.rb",
175
+ ]
176
+ result = ScoutApm::Utils::BacktraceParser.new(raw_backtrace, root, ['engines', 'components', 'plugins']).call
177
+
178
+ assert_equal 3, result.length
179
+ assert_equal false, (result[0] =~ %r|engines/billing/lib/invoice.rb|).nil?
180
+ assert_equal false, (result[1] =~ %r|components/shared/helpers.rb|).nil?
181
+ assert_equal false, (result[2] =~ %r|plugins/analytics/tracker.rb|).nil?
182
+ end
71
183
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scout_apm
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.0.2
4
+ version: 6.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Derek Haynes
@@ -140,16 +140,16 @@ dependencies:
140
140
  name: sqlite3
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
- - - "~>"
143
+ - - ">="
144
144
  - !ruby/object:Gem::Version
145
- version: '1.4'
145
+ version: '0'
146
146
  type: :development
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
- - - "~>"
150
+ - - ">="
151
151
  - !ruby/object:Gem::Version
152
- version: '1.4'
152
+ version: '0'
153
153
  - !ruby/object:Gem::Dependency
154
154
  name: rubocop
155
155
  requirement: !ruby/object:Gem::Requirement
@@ -232,6 +232,7 @@ files:
232
232
  - ext/rusage/extconf.rb
233
233
  - ext/rusage/rusage.c
234
234
  - gems/README.md
235
+ - gems/instruments-ruby4.gemfile
235
236
  - gems/instruments.gemfile
236
237
  - gems/octoshark.gemfile
237
238
  - gems/rails3.gemfile
@@ -500,7 +501,10 @@ files:
500
501
  homepage: https://github.com/scoutapp/scout_apm_ruby
501
502
  licenses:
502
503
  - MIT
503
- metadata: {}
504
+ metadata:
505
+ changelog_uri: https://github.com/scoutapp/scout_apm_ruby/blob/master/CHANGELOG.markdown
506
+ homepage_uri: https://www.scoutapm.com
507
+ source_code_uri: https://github.com/scoutapp/scout_apm_ruby
504
508
  rdoc_options: []
505
509
  require_paths:
506
510
  - lib
@@ -516,7 +520,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
516
520
  - !ruby/object:Gem::Version
517
521
  version: '0'
518
522
  requirements: []
519
- rubygems_version: 3.6.9
523
+ rubygems_version: 4.0.3
520
524
  specification_version: 4
521
525
  summary: Ruby application performance monitoring
522
526
  test_files: []