skylight 4.2.2 → 5.0.0.beta2
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 +4 -4
- data/CHANGELOG.md +29 -0
- data/CONTRIBUTING.md +1 -7
- data/ext/extconf.rb +6 -5
- data/ext/libskylight.yml +5 -6
- data/ext/skylight_native.c +24 -100
- data/lib/skylight.rb +204 -14
- data/lib/skylight/api.rb +7 -3
- data/lib/skylight/cli.rb +4 -3
- data/lib/skylight/cli/doctor.rb +13 -14
- data/lib/skylight/cli/merger.rb +6 -4
- data/lib/skylight/config.rb +604 -127
- data/lib/skylight/deprecation.rb +17 -0
- data/lib/skylight/errors.rb +17 -2
- data/lib/skylight/extensions.rb +107 -0
- data/lib/skylight/extensions/source_location.rb +280 -0
- data/lib/skylight/formatters/http.rb +19 -0
- data/lib/skylight/gc.rb +109 -0
- data/lib/skylight/helpers.rb +18 -2
- data/lib/skylight/instrumenter.rb +326 -15
- data/lib/skylight/middleware.rb +138 -1
- data/lib/skylight/native.rb +51 -1
- data/lib/skylight/native_ext_fetcher.rb +4 -3
- data/lib/skylight/normalizers.rb +151 -0
- data/lib/skylight/normalizers/action_controller/process_action.rb +69 -0
- data/lib/skylight/normalizers/action_controller/send_file.rb +50 -0
- data/lib/skylight/normalizers/action_dispatch/process_middleware.rb +22 -0
- data/lib/skylight/normalizers/action_dispatch/route_set.rb +27 -0
- data/lib/skylight/normalizers/action_view/render_collection.rb +24 -0
- data/lib/skylight/normalizers/action_view/render_layout.rb +25 -0
- data/lib/skylight/normalizers/action_view/render_partial.rb +23 -0
- data/lib/skylight/normalizers/action_view/render_template.rb +23 -0
- data/lib/skylight/normalizers/active_job/perform.rb +86 -0
- data/lib/skylight/normalizers/active_model_serializers/render.rb +28 -0
- data/lib/skylight/normalizers/active_record/instantiation.rb +16 -0
- data/lib/skylight/normalizers/active_record/sql.rb +12 -0
- data/lib/skylight/normalizers/active_storage.rb +30 -0
- data/lib/skylight/normalizers/active_support/cache.rb +22 -0
- data/lib/skylight/normalizers/active_support/cache_clear.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_decrement.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_delete.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_exist.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_fetch_hit.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_generate.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_increment.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_read.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_read_multi.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_write.rb +16 -0
- data/lib/skylight/normalizers/coach/handler_finish.rb +46 -0
- data/lib/skylight/normalizers/coach/middleware_finish.rb +33 -0
- data/lib/skylight/normalizers/couch_potato/query.rb +20 -0
- data/lib/skylight/normalizers/data_mapper/sql.rb +12 -0
- data/lib/skylight/normalizers/default.rb +32 -0
- data/lib/skylight/normalizers/elasticsearch/request.rb +20 -0
- data/lib/skylight/normalizers/faraday/request.rb +40 -0
- data/lib/skylight/normalizers/grape/endpoint.rb +34 -0
- data/lib/skylight/normalizers/grape/endpoint_render.rb +25 -0
- data/lib/skylight/normalizers/grape/endpoint_run.rb +41 -0
- data/lib/skylight/normalizers/grape/endpoint_run_filters.rb +22 -0
- data/lib/skylight/normalizers/grape/format_response.rb +20 -0
- data/lib/skylight/normalizers/graphiti/render.rb +22 -0
- data/lib/skylight/normalizers/graphiti/resolve.rb +31 -0
- data/lib/skylight/normalizers/graphql/base.rb +132 -0
- data/lib/skylight/normalizers/render.rb +81 -0
- data/lib/skylight/normalizers/sequel/sql.rb +12 -0
- data/lib/skylight/normalizers/sql.rb +45 -0
- data/lib/skylight/probes.rb +181 -0
- data/lib/skylight/probes/action_controller.rb +48 -0
- data/lib/skylight/probes/action_dispatch.rb +2 -0
- data/lib/skylight/probes/action_dispatch/request_id.rb +29 -0
- data/lib/skylight/probes/action_dispatch/routing/route_set.rb +28 -0
- data/lib/skylight/probes/action_view.rb +43 -0
- data/lib/skylight/probes/active_job.rb +27 -0
- data/lib/skylight/probes/active_job_enqueue.rb +35 -0
- data/lib/skylight/probes/active_model_serializers.rb +50 -0
- data/lib/skylight/probes/delayed_job.rb +148 -0
- data/lib/skylight/probes/elasticsearch.rb +38 -0
- data/lib/skylight/probes/excon.rb +25 -0
- data/lib/skylight/probes/excon/middleware.rb +66 -0
- data/lib/skylight/probes/faraday.rb +23 -0
- data/lib/skylight/probes/graphql.rb +43 -0
- data/lib/skylight/probes/httpclient.rb +44 -0
- data/lib/skylight/probes/middleware.rb +126 -0
- data/lib/skylight/probes/mongo.rb +163 -0
- data/lib/skylight/probes/mongoid.rb +13 -0
- data/lib/skylight/probes/net_http.rb +54 -0
- data/lib/skylight/probes/redis.rb +60 -0
- data/lib/skylight/probes/sequel.rb +33 -0
- data/lib/skylight/probes/sinatra.rb +63 -0
- data/lib/skylight/probes/sinatra_add_middleware.rb +10 -10
- data/lib/skylight/probes/tilt.rb +27 -0
- data/lib/skylight/railtie.rb +162 -18
- data/lib/skylight/sidekiq.rb +48 -0
- data/lib/skylight/subscriber.rb +110 -0
- data/lib/skylight/test.rb +146 -0
- data/lib/skylight/trace.rb +305 -10
- data/lib/skylight/user_config.rb +61 -0
- data/lib/skylight/util.rb +12 -0
- data/lib/skylight/util/allocation_free.rb +26 -0
- data/lib/skylight/util/clock.rb +56 -0
- data/lib/skylight/util/component.rb +5 -2
- data/lib/skylight/util/deploy.rb +7 -10
- data/lib/skylight/util/gzip.rb +20 -0
- data/lib/skylight/util/http.rb +5 -11
- data/lib/skylight/util/instrumenter_method.rb +26 -0
- data/lib/skylight/util/logging.rb +138 -0
- data/lib/skylight/util/lru_cache.rb +40 -0
- data/lib/skylight/vendor/cli/thor/rake_compat.rb +1 -1
- data/lib/skylight/version.rb +5 -1
- data/lib/skylight/vm/gc.rb +68 -0
- metadata +117 -19
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Skylight
|
|
2
|
+
module Formatters
|
|
3
|
+
module HTTP
|
|
4
|
+
# Build instrumentation options for HTTP queries
|
|
5
|
+
#
|
|
6
|
+
# @param [String] method HTTP method, e.g. get, post
|
|
7
|
+
# @param [String] scheme HTTP scheme, e.g. http, https
|
|
8
|
+
# @param [String] host Request host, e.g. example.com
|
|
9
|
+
# @param [String, Integer] port Request port
|
|
10
|
+
# @param [String] path Request path
|
|
11
|
+
# @param [String] query Request query string
|
|
12
|
+
# @return [Hash] a hash containing `:category`, `:title`, and `:annotations`
|
|
13
|
+
def self.build_opts(method, _scheme, host, _port, _path, _query)
|
|
14
|
+
{ category: "api.http.#{method.downcase}",
|
|
15
|
+
title: "#{method.upcase} #{host}" }
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
data/lib/skylight/gc.rb
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
require "skylight/util/logging"
|
|
2
|
+
|
|
3
|
+
module Skylight
|
|
4
|
+
# @api private
|
|
5
|
+
class GC
|
|
6
|
+
METHODS = %i[enable total_time].freeze
|
|
7
|
+
TH_KEY = :SK_GC_CURR_WINDOW
|
|
8
|
+
MAX_COUNT = 1000
|
|
9
|
+
MAX_TIME = 30_000_000
|
|
10
|
+
|
|
11
|
+
include Util::Logging
|
|
12
|
+
|
|
13
|
+
attr_reader :config
|
|
14
|
+
|
|
15
|
+
def initialize(config, profiler)
|
|
16
|
+
@listeners = []
|
|
17
|
+
@config = config
|
|
18
|
+
@lock = Mutex.new
|
|
19
|
+
@time = 0
|
|
20
|
+
|
|
21
|
+
if METHODS.all? { |m| profiler.respond_to?(m) }
|
|
22
|
+
@profiler = profiler
|
|
23
|
+
@time = @profiler.total_time
|
|
24
|
+
else
|
|
25
|
+
debug "disabling GC profiling"
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def enable
|
|
30
|
+
@profiler&.enable
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Total time in microseconds for GC over entire process lifetime
|
|
34
|
+
def total_time
|
|
35
|
+
@profiler ? @profiler.total_time : nil
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def track
|
|
39
|
+
if @profiler
|
|
40
|
+
win = Window.new(self)
|
|
41
|
+
|
|
42
|
+
@lock.synchronize do
|
|
43
|
+
__update
|
|
44
|
+
@listeners << win
|
|
45
|
+
|
|
46
|
+
# Cleanup any listeners that might have leaked
|
|
47
|
+
@listeners.shift until @listeners[0].time < MAX_TIME
|
|
48
|
+
|
|
49
|
+
if @listeners.length > MAX_COUNT
|
|
50
|
+
@listeners.shift
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
win
|
|
55
|
+
else
|
|
56
|
+
Window.new(nil)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def release(win)
|
|
61
|
+
@lock.synchronize do
|
|
62
|
+
@listeners.delete(win)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def update
|
|
67
|
+
@lock.synchronize do
|
|
68
|
+
__update
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
nil
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
private
|
|
75
|
+
|
|
76
|
+
def __update
|
|
77
|
+
time = @profiler.total_time
|
|
78
|
+
diff = time - @time
|
|
79
|
+
@time = time
|
|
80
|
+
|
|
81
|
+
if diff > 0
|
|
82
|
+
@listeners.each do |l|
|
|
83
|
+
l.add(diff)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
class Window
|
|
89
|
+
attr_reader :time
|
|
90
|
+
|
|
91
|
+
def initialize(global)
|
|
92
|
+
@global = global
|
|
93
|
+
@time = 0
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def update
|
|
97
|
+
@global&.update
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def add(time)
|
|
101
|
+
@time += time
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def release
|
|
105
|
+
@global&.release(self)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
data/lib/skylight/helpers.rb
CHANGED
|
@@ -135,14 +135,24 @@ module Skylight
|
|
|
135
135
|
title = (opts[:title] || title).to_s
|
|
136
136
|
desc = opts[:description].to_s if opts[:description]
|
|
137
137
|
|
|
138
|
+
# NOTE: The source location logic happens before we have have a config so we can'
|
|
139
|
+
# check if source locations are enabled. However, it only happens once so the potential impact
|
|
140
|
+
# should be minimal. This would more appropriately belong to Extensions::SourceLocation,
|
|
141
|
+
# but as that is a runtime concern, and this happens at compile time, there isn't currently
|
|
142
|
+
# a clean way to turn this on and off. The absence of the extension will cause the
|
|
143
|
+
# source_file and source_line to be removed from the trace span before it is submitted.
|
|
144
|
+
source_file, source_line = klass.instance_method(name).source_location
|
|
145
|
+
|
|
138
146
|
klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
139
147
|
alias_method :"before_instrument_#{name}", :"#{name}"
|
|
140
148
|
|
|
141
149
|
def #{name}(*args, &blk)
|
|
142
150
|
span = Skylight.instrument(
|
|
143
|
-
category:
|
|
151
|
+
category: :"#{category}",
|
|
144
152
|
title: #{title.inspect},
|
|
145
|
-
description: #{desc.inspect}
|
|
153
|
+
description: #{desc.inspect},
|
|
154
|
+
source_file: #{source_file.inspect},
|
|
155
|
+
source_line: #{source_line.inspect})
|
|
146
156
|
|
|
147
157
|
meta = {}
|
|
148
158
|
begin
|
|
@@ -154,6 +164,12 @@ module Skylight
|
|
|
154
164
|
Skylight.done(span, meta) if span
|
|
155
165
|
end
|
|
156
166
|
end
|
|
167
|
+
|
|
168
|
+
if protected_method_defined?(:"before_instrument_#{name}")
|
|
169
|
+
protected :"#{name}"
|
|
170
|
+
elsif private_method_defined?(:"before_instrument_#{name}")
|
|
171
|
+
private :"#{name}"
|
|
172
|
+
end
|
|
157
173
|
RUBY
|
|
158
174
|
end
|
|
159
175
|
|
|
@@ -1,10 +1,109 @@
|
|
|
1
|
+
require "strscan"
|
|
2
|
+
require "securerandom"
|
|
3
|
+
require "skylight/util/logging"
|
|
4
|
+
require "skylight/extensions"
|
|
5
|
+
|
|
1
6
|
module Skylight
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
7
|
+
# @api private
|
|
8
|
+
class Instrumenter
|
|
9
|
+
KEY = :__skylight_current_trace
|
|
10
|
+
|
|
11
|
+
include Util::Logging
|
|
12
|
+
|
|
13
|
+
class TraceInfo
|
|
14
|
+
def initialize(key = KEY)
|
|
15
|
+
@key = key
|
|
16
|
+
@muted_key = "#{key}_muted"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def current
|
|
20
|
+
Thread.current[@key]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def current=(trace)
|
|
24
|
+
Thread.current[@key] = trace
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# NOTE: This should only be set by the instrumenter, and only
|
|
28
|
+
# in the context of a `mute` block. Do not try to turn this
|
|
29
|
+
# flag on and off directly.
|
|
30
|
+
def muted=(val)
|
|
31
|
+
Thread.current[@muted_key] = val
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def muted?
|
|
35
|
+
!!Thread.current[@muted_key]
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
attr_reader :uuid, :config, :gc, :extensions
|
|
40
|
+
|
|
41
|
+
def self.native_new(_uuid, _config_env)
|
|
42
|
+
raise "not implemented"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def self.new(config)
|
|
46
|
+
config.validate!
|
|
47
|
+
|
|
48
|
+
uuid = SecureRandom.uuid
|
|
49
|
+
inst = native_new(uuid, config.to_native_env)
|
|
50
|
+
inst.send(:initialize, uuid, config)
|
|
51
|
+
inst
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def initialize(uuid, config)
|
|
55
|
+
@uuid = uuid
|
|
56
|
+
@gc = config.gc
|
|
57
|
+
@config = config
|
|
58
|
+
@subscriber = Skylight::Subscriber.new(config, self)
|
|
59
|
+
|
|
60
|
+
@trace_info = @config[:trace_info] || TraceInfo.new(KEY)
|
|
61
|
+
@mutex = Mutex.new
|
|
62
|
+
@extensions = Skylight::Extensions::Collection.new(@config)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def enable_extension!(name)
|
|
66
|
+
@mutex.synchronize { extensions.enable!(name) }
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def disable_extension!(name)
|
|
70
|
+
@mutex.synchronize { extensions.disable!(name) }
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def extension_enabled?(name)
|
|
74
|
+
extensions.enabled?(name)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def log_context
|
|
78
|
+
@log_context ||= { inst: uuid }
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def native_start
|
|
82
|
+
raise "not implemented"
|
|
5
83
|
end
|
|
6
84
|
|
|
7
|
-
def
|
|
85
|
+
def native_stop
|
|
86
|
+
raise "not implemented"
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def native_track_desc(_endpoint, _description)
|
|
90
|
+
raise "not implemented"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def native_submit_trace(_trace)
|
|
94
|
+
raise "not implemented"
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def current_trace
|
|
98
|
+
@trace_info.current
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def current_trace=(trace)
|
|
102
|
+
t { "setting current_trace=#{trace ? trace.uuid : 'nil'}; thread=#{Thread.current.object_id}" }
|
|
103
|
+
@trace_info.current = trace
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def validate_installation
|
|
8
107
|
# Warn if there was an error installing Skylight.
|
|
9
108
|
|
|
10
109
|
if defined?(Skylight.check_install_errors)
|
|
@@ -13,24 +112,236 @@ module Skylight
|
|
|
13
112
|
|
|
14
113
|
if !Skylight.native? && defined?(Skylight.warn_skylight_native_missing)
|
|
15
114
|
Skylight.warn_skylight_native_missing(config)
|
|
16
|
-
return
|
|
115
|
+
return false
|
|
17
116
|
end
|
|
117
|
+
|
|
118
|
+
true
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def muted=(val)
|
|
122
|
+
@trace_info.muted = val
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def muted?
|
|
126
|
+
@trace_info.muted?
|
|
18
127
|
end
|
|
19
128
|
|
|
20
|
-
def
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
if
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
129
|
+
def mute
|
|
130
|
+
old_muted = muted?
|
|
131
|
+
self.muted = true
|
|
132
|
+
yield if block_given?
|
|
133
|
+
ensure
|
|
134
|
+
self.muted = old_muted
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def unmute
|
|
138
|
+
old_muted = muted?
|
|
139
|
+
self.muted = false
|
|
140
|
+
yield if block_given?
|
|
141
|
+
ensure
|
|
142
|
+
self.muted = old_muted
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def silence_warnings(context)
|
|
146
|
+
@warnings_silenced || @mutex.synchronize do
|
|
147
|
+
@warnings_silenced ||= {}
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
@warnings_silenced[context] = true
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def warnings_silenced?(context)
|
|
154
|
+
@warnings_silenced && @warnings_silenced[context]
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
alias disable mute
|
|
158
|
+
alias disabled? muted?
|
|
159
|
+
|
|
160
|
+
def start!
|
|
161
|
+
# We do this here since we can't report these issues via Gem install without stopping install entirely.
|
|
162
|
+
return unless validate_installation
|
|
163
|
+
|
|
164
|
+
t { "starting instrumenter" }
|
|
165
|
+
|
|
166
|
+
unless config.validate_with_server
|
|
167
|
+
log_error "invalid config"
|
|
168
|
+
return
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
t { "starting native instrumenter" }
|
|
172
|
+
unless native_start
|
|
173
|
+
warn "failed to start instrumenter"
|
|
174
|
+
return
|
|
27
175
|
end
|
|
176
|
+
|
|
177
|
+
enable_extension!(:source_location) if @config.enable_source_locations?
|
|
178
|
+
config.gc.enable
|
|
179
|
+
@subscriber.register!
|
|
180
|
+
|
|
181
|
+
ActiveSupport::Notifications.instrument("started_instrumenter.skylight", instrumenter: self)
|
|
182
|
+
|
|
183
|
+
self
|
|
184
|
+
rescue Exception => e
|
|
185
|
+
log_error "failed to start instrumenter; msg=%s; config=%s", e.message, config.inspect
|
|
186
|
+
t { e.backtrace.join("\n") }
|
|
28
187
|
nil
|
|
29
188
|
end
|
|
30
189
|
|
|
31
|
-
def
|
|
32
|
-
|
|
33
|
-
|
|
190
|
+
def shutdown
|
|
191
|
+
@subscriber.unregister!
|
|
192
|
+
native_stop
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def trace(endpoint, cat, title = nil, desc = nil, meta: nil, segment: nil, component: nil)
|
|
196
|
+
# If a trace is already in progress, continue with that one
|
|
197
|
+
if (trace = @trace_info.current)
|
|
198
|
+
return yield(trace) if block_given?
|
|
199
|
+
|
|
200
|
+
return trace
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
begin
|
|
204
|
+
meta ||= {}
|
|
205
|
+
extensions.process_trace_meta(meta)
|
|
206
|
+
trace = Trace.new(self, endpoint, Skylight::Util::Clock.nanos, cat, title, desc,
|
|
207
|
+
meta: meta, segment: segment, component: component)
|
|
208
|
+
rescue Exception => e
|
|
209
|
+
log_error e.message
|
|
210
|
+
t { e.backtrace.join("\n") }
|
|
211
|
+
return
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
@trace_info.current = trace
|
|
215
|
+
return trace unless block_given?
|
|
216
|
+
|
|
217
|
+
begin
|
|
218
|
+
yield trace
|
|
219
|
+
ensure
|
|
220
|
+
@trace_info.current = nil
|
|
221
|
+
t { "instrumenter submitting trace; trace=#{trace.uuid}" }
|
|
222
|
+
trace.submit
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def instrument(cat, title = nil, desc = nil, meta = nil)
|
|
227
|
+
raise ArgumentError, "cat is required" unless cat
|
|
228
|
+
|
|
229
|
+
if muted?
|
|
230
|
+
return yield if block_given?
|
|
231
|
+
|
|
232
|
+
return
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
unless (trace = @trace_info.current)
|
|
236
|
+
return yield if block_given?
|
|
237
|
+
|
|
238
|
+
return
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
cat = cat.to_s
|
|
242
|
+
|
|
243
|
+
unless Skylight::CATEGORY_REGEX.match?(cat)
|
|
244
|
+
warn "invalid skylight instrumentation category; trace=%s; value=%s", trace.uuid, cat
|
|
245
|
+
return yield if block_given?
|
|
246
|
+
|
|
247
|
+
return
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
cat = "other.#{cat}" unless Skylight::TIER_REGEX.match?(cat)
|
|
251
|
+
|
|
252
|
+
unless (sp = trace.instrument(cat, title, desc, meta))
|
|
253
|
+
return yield if block_given?
|
|
254
|
+
|
|
255
|
+
return
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
return sp unless block_given?
|
|
259
|
+
|
|
260
|
+
begin
|
|
261
|
+
yield sp
|
|
262
|
+
rescue Exception => e
|
|
263
|
+
meta ||= {}
|
|
264
|
+
meta[:exception] = [e.class.name, e.message]
|
|
265
|
+
meta[:exception_object] = e
|
|
266
|
+
raise e
|
|
267
|
+
ensure
|
|
268
|
+
trace.done(sp, meta)
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
def broken!
|
|
273
|
+
return unless (trace = @trace_info.current)
|
|
274
|
+
|
|
275
|
+
trace.broken!
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
def poison!
|
|
279
|
+
@poisoned = true
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
def poisoned?
|
|
283
|
+
@poisoned
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
def done(span, meta = nil)
|
|
287
|
+
return unless (trace = @trace_info.current)
|
|
288
|
+
|
|
289
|
+
trace.done(span, meta)
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
def process(trace)
|
|
293
|
+
t { fmt "processing trace=#{trace.uuid}" }
|
|
294
|
+
|
|
295
|
+
if ignore?(trace)
|
|
296
|
+
t { fmt "ignoring trace=#{trace.uuid}" }
|
|
297
|
+
return false
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
begin
|
|
301
|
+
finalize_endpoint_segment(trace)
|
|
302
|
+
native_submit_trace(trace)
|
|
303
|
+
true
|
|
304
|
+
rescue => e
|
|
305
|
+
handle_instrumenter_error(trace, e)
|
|
306
|
+
end
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
def handle_instrumenter_error(trace, err)
|
|
310
|
+
poison! if err.is_a?(Skylight::InstrumenterUnrecoverableError)
|
|
311
|
+
|
|
312
|
+
warn "failed to submit trace to worker; trace=%s, err=%s", trace.uuid, err
|
|
313
|
+
t { "BACKTRACE:\n#{err.backtrace.join("\n")}" }
|
|
314
|
+
|
|
315
|
+
false
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
def ignore?(trace)
|
|
319
|
+
config.ignored_endpoints.include?(trace.endpoint)
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
# Because GraphQL can return multiple results, each of which
|
|
323
|
+
# may have their own success/error states, we need to set the
|
|
324
|
+
# skylight segment as follows:
|
|
325
|
+
#
|
|
326
|
+
# - when all queries have errors: "error"
|
|
327
|
+
# - when some queries have errors: "<rendered format>+error"
|
|
328
|
+
# - when no queries have errors: "<rendered format>"
|
|
329
|
+
#
|
|
330
|
+
# <rendered format> will be determined by the Rails controller as usual.
|
|
331
|
+
# See Instrumenter#finalize_endpoint_segment for the actual segment/error assignment.
|
|
332
|
+
def finalize_endpoint_segment(trace)
|
|
333
|
+
return unless (segment = trace.segment)
|
|
334
|
+
|
|
335
|
+
segment = case trace.compound_response_error_status
|
|
336
|
+
when :all
|
|
337
|
+
"error"
|
|
338
|
+
when :partial
|
|
339
|
+
"#{segment}+error"
|
|
340
|
+
else
|
|
341
|
+
segment
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
trace.endpoint += "<sk-segment>#{segment}</sk-segment>"
|
|
34
345
|
end
|
|
35
346
|
end
|
|
36
347
|
end
|