app_perf_rpm 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/app_perf_rpm/aggregator.rb +77 -0
- data/lib/app_perf_rpm/backtrace.rb +92 -0
- data/lib/app_perf_rpm/configuration.rb +56 -0
- data/lib/app_perf_rpm/dispatcher.rb +85 -0
- data/lib/app_perf_rpm/instrumentation.rb +21 -0
- data/lib/app_perf_rpm/instruments/action_controller.rb +51 -0
- data/lib/app_perf_rpm/instruments/action_view.rb +126 -0
- data/lib/app_perf_rpm/instruments/active_record/adapters/mysql2.rb +45 -0
- data/lib/app_perf_rpm/instruments/active_record/adapters/postgresql.rb +102 -0
- data/lib/app_perf_rpm/instruments/active_record/adapters/sqlite3.rb +103 -0
- data/lib/app_perf_rpm/instruments/active_record.rb +57 -0
- data/lib/app_perf_rpm/instruments/activerecord_import.rb +47 -0
- data/lib/app_perf_rpm/instruments/emque_consuming.rb +31 -0
- data/lib/app_perf_rpm/instruments/faraday.rb +37 -0
- data/lib/app_perf_rpm/instruments/net_http.rb +36 -0
- data/lib/app_perf_rpm/instruments/rack.rb +41 -0
- data/lib/app_perf_rpm/instruments/rack_middleware.rb +69 -0
- data/lib/app_perf_rpm/instruments/redis.rb +39 -0
- data/lib/app_perf_rpm/instruments/sequel.rb +92 -0
- data/lib/app_perf_rpm/instruments/sidekiq.rb +55 -0
- data/lib/app_perf_rpm/instruments/sinatra.rb +68 -0
- data/lib/app_perf_rpm/instruments/typhoeus.rb +55 -0
- data/lib/app_perf_rpm/introspector.rb +51 -0
- data/lib/app_perf_rpm/logger.rb +32 -0
- data/lib/app_perf_rpm/middleware.rb +30 -0
- data/lib/app_perf_rpm/rails.rb +14 -0
- data/lib/app_perf_rpm/railtie.rb +29 -0
- data/lib/app_perf_rpm/span.rb +103 -0
- data/lib/app_perf_rpm/tracer.rb +139 -0
- data/lib/app_perf_rpm/utils.rb +9 -0
- data/lib/app_perf_rpm/worker.rb +46 -0
- data/lib/app_perf_rpm.rb +124 -0
- data/lib/tasks/install.rake +6 -0
- metadata +146 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b34ed99c3e8e44848ad0973d852d87017529d97e
|
4
|
+
data.tar.gz: 21b6044514766bc7fc0df5ab6fe191e22d896cd9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 31f24ad79ef22b4a7835daec2a2abf9bdb8d5c8d3b02b48d223eba656eda148841bb12724dc95ddd479f01241e951f42a5862378444c283fa1811bec2adeca48
|
7
|
+
data.tar.gz: d1f1aaf3e684d319ff06378ccac8c8e0ccf9f482dd3cc309493dca89a2c7ed79479b3a40f06117e8cc9b0589cf10aebc0781f7f0fc73bba9c461f005bf9145af
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
|
3
|
+
module AppPerfRpm
|
4
|
+
class Aggregator
|
5
|
+
def initialize
|
6
|
+
end
|
7
|
+
|
8
|
+
def aggregate(traces)
|
9
|
+
metrics = []
|
10
|
+
traces = arrange_traces(traces)
|
11
|
+
spans = traces_to_spans(traces)
|
12
|
+
spans_by_time(spans).each_pair do |time, spans|
|
13
|
+
group_spans(spans).each_pair do |(type, layer, domain, url, controller, action), grouped_spans|
|
14
|
+
opts = {}
|
15
|
+
opts["type"] = type if type
|
16
|
+
opts["layer"] = layer if layer
|
17
|
+
opts["domain"] = domain if domain
|
18
|
+
opts["url"] = url if url
|
19
|
+
opts["controller"] = controller if controller
|
20
|
+
opts["action"] = action if action
|
21
|
+
metrics << build_metric("trace.web.request.duration", time, grouped_spans, opts)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
return metrics
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def build_metric(metric_name, time, spans, opts)
|
31
|
+
num_spans = spans.uniq(&:trace_id).size
|
32
|
+
durations = spans.inject(0.0) {|s, x| s + x.exclusive_duration }.to_f
|
33
|
+
hits = spans.size
|
34
|
+
|
35
|
+
tags = {
|
36
|
+
"traces" => num_spans,
|
37
|
+
"hits" => hits
|
38
|
+
}.merge(opts)
|
39
|
+
|
40
|
+
["metric", time.to_f, metric_name, durations, tags]
|
41
|
+
end
|
42
|
+
|
43
|
+
def arrange_traces(traces)
|
44
|
+
traces
|
45
|
+
.group_by(&:trace_id)
|
46
|
+
.map {|span| Span.arrange(span.last.dup) }
|
47
|
+
end
|
48
|
+
|
49
|
+
def traces_to_spans(traces)
|
50
|
+
traces
|
51
|
+
.map {|trace| trace.to_spans}
|
52
|
+
.flatten
|
53
|
+
end
|
54
|
+
|
55
|
+
def spans_by_time(spans)
|
56
|
+
spans.group_by {|span|
|
57
|
+
AppPerfRpm.floor_time(Time.at(span.started_at), dispatch_interval)
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
def group_spans(spans)
|
62
|
+
spans
|
63
|
+
.group_by {|span| [
|
64
|
+
span.type,
|
65
|
+
span.layer,
|
66
|
+
span.domain,
|
67
|
+
span.url,
|
68
|
+
span.controller,
|
69
|
+
span.action
|
70
|
+
]}
|
71
|
+
end
|
72
|
+
|
73
|
+
def dispatch_interval
|
74
|
+
30
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module AppPerfRpm
|
2
|
+
class Backtrace
|
3
|
+
class << self
|
4
|
+
def backtrace
|
5
|
+
bt = Kernel.caller
|
6
|
+
bt = clean(bt)
|
7
|
+
trim_backtrace(bt)
|
8
|
+
end
|
9
|
+
|
10
|
+
def clean(backtrace)
|
11
|
+
backtrace
|
12
|
+
.map {|b| clean_line(b) }
|
13
|
+
.select {|b| b !~ %r{lib/app_perf_rpm} }
|
14
|
+
end
|
15
|
+
|
16
|
+
#def source_extract(_backtrace = Kernel.caller(2))
|
17
|
+
# if(trace = _backtrace.first)
|
18
|
+
# file, line_number = extract_file_and_line_number(trace)
|
19
|
+
|
20
|
+
# {
|
21
|
+
# code: source_fragment(file, line_number),
|
22
|
+
# line_number: line_number
|
23
|
+
# }
|
24
|
+
# else
|
25
|
+
# nil
|
26
|
+
# end
|
27
|
+
#end
|
28
|
+
|
29
|
+
def source_extract(_backtrace = Kernel.caller(0))
|
30
|
+
Array(_backtrace).select {|bt| bt[/^#{::AppPerfRpm.configuration.app_root.to_s}\//] }.map do |trace|
|
31
|
+
file, line_number = extract_file_and_line_number(trace)
|
32
|
+
source_to_hash(file, line_number)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def source_to_hash(file, line_number)
|
37
|
+
{
|
38
|
+
"file" => clean_line(file),
|
39
|
+
"code" => source_fragment(file, line_number),
|
40
|
+
"line_number" => line_number
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def clean_line(line)
|
47
|
+
line
|
48
|
+
.sub(/#{::AppPerfRpm.configuration.app_root.to_s}\//, "[APP_PATH]/")
|
49
|
+
.sub(gems_regexp, '\2 (\3) [GEM_PATH]/\4')
|
50
|
+
end
|
51
|
+
|
52
|
+
def gems_regexp
|
53
|
+
gems_paths = (Gem.path | [Gem.default_dir]).map { |p| Regexp.escape(p) }
|
54
|
+
if gems_paths
|
55
|
+
%r{(#{gems_paths.join('|')})/gems/([^/]+)-([\w.]+)/(.*)}
|
56
|
+
else
|
57
|
+
nil
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def source_fragment(path, line)
|
62
|
+
return unless AppPerfRpm.configuration.app_root
|
63
|
+
full_path = AppPerfRpm.configuration.app_root.join(path)
|
64
|
+
if File.exist?(full_path)
|
65
|
+
File.open(full_path, "r") do |file|
|
66
|
+
start = [line - 3, 0].max
|
67
|
+
lines = file.each_line.drop(start).take(6)
|
68
|
+
Hash[*(start + 1..(lines.count + start)).zip(lines).flatten]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def extract_file_and_line_number(trace)
|
74
|
+
file, line = trace.match(/^(.+?):(\d+).*$/, &:captures) || trace
|
75
|
+
[file, line.to_i]
|
76
|
+
end
|
77
|
+
|
78
|
+
def trim_backtrace(_backtrace)
|
79
|
+
return _backtrace unless _backtrace.is_a?(Array)
|
80
|
+
|
81
|
+
length = _backtrace.size
|
82
|
+
if length > 100
|
83
|
+
# Trim backtraces by getting the first 180 and last 20 lines
|
84
|
+
trimmed = _backtrace[0, 80] + ['...[snip]...'] + _backtrace[length - 20, 20]
|
85
|
+
else
|
86
|
+
trimmed = _backtrace
|
87
|
+
end
|
88
|
+
trimmed
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module AppPerfRpm
|
4
|
+
class Configuration
|
5
|
+
attr_accessor :app_root,
|
6
|
+
:host,
|
7
|
+
:port,
|
8
|
+
:license_key,
|
9
|
+
:ssl,
|
10
|
+
:sample_rate,
|
11
|
+
:sample_threshold,
|
12
|
+
:dispatch_interval,
|
13
|
+
:application_name,
|
14
|
+
:instrumentation,
|
15
|
+
:agent_disabled
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
reload
|
19
|
+
end
|
20
|
+
|
21
|
+
def reload
|
22
|
+
::AppPerfRpm.mutex.synchronize do
|
23
|
+
self.app_root = app_root ? Pathname.new(app_root.to_s) : nil
|
24
|
+
self.host ||= default_if_blank(ENV["APP_PERF_HOST"], "http://localhost:5000")
|
25
|
+
self.ssl ||= false
|
26
|
+
self.license_key ||= default_if_blank(ENV["APP_PERF_LICENSE_KEY"], nil)
|
27
|
+
self.application_name ||= "Default"
|
28
|
+
self.sample_rate ||= 10 # Percentage of request to sample
|
29
|
+
self.sample_threshold ||= 0 # Minimum amount of duration to sample
|
30
|
+
self.dispatch_interval ||= 60 # In seconds
|
31
|
+
self.agent_disabled ||= default_if_blank(ENV["APP_PERF_AGENT_DISABLED"], false)
|
32
|
+
self.instrumentation = {
|
33
|
+
:rack => { :enabled => true, :backtrace => false, :trace_middleware => true },
|
34
|
+
:active_record => { :enabled => true, :backtrace => false },
|
35
|
+
:active_record_import => { :enabled => true, :backtrace => false },
|
36
|
+
:action_view => { :enabled => true, :backtrace => false },
|
37
|
+
:action_controller => { :enabled => true, :backtrace => false },
|
38
|
+
:emque_consuming => { :enabled => true, :backtrace => false },
|
39
|
+
:redis => { :enabled => true, :backtrace => false },
|
40
|
+
:sequel => { :enabled => true, :backtrace => false },
|
41
|
+
:sidekiq => { :enabled => true, :backtrace => false },
|
42
|
+
:sinatra => { :enabled => true, :backtrace => false },
|
43
|
+
:net_http => { :enabled => true, :backtrace => false },
|
44
|
+
:typhoeus => { :enabled => true, :backtrace => false },
|
45
|
+
:faraday => { :enabled => true, :backtrace => false }
|
46
|
+
}
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def default_if_blank(value, default)
|
53
|
+
value.nil? || value.blank? ? default : value
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
module AppPerfRpm
|
4
|
+
class Dispatcher
|
5
|
+
def initialize
|
6
|
+
@start_time = Time.now
|
7
|
+
@queue = Queue.new
|
8
|
+
@aggregator = Aggregator.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def add_event(event)
|
12
|
+
@queue << event
|
13
|
+
end
|
14
|
+
|
15
|
+
def configuration
|
16
|
+
::AppPerfRpm.configuration
|
17
|
+
end
|
18
|
+
|
19
|
+
def ready?
|
20
|
+
Time.now > @start_time + configuration.dispatch_interval.to_f &&
|
21
|
+
@queue.size.to_i > 0
|
22
|
+
end
|
23
|
+
|
24
|
+
def reset
|
25
|
+
@queue.clear
|
26
|
+
@start_time = Time.now
|
27
|
+
end
|
28
|
+
|
29
|
+
def dispatch
|
30
|
+
begin
|
31
|
+
spans = drain(@queue)
|
32
|
+
metrics = []#@aggregator.aggregate(spans)
|
33
|
+
|
34
|
+
dispatch_events(spans.map(&:to_a) + metrics)
|
35
|
+
rescue => ex
|
36
|
+
::AppPerfRpm.logger.error "#{ex.inspect}"
|
37
|
+
::AppPerfRpm.logger.error "#{ex.backtrace.inspect}"
|
38
|
+
ensure
|
39
|
+
reset
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def dispatch_events(data)
|
46
|
+
if data && data.length > 0
|
47
|
+
uri = URI(url)
|
48
|
+
|
49
|
+
sock = Net::HTTP.new(uri.host, uri.port)
|
50
|
+
sock.use_ssl = configuration.ssl
|
51
|
+
|
52
|
+
req = Net::HTTP::Post.new(uri.path, { "Content-Type" => "application/json", "Accept-Encoding" => "gzip", "User-Agent" => "gzip" })
|
53
|
+
req.body = compress_body(data)
|
54
|
+
req.content_type = "application/octet-stream"
|
55
|
+
|
56
|
+
res = sock.start do |http|
|
57
|
+
http.read_timeout = 30
|
58
|
+
http.request(req)
|
59
|
+
end
|
60
|
+
data.clear
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def compress_body(data)
|
65
|
+
body = Oj.dump({
|
66
|
+
"name" => configuration.application_name,
|
67
|
+
"host" => AppPerfRpm.host,
|
68
|
+
"data" => data
|
69
|
+
})
|
70
|
+
|
71
|
+
compressed_body = Zlib::Deflate.deflate(body, Zlib::DEFAULT_COMPRESSION)
|
72
|
+
Base64.encode64(compressed_body)
|
73
|
+
end
|
74
|
+
|
75
|
+
def drain(queue)
|
76
|
+
Array.new(queue.size) { queue.pop }
|
77
|
+
end
|
78
|
+
|
79
|
+
def url
|
80
|
+
host = configuration.host
|
81
|
+
license_key = configuration.license_key
|
82
|
+
@url ||= "#{host}/api/listener/2/#{license_key}"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module AppPerfRpm
|
2
|
+
class Instrumentation
|
3
|
+
class << self
|
4
|
+
def load
|
5
|
+
pattern = File.join(File.dirname(__FILE__), 'instruments', '**', '*.rb')
|
6
|
+
Dir.glob(pattern) do |f|
|
7
|
+
begin
|
8
|
+
require f
|
9
|
+
rescue => e
|
10
|
+
AppPerfRpm.logger.error "Error loading instrumentation file '#{f}' : #{e}"
|
11
|
+
AppPerfRpm.logger.error "#{e.backtrace[0..10]}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
if defined? Rails::Railtie
|
16
|
+
require "app_perf_rpm/railtie"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module AppPerfRpm
|
2
|
+
module Instruments
|
3
|
+
module ActionController
|
4
|
+
def process_action_with_trace(method_name, *args)
|
5
|
+
if ::AppPerfRpm::Tracer.tracing?
|
6
|
+
AppPerfRpm::Tracer.trace('actioncontroller') do |span|
|
7
|
+
span.controller = self.class.name
|
8
|
+
span.action = self.action_name
|
9
|
+
|
10
|
+
process_action_without_trace(method_name, *args)
|
11
|
+
end
|
12
|
+
else
|
13
|
+
process_action_without_trace(method_name, *args)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def perform_action_with_trace(*arguments)
|
18
|
+
if ::AppPerfRpm::Tracer.tracing?
|
19
|
+
AppPerfRpm::Tracer.trace('actioncontroller') do |span|
|
20
|
+
span.controller = @_request.path_parameters['controller']
|
21
|
+
span.action = @_request.path_parameters['action']
|
22
|
+
|
23
|
+
perform_action_without_trace(*arguments)
|
24
|
+
end
|
25
|
+
else
|
26
|
+
perform_action_without_trace(*arguments)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
if ::AppPerfRpm.configuration.instrumentation[:action_controller][:enabled] &&
|
34
|
+
defined?(::ActionController)
|
35
|
+
AppPerfRpm.logger.info "Initializing actioncontroller tracer."
|
36
|
+
|
37
|
+
::ActionController::Base.send(
|
38
|
+
:include,
|
39
|
+
AppPerfRpm::Instruments::ActionController
|
40
|
+
)
|
41
|
+
|
42
|
+
::ActionController::Base.class_eval do
|
43
|
+
if ::Rails::VERSION::MAJOR > 2
|
44
|
+
alias_method :process_action_without_trace, :process_action
|
45
|
+
alias_method :process_action, :process_action_with_trace
|
46
|
+
else
|
47
|
+
alias_method :perform_action_without_trace, :perform_action
|
48
|
+
alias_method :perform_action, :perform_action_with_trace
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
if ::AppPerfRpm.configuration.instrumentation[:action_view][:enabled] && defined?(::ActionView)
|
2
|
+
if defined?(Rails) && Rails::VERSION::MAJOR == 2
|
3
|
+
ActionView::Partials.module_eval do
|
4
|
+
alias :render_partial_without_trace :render_partial
|
5
|
+
def render_partial(options = {})
|
6
|
+
if ::AppPerfRpm::Tracer.tracing? && options.key?(:partial) && options[:partial].is_a?(String)
|
7
|
+
opts = {
|
8
|
+
"method" => "render_partial",
|
9
|
+
"name" => options[:partial]
|
10
|
+
}
|
11
|
+
|
12
|
+
opts["backtrace"] = ::AppPerfRpm::Backtrace.backtrace
|
13
|
+
opts["source"] = ::AppPerfRpm::Backtrace.source_extract
|
14
|
+
|
15
|
+
AppPerfRpm::Tracer.trace("actionview", opts) do |span|
|
16
|
+
span.controller = @_request.path_parameters['controller']
|
17
|
+
span.action = @_request.path_parameters['action']
|
18
|
+
span.backtrace = ::AppPerfRpm::Backtrace.backtrace
|
19
|
+
span.source = ::AppPerfRpm::Backtrace.source_extract
|
20
|
+
|
21
|
+
render_partial_without_trace(options)
|
22
|
+
end
|
23
|
+
else
|
24
|
+
render_partial_without_trace(options)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
alias :render_partial_collection_without_trace :render_partial_collection
|
29
|
+
def render_partial_collection(options = {})
|
30
|
+
if ::AppPerfRpm::Tracer.tracing?
|
31
|
+
AppPerfRpm::Tracer.trace("actionview") do |span|
|
32
|
+
span.backtrace = ::AppPerfRpm::Backtrace.backtrace
|
33
|
+
span.source = ::AppPerfRpm::Backtrace.source_extract
|
34
|
+
span.options = {
|
35
|
+
"method" => "render_partial_collection",
|
36
|
+
"name" => @path
|
37
|
+
}
|
38
|
+
|
39
|
+
render_partial_collection_without_trace(options)
|
40
|
+
end
|
41
|
+
else
|
42
|
+
render_partial_collection_without_trace(options)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
else
|
47
|
+
ActionView::PartialRenderer.class_eval do
|
48
|
+
alias :render_partial_without_trace :render_partial
|
49
|
+
def render_partial
|
50
|
+
if ::AppPerfRpm::Tracer.tracing?
|
51
|
+
AppPerfRpm::Tracer.trace("actionview") do |span|
|
52
|
+
span.backtrace = ::AppPerfRpm::Backtrace.backtrace
|
53
|
+
span.source = ::AppPerfRpm::Backtrace.source_extract
|
54
|
+
span.options = {
|
55
|
+
"method" => "render_partial",
|
56
|
+
"name" => @options[:partial]
|
57
|
+
}
|
58
|
+
|
59
|
+
render_partial_without_trace
|
60
|
+
end
|
61
|
+
else
|
62
|
+
render_partial_without_trace
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
alias :render_collection_without_trace :render_collection
|
67
|
+
def render_collection
|
68
|
+
if ::AppPerfRpm::Tracer.tracing?
|
69
|
+
AppPerfRpm::Tracer.trace("actionview") do |span|
|
70
|
+
span.options = {
|
71
|
+
"method" => "render_collection",
|
72
|
+
"name" => @path
|
73
|
+
}
|
74
|
+
|
75
|
+
render_collection_without_trace
|
76
|
+
end
|
77
|
+
else
|
78
|
+
render_collection_without_trace
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
::ActionView::TemplateRenderer.class_eval do
|
84
|
+
alias render_with_layout_without_trace render_with_layout
|
85
|
+
|
86
|
+
def render_with_layout(path, locals, *args, &block)
|
87
|
+
if ::AppPerfRpm::Tracer.tracing?
|
88
|
+
layout = nil
|
89
|
+
|
90
|
+
if path
|
91
|
+
if method(:find_layout).arity == 3
|
92
|
+
# Rails 5
|
93
|
+
layout = find_layout(path, locals.keys, [formats.first])
|
94
|
+
else
|
95
|
+
# Rails 3, 4
|
96
|
+
layout = find_layout(path, locals.keys)
|
97
|
+
end
|
98
|
+
|
99
|
+
@path = path
|
100
|
+
end
|
101
|
+
|
102
|
+
AppPerfRpm::Tracer.trace("actionview") do |span|
|
103
|
+
if layout
|
104
|
+
span.options = {
|
105
|
+
"method" => "render_with_layout",
|
106
|
+
"name" => layout.identifier,
|
107
|
+
"path" => @path,
|
108
|
+
"layout" => layout
|
109
|
+
}
|
110
|
+
else
|
111
|
+
span.options = {
|
112
|
+
"method" => "render_without_layout",
|
113
|
+
"path" => @path
|
114
|
+
}
|
115
|
+
end
|
116
|
+
render_with_layout_without_trace(path, locals, *args, &block)
|
117
|
+
end
|
118
|
+
else
|
119
|
+
render_with_layout_without_trace(path, locals, *args, &block)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
AppPerfRpm.logger.info "Initializing actionview tracer."
|
126
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module AppPerfRpm
|
2
|
+
module Instruments
|
3
|
+
module ActiveRecord
|
4
|
+
module Adapters
|
5
|
+
module Mysql2
|
6
|
+
include AppPerfRpm::Utils
|
7
|
+
|
8
|
+
IGNORE_STATEMENTS = {
|
9
|
+
"SCHEMA" => true,
|
10
|
+
"EXPLAIN" => true,
|
11
|
+
"CACHE" => true
|
12
|
+
}
|
13
|
+
|
14
|
+
def ignore_trace?(name)
|
15
|
+
IGNORE_STATEMENTS[name.to_s] ||
|
16
|
+
(name && name.to_sym == :skip_logging) ||
|
17
|
+
name == 'ActiveRecord::SchemaMigration Load'
|
18
|
+
end
|
19
|
+
|
20
|
+
def execute_with_trace(sql, name = nil)
|
21
|
+
if ::AppPerfRpm::Tracer.tracing?
|
22
|
+
if ignore_trace?(name)
|
23
|
+
execute_without_trace(sql, name)
|
24
|
+
else
|
25
|
+
sanitized_sql = sanitize_sql(sql, :mysql2)
|
26
|
+
|
27
|
+
AppPerfRpm::Tracer.trace('activerecord') do |span|
|
28
|
+
span.options ={
|
29
|
+
"adapter" => "mysql2",
|
30
|
+
"query" => sanitized_sql,
|
31
|
+
"name" => name
|
32
|
+
}
|
33
|
+
|
34
|
+
execute_without_trace(sql, name)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
else
|
38
|
+
execute_without_trace(sql, name)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
module AppPerfRpm
|
2
|
+
module Instruments
|
3
|
+
module ActiveRecord
|
4
|
+
module Adapters
|
5
|
+
module Postgresql
|
6
|
+
include AppPerfRpm::Utils
|
7
|
+
|
8
|
+
IGNORE_STATEMENTS = {
|
9
|
+
"SCHEMA" => true,
|
10
|
+
"EXPLAIN" => true,
|
11
|
+
"CACHE" => true
|
12
|
+
}
|
13
|
+
|
14
|
+
def ignore_trace?(name)
|
15
|
+
IGNORE_STATEMENTS[name.to_s] ||
|
16
|
+
(name && name.to_sym == :skip_logging) ||
|
17
|
+
name == 'ActiveRecord::SchemaMigration Load'
|
18
|
+
end
|
19
|
+
|
20
|
+
def exec_query_with_trace(sql, name = nil, binds = [])
|
21
|
+
if ::AppPerfRpm::Tracer.tracing?
|
22
|
+
if ignore_trace?(name)
|
23
|
+
exec_query_without_trace(sql, name, binds)
|
24
|
+
else
|
25
|
+
sanitized_sql = sanitize_sql(sql, :postgres)
|
26
|
+
|
27
|
+
AppPerfRpm::Tracer.trace('activerecord') do |span|
|
28
|
+
span.options = {
|
29
|
+
"adapter" => "postgresql",
|
30
|
+
"query" => sanitized_sql,
|
31
|
+
"name" => name
|
32
|
+
}
|
33
|
+
exec_query_without_trace(sql, name, binds)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
else
|
37
|
+
exec_query_without_trace(sql, name, binds)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def exec_delete_with_trace(sql, name = nil, binds = [])
|
42
|
+
if ::AppPerfRpm::Tracer.tracing?
|
43
|
+
if ignore_trace?(name)
|
44
|
+
exec_delete_without_trace(sql, name, binds)
|
45
|
+
else
|
46
|
+
sanitized_sql = sanitize_sql(sql)
|
47
|
+
|
48
|
+
AppPerfRpm::Tracer.trace('activerecord') do |span|
|
49
|
+
span.options = {
|
50
|
+
"adapter" => "postgresql",
|
51
|
+
"query" => sanitized_sql,
|
52
|
+
"name" => name
|
53
|
+
}
|
54
|
+
exec_delete_without_trace(sql, name, binds)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
else
|
58
|
+
exec_delete_without_trace(sql, name, binds)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def exec_insert_with_trace(sql, name = nil, binds = [], *args)
|
63
|
+
if ::AppPerfRpm::Tracer.tracing?
|
64
|
+
if ignore_trace?(name)
|
65
|
+
exec_insert_without_trace(sql, name, binds, *args)
|
66
|
+
else
|
67
|
+
sanitized_sql = sanitize_sql(sql, :postgres)
|
68
|
+
|
69
|
+
AppPerfRpm::Tracer.trace('activerecord') do |span|
|
70
|
+
span.options = {
|
71
|
+
"adapter" => "postgresql",
|
72
|
+
"query" => sanitized_sql,
|
73
|
+
"name" => name
|
74
|
+
}
|
75
|
+
|
76
|
+
exec_insert_without_trace(sql, name, binds, *args)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
else
|
80
|
+
exec_insert_without_trace(sql, name, binds, *args)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def begin_db_transaction_with_trace
|
85
|
+
if ::AppPerfRpm::Tracer.tracing?
|
86
|
+
AppPerfRpm::Tracer.trace('activerecord') do |span|
|
87
|
+
span.options = {
|
88
|
+
"adapter" => "postgresql",
|
89
|
+
"query" => "BEGIN"
|
90
|
+
}
|
91
|
+
|
92
|
+
begin_db_transaction_without_trace
|
93
|
+
end
|
94
|
+
else
|
95
|
+
begin_db_transaction_without_trace
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|