skylight 0.0.10 → 0.0.11

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,6 +4,7 @@ $:.unshift File.expand_path('../vendor', __FILE__)
4
4
  require "skylight"
5
5
  require "thor"
6
6
  require "highline"
7
+ require "active_support/inflector"
7
8
 
8
9
  module Skylight
9
10
  class CLI < Thor
@@ -77,8 +78,15 @@ module Skylight
77
78
  end
78
79
 
79
80
  def app_name
80
- require "./config/application"
81
- Rails.application.class.name.split("::").first.underscore
81
+ @app_name ||=
82
+ begin
83
+ if File.exist?("config/application.rb")
84
+ require "./config/application"
85
+ Rails.application.class.name.split("::").first.underscore.humanize
86
+ else
87
+ File.basename(File.expand_path('.')).humanize
88
+ end
89
+ end
82
90
  end
83
91
  end
84
92
  end
@@ -1,5 +1,6 @@
1
1
  require 'yaml'
2
2
  require 'logger'
3
+ require 'fileutils'
3
4
 
4
5
  module Skylight
5
6
  class Config
@@ -22,6 +23,7 @@ module Skylight
22
23
  end
23
24
 
24
25
  private
26
+
25
27
  def apply_env(config, env)
26
28
  env.each do |key, value|
27
29
  name = normalize_env(key)
@@ -46,7 +48,7 @@ module Skylight
46
48
  @port = 443
47
49
  @interval = 5
48
50
  @protocol = JsonProto.new(self)
49
- @max_pending_traces = 500
51
+ @max_pending_traces = 500
50
52
  @samples_per_interval = 100
51
53
 
52
54
  @logger = Logger.new(STDOUT)
@@ -60,6 +62,9 @@ module Skylight
60
62
  end
61
63
  end
62
64
 
65
+ @http ||= Util::HTTP.new(self)
66
+ @gc_profiler ||= GC::Profiler
67
+
63
68
  yield self if block_given?
64
69
  end
65
70
 
@@ -88,6 +93,7 @@ module Skylight
88
93
  attr_reader :normalizer
89
94
 
90
95
  attr_reader :protocol
96
+
91
97
  def protocol=(val)
92
98
  if val.is_a?(String) || val.is_a?(Symbol)
93
99
  class_name = val.to_s.capitalize+"Proto"
@@ -114,10 +120,13 @@ module Skylight
114
120
  attr_writer :gc_profiler
115
121
 
116
122
  def gc_profiler
123
+ # TODO: Move this into tests
117
124
  @gc_profiler ||= Struct.new(:enable, :disable, :clear, :total_time).new(nil, nil, nil, 0)
118
125
  end
119
126
 
120
127
  def save(filename=yaml_file)
128
+ FileUtils.mkdir_p File.dirname(filename)
129
+
121
130
  File.open(filename, "w") do |file|
122
131
  config = {}
123
132
  config["authentication_token"] = authentication_token if authentication_token
@@ -1,6 +1,9 @@
1
1
  module Skylight
2
2
  class Instrumenter
3
3
 
4
+ # Guards starting the instrumenter
5
+ LOCK = Mutex.new
6
+
4
7
  # Maximum number of traces to sample for each interval
5
8
  SAMPLE_SIZE = 100
6
9
 
@@ -8,44 +11,63 @@ module Skylight
8
11
  INTERVAL = 5
9
12
 
10
13
  def self.start!(config = Config.new)
11
- # Convert a hash to a config object
12
- if Hash === config
13
- config = Config.new config
14
- end
15
-
16
14
  new(config).start!
17
15
  end
18
16
 
19
17
  attr_reader :config, :worker, :samples
20
18
 
21
19
  def initialize(config)
22
- @config = config
20
+ # Convert a hash to a config object
21
+ if Hash === config
22
+ config = Config.new(config)
23
+ end
23
24
 
24
- @worker = Worker.new(self)
25
+ @config = config
26
+ @started = false
27
+ @worker = Worker.new(self)
25
28
  end
26
29
 
27
30
  def start!
28
- @worker.start!
29
- Subscriber.register!(config)
31
+ # Quick check
32
+ return self if @started
33
+
34
+ LOCK.synchronize do
35
+ # Ensure that the instrumenter has not been started now that the lock
36
+ # as been acquired
37
+ return self if @started
38
+
39
+ @worker.start!
40
+ Subscriber.register!(config)
30
41
 
