skylight 0.1.5.alpha2 → 0.1.5

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