skylight 0.9.3 → 0.9.4

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: 1564afa767483c0b2e5ce584e197f5ea3f72933a
4
- data.tar.gz: f20f7f995bfff398ee791d73066cd0495a8bef7d
3
+ metadata.gz: 3a889a7a09786acddcdf866faaf84ed4862909f4
4
+ data.tar.gz: 5e2f48fcfcea4166894f19422b435eb82d809856
5
5
  SHA512:
6
- metadata.gz: 61bb59ac6c2c256370adcc09962b3555c1b68bdedf6590926283f4398900a3a83c852b7686f693d4068666b11f6145fa70b0e3c8e82e66436c5fdf490a2dc728
7
- data.tar.gz: e1dc0699037df80f0127058b15263cf718f7e1e9fe441a00296e0edd5200d1f938afb9c1e2a823c3fad5fc2a97aed9c4e15ce3566d853db85ad7488851824680
6
+ metadata.gz: 59381efc987947df3b1a8bff022beb0a61288c02b41124b861ea3923db126a4b38fb74100ad67b8efac86b694843fa7c70545bef02be511c9b1892d265a998fa
7
+ data.tar.gz: 7c433c0b9b74b350955aa27641b3ae1ac6d1a2ddd8d018f71f94302078d04e1a000c697b8f339663d8af12d2417df4b973c5f786386cb14a426865eaa9b9ea95
@@ -1,3 +1,13 @@
1
+ ## 0.9.4 (November 23, 2015)
2
+
3
+ * [FEATURE] Added instrumentation for official Mongo Ruby Driver (utilized by Mongoid 5+). Add 'mongo' to probes list to enable.
4
+ * [BUGFIX] SQL lexer now handles indentifiers beginning with underscores.
5
+ * [BUGFIX] Excon instrumentation now works correctly.
6
+ * [BUGFIX] Graceful handling of native agent failures on old OS X versions.
7
+ * [IMPROVEMENT] Freeze some more strings for (likely very minor) performance improvements.
8
+ * [IMPROVEMENT] Better error messages when sockdir is an NFS mount.
9
+ * [IMPROVEMENT] On OS X, ensure that Xcode license has been approved before trying to build native agent.
10
+
1
11
  ## 0.9.3 (November 17, 2015)
2
12
 
3
13
  * [BUGFIX] Update SQL lexer to handle more common queries
@@ -46,6 +46,21 @@ def fail(msg, type=:error)
46
46
  end
47
47
  end
48
48
 
49
+ # Check that Xcode license has been approved
50
+ # Based on Homebrew's implementation
51
+ # https://github.com/Homebrew/homebrew/blob/03708b016755847facc4f19a43ee9f7a44141ed7/Library/Homebrew/cmd/doctor.rb#L1183
52
+ if Platform::OS == 'darwin'
53
+ # If the user installs Xcode-only, they have to approve the
54
+ # license or no "xc*" tool will work.
55
+ if `/usr/bin/xcrun clang 2>&1` =~ /license/ && !$?.success?
56
+ fail <<-EOS
57
+ You have not agreed to the Xcode license and so we are unable to build the native agent.
58
+ To resolve this, you can agree to the license by opening Xcode.app or running:
59
+ sudo xcodebuild -license
60
+ EOS
61
+ end
62
+ end
63
+
49
64
  #
50
65
  # === Setup paths
51
66
  #
@@ -1,6 +1,6 @@
1
1
  ---
2
- version: "0.7.0-629fc27"
2
+ version: "0.7.0-ffe066b"
3
3
  checksums:
4
- x86-linux: "cd601750d0250d9e2cfed96fa9d4ac642a1b22053cf5ee5a7523da2f583fdf2d"
5
- x86_64-linux: "eef6301799be9e1e6e70f71c59ac1449f52f65cf1dfe5c996762a42f31e08d5f"
6
- x86_64-darwin: "62b19c0f34e983d8d752b1b9514d427cc019cfdf2f3f6b2f1424cf06710330d8"
4
+ x86-linux: "311cf34d25383d1a0c7f4611919ac78e49cbd2e227532ea9aa2b308212e9fca9"
5
+ x86_64-linux: "9d4969487f16e0f1d2ed6410dc4ea408e28ec4ea157c1a56c93b0bf596600461"
6
+ x86_64-darwin: "4e40e9a08efa8953ed1afca07c684385fa374833a057136057bf36ef41cce55e"
@@ -39,6 +39,7 @@ module Skylight
39
39
 
40
40
  # == Instrumenter ==
