skylight 0.3.14 → 0.3.17

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -0
  3. data/lib/skylight/config.rb +7 -1
  4. data/lib/skylight/messages/trace.rb +6 -6
  5. data/lib/skylight/normalizers.rb +8 -7
  6. data/lib/skylight/normalizers/action_controller/process_action.rb +35 -0
  7. data/lib/skylight/normalizers/action_controller/send_file.rb +76 -0
  8. data/lib/skylight/normalizers/action_view/render_collection.rb +18 -0
  9. data/lib/skylight/normalizers/action_view/render_partial.rb +18 -0
  10. data/lib/skylight/normalizers/action_view/render_template.rb +18 -0
  11. data/lib/skylight/normalizers/active_record/sql.rb +81 -0
  12. data/lib/skylight/normalizers/active_support/cache.rb +50 -0
  13. data/lib/skylight/normalizers/active_support/cache_clear.rb +16 -0
  14. data/lib/skylight/normalizers/active_support/cache_decrement.rb +16 -0
  15. data/lib/skylight/normalizers/active_support/cache_delete.rb +16 -0
  16. data/lib/skylight/normalizers/active_support/cache_exist.rb +16 -0
  17. data/lib/skylight/normalizers/active_support/cache_fetch_hit.rb +16 -0
  18. data/lib/skylight/normalizers/active_support/cache_generate.rb +16 -0
  19. data/lib/skylight/normalizers/active_support/cache_increment.rb +16 -0
  20. data/lib/skylight/normalizers/active_support/cache_read.rb +16 -0
  21. data/lib/skylight/normalizers/active_support/cache_read_multi.rb +16 -0
  22. data/lib/skylight/normalizers/active_support/cache_write.rb +16 -0
  23. data/lib/skylight/normalizers/moped/query.rb +141 -0
  24. data/lib/skylight/version.rb +1 -1
  25. data/lib/skylight/worker/standalone.rb +3 -3
  26. metadata +37 -26
  27. data/lib/skylight/normalizers/moped.rb +0 -139
  28. data/lib/skylight/normalizers/process_action.rb +0 -34
  29. data/lib/skylight/normalizers/render_collection.rb +0 -16
  30. data/lib/skylight/normalizers/render_partial.rb +0 -16
  31. data/lib/skylight/normalizers/render_template.rb +0 -16
  32. data/lib/skylight/normalizers/send_file.rb +0 -74
  33. data/lib/skylight/normalizers/sql.rb +0 -79
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5620862e4260060cc2887d5fa2e902eeb96af51a
4
- data.tar.gz: 8e664fcdf47316d921921b96286c8b336f6c0892
3
+ metadata.gz: 0fe30001ff54231d9fc09691d32cfbe734b6511e
4
+ data.tar.gz: ba257edb4e82c556e5b86a4e93023d19e9d1fa9f
5
5
  SHA512:
6
- metadata.gz: 0ad66490a91813115f262f0c1640a0a50839bd82f0a81fb32952cd03fede4a742ed220db5d14491b1fda95b0217a5ff3ec48e3ddff6d77a9f4674f4dbf45bae1
7
- data.tar.gz: 122849003b5c4d135c8244d37e65ca1505a8cb421ff874c7d6e1af180e8fe122026155c734645ccf10a7527ad1182fe19cf64d9bab3ad2f0b13a1aa44b103c5b
6
+ metadata.gz: 4862132100ec976e3c8a9a0ba48df3df9323f0b70c4bad5816fb89f6a955c831b2ba07db354437410f00091d53b90d1f1fd517ff5944a7c5b4e14f6a79c692f3
7
+ data.tar.gz: e4a853e6647f09e4f717909e747ccce70b609f08748c1ff268f87aa5eceea4ebc8cfb04cb39ede0d8000de07ca0792c81f37735973f2bf9cbb5ae4bb79db0a2b
@@ -1,3 +1,18 @@
1
+ ## 0.3.17 (July 1, 2014)
2
+
3
+ * Fix warning for Cache.instrument overwrite
4
+
5
+ ## 0.3.16 (July 1, 2014) [YANKED]
6
+
7
+ * Fixed ActiveSupport::Cache monkeypatch
8
+
9
+ ## 0.3.15 (June 30, 2014) [YANKED]
10
+
11
+ * Basic instrumentation for ActiveSupport::Cache
12
+ * Fix incompatibility with old version of rack-mini-profiler
13
+ * Better error messages when config/skylight.yml is invalid
14
+ * Better error messages for non-writeable lock/sockfile path
15
+
1
16
  ## 0.3.14 (June 3, 2014)
2
17
 
3
18
  * Do not build C extension if dependencies (libraries/headers) are
@@ -29,6 +29,7 @@ module Skylight
29
29
  'SKIP_VALIDATION' => :'skip_validation',
30
30
  'AGENT_INTERVAL' => :'agent.interval',
31
31
  'AGENT_KEEPALIVE' => :'agent.keepalive',
32
+ 'AGENT_LOCKFILE' => :'agent.lockfile',
32
33
  'AGENT_SAMPLE_SIZE' => :'agent.sample',
33
34
  'AGENT_SOCKFILE_PATH' => :'agent.sockfile_path',
34
35
  'AGENT_STRATEGY' => :'agent.strategy',
