skylight-core 2.0.0.beta1
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 +7 -0
- data/lib/skylight/core/config.rb +454 -0
- data/lib/skylight/core/errors.rb +6 -0
- data/lib/skylight/core/fanout.rb +44 -0
- data/lib/skylight/core/formatters/http.rb +23 -0
- data/lib/skylight/core/gc.rb +107 -0
- data/lib/skylight/core/instrumentable.rb +144 -0
- data/lib/skylight/core/instrumenter.rb +249 -0
- data/lib/skylight/core/middleware.rb +101 -0
- data/lib/skylight/core/normalizers/action_controller/process_action.rb +50 -0
- data/lib/skylight/core/normalizers/action_controller/send_file.rb +50 -0
- data/lib/skylight/core/normalizers/action_view/render_collection.rb +22 -0
- data/lib/skylight/core/normalizers/action_view/render_partial.rb +21 -0
- data/lib/skylight/core/normalizers/action_view/render_template.rb +21 -0
- data/lib/skylight/core/normalizers/active_job/enqueue_at.rb +21 -0
- data/lib/skylight/core/normalizers/active_model_serializers/render.rb +26 -0
- data/lib/skylight/core/normalizers/active_record/instantiation.rb +17 -0
- data/lib/skylight/core/normalizers/active_record/sql.rb +33 -0
- data/lib/skylight/core/normalizers/active_support/cache.rb +20 -0
- data/lib/skylight/core/normalizers/active_support/cache_clear.rb +16 -0
- data/lib/skylight/core/normalizers/active_support/cache_decrement.rb +16 -0
- data/lib/skylight/core/normalizers/active_support/cache_delete.rb +16 -0
- data/lib/skylight/core/normalizers/active_support/cache_exist.rb +16 -0
- data/lib/skylight/core/normalizers/active_support/cache_fetch_hit.rb +16 -0
- data/lib/skylight/core/normalizers/active_support/cache_generate.rb +16 -0
- data/lib/skylight/core/normalizers/active_support/cache_increment.rb +16 -0
- data/lib/skylight/core/normalizers/active_support/cache_read.rb +16 -0
- data/lib/skylight/core/normalizers/active_support/cache_read_multi.rb +16 -0
- data/lib/skylight/core/normalizers/active_support/cache_write.rb +16 -0
- data/lib/skylight/core/normalizers/coach/handler_finish.rb +36 -0
- data/lib/skylight/core/normalizers/coach/middleware_finish.rb +23 -0
- data/lib/skylight/core/normalizers/couch_potato/query.rb +20 -0
- data/lib/skylight/core/normalizers/data_mapper/sql.rb +12 -0
- data/lib/skylight/core/normalizers/default.rb +27 -0
- data/lib/skylight/core/normalizers/elasticsearch/request.rb +20 -0
- data/lib/skylight/core/normalizers/faraday/request.rb +37 -0
- data/lib/skylight/core/normalizers/grape/endpoint.rb +30 -0
- data/lib/skylight/core/normalizers/grape/endpoint_render.rb +26 -0
- data/lib/skylight/core/normalizers/grape/endpoint_run.rb +33 -0
- data/lib/skylight/core/normalizers/grape/endpoint_run_filters.rb +23 -0
- data/lib/skylight/core/normalizers/moped/query.rb +100 -0
- data/lib/skylight/core/normalizers/sequel/sql.rb +12 -0
- data/lib/skylight/core/normalizers/sql.rb +49 -0
- data/lib/skylight/core/normalizers.rb +170 -0
- data/lib/skylight/core/probes/action_controller.rb +31 -0
- data/lib/skylight/core/probes/action_view.rb +37 -0
- data/lib/skylight/core/probes/active_model_serializers.rb +55 -0
- data/lib/skylight/core/probes/elasticsearch.rb +37 -0
- data/lib/skylight/core/probes/excon/middleware.rb +72 -0
- data/lib/skylight/core/probes/excon.rb +26 -0
- data/lib/skylight/core/probes/faraday.rb +22 -0
- data/lib/skylight/core/probes/grape.rb +80 -0
- data/lib/skylight/core/probes/httpclient.rb +46 -0
- data/lib/skylight/core/probes/middleware.rb +58 -0
- data/lib/skylight/core/probes/mongo.rb +171 -0
- data/lib/skylight/core/probes/mongoid.rb +21 -0
- data/lib/skylight/core/probes/moped.rb +39 -0
- data/lib/skylight/core/probes/net_http.rb +64 -0
- data/lib/skylight/core/probes/redis.rb +71 -0
- data/lib/skylight/core/probes/sequel.rb +33 -0
- data/lib/skylight/core/probes/sinatra.rb +69 -0
- data/lib/skylight/core/probes/tilt.rb +27 -0
- data/lib/skylight/core/probes.rb +129 -0
- data/lib/skylight/core/railtie.rb +166 -0
- data/lib/skylight/core/subscriber.rb +124 -0
- data/lib/skylight/core/test.rb +98 -0
- data/lib/skylight/core/trace.rb +190 -0
- data/lib/skylight/core/user_config.rb +61 -0
- data/lib/skylight/core/util/allocation_free.rb +26 -0
- data/lib/skylight/core/util/clock.rb +56 -0
- data/lib/skylight/core/util/deploy.rb +132 -0
- data/lib/skylight/core/util/gzip.rb +21 -0
- data/lib/skylight/core/util/inflector.rb +112 -0
- data/lib/skylight/core/util/logging.rb +127 -0
- data/lib/skylight/core/util/platform.rb +77 -0
- data/lib/skylight/core/util/proxy.rb +13 -0
- data/lib/skylight/core/util.rb +14 -0
- data/lib/skylight/core/vendor/active_support/notifications.rb +207 -0
- data/lib/skylight/core/vendor/active_support/per_thread_registry.rb +52 -0
- data/lib/skylight/core/vendor/thread_safe/non_concurrent_cache_backend.rb +133 -0
- data/lib/skylight/core/vendor/thread_safe/synchronized_cache_backend.rb +76 -0
- data/lib/skylight/core/vendor/thread_safe.rb +126 -0
- data/lib/skylight/core/version.rb +6 -0
- data/lib/skylight/core/vm/gc.rb +70 -0
- data/lib/skylight/core.rb +99 -0
- metadata +254 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
module Skylight
|
|
2
|
+
module Core
|
|
3
|
+
module Instrumentable
|
|
4
|
+
|
|
5
|
+
def self.included(base)
|
|
6
|
+
base.extend(ClassMethods)
|
|
7
|
+
|
|
8
|
+
base.const_set(:LOCK, Mutex.new)
|
|
9
|
+
|
|
10
|
+
base.class_eval do
|
|
11
|
+
at_exit do
|
|
12
|
+
if RUBY_VERSION == '1.9.2'
|
|
13
|
+
# workaround for MRI bug losing exit status in at_exit block
|
|
14
|
+
# http://bugs.ruby-lang.org/issues/5218
|
|
15
|
+
exit_status = $!.status if $!.is_a?(SystemExit)
|
|
16
|
+
stop!
|
|
17
|
+
exit exit_status if exit_status
|
|
18
|
+
else
|
|
19
|
+
stop!
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
Skylight::Core::Fanout.register(base)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
module ClassMethods
|
|
28
|
+
|
|
29
|
+
def instrumenter_class
|
|
30
|
+
Skylight::Core::Instrumenter
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def instrumenter
|
|
34
|
+
@instrumenter
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def correlation_header
|
|
38
|
+
nil
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Start instrumenting
|
|
42
|
+
def start!(config=nil)
|
|
43
|
+
return @instrumenter if @instrumenter
|
|
44
|
+
|
|
45
|
+
const_get(:LOCK).synchronize do
|
|
46
|
+
return @instrumenter if @instrumenter
|
|
47
|
+
|
|
48
|
+
config ||= {}
|
|
49
|
+
config = config_class.load(config) unless config.is_a?(config_class)
|
|
50
|
+
|
|
51
|
+
@instrumenter = instrumenter_class.new(config).start!
|
|
52
|
+
end
|
|
53
|
+
rescue => e
|
|
54
|
+
message = sprintf("[SKYLIGHT] [#{VERSION}] Unable to start Instrumenter; msg=%s; class=%s", e.message, e.class)
|
|
55
|
+
if config && config.respond_to?(:logger)
|
|
56
|
+
config.logger.warn message
|
|
57
|
+
else
|
|
58
|
+
warn message
|
|
59
|
+
end
|
|
60
|
+
false
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Stop instrumenting
|
|
64
|
+
def stop!
|
|
65
|
+
const_get(:LOCK).synchronize do
|
|
66
|
+
return unless @instrumenter
|
|
67
|
+
# This is only really helpful for getting specs to pass.
|
|
68
|
+
@instrumenter.current_trace = nil
|
|
69
|
+
|
|
70
|
+
@instrumenter.shutdown
|
|
71
|
+
@instrumenter = nil
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Check tracing
|
|
76
|
+
def tracing?
|
|
77
|
+
instrumenter && instrumenter.current_trace
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Start a trace
|
|
81
|
+
def trace(endpoint=nil, cat=nil, title=nil, meta=nil)
|
|
82
|
+
unless instrumenter
|
|
83
|
+
return yield if block_given?
|
|
84
|
+
return
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
if block_given?
|
|
88
|
+
instrumenter.trace(endpoint, cat || DEFAULT_CATEGORY, title, nil, meta) { yield }
|
|
89
|
+
else
|
|
90
|
+
instrumenter.trace(endpoint, cat || DEFAULT_CATEGORY, title, nil, meta)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Instrument
|
|
95
|
+
def instrument(opts = DEFAULT_OPTIONS, &block)
|
|
96
|
+
unless instrumenter
|
|
97
|
+
return yield if block_given?
|
|
98
|
+
return
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
if Hash === opts
|
|
102
|
+
category = opts[:category] || DEFAULT_CATEGORY
|
|
103
|
+
title = opts[:title]
|
|
104
|
+
desc = opts[:description]
|
|
105
|
+
meta = opts[:meta]
|
|
106
|
+
if opts.key?(:annotations)
|
|
107
|
+
warn "call to #instrument included deprecated annotations"
|
|
108
|
+
end
|
|
109
|
+
else
|
|
110
|
+
category = DEFAULT_CATEGORY
|
|
111
|
+
title = opts.to_s
|
|
112
|
+
desc = nil
|
|
113
|
+
meta = nil
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
instrumenter.instrument(category, title, desc, meta, &block)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def span_correlation_header(span)
|
|
120
|
+
return unless instrumenter
|
|
121
|
+
instrumenter.span_correlation_header(span)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# End a span
|
|
125
|
+
def done(span, meta=nil)
|
|
126
|
+
return unless instrumenter
|
|
127
|
+
instrumenter.done(span, meta)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Temporarily disable
|
|
131
|
+
def disable
|
|
132
|
+
unless instrumenter
|
|
133
|
+
return yield if block_given?
|
|
134
|
+
return
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
instrumenter.disable { yield }
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
require 'thread'
|
|
2
|
+
require 'strscan'
|
|
3
|
+
|
|
4
|
+
module Skylight::Core
|
|
5
|
+
# @api private
|
|
6
|
+
class Instrumenter
|
|
7
|
+
KEY = :__skylight_current_trace
|
|
8
|
+
|
|
9
|
+
TOO_MANY_UNIQUES = "<too many unique descriptions>"
|
|
10
|
+
|
|
11
|
+
include Util::Logging
|
|
12
|
+
|
|
13
|
+
class TraceInfo
|
|
14
|
+
def initialize(key=KEY)
|
|
15
|
+
@key = key
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def current
|
|
19
|
+
Thread.current[@key]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def current=(trace)
|
|
23
|
+
Thread.current[@key] = trace
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
attr_reader :config, :gc, :trace_info
|
|
28
|
+
|
|
29
|
+
def self.trace_class
|
|
30
|
+
Trace
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def self.native_new
|
|
34
|
+
raise "not implemented"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def self.new(config)
|
|
38
|
+
config.validate!
|
|
39
|
+
|
|
40
|
+
inst = native_new(config.to_native_env)
|
|
41
|
+
inst.send(:initialize, config)
|
|
42
|
+
inst
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def initialize(config)
|
|
46
|
+
@gc = config.gc
|
|
47
|
+
@config = config
|
|
48
|
+
@subscriber = Subscriber.new(config, self)
|
|
49
|
+
|
|
50
|
+
key = "#{KEY}_#{self.class.trace_class.name}".gsub(/\W/, '_')
|
|
51
|
+
@trace_info = @config[:trace_info] || TraceInfo.new(key)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def native_start
|
|
55
|
+
raise "not implemented"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def native_stop
|
|
59
|
+
raise "not implemented"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def native_track_desc
|
|
63
|
+
raise "not implemented"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def native_submit_trace
|
|
67
|
+
raise "not implemented"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def current_trace
|
|
71
|
+
@trace_info.current
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def current_trace=(trace)
|
|
75
|
+
@trace_info.current = trace
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def check_install!
|
|
79
|
+
true
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def start!
|
|
83
|
+
# We do this here since we can't report these issues via Gem install without stopping install entirely.
|
|
84
|
+
check_install!
|
|
85
|
+
|
|
86
|
+
t { "starting instrumenter" }
|
|
87
|
+
|
|
88
|
+
unless config.validate_with_server
|
|
89
|
+
log_error "invalid config"
|
|
90
|
+
return
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
t { "starting native instrumenter" }
|
|
94
|
+
unless native_start
|
|
95
|
+
warn "failed to start instrumenter"
|
|
96
|
+
return
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
config.gc.enable
|
|
100
|
+
@subscriber.register!
|
|
101
|
+
|
|
102
|
+
self
|
|
103
|
+
|
|
104
|
+
rescue Exception => e
|
|
105
|
+
log_error "failed to start instrumenter; msg=%s; config=%s", e.message, config.inspect
|
|
106
|
+
t { e.backtrace.join("\n") }
|
|
107
|
+
nil
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def shutdown
|
|
111
|
+
@subscriber.unregister!
|
|
112
|
+
native_stop
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def trace(endpoint, cat, title=nil, desc=nil, meta=nil)
|
|
116
|
+
# If a trace is already in progress, continue with that one
|
|
117
|
+
if trace = @trace_info.current
|
|
118
|
+
return yield(trace) if block_given?
|
|
119
|
+
return trace
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
begin
|
|
123
|
+
trace = self.class.trace_class.new(self, endpoint, Util::Clock.nanos, cat, title, desc, meta)
|
|
124
|
+
rescue Exception => e
|
|
125
|
+
log_error e.message
|
|
126
|
+
t { e.backtrace.join("\n") }
|
|
127
|
+
return
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
@trace_info.current = trace
|
|
131
|
+
return trace unless block_given?
|
|
132
|
+
|
|
133
|
+
begin
|
|
134
|
+
yield trace
|
|
135
|
+
|
|
136
|
+
ensure
|
|
137
|
+
@trace_info.current = nil
|
|
138
|
+
t { "submitting trace" }
|
|
139
|
+
trace.submit
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def disable
|
|
144
|
+
@disabled = true
|
|
145
|
+
yield
|
|
146
|
+
ensure
|
|
147
|
+
@disabled = false
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def disabled?
|
|
151
|
+
@disabled
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def self.match?(string, regex)
|
|
155
|
+
@scanner ||= StringScanner.new('')
|
|
156
|
+
@scanner.string = string
|
|
157
|
+
@scanner.match?(regex)
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def match?(string, regex)
|
|
161
|
+
self.class.match?(string, regex)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def instrument(cat, title=nil, desc=nil, meta=nil)
|
|
165
|
+
raise ArgumentError, 'cat is required' unless cat
|
|
166
|
+
|
|
167
|
+
unless trace = @trace_info.current
|
|
168
|
+
return yield if block_given?
|
|
169
|
+
return
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
cat = cat.to_s
|
|
173
|
+
|
|
174
|
+
unless match?(cat, Skylight::CATEGORY_REGEX)
|
|
175
|
+
warn "invalid skylight instrumentation category; value=%s", cat
|
|
176
|
+
return yield if block_given?
|
|
177
|
+
return
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
cat = "other.#{cat}" unless match?(cat, Skylight::TIER_REGEX)
|
|
181
|
+
|
|
182
|
+
unless sp = trace.instrument(cat, title, desc, meta)
|
|
183
|
+
return yield if block_given?
|
|
184
|
+
return
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
return sp unless block_given?
|
|
188
|
+
|
|
189
|
+
meta = {}
|
|
190
|
+
begin
|
|
191
|
+
yield sp
|
|
192
|
+
rescue Exception => e
|
|
193
|
+
meta = { exception: [e.class.name, e.message], exception_object: e }
|
|
194
|
+
raise e
|
|
195
|
+
ensure
|
|
196
|
+
trace.done(sp, meta)
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def span_correlation_header(span)
|
|
201
|
+
return unless trace = @trace_info.current
|
|
202
|
+
trace.span_correlation_header(span)
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def done(span, meta=nil)
|
|
206
|
+
return unless trace = @trace_info.current
|
|
207
|
+
trace.done(span, meta)
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def limited_description(description)
|
|
211
|
+
endpoint = @trace_info.current.endpoint
|
|
212
|
+
|
|
213
|
+
if description
|
|
214
|
+
if native_track_desc(endpoint, description)
|
|
215
|
+
description
|
|
216
|
+
else
|
|
217
|
+
TOO_MANY_UNIQUES
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def process(trace)
|
|
223
|
+
t { fmt "processing trace" }
|
|
224
|
+
|
|
225
|
+
if ignore?(trace)
|
|
226
|
+
t { fmt "ignoring trace" }
|
|
227
|
+
return false
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
begin
|
|
231
|
+
native_submit_trace(trace)
|
|
232
|
+
true
|
|
233
|
+
rescue => e
|
|
234
|
+
warn "failed to submit trace to worker; err=%s", e
|
|
235
|
+
false
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
def ignore?(trace)
|
|
240
|
+
config.ignored_endpoints.include?(trace.endpoint.sub(%r{<sk-segment>.+</sk-segment>}, ''))
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
# Return [title, sql]
|
|
244
|
+
def process_sql(sql)
|
|
245
|
+
[nil, sql]
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
end
|
|
249
|
+
end
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
module Skylight::Core
|
|
2
|
+
# @api private
|
|
3
|
+
class Middleware
|
|
4
|
+
|
|
5
|
+
class BodyProxy
|
|
6
|
+
def initialize(body, &block)
|
|
7
|
+
@body, @block, @closed = body, block, false
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def respond_to?(*args)
|
|
11
|
+
return false if args.first.to_s =~ /^to_ary$/
|
|
12
|
+
super or @body.respond_to?(*args)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def close
|
|
16
|
+
return if @closed
|
|
17
|
+
@closed = true
|
|
18
|
+
begin
|
|
19
|
+
@body.close if @body.respond_to? :close
|
|
20
|
+
ensure
|
|
21
|
+
@block.call
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def closed?
|
|
26
|
+
@closed
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# N.B. This method is a special case to address the bug described by
|
|
30
|
+
# https://github.com/rack/rack/issues/434.
|
|
31
|
+
# We are applying this special case for #each only. Future bugs of this
|
|
32
|
+
# class will be handled by requesting users to patch their ruby
|
|
33
|
+
# implementation, to save adding too many methods in this class.
|
|
34
|
+
def each(*args, &block)
|
|
35
|
+
@body.each(*args, &block)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def method_missing(*args, &block)
|
|
39
|
+
super if args.first.to_s =~ /^to_ary$/
|
|
40
|
+
@body.__send__(*args, &block)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def self.with_after_close(resp, &block)
|
|
45
|
+
# Responses should be finished but in some situations they aren't
|
|
46
|
+
# e.g. https://github.com/ruby-grape/grape/issues/1041
|
|
47
|
+
if resp.respond_to?(:finish)
|
|
48
|
+
resp = resp.finish
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
resp[2] = BodyProxy.new(resp[2], &block)
|
|
52
|
+
resp
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
include Util::Logging
|
|
56
|
+
|
|
57
|
+
# For Util::Logging
|
|
58
|
+
attr_reader :config
|
|
59
|
+
|
|
60
|
+
def initialize(app, opts={})
|
|
61
|
+
@app = app
|
|
62
|
+
@config = opts[:config]
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def instrumentable
|
|
66
|
+
Skylight
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Allow for overwriting
|
|
70
|
+
def endpoint_name(_env)
|
|
71
|
+
"Rack"
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def endpoint_meta(_env)
|
|
75
|
+
nil
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def call(env)
|
|
79
|
+
if env["REQUEST_METHOD"] == "HEAD"
|
|
80
|
+
t { "middleware skipping HEAD" }
|
|
81
|
+
@app.call(env)
|
|
82
|
+
else
|
|
83
|
+
begin
|
|
84
|
+
t { "middleware beginning trace" }
|
|
85
|
+
trace = instrumentable.trace(endpoint_name(env), 'app.rack.request', nil, endpoint_meta(env))
|
|
86
|
+
resp = @app.call(env)
|
|
87
|
+
|
|
88
|
+
if trace
|
|
89
|
+
Middleware.with_after_close(resp) { trace.submit }
|
|
90
|
+
else
|
|
91
|
+
resp
|
|
92
|
+
end
|
|
93
|
+
rescue Exception
|
|
94
|
+
t { "middleware exception: #{trace}"}
|
|
95
|
+
trace.submit if trace
|
|
96
|
+
raise
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
module Skylight::Core
|
|
2
|
+
module Normalizers
|
|
3
|
+
module ActionController
|
|
4
|
+
# Normalizer for processing a Rails controller action
|
|
5
|
+
class ProcessAction < Normalizer
|
|
6
|
+
register "process_action.action_controller"
|
|
7
|
+
|
|
8
|
+
CAT = "app.controller.request".freeze
|
|
9
|
+
|
|
10
|
+
# Payload Keys: controller, action, params, format, method, path
|
|
11
|
+
# Additional keys available in `normalize_after`: status, view_runtime
|
|
12
|
+
# Along with ones added by probe: variant
|
|
13
|
+
|
|
14
|
+
# @param trace [Skylight::Messages::Trace::Builder]
|
|
15
|
+
# @param name [String] ignored, only present to match API
|
|
16
|
+
# @param payload [Hash]
|
|
17
|
+
# @option payload [String] :controller Controller name
|
|
18
|
+
# @option payload [String] :action Action name
|
|
19
|
+
# @return [Array]
|
|
20
|
+
def normalize(trace, name, payload)
|
|
21
|
+
trace.endpoint = controller_action(payload)
|
|
22
|
+
[ CAT, trace.endpoint, nil ]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def normalize_after(trace, span, name, payload)
|
|
26
|
+
return unless config.enable_segments?
|
|
27
|
+
|
|
28
|
+
# Show 'error' if there's an unhandled exception or if the status is 4xx or 5xx
|
|
29
|
+
if payload[:exception] || payload[:exception_object] || payload[:status].to_s =~ /^[45]/
|
|
30
|
+
segment = "error"
|
|
31
|
+
# We won't have a rendered_format if it's a `head` outside of a `respond_to` block.
|
|
32
|
+
elsif payload[:rendered_format]
|
|
33
|
+
# We only show the variant if we actually have a format
|
|
34
|
+
segment = [payload[:rendered_format], payload[:variant]].compact.flatten.join('+')
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
if segment
|
|
38
|
+
trace.endpoint += "<sk-segment>#{segment}</sk-segment>"
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def controller_action(payload)
|
|
45
|
+
"#{payload[:controller]}##{payload[:action]}"
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
module Skylight::Core
|
|
2
|
+
module Normalizers
|
|
3
|
+
module ActionController
|
|
4
|
+
|
|
5
|
+
# Temporary hacks
|
|
6
|
+
begin
|
|
7
|
+
require "action_dispatch/http/mime_type"
|
|
8
|
+
require "action_dispatch/http/mime_types"
|
|
9
|
+
require "rack/utils"
|
|
10
|
+
|
|
11
|
+
class SendFile < Normalizer
|
|
12
|
+
register "send_file.action_controller"
|
|
13
|
+
|
|
14
|
+
CAT = "app.controller.send_file".freeze
|
|
15
|
+
TITLE = "send file".freeze
|
|
16
|
+
|
|
17
|
+
def normalize(trace, name, payload)
|
|
18
|
+
path = payload[:path]
|
|
19
|
+
|
|
20
|
+
title = TITLE
|
|
21
|
+
|
|
22
|
+
# depending on normalization, we probably want this to eventually
|
|
23
|
+
# include the full path, but we need to make sure we have a good
|
|
24
|
+
# deduping strategy first.
|
|
25
|
+
desc = nil
|
|
26
|
+
|
|
27
|
+
[ CAT, title, desc ]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
OCTET_STREAM = "application/octet-stream".freeze
|
|
33
|
+
ATTACHMENT = "attachment".freeze
|
|
34
|
+
|
|
35
|
+
def initialize(*)
|
|
36
|
+
super
|
|
37
|
+
|
|
38
|
+
@mimes = Mime::SET.reduce({}) do |hash, mime|
|
|
39
|
+
hash[mime.symbol] = mime.to_s.dup.freeze
|
|
40
|
+
hash
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
rescue LoadError
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Skylight::Core
|
|
2
|
+
module Normalizers
|
|
3
|
+
module ActionView
|
|
4
|
+
# Normalizer for Rails collection rendering
|
|
5
|
+
class RenderCollection < RenderNormalizer
|
|
6
|
+
register "render_collection.action_view"
|
|
7
|
+
|
|
8
|
+
CAT = "view.render.collection".freeze
|
|
9
|
+
|
|
10
|
+
# @param trace [Skylight::Messages::Trace::Builder] ignored, only present to match API
|
|
11
|
+
# @param name [String] ignored, only present to match API
|
|
12
|
+
# @param payload (see RenderNormalizer#normalize_render)
|
|
13
|
+
# @option payload (see RenderNormalizer#normalize_render)
|
|
14
|
+
# @option payload [Integer] :count
|
|
15
|
+
# @return (see RenderNormalizer#normalize_render)
|
|
16
|
+
def normalize(trace, name, payload)
|
|
17
|
+
normalize_render(CAT, payload)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Skylight::Core
|
|
2
|
+
module Normalizers
|
|
3
|
+
module ActionView
|
|
4
|
+
# Normalizer for Rails partial rendering
|
|
5
|
+
class RenderPartial < RenderNormalizer
|
|
6
|
+
register "render_partial.action_view"
|
|
7
|
+
|
|
8
|
+
CAT = "view.render.template".freeze
|
|
9
|
+
|
|
10
|
+
# @param trace [Skylight::Messages::Trace::Builder] ignored, only present to match API
|
|
11
|
+
# @param name [String] ignored, only present to match API
|
|
12
|
+
# @param payload (see RenderNormalizer#normalize_render)
|
|
13
|
+
# @option payload (see RenderNormalizer#normalize_render)
|
|
14
|
+
# @return (see RenderNormalizer#normalize_render)
|
|
15
|
+
def normalize(trace, name, payload)
|
|
16
|
+
normalize_render(CAT, payload)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Skylight::Core
|
|
2
|
+
module Normalizers
|
|
3
|
+
module ActionView
|
|
4
|
+
# Normalizer for Rails template rendering
|
|
5
|
+
class RenderTemplate < RenderNormalizer
|
|
6
|
+
register "render_template.action_view"
|
|
7
|
+
|
|
8
|
+
CAT = "view.render.template".freeze
|
|
9
|
+
|
|
10
|
+
# @param trace [Skylight::Messages::Trace::Builder] ignored, only present to match API
|
|
11
|
+
# @param name [String] ignored, only present to match API
|
|
12
|
+
# @param payload (see RenderNormalizer#normalize_render)
|
|
13
|
+
# @option payload (see RenderNormalizer#normalize_render)
|
|
14
|
+
# @return (see RenderNormalizer#normalize_render)
|
|
15
|
+
def normalize(trace, name, payload)
|
|
16
|
+
normalize_render(CAT, payload)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Skylight::Core
|
|
2
|
+
module Normalizers
|
|
3
|
+
module ActiveJob
|
|
4
|
+
class EnqueueAt < Normalizer
|
|
5
|
+
register "enqueue_at.active_job"
|
|
6
|
+
|
|
7
|
+
CAT = "other.job.enqueue_at".freeze
|
|
8
|
+
|
|
9
|
+
def normalize(_trace, _name, payload)
|
|
10
|
+
title = "Enqueue #{payload[:job].class}"
|
|
11
|
+
|
|
12
|
+
adapter_class_name = payload[:adapter].class.name
|
|
13
|
+
adapter_name = adapter_class_name.match(/^ActiveJob::QueueAdapters::(\w+)Adapter$/)[1].underscore
|
|
14
|
+
desc = "{ adapter: '#{adapter_name}', queue: '#{payload[:job].queue_name}' }"
|
|
15
|
+
|
|
16
|
+
[ CAT, title, desc ]
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Skylight::Core
|
|
2
|
+
module Normalizers
|
|
3
|
+
module ActiveModelSerializers
|
|
4
|
+
class Render < Normalizer
|
|
5
|
+
register "render.active_model_serializers"
|
|
6
|
+
|
|
7
|
+
CAT = "view.render.active_model_serializers".freeze
|
|
8
|
+
|
|
9
|
+
def normalize(trace, name, payload)
|
|
10
|
+
serializer_class = payload[:serializer]
|
|
11
|
+
|
|
12
|
+
title = serializer_class.name.sub(/^ActiveModel::(Serializer::)?/, '')
|
|
13
|
+
|
|
14
|
+
if adapter_instance = payload[:adapter]
|
|
15
|
+
adapter_name = adapter_instance.class.name
|
|
16
|
+
.sub(/^ActiveModel::Serializer::Adapter::/, '')
|
|
17
|
+
.sub(/^ActiveModelSerializers::Adapter::/, '')
|
|
18
|
+
desc = "Adapter: #{adapter_name}"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
[ CAT, title, desc ]
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|