truex-skylight 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +277 -0
- data/CLA.md +9 -0
- data/CONTRIBUTING.md +1 -0
- data/LICENSE.md +79 -0
- data/README.md +4 -0
- data/bin/skylight +3 -0
- data/ext/extconf.rb +186 -0
- data/ext/libskylight.yml +6 -0
- data/ext/skylight_memprof.c +115 -0
- data/ext/skylight_native.c +416 -0
- data/ext/skylight_native.h +20 -0
- data/lib/skylight.rb +2 -0
- data/lib/skylight/api.rb +79 -0
- data/lib/skylight/cli.rb +146 -0
- data/lib/skylight/compat.rb +47 -0
- data/lib/skylight/config.rb +498 -0
- data/lib/skylight/core.rb +122 -0
- data/lib/skylight/data/cacert.pem +3894 -0
- data/lib/skylight/formatters/http.rb +17 -0
- data/lib/skylight/gc.rb +107 -0
- data/lib/skylight/helpers.rb +137 -0
- data/lib/skylight/instrumenter.rb +290 -0
- data/lib/skylight/middleware.rb +75 -0
- data/lib/skylight/native.rb +69 -0
- data/lib/skylight/normalizers.rb +133 -0
- data/lib/skylight/normalizers/action_controller/process_action.rb +35 -0
- data/lib/skylight/normalizers/action_controller/send_file.rb +76 -0
- data/lib/skylight/normalizers/action_view/render_collection.rb +18 -0
- data/lib/skylight/normalizers/action_view/render_partial.rb +18 -0
- data/lib/skylight/normalizers/action_view/render_template.rb +18 -0
- data/lib/skylight/normalizers/active_record/sql.rb +79 -0
- data/lib/skylight/normalizers/active_support/cache.rb +50 -0
- data/lib/skylight/normalizers/active_support/cache_clear.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_decrement.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_delete.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_exist.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_fetch_hit.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_generate.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_increment.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_read.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_read_multi.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_write.rb +16 -0
- data/lib/skylight/normalizers/default.rb +21 -0
- data/lib/skylight/normalizers/moped/query.rb +141 -0
- data/lib/skylight/probes.rb +91 -0
- data/lib/skylight/probes/excon.rb +25 -0
- data/lib/skylight/probes/excon/middleware.rb +65 -0
- data/lib/skylight/probes/net_http.rb +44 -0
- data/lib/skylight/probes/redis.rb +30 -0
- data/lib/skylight/probes/sequel.rb +30 -0
- data/lib/skylight/probes/sinatra.rb +74 -0
- data/lib/skylight/probes/tilt.rb +27 -0
- data/lib/skylight/railtie.rb +122 -0
- data/lib/skylight/sinatra.rb +4 -0
- data/lib/skylight/subscriber.rb +92 -0
- data/lib/skylight/trace.rb +191 -0
- data/lib/skylight/util.rb +16 -0
- data/lib/skylight/util/allocation_free.rb +17 -0
- data/lib/skylight/util/clock.rb +53 -0
- data/lib/skylight/util/gzip.rb +15 -0
- data/lib/skylight/util/hostname.rb +17 -0
- data/lib/skylight/util/http.rb +218 -0
- data/lib/skylight/util/inflector.rb +110 -0
- data/lib/skylight/util/logging.rb +87 -0
- data/lib/skylight/util/multi_io.rb +21 -0
- data/lib/skylight/util/native_ext_fetcher.rb +205 -0
- data/lib/skylight/util/platform.rb +67 -0
- data/lib/skylight/util/ssl.rb +50 -0
- data/lib/skylight/vendor/active_support/notifications.rb +207 -0
- data/lib/skylight/vendor/active_support/notifications/fanout.rb +159 -0
- data/lib/skylight/vendor/active_support/notifications/instrumenter.rb +72 -0
- data/lib/skylight/vendor/active_support/per_thread_registry.rb +52 -0
- data/lib/skylight/vendor/cli/highline.rb +1034 -0
- data/lib/skylight/vendor/cli/highline/color_scheme.rb +134 -0
- data/lib/skylight/vendor/cli/highline/compatibility.rb +16 -0
- data/lib/skylight/vendor/cli/highline/import.rb +41 -0
- data/lib/skylight/vendor/cli/highline/menu.rb +381 -0
- data/lib/skylight/vendor/cli/highline/question.rb +481 -0
- data/lib/skylight/vendor/cli/highline/simulate.rb +48 -0
- data/lib/skylight/vendor/cli/highline/string_extensions.rb +111 -0
- data/lib/skylight/vendor/cli/highline/style.rb +181 -0
- data/lib/skylight/vendor/cli/highline/system_extensions.rb +242 -0
- data/lib/skylight/vendor/cli/thor.rb +473 -0
- data/lib/skylight/vendor/cli/thor/actions.rb +318 -0
- data/lib/skylight/vendor/cli/thor/actions/create_file.rb +105 -0
- data/lib/skylight/vendor/cli/thor/actions/create_link.rb +60 -0
- data/lib/skylight/vendor/cli/thor/actions/directory.rb +119 -0
- data/lib/skylight/vendor/cli/thor/actions/empty_directory.rb +137 -0
- data/lib/skylight/vendor/cli/thor/actions/file_manipulation.rb +314 -0
- data/lib/skylight/vendor/cli/thor/actions/inject_into_file.rb +109 -0
- data/lib/skylight/vendor/cli/thor/base.rb +652 -0
- data/lib/skylight/vendor/cli/thor/command.rb +136 -0
- data/lib/skylight/vendor/cli/thor/core_ext/hash_with_indifferent_access.rb +80 -0
- data/lib/skylight/vendor/cli/thor/core_ext/io_binary_read.rb +12 -0
- data/lib/skylight/vendor/cli/thor/core_ext/ordered_hash.rb +100 -0
- data/lib/skylight/vendor/cli/thor/error.rb +28 -0
- data/lib/skylight/vendor/cli/thor/group.rb +282 -0
- data/lib/skylight/vendor/cli/thor/invocation.rb +172 -0
- data/lib/skylight/vendor/cli/thor/parser.rb +4 -0
- data/lib/skylight/vendor/cli/thor/parser/argument.rb +74 -0
- data/lib/skylight/vendor/cli/thor/parser/arguments.rb +171 -0
- data/lib/skylight/vendor/cli/thor/parser/option.rb +121 -0
- data/lib/skylight/vendor/cli/thor/parser/options.rb +218 -0
- data/lib/skylight/vendor/cli/thor/rake_compat.rb +72 -0
- data/lib/skylight/vendor/cli/thor/runner.rb +322 -0
- data/lib/skylight/vendor/cli/thor/shell.rb +88 -0
- data/lib/skylight/vendor/cli/thor/shell/basic.rb +393 -0
- data/lib/skylight/vendor/cli/thor/shell/color.rb +148 -0
- data/lib/skylight/vendor/cli/thor/shell/html.rb +127 -0
- data/lib/skylight/vendor/cli/thor/util.rb +270 -0
- data/lib/skylight/vendor/cli/thor/version.rb +3 -0
- data/lib/skylight/vendor/thread_safe.rb +126 -0
- data/lib/skylight/vendor/thread_safe/non_concurrent_cache_backend.rb +133 -0
- data/lib/skylight/vendor/thread_safe/synchronized_cache_backend.rb +76 -0
- data/lib/skylight/version.rb +4 -0
- data/lib/skylight/vm/gc.rb +70 -0
- data/lib/sql_lexer.rb +6 -0
- data/lib/sql_lexer/lexer.rb +579 -0
- data/lib/sql_lexer/string_scanner.rb +11 -0
- data/lib/sql_lexer/version.rb +3 -0
- metadata +179 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Skylight
|
|
2
|
+
module Formatters
|
|
3
|
+
module HTTP
|
|
4
|
+
def self.build_opts(method, scheme, host, port, path, query)
|
|
5
|
+
{ category: "api.http.#{method.downcase}",
|
|
6
|
+
title: "#{method.upcase} #{host}",
|
|
7
|
+
annotations: {
|
|
8
|
+
method: method.upcase,
|
|
9
|
+
scheme: scheme,
|
|
10
|
+
host: host,
|
|
11
|
+
port: port ? port.to_i : nil,
|
|
12
|
+
path: path,
|
|
13
|
+
query: query }}
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
data/lib/skylight/gc.rb
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
require 'thread'
|
|
2
|
+
|
|
3
|
+
module Skylight
|
|
4
|
+
# @api private
|
|
5
|
+
class GC
|
|
6
|
+
METHODS = [ :enable, :total_time ]
|
|
7
|
+
TH_KEY = :SK_GC_CURR_WINDOW
|
|
8
|
+
MAX_COUNT = 1000
|
|
9
|
+
MAX_TIME = 30_000_000
|
|
10
|
+
|
|
11
|
+
include Util::Logging
|
|
12
|
+
|
|
13
|
+
attr_reader :config
|
|
14
|
+
|
|
15
|
+
def initialize(config, profiler)
|
|
16
|
+
@listeners = []
|
|
17
|
+
@config = config
|
|
18
|
+
@lock = Mutex.new
|
|
19
|
+
@time = 0
|
|
20
|
+
|
|
21
|
+
if METHODS.all? { |m| profiler.respond_to?(m) }
|
|
22
|
+
@profiler = profiler
|
|
23
|
+
@time = @profiler.total_time
|
|
24
|
+
else
|
|
25
|
+
debug "disabling GC profiling"
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def enable
|
|
30
|
+
@profiler.enable if @profiler
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def track
|
|
34
|
+
unless @profiler
|
|
35
|
+
win = Window.new(nil)
|
|
36
|
+
else
|
|
37
|
+
win = Window.new(self)
|
|
38
|
+
|
|
39
|
+
@lock.synchronize do
|
|
40
|
+
__update
|
|
41
|
+
@listeners << win
|
|
42
|
+
|
|
43
|
+
# Cleanup any listeners that might have leaked
|
|
44
|
+
until @listeners[0].time < MAX_TIME
|
|
45
|
+
@listeners.shift
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
if @listeners.length > MAX_COUNT
|
|
49
|
+
@listeners.shift
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
win
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def release(win)
|
|
58
|
+
@lock.synchronize do
|
|
59
|
+
@listeners.delete(win)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def update
|
|
64
|
+
@lock.synchronize do
|
|
65
|
+
__update
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
nil
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
private
|
|
72
|
+
|
|
73
|
+
def __update
|
|
74
|
+
time = @profiler.total_time
|
|
75
|
+
diff = time - @time
|
|
76
|
+
@time = time
|
|
77
|
+
|
|
78
|
+
if diff > 0
|
|
79
|
+
@listeners.each do |l|
|
|
80
|
+
l.add(diff)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
class Window
|
|
86
|
+
attr_reader :time
|
|
87
|
+
|
|
88
|
+
def initialize(global)
|
|
89
|
+
@global = global
|
|
90
|
+
@time = 0
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def update
|
|
94
|
+
@global.update if @global
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def add(time)
|
|
98
|
+
@time += time
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def release
|
|
102
|
+
@global.release(self) if @global
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
end
|
|
107
|
+
end
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
module Skylight
|
|
2
|
+
# Instrumenting a specific method will cause an event to be created every time that method is called.
|
|
3
|
+
# The event will be inserted at the appropriate place in the Skylight trace.
|
|
4
|
+
#
|
|
5
|
+
# To instrument a method, the first thing to do is include {Skylight::Helpers Skylight::Helpers}
|
|
6
|
+
# into the class that you will be instrumenting. Then, annotate each method that
|
|
7
|
+
# you wish to instrument with {Skylight::Helpers::ClassMethods#instrument_method instrument_method}.
|
|
8
|
+
module Helpers
|
|
9
|
+
|
|
10
|
+
# @see Skylight::Helpers
|
|
11
|
+
module ClassMethods
|
|
12
|
+
# @api private
|
|
13
|
+
def method_added(name)
|
|
14
|
+
super
|
|
15
|
+
|
|
16
|
+
if opts = @__sk_instrument_next_method
|
|
17
|
+
@__sk_instrument_next_method = nil
|
|
18
|
+
title = "#{to_s}##{name}"
|
|
19
|
+
__sk_instrument_method_on(self, name, title, opts)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# @api private
|
|
24
|
+
def singleton_method_added(name)
|
|
25
|
+
super
|
|
26
|
+
|
|
27
|
+
if opts = @__sk_instrument_next_method
|
|
28
|
+
@__sk_instrument_next_method = nil
|
|
29
|
+
title = "#{to_s}.#{name}"
|
|
30
|
+
__sk_instrument_method_on(__sk_singleton_class, name, title, opts)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# @overload instrument_method
|
|
35
|
+
# Instruments the following method
|
|
36
|
+
#
|
|
37
|
+
# @example
|
|
38
|
+
# class MyClass
|
|
39
|
+
# include Skylight::Helpers
|
|
40
|
+
#
|
|
41
|
+
# instrument_method
|
|
42
|
+
# def my_method
|
|
43
|
+
# do_expensive_stuff
|
|
44
|
+
# end
|
|
45
|
+
#
|
|
46
|
+
# end
|
|
47
|
+
#
|
|
48
|
+
# @overload instrument_method([name], opts={})
|
|
49
|
+
# @param [Symbol|String] [name]
|
|
50
|
+
# @param [Hash] opts
|
|
51
|
+
# @option opts [String] :category ('app.method')
|
|
52
|
+
# @option opts [String] :title (ClassName#method_name)
|
|
53
|
+
# @option opts [String] :description
|
|
54
|
+
#
|
|
55
|
+
# You may also declare the methods to instrument at any time by passing the name
|
|
56
|
+
# of the method as the first argument to `instrument_method`.
|
|
57
|
+
#
|
|
58
|
+
# @example With name
|
|
59
|
+
# class MyClass
|
|
60
|
+
# include Skylight::Helpers
|
|
61
|
+
#
|
|
62
|
+
# def my_method
|
|
63
|
+
# do_expensive_stuff
|
|
64
|
+
# end
|
|
65
|
+
#
|
|
66
|
+
# instrument_method :my_method
|
|
67
|
+
#
|
|
68
|
+
# end
|
|
69
|
+
#
|
|
70
|
+
# By default, the event will be titled using the name of the class and the
|
|
71
|
+
# method. For example, in our previous example, the event name will be:
|
|
72
|
+
# +MyClass#my_method+. You can customize this by passing using the *:title* option.
|
|
73
|
+
#
|
|
74
|
+
# @example Without name
|
|
75
|
+
# class MyClass
|
|
76
|
+
# include Skylight::Helpers
|
|
77
|
+
#
|
|
78
|
+
# instrument_method title: 'Expensive work'
|
|
79
|
+
# def my_method
|
|
80
|
+
# do_expensive_stuff
|
|
81
|
+
# end
|
|
82
|
+
# end
|
|
83
|
+
def instrument_method(*args)
|
|
84
|
+
opts = args.pop if Hash === args.last
|
|
85
|
+
|
|
86
|
+
if name = args.pop
|
|
87
|
+
title = "#{to_s}##{name}"
|
|
88
|
+
__sk_instrument_method_on(self, name, title, opts || {})
|
|
89
|
+
else
|
|
90
|
+
@__sk_instrument_next_method = opts || {}
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
private
|
|
95
|
+
|
|
96
|
+
def __sk_instrument_method_on(klass, name, title, opts)
|
|
97
|
+
category = (opts[:category] || "app.method").to_s
|
|
98
|
+
title = (opts[:title] || title).to_s
|
|
99
|
+
desc = opts[:description].to_s if opts[:description]
|
|
100
|
+
|
|
101
|
+
klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
102
|
+
alias_method :"before_instrument_#{name}", :"#{name}"
|
|
103
|
+
|
|
104
|
+
def #{name}(*args, &blk)
|
|
105
|
+
span = Skylight.instrument(
|
|
106
|
+
category: :"#{category}",
|
|
107
|
+
title: #{title.inspect},
|
|
108
|
+
description: #{desc.inspect})
|
|
109
|
+
|
|
110
|
+
begin
|
|
111
|
+
before_instrument_#{name}(*args, &blk)
|
|
112
|
+
ensure
|
|
113
|
+
Skylight.done(span) if span
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
RUBY
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
if respond_to?(:singleton_class)
|
|
120
|
+
alias :__sk_singleton_class :singleton_class
|
|
121
|
+
else
|
|
122
|
+
def __sk_singleton_class
|
|
123
|
+
class << self; self; end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# @api private
|
|
129
|
+
def self.included(base)
|
|
130
|
+
base.class_eval do
|
|
131
|
+
@__sk_instrument_next_method = nil
|
|
132
|
+
extend ClassMethods
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
end
|
|
137
|
+
end
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
require 'thread'
|
|
2
|
+
require 'strscan'
|
|
3
|
+
require 'skylight/api'
|
|
4
|
+
|
|
5
|
+
module Skylight
|
|
6
|
+
# @api private
|
|
7
|
+
class Instrumenter
|
|
8
|
+
KEY = :__skylight_current_trace
|
|
9
|
+
LOCK = Mutex.new
|
|
10
|
+
DESC_LOCK = Mutex.new
|
|
11
|
+
|
|
12
|
+
TOO_MANY_UNIQUES = "<too many unique descriptions>"
|
|
13
|
+
|
|
14
|
+
include Util::Logging
|
|
15
|
+
|
|
16
|
+
class TraceInfo
|
|
17
|
+
def current
|
|
18
|
+
Thread.current[KEY]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def current=(trace)
|
|
22
|
+
Thread.current[KEY] = trace
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.instance
|
|
27
|
+
@instance
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Do start
|
|
31
|
+
# @param [Config] config The config
|
|
32
|
+
def self.start!(config = nil)
|
|
33
|
+
return @instance if @instance
|
|
34
|
+
|
|
35
|
+
LOCK.synchronize do
|
|
36
|
+
return @instance if @instance
|
|
37
|
+
@instance = new(config).start!
|
|
38
|
+
end
|
|
39
|
+
rescue => e
|
|
40
|
+
message = sprintf("[SKYLIGHT] [#{Skylight::VERSION}] Unable to start Instrumenter; msg=%s; class=%s", e.message, e.class)
|
|
41
|
+
if config && config.respond_to?(:logger)
|
|
42
|
+
config.logger.warn message
|
|
43
|
+
else
|
|
44
|
+
warn message
|
|
45
|
+
end
|
|
46
|
+
false
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def self.stop!
|
|
50
|
+
LOCK.synchronize do
|
|
51
|
+
return unless @instance
|
|
52
|
+
# This is only really helpful for getting specs to pass.
|
|
53
|
+
@instance.current_trace = nil
|
|
54
|
+
|
|
55
|
+
@instance.shutdown
|
|
56
|
+
@instance = nil
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
at_exit do
|
|
61
|
+
if RUBY_VERSION == '1.9.2'
|
|
62
|
+
# workaround for MRI bug losing exit status in at_exit block
|
|
63
|
+
# http://bugs.ruby-lang.org/issues/5218
|
|
64
|
+
exit_status = $!.status if $!.is_a?(SystemExit)
|
|
65
|
+
stop!
|
|
66
|
+
exit exit_status if exit_status
|
|
67
|
+
else
|
|
68
|
+
stop!
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
attr_reader :config, :gc, :trace_info
|
|
73
|
+
|
|
74
|
+
def self.new(config)
|
|
75
|
+
config ||= {}
|
|
76
|
+
config = Config.load(config) unless config.is_a?(Config)
|
|
77
|
+
config.validate!
|
|
78
|
+
|
|
79
|
+
inst = native_new(config.to_env)
|
|
80
|
+
inst.send(:initialize, config)
|
|
81
|
+
inst
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def initialize(config)
|
|
85
|
+
@gc = config.gc
|
|
86
|
+
@config = config
|
|
87
|
+
@subscriber = Subscriber.new(config, self)
|
|
88
|
+
|
|
89
|
+
@trace_info = @config[:trace_info] || TraceInfo.new
|
|
90
|
+
@descriptions = Hash.new { |h,k| h[k] = {} }
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def current_trace
|
|
94
|
+
@trace_info.current
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def current_trace=(trace)
|
|
98
|
+
@trace_info.current = trace
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def start!
|
|
102
|
+
# Warn if there was an error installing Skylight.
|
|
103
|
+
# We do this here since we can't report these issues via Gem install without stopping install entirely.
|
|
104
|
+
Skylight.check_install_errors(config)
|
|
105
|
+
|
|
106
|
+
unless Skylight.native?
|
|
107
|
+
Skylight.warn_skylight_native_missing(config)
|
|
108
|
+
return
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
t { "starting instrumenter" }
|
|
112
|
+
@config.validate!
|
|
113
|
+
|
|
114
|
+
unless validate_authentication
|
|
115
|
+
warn "invalid authentication token"
|
|
116
|
+
return
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
t { "starting native instrumenter" }
|
|
120
|
+
unless native_start
|
|
121
|
+
warn "failed to start instrumenter"
|
|
122
|
+
return
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
@config.gc.enable
|
|
126
|
+
@subscriber.register!
|
|
127
|
+
|
|
128
|
+
self
|
|
129
|
+
|
|
130
|
+
rescue Exception => e
|
|
131
|
+
log_error "failed to start instrumenter; msg=%s; config=%s", e.message, @config.inspect
|
|
132
|
+
t { e.backtrace.join("\n") }
|
|
133
|
+
nil
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def shutdown
|
|
137
|
+
@subscriber.unregister!
|
|
138
|
+
native_stop
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def trace(endpoint, cat, title=nil, desc=nil, annot=nil)
|
|
142
|
+
# If a trace is already in progress, continue with that one
|
|
143
|
+
if trace = @trace_info.current
|
|
144
|
+
return yield(trace) if block_given?
|
|
145
|
+
return trace
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
begin
|
|
149
|
+
trace = Trace.new(self, endpoint, Util::Clock.nanos, cat, title, desc, annot)
|
|
150
|
+
rescue Exception => e
|
|
151
|
+
log_error e.message
|
|
152
|
+
t { e.backtrace.join("\n") }
|
|
153
|
+
return
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
@trace_info.current = trace
|
|
157
|
+
return trace unless block_given?
|
|
158
|
+
|
|
159
|
+
begin
|
|
160
|
+
yield trace
|
|
161
|
+
|
|
162
|
+
ensure
|
|
163
|
+
@trace_info.current = nil
|
|
164
|
+
t { "submitting trace" }
|
|
165
|
+
trace.submit
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def disable
|
|
170
|
+
@disabled = true
|
|
171
|
+
yield
|
|
172
|
+
ensure
|
|
173
|
+
@disabled = false
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def disabled?
|
|
177
|
+
@disabled
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
@scanner = StringScanner.new('')
|
|
181
|
+
def self.match?(string, regex)
|
|
182
|
+
@scanner.string = string
|
|
183
|
+
@scanner.match?(regex)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def match?(string, regex)
|
|
187
|
+
self.class.match?(string, regex)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def done(span)
|
|
191
|
+
return unless trace = @trace_info.current
|
|
192
|
+
trace.done(span)
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def instrument(cat, title=nil, desc=nil, annot=nil)
|
|
196
|
+
raise ArgumentError, 'cat is required' unless cat
|
|
197
|
+
|
|
198
|
+
unless trace = @trace_info.current
|
|
199
|
+
return yield if block_given?
|
|
200
|
+
return
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
cat = cat.to_s
|
|
204
|
+
|
|
205
|
+
unless match?(cat, CATEGORY_REGEX)
|
|
206
|
+
warn "invalid skylight instrumentation category; value=%s", cat
|
|
207
|
+
return yield if block_given?
|
|
208
|
+
return
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
cat = "other.#{cat}" unless match?(cat, TIER_REGEX)
|
|
212
|
+
|
|
213
|
+
unless sp = trace.instrument(cat, title, desc, annot)
|
|
214
|
+
return yield if block_given?
|
|
215
|
+
return
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
return sp unless block_given?
|
|
219
|
+
|
|
220
|
+
begin
|
|
221
|
+
yield sp
|
|
222
|
+
ensure
|
|
223
|
+
trace.done(sp)
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def limited_description(description)
|
|
228
|
+
endpoint = @trace_info.current.endpoint
|
|
229
|
+
|
|
230
|
+
DESC_LOCK.synchronize do
|
|
231
|
+
set = @descriptions[endpoint]
|
|
232
|
+
|
|
233
|
+
if set.size >= 100
|
|
234
|
+
return TOO_MANY_UNIQUES
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
set[description] = true
|
|
238
|
+
description
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
def process(trace)
|
|
243
|
+
t { fmt "processing trace" }
|
|
244
|
+
|
|
245
|
+
if ignore?(trace)
|
|
246
|
+
t { fmt "ignoring trace" }
|
|
247
|
+
return false
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
begin
|
|
251
|
+
native_submit_trace(trace)
|
|
252
|
+
true
|
|
253
|
+
rescue => e
|
|
254
|
+
warn "failed to submit trace to worker; err=%s", e
|
|
255
|
+
false
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def ignore?(trace)
|
|
260
|
+
@config.ignored_endpoints.include?(trace.endpoint)
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
# Validates that the provided authentication token is valid. This is done
|
|
264
|
+
# by issuing a request for a session token and checking the response
|
|
265
|
+
def validate_authentication
|
|
266
|
+
# If a session token is specified, don't bother attempting to validate
|
|
267
|
+
if config[:session_token]
|
|
268
|
+
debug "using pre-generated session token"
|
|
269
|
+
true
|
|
270
|
+
else
|
|
271
|
+
api = Api.new(config)
|
|
272
|
+
api.authentication = config[:authentication]
|
|
273
|
+
|
|
274
|
+
case res = api.validate_authentication
|
|
275
|
+
when :ok
|
|
276
|
+
true
|
|
277
|
+
when :invalid
|
|
278
|
+
false
|
|
279
|
+
when :unknown
|
|
280
|
+
warn "unable to validate authentication token"
|
|
281
|
+
true
|
|
282
|
+
else
|
|
283
|
+
error "[BUG] unexpected validate_token result; res=%s", res
|
|
284
|
+
true
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
end
|
|
290
|
+
end
|