skylight 0.2.0.beta.4 → 0.2.0

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: 6c34ce7c2bd1892ae5f05d4e9cc0ee5054cbb9f1
4
- data.tar.gz: ce556c192f1f5b1d72be7680d358d8373a80cfe7
3
+ metadata.gz: 01c568e8a8c6485f4257cc1cbd29c7649fa11397
4
+ data.tar.gz: 15a33396cd41de105c07c3879c65fbe7a0c30ea3
5
5
  SHA512:
6
- metadata.gz: a9b4be609c1d76a2075cbb9ad116d724fc35be01dfe133e00978c3b09a8e32765a78d2db0ccb2f3c43a60182891a57e42ee8bcecd53ec8d50750a6fc2f38f138
7
- data.tar.gz: 082e9dd9bfc81ea18b53b830c52bf26796b90943c6af65b78723b21a8d1207478f87ac835a8386c4f0741a4fb97d9d89200ed2746b8fdadb8d9945b869c1a975
6
+ metadata.gz: 0dda0d97a94a3e6366110f8a88fa50c16abede270e0f1eae2908f80aeef5b4c279c948e53cc5e52c89f815d906aed9c05c55abe22bdd6ebb6a00a15b2cd8acd6
7
+ data.tar.gz: e9563e4dda34af825883d28260d098176bc30bb7217fdf6f2a845472a6c1a9a7d2bdf26ba92988b6e46eac568cbcedc2094977add1e2f5e1845db4cc8475eedb
@@ -1,4 +1,13 @@
1
- ## unreleased ##
1
+ ## 0.2.0 (December 3, 2013)
2
+
3
+ * Added Probes, initially Net::HTTP and Excon
4
+ * Wide-ranging memory cleanup
5
+ * Better resiliance to binary and encoding errors
6
+ * Add support for disabling
7
+ * De-dupe rendering instrumentation better
8
+ * Fix send_file event to not spew a gazillion nodes
9
+ * Rails 3.0 compatibility
10
+ * Detailed SQL annotations
2
11
 
3
12
  ## 0.1.8 (July 19, 2013)
4
13
 
@@ -35,12 +35,17 @@ module Skylight
35
35
  autoload :Clock, 'skylight/util/clock'
36
36
  autoload :Gzip, 'skylight/util/gzip'
37
37
  autoload :HTTP, 'skylight/util/http'
38
+ autoload :Inflector, 'skylight/util/inflector'
38
39
  autoload :Logging, 'skylight/util/logging'
39
40
  autoload :Queue, 'skylight/util/queue'
40
41
  autoload :Task, 'skylight/util/task'
41
42
  autoload :UniformSample, 'skylight/util/uniform_sample'
42
43
  end
43
44
 
45
+ module Formatters
46
+ autoload :HTTP, 'skylight/formatters/http'
47
+ end
48
+
44
49
  # ==== Vendor ====
45
50
  autoload :Beefcake, 'skylight/vendor/beefcake'
46
51
 
@@ -127,4 +132,6 @@ module Skylight
127
132
  if defined?(Rails)
128
133
  require 'skylight/railtie'
129
134
  end
135
+
136
+ require 'skylight/probes'
130
137
  end
@@ -255,6 +255,10 @@ authentication: #{self[:authentication]}
255
255
  @gc ||= GC.new(self, get('gc.profiler', VM::GC.new))
256
256
  end
257
257
 
258
+ def constant_flush?
259
+ get('test.constant_flush')
260
+ end
261
+
258
262
  def root
259
263
  self[:root] || Dir.pwd
260
264
  end