@@ -91,12 +92,17 @@ module Skylight
91
92
  version = nil
92
93
 
93
94
  if path
95
+ error = nil
94
96
  begin
95
97
  attrs = YAML.load_file(path)
98
+ error = "empty file" unless attrs
99
+ error = "invalid format" if attrs && !attrs.is_a?(Hash)
96
100
  rescue Exception => e
97
- raise ConfigError, "could not load config file; msg=#{e.message}"
101
+ error = e.message
98
102
  end
99
103
 
104
+ raise ConfigError, "could not load config file; msg=#{error}" if error
105
+
100
106
  version = File.mtime(path).to_i
101
107
  end
102
108
 
@@ -9,7 +9,7 @@ module Skylight
9
9
  attr_reader :endpoint, :spans, :notifications
10
10
 
11
11
  def endpoint=(value)
12
- @endpoint = value.freeze
12
+ @endpoint = value.is_a?(String) ? value.freeze : value
13
13
  @native_builder.native_set_name(value)
14
14
  end
15
15
 
@@ -22,7 +22,7 @@ module Skylight
22
22
  @native_builder.native_set_name(endpoint)
23
23
 
24
24
  @instrumenter = instrumenter
25
- @endpoint = endpoint.freeze
25
+ @endpoint = endpoint
26
26
  @submitted = false
27
27
  @start = start
28
28
 
@@ -63,8 +63,8 @@ module Skylight
63
63
  desc = nil
64
64
  end
65
65
 
66
- title.freeze
67
- desc.freeze
66
+ title.freeze if title.is_a?(String)
67
+ desc.freeze if desc.is_a?(String)
68
68
 
69
69
  desc = @instrumenter.limited_description(desc)
70
70
 
@@ -86,8 +86,8 @@ module Skylight
86
86
  desc = nil
87
87
  end
88
88
 
89
- title.freeze
90
- desc.freeze
89
+ title.freeze if title.is_a?(String)
90
+ desc.freeze if desc.is_a?(String)
91
91
 
92
92
  original_desc = desc
93
93
  now = Util::Clock.nanos
@@ -120,13 +120,14 @@ module Skylight
120
120
  end
121
121
  end
122
122
 
123
- %w( moped
124
- process_action
125
- render_collection
126
- render_partial
127
- render_template
128
- send_file
129
- sql).each do |file|
123
+ %w( action_controller/process_action
124
+ action_controller/send_file
125
+ action_view/render_collection
126
+ action_view/render_partial
127
+ action_view/render_template
128
+ active_record/sql
129
+ active_support/cache
130
+ moped/query).each do |file|
130
131
  require "skylight/normalizers/#{file}"
131
132
  end
132
133
  end
