skylight 0.1.6.alpha1 → 0.1.6.alpha3
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 +5 -0
- data/lib/skylight.rb +10 -2
- data/lib/skylight/config.rb +1 -0
- data/lib/skylight/gc.rb +14 -38
- data/lib/skylight/instrumenter.rb +28 -29
- data/lib/skylight/messages/span.rb +13 -0
- data/lib/skylight/messages/trace.rb +100 -100
- data/lib/skylight/middleware.rb +48 -4
- data/lib/skylight/railtie.rb +3 -3
- data/lib/skylight/subscriber.rb +24 -27
- data/lib/skylight/util/queue.rb +11 -12
- data/lib/skylight/vendor/beefcake.rb +24 -7
- data/lib/skylight/vendor/beefcake/buffer.rb +1 -2
- data/lib/skylight/version.rb +1 -1
- data/lib/skylight/worker/collector.rb +9 -4
- data/lib/skylight/worker/standalone.rb +39 -19
- metadata +2 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bd3fcb8b023de4a803c0afc513b516b4cf427d21
|
4
|
+
data.tar.gz: 6df2ed3b9dececb6b58f3a7e8201137418345f61
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f94b8e72f33d0c3c3446d4b7d9ea3448bb5e33ccc7deb16da4837bbcca7e486b8d9a5c38f430de4af4c1b960cea879fadda5da2f3bc5dcd505e8a70882167a6f
|
7
|
+
data.tar.gz: 156b54dfa5b95ebdac49ec7e67642370ed2f9005d9c357894056b3758cd27a2af6eda8e3a0410cb664caf8599ae27b37e7b078df0e12234e89ec7498ec390cae
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
## unreleased ##
|
2
2
|
|
3
|
+
* [BUG] Fix unix domain socket write function in standalone agent
|
4
|
+
* Performance improvements
|
5
|
+
* Tolerate invalid trace building
|
6
|
+
* Fix Skylight on Rails 4
|
7
|
+
|
3
8
|
## 0.1.5 (May 31, 2013)
|
4
9
|
|
5
10
|
* Provide a default CA cert when one is not already present
|
data/lib/skylight.rb
CHANGED
@@ -69,12 +69,20 @@ module Skylight
|
|
69
69
|
end
|
70
70
|
|
71
71
|
def self.trace(*args, &blk)
|
72
|
-
|
72
|
+
unless inst = Instrumenter.instance
|
73
|
+
return yield if block_given?
|
74
|
+
return
|
75
|
+
end
|
76
|
+
|
73
77
|
inst.trace(*args, &blk)
|
74
78
|
end
|
75
79
|
|
76
80
|
def self.instrument(*args, &blk)
|
77
|
-
|
81
|
+
unless inst = Instrumenter.instance
|
82
|
+
return yield if block_given?
|
83
|
+
return
|
84
|
+
end
|
85
|
+
|
78
86
|
inst.instrument(*args, &blk)
|
79
87
|
end
|
80
88
|
|
data/lib/skylight/config.rb
CHANGED
@@ -15,6 +15,7 @@ module Skylight
|
|
15
15
|
'SK_AGENT_KEEPALIVE' => :'agent.keepalive',
|
16
16
|
'SK_AGENT_SAMPLE_SIZE' => :'agent.sample',
|
17
17
|
'SK_AGENT_SOCKFILE_PATH' => :'agent.sockfile_path',
|
18
|
+
'SK_AGENT_STRATEGY' => :'agent.strategy',
|
18
19
|
'SK_REPORT_HOST' => :'report.host',
|
19
20
|
'SK_REPORT_PORT' => :'report.port',
|
20
21
|
'SK_REPORT_SSL' => :'report.ssl',
|
data/lib/skylight/gc.rb
CHANGED
@@ -2,25 +2,13 @@ require 'thread'
|
|
2
2
|
|
3
3
|
module Skylight
|
4
4
|
class GC
|
5
|
-
METHODS
|
6
|
-
TH_KEY
|
5
|
+
METHODS = [ :enable, :total_time ]
|
6
|
+
TH_KEY = :SK_GC_CURR_WINDOW
|
7
|
+
MAX_COUNT = 1000
|
8
|
+
MAX_TIME = 30_000_000
|
7
9
|
|
8
10
|
include Util::Logging
|
9
11
|
|
10
|
-
def self.update
|
11
|
-
if win = Thread.current[TH_KEY]
|
12
|
-
win.update
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def self.time
|
17
|
-
if win = Thread.current[TH_KEY]
|
18
|
-
win.time
|
19
|
-
else
|
20
|
-
0
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
12
|
attr_reader :config
|
25
13
|
|
26
14
|
def initialize(config, profiler)
|
@@ -41,9 +29,7 @@ module Skylight
|
|
41
29
|
@profiler.enable if @profiler
|
42
30
|
end
|
43
31
|
|
44
|
-
def
|
45
|
-
return if Thread.current[TH_KEY]
|
46
|
-
|
32
|
+
def track
|
47
33
|
unless @profiler
|
48
34
|
win = Window.new(nil)
|
49
35
|
else
|
@@ -52,29 +38,19 @@ module Skylight
|
|
52
38
|
@lock.synchronize do
|
53
39
|
__update
|
54
40
|
@listeners << win
|
55
|
-
end
|
56
|
-
end
|
57
41
|
|
58
|
-
|
59
|
-
|
42
|
+
# Cleanup any listeners that might have leaked
|
43
|
+
until @listeners[0].time < MAX_TIME
|
44
|
+
@listeners.shift
|
45
|
+
end
|
60
46
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
47
|
+
if @listeners.length > MAX_COUNT
|
48
|
+
@listeners.shift
|
49
|
+
end
|
50
|
+
end
|
65
51
|
end
|
66
|
-
end
|
67
52
|
|
68
|
-
|
69
|
-
return unless block_given?
|
70
|
-
|
71
|
-
start_track
|
72
|
-
|
73
|
-
begin
|
74
|
-
yield
|
75
|
-
ensure
|
76
|
-
stop_track
|
77
|
-
end
|
53
|
+
win
|
78
54
|
end
|
79
55
|
|
80
56
|
def release(win)
|
@@ -70,65 +70,64 @@ module Skylight
|
|
70
70
|
@worker.shutdown
|
71
71
|
end
|
72
72
|
|
73
|
-
def trace(endpoint
|
73
|
+
def trace(endpoint, cat, *args)
|
74
74
|
# If a trace is already in progress, continue with that one
|
75
75
|
if trace = Instrumenter.current_trace
|
76
76
|
t { "already tracing" }
|
77
|
-
return yield(trace)
|
77
|
+
return yield(trace) if block_given?
|
78
|
+
return trace
|
78
79
|
end
|
79
80
|
|
80
|
-
trace = Messages::Trace::Builder.new(endpoint, Util::Clock.micros, @config)
|
81
|
-
|
82
81
|
begin
|
82
|
+
trace = Messages::Trace::Builder.new(self, endpoint, Util::Clock.micros, cat, *args)
|
83
|
+
rescue Exception => e
|
84
|
+
error e.message
|
85
|
+
t { e.backtrace.join("\n") }
|
86
|
+
return
|
87
|
+
end
|
88
|
+
|
89
|
+
Instrumenter.current_trace = trace
|
90
|
+
return trace unless block_given?
|
83
91
|
|
84
|
-
|
92
|
+
begin
|
85
93
|
yield trace
|
86
94
|
|
87
95
|
ensure
|
88
96
|
Instrumenter.current_trace = nil
|
89
|
-
|
90
|
-
begin
|
91
|
-
built = trace.build
|
92
|
-
|
93
|
-
if built && built.valid?
|
94
|
-
process(built)
|
95
|
-
else
|
96
|
-
if built && built.spans.empty?
|
97
|
-
debug "trace invalid -- dropping; spans=0"
|
98
|
-
elsif built
|
99
|
-
debug "trace invalid -- dropping; spans=%d; started_at=%d",
|
100
|
-
built.spans.length, built.spans[-1].started_at
|
101
|
-
else
|
102
|
-
debug "trace invalid -- dropping; trace=nil"
|
103
|
-
end
|
104
|
-
end
|
105
|
-
rescue Exception => e
|
106
|
-
error e
|
107
|
-
end
|
97
|
+
trace.submit
|
108
98
|
end
|
109
99
|
end
|
110
100
|
|
111
101
|
def instrument(cat, *args)
|
102
|
+
unless trace = Instrumenter.current_trace
|
103
|
+
return yield if block_given?
|
104
|
+
return
|
105
|
+
end
|
106
|
+
|
112
107
|
cat = cat.to_s
|
113
108
|
|
114
109
|
unless cat =~ CATEGORY_REGEX
|
115
110
|
warn "invalid skylight instrumentation category; value=%s", cat
|
116
|
-
return yield
|
111
|
+
return yield if block_given?
|
112
|
+
return
|
117
113
|
end
|
118
114
|
|
119
115
|
cat = "other.#{cat}" unless cat =~ TIER_REGEX
|
120
116
|
|
121
|
-
|
117
|
+
unless sp = trace.instrument(cat, *args)
|
118
|
+
return yield if block_given?
|
119
|
+
return
|
120
|
+
end
|
121
|
+
|
122
|
+
return sp unless block_given?
|
122
123
|
|
123
124
|
begin
|
124
125
|
yield sp
|
125
126
|
ensure
|
126
|
-
|
127
|
+
sp.done
|
127
128
|
end
|
128
129
|
end
|
129
130
|
|
130
|
-
private
|
131
|
-
|
132
131
|
def process(trace)
|
133
132
|
t { fmt "processing trace; spans=%d; duration=%d",
|
134
133
|
trace.spans.length, trace.spans[-1].duration }
|
@@ -19,6 +19,8 @@ module Skylight
|
|
19
19
|
|
20
20
|
class Builder
|
21
21
|
|
22
|
+
include Util::Logging
|
23
|
+
|
22
24
|
attr_reader \
|
23
25
|
:time,
|
24
26
|
:category,
|
@@ -40,10 +42,21 @@ module Skylight
|
|
40
42
|
self.description = desc
|
41
43
|
end
|
42
44
|
|
45
|
+
def config
|
46
|
+
@trace.config
|
47
|
+
end
|
48
|
+
|
43
49
|
def endpoint=(name)
|
44
50
|
@trace.endpoint = name
|
45
51
|
end
|
46
52
|
|
53
|
+
def done
|
54
|
+
@trace.done(self) unless built?
|
55
|
+
rescue Exception => e
|
56
|
+
error e.message
|
57
|
+
t { e.backtrace.join("\n") }
|
58
|
+
end
|
59
|
+
|
47
60
|
def built?
|
48
61
|
@built
|
49
62
|
end
|
@@ -8,160 +8,155 @@ module Skylight
|
|
8
8
|
optional :endpoint, :string, 2
|
9
9
|
repeated :spans, Span, 3
|
10
10
|
|
11
|
-
def valid?
|
12
|
-
return false unless spans && spans.length > 0
|
13
|
-
spans[-1].started_at == 0
|
14
|
-
end
|
15
|
-
|
16
11
|
class Builder
|
12
|
+
GC_CAT = 'noise.gc'.freeze
|
13
|
+
|
17
14
|
include Util::Logging
|
18
15
|
|
19
16
|
attr_accessor :endpoint
|
20
|
-
attr_reader :spans, :
|
21
|
-
|
22
|
-
def initialize(endpoint = "Unknown", start = Util::Clock.micros, config = nil)
|
23
|
-
@endpoint = endpoint
|
24
|
-
@busted = false
|
25
|
-
@config = config
|
26
|
-
@start = start
|
27
|
-
@spans = []
|
28
|
-
@stack = []
|
29
|
-
@parents = []
|
30
|
-
|
31
|
-
# Track time
|
32
|
-
@last_seen_time = start
|
33
|
-
end
|
17
|
+
attr_reader :spans, :notifications
|
34
18
|
|
35
|
-
def
|
36
|
-
|
37
|
-
return yield unless @stack == []
|
38
|
-
return yield unless config
|
19
|
+
def initialize(instrumenter, endpoint, start, cat, *args)
|
20
|
+
raise ArgumentError, 'instrumenter is required' unless instrumenter
|
39
21
|
|
40
|
-
|
41
|
-
|
22
|
+
@instrumenter = instrumenter
|
23
|
+
@endpoint = endpoint
|
24
|
+
@start = start
|
25
|
+
@spans = []
|
26
|
+
@stack = []
|
27
|
+
@submitted = false
|
42
28
|
|
43
|
-
|
44
|
-
|
29
|
+
# Tracks the AS::N stack
|
30
|
+
@notifications = []
|
45
31
|
|
46
|
-
|
47
|
-
|
48
|
-
ensure
|
49
|
-
unless @busted
|
50
|
-
now = Util::Clock.micros
|
51
|
-
|
52
|
-
GC.update
|
53
|
-
gc_time = GC.time
|
32
|
+
# Track time
|
33
|
+
@last_seen_time = start
|
54
34
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
stop(now)
|
59
|
-
end
|
35
|
+
annot = args.pop if Hash === args
|
36
|
+
title = args.shift
|
37
|
+
desc = args.shift
|
60
38
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
ensure
|
65
|
-
gc.stop_track
|
66
|
-
end
|
39
|
+
# Create the root node
|
40
|
+
@root = start(@start, cat, title, desc, annot)
|
41
|
+
@gc = config.gc.track
|
67
42
|
end
|
68
43
|
|
69
|
-
def
|
70
|
-
|
71
|
-
|
72
|
-
time = adjust_for_skew(time)
|
73
|
-
|
74
|
-
sp = span(time, cat, title, desc, annot)
|
44
|
+
def config
|
45
|
+
@instrumenter.config
|
46
|
+
end
|
75
47
|
|
76
|
-
|
48
|
+
def record(cat, *args)
|
49
|
+
annot = args.pop if Hash === args
|
50
|
+
title = args.shift
|
51
|
+
desc = args.shift
|
52
|
+
now = adjust_for_skew(Util::Clock.micros)
|
77
53
|
|
54
|
+
sp = span(now - gc_time, cat, title, desc, annot)
|
78
55
|
inc_children
|
79
56
|
@spans << sp.build(0)
|
80
57
|
|
81
58
|
nil
|
82
59
|
end
|
83
60
|
|
84
|
-
def
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
sp = span(time, cat, title, desc, annot)
|
90
|
-
|
91
|
-
push(sp)
|
61
|
+
def instrument(cat, *args)
|
62
|
+
annot = args.pop if Hash === args
|
63
|
+
title = args.shift
|
64
|
+
desc = args.shift
|
65
|
+
now = adjust_for_skew(Util::Clock.micros)
|
92
66
|
|
93
|
-
|
67
|
+
start(now - gc_time, cat, title, desc, annot)
|
68
|
+
end
|
94
69
|
|
95
|
-
|
70
|
+
def done(span)
|
71
|
+
return unless span
|
72
|
+
stop(span, adjust_for_skew(Util::Clock.micros) - gc_time)
|
96
73
|
end
|
97
74
|
|
98
|
-
def
|
99
|
-
return
|
75
|
+
def release
|
76
|
+
return unless Instrumenter.current_trace == self
|
77
|
+
Instrumenter.current_trace = nil
|
78
|
+
end
|
100
79
|
|
101
|
-
|
80
|
+
def submit
|
81
|
+
return if @submitted
|
102
82
|
|
103
|
-
|
83
|
+
release
|
84
|
+
@submitted = true
|
104
85
|
|
105
|
-
|
86
|
+
now = adjust_for_skew(Util::Clock.micros)
|
106
87
|
|
107
|
-
|
88
|
+
# Pop everything that is left
|
89
|
+
while sp = pop
|
90
|
+
@spans << sp.build(relativize(now) - sp.started_at)
|
91
|
+
end
|
108
92
|
|
109
|
-
|
110
|
-
end
|
93
|
+
time = gc_time
|
111
94
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
end
|
95
|
+
if time > 0
|
96
|
+
t { fmt "tracking GC time; duration=%d", time }
|
97
|
+
noise = start(now - time, GC_CAT, nil, nil, {})
|
98
|
+
stop(noise, now)
|
99
|
+
end
|
118
100
|
|
119
|
-
|
101
|
+
if sp = @stack.pop
|
102
|
+
@spans << sp.build(relativize(now) - sp.started_at)
|
120
103
|
end
|
121
104
|
|
122
|
-
Trace.new(
|
105
|
+
t = Trace.new(
|
123
106
|
uuid: 'TODO',
|
124
107
|
endpoint: endpoint,
|
125
108
|
spans: spans)
|
109
|
+
|
110
|
+
@instrumenter.process(t)
|
111
|
+
rescue Exception => e
|
112
|
+
error e
|
113
|
+
t { e.backtrace.join("\n") }
|
126
114
|
end
|
127
115
|
|
128
116
|
private
|
129
117
|
|
130
|
-
def
|
131
|
-
|
118
|
+
def start(time, cat, title, desc, annot)
|
119
|
+
sp = span(time, cat, title, desc, annot)
|
132
120
|
|
133
|
-
|
134
|
-
self, time, relativize(time),
|
135
|
-
cat, title, desc, annot)
|
136
|
-
end
|
121
|
+
push(sp)
|
137
122
|
|
138
|
-
|
139
|
-
|
123
|
+
sp
|
124
|
+
end
|
140
125
|
|
141
|
-
|
142
|
-
|
143
|
-
|
126
|
+
def stop(span, time)
|
127
|
+
until span == (sp = pop)
|
128
|
+
return unless sp
|
129
|
+
@spans << sp.build(relativize(time) - sp.started_at)
|
144
130
|
end
|
131
|
+
|
132
|
+
@spans << span.build(relativize(time) - sp.started_at)
|
133
|
+
|
134
|
+
nil
|
145
135
|
end
|
146
136
|
|
147
|
-
def
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
137
|
+
def span(time, cat, title, desc, annot)
|
138
|
+
Span::Builder.new(
|
139
|
+
self, time, relativize(time),
|
140
|
+
cat, title, desc, annot)
|
141
|
+
end
|
152
142
|
|
153
|
-
|
143
|
+
def pop
|
144
|
+
return unless @stack.length > 1
|
145
|
+
@stack.pop
|
146
|
+
end
|
154
147
|
|
155
|
-
|
148
|
+
def push(sp)
|
149
|
+
inc_children
|
150
|
+
@stack << sp
|
156
151
|
end
|
157
152
|
|
158
153
|
def inc_children
|
159
|
-
return unless sp = @
|
154
|
+
return unless sp = @stack[-1]
|
160
155
|
sp.children += 1
|
161
156
|
end
|
162
157
|
|
163
158
|
def relativize(time)
|
164
|
-
if parent = @
|
159
|
+
if parent = @stack[-1]
|
165
160
|
((time - parent.time) / 100).to_i
|
166
161
|
else
|
167
162
|
((time - @start) / 100).to_i
|
@@ -179,8 +174,13 @@ module Skylight
|
|
179
174
|
time
|
180
175
|
end
|
181
176
|
|
182
|
-
|
177
|
+
def gc_time
|
178
|
+
return 0 unless @gc
|
179
|
+
@gc.update
|
180
|
+
@gc.time
|
181
|
+
end
|
183
182
|
|
183
|
+
end
|
184
184
|
end
|
185
185
|
end
|
186
186
|
end
|
data/lib/skylight/middleware.rb
CHANGED
@@ -1,15 +1,59 @@
|
|
1
1
|
module Skylight
|
2
2
|
class Middleware
|
3
3
|
|
4
|
+
class BodyProxy
|
5
|
+
def initialize(body, &block)
|
6
|
+
@body, @block, @closed = body, block, false
|
7
|
+
end
|
8
|
+
|
9
|
+
def respond_to?(*args)
|
10
|
+
return false if args.first.to_s =~ /^to_ary$/
|
11
|
+
super or @body.respond_to?(*args)
|
12
|
+
end
|
13
|
+
|
14
|
+
def close
|
15
|
+
return if @closed
|
16
|
+
@closed = true
|
17
|
+
begin
|
18
|
+
@body.close if @body.respond_to? :close
|
19
|
+
ensure
|
20
|
+
@block.call
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def closed?
|
25
|
+
@closed
|
26
|
+
end
|
27
|
+
|
28
|
+
# N.B. This method is a special case to address the bug described by #434.
|
29
|
+
# We are applying this special case for #each only. Future bugs of this
|
30
|
+
# class will be handled by requesting users to patch their ruby
|
31
|
+
# implementation, to save adding too many methods in this class.
|
32
|
+
def each(*args, &block)
|
33
|
+
@body.each(*args, &block)
|
34
|
+
end
|
35
|
+
|
36
|
+
def method_missing(*args, &block)
|
37
|
+
super if args.first.to_s =~ /^to_ary$/
|
38
|
+
@body.__send__(*args, &block)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
4
42
|
def initialize(app)
|
5
43
|
@app = app
|
6
44
|
end
|
7
45
|
|
8
46
|
def call(env)
|
9
|
-
|
10
|
-
trace.
|
11
|
-
|
12
|
-
|
47
|
+
begin
|
48
|
+
trace = Skylight.trace "Rack", 'app.rack.request'
|
49
|
+
resp = @app.call(env)
|
50
|
+
resp[2] = BodyProxy.new(resp[2]) { trace.submit } if trace
|
51
|
+
resp
|
52
|
+
rescue Exception
|
53
|
+
trace.submit if trace
|
54
|
+
raise
|
55
|
+
ensure
|
56
|
+
trace.release if trace
|
13
57
|
end
|
14
58
|
end
|
15
59
|
end
|
data/lib/skylight/railtie.rb
CHANGED
@@ -17,7 +17,7 @@ module Skylight
|
|
17
17
|
Instrumenter.start!(config)
|
18
18
|
app.middleware.insert 0, Middleware
|
19
19
|
|
20
|
-
|
20
|
+
puts "[SKYLIGHT] Skylight agent enabled"
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
@@ -29,7 +29,7 @@ module Skylight
|
|
29
29
|
path = nil unless File.exist?(path)
|
30
30
|
|
31
31
|
unless tmp = app.config.paths['tmp'].first
|
32
|
-
|
32
|
+
puts "[SKYLIGHT] tmp directory missing from rails configuration"
|
33
33
|
return nil
|
34
34
|
end
|
35
35
|
|
@@ -41,7 +41,7 @@ module Skylight
|
|
41
41
|
config
|
42
42
|
|
43
43
|
rescue ConfigError => e
|
44
|
-
|
44
|
+
puts "[SKYLIGHT] #{e.message}; disabling Skylight agent"
|
45
45
|
nil
|
46
46
|
end
|
47
47
|
|
data/lib/skylight/subscriber.rb
CHANGED
@@ -20,43 +20,49 @@ module Skylight
|
|
20
20
|
@subscriber = nil
|
21
21
|
end
|
22
22
|
|
23
|
-
def instrument(category, *args)
|
24
|
-
return unless trace = Instrumenter.current_trace
|
25
|
-
|
26
|
-
annot = args.pop if Hash === args
|
27
|
-
title = args.shift
|
28
|
-
desc = args.shift
|
29
|
-
|
30
|
-
trace.start(now - gc_time, category, title, desc, annot)
|
31
|
-
end
|
32
|
-
|
33
|
-
def done
|
34
|
-
return unless trace = Instrumenter.current_trace
|
35
|
-
trace.stop(now - gc_time)
|
36
|
-
end
|
37
|
-
|
38
23
|
#
|
39
24
|
#
|
40
25
|
# ===== ActiveSupport::Notifications API
|
41
26
|
#
|
42
27
|
#
|
43
28
|
|
29
|
+
class Notification
|
30
|
+
attr_reader :name, :span
|
31
|
+
|
32
|
+
def initialize(name, span)
|
33
|
+
@name, @span = name, span
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
44
37
|
def start(name, id, payload)
|
45
38
|
return unless trace = Instrumenter.current_trace
|
46
39
|
|
47
40
|
cat, title, desc, annot = normalize(trace, name, payload)
|
48
|
-
trace.start(now - gc_time, cat, title, desc, annot)
|
49
41
|
|
50
|
-
|
42
|
+
unless cat == :skip
|
43
|
+
span = trace.instrument(cat, title, desc, annot)
|
44
|
+
end
|
45
|
+
|
46
|
+
trace.notifications << Notification.new(name, span)
|
47
|
+
|
51
48
|
rescue Exception => e
|
52
49
|
error "Subscriber#start error; msg=%s", e.message
|
50
|
+
nil
|
53
51
|
end
|
54
52
|
|
55
53
|
def finish(name, id, payload)
|
56
54
|
return unless trace = Instrumenter.current_trace
|
57
|
-
|
55
|
+
|
56
|
+
while curr = trace.notifications.pop
|
57
|
+
if curr.name == name
|
58
|
+
curr.span.done if curr.span
|
59
|
+
return
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
58
63
|
rescue Exception => e
|
59
64
|
error "Subscriber#finish error; msg=%s", e.message
|
65
|
+
nil
|
60
66
|
end
|
61
67
|
|
62
68
|
def publish(name, *args)
|
@@ -69,14 +75,5 @@ module Skylight
|
|
69
75
|
@normalizers.normalize(*args)
|
70
76
|
end
|
71
77
|
|
72
|
-
def gc_time
|
73
|
-
GC.update
|
74
|
-
GC.time
|
75
|
-
end
|
76
|
-
|
77
|
-
def now
|
78
|
-
Util::Clock.micros
|
79
|
-
end
|
80
|
-
|
81
78
|
end
|
82
79
|
end
|
data/lib/skylight/util/queue.rb
CHANGED
@@ -3,7 +3,7 @@ require 'thread'
|
|
3
3
|
module Skylight
|
4
4
|
module Util
|
5
5
|
# Simple thread-safe queue backed by a ring buffer. Will only block when
|
6
|
-
# poping.
|
6
|
+
# poping. Single consumer only
|
7
7
|
class Queue
|
8
8
|
|
9
9
|
def initialize(max)
|
@@ -15,7 +15,7 @@ module Skylight
|
|
15
15
|
@values = [nil] * max
|
16
16
|
@consume = 0
|
17
17
|
@produce = 0
|
18
|
-
@waiting =
|
18
|
+
@waiting = nil
|
19
19
|
@mutex = Mutex.new
|
20
20
|
end
|
21
21
|
|
@@ -39,11 +39,8 @@ module Skylight
|
|
39
39
|
ret = __length
|
40
40
|
|
41
41
|
# Wakeup a blocked thread
|
42
|
-
|
43
|
-
t
|
44
|
-
t.wakeup if t
|
45
|
-
rescue ThreadError
|
46
|
-
retry
|
42
|
+
if t = @waiting
|
43
|
+
t.run rescue nil
|
47
44
|
end
|
48
45
|
end
|
49
46
|
|
@@ -58,11 +55,13 @@ module Skylight
|
|
58
55
|
@mutex.synchronize do
|
59
56
|
if __empty?
|
60
57
|
if !timeout || timeout > 0
|
61
|
-
|
62
|
-
@waiting
|
63
|
-
|
64
|
-
|
65
|
-
|
58
|
+
return if @waiting
|
59
|
+
@waiting = Thread.current
|
60
|
+
begin
|
61
|
+
@mutex.sleep(timeout)
|
62
|
+
ensure
|
63
|
+
@waiting = nil
|
64
|
+
end
|
66
65
|
else
|
67
66
|
return
|
68
67
|
end
|
@@ -34,6 +34,13 @@ module Skylight
|
|
34
34
|
|
35
35
|
|
36
36
|
module Dsl
|
37
|
+
def self.extended(base)
|
38
|
+
initializer = Module.new
|
39
|
+
base.instance_variable_set(:@__initializer, initializer)
|
40
|
+
base.__write_initializer
|
41
|
+
base.send(:include, initializer)
|
42
|
+
end
|
43
|
+
|
37
44
|
def required(name, type, fn, opts={})
|
38
45
|
field(:required, name, type, fn, opts)
|
39
46
|
end
|
@@ -48,12 +55,27 @@ module Skylight
|
|
48
55
|
|
49
56
|
def field(rule, name, type, fn, opts)
|
50
57
|
fields[fn] = Field.new(rule, name, type, fn, opts)
|
58
|
+
__write_initializer
|
51
59
|
attr_accessor name
|
52
60
|
end
|
53
61
|
|
54
62
|
def fields
|
55
63
|
@fields ||= {}
|
56
64
|
end
|
65
|
+
|
66
|
+
def __write_initializer
|
67
|
+
lines = []
|
68
|
+
|
69
|
+
lines << "def initialize(attrs=nil)"
|
70
|
+
lines << "return unless attrs"
|
71
|
+
fields.values.each do |fld|
|
72
|
+
lines << "@#{fld.name} = attrs[:#{fld.name}]"
|
73
|
+
end
|
74
|
+
|
75
|
+
lines << "end"
|
76
|
+
|
77
|
+
@__initializer.module_eval(lines.join("\n"), __FILE__, __LINE__+1)
|
78
|
+
end
|
57
79
|
end
|
58
80
|
|
59
81
|
module Encode
|
@@ -133,7 +155,8 @@ module Skylight
|
|
133
155
|
|
134
156
|
|
135
157
|
module Decode
|
136
|
-
|
158
|
+
# Use allocate instead of new for performance
|
159
|
+
def decode(buf, o=self.allocate)
|
137
160
|
if ! buf.is_a?(Buffer)
|
138
161
|
buf = Buffer.new(buf)
|
139
162
|
end
|
@@ -191,12 +214,6 @@ module Skylight
|
|
191
214
|
o.send(:include, Encode)
|
192
215
|
end
|
193
216
|
|
194
|
-
def initialize(attrs={})
|
195
|
-
fields.values.each do |fld|
|
196
|
-
self[fld.name] = attrs[fld.name]
|
197
|
-
end
|
198
|
-
end
|
199
|
-
|
200
217
|
def fields
|
201
218
|
self.class.fields
|
202
219
|
end
|
data/lib/skylight/version.rb
CHANGED
@@ -18,6 +18,7 @@ module Skylight
|
|
18
18
|
@size = config[:'agent.sample']
|
19
19
|
@batch = nil
|
20
20
|
@interval = config[:'agent.interval']
|
21
|
+
@buf = ""
|
21
22
|
|
22
23
|
t { fmt "starting collector; interval=%d; size=%d", @interval, @size }
|
23
24
|
end
|
@@ -53,8 +54,10 @@ module Skylight
|
|
53
54
|
def flush(batch)
|
54
55
|
return if batch.empty?
|
55
56
|
|
56
|
-
|
57
|
-
|
57
|
+
debug "flushing batch; size=%d", batch.sample.count
|
58
|
+
|
59
|
+
@buf.clear
|
60
|
+
@http.post(ENDPOINT, batch.encode(@buf), CONTENT_TYPE => SKYLIGHT_V1)
|
58
61
|
end
|
59
62
|
|
60
63
|
def new_batch(now)
|
@@ -93,7 +96,7 @@ module Skylight
|
|
93
96
|
@sample << trace
|
94
97
|
end
|
95
98
|
|
96
|
-
def encode
|
99
|
+
def encode(buf)
|
97
100
|
endpoints = {}
|
98
101
|
|
99
102
|
sample.each do |trace|
|
@@ -115,7 +118,9 @@ module Skylight
|
|
115
118
|
Messages::Batch.new(
|
116
119
|
timestamp: from,
|
117
120
|
endpoints: endpoints.values).
|
118
|
-
encode
|
121
|
+
encode(buf)
|
122
|
+
|
123
|
+
buf
|
119
124
|
end
|
120
125
|
end
|
121
126
|
|
@@ -2,6 +2,7 @@ require 'socket'
|
|
2
2
|
require 'thread'
|
3
3
|
require 'fileutils'
|
4
4
|
|
5
|
+
# TODO: Handle cool-off
|
5
6
|
module Skylight
|
6
7
|
module Worker
|
7
8
|
# Handle to the agent subprocess. Manages creation, communication, and
|
@@ -146,17 +147,17 @@ module Skylight
|
|
146
147
|
# is still healthy but is simply reloading itself, this should work
|
147
148
|
# just fine.
|
148
149
|
if sock = connect(@pid)
|
149
|
-
|
150
|
+
t { "reconnected to worker" }
|
150
151
|
@sock = sock
|
151
152
|
# TODO: Should HELLO be sent again?
|
152
153
|
return true
|
153
154
|
end
|
154
155
|
|
155
|
-
|
156
|
+
debug "failed to reconnect -- attempting worker respawn"
|
156
157
|
|
157
158
|
# Attempt to respawn the agent process
|
158
159
|
unless __spawn
|
159
|
-
|
160
|
+
debug "could not respawn -- shutting down"
|
160
161
|
|
161
162
|
@pid = nil
|
162
163
|
@sock = nil
|
@@ -205,10 +206,13 @@ module Skylight
|
|
205
206
|
@sock = nil
|
206
207
|
sock.close rescue nil
|
207
208
|
|
208
|
-
|
209
|
-
|
209
|
+
unless repair
|
210
|
+
return false
|
211
|
+
end
|
210
212
|
end
|
211
213
|
|
214
|
+
debug "could not handle message; msg=%s", msg.class
|
215
|
+
|
212
216
|
false
|
213
217
|
end
|
214
218
|
|
@@ -231,23 +235,39 @@ module Skylight
|
|
231
235
|
end
|
232
236
|
end
|
233
237
|
|
234
|
-
def write(sock, msg, timeout =
|
238
|
+
def write(sock, msg, timeout = 5)
|
235
239
|
msg = msg.to_s
|
236
|
-
cnt =
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
240
|
+
cnt = 10
|
241
|
+
|
242
|
+
begin
|
243
|
+
while true
|
244
|
+
res = sock.write_nonblock(msg)
|
245
|
+
|
246
|
+
if res == msg.bytesize
|
247
|
+
return true
|
248
|
+
elsif res > 0
|
249
|
+
msg = msg.byteslice(res..-1)
|
250
|
+
cnt = 10
|
251
|
+
else
|
252
|
+
if 0 <= (cnt -= 1)
|
253
|
+
t { "write failed -- max attempts" }
|
254
|
+
return false
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
rescue Errno::EAGAIN, Errno::EWOULDBLOCK
|
259
|
+
_, socks, = IO.select([], [sock], [], timeout)
|
260
|
+
unless socks == [sock]
|
261
|
+
t { "write timed out" }
|
262
|
+
return false
|
247
263
|
end
|
264
|
+
retry
|
265
|
+
rescue Errno::EINTR
|
266
|
+
raise
|
267
|
+
rescue SystemCallError => e
|
268
|
+
t { fmt "write failed; err=%s", e.class }
|
269
|
+
return false
|
248
270
|
end
|
249
|
-
|
250
|
-
return false
|
251
271
|
end
|
252
272
|
|
253
273
|
# Spawn the worker process.
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: skylight
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.6.
|
4
|
+
version: 0.1.6.alpha3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tilde, Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-06-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -24,20 +24,6 @@ dependencies:
|
|
24
24
|
- - '>='
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 3.0.0
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: actionpack
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - '>='
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: 3.0.0
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - '>='
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: 3.0.0
|
41
27
|
description: Currently in pre-alpha.
|
42
28
|
email:
|
43
29
|
- engineering@tilde.io
|