skylight-core 2.0.1 → 2.0.2.beta

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: fe55886e88fc2828fad4c6565eb0c1db58d0901e751602306079fa1b42e3be43
4
- data.tar.gz: d0598c4efa965eb3911c59991eca2664b53cfd0eb6e86a712ca642ca2fc24b6f
3
+ metadata.gz: d9ef05dea2241e0a6ec4b0d5cef5803457a80b5e40ef5d8b166640528da91555
4
+ data.tar.gz: fea0b9a66551b26c8d0f0cc4daf6f59ac320e80fa4b860c5d299547ac243eb1b
5
5
  SHA512:
6
- metadata.gz: 3aed5c95952a9b1db5ae89e2c8085aea8bb00c614ffe9974e4f75d77a1a34c1cfa07910009c35cdaffd8ccf35ab2d3a64380acfeb26b386ec07da4f131187765
7
- data.tar.gz: 6308094a1e5611924304bd14512deb40ca6d161d51ddb24c0c50e892bb1c5af0766e3542b3c54ff883f8d6692f2e92428031cd985a8430745dcd064100195f06
6
+ metadata.gz: dff2bc263dbdf1335e7c84123fca8814f3f32ef883420730e7a08bf3e5e8449c11470ccaf61b691829178c49dffbcc62360a8f6153c93d53232dac2906e51c45
7
+ data.tar.gz: 9cae9daf7ddf1302125b68ea98eacb27d34b6444e2bd8a0ac92dfdc0c34b532562f95179ea17b5394f8b6457d21f3fd2c6b5cd3ab489d6c8f1f1b542e95616c8
@@ -32,12 +32,12 @@ module Skylight::Core
32
32
 
33
33
  # == Instrumenter ==
34
34
  "ENABLE_SEGMENTS" => :enable_segments,
35
+ "ENABLE_SIDEKIQ" => :enable_sidekiq,
35
36
 
36
37
  # == User config settings ==
37
38
  "USER_CONFIG_PATH" => :'user_config_path',
38
39
 
39
40
  # == Heroku settings ==
40
- #
41
41
  "HEROKU_DYNO_INFO_PATH" => :'heroku.dyno_info_path'
42
42
  }
43
43
  end
@@ -50,6 +50,7 @@ module Skylight::Core
50
50
  :alert_log_file => '-'.freeze,
51
51
  :log_sql_parse_errors => true,
52
52
  :enable_segments => true,
53
+ :enable_sidekiq => false,
53
54
  :'heroku.dyno_info_path' => '/etc/heroku/dyno'
54
55
  }
55
56
  end
@@ -404,6 +405,10 @@ module Skylight::Core
404
405
  !!get(:enable_segments)
405
406
  end
406
407
 
408
+ def enable_sidekiq?
409
+ !!get(:enable_sidekiq)
410
+ end
411
+
407
412
  def user_config
408
413
  @user_config ||= UserConfig.new(self)
409
414
  end
@@ -445,6 +450,8 @@ module Skylight::Core
445
450
  when /^info$/i then Logger::INFO
446
451
  when /^warn$/i then Logger::WARN
447
452
  when /^error$/i then Logger::ERROR
453
+ when /^fatal$/i then Logger::FATAL
454
+ else Logger::ERROR
448
455
  end
449
456
  end
450
457
  end
@@ -42,7 +42,6 @@ module Skylight
42
42
  def self.broken!
43
43
  registered.each(&:broken!)
44
44
  end
45
-
46
45
  end
47
46
  end
48
47
  end
@@ -107,6 +107,8 @@ module Skylight::Core
107
107
  config.gc.enable
108
108
  @subscriber.register!
109
109
 
110
+ ActiveSupport::Notifications.instrument("started_instrumenter.skylight", instrumenter: self)
111
+
110
112
  self
111
113
 
112
114
  rescue Exception => e
@@ -124,7 +124,7 @@ module Skylight::Core
124
124
 
125
125
  def make_request_id(request_id)
126
126
  if request_id && !request_id.empty?
127
- request_id.gsub(/[^\w\-]/, "".freeze).first(255)
127
+ request_id.gsub(/[^\w\-]/, "".freeze)[0...255]
128
128
  else
129
129
  internal_request_id
130
130
  end
@@ -21,7 +21,7 @@ module Skylight::Core
21
21
  meta[:adapter] = config[:adapter]