31
- # Ensure properly configured
32
- return unless config
42
+ # Ensure properly configured
43
+ return unless config
33
44
 
34
- # Ensure that there is an API token
35
- unless config.authentication_token
36
- if logger = config.logger
37
- logger.warn "[SKYLIGHT] No authentication token provided; cannot start agent."
45
+ # Ensure that there is an API token
46
+ unless config.authentication_token
47
+ if logger = config.logger
48
+ logger.warn "[SKYLIGHT] No authentication token provided; cannot start agent."
49
+ end
50
+
51
+ return
38
52
  end
39
53
 
40
- return
41
- end
54
+ config.gc_profiler.enable
42
55
 
43
- config.gc_profiler.enable
56
+ @started = true
57
+ end
44
58
 
45
59
  self
60
+
61
+ rescue
62
+ nil
46
63
  end
47
64
 
48
65
  def trace(endpoint = nil)
66
+ # Ignore everything unless the instrumenter has been started
67
+ unless @started
68
+ return yield
69
+ end
70
+
49
71
  # If there already is a trace going on, then just continue
50
72
  if Thread.current[Trace::KEY]
51
73
  return yield
@@ -1,46 +1,24 @@
1
1
  module Skylight
2
2
  class Middleware
3
- def self.new(app, config, *)
4
- return app unless config
3
+
4
+ def self.new(app, instrumenter, *)
5
+ return app unless instrumenter
5
6
  super
6
7
  end
7
8
 
8
- def initialize(app, config, instrumenter_class=Instrumenter)
9
+ def initialize(app, instrumenter)
9
10
  @app = app
10
- @config = config
11
- @config.gc_profiler = GC::Profiler
12
- @instrumenter_class = instrumenter_class
11
+ @instrumenter = instrumenter
13
12
  end
14
13
 
15
14
  def call(env)
16
- instrumenter.trace("Rack") do
15
+ @instrumenter.start!
16
+
17
+ @instrumenter.trace("Rack") do
17
18
  ActiveSupport::Notifications.instrument("app.rack.request") do
18
19
  @app.call(env)
19
20
  end
20
21
  end
21
22
  end
22
-
23
- private
24
- LOCK = Mutex.new
25
-
26
- def instrumenter
27
- return @instrumenter if defined?(@instrumenter)
28
-
29
- LOCK.synchronize do
30
- return @instrumeter if defined?(@instrumenter)
31
- @instrumenter = @instrumenter_class.start!(@config)
32
- return @instrumenter
33
- end
34
- rescue Exception
35
- @instrumenter = stub
36
- end
37
-
38
- def stub
39
- Class.new do
40
- def trace(*)
41
- yield
42
- end
43
- end.new
44
- end
45
23
  end
46
24
  end
@@ -1,44 +1,51 @@
1
- require "action_dispatch/http/mime_type"
2
- require "action_dispatch/http/mime_types"
3
- require "rack/utils"
4
-
5
1
  module Skylight
6
2
  module Normalize
7
- class SendFile < Normalizer
8
- register "send_file.action_controller"
9
-
10
- def normalize
11
- path = @payload[:path]
12
-
13
- annotations = {
14
- path: path,
15
- filename: @payload[:filename],
16
- type: normalize_type,
17
- disposition: normalize_disposition,
18
- status: normalize_status
19
- }
20
-
21
- # These will eventually be different
22
- title = desc = "send file: #{path}"
23
-
24
- [ "app.controller.send_file", title, desc, annotations ]
25
- end
26
-
27
- private
28
- def normalize_type
29
- type = @payload[:type] || "application/octet-stream"
30
- type = Mime[type].to_s if type.is_a?(Symbol)
31
- type
32
- end
33
3
 