41
41
  "IGNORED_ENDPOINT" => :'ignored_endpoint',
42
+ "IGNORED_ENDPOINTS" => :'ignored_endpoints',
42
43
  "SQL_MODE" => :'sql_mode',
43
44
 
44
45
  # == Skylight Remote ==
@@ -268,6 +269,8 @@ module Skylight
268
269
  end
269
270
  end
270
271
 
272
+ # FIXME: Why not set the sockdir_path and pidfile_path explicitly?
273
+ # That way we don't have to keep this in sync with the Rust repo.
271
274
  sockdir_path = self[:'daemon.sockdir_path'] || File.expand_path('.')
272
275
  pidfile_path = self[:'daemon.pidfile_path'] || File.expand_path('skylight.pid', sockdir_path)
273
276
 
@@ -283,11 +286,11 @@ module Skylight
283
286
  FileUtils.mkdir_p sockdir_path
284
287
 
285
288
  if File.exist?(pidfile)
286
- if !FileTest.writable?(pidfile)
289
+ unless FileTest.writable?(pidfile)
287
290
  raise ConfigError, "File `#{pidfile}` not writable. Please set daemon.pidfile_path or daemon.sockdir_path in your config to a writable path"
288
291
  end
289
292
  else
290
- if !FileTest.writable?(pidfile_root)
293
+ unless FileTest.writable?(pidfile_root)
291
294
  raise ConfigError, "Directory `#{pidfile_root}` not writable. Please set daemon.pidfile_path or daemon.sockdir_path in your config to a writable path"
292
295
  end
293
296
  end
@@ -295,6 +298,10 @@ module Skylight
295
298
  unless FileTest.writable?(sockdir_path)
296
299
  raise ConfigError, "Directory `#{sockdir_path}` not writable. Please set daemon.sockdir_path in your config to a writable path"
297
300
  end
301
+
302
+ if check_nfs(pidfile)
303
+ raise ConfigError, "Directory `#{sockdir_path}` is an NFS mount and will not allow sockets. Please set daemon.sockdir_path in your config to a non-NFS path."
304
+ end
298
305
  end
299
306
 
300
307
  def key?(key)
@@ -420,8 +427,16 @@ authentication: #{self[:authentication]}
420
427
  def ignored_endpoints
421
428
  @ignored_endpoints ||=
422
429
  begin
430
+ ignored_endpoints = get(:'ignored_endpoints')
431
+
432
+ # If, for some odd reason you have a comma in your endpoint name, use the
433
+ # YML config instead.
434
+ if ignored_endpoints.is_a?(String)
435
+ ignored_endpoints = ignored_endpoints.split(/\s*,\s*/)
436
+ end
437
+
423
438
  val = Array(get(:'ignored_endpoint'))
424
- val.concat(Array(get(:'ignored_endpoints')))
439
+ val.concat(Array(ignored_endpoints))
425
440
  val
426
441
  end
427
442
  end
@@ -470,6 +485,11 @@ authentication: #{self[:authentication]}
470
485
 
471
486
  private
472
487
 
488
+ def check_nfs(path)
489
+ # Should work on most *nix, though not on OS X
490
+ `stat -f -L -c %T #{path} 2>&1`.strip == 'nfs'
491
+ end
492
+
473
493
  def load_logger
474
494
  unless l = @logger
475
495
  out = get(:'log_file')
@@ -86,7 +86,7 @@ module Skylight
86
86
  end
87
87
 
88
88
  # Instrument
89
- def self.instrument(opts = DEFAULT_OPTIONS)
89
+ def self.instrument(opts = DEFAULT_OPTIONS, &block)
90
90
  unless inst = Instrumenter.instance
91
91
  return yield if block_given?
92
92
  return
@@ -105,11 +105,7 @@ module Skylight
105
105
  desc = nil
106
106
  end
107
107
 
108
- if block_given?
109
- inst.instrument(category, title, desc) { yield }
110
- else
111
- inst.instrument(category, title, desc)
112
- end
108
+ inst.instrument(category, title, desc, &block)
113
109
  end
114
110
 
115
111
  # Temporarily disable
@@ -32,6 +32,9 @@ module Skylight
32
32
  raise LoadError, "Cannot find native extensions in #{libskylight_path}"
33
33
  end
34
34
  end
35
+ rescue RuntimeError => e
36
+ # Old versions of OS X can have dlerrors, just treat it like a missing native
37
+ raise if skylight_required || e.message !~ /dlerror/
35
38
  rescue LoadError => e
36
39
  raise if skylight_required
37
40
  end
@@ -13,11 +13,11 @@ module Skylight
13
13
 
