skylight-core 2.0.0.beta3 → 2.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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/lib/skylight/core.rb +1 -0
  3. data/lib/skylight/core/config.rb +2 -0
  4. data/lib/skylight/core/deprecation.rb +15 -0
  5. data/lib/skylight/core/instrumentable.rb +8 -0
  6. data/lib/skylight/core/instrumenter.rb +20 -12
  7. data/lib/skylight/core/middleware.rb +46 -14
  8. data/lib/skylight/core/normalizers.rb +34 -86
  9. data/lib/skylight/core/normalizers/action_view/render_collection.rb +2 -0
  10. data/lib/skylight/core/normalizers/action_view/render_partial.rb +2 -0
  11. data/lib/skylight/core/normalizers/action_view/render_template.rb +2 -0
  12. data/lib/skylight/core/normalizers/render.rb +77 -0
  13. data/lib/skylight/core/probes.rb +73 -73
  14. data/lib/skylight/core/probes/action_controller.rb +1 -1
  15. data/lib/skylight/core/probes/action_dispatch.rb +1 -0
  16. data/lib/skylight/core/probes/action_dispatch/request_id.rb +31 -0
  17. data/lib/skylight/core/probes/action_view.rb +1 -1
  18. data/lib/skylight/core/probes/active_model_serializers.rb +1 -1
  19. data/lib/skylight/core/probes/elasticsearch.rb +1 -1
  20. data/lib/skylight/core/probes/excon.rb +1 -1
  21. data/lib/skylight/core/probes/faraday.rb +1 -1
  22. data/lib/skylight/core/probes/httpclient.rb +1 -1
  23. data/lib/skylight/core/probes/middleware.rb +19 -3
  24. data/lib/skylight/core/probes/mongo.rb +1 -1
  25. data/lib/skylight/core/probes/mongoid.rb +3 -3
  26. data/lib/skylight/core/probes/moped.rb +1 -1
  27. data/lib/skylight/core/probes/net_http.rb +1 -1
  28. data/lib/skylight/core/probes/redis.rb +1 -1
  29. data/lib/skylight/core/probes/sequel.rb +1 -1
  30. data/lib/skylight/core/probes/sinatra.rb +1 -1
  31. data/lib/skylight/core/probes/tilt.rb +1 -1
  32. data/lib/skylight/core/test.rb +95 -82
  33. data/lib/skylight/core/trace.rb +48 -19
  34. data/lib/skylight/core/user_config.rb +1 -0
  35. data/lib/skylight/core/util.rb +0 -1
  36. data/lib/skylight/core/util/logging.rb +12 -4
  37. data/lib/skylight/core/version.rb +1 -1
  38. metadata +9 -8
  39. data/lib/skylight/core/normalizers/couch_potato/query.rb +0 -20
  40. data/lib/skylight/core/probes/grape.rb +0 -80
  41. data/lib/skylight/core/util/deploy.rb +0 -132
@@ -8,14 +8,14 @@ module Skylight::Core
8
8
  version = Gem::Version.new(::Mongoid::VERSION)
9
9
 
10
10
  if version < Gem::Version.new("5.0")
11
- require 'skylight/core/probes/moped'
11
+ Skylight::Core::Probes.probe(:moped)
12
12
  else
13
- require 'skylight/core/probes/mongo'
13
+ Skylight::Core::Probes.probe(:mongo)
14
14
  end
15
15
  end
16
16
  end
17
17
  end
18
18
 
19
- register("Mongoid", "mongoid", Mongoid::Probe.new)
19
+ register(:mongoid, "Mongoid", "mongoid", Mongoid::Probe.new)
20
20
  end
21
21
  end
@@ -34,6 +34,6 @@ module Skylight::Core
34
34
  end
35
35
  end
36
36
 
37
- register("Moped", "moped", Moped::Probe.new)
37
+ register(:moped, "Moped", "moped", Moped::Probe.new)
38
38
  end
39
39
  end
@@ -59,6 +59,6 @@ module Skylight::Core
59
59
  end
60
60
  end
61
61
 
62
- register("Net::HTTP", "net/http", NetHTTP::Probe.new)
62
+ register(:net_http, "Net::HTTP", "net/http", NetHTTP::Probe.new)
63
63
  end
64
64
  end
@@ -66,6 +66,6 @@ module Skylight::Core
66
66
  end
67
67
  end
68
68
 
69
- register("Redis", "redis", Redis::Probe.new)
69
+ register(:redis, "Redis", "redis", Redis::Probe.new)
70
70
  end
71
71
  end
@@ -28,6 +28,6 @@ module Skylight::Core
28
28
  end
29
29
  end
30
30
 