@@ -0,0 +1,32 @@
1
+ module Skylight
2
+ module Formatters
3
+ module HTTP
4
+
5
+ def self.build_opts(method, scheme, host, port, path, query)
6
+ category = "api.http.#{method.downcase}"
7
+ title = "#{method.upcase} #{host || path}"
8
+ description = "#{method.upcase} #{build_url(scheme, host, port, path, query)}"
9
+
10
+ { category: category, title: title, description: description }
11
+ end
12
+
13
+ def self.build_url(scheme, host, port, path, query)
14
+ url = ''
15
+ if scheme
16
+ url << "#{scheme}://"
17
+ end
18
+ if host
19
+ url << host
20
+ end
21
+ if port
22
+ url << ":#{port}"
23
+ end
24
+ url << path
25
+ if query
26
+ url << "?#{query}"
27
+ end
28
+ url
29
+ end
30
+ end
31
+ end
32
+ end
@@ -78,7 +78,8 @@ module Skylight
78
78
 
79
79
  SEPARATOR_BYTE = File::SEPARATOR.ord
80
80
 
81
- if File::NULL == "NUL"
81
+ if File.const_defined?(:NULL) ? File::NULL == "NUL" : RbConfig::CONFIG['host_os'] =~ /mingw|mswin32/
82
+ # This is a DOSish environment
82
83
  ALT_SEPARATOR_BYTE = File::ALT_SEPARATOR && File::ALT_SEPARATOR.ord
83
84
  COLON_BYTE = ":".ord
84
85
  def absolute_path?(path)