@@ -0,0 +1,35 @@
1
+ module Skylight
2
+ module Normalizers
3
+ module ActionController
4
+ class ProcessAction < Normalizer
5
+ register "process_action.action_controller"
6
+
7
+ CAT = "app.controller.request".freeze
8
+ PAYLOAD_KEYS = %w[ controller action params format method path ].map(&:to_sym).freeze
9
+
10
+ def normalize(trace, name, payload)
11
+ trace.endpoint = controller_action(payload)
12
+ [ CAT, trace.endpoint, nil, normalize_payload(payload) ]
13
+ end
14
+
15
+ private
16
+
17
+ def controller_action(payload)
18
+ "#{payload[:controller]}##{payload[:action]}"
19
+ end
20
+
21
+ def normalize_payload(payload)
22
+ normalized = {}
23
+
24
+ PAYLOAD_KEYS.each do |key|
25
+ val = payload[key]
26
+ val = val.inspect unless val.is_a?(String) || val.is_a?(Numeric)
27
+ normalized[key] = val
28
+ end
29
+
30
+ normalized
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,76 @@
1
+ module Skylight
2
+ module Normalizers
3
+ module ActionController
4
+
5
+ # Temporary hacks
6
+ begin
7
+ require "action_dispatch/http/mime_type"
8
+ require "action_dispatch/http/mime_types"
9
+ require "rack/utils"
10
+
11
+ class SendFile < Normalizer
12
+ register "send_file.action_controller"
13
+
14
+ CAT = "app.controller.send_file".freeze
15
+ TITLE = "send file".freeze
16
+
17
+ def normalize(trace, name, payload)
18
+ path = payload[:path]
19
+
20
+ annotations = {
21
+ path: path,
22
+ filename: payload[:filename],
23
+ type: normalize_type(payload),
24
+ disposition: normalize_disposition(payload),
25
+ status: normalize_status(payload) }
26
+
27
+ title = TITLE
28
+
29
+ # depending on normalization, we probably want this to eventually
30
+ # include the full path, but we need to make sure we have a good
31
+ # deduping strategy first.
32
+ desc = nil
33
+
34
+ [ CAT, title, desc, annotations ]
35
+ end
36
+
37
+ private
38
+
39
+ OCTET_STREAM = "application/octet-stream".freeze
40
+ ATTACHMENT = "attachment".freeze
41
+
42
+ def initialize(*)
43
+ super
44
+
45
+ @mimes = Mime::SET.reduce({}) do |hash, mime|
46
+ hash[mime.symbol] = mime.to_s.dup.freeze
47
+ hash
48
+ end
49
+ end
50
+
51
+ def normalize_type(payload)
52
+ type = payload[:type] || OCTET_STREAM
53
+ type = @mimes[type] if type.is_a?(Symbol)
54
+ type
55
+ end
56
+
57
+ def mime_for(type)
58
+ @mimes[type] ||= Mime[type].to_s.freeze
59
+ end
60
+
61
+ def normalize_status(payload)
62
+ status = payload[:status] || 200
63
+ Rack::Utils.status_code(status)
64
+ end
65
+
66
+ def normalize_disposition(payload)
67
+ payload[:disposition] || ATTACHMENT
68
+ end
69
+ end
70
+
71
+ rescue LoadError
72
+ end
73
+
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,18 @@
1
+ module Skylight
2
+ module Normalizers
3
+ module ActionView
4
+ class RenderCollection < RenderNormalizer
5
+ register "render_collection.action_view"
6
+
7
+ CAT = "view.render.collection".freeze
8
+
9
+ def normalize(trace, name, payload)
10
+ normalize_render(
11
+ CAT,
12
+ payload,
13
+ count: payload[:count])
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ module Skylight
2
+ module Normalizers
3
+ module ActionView
4
+ class RenderPartial < RenderNormalizer
5
+ register "render_partial.action_view"
6
+
7
+ CAT = "view.render.template".freeze
8
+
9
+ def normalize(trace, name, payload)
10
+ normalize_render(
11
+ CAT,
12
+ payload,
13
+ partial: 1)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ module Skylight
2
+ module Normalizers
3
+ module ActionView
4
+ class RenderTemplate < RenderNormalizer
5
+ register "render_template.action_view"
6
+
7
+ CAT = "view.render.template".freeze
8
+
9
+ def normalize(trace, name, payload)
10
+ normalize_render(
11
+ CAT,
12
+ payload,
13
+ partial: 0)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,81 @@
1
+ require "sql_lexer"
2
+ require "json"
3
+
4
+ module Skylight
5
+ module Normalizers
6
+ module ActiveRecord
7
+ class SQL < Normalizer
8
+ register "sql.active_record"
9
+
10
+ CAT = "db.sql.query".freeze
11
+
12
+ def normalize(trace, name, payload)
13
+ case payload[:name]
14
+ when "SCHEMA", "CACHE"
15
+ return :skip
16
+ else
17
+ name = CAT
18
+ title = payload[:name] || "SQL"
19
+ end
20
+
21
+ binds = payload[:binds]
22
+
23
+ if binds && !binds.empty?
24
+ binds = binds.map { |col, val| val.inspect }
25
+ end
26
+
27
+ extracted_title, sql, binds, error = extract_binds(payload, binds)
28
+ title = extracted_title if extracted_title
29
+
30
+ if sql
31
+ annotations = {
32
+ sql: sql,
33
+ binds: binds,
34
+ }
35
+ else
36
+ annotations = {
37
+ skylight_error: error
38
+ }
39
+ end
40
+
41
+ [ name, title, sql, annotations ]
42
+ end
43
+
44
+ private
45
+ def extract_binds(payload, precalculated)
46
+ title, sql, binds = SqlLexer::Lexer.bindify(payload[:sql], precalculated)
47
+ [ title, sql, binds, nil ]
48
+ rescue => e
49
+ group = "sql_parse"
50
+ description = e.inspect
51
+ details = encode(backtrace: e.backtrace,
52
+ original_exception: {
53
+ class_name: e.class.name,
54
+ message: e.message
55
+ },
56
+ payload: payload,
57
+ precalculated: precalculated)
58
+
59
+ error = [group, description, details]
60
+ [ nil, nil, nil, error ]
61
+ end
62
+
63
+ # While operating in place would save memory, some of these passed in items are re-used elsewhere
64
+ # and, as such, should not be modified.
65
+ def encode(body)
66
+ if body.is_a?(Hash)
67
+ hash = {}
68
+ body.each{|k,v| hash[k] = encode(v) }
69
+ hash
70
+ elsif body.is_a?(Array)
71
+ body.map{|v| encode(v) }
72
+ elsif body.respond_to?(:encoding) && (body.encoding == Encoding::BINARY || !body.valid_encoding?)
73
+ Base64.encode64(body)
74
+ else
75
+ body
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,50 @@
1
+ module Skylight
2
+ module Normalizers
3
+ module ActiveSupport
4
+ # NOTE: Instrumentation may not be turned on by default and is possibly buggy
5
+ # https://github.com/mperham/dalli/pull/284
6
+ class Cache < Normalizer
7
+ %w(clear
8
+ decrement
9
+ delete
10
+ exist
11
+ fetch_hit
12
+ generate
13
+ increment
14
+ read
15
+ read_multi
16
+ write).each do |type|
17
+ require "skylight/normalizers/active_support/cache_#{type}"
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ # See https://github.com/rails/rails/pull/15943
25
+ if defined?(ActiveSupport::Cache::Store.instrument)
26
+ deprecated = false
27
+
28
+ # If it's deprecated, setting to false will cause a deprecation warning
29
+ # and the value will remain true
30
+ ActiveSupport::Deprecation.silence do
31
+ ActiveSupport::Cache::Store.instrument = false
32
+ deprecated = ActiveSupport::Cache::Store.instrument
33
+ end
34
+
35
+ unless deprecated
36
+ class ActiveSupport::Cache::Store
37
+ def self.instrument
38
+ true
39
+ end
40
+
41
+ def self.instrument=(val)
42
+ unless val
43
+ Rails.logger.warn "[WARNING] Skylight has patched ActiveSupport::Cache::Store.instrument to always be true. " \
44
+ "In future versions of Rails, this method will no longer be settable. " \
45
+ "See https://github.com/rails/rails/pull/15943 for more information."
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,16 @@
1
+ module Skylight
2
+ module Normalizers
3
+ module ActiveSupport
4
+ class CacheClear < Cache
5
+ register "cache_clear.active_support"
6
+
7
+ CAT = "app.cache.clear".freeze
8
+ TITLE = "cache clear".freeze
9
+
10
+ def normalize(trace, name, payload)
11
+ [ CAT, TITLE, nil, payload ]
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module Skylight
2
+ module Normalizers
3
+ module ActiveSupport
4
+ class CacheDecrement < Cache
5
+ register "cache_decrement.active_support"
6
+
7
+ CAT = "app.cache.decrement".freeze
8
+ TITLE = "cache decrement"
9
+
10
+ def normalize(trace, name, payload)
11
+ [ CAT, TITLE, nil, payload ]
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module Skylight
2
+ module Normalizers
3
+ module ActiveSupport
4
+ class CacheDelete < Cache
5
+ register "cache_delete.active_support"
6
+
7
+ CAT = "app.cache.delete".freeze
8
+ TITLE = "cache delete"
9
+
10
+ def normalize(trace, name, payload)
11
+ [ CAT, TITLE, nil, payload ]
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module Skylight
2
+ module Normalizers
3
+ module ActiveSupport
4
+ class CacheExist < Cache
5
+ register "cache_exist?.active_support"
6
+
7
+ CAT = "app.cache.exist".freeze
8
+ TITLE = "cache exist?"
9
+
10
+ def normalize(trace, name, payload)
11
+ [ CAT, TITLE, nil, payload ]
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module Skylight
2
+ module Normalizers
3
+ module ActiveSupport
4
+ class CacheFetchHit < Cache
5
+ register "cache_fetch_hit.active_support"
6
+
7
+ CAT = "app.cache.fetch_hit".freeze
8
+ TITLE = "cache fetch hit"
9
+
10
+ def normalize(trace, name, payload)
11
+ [ CAT, TITLE, nil, payload ]
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module Skylight
2
+ module Normalizers
3
+ module ActiveSupport
4
+ class CacheGenerate < Cache
5
+ register "cache_generate.active_support"
6
+
7
+ CAT = "app.cache.generate".freeze
8
+ TITLE = "cache generate"
9
+
10
+ def normalize(trace, name, payload)
11
+ [ CAT, TITLE, nil, payload ]
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module Skylight
2
+ module Normalizers
3
+ module ActiveSupport
4
+ class CacheIncrement < Cache
5
+ register "cache_increment.active_support"
6
+
7
+ CAT = "app.cache.increment".freeze
8
+ TITLE = "cache increment"
9
+
10
+ def normalize(trace, name, payload)
11
+ [ CAT, TITLE, nil, payload ]
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module Skylight
2
+ module Normalizers
3
+ module ActiveSupport
4
+ class CacheRead < Cache
5
+ register "cache_read.active_support"
6
+
7
+ CAT = "app.cache.read".freeze
8
+ TITLE = "cache read"
9
+
10
+ def normalize(trace, name, payload)
11
+ [ CAT, TITLE, nil, payload ]
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module Skylight
2
+ module Normalizers
3
+ module ActiveSupport
4
+ class CacheReadMulti < Cache
5
+ register "cache_read_multi.active_support"
6
+
7
+ CAT = "app.cache.read_multi".freeze
8
+ TITLE = "cache read multi"
9
+
10
+ def normalize(trace, name, payload)
11
+ [ CAT, TITLE, nil, payload ]
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module Skylight
2
+ module Normalizers
3
+ module ActiveSupport
4
+ class CacheWrite < Cache
5
+ register "cache_write.active_support"
6
+
7
+ CAT = "app.cache.write".freeze
8
+ TITLE = "cache write"
9
+
10
+ def normalize(trace, name, payload)
11
+ [ CAT, TITLE, nil, payload ]
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,141 @@
1
+ module Skylight
2
+ module Normalizers
3
+ module Moped
4
+ class Query < Normalizer
5
+ register "query.moped"
6
+
7
+ CAT = "db.mongo.query".freeze
8
+
9
+ def normalize(trace, name, payload)
10
+ # payload: { prefix: " MOPED: #{address.resolved}", ops: operations }
11
+
12
+ # We can sometimes have multiple operations. However, it seems like this only happens when doing things
13
+ # like an insert, followed by a get last error, so we can probably ignore all but the first.
14
+ operation = payload[:ops] ? payload[:ops].first : nil
15
+ type = operation && operation.class.to_s =~ /^Moped::Protocol::(.+)$/ ? $1 : nil
16
+
17
+ case type
18
+ when "Query" then normalize_query(operation)
19
+ when "GetMore" then normalize_get_more(operation)
20
+ when "Insert" then normalize_insert(operation)
21
+ when "Update" then normalize_update(operation)
22
+ when "Delete" then normalize_delete(operation)
23
+ else :skip
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def normalize_query(operation)
30
+ title = normalize_title("QUERY", operation)
31
+
32
+ hash, binds = extract_binds(operation.selector)
33
+ description = hash.to_json
34
+
35
+ annotations = build_annotations(operation)
36
+ annotations[:skip] = operation.skip
37
+ if operation.fields
38
+ annotations[:fields] = operation.fields.select{|k,v| v == 1 }.keys.map(&:to_s)
39
+ end
40
+ annotations[:binds] = binds unless binds.empty?
41
+
42
+ [CAT, title, description, annotations]
43
+ end
44
+
45
+ def normalize_get_more(operation)
46
+ title = normalize_title("GET_MORE", operation)
47
+
48
+ annotations = build_annotations(operation)
49
+ annotations[:limit] = operation.limit
50
+
51
+ [CAT, title, nil, annotations]
52
+ end
53
+
54
+ def normalize_insert(operation)
55
+ title = normalize_title("INSERT", operation)
56
+
57
+ annotations = build_annotations(operation)
58
+ annotations[:count] = operation.documents.count
59
+
60
+ [CAT, title, nil, annotations]
61
+ end
62
+
63
+ def normalize_update(operation)
64
+ title = normalize_title("UPDATE", operation)
65
+
66
+ selector_hash, selector_binds = extract_binds(operation.selector)
67
+ update_hash, update_binds = extract_binds(operation.update)
68
+
69
+ description = { selector: selector_hash, update: update_hash }.to_json
70
+
71
+ annotations = build_annotations(operation)
72
+
73
+ binds = {}
74
+ binds[:selector] = selector_binds unless selector_binds.empty?
75
+ binds[:update] = update_binds unless update_binds.empty?
76
+ annotations[:binds] = binds unless binds.empty?
77
+
78
+ [CAT, title, description, annotations]
79
+ end
80
+
81
+ def normalize_delete(operation)
82
+ title = normalize_title("DELETE", operation)
83
+
84
+ hash, binds = extract_binds(operation.selector)
85
+ description = hash.to_json
86
+
87
+ annotations = build_annotations(operation)
88
+ annotations[:binds] = binds unless binds.empty?
89
+
90
+ [CAT, title, description, annotations]
91
+ end
92
+
93
+ def normalize_title(type, operation)
94
+ "#{type} #{operation.collection}"
95
+ end
96
+
97
+ def build_annotations(operation)
98
+ annotations = {}
99
+
100
+ if operation.respond_to?(:flags)
101
+ flags = operation.flags.map{|f| flag_name(f) }
102
+ annotations[:flags] = flags unless flags.empty?
103
+ end
104
+
105
+ annotations
106
+ end
107
+
108
+ # Some flags used by Moped don't map directly to the Mongo docs
109
+ # See http://docs.mongodb.org/meta-driver/latest/legacy/mongodb-wire-protocol/
110
+ FLAG_MAP = {
111
+ tailable: "TailableCursor",
112
+ multi: "MultiUpdate"
113
+ }
114
+
115
+ def flag_name(flag)
116
+ FLAG_MAP[flag] || flag.to_s.sub(/^[a-z\d]*/) { $&.capitalize }.gsub(/(?:_|(\/))([a-z\d]*)/) { "#{$1}#{$2.capitalize}" }
117
+ end
118
+
119
+ def extract_binds(hash, binds=[])
120
+ hash = hash.dup
121
+
122
+ hash.each do |k,v|
123
+ if v.is_a?(Hash)
124
+ hash[k] = extract_binds(v, binds)[0]
125
+ else
126
+ binds << stringify(hash[k])
127
+ hash[k] = '?'
128
+ end
129
+ end
130
+
131
+ [hash, binds]
132
+ end
133
+
134
+ def stringify(value)
135
+ value.is_a?(Regexp) ? value.inspect : value.to_s
136
+ end
137
+
138
+ end
139
+ end
140
+ end
141
+ end
@@ -1,4 +1,4 @@
1
1
  module Skylight