31
- register("Sequel", "sequel", Sequel::Probe.new)
31
+ register(:sequel, "Sequel", "sequel", Sequel::Probe.new)
32
32
  end
33
33
  end
@@ -64,6 +64,6 @@ module Skylight::Core
64
64
  end
65
65
  end
66
66
 
67
- register("Sinatra::Base", "sinatra/base", Sinatra::Probe.new)
67
+ register(:sinatra, "Sinatra::Base", "sinatra/base", Sinatra::Probe.new)
68
68
  end
69
69
  end
@@ -22,6 +22,6 @@ module Skylight::Core
22
22
  end
23
23
  end
24
24
 
25
- register("Tilt::Template", "tilt/template", Tilt::Probe.new)
25
+ register(:tilt, "Tilt::Template", "tilt/template", Tilt::Probe.new)
26
26
  end
27
27
  end
@@ -7,94 +7,107 @@ module Skylight
7
7
  config_opts[:mock_submission] ||= callback || proc {}
8
8
  config = config_class.load(config_opts)
9
9
 
10
- mock_instrumenter_klass = Class.new(instrumenter_class) do
11
- def self.trace_class
12
- @trace_class ||= Class.new(super) do
13
- def self.native_new(start, _uuid, endpoint, meta)
14
- inst = allocate
15
- inst.instance_variable_set(:@start, start)
16
- inst.instance_variable_set(:@endpoint, endpoint)
17
- inst.instance_variable_set(:@starting_endpoint, endpoint)
18
- inst.instance_variable_set(:@meta, meta)
19
- inst
20
- end
21
-
22
- attr_reader :endpoint, :starting_endpoint, :meta
23
-
24
- def mock_spans
25
- @mock_spans ||= []
26
- end
27
-
28
- def native_get_started_at
29
- @start
30
- end
31
-
32
- def native_set_endpoint(endpoint)
33
- @endpoint = endpoint
34
- end
35
-
36
- def native_start_span(time, cat)
37
- span = {
38
- start: time,
39
- cat: cat
40
- }
41
- mock_spans << span
42
- # Return integer like the native method does
43
- mock_spans.index(span)
44
- end
45
-
46
- def native_span_set_title(sp, title)
47
- mock_spans[sp][:title] = title
48
-
49
- end
50
-
51
- def native_span_set_description(sp, desc)
52
- mock_spans[sp][:desc] = desc
53
- end
54
-
55
- def native_span_set_meta(sp, meta)
56
- mock_spans[sp][:meta] = meta
57
- end
58
-
59
- def native_span_started(sp)
60
- end
61
-
62
- def native_span_set_exception(sp, exception_object, exception)
63
- mock_spans[sp][:exception_object] = exception_object
64
- mock_spans[sp][:exception] = exception
65
- end
66
-
67
- def native_stop_span(span, time)
68
- span = mock_spans[span]
69
- span[:duration] = time - span[:start]
70
- nil
10
+ unless respond_to?(:__original_instrumenter_class)
11
+ class_eval do
12
+ class << self
13
+ alias __original_instrumenter_class instrumenter_class
14
+
15
+ def instrumenter_class
16
+ @instrumenter_class ||= Class.new(__original_instrumenter_class) do
17
+ def self.name
18
+ "Mocked Instrumenter"
19
+ end
20
+
21
+ def self.native_new(*)
22
+ allocate
23
+ end
24
+
25
+ def self.trace_class
26
+ @trace_class ||= Class.new(super) do
27
+ def self.native_new(start, _uuid, endpoint, meta)
28
+ inst = allocate
29
+ inst.instance_variable_set(:@start, start)
30
+ inst.instance_variable_set(:@endpoint, endpoint)
31
+ inst.instance_variable_set(:@starting_endpoint, endpoint)
32
+ inst.instance_variable_set(:@meta, meta)
33
+ inst
34
+ end
35
+
36
+ attr_reader :endpoint, :starting_endpoint, :meta
37
+
38
+ def mock_spans
39
+ @mock_spans ||= []
40
+ end
41
+
42
+ def native_get_started_at
43
+ @start
44
+ end
45
+
46
+ def native_set_endpoint(endpoint)
47
+ @endpoint = endpoint
48
+ end
49
+
50
+ def native_start_span(time, cat)
51
+ span = {
52
+ start: time,
53
+ cat: cat
54
+ }
55
+ mock_spans << span
56
+ # Return integer like the native method does
57
+ mock_spans.index(span)
58
+ end
59
+
60
+ def native_span_set_title(sp, title)
61
+ mock_spans[sp][:title] = title
62
+
63
+ end
64
+
65
+ def native_span_set_description(sp, desc)
66
+ mock_spans[sp][:desc] = desc
67
+ end
68
+
69
+ def native_span_set_meta(sp, meta)
70
+ mock_spans[sp][:meta] = meta
71
+ end
72
+
73
+ def native_span_started(sp)
74
+ end
75
+
76
+ def native_span_set_exception(sp, exception_object, exception)
77
+ mock_spans[sp][:exception_object] = exception_object
78
+ mock_spans[sp][:exception] = exception
79
+ end
80
+
81
+ def native_stop_span(span, time)
82
+ span = mock_spans[span]
83
+ span[:duration] = time - span[:start]
84
+ nil
85
+ end
86
+ end
87
+ end
88
+
89
+ def native_start
90
+ true
91
+ end
92
+
93
+ def native_submit_trace(trace)
94
+ config[:mock_submission].call(trace)
95
+ end
96
+
97
+ def native_stop
98
+ end
99
+
100
+ def limited_description(description)
101
+ description
102
+ end
103
+ end
71
104
  end