@@ -0,0 +1,90 @@
1
+ # skylight/probes.rb
2
+
3
+ module Skylight
4
+ module Probes
5
+
6
+ class ProbeRegistration
7
+ attr_reader :klass_name, :require_paths, :probe
8
+
9
+ def initialize(klass_name, require_paths, probe)
10
+ @klass_name = klass_name
11
+ @require_paths = Array(require_paths)
12
+ @probe = probe
13
+ end
14
+
15
+ def install
16
+ probe.install
17
+ end
18
+ end
19
+
20
+ def self.require_hooks
21
+ @require_hooks ||= {}
22
+ end
23
+
24
+ def self.installed
25
+ @installed ||= {}
26
+ end
27
+
28
+ def self.is_available?(klass_name)
29
+ !!Skylight::Util::Inflector.safe_constantize(klass_name)
30
+ end
31
+
32
+ def self.register(*args)
33
+ registration = ProbeRegistration.new(*args)
34
+
35
+ if is_available?(registration.klass_name)
36
+ installed[registration.klass_name] = registration
37
+ registration.install
38
+ else
39
+ register_require_hook(registration)
40
+ end
41
+ end
42
+
43
+ def self.require_hook(require_path)
44
+ registration = lookup_by_require_path(require_path)
45
+ return unless registration
46
+
47
+ # Double check constant is available
48
+ if is_available?(registration.klass_name)
49
+ installed[registration.klass_name] = registration
50
+ registration.install
51
+
52
+ # Don't need this to be called again
53
+ unregister_require_hook(registration)
54
+ end
55
+ end
56
+
57
+ def self.register_require_hook(registration)
58
+ registration.require_paths.each do |p|
59
+ require_hooks[p] = registration
60
+ end
61
+ end
62
+
63
+ def self.unregister_require_hook(registration)
64
+ registration.require_paths.each do |p|
65
+ require_hooks.delete(p)
66
+ end
67
+ end
68
+
69
+ def self.lookup_by_require_path(require_path)
70
+ require_hooks[require_path]
71
+ end
72
+ end
73
+ end
74
+
75
+ # Allow hooking require
76
+ module ::Kernel
77
+ alias require_without_sk require
78
+
79
+ def require(name)
80
+ ret = require_without_sk(name)
81
+
82
+ begin
83
+ Skylight::Probes.require_hook(name)
84
+ rescue Exception
85
+ # FIXME: Log these errors
86
+ end
87
+
88
+ ret
89
+ end
90
+ end
@@ -0,0 +1,19 @@
1
+ module Skylight
2
+ module Probes
3
+ module Excon
4
+ class Probe
5
+ def install
6
+ # Don't require until installation since it depends on Excon being loaded
7
+ require 'skylight/probes/excon/middleware'
8
+
9
+ idx = ::Excon.defaults[:middlewares].index(::Excon::Middleware::Instrumentor)
10
+
11
+ # TODO: Handle possibility of idx being nil
12
+ ::Excon.defaults[:middlewares].insert(idx, Skylight::Probes::Excon::Middleware)
13
+ end
14
+ end
15
+ end
16
+
17
+ register("Excon", "excon", Excon::Probe.new)
18
+ end
19
+ end
@@ -0,0 +1,62 @@
1
+ module Skylight
2
+ module Probes
3
+ module Excon
4
+ class Middleware < ::Excon::Middleware::Base
5
+
6
+ include Util::Logging
7
+
8
+ def initialize(*)
9
+ @requests = {}
10
+ super
11
+ end
12
+
13
+ # TODO:
14
+ # - Consider whether a LIFO queue would be sufficient
15
+ # - Check that errors can't be called without a request
16
+
17
+ def request_call(datum)
18
+ begin_instrumentation(datum)
19
+ super
20
+ end
21
+
22
+ def response_call(datum)
23
+ super
24
+ ensure
25
+ end_instrumentation(datum)
26
+ end
27
+
28
+ def error_call(datum)
29
+ super
30
+ ensure
31
+ end_instrumentation(datum)
32
+ end
33
+
34
+ private
35
+
36
+ def begin_instrumentation(datum)
37
+ method = datum[:method].to_s
38
+ scheme = datum[:scheme]
39
+ host = datum[:host]
40
+ # TODO: Maybe don't show other default ports like 443
41
+ port = datum[:port] != 80 ? datum[:port] : nil
42
+ path = datum[:path]
43
+ query = datum[:query]
44
+
45
+ opts = Formatters::HTTP.build_opts(method, scheme, host, port, path, query)
46
+
47
+ @requests[datum.object_id] = Skylight.instrument(opts)
48
+ rescue Exception => e
49
+ error "failed to begin instrumentation for Excon; msg=%s", e.message
50
+ end
51
+
52
+ def end_instrumentation(datum)
53
+ @requests[datum.object_id].done
54
+ @requests.delete(datum)
55
+ rescue Exception => e
56
+ error "failed to end instrumentation for Excon; msg=%s", e.message
57
+ end
58
+
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,42 @@
1
+ module Skylight
2
+ module Probes
3
+ module NetHTTP
4
+ class Probe
5
+ def install
6
+ Net::HTTP.class_eval do
7
+ alias request_without_sk request
8
+
9
+ def request(req, body = nil, &block)
10
+ unless started?
11
+ return request_without_sk(req, body, &block)
12
+ end
13
+
14
+ method = req.method
15
+
16
+ # req['host'] also includes special handling for default ports
17
+ host, port = req['host'] ? req['host'].split(':') : nil
18
+
19
+ # If we're connected with a persistent socket
20
+ host ||= self.address
21
+ port ||= self.port
22
+
23
+ path = req.path
24
+ scheme = use_ssl? ? "https" : "http"
25
+
26
+ # Contained in the path
27
+ query = nil
28
+
29
+ opts = Formatters::HTTP.build_opts(method, scheme, host, port, path, query)
30
+
31
+ Skylight.instrument(opts) do
32
+ request_without_sk(req, body, &block)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ register("Net::HTTP", "net/http", NetHTTP::Probe.new)
41
+ end
42
+ end
@@ -11,8 +11,13 @@ module Skylight
11
11
  # The path to the configuration file
12
12
  config.skylight.config_path = "config/skylight.yml"
13
13
 
14
+ # The probes to load
15
+ config.skylight.probes = []
16
+
14
17
  initializer 'skylight.configure' do |app|
15
18
  if activate?
19
+ load_probes
20
+
16
21
  if config = load_skylight_config(app)
17
22
  Instrumenter.start!(config)