14
14
  def normalize(trace, name, payload)
15
15
  case payload[:name]
16
- when "SCHEMA", "CACHE"
16
+ when "SCHEMA".freeze, "CACHE".freeze
17
17
  return :skip
18
18
  else
19
19
  name = CAT
20
- title = payload[:name] || "SQL"
20
+ title = payload[:name] || "SQL".freeze
21
21
  end
22
22
 
23
23
  binds = payload[:binds]
@@ -41,9 +41,9 @@ module Skylight
41
41
 
42
42
  def extract_binds(payload, precalculated)
43
43
  case config[:sql_mode]
44
- when 'rust'
44
+ when 'rust'.freeze
45
45
  extract_rust(payload)
46
- when 'ruby'
46
+ when 'ruby'.freeze
47
47
  extract_ruby(payload, precalculated)
48
48
  else
49
49
  raise "Unrecognized sql_mode: #{config.sql_mode}"
@@ -15,11 +15,11 @@ module Skylight
15
15
  type = operation && operation.class.to_s =~ /^Moped::Protocol::(.+)$/ ? $1 : nil
16
16
 
17
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)
18
+ when "Query".freeze then normalize_query(operation)
19
+ when "GetMore".freeze then normalize_get_more(operation)
20
+ when "Insert".freeze then normalize_insert(operation)
21
+ when "Update".freeze then normalize_update(operation)
22
+ when "Delete".freeze then normalize_delete(operation)
23
23
  else :skip
24
24
  end
25
25
  end
@@ -27,7 +27,7 @@ module Skylight
27
27
  private
28
28
 
29
29
  def normalize_query(operation)
30
- title = normalize_title("QUERY", operation)
30
+ title = normalize_title("QUERY".freeze, operation)
31
31
 
32
32
  hash = extract_binds(operation.selector)
33
33
  description = hash.to_json
@@ -36,19 +36,19 @@ module Skylight
36
36
  end
37
37
 
38
38
  def normalize_get_more(operation)
39
- title = normalize_title("GET_MORE", operation)
39
+ title = normalize_title("GET_MORE".freeze, operation)
40
40
 
41
41
  [CAT, title, nil]
42
42
  end
43
43
 
44
44
  def normalize_insert(operation)
45
- title = normalize_title("INSERT", operation)
45
+ title = normalize_title("INSERT".freeze, operation)
46
46
 
47
47
  [CAT, title, nil]
48
48
  end
49
49
 
50
50
  def normalize_update(operation)
51
- title = normalize_title("UPDATE", operation)
51
+ title = normalize_title("UPDATE".freeze, operation)
52
52
 
53
53
  selector_hash = extract_binds(operation.selector)
54
54
  update_hash = extract_binds(operation.update)
@@ -59,7 +59,7 @@ module Skylight
59
59
  end
60
60
 
61
61
  def normalize_delete(operation)
62
- title = normalize_title("DELETE", operation)
62
+ title = normalize_title("DELETE".freeze, operation)
63
63
 
64
64
  hash = extract_binds(operation.selector)
65
65
  description = hash.to_json
@@ -78,17 +78,13 @@ module Skylight
78
78
  if v.is_a?(Hash)
79
79
  ret[k] = extract_binds(v)
80
80
  else
81
- ret[k] = '?'
81
+ ret[k] = '?'.freeze
82
82
  end
83
83
  end
84
84
 
85
85
  ret
86
86
  end
87
87
 
88
- def stringify(value)
89
- value.is_a?(Regexp) ? value.inspect : value.to_s
90
- end
91
-
92
88
  end
93
89
  end
94
90
  end
@@ -53,8 +53,9 @@ module Skylight
53
53
  end
54
54
 
55
55
  def end_instrumentation(datum)
56
- @requests[datum.object_id].done
57
- @requests.delete(datum)
56
+ if request = @requests.delete(datum.object_id)
57
+ Skylight.done(request)
58
+ end
58
59
  rescue Exception => e
59
60
  error "failed to end instrumentation for Excon; msg=%s", e.message
60
61
  end