2
- VERSION = '0.3.14'
2
+ VERSION = '0.3.17'
3
3
  end
4
4
 
@@ -380,16 +380,16 @@ module Skylight
380
380
 
381
381
  if File.exist?(lockfile)
382
382
  if !FileTest.writable?(lockfile)
383
- raise WorkerStateError, "`#{lockfile}` not writable"
383
+ raise WorkerStateError, "`#{lockfile}` not writable. Please set agent.lockfile or agent.sockfile_path in your config to a writable path."
384
384
  end
385
385
  else
386
386
  if !FileTest.writable?(lockfile_root)
387
- raise WorkerStateError, "`#{lockfile_root}` not writable"
387
+ raise WorkerStateError, "`#{lockfile_root}` not writable. Please set agent.lockfile or agent.sockfile_path in your config to a writable path."
388
388
  end
389
389
  end
390
390
 
391
391
  unless FileTest.writable?(sockfile_path)
392
- raise WorkerStateError, "`#{sockfile_path}` not writable"
392
+ raise WorkerStateError, "`#{sockfile_path}` not writable. Please set agent.sockfile_path in your config to a writable path."
393
393
  end
394
394
  end
395
395
 
metadata CHANGED
@@ -1,27 +1,27 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: skylight
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.14
4
+ version: 0.3.17
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tilde, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-03 00:00:00.000000000 Z
11
+ date: 2014-07-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: 3.0.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: 3.0.0
27
27
  description:
@@ -33,6 +33,18 @@ extensions:
33
33
  - ext/extconf.rb
34
34
  extra_rdoc_files: []
35
35
  files:
36
+ - CHANGELOG.md
37
+ - README.md
38
+ - bin/skylight
39
+ - ext/extconf.rb
40
+ - ext/libskylight.yml
41
+ - ext/rust_support/ruby.h
42
+ - ext/skylight.h
43
+ - ext/skylight.map
44
+ - ext/skylight_native.c
45
+ - ext/test/extconf.rb
46
+ - ext/test/skylight_native_test.c
47
+ - ext/test/skylight_test.h
36
48
  - lib/skylight.rb
37
49
  - lib/skylight/api.rb
38
50
  - lib/skylight/cli.rb
@@ -57,14 +69,25 @@ files:
57
69
  - lib/skylight/middleware.rb
58
70
  - lib/skylight/native.rb
59
71
  - lib/skylight/normalizers.rb
72
+ - lib/skylight/normalizers/action_controller/process_action.rb
73
+ - lib/skylight/normalizers/action_controller/send_file.rb
74
+ - lib/skylight/normalizers/action_view/render_collection.rb
75
+ - lib/skylight/normalizers/action_view/render_partial.rb
76
+ - lib/skylight/normalizers/action_view/render_template.rb
77
+ - lib/skylight/normalizers/active_record/sql.rb
78
+ - lib/skylight/normalizers/active_support/cache.rb
79
+ - lib/skylight/normalizers/active_support/cache_clear.rb
80
+ - lib/skylight/normalizers/active_support/cache_decrement.rb
81
+ - lib/skylight/normalizers/active_support/cache_delete.rb
82
+ - lib/skylight/normalizers/active_support/cache_exist.rb
83
+ - lib/skylight/normalizers/active_support/cache_fetch_hit.rb
84
+ - lib/skylight/normalizers/active_support/cache_generate.rb
85
+ - lib/skylight/normalizers/active_support/cache_increment.rb
86
+ - lib/skylight/normalizers/active_support/cache_read.rb
87
+ - lib/skylight/normalizers/active_support/cache_read_multi.rb
88
+ - lib/skylight/normalizers/active_support/cache_write.rb
60
89
  - lib/skylight/normalizers/default.rb
