skylight-core 2.0.1 → 2.0.2.beta

Sign up to get free protection for your applications and to get access to all the features.
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