34
- def normalize_status
35
- status = @payload[:status] || 200
36
- Rack::Utils.status_code(status)
4
+ # Temporary hacks
5
+ begin
6
+ require "action_dispatch/http/mime_type"
7
+ require "action_dispatch/http/mime_types"
8
+ require "rack/utils"
9
+
10
+ class SendFile < Normalizer
11
+ register "send_file.action_controller"
12
+
13
+ def normalize
14
+ path = @payload[:path]
15
+
16
+ annotations = {
17
+ path: path,
18
+ filename: @payload[:filename],
19
+ type: normalize_type,
20
+ disposition: normalize_disposition,
21
+ status: normalize_status
22
+ }
23
+
24
+ # These will eventually be different
25
+ title = desc = "send file: #{path}"
26
+
27
+ [ "app.controller.send_file", title, desc, annotations ]
28
+ end
29
+
30
+ private
31
+ def normalize_type
32
+ type = @payload[:type] || "application/octet-stream"
33
+ type = Mime[type].to_s if type.is_a?(Symbol)
34
+ type
35
+ end
36
+
37
+ def normalize_status
38
+ status = @payload[:status] || 200
39
+ Rack::Utils.status_code(status)
40
+ end
41
+
42
+ def normalize_disposition
43
+ @payload[:disposition] || "attachment"
44
+ end
37
45
  end
38
46
 
39
- def normalize_disposition
40
- @payload[:disposition] || "attachment"
41
- end
47
+ rescue LoadError
42
48
  end
49
+
43
50
  end
44
51
  end
@@ -13,52 +13,61 @@ module Skylight
13
13
 
14
14
  attr_accessor :instrumenter
15
15
 
16
- initializer "skylight.sanity_check" do |app|
17
- checker = SanityChecker.new
18
- @problems = checker.smoke_test(config_path(app)) || checker.sanity_check(load_config(app))
19
- next unless @problems
16
+ initializer "skylight.configure" do |app|
17
+ config = load_config(app)
20
18
 
21
- @problems.each do |group, problem_list|
22
- problem_list.each do |problem|
23
- puts "[SKYLIGHT] PROBLEM: #{group} #{problem}"
24
- end
25
- end
26
- end
19
+ if good_to_go?(app, config)
20
+ @instrumenter = Instrumenter.new(config)
27
21
 
28
- initializer "skylight.configure" do |app|
29
- if @problems
30
- puts "[SKYLIGHT] Skipping Skylight boot"
31
- else
32
22
  Rails.logger.debug "[SKYLIGHT] Installing middleware"
33
- app.middleware.insert 0, Middleware, load_config(app)
23
+ app.middleware.insert 0, Middleware, @instrumenter
24
+ else
25
+ puts "[SKYLIGHT] Skipping Skylight boot"
34
26
  end
35
27
  end
36
28
 
37
29
  private
38
30
 
39
- def environments
40
- Array(config.skylight.environments).map { |e| e && e.to_s }.compact
31
+ def good_to_go?(app, config)
32
+ unless problems = check_for_problems(app, config)
33
+ return true
34
+ end
35
+
36
+ problems.each do |group, problem_list|
37
+ problem_list.each do |problem|
38
+ puts "[SKYLIGHT] PROBLEM: #{group} #{problem}"
39
+ end
40
+ end
41
+
42
+ false
41
43
  end
42
44
 
43
- def config_path(app)
44
- path = config.skylight.config_path
45
- File.expand_path(path, app.root)
45
+ def check_for_problems(app, config)
46
+ checker = SanityChecker.new
47
+ checker.smoke_test(config_path(app)) || checker.sanity_check(config)
46
48
  end
47
49
 
48
50
  def load_config(app)
49
- @skylight_config ||= begin
50
51
  config = Config.load_from_yaml(config_path(app), ENV).tap do |c|
51
52
  c.logger = Rails.logger
52
53
  end
53
54
 
54
55
  config.normalizer.view_paths = app.config.paths["app/views"].existent
55
- config.http = Util::HTTP.new(config)
56
56
  config
57
- end
58
57
  rescue => e
59
58
  raise
60
59
  Rails.logger.error "[SKYLIGHT] #{e.message} (#{e.class}) - #{e.backtrace.first}"
61
60
  end
62
61
 
62
+ def environments
63
+ Array(config.skylight.environments).map { |e| e && e.to_s }.compact
64
+ end
65
+
66
+ def config_path(app)
67
+ path = config.skylight.config_path
68
+ File.expand_path(path, app.root)
69
+ end
70
+
71
+
63
72
  end
64
73
  end
@@ -19,8 +19,6 @@ module Skylight
19
19
 