@@ -0,0 +1,159 @@
1
+ module Skylight
2
+ module Probes
3
+ module Mongo
4
+ class Probe
5
+ def install
6
+ ::Mongo::Monitoring::Global.subscribe(::Mongo::Monitoring::COMMAND, Subscriber.new)
7
+ end
8
+ end
9
+
10
+ class Subscriber
11
+ include Skylight::Util::Logging
12
+
13
+ COMMANDS = [:insert, :find, :count, :distinct, :update, :findandmodify, :delete].freeze
14
+
15
+ COMMAND_NAMES = {
16
+ findandmodify: 'findAndModify'.freeze
17
+ }.freeze
18
+
19
+ def initialize
20
+ @events = {}
21
+ end
22
+
23
+ def started(event)
24
+ begin_instrumentation(event)
25
+ end
26
+
27
+ def succeeded(event)
28
+ end_instrumentation(event)
29
+ end
30
+
31
+ def failed(event)
32
+ end_instrumentation(event)
33
+ end
34
+
35
+ # For logging
36
+ def config
37
+ instrumenter = Skylight::Instrumenter.instance
38
+ instrumenter ? instrumenter.config : nil
39
+ end
40
+
41
+ private
42
+
43
+ def begin_instrumentation(event)
44
+ return unless COMMANDS.include?(event.command_name.to_sym)
45
+
46
+ command_name = COMMAND_NAMES[event.command_name] || event.command_name
47
+
48
+ title = "#{event.database_name}.#{command_name}"
49
+
50
+ command = event.command
51
+
52
+ # Not sure if this will always exist
53
+ # Delete so the description will be less redundant
54
+ if target = command[event.command_name]
55
+ title << " #{target}"
56
+ end
57
+
58
+ payload = {}
59
+
60
+ # Ruby Hashes are ordered based on insertion so do the most important ones first
61
+
62
+ add_value('key'.freeze, command, payload)
63
+ add_bound('query'.freeze, command, payload)
64
+ add_bound('filter'.freeze, command, payload)
65
+ add_value('sort'.freeze, command, payload)
66
+
67
+ if event.command_name == :findandmodify
68
+ add_bound('update'.freeze, command, payload)
69
+ end
70
+
71
+ add_value('remove'.freeze, command, payload)
72
+ add_value('new'.freeze, command, payload)
73
+
74
+ if updates = command['updates'.freeze]
75
+ # AFAICT the gem generally just sends one item in the updates array
76
+ update = updates[0]
77
+ update_payload = {}
78
+ add_bound('q'.freeze, update, update_payload)
79
+ add_bound('u'.freeze, update, update_payload)
80
+ add_value('multi'.freeze, update, update_payload)
81
+ add_value('upsert'.freeze, update, update_payload)
82
+
83
+ payload['updates'.freeze] = [update_payload]
84
+
85
+ if updates.length > 1
86
+ payload['updates'.freeze] << '...'
87
+ end
88
+ end
89
+
90
+ if deletes = command['deletes'.freeze]
91
+ # AFAICT the gem generally just sends one item in the updates array
92
+ delete = deletes[0]
93
+ delete_payload = {}
94
+ add_bound('q'.freeze, delete, delete_payload)
95
+ add_value('limit'.freeze, delete, delete_payload)
96
+
97
+ payload['deletes'.freeze] = [delete_payload]
98
+
99
+ if deletes.length > 1
100
+ payload['deletes'.freeze] << '...'
101
+ end
102
+ end
103
+
104
+
105
+ # We're ignoring documents from insert because they could have completely inconsistent
106
+ # format which would make it hard to merge.
107
+
108
+ opts = {
109
+ category: "db.mongo.command".freeze,
110
+ title: title,
111
+ description: payload.empty? ? nil : payload.to_json
112
+ }
113
+
114
+ @events[event.operation_id] = Skylight.instrument(opts)
115
+ rescue Exception => e
116
+ error "failed to begin instrumentation for Mongo; msg=%s", e.message
117
+ end
118
+
119
+ def end_instrumentation(event)
120
+ if original_event = @events.delete(event.operation_id)
121
+ Skylight.done(original_event)
122
+ end
123
+ rescue Exception => e
124
+ error "failed to end instrumentation for Mongo; msg=%s", e.message
125
+ end
126
+
127
+ def add_value(key, command, payload)
128
+ if command.has_key?(key)
129
+ value = command[key]
130
+ payload[key] = value
131
+ end
132
+ end
133
+
134
+ def add_bound(key, command, payload)
135
+ if value = command[key]
136
+ payload[key] = extract_binds(value)
137
+ end
138
+ end
139
+
140
+ def extract_binds(hash)
141
+ ret = {}
142
+
143
+ hash.each do |k,v|
144
+ if v.is_a?(Hash)
145
+ ret[k] = extract_binds(v)
146
+ else
147
+ ret[k] = '?'.freeze
148
+ end
149
+ end
150
+
151
+ ret
152
+ end
153
+
154
+ end
155
+ end
156
+
157
+ register("Mongo", "mongo", Mongo::Probe.new)
158
+ end
159
+ end
@@ -0,0 +1,21 @@
1
+ module Skylight
2
+ module Probes
3
+ module Mongoid
4
+ class Probe
5
+
6
+ def install
7
+ require 'mongoid/version'
8
+ version = Gem::Version.new(::Mongoid::VERSION)
9
+
10
+ if version < Gem::Version.new("5.0")
11
+ require 'skylight/probes/moped'
12
+ else
13
+ require 'skylight/probes/mongo'
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ register("Mongoid", "mongoid", Mongoid::Probe.new)
20
+ end
21
+ end
@@ -0,0 +1,31 @@
1
+ module Skylight
2
+ module Probes
3
+ module Moped
4
+ class Probe
5
+
6
+ def install
7
+ ::Moped::Instrumentable.module_eval do
8
+ alias instrument_without_sk instrument
9
+
10
+ def instrument(*args, &block)
11
+ # Mongoid sets the instrumenter to AS::N
12
+ if instrumenter == ActiveSupport::Notifications
13
+ asn_block = block
14
+ else
15
+ # If the instrumenter hasn't been changed to AS::N use both
16
+ asn_block = Proc.new do
17
+ ActiveSupport::Notifications.instrument(*args, &block)
18
+ end
19
+ end
20
+
21
+ instrument_without_sk(*args, &asn_block)
22
+ end
23
+ end
24
+ end
25
+
26
+ end
27
+ end
28
+
29
+ register("Moped", "moped", Moped::Probe.new)
30
+ end
31
+ end
@@ -66,12 +66,12 @@ module Skylight
66
66
  end
