skylight 5.0.0.beta2 → 5.0.0.beta3

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: 2b77ca3f00aac3011421d279776acf31f9259debecb3319689250e49fbd3310f
4
- data.tar.gz: 6cee4d4a09aa991c3e5d3cf65bc9534797f59fc8951a7d088025271068d9e9cc
3
+ metadata.gz: c951c13914411fa23c37504ba022bd55229c2c4c59dc4dcf0a751b24b9dad33c
4
+ data.tar.gz: 93734aa403e74cbcc5c7afda5473800b962a1fe4a0b06fff0cbfab2a23d7d316
5
5
  SHA512:
6
- metadata.gz: 98649cab11fb628dcfdade4a7dc5507d7640f5f90b6aa9230305fc1c5261d5f73ff3014bc399595f4bc6c85fafb334668f1b81e9020ea5e1f644f3e60ad966d7
7
- data.tar.gz: edfacb9d5322768a0dbdd9acbdd31ea5305a077dee1a24076078c448c73a9cd7b0b1889ead269db9e661ed49d11e02e2da38326bad90448b12db72718b949a81
6
+ metadata.gz: 7901ffd7e863387424ab384d8276472a6d2c3dfabef2075cb859db8e1ff8f81643cce80f2ac9ffba1f3cb1c27d06338a6b6477347f7e7db58745d9ede000a78b
7
+ data.tar.gz: a404ebc97ac20f763f21df54e444e0abf72b4ad442bb39efca1c6b19a408f0d8edab2021032237aac044cb39c333815ed101ad6015fdd4246d3a66932cd9b7e9
@@ -1,3 +1,9 @@
1
+ ## 5.0.0.beta3
2
+ * [IMPROVEMENT] Optimizations for the Source Locations extension
3
+ * [FEATURE] Configuration for the Source Locations caches via `SYLIGHT_SOURCE_LOCATION_CACHE_SIZE`
4
+ * [BUGFIX] Fix issue with missing metadata in MongoDB probe
5
+ * [BUGFIX] Resolve an inability to parse certain SQL queries containing arrays
6
+
1
7
  ## 5.0.0.beta2
2
8
  * [FEATURE] Source Locations detection and reporting is now enabled by default (can be disabled with `SKYLIGHT_ENABLE_SOURCE_LOCATIONS=false`)
3
9
  * [BREAKING] Rename `environment` keyword argument to `priority_key`. Note `env` has not changed.
@@ -1,6 +1,6 @@
1
- version: "5.0.0-45b02dd"
1
+ version: "5.0.0-7111415"
2
2
  checksums:
3
- x86-linux: "218a51683cbe3f6e7f1d31097a7e732c6bac3e3780a707312f8441dd45d8f3a6"
4
- x86_64-linux: "2426968fef8cd7fe0fd0ea582fd8098db78025ce936bac9d72b7753995bd1ea9"
5
- x86_64-linux-musl: "ca07748d43fac0b4a05b38b5ce0fc4cb7e43469a183919c5d9980a8b2e0b01ab"
6
- x86_64-darwin: "8b19eb2ffd19f78ee6e547b37fcf5cad2e49aa9a8bc2b9615a791ccfc91c2552"
3
+ x86-linux: "c304b73401b82adcbede23886168ca3487ca5901ebeddd6377d8ce758bf9d72d"
4
+ x86_64-linux: "4005f06b71295c77dccc7369f313452c7a26fe4c8de1108988e4d06d8f5fb36e"
5
+ x86_64-linux-musl: "0b8c582f99cc65ef466a506b9f589d634c8b502d4de5991c80c38e9efa812909"
6
+ x86_64-darwin: "efbd36e1cbea562ca9b76342cc3e938a6c0c506e7e7e1c0daaafff71da68364e"
@@ -101,7 +101,7 @@ module Skylight
101
101
  message: e.message, klass: e.class)]
102
102
  end
103
103
 
104
- if config&.respond_to?("log_#{level}") && config&.respond_to?(:log_trace)
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
 
@@ -110,7 +110,8 @@ module Skylight
110
110
  -"HEROKU_DYNO_INFO_PATH" => :'heroku.dyno_info_path',
111
111
 