20
20
  def finish(name, id, payload)
21
21
  return unless trace = Trace.current
22
-
23
- logger.debug("[SKYLIGHT] END")
24
22
  trace.stop
25
23
  end
26
24
 
@@ -94,7 +94,14 @@ module Skylight
94
94
 
95
95
  update_cumulative_gc
96
96
 
97
- span.ended_at = now - @timestamp - @cumulative_gc
97
+ ended_at = now - @timestamp
98
+
99
+ # If it's not the root node
100
+ if span.parent
101
+ ended_at -= @cumulative_gc
102
+ end
103
+
104
+ span.ended_at = ended_at
98
105
 
99
106
  # Update the parent
100
107
  @parent = @spans[@parent].parent
@@ -1,3 +1,3 @@
1
1
  module Skylight
2
- VERSION = '0.0.10'
2
+ VERSION = '0.0.11'
3
3
  end
metadata CHANGED
@@ -1,7 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: skylight
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.10
4
+ version: 0.0.11
5
+ prerelease:
5
6
  platform: ruby
6
7
  authors:
7
8
  - Tilde, Inc.
@@ -13,29 +14,33 @@ dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: activesupport
15
16
  requirement: !ruby/object:Gem::Requirement
17
+ none: false
16
18
  requirements:
17
- - - '>='
19
+ - - ! '>='
18
20
  - !ruby/object:Gem::Version
19
21
  version: 3.0.0
20
22
  type: :runtime
21
23
  prerelease: false
22
24
  version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
23
26
  requirements:
24
- - - '>='
27
+ - - ! '>='
25
28
  - !ruby/object:Gem::Version
26
29
  version: 3.0.0
27
30
  - !ruby/object:Gem::Dependency
28
31
  name: actionpack
29
32
  requirement: !ruby/object:Gem::Requirement
33
+ none: false
30
34
  requirements:
31
- - - '>='
35
+ - - ! '>='
32
36
  - !ruby/object:Gem::Version
33
37
  version: 3.0.0
34
38
  type: :development
35
39
  prerelease: false
36
40
  version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
37
42
  requirements:
38
- - - '>='
43
+ - - ! '>='
39
44
  - !ruby/object:Gem::Version
40
45
  version: 3.0.0
41
46
  description: Currently in pre-alpha.
@@ -124,25 +129,26 @@ files:
124
129
  - bin/skylight
125
130
  homepage: http://www.skylight.io
126
131
  licenses: []
127
- metadata: {}
128
132
  post_install_message:
129
133
  rdoc_options: []
130
134
  require_paths:
131
135
  - lib
132
136
  required_ruby_version: !ruby/object:Gem::Requirement
137
+ none: false
133
138
  requirements:
134
- - - '>='
139
+ - - ! '>='
135
140
  - !ruby/object:Gem::Version
136
141
  version: 1.9.2
137
142
  required_rubygems_version: !ruby/object:Gem::Requirement
143
+ none: false
138
144
  requirements:
139
- - - '>='
145
+ - - ! '>='
140
146
  - !ruby/object:Gem::Version
141
147
  version: '0'
142
148
  requirements: []
143
149
  rubyforge_project:
144
- rubygems_version: 2.0.3
150
+ rubygems_version: 1.8.25
145
151
  signing_key:
146
- specification_version: 4
152
+ specification_version: 3
147
153
  summary: Skylight is a ruby application monitoring tool.
148
154
  test_files: []
checksums.yaml DELETED
@@ -1,7 +0,0 @@
1
- ---
2
- SHA1:
3
- metadata.gz: addb4eed3d6a9b0f22eb5163115018211c5da90c
4
- data.tar.gz: 513eb7a8391b46447744f602127b2e0e4fe84edc
5
- SHA512:
6
- metadata.gz: cd3900fdbb47bc3adf7a81dda75a69277b72484d056a1f86c66b83b36335d0a2e01568830c0bb412bdcd76c82eb7ceec11fc2a5b8f73c1c129d725ab342e27b4
7
- data.tar.gz: e94a2b3bf08c8151b1a23e666402a4530eaa3310087de8f6b43f109f57792c7556e17314711babfeff7cfaca3a3f8d1df41f18b36587bf356c5c12d2533f668a