67
67
 
68
68
  config = Config.load(file: path, environment: Rails.env.to_s)
69
- config['root'] = Rails.root
69
+ config[:root] = Rails.root
70
70
 
71
71
  configure_logging(config, app)
72
72
 
73
- config['daemon.sockdir_path'] ||= tmp
74
- config['normalizers.render.view_paths'] = existent_paths(app.config.paths["app/views"]) + [Rails.root.to_s]
73
+ config[:'daemon.sockdir_path'] ||= tmp
74
+ config[:'normalizers.render.view_paths'] = existent_paths(app.config.paths["app/views"]) + [Rails.root.to_s]
75
75
  config.validate!
76
76
  config
77
77
 
@@ -30,9 +30,7 @@ module Skylight
30
30
  @notifications = []
31
31
 
32
32
  # create the root node
33
- @root = native_start_span(native_get_started_at, cat)
34
- native_span_set_title(@root, title) if title
35
- native_span_set_description(@root, desc) if desc
33
+ @root = start(native_get_started_at, cat, title, desc, normalize: false)
36
34
 
37
35
  @gc = config.gc.track unless ENV.key?("SKYLIGHT_DISABLE_GC_TRACKING")
38
36
  end
@@ -140,15 +138,18 @@ module Skylight
140
138
 
141
139
  private
142
140
 
143
- def start(time, cat, title, desc)
144
- sp = native_start_span(self.class.normalize_time(time), cat.to_s)
141
+ def start(time, cat, title, desc, opts={})
142
+ time = self.class.normalize_time(time) unless opts[:normalize] == false
143
+
144
+ sp = native_start_span(time, cat.to_s)
145
145
  native_span_set_title(sp, title.to_s) if title
146
146
  native_span_set_description(sp, desc.to_s) if desc
147
147
  sp
148
148
  end
149
149
 
150
150
  def stop(span, time)
151
- native_stop_span(span, self.class.normalize_time(time))
151
+ time = self.class.normalize_time(time)
152
+ native_stop_span(span, time)
152
153
  nil
153
154
  end
154
155
 
@@ -1,4 +1,4 @@
1
1
  module Skylight
2
- VERSION = '0.9.3'
2
+ VERSION = '0.9.4'
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.9.3
4
+ version: 0.9.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tilde, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-11-17 00:00:00.000000000 Z
11
+ date: 2015-11-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -86,6 +86,9 @@ files:
86
86
  - lib/skylight/probes/excon.rb
87
87
  - lib/skylight/probes/excon/middleware.rb
88
88
  - lib/skylight/probes/grape.rb
89
+ - lib/skylight/probes/mongo.rb
90
+ - lib/skylight/probes/mongoid.rb
91
+ - lib/skylight/probes/moped.rb
89
92
  - lib/skylight/probes/net_http.rb
90
93
  - lib/skylight/probes/redis.rb
91
94
  - lib/skylight/probes/sequel.rb