22
22
  meta[:database] = config[:database]
23
23
  rescue => e
24
- warn "Unable to get ActiveRecord config; e=#{e}"
24
+ trace.instrumenter.warn "Unable to get ActiveRecord config; e=#{e}"
25
25
  end
26
26
 
27
27
  [name, title, description, meta]
@@ -8,6 +8,8 @@ module Skylight::Core
8
8
  require "skylight/core/normalizers/grape/endpoint_#{type}"
9
9
  end
10
10
 
11
+ require 'skylight/core/normalizers/grape/format_response'
12
+
11
13
  private
12
14
 
13
15
  def get_method(endpoint)
@@ -27,4 +29,4 @@ module Skylight::Core
27
29
  end
28
30
  end
29
31
  end
30
- end
32
+ end
@@ -0,0 +1,21 @@
1
+ module Skylight::Core
2
+ module Normalizers
3
+ module Grape
4
+ class FormatResponse < Normalizer
5
+ register "format_response.grape"
6
+
7
+ CAT = "view.grape.format_response".freeze
8
+
9
+ def normalize(_trace, _name, payload)
10
+ if (formatter = payload[:formatter])
11
+ title = formatter.is_a?(Module) ? formatter.to_s : formatter.class.to_s
12
+ [CAT, title, nil]
13
+ else
14
+ :skip
15
+ end
16
+ end
17
+
18
+ end
19
+ end
20
+ end
21
+ end
@@ -36,13 +36,21 @@ module Skylight::Core
36
36
  spans = Skylight::Core::Fanout.instrument(title: name, category: "#{category}")
37
37
  resp = call_without_sk(*args, &block)
38
38
 
39
- Skylight::Core::Middleware.with_after_close(resp) do
39
+ proxied_response = Skylight::Core::Middleware.with_after_close(resp) do
40
40
  Skylight::Core::Fanout.done(spans)
41
41
  end
42
- rescue Exception => e
42
+ rescue Exception => err
43
43
  # FIXME: Log this?
44
- Skylight::Core::Fanout.done(spans, exception_object: e)
44
+ Skylight::Core::Fanout.done(spans, exception_object: err)
45
45
  raise
46
+ ensure
47
+ unless err || proxied_response
48
+ # If we've gotten to this point, the most likely scenario is that
49
+ # a throw/catch has bypassed a portion of the callstack. Since these spans would not otherwise
50
+ # be closed, mark them deferred to indicate that they should be implicitly closed.
51
+ # See Core::Trace#deferred_spans or Core::Trace#stop for more information.
52
+ Skylight::Core::Fanout.done(spans, defer: true)
53
+ end
46
54
  end
47
55
  end
48
56
  RUBY
@@ -10,7 +10,7 @@ module Skylight::Core
10
10
  def render(*args, &block)
11
11
  opts = {
12
12
  category: "view.render.template",
13
- title: options[:sky_virtual_path] || "Unknown template name"
13
+ title: options[:sky_virtual_path] || basename || "Unknown template name"
14
14
  }
15
15
 
16
16
  Skylight::Core::Fanout.instrument(opts) do
@@ -0,0 +1,41 @@
1
+ module Skylight
2
+ module Core
3
+ module Sidekiq
4
+ def self.add_middleware(instrumentable)
5
+ ::Sidekiq.configure_server do |sidekiq_config|
6
+ instrumentable.debug "Adding Sidekiq Middleware"
7
+
8
+ sidekiq_config.server_middleware do |chain|
9
+ # Put it at the front
10
+ chain.prepend ServerMiddleware, instrumentable
11
+ end
12
+ end
13
+ end
14
+
15
+ class ServerMiddleware
16
+ include Util::Logging
17
+
18
+ def initialize(instrumentable)
19
+ @instrumentable = instrumentable
20
+ end
21
+
22
+ def call(_worker, job, queue)
23
+ t { "Sidekiq middleware beginning trace" }
24
+ job_class = job['wrapped'] || job['class']
25
+ title = "#{job_class}#perform"
26
+ segment = queue != 'default' ? "<sk-segment>#{queue}</sk-segment>" : ""
27
+ @instrumentable.trace("#{title}#{segment}", 'app.sidekiq.worker', title) do
28
+ yield
29
+ end
30
+ end
31
+ end
32
+
33
+ ActiveSupport::Notifications.subscribe("started_instrumenter.skylight") \
34
+ do |_name, _started, _finished, _unique_id, payload|
35
+ if payload[:instrumenter].config.enable_sidekiq?
36
+ add_middleware(payload[:instrumenter])
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -7,32 +7,22 @@ module Skylight::Core
7
7
 
