skylight 5.0.0.beta → 5.0.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 +4 -4
- data/CHANGELOG.md +26 -6
- data/CONTRIBUTING.md +1 -1
- data/ext/extconf.rb +2 -2
- data/ext/libskylight.yml +7 -5
- data/lib/skylight.rb +9 -2
- data/lib/skylight/api.rb +3 -0
- data/lib/skylight/cli/doctor.rb +11 -13
- data/lib/skylight/config.rb +25 -32
- data/lib/skylight/deprecation.rb +3 -1
- data/lib/skylight/errors.rb +4 -4
- data/lib/skylight/extensions.rb +8 -0
- data/lib/skylight/extensions/source_location.rb +123 -81
- data/lib/skylight/formatters/http.rb +2 -1
- data/lib/skylight/helpers.rb +44 -35
- data/lib/skylight/instrumenter.rb +3 -2
- data/lib/skylight/middleware.rb +4 -4
- data/lib/skylight/native.rb +1 -1
- data/lib/skylight/native_ext_fetcher.rb +2 -2
- data/lib/skylight/normalizers.rb +6 -4
- data/lib/skylight/normalizers/action_controller/process_action.rb +1 -1
- data/lib/skylight/normalizers/action_dispatch/route_set.rb +1 -1
- data/lib/skylight/normalizers/active_job/perform.rb +5 -0
- data/lib/skylight/normalizers/graphql/base.rb +1 -0
- data/lib/skylight/normalizers/render.rb +1 -1
- data/lib/skylight/normalizers/shrine.rb +34 -0
- data/lib/skylight/normalizers/sql.rb +3 -2
- data/lib/skylight/probes.rb +38 -10
- data/lib/skylight/probes/active_job.rb +4 -6
- data/lib/skylight/probes/active_job_enqueue.rb +18 -14
- data/lib/skylight/probes/active_model_serializers.rb +2 -6
- data/lib/skylight/probes/delayed_job.rb +112 -25
- data/lib/skylight/probes/elasticsearch.rb +1 -1
- data/lib/skylight/probes/excon/middleware.rb +4 -4
- data/lib/skylight/probes/middleware.rb +2 -1
- data/lib/skylight/probes/mongo.rb +2 -1
- data/lib/skylight/probes/net_http.rb +0 -1
- data/lib/skylight/probes/redis.rb +6 -3
- data/lib/skylight/railtie.rb +1 -1
- data/lib/skylight/sidekiq.rb +12 -7
- data/lib/skylight/subscriber.rb +1 -1
- data/lib/skylight/trace.rb +10 -4
- data/lib/skylight/util/deploy.rb +3 -6
- data/lib/skylight/util/instrumenter_method.rb +11 -11
- data/lib/skylight/util/logging.rb +6 -6
- data/lib/skylight/util/lru_cache.rb +1 -3
- data/lib/skylight/util/platform.rb +1 -1
- data/lib/skylight/version.rb +1 -1
- metadata +27 -13
- data/lib/skylight/fanout.rb +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 66c646baeaeddece5a75140908f8c7d1aec447945903ff5681c1e4de58839e79
|
4
|
+
data.tar.gz: a3fe10a6b05963038f40f4b82d77cd545c42fa546d63cd440a21eb3839280b71
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ca6b42cfa51a39f1cccfc8f169a9bdc1560ec9774423c1ca335ec6fc26bd70d47f40c62d9e645ea626b00626e962a9ef3dbda49c693de0a56fef10bc04ab1d76
|
7
|
+
data.tar.gz: ccb18fe7cc713c03544db2a0d1dc5c42d86fe5ee14c0db11e208884203b7141cd39032bdb75f5c7eaf341b1ded6e9c761e8529e1bf50d1c499b1bab85a545fcd
|
data/CHANGELOG.md
CHANGED
@@ -1,18 +1,38 @@
|
|
1
|
-
## 5.0.0
|
2
|
-
|
3
|
-
* [
|
4
|
-
* [
|
5
|
-
* [
|
1
|
+
## 5.0.0 (March 5, 2021)
|
2
|
+
|
3
|
+
* [FEATURE] Add normalizer for Shrine events (thanks @janko!)
|
4
|
+
* [FEATURE] Source Locations detection and reporting is now enabled by default (can be disabled with `SKYLIGHT_ENABLE_SOURCE_LOCATIONS=false`)
|
5
|
+
* [FEATURE] Configuration for the Source Locations caches via `SYLIGHT_SOURCE_LOCATION_CACHE_SIZE`
|
6
|
+
|
7
|
+
* [IMPROVEMENT] Improve keyword argument handling in Skylight::Helpers (thanks @lukebooth!)
|
8
|
+
* [IMPROVEMENT] Replace a Kernel.puts with Skylight.log (thanks @johnnyshields!)
|
9
|
+
* [IMPROVEMENT] Various updates to the SQL lexer
|
10
|
+
* [IMPROVEMENT] Reduce volume of log messages sent to the native logger in debug level
|
11
|
+
* [IMPROVEMENT] Optimizations for the Source Locations extension
|
12
|
+
* [IMPROVEMENT] Improved Delayed::Job probe
|
6
13
|
* [IMPROVEMENT] Maintain method visibility when instrumenting with `instrument_method`
|
7
14
|
* [IMPROVEMENT] Update probes to use `Module#prepend` where possible
|
8
15
|
* [IMPROVEMENT] New tokio-based skylightd
|
9
16
|
* [IMPROVEMENT] Support `render_layout` notifications in Rails 6.1
|
10
17
|
* [IMPROVEMENT] Support `ActionMailer::MailDeliveryJob` in Rails 6.1
|
11
|
-
* [IMPROVEMENT] Better logging config
|
18
|
+
* [IMPROVEMENT] Better logging config. `SKYLIGHT_NATIVE_LOG_LEVEL` now defaults to `warn`.
|
19
|
+
|
20
|
+
* [BREAKING] Rename `environment` keyword argument to `priority_key`. Note `env` has not changed.
|
21
|
+
* [BREAKING] Drop support for Ruby 2.4
|
22
|
+
* [BREAKING] Merge skylight-core into skylight. All classes previously namespaced under `Skylight::Core` have been moved to `Skylight`.
|
23
|
+
* [BREAKING] Remove `Skylight::Util::Inflector`
|
24
|
+
* [BREAKING] Drop support for Rails 4
|
25
|
+
* [BREAKING] Drop support for Ruby 2.3
|
26
|
+
|
27
|
+
* [BUGFIX] Fix issue with missing metadata in MongoDB probe
|
28
|
+
* [BUGFIX] Resolve an inability to parse certain SQL queries containing arrays
|
12
29
|
* [BUGFIX] Allow multiple probes to be registered under the same key
|
13
30
|
* [BUGFIX] Do not refer to Redis constant until the probe is installed
|
14
31
|
* [BUGFIX] Fix nested calls to `Normalizers::Faraday::Request.disable`
|
15
32
|
|
33
|
+
## 4.3.2 (December 14, 2020)
|
34
|
+
* [BUGFIX] Backport an ActionView fix from Skylight 5 (makes Skylight 4 compatible with Rails 6.1)
|
35
|
+
|
16
36
|
## 4.3.1 (June 24, 2020)
|
17
37
|
* [BUGFIX] Fix an issue in which `Mime::NullType` would result in an exception
|
18
38
|
|
data/CONTRIBUTING.md
CHANGED
@@ -16,7 +16,7 @@ If you prefer to run tests in your own environment, you may do so as follows:
|
|
16
16
|
|
17
17
|
```shell
|
18
18
|
# Select a gemfile and bundle install
|
19
|
-
export BUNDLE_GEMFILE=$PWD/gemfiles/
|
19
|
+
export BUNDLE_GEMFILE=$PWD/gemfiles/rails-5.2.x/Gemfile
|
20
20
|
bundle install
|
21
21
|
# Run the test suite (takes 5-10 minutes)
|
22
22
|
bundle exec rspec
|
data/ext/extconf.rb
CHANGED
@@ -42,7 +42,7 @@ SKYLIGHT_CHECKSUM = ENV["SKYLIGHT_CHECKSUM"]
|
|
42
42
|
SKYLIGHT_EXT_STRICT = ENV.key?("SKYLIGHT_EXT_STRICT") && ENV["SKYLIGHT_EXT_STRICT"] =~ /^true$/i
|
43
43
|
|
44
44
|
# Setup logger
|
45
|
-
LOG = Logger.new(MultiIO.new(
|
45
|
+
LOG = Logger.new(MultiIO.new($stdout, File.open(SKYLIGHT_INSTALL_LOG, "a")))
|
46
46
|
|
47
47
|
# Handles terminating in the case of a failure. If we have a bug, we do not
|
48
48
|
# want to break our customer's deploy, but extconf.rb requires a Makefile to be
|
@@ -69,7 +69,7 @@ end
|
|
69
69
|
if Platform::OS == "darwin"
|
70
70
|
# If the user installs Xcode-only, they have to approve the
|
71
71
|
# license or no "xc*" tool will work.
|
72
|
-
if `/usr/bin/xcrun clang 2>&1` =~ /license/ && !$CHILD_STATUS.success?
|
72
|
+
if `/usr/bin/xcrun clang 2>&1` =~ /license/ && !$CHILD_STATUS.success? # rubocop:disable Style/SoleNestedConditional
|
73
73
|
fail <<~MESSAGE
|
74
74
|
You have not agreed to the Xcode license and so we are unable to build the native agent.
|
75
75
|
To resolve this, you can agree to the license by opening Xcode.app or running:
|
data/ext/libskylight.yml
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
-
|
1
|
+
# commit: ea59cc7bdbbee0f69d1cf7e69827974a9ea67645
|
2
|
+
---
|
3
|
+
version: "5.0.0-488d432"
|
2
4
|
checksums:
|
3
|
-
x86-linux: "
|
4
|
-
x86_64-linux: "
|
5
|
-
x86_64-linux-musl: "
|
6
|
-
x86_64-darwin: "
|
5
|
+
x86-linux: "3c16b6db1508f35720258551783fbcd30fd231638bad316ea76748d659838399"
|
6
|
+
x86_64-linux: "94383aa3359c3f2e9c0e3c16ee263d46c5673dd255f8842e6acadf5ec3131c06"
|
7
|
+
x86_64-linux-musl: "d2e2e2e61c321315f9bcaa157426f33aef8ffc2330ba46b2cdcbd9442e65f728"
|
8
|
+
x86_64-darwin: "bcc925d0bcbae83a484f35dbc9729dcf262e1f3a8c29b8d387d0f58ad8f3afa3"
|
data/lib/skylight.rb
CHANGED
@@ -101,7 +101,7 @@ module Skylight
|
|
101
101
|
message: e.message, klass: e.class)]
|
102
102
|
end
|
103
103
|
|
104
|
-
if config
|
104
|
+
if config.respond_to?("log_#{level}") && config.respond_to?(:log_trace)
|
105
105
|
config.send("log_#{level}", message)
|
106
106
|
config.log_trace e.backtrace.join("\n")
|
107
107
|
else
|
@@ -194,10 +194,17 @@ module Skylight
|
|
194
194
|
opts = {}
|
195
195
|
end
|
196
196
|
|
197
|
+
# NOTE: unless we have `:internal` (indicating a built-in Skylight instrument block),
|
198
|
+
# or we already have a `source_file` or `source_line` (probably set by `instrument_method`),
|
199
|
+
# we set the caller location to the second item on the stack
|
200
|
+
# (immediate caller of the `instrument` method).
|
201
|
+
unless opts[:source_file] || opts[:source_line] || opts[:internal]
|
202
|
+
opts = opts.merge(sk_instrument_location: caller_locations(1..1).first)
|
203
|
+
end
|
204
|
+
|
197
205
|
meta ||= {}
|
198
206
|
|
199
207
|
instrumenter.extensions.process_instrument_options(opts, meta)
|
200
|
-
|
201
208
|
instrumenter.instrument(category, title, desc, meta, &block)
|
202
209
|
end
|
203
210
|
|
data/lib/skylight/api.rb
CHANGED
data/lib/skylight/cli/doctor.rb
CHANGED
@@ -85,20 +85,18 @@ module Skylight
|
|
85
85
|
say "Checking for valid configuration"
|
86
86
|
|
87
87
|
indent do
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
say "This may occur if you are configuring with ENV variables and didn't set them in this shell."
|
98
|
-
end
|
99
|
-
|
100
|
-
done!
|
88
|
+
config.validate!
|
89
|
+
say "Configuration is valid", :green
|
90
|
+
rescue ConfigError => e
|
91
|
+
encountered_error!
|
92
|
+
|
93
|
+
say "Configuration is invalid", :red
|
94
|
+
indent do
|
95
|
+
say e.message, :red
|
96
|
+
say "This may occur if you are configuring with ENV variables and didn't set them in this shell."
|
101
97
|
end
|
98
|
+
|
99
|
+
done!
|
102
100
|
end
|
103
101
|
|
104
102
|
puts "\n"
|
data/lib/skylight/config.rb
CHANGED
@@ -44,6 +44,7 @@ module Skylight
|
|
44
44
|
-"LOG_LEVEL" => :log_level,
|
45
45
|
-"ALERT_LOG_FILE" => :alert_log_file,
|
46
46
|
-"NATIVE_LOG_FILE" => :native_log_file,
|
47
|
+
-"NATIVE_LOG_LEVEL" => :native_log_level,
|
47
48
|
-"LOG_SQL_PARSE_ERRORS" => :log_sql_parse_errors,
|
48
49
|
|
49
50
|
# == Proxy ==
|
@@ -110,7 +111,8 @@ module Skylight
|
|
110
111
|
-"HEROKU_DYNO_INFO_PATH" => :'heroku.dyno_info_path',
|
111
112
|
|
112
113
|
# == Source Location ==
|
113
|
-
-"SOURCE_LOCATION_IGNORED_GEMS" => :source_location_ignored_gems
|
114
|
+
-"SOURCE_LOCATION_IGNORED_GEMS" => :source_location_ignored_gems,
|
115
|
+
-"SOURCE_LOCATION_CACHE_SIZE" => :source_location_cache_size
|
114
116
|
}.freeze
|
115
117
|
|
116
118
|
KEY_TO_NATIVE_ENV = {
|
@@ -119,9 +121,7 @@ module Skylight
|
|
119
121
|
native_log_level: "LOG_LEVEL"
|
120
122
|
}.freeze
|
121
123
|
|
122
|
-
SERVER_VALIDATE = %i[
|
123
|
-
enable_source_locations
|
124
|
-
].freeze
|
124
|
+
SERVER_VALIDATE = %i[].freeze
|
125
125
|
|
126
126
|
DEFAULT_IGNORED_SOURCE_LOCATION_GEMS = [
|
127
127
|
-"skylight",
|
@@ -145,12 +145,13 @@ module Skylight
|
|
145
145
|
log_level: -"INFO",
|
146
146
|
alert_log_file: -"-",
|
147
147
|
log_sql_parse_errors: true,
|
148
|
+
native_log_level: -"warn",
|
148
149
|
|
149
150
|
# Features
|
150
151
|
enable_segments: true,
|
151
152
|
enable_sidekiq: false,
|
152
153
|
sinatra_route_prefixes: false,
|
153
|
-
enable_source_locations:
|
154
|
+
enable_source_locations: true,
|
154
155
|
|
155
156
|
# Deploys
|
156
157
|
'heroku.dyno_info_path': -"/etc/heroku/dyno",
|
@@ -243,7 +244,7 @@ module Skylight
|
|
243
244
|
end
|
244
245
|
|
245
246
|
# @api private
|
246
|
-
attr_reader :
|
247
|
+
attr_reader :priority_key
|
247
248
|
|
248
249
|
# @api private
|
249
250
|
def initialize(*args)
|
@@ -253,16 +254,16 @@ module Skylight
|
|
253
254
|
attrs = args.pop.dup
|
254
255
|
end
|
255
256
|
|
256
|
-
@values
|
257
|
+
@values = {}
|
257
258
|
@priority = {}
|
258
|
-
@
|
259
|
+
@priority_regexp = nil
|
259
260
|
@alert_logger = nil
|
260
261
|
@logger = nil
|
261
262
|
|
262
263
|
p = attrs.delete(:priority)
|
263
264
|
|
264
|
-
if (@
|
265
|
-
@
|
265
|
+
if (@priority_key = args[0])
|
266
|
+
@priority_regexp = /^#{Regexp.escape(priority_key)}\.(.+)$/
|
266
267
|
end
|
267
268
|
|
268
269
|
attrs.each do |k, v|
|
@@ -277,7 +278,8 @@ module Skylight
|
|
277
278
|
def self.load(opts = {}, env = ENV)
|
278
279
|
attrs = {}
|
279
280
|
path = opts.delete(:file)
|
280
|
-
|
281
|
+
priority_key = opts.delete(:priority_key)
|
282
|
+
priority_key ||= opts[:env] # if a priority_key is not given, use env if available
|
281
283
|
|
282
284
|
if path
|
283
285
|
error = nil
|
@@ -295,11 +297,14 @@ module Skylight
|
|
295
297
|
raise ConfigError, "could not load config file; msg=#{error}" if error
|
296
298
|
end
|
297
299
|
|
300
|
+
# The key-value pairs in this `priority` option are inserted into the
|
301
|
+
# config's @priority hash *after* anything listed under priority_key;
|
302
|
+
# i.e., ENV takes precendence over priority_key
|
298
303
|
if env
|
299
304
|
attrs[:priority] = remap_env(env)
|
300
305
|
end
|
301
306
|
|
302
|
-
config = new(
|
307
|
+
config = new(priority_key, attrs)
|
303
308
|
|
304
309
|
opts.each do |k, v|
|
305
310
|
config[k] = v
|
@@ -439,7 +444,7 @@ module Skylight
|
|
439
444
|
end
|
440
445
|
end
|
441
446
|
|
442
|
-
if @
|
447
|
+
if @priority_regexp && k =~ @priority_regexp
|
443
448
|
@priority[$1.to_sym] = val
|
444
449
|
end
|
445
450
|
|
@@ -549,23 +554,13 @@ module Skylight
|
|
549
554
|
when /^warn$/i then Logger::WARN
|
550
555
|
when /^error$/i then Logger::ERROR
|
551
556
|
when /^fatal$/i then Logger::FATAL
|
552
|
-
else Logger::ERROR
|
557
|
+
else Logger::ERROR # rubocop:disable Lint/DuplicateBranch
|
553
558
|
end
|
554
559
|
end
|
555
560
|
end
|
556
561
|
|
557
562
|
def native_log_level
|
558
|
-
|
559
|
-
if trace?
|
560
|
-
"trace"
|
561
|
-
else
|
562
|
-
case log_level
|
563
|
-
when Logger::DEBUG then "debug"
|
564
|
-
when Logger::INFO then "info"
|
565
|
-
when Logger::WARN then "warn"
|
566
|
-
else "error"
|
567
|
-
end
|
568
|
-
end
|
563
|
+
get(:native_log_level).to_s.downcase
|
569
564
|
end
|
570
565
|
|
571
566
|
def logger
|
@@ -586,7 +581,7 @@ module Skylight
|
|
586
581
|
end
|
587
582
|
end
|
588
583
|
|
589
|
-
attr_writer :logger
|
584
|
+
attr_writer :logger, :alert_logger
|
590
585
|
|
591
586
|
def alert_logger
|
592
587
|
@alert_logger ||= MUTEX.synchronize do
|
@@ -601,8 +596,6 @@ module Skylight
|
|
601
596
|
end
|
602
597
|
end
|
603
598
|
|
604
|
-
attr_writer :alert_logger
|
605
|
-
|
606
599
|
def enable_segments?
|
607
600
|
!!get(:enable_segments)
|
608
601
|
end
|
@@ -638,13 +631,13 @@ module Skylight
|
|
638
631
|
|
639
632
|
Logger.new(out, progname: "Skylight", level: level)
|
640
633
|
rescue
|
641
|
-
Logger.new(
|
634
|
+
Logger.new($stdout, progname: "Skylight", level: level)
|
642
635
|
end
|
643
636
|
|
644
637
|
def load_logger
|
645
638
|
unless (l = @logger)
|
646
639
|
out = get(:log_file)
|
647
|
-
out =
|
640
|
+
out = $stdout if out == "-"
|
648
641
|
l = create_logger(out, level: log_level)
|
649
642
|
end
|
650
643
|
|
@@ -690,7 +683,7 @@ module Skylight
|
|
690
683
|
corrected_config = res.corrected_config
|
691
684
|
|
692
685
|
# Use defaults if no corrected config is available. This will happen if the request failed.
|
693
|
-
corrected_config ||=
|
686
|
+
corrected_config ||= SERVER_VALIDATE.map { |k| [k, self.class.default_values.fetch(k)] }.to_h
|
694
687
|
|
695
688
|
config_to_update = corrected_config.reject { |k, v| get(k) == v }
|
696
689
|
unless config_to_update.empty?
|
@@ -700,7 +693,7 @@ module Skylight
|
|
700
693
|
|
701
694
|
# This is a weird way to handle priorities
|
702
695
|
# See https://github.com/tildeio/direwolf-agent/issues/275
|
703
|
-
k = "#{
|
696
|
+
k = "#{priority_key}.#{k}" if priority_key
|
704
697
|
|
705
698
|
set(k, v)
|
706
699
|
end
|
data/lib/skylight/deprecation.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_support/deprecation"
|
2
4
|
|
3
5
|
module Skylight
|
4
|
-
SKYLIGHT_GEM_ROOT = File.expand_path(
|
6
|
+
SKYLIGHT_GEM_ROOT = "#{File.expand_path('../..', __dir__)}/"
|
5
7
|
|
6
8
|
class Deprecation < ActiveSupport::Deprecation
|
7
9
|
private
|
data/lib/skylight/errors.rb
CHANGED
@@ -13,10 +13,10 @@ module Skylight
|
|
13
13
|
end
|
14
14
|
|
15
15
|
Skylight.module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
16
|
-
class #{name}Error < NativeError
|
17
|
-
def self.code; #{code}; end
|
18
|
-
def self.message; #{message.to_json}; end
|
19
|
-
end
|
16
|
+
class #{name}Error < NativeError # class SqlLexError < NativeError
|
17
|
+
def self.code; #{code}; end # def self.code; 4; end
|
18
|
+
def self.message; #{message.to_json}; end # def self.message; "Failed to lex SQL query."; end
|
19
|
+
end # end
|
20
20
|
RUBY
|
21
21
|
|
22
22
|
klass = Skylight.const_get("#{name}Error")
|
data/lib/skylight/extensions.rb
CHANGED
@@ -32,6 +32,12 @@ module Skylight
|
|
32
32
|
!!extensions.detect { |x| x.is_a?(ext_class) }
|
33
33
|
end
|
34
34
|
|
35
|
+
def process_trace_meta(meta)
|
36
|
+
extensions.each do |ext|
|
37
|
+
ext.process_trace_meta(meta)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
35
41
|
# meta is a mutable hash that will be passed to the instrumenter.
|
36
42
|
# This method bridges Skylight.instrument and instrumenter.instrument.
|
37
43
|
def process_instrument_options(opts, meta)
|
@@ -83,6 +89,8 @@ module Skylight
|
|
83
89
|
@config = config
|
84
90
|
end
|
85
91
|
|
92
|
+
def process_trace_meta(_meta); end
|
93
|
+
|
86
94
|
def process_instrument_options(_opts, _meta); end
|
87
95
|
|
88
96
|
def process_normalizer_meta(_payload, _meta, **opts); end
|
@@ -11,24 +11,46 @@ module Skylight
|
|
11
11
|
include Util::Logging
|
12
12
|
|
13
13
|
META_KEYS = %i[source_location source_file source_line].freeze
|
14
|
+
MAX_CALLER_DEPTH = 75
|
14
15
|
|
15
16
|
def initialize(*)
|
16
17
|
super
|
17
|
-
|
18
|
-
@
|
18
|
+
cache_size = (config[:source_location_cache_size] || 1000).to_i
|
19
|
+
@caller_cache = Util::LruCache.new(cache_size)
|
20
|
+
@instance_method_source_location_cache = Util::LruCache.new(cache_size)
|
19
21
|
gem_require_trie # memoize this at startup
|
20
22
|
end
|
21
23
|
|
24
|
+
def process_trace_meta(meta)
|
25
|
+
unless meta[:source_location] || meta[:source_file]
|
26
|
+
warn "Ignoring source_line without source_file" if meta[:source_line]
|
27
|
+
if (location = find_caller)
|
28
|
+
meta[:source_file] = location.absolute_path
|
29
|
+
meta[:source_line] = location.lineno
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
22
34
|
def process_instrument_options(opts, meta)
|
23
35
|
source_location = opts[:source_location] || opts[:meta]&.[](:source_location)
|
24
36
|
source_file = opts[:source_file] || opts[:meta]&.[](:source_file)
|
25
37
|
source_line = opts[:source_line] || opts[:meta]&.[](:source_line)
|
38
|
+
source_name_hint, const_name, method_name = opts[:source_location_hint] ||
|
39
|
+
opts[:meta]&.[](:source_location_hint)
|
40
|
+
instrument_location = opts[:sk_instrument_location]
|
26
41
|
|
27
42
|
if source_location
|
28
43
|
meta[:source_location] = source_location
|
44
|
+
elsif source_name_hint
|
45
|
+
source_location = dispatch_hinted_source_location(source_name_hint, const_name, method_name)
|
46
|
+
meta[:source_file], meta[:source_line] = source_location
|
47
|
+
meta.delete(:source_location_hint) if source_location
|
29
48
|
elsif source_file
|
30
49
|
meta[:source_file] = source_file
|
31
50
|
meta[:source_line] = source_line
|
51
|
+
elsif instrument_location && project_path?(instrument_location.absolute_path)
|
52
|
+
meta[:source_file] = instrument_location.absolute_path
|
53
|
+
meta[:source_line] = instrument_location.lineno
|
32
54
|
else
|
33
55
|
warn "Ignoring source_line without source_file" if source_line
|
34
56
|
if (location = find_caller(cache_key: opts.hash))
|
@@ -41,14 +63,21 @@ module Skylight
|
|
41
63
|
end
|
42
64
|
|
43
65
|
def process_normalizer_meta(payload, meta, **opts)
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
66
|
+
if opts[:source_location] && (opts[:source_file] || opts[:source_line])
|
67
|
+
warn "Found both source_location and source_file or source_line in normalizer\n" \
|
68
|
+
" location=#{opts[:source_location]}; file=#{opts[:source_file]}; line=#{opts[:source_line]}"
|
69
|
+
end
|
70
|
+
|
71
|
+
sl =
|
72
|
+
if (source_name, constant_name, method_name = opts[:source_location_hint])
|
73
|
+
dispatch_hinted_source_location(
|
74
|
+
source_name,
|
75
|
+
constant_name,
|
76
|
+
method_name
|
77
|
+
)
|
78
|
+
elsif opts[:source_file]
|
79
|
+
[opts[:source_file], opts[:source_line]]
|
80
|
+
end
|
52
81
|
|
53
82
|
sl ||= source_location(payload, meta, cache_key: opts[:cache_key])
|
54
83
|
|
@@ -91,86 +120,92 @@ module Skylight
|
|
91
120
|
|
92
121
|
protected
|
93
122
|
|
94
|
-
|
95
|
-
|
96
|
-
return unless const_name && method_name
|
123
|
+
def dispatch_hinted_source_location(source_name, const_name, method_name)
|
124
|
+
return unless const_name && method_name
|
97
125
|
|
98
|
-
|
99
|
-
|
126
|
+
instance_method_source_location(const_name, method_name, source_name: source_name)
|
127
|
+
end
|
100
128
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
129
|
+
# from normalizers.rb
|
130
|
+
# Returns an array of file and line
|
131
|
+
def source_location(payload, meta, cache_key: nil)
|
132
|
+
# FIXME: what should precedence be?
|
133
|
+
if meta.is_a?(Hash) && meta[:source_location]
|
134
|
+
meta.delete(:source_location)
|
135
|
+
elsif payload.is_a?(Hash) && payload[:sk_source_location]
|
136
|
+
payload[:sk_source_location]
|
137
|
+
elsif (location = find_caller(cache_key: cache_key))
|
138
|
+
[location.absolute_path, location.lineno]
|
139
|
+
end
|
111
140
|
end
|
112
|
-
end
|
113
141
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
142
|
+
def find_caller(cache_key: nil)
|
143
|
+
# starting at 4 to skip Skylight extension processing logic
|
144
|
+
locations = ::Kernel.caller_locations(4..MAX_CALLER_DEPTH)
|
145
|
+
|
146
|
+
if cache_key
|
147
|
+
localized_cache_key = [cache_key, locations.map(&:lineno)].hash
|
148
|
+
@caller_cache.fetch(localized_cache_key) { find_caller_inner(locations) }
|
149
|
+
else
|
150
|
+
find_caller_inner(locations)
|
151
|
+
end
|
119
152
|
end
|
120
|
-
end
|
121
153
|
|
122
|
-
|
123
|
-
|
124
|
-
return false unless path.start_with?(config.root.to_s)
|
125
|
-
# Must not be Bundler's vendor location
|
126
|
-
return false if defined?(Bundler) && path.start_with?(Bundler.bundle_path.to_s)
|
127
|
-
# Must not be Ruby files
|
128
|
-
return false if path.include?("/ruby-#{RUBY_VERSION}/lib/ruby/")
|
154
|
+
def project_path?(path)
|
155
|
+
return false unless path
|
129
156
|
|
130
|
-
|
131
|
-
|
132
|
-
|
157
|
+
# Must be in the project root
|
158
|
+
return false unless path.start_with?(config.root.to_s)
|
159
|
+
# Must not be Bundler's vendor location
|
160
|
+
return false if defined?(Bundler) && path.start_with?(Bundler.bundle_path.to_s)
|
161
|
+
# Must not be Ruby files
|
162
|
+
return false if path.include?("/ruby-#{RUBY_VERSION}/lib/ruby/")
|
133
163
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
164
|
+
# So it must be a project file
|
165
|
+
true
|
166
|
+
end
|
167
|
+
|
168
|
+
def instance_method_source_location(constant_name, method_name, source_name: :instance_method)
|
169
|
+
@instance_method_source_location_cache.fetch([constant_name, method_name, source_name]) do
|
170
|
+
if (constant = ::ActiveSupport::Dependencies.safe_constantize(constant_name))
|
171
|
+
if constant.instance_methods.include?(:"before_instrument_#{method_name}")
|
172
|
+
method_name = :"before_instrument_#{method_name}"
|
173
|
+
end
|
174
|
+
begin
|
175
|
+
unbound_method = case source_name
|
176
|
+
when :instance_method
|
177
|
+
find_instance_method(constant, method_name)
|
178
|
+
when :own_instance_method
|
179
|
+
find_own_instance_method(constant, method_name)
|
180
|
+
when :instance_method_super
|
181
|
+
find_instance_method_super(constant, method_name)
|
182
|
+
when :class_method
|
183
|
+
find_class_method(constant, method_name)
|
184
|
+
end
|
185
|
+
|
186
|
+
unbound_method&.source_location
|
187
|
+
rescue NameError
|
188
|
+
nil
|
189
|
+
end
|
153
190
|
end
|
154
191
|
end
|
155
192
|
end
|
156
|
-
end
|
157
193
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
end
|
194
|
+
def sanitize_source_location(path, line)
|
195
|
+
# Do this first since gems may be vendored in the app repo. However, it might be slower.
|
196
|
+
# Should we cache matches?
|
197
|
+
if (gem_name = find_source_gem(path))
|
198
|
+
path = gem_name
|
199
|
+
line = nil
|
200
|
+
elsif project_path?(path)
|
201
|
+
# Get relative path to root
|
202
|
+
path = Pathname.new(path).relative_path_from(config.root).to_s
|
203
|
+
else
|
204
|
+
return
|
205
|
+
end
|
171
206
|
|
172
|
-
|
173
|
-
|
207
|
+
line ? "#{path}:#{line}" : path
|
208
|
+
end
|
174
209
|
|
175
210
|
private
|
176
211
|
|
@@ -198,21 +233,25 @@ module Skylight
|
|
198
233
|
end
|
199
234
|
|
200
235
|
def find_source_gem(path)
|
236
|
+
return nil unless path
|
237
|
+
|
201
238
|
trie = gem_require_trie
|
202
239
|
|
203
240
|
path.split(File::SEPARATOR).each do |segment|
|
204
241
|
trie = trie[segment]
|
205
|
-
|
242
|
+
break unless trie
|
206
243
|
return trie[:name] if trie[:name]
|
207
244
|
end
|
208
245
|
|
209
246
|
nil
|
210
247
|
end
|
211
248
|
|
212
|
-
def find_caller_inner
|
249
|
+
def find_caller_inner(locations)
|
213
250
|
# Start at file before this one
|
214
|
-
|
215
|
-
|
251
|
+
# NOTE: We could start farther back now to avoid more Skylight files
|
252
|
+
locations.find do |l|
|
253
|
+
absolute_path = l.absolute_path
|
254
|
+
find_source_gem(absolute_path) || project_path?(absolute_path)
|
216
255
|
end
|
217
256
|
end
|
218
257
|
|
@@ -244,6 +283,9 @@ module Skylight
|
|
244
283
|
constant.instance_method(method_name)
|
245
284
|
end
|
246
285
|
|
286
|
+
def find_class_method(constant, method_name)
|
287
|
+
constant.method(method_name)
|
288
|
+
end
|
247
289
|
end
|
248
290
|
end
|
249
291
|
end
|