18
23
  app.middleware.insert 0, Middleware
@@ -85,5 +90,12 @@ module Skylight
85
90
  def activate?
86
91
  environments.include?(Rails.env.to_s)
87
92
  end
93
+
94
+ def load_probes
95
+ probes = config.skylight.probes || []
96
+ probes.each do |p|
97
+ require 'skylight/probes/#{p}'
98
+ end
99
+ end
88
100
  end
89
101
  end
@@ -0,0 +1,107 @@
1
+ module Skylight
2
+ module Util
3
+ module Inflector
4
+ extend self
5
+
6
+ # From https://github.com/rails/rails/blob/f8e5022c73679f41db9bb6743179bab4571fb28e/activesupport/lib/active_support/inflector/methods.rb
7
+
8
+ # Tries to find a constant with the name specified in the argument string.
9
+ #
10
+ # 'Module'.constantize # => Module
11
+ # 'Test::Unit'.constantize # => Test::Unit
12
+ #
13
+ # The name is assumed to be the one of a top-level constant, no matter
14
+ # whether it starts with "::" or not. No lexical context is taken into
15
+ # account:
16
+ #
17
+ # C = 'outside'
18
+ # module M
19
+ # C = 'inside'
20
+ # C # => 'inside'
21
+ # 'C'.constantize # => 'outside', same as ::C
22
+ # end
23
+ #
24
+ # NameError is raised when the name is not in CamelCase or the constant is
25
+ # unknown.
26
+ def constantize(camel_cased_word)
27
+ names = camel_cased_word.split('::')
28
+
29
+ # Trigger a builtin NameError exception including the ill-formed constant in the message.
30
+ Object.const_get(camel_cased_word) if names.empty?
31
+
32
+ # Remove the first blank element in case of '::ClassName' notation.
33
+ names.shift if names.size > 1 && names.first.empty?
34
+
35
+ names.inject(Object) do |constant, name|
36
+ if constant == Object
37
+ constant.const_get(name)
38
+ else
39
+ candidate = constant.const_get(name)
40
+ next candidate if constant.const_defined?(name, false)
41
+ next candidate unless Object.const_defined?(name)
42
+
43
+ # Go down the ancestors to check it it's owned
44
+ # directly before we reach Object or the end of ancestors.
45
+ constant = constant.ancestors.inject do |const, ancestor|
46
+ break const if ancestor == Object
47
+ break ancestor if ancestor.const_defined?(name, false)
48
+ const
49
+ end
50
+
51
+ # owner is in Object, so raise
52
+ constant.const_get(name, false)
53
+ end
54
+ end
55
+ end
56
+
57
+ # Tries to find a constant with the name specified in the argument string.
58
+ #
59
+ # 'Module'.safe_constantize # => Module
60
+ # 'Test::Unit'.safe_constantize # => Test::Unit
61
+ #
62
+ # The name is assumed to be the one of a top-level constant, no matter
63
+ # whether it starts with "::" or not. No lexical context is taken into
64
+ # account:
65
+ #
66
+ # C = 'outside'
67
+ # module M
68
+ # C = 'inside'
69
+ # C # => 'inside'
70
+ # 'C'.safe_constantize # => 'outside', same as ::C
71
+ # end
72
+ #
73
+ # +nil+ is returned when the name is not in CamelCase or the constant (or
74
+ # part of it) is unknown.
75
+ #
76
+ # 'blargle'.safe_constantize # => nil
77
+ # 'UnknownModule'.safe_constantize # => nil
78
+ # 'UnknownModule::Foo::Bar'.safe_constantize # => nil
79
+ def safe_constantize(camel_cased_word)
80
+ constantize(camel_cased_word)
81
+ rescue NameError => e
82
+ raise unless e.message =~ /(uninitialized constant|wrong constant name) #{const_regexp(camel_cased_word)}$/ ||
83
+ e.name.to_s == camel_cased_word.to_s
84
+ rescue ArgumentError => e
85
+ raise unless e.message =~ /not missing constant #{const_regexp(camel_cased_word)}\!$/
86
+ end
87
+
88
+ private
89
+
90
+ # Mount a regular expression that will match part by part of the constant.
91
+ #
92
+ # const_regexp("Foo::Bar::Baz") # => /Foo(::Bar(::Baz)?)?/
93
+ # const_regexp("::") # => /::/
94
+ def const_regexp(camel_cased_word) #:nodoc:
95
+ parts = camel_cased_word.split("::")
96
+
97
+ return Regexp.escape(camel_cased_word) if parts.empty?
98
+
99
+ last = parts.pop
100
+
101
+ parts.reverse.inject(last) do |acc, part|
102
+ part.empty? ? acc : "#{part}(::#{acc})?"
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
@@ -1,4 +1,4 @@
1
1
  module Skylight