112
112
  # == Source Location ==
113
- -"SOURCE_LOCATION_IGNORED_GEMS" => :source_location_ignored_gems
113
+ -"SOURCE_LOCATION_IGNORED_GEMS" => :source_location_ignored_gems,
114
+ -"SOURCE_LOCATION_CACHE_SIZE" => :source_location_cache_size
114
115
  }.freeze
115
116
 
116
117
  KEY_TO_NATIVE_ENV = {
@@ -551,7 +552,7 @@ module Skylight
551
552
  when /^warn$/i then Logger::WARN
552
553
  when /^error$/i then Logger::ERROR
553
554
  when /^fatal$/i then Logger::FATAL
554
- else Logger::ERROR
555
+ else Logger::ERROR # rubocop:disable Lint/DuplicateBranch
555
556
  end
556
557
  end
557
558
  end
@@ -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")
@@ -11,11 +11,13 @@ 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
- @caller_cache = Util::LruCache.new(100)
18
- @instance_method_source_location_cache = Util::LruCache.new(100)
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
 
@@ -35,6 +37,7 @@ module Skylight
35
37
  source_line = opts[:source_line] || opts[:meta]&.[](:source_line)
36
38
  source_name_hint, const_name, method_name = opts[:source_location_hint] ||
37
39
  opts[:meta]&.[](:source_location_hint)
40
+ instrument_location = opts[:sk_instrument_location]
38
41
 
39
42
  if source_location
40
43
  meta[:source_location] = source_location
@@ -45,6 +48,9 @@ module Skylight
45
48
  elsif source_file
46
49
  meta[:source_file] = source_file
47
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
48
54
  else
49
55
  warn "Ignoring source_line without source_file" if source_line
50
56
  if (location = find_caller(cache_key: opts.hash))
@@ -134,10 +140,14 @@ module Skylight
134
140
  end
135
141
 
136
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
+
137
146
  if cache_key
138
- @caller_cache.fetch(cache_key) { find_caller_inner }
147
+ localized_cache_key = [cache_key, locations.map(&:lineno)].hash
148
+ @caller_cache.fetch(localized_cache_key) { find_caller_inner(locations) }
139
149
  else
140
- find_caller_inner
150
+ find_caller_inner(locations)
141
151
  end
142
152
  end
143
153
 
@@ -236,11 +246,12 @@ module Skylight
236
246
  nil
237
247
  end
238
248
 
239
- def find_caller_inner
249
+ def find_caller_inner(locations)
240
250
  # Start at file before this one
241
251
  # NOTE: We could start farther back now to avoid more Skylight files
242
- caller_locations(1).find do |l|
243
- find_source_gem(l.absolute_path) || project_path?(l.absolute_path)
252
+ locations.find do |l|
253
+ absolute_path = l.absolute_path
254
+ find_source_gem(absolute_path) || project_path?(absolute_path)
244
255
  end
245
256
  end
246
257
 
@@ -12,7 +12,8 @@ module Skylight
12
12
  # @return [Hash] a hash containing `:category`, `:title`, and `:annotations`
13
13
  def self.build_opts(method, _scheme, host, _port, _path, _query)
14
14
  { category: "api.http.#{method.downcase}",
15
- title: "#{method.upcase} #{host}" }
15
+ title: "#{method.upcase} #{host}",
16
+ internal: true }
16
17
  end
17
18
  end
18
19
  end
@@ -124,6 +124,8 @@ module Skylight
124
124
  # instrument_class_method :my_method, title: 'Expensive work'
125
125
  # end
126
126
  def instrument_class_method(name, opts = {})
127
+ # NOTE: If the class is defined anonymously and then assigned to a variable this code
128
+ # will not be aware of the updated name.
127
129
  title = "#{self}.#{name}"
128
130
  __sk_instrument_method_on(__sk_singleton_class, name, title, opts || {})
129
131
  end
@@ -144,32 +146,32 @@ module Skylight
144
146
  source_file, source_line = klass.instance_method(name).source_location
145
147
 
146
148
  klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
