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