skylight 0.1.5.alpha2 → 0.1.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6059d5cc28b761943e1e644d04404a1f4420b41d
4
- data.tar.gz: e9df2d646694636ef1f68db3787571249df39606
3
+ metadata.gz: ffd96c332034f1a8aac5a14cb5a326edc78b3940
4
+ data.tar.gz: 2013e889ac8555f1fbbe27b018c337c0039ed39c
5
5
  SHA512:
6
- metadata.gz: 49ddf44811aef8f2f440712baef90ed957f87cf4caddacee72074e2d9ada901f7f7fd149645aa17ad0698a06c616f86feecec2b25641e41a900e667d5c3ad38c
7
- data.tar.gz: e6ff2793abc7d6781ae8acf7ca196bb60f2e4ef2c4f49bf6f3de9b0ad9a7830d9b215af60049c85f2f968a2db3a2f42528de538d00098c2dd223d100c55693be
6
+ metadata.gz: ef18196dcd99d0eb39d6d47e0f92e0fe762e52c8fede06778bd44cd8e258de3eb453c2bbf65eab939d87b71f3df002106c8e278eb029339e00451713977cf330
7
+ data.tar.gz: d9bae247b299859a0e3095ad849c6ea24ef1d82affc3deba326cb2965b34ed5d2abc88cb67a1cf51fa10cb2b4cd939e088f2e059fcb4af786d9c8de40979cb80
data/CHANGELOG.md CHANGED
@@ -1,6 +1,10 @@
1
1
  ## unreleased ##
2
2
 
3
+ ## 0.1.5 (May 31, 2013)
4
+
3
5
  * Provide a default CA cert when one is not already present
6
+ * Expose Skylight.start! and Skylight.trace as APIs
7
+ * Expose Skylight.instrument as an API for custom instrumentation.
4
8
 
5
9
  ## 0.1.4 (May 30, 2013)
6
10
 
data/lib/skylight.rb CHANGED
@@ -50,12 +50,34 @@ module Skylight
50
50
  class TraceError < RuntimeError; end
51
51
 
52
52
  TIERS = %w(
53
+ api
53
54
  app
54
55
  view
55
56
  db
56
57
  noise
57
58
  other)
58
59
 