2
- VERSION = '0.2.0.beta.4'
2
+ VERSION = '0.2.0'
3
3
  end
4
4
 
@@ -173,6 +173,7 @@ module Skylight
173
173
  end
174
174
 
175
175
  def should_flush?(now)
176
+ return true if @config.constant_flush?
176
177
  now >= @flush_at
177
178
  end
178
179
 
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.2.0.beta.4
4
+ version: 0.2.0
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-09 00:00:00.000000000 Z
11
+ date: 2013-12-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -24,7 +24,7 @@ dependencies:
24
24
  - - '>='
25
25
  - !ruby/object:Gem::Version
26
26
  version: 3.0.0
27
- description: Currently in pre-alpha.
27
+ description:
28
28
  email:
29
29
  - engineering@tilde.io
30
30
  executables:
@@ -38,6 +38,7 @@ files:
38
38
  - lib/skylight/compat.rb
39
39
  - lib/skylight/config.rb
40
40
  - lib/skylight/data/cacert.pem
41
+ - lib/skylight/formatters/http.rb
41
42
  - lib/skylight/gc.rb
42
43
  - lib/skylight/helpers.rb
43
44
  - lib/skylight/instrumenter.rb
@@ -60,12 +61,17 @@ files:
60
61
  - lib/skylight/normalizers/render_template.rb
61
62
  - lib/skylight/normalizers/send_file.rb
62
63
  - lib/skylight/normalizers/sql.rb
64
+ - lib/skylight/probes.rb
65
+ - lib/skylight/probes/excon.rb
66
+ - lib/skylight/probes/excon/middleware.rb
67
+ - lib/skylight/probes/net_http.rb
63
68
  - lib/skylight/railtie.rb
64
69
  - lib/skylight/subscriber.rb
65
70
  - lib/skylight/util/allocation_free.rb
66
71
  - lib/skylight/util/clock.rb
67
72
  - lib/skylight/util/gzip.rb
68
73
  - lib/skylight/util/http.rb
74
+ - lib/skylight/util/inflector.rb
69
75
  - lib/skylight/util/logging.rb
70
76
  - lib/skylight/util/queue.rb
71
77
  - lib/skylight/util/task.rb
@@ -149,13 +155,13 @@ required_ruby_version: !ruby/object:Gem::Requirement
149
155
  version: 1.9.2
150
156
  required_rubygems_version: !ruby/object:Gem::Requirement
151
157
  requirements:
152
- - - '>'
158
+ - - '>='
153
159
  - !ruby/object:Gem::Version
154
- version: 1.3.1
160
+ version: '0'
155
161
  requirements: []
156
162
  rubyforge_project:
157
- rubygems_version: 2.1.9
163
+ rubygems_version: 2.1.0
158
164
  signing_key:
159
165
  specification_version: 4
160
- summary: Skylight is a ruby application monitoring tool.
166
+ summary: Skylight is a ruby application monitoring tool. Currently in closed beta.
161
167
  test_files: []