72
105
  end
73
106
  end
74
-
75
- def self.native_new(*)
76
- allocate
77
- end
78
-
79
- def native_start
80
- true
81
- end
82
-
83
- def native_submit_trace(trace)
84
- config[:mock_submission].call(trace)
85
- end
86
-
87
- def native_stop
88
- end
89
-
90
- def limited_description(description)
91
- description
92
- end
93
107
  end
94
108
 
95
- @instrumenter = mock_instrumenter_klass.new(config).start!
109
+ start!(config)
96
110
  end
97
-
98
111
  end
99
112
  end
100
113
  end
@@ -1,3 +1,5 @@
1
+ require 'securerandom'
2
+
1
3
  module Skylight::Core
2
4
  class Trace
3
5
  GC_CAT = 'noise.gc'.freeze
@@ -5,10 +7,13 @@ module Skylight::Core
5
7
  include Util::Logging
6
8
 
7
9
  attr_reader :instrumenter, :endpoint, :notifications, :meta
10
+ attr_accessor :uuid
8
11
 
9
12
  def self.new(instrumenter, endpoint, start, cat, title=nil, desc=nil, meta=nil)
10
- inst = native_new(normalize_time(start), "TODO", endpoint, meta)
13
+ uuid = SecureRandom.uuid
14
+ inst = native_new(normalize_time(start), uuid, endpoint, meta)
11
15
  inst.send(:initialize, instrumenter, cat, title, desc, meta)
16
+ inst.uuid = uuid
12
17
  inst.endpoint = endpoint
13
18
  inst
14
19
  end
@@ -40,6 +45,10 @@ module Skylight::Core
40
45
  @gc = config.gc.track unless ENV.key?("SKYLIGHT_DISABLE_GC_TRACKING")
41
46
  end
42
47
 
48
+ def log_context
49
+ @log_context ||= { trace: uuid }
50
+ end
51
+
43
52
  def endpoint=(value)
44
53
  @endpoint = value
45
54
  native_set_endpoint(value)
@@ -54,6 +63,11 @@ module Skylight::Core
54
63
  !!@broken
55
64
  end
56
65
 
66
+ def maybe_broken(e)
67
+ error "failed to instrument span; msg=%s; endpoint=%s", e.message, endpoint
68
+ broken!
69
+ end
70
+
57
71
  def record(cat, title=nil, desc=nil)
58
72
  return if broken?
59
73
 
@@ -68,8 +82,7 @@ module Skylight::Core
68
82
 
69
83
  nil
70
84
  rescue => e
71
- error "failed to record span; msg=%s", e.message
72
- broken!
85
+ maybe_broken(e)
73
86
  nil
74
87
  end
75
88
 
@@ -93,8 +106,7 @@ module Skylight::Core
93
106
 
94
107
  start(now - gc_time, cat, title, desc, meta)
95
108
  rescue => e
96
- error "failed to instrument span; msg=%s", e.message
97
- broken!
109
+ maybe_broken(e)
98
110
  nil
99
111
  end
100
112
 
@@ -104,7 +116,10 @@ module Skylight::Core
104
116
  end
105
117
 
106
118
  def done(span, meta=nil)
119
+ # `span` will be `nil` if we failed to start instrumenting, such as in
120
+ # the case of too many spans in a request.
107
121
  return unless span
122
+
108
123
  return if broken?
109
124
 
110
125
  if meta && (meta[:exception_object] || meta[:exception])
@@ -113,12 +128,13 @@ module Skylight::Core
113
128
 
114
129
  stop(span, Util::Clock.nanos - gc_time)
115
130
  rescue => e
116
- error "failed to close span; msg=%s", e.message
131
+ error "failed to close span; msg=%s; endpoint=%s", e.message, endpoint
117
132
  broken!
118
133
  nil
