app_perf_rpm 0.0.5 → 0.0.6
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 +4 -4
- data/lib/app_perf_rpm/backtrace.rb +7 -7
- data/lib/app_perf_rpm/configuration.rb +6 -4
- data/lib/app_perf_rpm/instruments/action_controller.rb +33 -16
- data/lib/app_perf_rpm/instruments/action_view.rb +93 -65
- data/lib/app_perf_rpm/instruments/active_record/adapters/mysql2.rb +24 -15
- data/lib/app_perf_rpm/instruments/active_record/adapters/postgresql.rb +95 -52
- data/lib/app_perf_rpm/instruments/active_record/adapters/sqlite3.rb +95 -54
- data/lib/app_perf_rpm/instruments/active_record.rb +1 -1
- data/lib/app_perf_rpm/instruments/activerecord_import.rb +22 -13
- data/lib/app_perf_rpm/instruments/emque_consuming.rb +16 -7
- data/lib/app_perf_rpm/instruments/faraday.rb +26 -16
- data/lib/app_perf_rpm/instruments/net_http.rb +16 -10
- data/lib/app_perf_rpm/instruments/rack.rb +75 -25
- data/lib/app_perf_rpm/instruments/redis.rb +49 -13
- data/lib/app_perf_rpm/instruments/sequel.rb +36 -28
- data/lib/app_perf_rpm/instruments/sidekiq.rb +65 -21
- data/lib/app_perf_rpm/instruments/sinatra.rb +34 -20
- data/lib/app_perf_rpm/instruments/typhoeus.rb +40 -21
- data/lib/app_perf_rpm/rails.rb +2 -1
- data/lib/app_perf_rpm/railtie.rb +4 -4
- data/lib/app_perf_rpm/reporters/json_client.rb +69 -0
- data/lib/app_perf_rpm/reporters/null_client.rb +14 -0
- data/lib/app_perf_rpm/tracer.rb +20 -89
- data/lib/app_perf_rpm/tracing/buffer.rb +25 -0
- data/lib/app_perf_rpm/tracing/carrier.rb +23 -0
- data/lib/app_perf_rpm/tracing/collector.rb +31 -0
- data/lib/app_perf_rpm/tracing/endpoint.rb +19 -0
- data/lib/app_perf_rpm/tracing/managed_span.rb +36 -0
- data/lib/app_perf_rpm/tracing/managed_tracer.rb +32 -0
- data/lib/app_perf_rpm/tracing/span.rb +67 -0
- data/lib/app_perf_rpm/tracing/span_context.rb +41 -0
- data/lib/app_perf_rpm/tracing/thread_span_stack.rb +32 -0
- data/lib/app_perf_rpm/tracing/trace_id.rb +11 -0
- data/lib/app_perf_rpm/tracing/tracer.rb +91 -0
- data/lib/app_perf_rpm/utils.rb +18 -0
- data/lib/app_perf_rpm.rb +59 -26
- metadata +90 -12
- data/lib/app_perf_rpm/aggregator.rb +0 -77
- data/lib/app_perf_rpm/dispatcher.rb +0 -85
- data/lib/app_perf_rpm/middleware.rb +0 -30
- data/lib/app_perf_rpm/span.rb +0 -103
- data/lib/app_perf_rpm/worker.rb +0 -46
@@ -1,77 +0,0 @@
|
|
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
|
@@ -1,85 +0,0 @@
|
|
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
|
@@ -1,30 +0,0 @@
|
|
1
|
-
module AppPerfRpm
|
2
|
-
class Middleware
|
3
|
-
attr_reader :app
|
4
|
-
|
5
|
-
def initialize(app)
|
6
|
-
@app = app
|
7
|
-
end
|
8
|
-
|
9
|
-
def call(env)
|
10
|
-
begin
|
11
|
-
@status, @headers, @response = @app.call(env)
|
12
|
-
rescue Exception => e
|
13
|
-
handle_exception(env, e)
|
14
|
-
end
|
15
|
-
[@status, @headers, @response]
|
16
|
-
end
|
17
|
-
|
18
|
-
def handle_exception(env, exception)
|
19
|
-
::AppPerfRpm::Tracer.log_event("error",
|
20
|
-
"path" => env["PATH_INFO"],
|
21
|
-
"method" => env["REQUEST_METHOD"],
|
22
|
-
"message" => exception.message,
|
23
|
-
"error_class" => exception.class.to_s,
|
24
|
-
"backtrace" => ::AppPerfRpm::Backtrace.clean(exception.backtrace),
|
25
|
-
"source" => ::AppPerfRpm::Backtrace.source_extract(exception.backtrace)
|
26
|
-
)
|
27
|
-
raise exception
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
data/lib/app_perf_rpm/span.rb
DELETED
@@ -1,103 +0,0 @@
|
|
1
|
-
module AppPerfRpm
|
2
|
-
class Span
|
3
|
-
attr_accessor :layer,
|
4
|
-
:controller,
|
5
|
-
:action,
|
6
|
-
:url,
|
7
|
-
:domain,
|
8
|
-
:type,
|
9
|
-
:backtrace,
|
10
|
-
:source,
|
11
|
-
:trace_id,
|
12
|
-
:started_at,
|
13
|
-
:ended_at,
|
14
|
-
:children,
|
15
|
-
:options
|
16
|
-
|
17
|
-
def self.arrange(spans)
|
18
|
-
spans.sort! { |a, b| (a.ended_at <=> b.ended_at) }
|
19
|
-
|
20
|
-
null_span = Span.new
|
21
|
-
controller = (spans.find {|s| s.controller } || null_span).controller
|
22
|
-
action = (spans.find {|s| s.action } || null_span).action
|
23
|
-
domain = (spans.find {|s| s.domain } || null_span).domain
|
24
|
-
url = (spans.find {|s| s.url } || null_span).url
|
25
|
-
|
26
|
-
while span = spans.shift
|
27
|
-
span.controller ||= controller
|
28
|
-
span.action ||= action
|
29
|
-
span.domain ||= domain
|
30
|
-
span.url ||= url
|
31
|
-
|
32
|
-
if parent = spans.find { |n| n.parent_of?(span) }
|
33
|
-
parent.children << span
|
34
|
-
elsif spans.empty?
|
35
|
-
root = span
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
root
|
40
|
-
end
|
41
|
-
|
42
|
-
def initialize
|
43
|
-
self.children = []
|
44
|
-
self.type = "web"
|
45
|
-
self.options = {}
|
46
|
-
end
|
47
|
-
|
48
|
-
def duration
|
49
|
-
@duration ||= (ended_at - started_at) * 1000.0
|
50
|
-
end
|
51
|
-
|
52
|
-
def exclusive_duration
|
53
|
-
@exclusive_duration ||= duration - children.inject(0.0) { |sum, child| sum + child.duration }
|
54
|
-
end
|
55
|
-
|
56
|
-
def parent_of?(span)
|
57
|
-
start = (started_at - span.started_at) * 1000.0
|
58
|
-
start <= 0 && (start + duration >= span.duration)
|
59
|
-
end
|
60
|
-
|
61
|
-
def child_of?(span)
|
62
|
-
span.parent_of?(self)
|
63
|
-
end
|
64
|
-
|
65
|
-
def to_spans
|
66
|
-
span = self.dup
|
67
|
-
span.exclusive_duration
|
68
|
-
span.children = []
|
69
|
-
|
70
|
-
if children.size > 0
|
71
|
-
return [span] + children.map(&:to_spans)
|
72
|
-
else
|
73
|
-
return [span]
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
def base_options
|
78
|
-
opts = {}
|
79
|
-
opts["domain"] = domain
|
80
|
-
opts["controller"] = controller
|
81
|
-
opts["action"] = action
|
82
|
-
opts["url"] = url
|
83
|
-
opts["type"] = type
|
84
|
-
#opts["backtrace"] = ::AppPerfRpm::Backtrace.backtrace
|
85
|
-
opts["source"] = ::AppPerfRpm::Backtrace.source_extract
|
86
|
-
opts.delete_if { |k, v| v.nil? }
|
87
|
-
end
|
88
|
-
|
89
|
-
def to_s
|
90
|
-
"#{layer}:#{trace_id}:#{started_at}:#{exclusive_duration}"
|
91
|
-
end
|
92
|
-
|
93
|
-
def to_a
|
94
|
-
[
|
95
|
-
layer,
|
96
|
-
trace_id,
|
97
|
-
started_at,
|
98
|
-
duration,
|
99
|
-
base_options.merge(options)
|
100
|
-
]
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
data/lib/app_perf_rpm/worker.rb
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
module AppPerfRpm
|
2
|
-
class Worker
|
3
|
-
def initialize
|
4
|
-
AppPerfRpm.logger.info "Starting worker."
|
5
|
-
@dispatcher = Dispatcher.new
|
6
|
-
end
|
7
|
-
|
8
|
-
def save(event)
|
9
|
-
start
|
10
|
-
return if event.nil?
|
11
|
-
@dispatcher.add_event(event)
|
12
|
-
end
|
13
|
-
|
14
|
-
def start
|
15
|
-
return if worker_running?
|
16
|
-
::AppPerfRpm.mutex.synchronize do
|
17
|
-
return if worker_running?
|
18
|
-
start_dispatcher
|
19
|
-
::AppPerfRpm.logger.info "Worker is running."
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def worker_running?
|
24
|
-
@worker_thread && @worker_thread.alive?
|
25
|
-
end
|
26
|
-
|
27
|
-
def start_dispatcher
|
28
|
-
@worker_thread = Thread.new do
|
29
|
-
::AppPerfRpm.configuration.reload
|
30
|
-
@dispatcher.reset
|
31
|
-
|
32
|
-
loop do
|
33
|
-
start = Time.now
|
34
|
-
if @dispatcher.ready?
|
35
|
-
@dispatcher.dispatch
|
36
|
-
@dispatcher.reset
|
37
|
-
end
|
38
|
-
sleep_for = (start + 15 - Time.now)
|
39
|
-
sleep_for = 1 if sleep_for < 1
|
40
|
-
sleep sleep_for
|
41
|
-
end
|
42
|
-
end
|
43
|
-
@worker_thread.abort_on_exception = true
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|