61
- - lib/skylight/normalizers/moped.rb
62
- - lib/skylight/normalizers/process_action.rb
63
- - lib/skylight/normalizers/render_collection.rb
64
- - lib/skylight/normalizers/render_partial.rb
65
- - lib/skylight/normalizers/render_template.rb
66
- - lib/skylight/normalizers/send_file.rb
67
- - lib/skylight/normalizers/sql.rb
90
+ - lib/skylight/normalizers/moped/query.rb
68
91
  - lib/skylight/probes.rb
69
92
  - lib/skylight/probes/excon.rb
70
93
  - lib/skylight/probes/excon/middleware.rb
@@ -143,18 +166,6 @@ files:
143
166
  - lib/sql_lexer.rb
144
167
  - lib/sql_lexer/lexer.rb
145
168
  - lib/sql_lexer/version.rb
146
- - ext/rust_support/ruby.h
147
- - ext/skylight.h
148
- - ext/test/skylight_test.h
149
- - ext/skylight_native.c
150
- - ext/test/skylight_native_test.c
151
- - ext/skylight.map
152
- - ext/extconf.rb
153
- - ext/test/extconf.rb
154
- - ext/libskylight.yml
155
- - CHANGELOG.md
156
- - README.md
157
- - bin/skylight
158
169
  homepage: http://www.skylight.io
159
170
  licenses: []
160
171
  metadata: {}
@@ -164,17 +175,17 @@ require_paths:
164
175
  - lib
165
176
  required_ruby_version: !ruby/object:Gem::Requirement
166
177
  requirements:
167
- - - '>='
178
+ - - ">="
168
179
  - !ruby/object:Gem::Version
169
180
  version: 1.9.2
170
181
  required_rubygems_version: !ruby/object:Gem::Requirement
171
182
  requirements:
172
- - - '>='
183
+ - - ">="
173
184
  - !ruby/object:Gem::Version
174
185
  version: '0'
175
186
  requirements: []
176
187
  rubyforge_project:
177
- rubygems_version: 2.0.3
188
+ rubygems_version: 2.2.2
178
189
  signing_key:
179
190
  specification_version: 4
180
191
  summary: Skylight is a smart profiler for Rails apps
