skylight 0.3.21 → 0.4.0.alpha1
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 +0 -4
- data/ext/extconf.rb +92 -47
- data/ext/libskylight.yml +4 -4
- data/ext/skylight_native.c +248 -286
- data/lib/skylight.rb +19 -114
- data/lib/skylight/api.rb +1 -1
- data/lib/skylight/config.rb +176 -146
- data/lib/skylight/data/cacert.pem +717 -719
- data/lib/skylight/formatters/http.rb +1 -1
- data/lib/skylight/instrumenter.rb +28 -35
- data/lib/skylight/native.rb +58 -72
- data/lib/skylight/normalizers.rb +0 -1
- data/lib/skylight/normalizers/active_record/sql.rb +0 -4
- data/lib/skylight/probes/excon/middleware.rb +3 -1
- data/lib/skylight/probes/net_http.rb +3 -1
- data/lib/skylight/subscriber.rb +0 -4
- data/lib/skylight/trace.rb +189 -0
- data/lib/skylight/util.rb +10 -12
- data/lib/skylight/util/hostname.rb +17 -0
- data/lib/skylight/util/http.rb +33 -36
- data/lib/skylight/util/logging.rb +20 -1
- data/lib/skylight/util/multi_io.rb +21 -0
- data/lib/skylight/util/native_ext_fetcher.rb +83 -69
- data/lib/skylight/util/platform.rb +67 -0
- data/lib/skylight/util/ssl.rb +50 -0
- data/lib/skylight/version.rb +1 -1
- metadata +9 -34
- data/ext/rust_support/ruby.h +0 -93
- data/ext/skylight.h +0 -85
- data/ext/skylight.map +0 -4
- data/ext/test/extconf.rb +0 -18
- data/ext/test/skylight_native_test.c +0 -82
- data/ext/test/skylight_test.h +0 -20
- data/lib/skylight/formatters.rb +0 -6
- data/lib/skylight/messages.rb +0 -21
- data/lib/skylight/messages/error.rb +0 -15
- data/lib/skylight/messages/hello.rb +0 -13
- data/lib/skylight/messages/trace.rb +0 -179
- data/lib/skylight/messages/trace_envelope.rb +0 -19
- data/lib/skylight/metrics.rb +0 -9
- data/lib/skylight/metrics/ewma.rb +0 -69
- data/lib/skylight/metrics/meter.rb +0 -58
- data/lib/skylight/metrics/process_cpu_gauge.rb +0 -65
- data/lib/skylight/metrics/process_mem_gauge.rb +0 -34
- data/lib/skylight/util/conversions.rb +0 -9
- data/lib/skylight/util/queue.rb +0 -96
- data/lib/skylight/util/task.rb +0 -172
- data/lib/skylight/util/uniform_sample.rb +0 -63
- data/lib/skylight/worker.rb +0 -19
- data/lib/skylight/worker/builder.rb +0 -73
- data/lib/skylight/worker/collector.rb +0 -274
- data/lib/skylight/worker/connection.rb +0 -87
- data/lib/skylight/worker/connection_set.rb +0 -56
- data/lib/skylight/worker/embedded.rb +0 -24
- data/lib/skylight/worker/metrics_reporter.rb +0 -104
- data/lib/skylight/worker/server.rb +0 -336
- data/lib/skylight/worker/standalone.rb +0 -421
@@ -59,16 +59,27 @@ module Skylight
|
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
|
+
at_exit { stop! }
|
63
|
+
|
62
64
|
attr_reader :config, :gc, :trace_info
|
63
65
|
|
64
|
-
def
|
65
|
-
if
|
66
|
+
def self.new(config)
|
67
|
+
if config.nil?
|
68
|
+
raise ArgumentError, "config is required"
|
69
|
+
elsif Hash === config
|
66
70
|
config = Config.new(config)
|
67
71
|
end
|
68
72
|
|
73
|
+
config.validate!
|
74
|
+
|
75
|
+
inst = native_new(config.to_env)
|
76
|
+
inst.send(:initialize, config)
|
77
|
+
inst
|
78
|
+
end
|
79
|
+
|
80
|
+
def initialize(config)
|
69
81
|
@gc = config.gc
|
70
82
|
@config = config
|
71
|
-
@worker = config.worker.build
|
72
83
|
@subscriber = Subscriber.new(config, self)
|
73
84
|
|
74
85
|
@trace_info = @config[:trace_info] || TraceInfo.new
|
@@ -84,8 +95,6 @@ module Skylight
|
|
84
95
|
end
|
85
96
|
|
86
97
|
def start!
|
87
|
-
return unless config
|
88
|
-
|
89
98
|
# Warn if there was an error installing Skylight.
|
90
99
|
# We do this here since we can't report these issues via Gem install without stopping install entirely.
|
91
100
|
Skylight.check_install_errors(config)
|
@@ -98,48 +107,37 @@ module Skylight
|
|
98
107
|
t { "starting instrumenter" }
|
99
108
|
@config.validate!
|
100
109
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
log_warn "unable to validate authentication token"
|
106
|
-
else
|
107
|
-
raise ConfigError, "authentication token is invalid"
|
110
|
+
t { "starting native instrumenter" }
|
111
|
+
unless native_start
|
112
|
+
warn "failed to start instrumenter"
|
113
|
+
return
|
108
114
|
end
|
109
115
|
|
110
116
|
@config.gc.enable
|
111
|
-
|
112
|
-
unless @worker.spawn
|
113
|
-
log_error "failed to spawn worker"
|
114
|
-
return nil
|
115
|
-
end
|
116
|
-
|
117
117
|
@subscriber.register!
|
118
118
|
|
119
119
|
self
|
120
120
|
|
121
121
|
rescue Exception => e
|
122
122
|
log_error "failed to start instrumenter; msg=%s; config=%s", e.message, @config.inspect
|
123
|
+
t { e.backtrace.join("\n") }
|
123
124
|
nil
|
124
125
|
end
|
125
126
|
|
126
127
|
def shutdown
|
127
128
|
@subscriber.unregister!
|
128
|
-
|
129
|
+
native_stop
|
129
130
|
end
|
130
131
|
|
131
132
|
def trace(endpoint, cat, title=nil, desc=nil, annot=nil)
|
132
133
|
# If a trace is already in progress, continue with that one
|
133
134
|
if trace = @trace_info.current
|
134
|
-
t { "already tracing" }
|
135
135
|
return yield(trace) if block_given?
|
136
136
|
return trace
|
137
137
|
end
|
138
138
|
|
139
|
-
t { "starting trace" }
|
140
|
-
|
141
139
|
begin
|
142
|
-
trace =
|
140
|
+
trace = Trace.new(self, endpoint, Util::Clock.nanos, cat, title, desc, annot)
|
143
141
|
rescue Exception => e
|
144
142
|
log_error e.message
|
145
143
|
t { e.backtrace.join("\n") }
|
@@ -154,6 +152,7 @@ module Skylight
|
|
154
152
|
|
155
153
|
ensure
|
156
154
|
@trace_info.current = nil
|
155
|
+
t { "submitting trace" }
|
157
156
|
trace.submit
|
158
157
|
end
|
159
158
|
end
|
@@ -231,20 +230,14 @@ module Skylight
|
|
231
230
|
end
|
232
231
|
end
|
233
232
|
|
234
|
-
def error(type, description, details=nil)
|
235
|
-
t { fmt "processing error; type=%s; description=%s", type, description }
|
236
|
-
|
237
|
-
message = Skylight::Messages::Error.build(type, description, details && details.to_json)
|
238
|
-
|
239
|
-
unless @worker.submit(message)
|
240
|
-
warn "failed to submit error to worker"
|
241
|
-
end
|
242
|
-
end
|
243
|
-
|
244
233
|
def process(trace)
|
245
234
|
t { fmt "processing trace" }
|
246
|
-
|
247
|
-
|
235
|
+
begin
|
236
|
+
native_submit_trace(trace)
|
237
|
+
true
|
238
|
+
rescue => e
|
239
|
+
warn "failed to submit trace to worker; err=%s", e
|
240
|
+
false
|
248
241
|
end
|
249
242
|
end
|
250
243
|
|
data/lib/skylight/native.rb
CHANGED
@@ -1,90 +1,76 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
if native?
|
4
|
-
|
5
|
-
# @api private
|
6
|
-
class Hello
|
7
|
-
DIGITS = /^\s*\d+\s*$/
|
8
|
-
|
9
|
-
alias serialize native_serialize
|
10
|
-
alias version native_get_version
|
11
|
-
|
12
|
-
class << self
|
13
|
-
alias deserialize native_load
|
14
|
-
end
|
1
|
+
require 'skylight/util/platform'
|
15
2
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
end
|
3
|
+
module Skylight
|
4
|
+
# @api private
|
5
|
+
# Whether or not the native extension is present
|
6
|
+
@@has_native_ext = false
|
21
7
|
|
22
|
-
|
23
|
-
|
24
|
-
|
8
|
+
def self.native?
|
9
|
+
@@has_native_ext
|
10
|
+
end
|
25
11
|
|
26
|
-
|
27
|
-
|
28
|
-
|
12
|
+
def self.libskylight_path
|
13
|
+
ENV['SKYLIGHT_LIB_PATH'] || File.expand_path("../native/#{Util::Platform.tuple}", __FILE__)
|
14
|
+
end
|
29
15
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
curr_i = curr[i].to_i
|
16
|
+
begin
|
17
|
+
unless ENV["SKYLIGHT_DISABLE_AGENT"]
|
18
|
+
lib = "#{libskylight_path}/libskylight.#{Util::Platform.libext}"
|
34
19
|
|
35
|
-
|
20
|
+
if File.exist?(lib)
|
21
|
+
# First attempt to require the native extension
|
22
|
+
require 'skylight_native'
|
36
23
|
|
37
|
-
|
38
|
-
|
39
|
-
return false
|
40
|
-
end
|
41
|
-
else
|
42
|
-
if curr[i] =~ DIGITS
|
43
|
-
return true
|
44
|
-
else
|
45
|
-
next if curr[i] == other[i]
|
46
|
-
return curr[i] > other[i]
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
24
|
+
# Attempt to link the dylib
|
25
|
+
load_libskylight(lib)
|
50
26
|
|
51
|
-
|
27
|
+
# If nothing was thrown, then the native extension is present
|
28
|
+
@@has_native_ext = true
|
52
29
|
end
|
53
|
-
|
54
|
-
private
|
55
|
-
|
56
|
-
def split(v)
|
57
|
-
v.split('.')
|
58
|
-
end
|
59
|
-
|
60
30
|
end
|
31
|
+
rescue LoadError => e
|
32
|
+
raise if ENV.key?("SKYLIGHT_REQUIRED")
|
33
|
+
end
|
61
34
|
|
62
|
-
|
63
|
-
class
|
64
|
-
|
65
|
-
|
66
|
-
alias description native_get_description
|
67
|
-
alias details native_get_details
|
68
|
-
|
69
|
-
class << self
|
70
|
-
alias deserialize native_load
|
35
|
+
unless Skylight.native?
|
36
|
+
class Instrumenter
|
37
|
+
def self.native_new(*args)
|
38
|
+
allocate
|
71
39
|
end
|
72
40
|
end
|
41
|
+
end
|
73
42
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
43
|
+
# @api private
|
44
|
+
def self.check_install_errors(config)
|
45
|
+
# Note: An unsupported arch doesn't count as an error.
|
46
|
+
install_log = File.expand_path("../../ext/install.log", __FILE__)
|
47
|
+
|
48
|
+
if File.exist?(install_log) && File.read(install_log) =~ /ERROR/
|
49
|
+
config.alert_logger.error \
|
50
|
+
"[SKYLIGHT] [#{Skylight::VERSION}] The Skylight native extension failed to install. " \
|
51
|
+
"Please check #{install_log} and notify support@skylight.io." \
|
52
|
+
"The missing extension will not affect the functioning of your application."
|
82
53
|
end
|
83
54
|
end
|
84
55
|
|
85
56
|
# @api private
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
57
|
+
def self.warn_skylight_native_missing(config)
|
58
|
+
# TODO: Dumping the error messages this way is pretty hacky
|
59
|
+
is_rails = defined?(Rails)
|
60
|
+
env_name = is_rails ? Rails.env : "development"
|
61
|
+
|
62
|
+
if env_name == "development" || env_name == "test"
|
63
|
+
config.alert_logger.warn \
|
64
|
+
"[SKYLIGHT] [#{Skylight::VERSION}] Running Skylight in #{env_name} mode. " \
|
65
|
+
"No data will be reported until you deploy your app.\n" \
|
66
|
+
"(To disable this message, set `alert_log_file` in your config.)"
|
67
|
+
else
|
68
|
+
config.alert_logger.error \
|
69
|
+
"[SKYLIGHT] [#{Skylight::VERSION}] The Skylight native extension for your platform wasn't found. " \
|
70
|
+
"The monitoring portion of Skylight is only supported on production servers running 32- or " \
|
71
|
+
"64-bit Linux. The missing extension will not affect the functioning of your application " \
|
72
|
+
"and you can continue local development without data being reported. If you are on a " \
|
73
|
+
"supported platform, please contact support at support@skylight.io."
|
74
|
+
end
|
75
|
+
end
|
90
76
|
end
|
data/lib/skylight/normalizers.rb
CHANGED
data/lib/skylight/subscriber.rb
CHANGED
@@ -42,10 +42,6 @@ module Skylight
|
|
42
42
|
|
43
43
|
cat, title, desc, annot = normalize(trace, name, payload)
|
44
44
|
|
45
|
-
if cat != :skip && error = annot.delete(:skylight_error)
|
46
|
-
@instrumenter.error(*error)
|
47
|
-
end
|
48
|
-
|
49
45
|
unless cat == :skip
|
50
46
|
span = trace.instrument(cat, title, desc, annot)
|
51
47
|
end
|
@@ -0,0 +1,189 @@
|
|
1
|
+
module Skylight
|
2
|
+
class Trace
|
3
|
+
GC_CAT = 'noise.gc'.freeze
|
4
|
+
|
5
|
+
include Util::Logging
|
6
|
+
|
7
|
+
attr_reader :endpoint, :notifications
|
8
|
+
|
9
|
+
def self.new(instrumenter, endpoint, start, cat, title = nil, desc = nil, annot = nil)
|
10
|
+
inst = native_new(normalize_time(start), "TODO", endpoint)
|
11
|
+
inst.send(:initialize, instrumenter, cat, title, desc, annot)
|
12
|
+
inst.endpoint = endpoint
|
13
|
+
inst
|
14
|
+
end
|
15
|
+
|
16
|
+
# TODO: Move this into native
|
17
|
+
def self.normalize_time(time)
|
18
|
+
# At least one customer has extensions that cause integer division to produce rationals.
|
19
|
+
# Since the native code expects an integer, we force it again.
|
20
|
+
(time.to_i / 100_000).to_i
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(instrumenter, cat, title, desc, annot)
|
24
|
+
raise ArgumentError, 'instrumenter is required' unless instrumenter
|
25
|
+
|
26
|
+
@instrumenter = instrumenter
|
27
|
+
@submitted = false
|
28
|
+
@broken = false
|
29
|
+
|
30
|
+
@notifications = []
|
31
|
+
|
32
|
+
if Hash === title
|
33
|
+
annot = title
|
34
|
+
title = desc = nil
|
35
|
+
elsif Hash === desc
|
36
|
+
annot = desc
|
37
|
+
desc = nil
|
38
|
+
end
|
39
|
+
|
40
|
+
# create the root node
|
41
|
+
@root = native_start_span(native_get_started_at, cat)
|
42
|
+
native_span_set_title(@root, title) if title
|
43
|
+
native_span_set_description(@root, desc) if desc
|
44
|
+
|
45
|
+
@gc = config.gc.track unless ENV.key?("SKYLIGHT_DISABLE_GC_TRACKING")
|
46
|
+
end
|
47
|
+
|
48
|
+
def endpoint=(value)
|
49
|
+
@endpoint = value
|
50
|
+
native_set_endpoint(value)
|
51
|
+
value
|
52
|
+
end
|
53
|
+
|
54
|
+
def config
|
55
|
+
@instrumenter.config
|
56
|
+
end
|
57
|
+
|
58
|
+
def record(cat, title=nil, desc=nil, annot=nil)
|
59
|
+
@return if @broken
|
60
|
+
|
61
|
+
if Hash === title
|
62
|
+
annot = title
|
63
|
+
title = desc = nil
|
64
|
+
elsif Hash === desc
|
65
|
+
annot = desc
|
66
|
+
desc = nil
|
67
|
+
end
|
68
|
+
|
69
|
+
title.freeze if title.is_a?(String)
|
70
|
+
desc.freeze if desc.is_a?(String)
|
71
|
+
|
72
|
+
desc = @instrumenter.limited_description(desc)
|
73
|
+
|
74
|
+
time = Util::Clock.nanos - gc_time
|
75
|
+
|
76
|
+
stop(start(time, cat, title, desc), time)
|
77
|
+
|
78
|
+
nil
|
79
|
+
rescue => e
|
80
|
+
error "failed to record span; msg=%s", e.message
|
81
|
+
@broken = true
|
82
|
+
nil
|
83
|
+
end
|
84
|
+
|
85
|
+
def instrument(cat, title=nil, desc=nil, annot=nil)
|
86
|
+
return if @broken
|
87
|
+
t { "instrument: #{cat}, #{title}" }
|
88
|
+
|
89
|
+
if Hash === title
|
90
|
+
annot = title
|
91
|
+
title = desc = nil
|
92
|
+
elsif Hash === desc
|
93
|
+
annot = desc
|
94
|
+
desc = nil
|
95
|
+
end
|
96
|
+
|
97
|
+
title.freeze if title.is_a?(String)
|
98
|
+
desc.freeze if desc.is_a?(String)
|
99
|
+
|
100
|
+
original_desc = desc
|
101
|
+
now = Util::Clock.nanos
|
102
|
+
desc = @instrumenter.limited_description(desc)
|
103
|
+
|
104
|
+
if desc == Instrumenter::TOO_MANY_UNIQUES
|
105
|
+
debug "[SKYLIGHT] [#{Skylight::VERSION}] A payload description produced <too many uniques>"
|
106
|
+
debug "original desc=%s", original_desc
|
107
|
+
debug "cat=%s, title=%s, desc=%s, annot=%s", cat, title, desc, annot.inspect
|
108
|
+
end
|
109
|
+
|
110
|
+
start(now - gc_time, cat, title, desc, annot)
|
111
|
+
rescue => e
|
112
|
+
error "failed to instrument span; msg=%s", e.message
|
113
|
+
@broken = true
|
114
|
+
nil
|
115
|
+
end
|
116
|
+
|
117
|
+
def done(span)
|
118
|
+
return unless span
|
119
|
+
return if @broken
|
120
|
+
stop(span, Util::Clock.nanos - gc_time)
|
121
|
+
rescue => e
|
122
|
+
error "failed to close span; msg=%s", e.message
|
123
|
+
@broken = true
|
124
|
+
nil
|
125
|
+
end
|
126
|
+
|
127
|
+
def release
|
128
|
+
return unless @instrumenter.current_trace == self
|
129
|
+
@instrumenter.current_trace = nil
|
130
|
+
end
|
131
|
+
|
132
|
+
def traced
|
133
|
+
time = gc_time
|
134
|
+
now = Util::Clock.nanos
|
135
|
+
|
136
|
+
if time > 0
|
137
|
+
t { fmt "tracking GC time; duration=%d", time }
|
138
|
+
stop(start(now - time, GC_CAT, nil, nil, {}), now)
|
139
|
+
end
|
140
|
+
|
141
|
+
stop(@root, now)
|
142
|
+
end
|
143
|
+
|
144
|
+
def submit
|
145
|
+
return if @broken
|
146
|
+
|
147
|
+
t { "submitting trace" }
|
148
|
+
|
149
|
+
if @submitted
|
150
|
+
t { "already submitted" }
|
151
|
+
return
|
152
|
+
end
|
153
|
+
|
154
|
+
release
|
155
|
+
@submitted = true
|
156
|
+
|
157
|
+
traced
|
158
|
+
|
159
|
+
@instrumenter.process(self)
|
160
|
+
rescue Exception => e
|
161
|
+
error e
|
162
|
+
t { e.backtrace.join("\n") }
|
163
|
+
end
|
164
|
+
|
165
|
+
private
|
166
|
+
|
167
|
+
def start(time, cat, title, desc, annot=nil)
|
168
|
+
span(self.class.normalize_time(time), cat, title, desc, annot)
|
169
|
+
end
|
170
|
+
|
171
|
+
def stop(span, time)
|
172
|
+
native_stop_span(span, self.class.normalize_time(time))
|
173
|
+
nil
|
174
|
+
end
|
175
|
+
|
176
|
+
def span(time, cat, title=nil, desc=nil, annot=nil)
|
177
|
+
sp = native_start_span(time, cat.to_s)
|
178
|
+
native_span_set_title(sp, title.to_s) if title
|
179
|
+
native_span_set_description(sp, desc.to_s) if desc
|
180
|
+
sp
|
181
|
+
end
|
182
|
+
|
183
|
+
def gc_time
|
184
|
+
return 0 unless @gc
|
185
|
+
@gc.update
|
186
|
+
@gc.time
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|