147
- alias_method :"before_instrument_#{name}", :"#{name}"
148
-
149
- def #{name}(*args, &blk)
150
- span = Skylight.instrument(
151
- category: :"#{category}",
152
- title: #{title.inspect},
153
- description: #{desc.inspect},
154
- source_file: #{source_file.inspect},
155
- source_line: #{source_line.inspect})
156
-
157
- meta = {}
158
- begin
159
- send(:before_instrument_#{name}, *args, &blk)
160
- rescue Exception => e
161
- meta[:exception_object] = e
162
- raise e
163
- ensure
164
- Skylight.done(span, meta) if span
165
- end
166
- end
167
-
168
- if protected_method_defined?(:"before_instrument_#{name}")
169
- protected :"#{name}"
170
- elsif private_method_defined?(:"before_instrument_#{name}")
171
- private :"#{name}"
172
- end
149
+ alias_method :"before_instrument_#{name}", :"#{name}" # alias_method :"before_instrument_process", :"process"
150
+ #
151
+ def #{name}(*args, &blk) # def process(*args, &blk)
152
+ span = Skylight.instrument( # span = Skylight.instrument(
153
+ category: :"#{category}", # category: :"app.method",
154
+ title: #{title.inspect}, # title: "process",
155
+ description: #{desc.inspect}, # description: "Process data",
156
+ source_file: #{source_file.inspect}, # source_file: "myapp/lib/processor.rb",
157
+ source_line: #{source_line.inspect}) # source_line: 123)
158
+ #
159
+ meta = {} # meta = {}
160
+ begin # begin
161
+ send(:before_instrument_#{name}, *args, &blk) # send(:before_instrument_process)
162
+ rescue Exception => e # rescue Exception => e
163
+ meta[:exception_object] = e # meta[:exception_object] = e
164
+ raise e # raise e
165
+ ensure # ensure
166
+ Skylight.done(span, meta) if span # Skylight.done(span, meta) if span
167
+ end # end
168
+ end # end
169
+ #
170
+ if protected_method_defined?(:"before_instrument_#{name}") # if protected_method_defined?(:"before_instrument_process")
171
+ protected :"#{name}" # protected :"process"
172
+ elsif private_method_defined?(:"before_instrument_#{name}") # elsif private_method_defined?(:"before_instrument_process")
173
+ private :"#{name}" # private :"process"
174
+ end # end
173
175
  RUBY
174
176
  end
175
177
 
@@ -10,7 +10,7 @@ module Skylight
10
10
  @closed = false
11
11
  end
12
12
 
13
- def respond_to_missing?(name, include_all = false) # rubocop:disable Lint/MissingSuper, Style/OptionalBooleanParameter
13
+ def respond_to_missing?(name, include_all = false) # rubocop:disable Lint/MissingSuper
14
14
  return false if name.to_s !~ /^to_ary$/
15
15
 
16
16
  @body.respond_to?(name, include_all)
@@ -101,7 +101,7 @@ module Skylight
101
101
 
102
102
  # @api private
103
103
  def self.check_install_errors(config)
104
- # Note: An unsupported arch doesn't count as an error.
104
+ # NOTE: An unsupported arch doesn't count as an error.
105
105
  install_log = File.expand_path("../../ext/install.log", __dir__)
106
106
 
107
107
  if File.exist?(install_log) && File.read(install_log) =~ /ERROR/
@@ -69,7 +69,8 @@ module Skylight
69
69
  return cat if cat == :skip
70
70
 
71
71
  meta ||= {}
72
- process_meta(trace, name, payload, meta, cache_key: ret.hash)
72
+ cache_key = ret.hash
73
+ process_meta(trace, name, payload, meta, cache_key: cache_key)
73
74
 
74
75
  [cat, title, desc, meta]
75
76
  end
@@ -18,7 +18,13 @@ module Skylight
18
18
  rescue
19
19
  block.call
20
20
  else
21
- Skylight.instrument(title: "Enqueue #{name}", category: CAT, description: desc, &block)
21
+ Skylight.instrument(
22
+ title: "Enqueue #{name}",
23
+ category: CAT,
24
+ description: desc,
25
+ internal: true,
26
+ &block
27
+ )
22
28
  end
23
29
 
24
30
  self.class.instance_eval do
@@ -85,7 +85,8 @@ module Skylight
85
85
  opts = {
86
86
  category: "app.delayed_job.job",
87
87
  title: format_source(*source_meta),
88
- meta: { source_location_hint: source_meta }
88
+ meta: { source_location_hint: source_meta },
89
+ internal: true
89
90
  }
90
91
 
91
92
  Skylight.instrument(opts) { __getobj__.perform }
@@ -6,7 +6,7 @@ module Skylight
6
6
  # Middleware for Excon that instruments requests
7
7
  class Middleware < ::Excon::Middleware::Base
8
8
  def initialize(*)
9
- @requests = {}
9
+ @requests = {}.compare_by_identity
10
10
  super
11
11
  end
12
12
 
@@ -38,19 +38,19 @@ module Skylight
38
38
  scheme = datum[:scheme]
39
39
  host = datum[:host]
40
40
  # TODO: Maybe don't show other default ports like 443
41
- port = datum[:port] != 80 ? datum[:port] : nil
41
+ port = datum[:port] == 80 ? nil : datum[:port]
42
42
  path = datum[:path]
43
43
  query = datum[:query]
44
44
 
45
45
  opts = Formatters::HTTP.build_opts(method, scheme, host, port, path, query)
46
46
 
47
- @requests[datum.object_id] = Skylight.instrument(opts)
47
+ @requests[datum] = Skylight.instrument(opts)
48
48
  rescue Exception => e
49
49
  Skylight.error "failed to begin instrumentation for Excon; msg=%s", e.message
50
50
  end
51
51
 
52
52
  def end_instrumentation(datum)
53
- if (request = @requests.delete(datum.object_id))
53
+ if (request = @requests.delete(datum))
54
54
  meta = {}
55
55
  if datum[:error].is_a?(Exception)
56
56
  meta[:exception_object] = datum[:error]
@@ -113,7 +113,8 @@ module Skylight
113
113
  category: CAT,
114
114
  title: title,
115
115
  description: payload.empty? ? nil : payload.to_json,
116
- meta: { database: event.database_name }
116
+ meta: { database: event.database_name },
117
+ internal: true
117
118
  }
118
119
 
119
120
  @events[event.operation_id] = Skylight.instrument(opts)
@@ -6,12 +6,14 @@ module Skylight
6
6
 
7
7
  PIPELINED_OPTS = {
8
8
  category: "db.redis.pipelined".freeze,
9
- title: "PIPELINE".freeze
9
+ title: "PIPELINE".freeze,
10
+ internal: true
10
11
  }.freeze
11
12
 
12
13
  MULTI_OPTS = {
13
14
  category: "db.redis.multi".freeze,
14
- title: "MULTI".freeze
15
+ title: "MULTI".freeze,
16
+ internal: true
15
17
  }.freeze
16
18
 
17
19
  module ClientInstrumentation
@@ -22,7 +24,8 @@ module Skylight
22
24
 
23
25
  opts = {
24
26
  category: "db.redis.command",
25
- title: command_name.upcase.to_s
27
+ title: command_name.upcase.to_s,
28
+ internal: true
26
29
  }
27
30
 
28
31
  Skylight.instrument(opts) { super }
@@ -6,7 +6,7 @@ module Skylight
6
6
  GC_CAT = "noise.gc".freeze
7
7
  SYNTHETIC = "<synthetic>".freeze
8
8
 
9
- META_KEYS = %i[mute_children].freeze
9
+ META_KEYS = %i[mute_children database].freeze
10
10
 
11
11
  include Util::Logging
12
12
 
@@ -340,8 +340,10 @@ module Skylight
340
340
  def validate_meta(meta)
341
341
  unknown_keys = meta.keys - allowed_meta_keys
342
342
  if unknown_keys.any?
343
- warn "Unknown meta keys will be ignored; keys=#{unknown_keys.inspect}"
344
- unknown_keys.each { |key| meta.delete(key) }
343
+ unknown_keys.each do |key|
344
+ maybe_warn("unknown_meta:#{key}", "Unknown meta key will be ignored; key=#{key.inspect}")
345
+ meta.delete(key)
346
+ end
345
347
  end
346
348
  end
347
349
 
@@ -192,7 +192,7 @@ module Skylight
192
192
  body.dig(*key.split(".")) if body.is_a?(Hash)
193
193
  end
194
194
 
195
- def respond_to_missing?(name, include_all = false) # rubocop:disable Style/OptionalBooleanParameter
195
+ def respond_to_missing?(name, include_all = false)
196
196
  super || body.respond_to?(name, include_all)
197
197
  end
198
198
 
@@ -4,20 +4,20 @@ module Skylight
4
4
  def instrumenter_method(name, block: false)
5
5
  if block
6
6
  module_eval <<-RUBY, __FILE__, __LINE__ + 1
7
- def #{name}(*args)
8
- unless instrumenter
9
- return yield if block_given?
10
- return
11
- end
12
-
13
- instrumenter.#{name}(*args) { yield }
14
- end
7
+ def #{name}(*args) # def mute(*args)
8
+ unless instrumenter # unless instrumenter
9
+ return yield if block_given? # return yield if block_given?
10
+ return # return
11
+ end # end
12
+ #
13
+ instrumenter.#{name}(*args) { yield } # instrumenter.mute(*args) { yield }
14
+ end # end
15
15
  RUBY
16
16
  else
17
17
  module_eval <<-RUBY, __FILE__, __LINE__ + 1
18
- def #{name}(*args)
19
- instrumenter&.#{name}(*args)
20
- end
18
+ def #{name}(*args) # def config(*args)
19
+ instrumenter&.#{name}(*args) # instrumenter&.config(*args)
20
+ end # end
21
21
  RUBY
22
22
  end
23
23
  end
@@ -13,7 +13,7 @@ module Skylight
13
13
 
14
14
  # Try to avoid writing to STDOUT/STDERR twice
15
15
  logger_logdev = @logger.instance_variable_get(:@logdev)
16
- logger_out = logger_logdev&.respond_to?(:dev) ? logger_logdev.dev : nil
16
+ logger_out = logger_logdev.respond_to?(:dev) ? logger_logdev.dev : nil
17
17
  if logger_out != $stdout && logger_out != $stderr
18
18
  @logger.<<(*args)
19
19
  end
@@ -114,10 +114,10 @@ module Skylight
114
114
 
115
115
  if logger
116
116
  if logger.respond_to?(level)
117
- if !args.empty?
118
- logger.send level, format(msg, *args)
119
- else
117
+ if args.empty?
120
118
  logger.send level, msg
119
+ else
120
+ logger.send level, format(msg, *args)
121
121
  end
122
122
  return # rubocop:disable Style/RedundantReturn
123
123
  else
@@ -56,7 +56,7 @@ module Skylight
56
56
  "so"
57
57
  when /windows|cygwin/
58
58
  "dll"
59
- else
59
+ else # rubocop:disable Lint/DuplicateBranch
60
60
  "so"
61
61
  end
62
62
 
@@ -3,5 +3,5 @@ module Skylight
3
3
  # for compatibility with semver when it is parsed by the rust agent.
4
4
  # This string will be transformed in the gemspec to "5.0.0.alpha"
5
5
  # to conform with rubygems.
6
- VERSION = "5.0.0-beta2".freeze
6
+ VERSION = "5.0.0-beta3".freeze
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: skylight
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.0.beta2
4
+ version: 5.0.0.beta3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tilde, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-10-26 00:00:00.000000000 Z
11
+ date: 2020-11-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -142,14 +142,14 @@ dependencies:
142
142
  requirements:
143
143
  - - "~>"
144
144
  - !ruby/object:Gem::Version
145
- version: 0.79.0
145
+ version: 1.3.1
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: 0.79.0
152
+ version: 1.3.1
153
153
  - !ruby/object:Gem::Dependency
154
154
  name: timecop
155
155
  requirement: !ruby/object:Gem::Requirement
@@ -367,7 +367,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
367
367
  - !ruby/object:Gem::Version
368
368
  version: 1.3.1
369
369
  requirements: []
370
- rubygems_version: 3.1.2
370
+ rubygems_version: 3.1.4
371
371
  signing_key:
372
372
  specification_version: 4
373
373
  summary: Skylight is a smart profiler for Rails, Sinatra, and other Ruby apps.