60
+ TIER_REGEX = /^(?:#{TIERS.join('|')})(?:\.|$)/
61
+ CATEGORY_REGEX = /^[a-z0-9_-]+(?:\.[a-z0-9_-]+)*$/i
62
+
63
+ def self.start!(*args)
64
+ Instrumenter.start!(*args)
65
+ end
66
+
67
+ def self.stop!(*args)
68
+ Instrumenter.stop!(*args)
69
+ end
70
+
71
+ def self.trace(*args, &blk)
72
+ return yield unless inst = Instrumenter.instance
73
+ inst.trace(*args, &blk)
74
+ end
75
+
76
+ def self.instrument(*args, &blk)
77
+ return yield unless inst = Instrumenter.instance
78
+ inst.instrument(*args, &blk)
79
+ end
80
+
59
81
  RUBYBIN = File.join(
60
82
  RbConfig::CONFIG['bindir'],
61
83
  "#{RbConfig::CONFIG['ruby_install_name']}#{RbConfig::CONFIG['EXEEXT']}")
@@ -2,7 +2,8 @@ require 'thread'
2
2
 
3
3
  module Skylight
4
4
  class Instrumenter
5
- KEY = :__skylight_current_trace
5
+ KEY = :__skylight_current_trace
6
+ LOCK = Mutex.new
6
7
 
7
8
  include Util::Logging
8
9
 
@@ -14,8 +15,25 @@ module Skylight
14
15
  Thread.current[KEY] = trace
15
16
  end
16
17
 
18
+ def self.instance
19
+ @instance
20
+ end
21
+
17
22
  def self.start!(config = Config.new)
18
- new(config).start!
23
+ return @instance if @instance
24
+
25
+ LOCK.synchronize do
26
+ return @instance if @instance
27
+ @instance = new(config).start!
28
+ end
29
+ end
30
+
31
+ def self.stop!
32
+ LOCK.synchronize do
33
+ return unless @instance
34
+ @instance.shutdown
35
+ @instance = nil
36
+ end
19
37
  end
20
38
 
21
39
  attr_reader :config, :gc
@@ -26,31 +44,19 @@ module Skylight
26
44
  end
27
45
 
28
46
  @gc = config.gc
29
- @lock = Mutex.new
30
47
  @config = config
31
48
  @worker = config.worker.build
32
- @started = false
33
49
  @subscriber = Subscriber.new(config)
34
50
  end
35
51
 
36
52
  def start!
37
- # Quick check
38
- return self if @started
39
53
  return unless config
40
54
 
41
- @lock.synchronize do
42
- # Ensure that the instrumenter has not been started now that the lock
43
- # has been acquired.
44
- return self if @started
45
-
46
- t { "starting instrumenter" }
47
- @config.validate!
48
- @config.gc.enable
49
- @worker.spawn
50
- @subscriber.register!
51
-
52
- @started = true
53
- end
55
+ t { "starting instrumenter" }
56
+ @config.validate!
57
+ @config.gc.enable
58
+ @worker.spawn
59
+ @subscriber.register!
54
60
 
55
61
  self
56
62
 
@@ -60,19 +66,11 @@ module Skylight
60
66
  end
61
67
 
62
68
  def shutdown
63
- @lock.synchronize do
64
- return unless @started
65
- @subscriber.unregister!
66
- @worker.shutdown
67
- end
69
+ @subscriber.unregister!
70
+ @worker.shutdown
68
71
  end
69
72
 
70
73
  def trace(endpoint = 'Unknown')
71
- # Ignore everything unless the instrumenter has been started
72
- unless @started
73
- return yield
74
- end
75
-
76
74
  # If a trace is already in progress, continue with that one
77
75
  if trace = Instrumenter.current_trace
78
76
  t { "already tracing" }
@@ -98,7 +96,8 @@ module Skylight
98
96
  if built && built.spans.empty?
99
97
  debug "trace invalid -- dropping; spans=0"
100
98
  elsif built
101
- debug "trace invalid -- dropping; spans=%d; started_at=%d", built.spans, built.spans[-1].started_at
99
+ debug "trace invalid -- dropping; spans=%d; started_at=%d",
100
+ built.spans.length, built.spans[-1].started_at
102
101
  else
103
102
  debug "trace invalid -- dropping; trace=nil"
104
103
  end
@@ -109,6 +108,25 @@ module Skylight
109
108
  end
110
109
  end
111
110
 
111
+ def instrument(cat, *args)
112
+ cat = cat.to_s
113
+
114
+ unless cat =~ CATEGORY_REGEX
115
+ warn "invalid skylight instrumentation category; value=%s", cat
116
+ return yield
117
+ end
118
+
119
+ cat = "other.#{cat}" unless cat =~ TIER_REGEX
120
+
121
+ return yield unless sp = @subscriber.instrument(cat, *args)
122
+
123
+ begin
124
+ yield sp
125
+ ensure
126
+ @subscriber.done
127
+ end
128
+ end
129
+
112
130
  private
113
131
 
114
132
  def process(trace)
@@ -16,6 +16,68 @@ module Skylight
16
16
  def initialize(attrs = nil)
17
17
  super if attrs
18
18
  end
19
+
20
+ class Builder
21
+
22
+ attr_reader \
23
+ :time,
24
+ :category,
25
+ :title,
26
+ :started_at,
27
+ :description,
28
+ :annotations
29
+
30
+ attr_accessor :children
31
+
32
+ def initialize(trace, time, started_at, cat, title, desc, annot)
33
+ @trace = trace
34
+ @built = false
35
+ @time = time
36
+ @started_at = started_at
37
+ @category = cat.to_s
38
+ @children = 0
39
+ self.title = title
40
+ self.description = desc
41
+ end
42
+
43
+ def endpoint=(name)
44
+ @trace.endpoint = name
45
+ end
46
+
47
+ def built?
48
+ @built
49
+ end
50
+
51
+ def build(duration)
52
+ @built = true
53
+ Span.new(
54
+ event: Event.new(
55
+ category: category,
56
+ title: title,
57
+ description: description),
58
+ annotations: to_annotations(annotations),
59
+ started_at: @started_at,
60
+ duration: duration && duration > 0 ? duration : nil,
61
+ children: @children > 0 ? @children : nil)
62
+ end
63
+
64
+ def title=(val)
65
+ val = nil unless val.respond_to?(:to_str)
66
+ @title = val && val.to_str
67
+ end
68
+
69
+ def description=(val)
70
+ val = nil unless val.respond_to?(:to_str)
71
+ @description = val && val.to_str
72
+ end
73
+
74
+ private
75
+
76
+ def to_annotations(val)
77
+ [] # TODO: Implement
78
+ end
79
+
80
+ end
19
81
  end
20
82
  end
21
83
  end
@@ -73,12 +73,12 @@ module Skylight
73
73
 
74
74
  sp = span(time, cat, title, desc, annot)
75
75
 
76
- return self if :skip == sp
76
+ return if :skip == sp
77
77
 
78
78
  inc_children
79
- @spans << sp
79
+ @spans << sp.build(0)
80
80
 
81
- self
81
+ nil
82
82
  end
83
83
 
84
84
  def start(time, cat, title = nil, desc = nil, annot = {})
@@ -90,7 +90,9 @@ module Skylight
90
90
 
91
91
  push(sp)
92
92
 
93
- self
93
+ return if :skip == sp
94
+
95
+ sp
94
96
  end
95
97
 
96
98
  def stop(time)
@@ -100,12 +102,11 @@ module Skylight
100
102
 
101
103
  sp = pop
102
104
 
103
- return self if :skip == sp
105
+ return if :skip == sp
104
106
 
105
- sp.duration = relativize(time) - sp.started_at
106
- @spans << sp
107
+ @spans << sp.build(relativize(time) - sp.started_at)
107
108
 
108
- self
109
+ nil
109
110
  end
110
111
 
111
112
  def build
@@ -123,30 +124,9 @@ module Skylight
123
124
  def span(time, cat, title, desc, annot)
124
125
  return cat if :skip == cat
125
126
 
126
- sp = Span.new
127
- sp.event = event(cat, title, desc)
128
- sp.annotations = to_annotations(annot)
129
- sp.started_at = relativize(time)
130
- sp.absolute_time = time
131
-
132
- if sp.started_at < 0
133
- @busted = true
134
- raise TraceError, "[BUG] span started_at negative; event=#{cat};" \
135
- " started_at=#{sp.started_at};" \
136
- " duration=#{sp.duration}"
137
- end
138
-
139
- sp
140
- end
141
-
142
- def event(cat, title, desc)
143
- title = nil unless title.respond_to?(:to_str)
144
- desc = nil unless desc.respond_to?(:to_str)
145
-
146
- Event.new(
147
- category: cat.to_s,
148
- title: title && title.to_str,
149
- description: desc && desc.to_str)
127
+ Span::Builder.new(
128
+ self, time, relativize(time),
129
+ cat, title, desc, annot)
150
130
  end
151
131
 
152
132
  def push(sp)
@@ -171,16 +151,12 @@ module Skylight
171
151
 
172
152
  def inc_children
173
153
  return unless sp = @parents.last
174
- sp.children = (sp.children || 0) + 1
175
- end
176
-
177
- def to_annotations(annot)
178
- [] # TODO: Implement
154
+ sp.children += 1
179
155
  end
180
156
 
181
157
  def relativize(time)
182
158
  if parent = @parents[-1]
183
- ((time - parent.absolute_time) / 100).to_i
159
+ ((time - parent.time) / 100).to_i
184
160
  else
185
161
  ((time - @start) / 100).to_i
186
162
  end
@@ -1,18 +1,12 @@
1
1
  module Skylight
2
2
  class Middleware
3
3
 
4
- def self.new(app, instrumenter, *)
5
- return app unless instrumenter
6
- super
7
- end
8
-
9
- def initialize(app, instrumenter)
4
+ def initialize(app)
10
5
  @app = app
11
- @instrumenter = instrumenter
12
6
  end
13
7
 
14
8
  def call(env)
15
- @instrumenter.trace("Rack") do |trace|
9
+ Skylight.trace "Rack" do |trace|
16
10
  trace.root 'app.rack.request' do
17
11
  @app.call(env)
18
12
  end
@@ -1,10 +1,9 @@
1
1
  module Skylight
2
2
  module Normalizers
3
3
  class Default
4
- REGEX = /^(?:#{TIERS.join('|')})(?:\.|$)/
5
4
 
6
5
  def normalize(trace, name, payload)
7
- if name =~ REGEX
6
+ if name =~ TIER_REGEX
8
7
  annot = payload.dup
9
8
  [
10
9
  name,
@@ -14,9 +14,8 @@ module Skylight
14
14
  initializer 'skylight.configure' do |app|
15
15
  if activate?
16
16
  if config = load_skylight_config(app)
17
- @instrumenter = Instrumenter.start!(config)
18
-
19
- app.middleware.insert 0, Middleware, @instrumenter
17
+ Instrumenter.start!(config)
18
+ app.middleware.insert 0, Middleware
20
19
 
21
20
  Rails.logger.info "[SKYLIGHT] Skylight agent enabled"
22
21
  end
@@ -20,6 +20,27 @@ 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
+ #
39
+ #
40
+ # ===== ActiveSupport::Notifications API
41
+ #
42
+ #
43
+
23
44
  def start(name, id, payload)
24
45
  return unless trace = Instrumenter.current_trace
25
46
 
@@ -1,4 +1,4 @@
1
1
  module Skylight
2
- VERSION = '0.1.5.alpha2'
2
+ VERSION = '0.1.5'
3
3
  end
4
4
 
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.5.alpha2
4
+ version: 0.1.5
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-05-30 00:00:00.000000000 Z
11
+ date: 2013-05-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -157,9 +157,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
157
157
  version: 1.9.2
158
158
  required_rubygems_version: !ruby/object:Gem::Requirement
159
159
  requirements:
160
- - - '>'
160
+ - - '>='
161
161
  - !ruby/object:Gem::Version
162
- version: 1.3.1
162
+ version: '0'
163
163
  requirements: []
164
164
  rubyforge_project:
165
165
  rubygems_version: 2.0.3