8
8
  def initialize(config, instrumenter)
9
9
  @config = config
10
- @subscriber = nil
11
10
  @normalizers = Normalizers.build(config)
12
11
  @instrumenter = instrumenter
12
+ @subscribers = []
13
13
  end
14
14
 
15
15
  def register!
16
- unregister! if @subscriber
17
- pattern = ArrayPattern.new(@normalizers.keys)
18
- @subscriber = ActiveSupport::Notifications.subscribe pattern, self
16
+ unregister!
17
+ @normalizers.keys.each do |key|
18
+ @subscribers << ActiveSupport::Notifications.subscribe(key, self)
19
+ end
19
20
  end
20
21
 
21
22
  def unregister!
22
- ActiveSupport::Notifications.unsubscribe @subscriber
23
- @subscriber = nil
24
- end
25
-
26
- class ArrayPattern
27
-
28
- def initialize(keys)
29
- @keys = Set.new keys
23
+ until @subscribers.empty?
24
+ ActiveSupport::Notifications.unsubscribe @subscribers.shift
30
25
  end
31
-
32
- def ===(item)
33
- @keys.include?(item)
34
- end
35
-
36
26
  end
37
27
 
38
28
  #
@@ -57,10 +47,8 @@ module Skylight::Core
57
47
 
58
48
  unless result == :skip
59
49
  case result.size
60
- when 4
50
+ when 3, 4
61
51
  cat, title, desc, meta = result
62
- when 3
63
- cat, title, desc = result
64
52
  else
65
53
  raise "Invalid normalizer result: #{result.inspect}"
66
54
  end
@@ -122,6 +122,11 @@ module Skylight::Core
122
122
 
123
123
  return if broken?
124
124
 
125
+ if meta && meta[:defer]
126
+ deferred_spans[span] ||= (Util::Clock.nanos - gc_time)
127
+ return
128
+ end
129
+
125
130
  if meta && (meta[:exception_object] || meta[:exception])
126
131
  native_span_set_exception(span, meta[:exception_object], meta[:exception])
127
132
  end
@@ -201,37 +206,59 @@ module Skylight::Core
201
206
  sp
202
207
  end
203
208
 
209
+ # Middleware spans that were interrupted by a throw/catch should be cached here.
210
+ # keys: span ids
211
+ # values: nsec timestamp at which the span was cached here.
212
+ def deferred_spans
213
+ @deferred_spans ||= {}
214
+ end
215
+
204
216
  def stop(span, time)
205
217
  t { "stopping span: #{span}" }
206
218
 
207
- expected = @spans.pop
208
- unless span == expected
209
- message = "[E0001] Spans were closed out of order. Expected to see '#{native_span_get_title(expected)}', " \
210
- "but got '#{native_span_get_title(span)}' instead."
211
-
212
- if native_span_get_category(span) == "rack.middleware" &&
213
- Probes.installed.keys.include?("ActionDispatch::MiddlewareStack::Middleware")
214
- if Probes::Middleware::Probe.disabled?
215
- message << "\nWe disabled the Middleware probe but unfortunately, this didn't solve the issue."
216
- else
217
- Probes::Middleware::Probe.disable!
218
- message << "\n#{native_span_get_title(span)} may be a Middleware that doesn't fully conform " \
219
- "to the Rack SPEC. We've disabled the Middleware probe to see if that resolves the issue."
220
- end
221
- end
219
+ # If `stop` is called for a span that is not the last item in the stack,
220
+ # check to see if the last item has been marked as deferred. If so, close
221
+ # that span first, then try to close the original.
222
+ while deferred_spans[expected = @spans.pop]
223
+ normalized_stop(expected, deferred_spans.delete(expected))
224
+ end
222
225
 
223
- message << "\nThis request will not be tracked. Please contact support@skylight.io for more information."
226
+ handle_unexpected_stop(expected, span) unless span == expected
224
227
 
225
- error message
228
+ normalized_stop(span, time)
229
+ nil
230
+ end
226
231
 