@@ -1,139 +0,0 @@
1
- module Skylight
2
- module Normalizers
3
- class Moped < Normalizer
4
- register "query.moped"
5
-
6
- CAT = "db.mongo.query".freeze
7
-
8
- def normalize(trace, name, payload)
9
- # payload: { prefix: " MOPED: #{address.resolved}", ops: operations }
10
-
11
- # We can sometimes have multiple operations. However, it seems like this only happens when doing things
12
- # like an insert, followed by a get last error, so we can probably ignore all but the first.
13
- operation = payload[:ops] ? payload[:ops].first : nil
14
- type = operation && operation.class.to_s =~ /^Moped::Protocol::(.+)$/ ? $1 : nil
15
-
16
- case type
17
- when "Query" then normalize_query(operation)
18
- when "GetMore" then normalize_get_more(operation)
19
- when "Insert" then normalize_insert(operation)
20
- when "Update" then normalize_update(operation)
21
- when "Delete" then normalize_delete(operation)
22
- else :skip
23
- end
24
- end
25
-
26
- private
27
-
28
- def normalize_query(operation)
29
- title = normalize_title("QUERY", operation)
30
-
31
- hash, binds = extract_binds(operation.selector)
32
- description = hash.to_json
33
-
34
- annotations = build_annotations(operation)
35
- annotations[:skip] = operation.skip
36
- if operation.fields
37
- annotations[:fields] = operation.fields.select{|k,v| v == 1 }.keys.map(&:to_s)
38
- end
39
- annotations[:binds] = binds unless binds.empty?
40
-
41
- [CAT, title, description, annotations]
42
- end
43
-
44
- def normalize_get_more(operation)
45
- title = normalize_title("GET_MORE", operation)
46
-
47
- annotations = build_annotations(operation)
48
- annotations[:limit] = operation.limit
49
-
50
- [CAT, title, nil, annotations]
51
- end
52
-
53
- def normalize_insert(operation)
54
- title = normalize_title("INSERT", operation)
55
-
56
- annotations = build_annotations(operation)
57
- annotations[:count] = operation.documents.count
58
-
59
- [CAT, title, nil, annotations]
60
- end
61
-
62
- def normalize_update(operation)
63
- title = normalize_title("UPDATE", operation)
64
-
65
- selector_hash, selector_binds = extract_binds(operation.selector)
66
- update_hash, update_binds = extract_binds(operation.update)
67
-
68
- description = { selector: selector_hash, update: update_hash }.to_json
69
-
70
- annotations = build_annotations(operation)
71
-
72
- binds = {}
73
- binds[:selector] = selector_binds unless selector_binds.empty?
74
- binds[:update] = update_binds unless update_binds.empty?
75
- annotations[:binds] = binds unless binds.empty?
76
-
77
- [CAT, title, description, annotations]
78
- end
79
-
80
- def normalize_delete(operation)
81
- title = normalize_title("DELETE", operation)
82
-
83
- hash, binds = extract_binds(operation.selector)
84
- description = hash.to_json
85
-
86
- annotations = build_annotations(operation)
87
- annotations[:binds] = binds unless binds.empty?
88
-
89
- [CAT, title, description, annotations]
90
- end
91
-
92
- def normalize_title(type, operation)
93
- "#{type} #{operation.collection}"
94
- end
95
-
96
- def build_annotations(operation)
97
- annotations = {}
98
-
99
- if operation.respond_to?(:flags)
100
- flags = operation.flags.map{|f| flag_name(f) }
101
- annotations[:flags] = flags unless flags.empty?
102
- end
103
-
104
- annotations
105
- end
106
-
107
- # Some flags used by Moped don't map directly to the Mongo docs
108
- # See http://docs.mongodb.org/meta-driver/latest/legacy/mongodb-wire-protocol/
109
- FLAG_MAP = {
110
- tailable: "TailableCursor",
111
- multi: "MultiUpdate"
112
- }
113
-
114
- def flag_name(flag)
115
- FLAG_MAP[flag] || flag.to_s.sub(/^[a-z\d]*/) { $&.capitalize }.gsub(/(?:_|(\/))([a-z\d]*)/) { "#{$1}#{$2.capitalize}" }
116
- end
117
-
118
- def extract_binds(hash, binds=[])
119
- hash = hash.dup
120
-
121
- hash.each do |k,v|
122
- if v.is_a?(Hash)
123
- hash[k] = extract_binds(v, binds)[0]
124
- else
125
- binds << stringify(hash[k])
126
- hash[k] = '?'
127
- end
128
- end
129
-
130
- [hash, binds]
131
- end
132
-
133
- def stringify(value)
134
- value.is_a?(Regexp) ? value.inspect : value.to_s
135
- end
136
-
137
- end
138
- end
139
- end
@@ -1,34 +0,0 @@
1
- module Skylight
2
- module Normalizers
3
- class ProcessAction < Normalizer
4
- register "process_action.action_controller"
5
-
6
- CAT = "app.controller.request".freeze
7
- PAYLOAD_KEYS = %w[ controller action params format method path ].map(&:to_sym).freeze
8
-
9
- def normalize(trace, name, payload)
10
- trace.endpoint = controller_action(payload)
11
- [ CAT, trace.endpoint, nil, normalize_payload(payload) ]
12
- end
13
-
14
- private
15
-
16
- def controller_action(payload)
17
- "#{payload[:controller]}##{payload[:action]}"
18
- end
19
-
20
- def normalize_payload(payload)
21
- normalized = {}
22
-
23
- PAYLOAD_KEYS.each do |key|
24
- val = payload[key]
25
- val = val.inspect unless val.is_a?(String) || val.is_a?(Numeric)
26
- normalized[key] = val
27
- end
28
-
29
- normalized
30
- end
31
- end
32
- end
33
- end
34
-
@@ -1,16 +0,0 @@
1
- module Skylight
2
- module Normalizers
3
- class RenderCollection < RenderNormalizer
4
- register "render_collection.action_view"
5
-
6
- CAT = "view.render.collection".freeze
7
-
8
- def normalize(trace, name, payload)
9
- normalize_render(
10
- CAT,
11
- payload,
12
- count: payload[:count])
13
- end
14
- end
15
- end
16
- end
@@ -1,16 +0,0 @@
1
- module Skylight
2
- module Normalizers
3
- class RenderPartial < RenderNormalizer
4
- register "render_partial.action_view"
5
-
6
- CAT = "view.render.template".freeze
7
-
8
- def normalize(trace, name, payload)
9
- normalize_render(
10
- CAT,
11
- payload,
12
- partial: 1)
13
- end
14
- end
15
- end
16
- end
@@ -1,16 +0,0 @@
1
- module Skylight
2
- module Normalizers
3
- class RenderTemplate < RenderNormalizer
4
- register "render_template.action_view"
5
-
6
- CAT = "view.render.template".freeze
7
-
8
- def normalize(trace, name, payload)
9
- normalize_render(
10
- CAT,
11
- payload,
12
- partial: 0)
13
- end
14
- end
15
- end
16
- end
@@ -1,74 +0,0 @@
1
- module Skylight
2
- module Normalizers
3
-
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
- CAT = "app.controller.send_file".freeze
14
- TITLE = "send file".freeze
15
-
16
- def normalize(trace, name, payload)
17
- path = payload[:path]
18
-
19
- annotations = {
20
- path: path,
21
- filename: payload[:filename],
22
- type: normalize_type(payload),
23
- disposition: normalize_disposition(payload),
24
- status: normalize_status(payload) }
25
-
26
- title = TITLE
27
-
28
- # depending on normalization, we probably want this to eventually
29
- # include the full path, but we need to make sure we have a good
30
- # deduping strategy first.
31
- desc = nil
32
-
33
- [ CAT, title, desc, annotations ]
34
- end
35
-
36
- private
37
-
38
- OCTET_STREAM = "application/octet-stream".freeze
39
- ATTACHMENT = "attachment".freeze
40
-
41
- def initialize(*)
42
- super
43
-
44
- @mimes = Mime::SET.reduce({}) do |hash, mime|
45
- hash[mime.symbol] = mime.to_s.dup.freeze
46
- hash
47
- end
48
- end
49
-
50
- def normalize_type(payload)
51
- type = payload[:type] || OCTET_STREAM
52
- type = @mimes[type] if type.is_a?(Symbol)
53
- type
54
- end
55
-
56
- def mime_for(type)
57
- @mimes[type] ||= Mime[type].to_s.freeze
58
- end
59
-
60
- def normalize_status(payload)
61
- status = payload[:status] || 200
62
- Rack::Utils.status_code(status)
63
- end
64
-
65
- def normalize_disposition(payload)
66
- payload[:disposition] || ATTACHMENT
67
- end
68
- end
69
-
70
- rescue LoadError
71
- end
72
-
73
- end
74
- end
@@ -1,79 +0,0 @@
1
- require "sql_lexer"
2
- require "json"
3
-
4
- module Skylight
5
- module Normalizers
6
- class SQL < Normalizer
7
- register "sql.active_record"
8
-
9
- CAT = "db.sql.query".freeze
10
-
11
- def normalize(trace, name, payload)
12
- case payload[:name]
13
- when "SCHEMA", "CACHE"
14
- return :skip
15
- else
16
- name = CAT
17
- title = payload[:name] || "SQL"
18
- end
19
-
20
- binds = payload[:binds]
21
-
22
- if binds && !binds.empty?
23
- binds = binds.map { |col, val| val.inspect }
24
- end
25
-
26
- extracted_title, sql, binds, error = extract_binds(payload, binds)
27
- title = extracted_title if extracted_title
28
-
29
- if sql
30
- annotations = {
31
- sql: sql,
32
- binds: binds,
33
- }
34
- else
35
- annotations = {
36
- skylight_error: error
37
- }
38
- end
39
-
40
- [ name, title, sql, annotations ]
41
- end
42
-
43
- private
44
- def extract_binds(payload, precalculated)
45
- title, sql, binds = SqlLexer::Lexer.bindify(payload[:sql], precalculated)
46
- [ title, sql, binds, nil ]
47
- rescue => e
48
- group = "sql_parse"
49
- description = e.inspect
50
- details = encode(backtrace: e.backtrace,
51
- original_exception: {
52
- class_name: e.class.name,
53
- message: e.message
54
- },
55
- payload: payload,
56
- precalculated: precalculated)
57
-
58
- error = [group, description, details]
59
- [ nil, nil, nil, error ]
60
- end
61
-
62
- # While operating in place would save memory, some of these passed in items are re-used elsewhere
63
- # and, as such, should not be modified.
64
- def encode(body)
65
- if body.is_a?(Hash)
66
- hash = {}
67
- body.each{|k,v| hash[k] = encode(v) }
68
- hash
69
- elsif body.is_a?(Array)
70
- body.map{|v| encode(v) }
71
- elsif body.respond_to?(:encoding) && (body.encoding == Encoding::BINARY || !body.valid_encoding?)
72
- Base64.encode64(body)
73
- else
74
- body
75
- end
76
- end
77
- end
78
- end
79
- end