119
134
  end
120
135
 
121
136
  def release
137
+ t { "release; is_current=#{@instrumenter.current_trace == self}" }
122
138
  return unless @instrumenter.current_trace == self
123
139
  @instrumenter.current_trace = nil
124
140
  end
@@ -129,28 +145,28 @@ module Skylight::Core
129
145
  end
130
146
 
131
147
  def traced
132
- time = gc_time
148
+ gc = gc_time
133
149
  now = Util::Clock.nanos
134
-
135
- if time > 0
136
- t { fmt "tracking GC time; duration=%d", time }
137
- stop(start(now - time, GC_CAT, nil, nil, nil), now)
138
- end
139
-
150
+ track_gc(gc, now)
140
151
  stop(@root, now)
141
152
  end
142
153
 
143
154
  def submit
144
- t { "submitting trace; broken=#{broken?}" }
155
+ t { "submitting trace" }
145
156
 
146
- return if broken?
157
+ # This must always be called to clean up properly
158
+ release
159
+
160
+ if broken?
161
+ t { "broken, not submitting" }
162
+ return
163
+ end
147
164
 
148
165
  if @submitted
149
166
  t { "already submitted" }
150
167
  return
151
168
  end
152
169
 
153
- release
154
170
  @submitted = true
155
171
 
156
172
  traced
@@ -163,6 +179,13 @@ module Skylight::Core
163
179
 
164
180
  private
165
181
 
182
+ def track_gc(time, now)
183
+ if time > 0
184
+ t { fmt "tracking GC time; duration=%d", time }
185
+ stop(start(now - time, GC_CAT, nil, nil, nil), now)
186
+ end
187
+ end
188
+
166
189
  def start(time, cat, title, desc, meta, opts={})
167
190
  time = self.class.normalize_time(time) unless opts[:normalize] == false
168
191
 
@@ -186,9 +209,15 @@ module Skylight::Core
186
209
  message = "[E0001] Spans were closed out of order. Expected to see '#{native_span_get_title(expected)}', " \
187
210
  "but got '#{native_span_get_title(span)}' instead."
188
211
 
189
- if native_span_get_category(span) == "rack.middleware"
190
- message << "\n#{native_span_get_title(span)} may be a Middleware that doesn't fully conform " \
191
- "to the Rack SPEC."
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
192
221
  end
193
222
 
194
223
  message << "\nThis request will not be tracked. Please contact support@skylight.io for more information."
@@ -8,6 +8,7 @@ module Skylight::Core
8
8
 
9
9
  def initialize(config)
10
10
  @config = config
11
+ @file_path = nil
11
12
  reload
12
13
  end
13
14
 
@@ -4,7 +4,6 @@ module Skylight::Core
4
4
  # Used from the main lib
5
5
  require 'skylight/core/util/allocation_free'
6
6
  require 'skylight/core/util/clock'
7
- require 'skylight/core/util/deploy'
8
7
  require 'skylight/core/util/logging'
9
8
 
10
9
  # Used from the CLI
@@ -9,7 +9,7 @@ module Skylight::Core
9
9
  end
10
10
 
11
11
  def write(*args)
12
- STDERR.write *args
12
+ STDERR.write(*args)
13
13
 
14
14
  # Try to avoid writing to STDOUT/STDERR twice
15
15
  logger_logdev = @logger.instance_variable_get(:@logdev)
@@ -25,6 +25,10 @@ module Skylight::Core
25
25
 
26
26
  module Logging
27
27
 
28
+ def log_context
29
+ {}
30
+ end
31
+
28
32
  def log_env_prefix
29
33
  if c = config_for_logging
30
34
  c.class.env_prefix
@@ -114,6 +118,8 @@ module Skylight::Core
114
118
  c = config_for_logging
115
119
  logger = c ? c.logger : nil
116
120
 
121
+ msg = log_context.map{|(k,v)| "#{k}=#{v}; " }.join << msg
122
+
117
123
  if logger
118
124
  if logger.respond_to?(level)
119
125
  if args.length > 0
@@ -128,9 +134,11 @@ module Skylight::Core
128
134
  end
129
135
 
130
136
  # Fallback
131
- module_name = self.is_a?(Module) ? name : self.class.name
132
- root_name = module_name.split('::').first.upcase
133
- puts sprintf("[#{root_name}] #{msg}", *args)
137
+ if module_name = self.is_a?(Module) ? name : self.class.name
138
+ root_name = module_name.split('::').first.upcase
139
+ msg.prepend("[#{root_name}] ")
140
+ end
141
+ puts sprintf(msg, *args)
134
142
  rescue Exception => e
135
143
  if trace?
136
144
  puts "[ERROR] #{e.message}"