227
- t { "expected=#{expected}, actual=#{span}" }
232
+ def normalized_stop(span, time)
233
+ time = self.class.normalize_time(time)
234
+ native_stop_span(span, time)
235
+ end
228
236
 
229
- broken!
237
+ # Originally extracted from `stop`.
238
+ # If we attempt to close spans out of order, and it appears to be a middleware issue,
239
+ # disable the middleware probe and mark trace as broken.
240
+ def handle_unexpected_stop(expected, span)
241
+ message = "[E0001] Spans were closed out of order. Expected to see '#{native_span_get_title(expected)}', " \
242
+ "but got '#{native_span_get_title(span)}' instead."
243
+
244
+ if native_span_get_category(span) == "rack.middleware" &&
245
+ Probes.installed.keys.include?("ActionDispatch::MiddlewareStack::Middleware")
246
+ if Probes::Middleware::Probe.disabled?
247
+ message << "\nWe disabled the Middleware probe but unfortunately, this didn't solve the issue."
248
+ else
249
+ Probes::Middleware::Probe.disable!
250
+ message << "\n#{native_span_get_title(span)} may be a Middleware that doesn't fully conform " \
251
+ "to the Rack SPEC. We've disabled the Middleware probe to see if that resolves the issue."
252
+ end
230
253
  end
231
254
 
232
- time = self.class.normalize_time(time)
233
- native_stop_span(span, time)
234
- nil
255
+ message << "\nThis request will not be tracked. Please contact support@skylight.io for more information."
256
+
257
+ error message
258
+
259
+ t { "expected=#{expected}, actual=#{span}" }
260
+
261
+ broken!
235
262
  end
236
263
 
237
264
  def gc_time
@@ -29,7 +29,7 @@ module Skylight::Core
29
29
  end
30
30
 
31
31
  def disable_dev_warning?
32
- disable_dev_warning
32
+ disable_dev_warning || ENV['SKYLIGHT_DISABLE_DEV_WARNING'] =~ /^true$/i
33
33
  end
34
34
 
35
35
  def disable_env_warning?
@@ -1,6 +1,6 @@
1
1
  module Skylight
2
2
  module Core
3
- VERSION = '2.0.1'
3
+ VERSION = '2.0.2.beta'
4
4
  end
5
5
  end
6
6
 
data/lib/skylight/core.rb CHANGED
@@ -67,6 +67,7 @@ module Skylight
67
67
  require 'skylight/core/vm/gc'
68
68
  require 'skylight/core/util'
69
69
  require 'skylight/core/middleware'
70
+ require 'skylight/core/sidekiq'
70
71
  require 'skylight/core/subscriber'
71
72
  require 'skylight/core/instrumentable'
72
73
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: skylight-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 2.0.2.beta
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tilde, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-05-01 00:00:00.000000000 Z
11
+ date: 2018-05-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -184,6 +184,7 @@ files:
184
184
  - lib/skylight/core/normalizers/grape/endpoint_render.rb
185
185
  - lib/skylight/core/normalizers/grape/endpoint_run.rb
186
186
  - lib/skylight/core/normalizers/grape/endpoint_run_filters.rb
187
+ - lib/skylight/core/normalizers/grape/format_response.rb
187
188
  - lib/skylight/core/normalizers/moped/query.rb
188
189
  - lib/skylight/core/normalizers/render.rb
189
190
  - lib/skylight/core/normalizers/sequel/sql.rb
@@ -210,6 +211,7 @@ files:
210
211
  - lib/skylight/core/probes/sinatra.rb
211
212
  - lib/skylight/core/probes/tilt.rb
212
213
  - lib/skylight/core/railtie.rb
214
+ - lib/skylight/core/sidekiq.rb
213
215
  - lib/skylight/core/subscriber.rb
214
216
  - lib/skylight/core/test.rb
215
217
  - lib/skylight/core/trace.rb
@@ -244,9 +246,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
244
246
  version: 2.2.7
245
247
  required_rubygems_version: !ruby/object:Gem::Requirement
246
248
  requirements:
247
- - - ">="
249
+ - - ">"
248
250
  - !ruby/object:Gem::Version
249
- version: '0'
251
+ version: 1.3.1
250
252
  requirements: []
251
253
  rubyforge_project:
252
254
  rubygems_version: 2.7.6