rorvswild 1.7.0 → 1.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/rorvswild/agent.rb +38 -11
- data/lib/rorvswild/local/javascript/local.js +205 -35
- data/lib/rorvswild/local/local.html.erb +294 -88
- data/lib/rorvswild/local/middleware.rb +16 -0
- data/lib/rorvswild/local/queue.rb +45 -7
- data/lib/rorvswild/local/stylesheet/local.css +327 -59
- data/lib/rorvswild/local/stylesheet/vendor/prism.css +1 -1
- data/lib/rorvswild/local.rb +1 -1
- data/lib/rorvswild/plugin/action_controller.rb +1 -1
- data/lib/rorvswild/plugin/action_mailer.rb +1 -1
- data/lib/rorvswild/plugin/action_view.rb +1 -1
- data/lib/rorvswild/plugin/active_job.rb +1 -1
- data/lib/rorvswild/plugin/active_record.rb +1 -3
- data/lib/rorvswild/plugin/delayed_job.rb +10 -1
- data/lib/rorvswild/plugin/middleware.rb +36 -6
- data/lib/rorvswild/plugin/redis.rb +2 -6
- data/lib/rorvswild/queue.rb +4 -0
- data/lib/rorvswild/section.rb +62 -29
- data/lib/rorvswild/version.rb +1 -1
- data/lib/rorvswild.rb +13 -3
- metadata +2 -2
@@ -18,7 +18,7 @@ module RorVsWild
|
|
18
18
|
RorVsWild.agent.current_data[:path] = env["ORIGINAL_FULLPATH"]
|
19
19
|
section = RorVsWild::Section.start
|
20
20
|
section.file, section.line = rails_engine_location
|
21
|
-
section.
|
21
|
+
section.commands << "Rails::Engine#call"
|
22
22
|
code, headers, body = @app.call(env)
|
23
23
|
[code, headers, body]
|
24
24
|
ensure
|
@@ -26,23 +26,53 @@ module RorVsWild
|
|
26
26
|
inject_server_timing(RorVsWild.agent.stop_request, headers)
|
27
27
|
end
|
28
28
|
|
29
|
+
private
|
30
|
+
|
29
31
|
def rails_engine_location
|
30
32
|
@rails_engine_location = ::Rails::Engine.instance_method(:call).source_location
|
31
33
|
end
|
32
34
|
|
33
|
-
def
|
34
|
-
sections.
|
35
|
+
def format_server_timing_header(sections)
|
36
|
+
sections.map do |section|
|
35
37
|
if section.kind == "view"
|
36
|
-
"#{section.kind};dur=#{section.
|
38
|
+
"#{section.kind};dur=#{section.self_ms.round};desc=\"#{section.file}\""
|
37
39
|
else
|
38
|
-
"#{section.kind};dur=#{section.
|
40
|
+
"#{section.kind};dur=#{section.self_ms.round};desc=\"#{section.file}:#{section.line}\""
|
39
41
|
end
|
40
42
|
end.join(", ")
|
41
43
|
end
|
42
44
|
|
45
|
+
def format_server_timing_ascii(sections, total_width = 80)
|
46
|
+
max_time = sections.map(&:self_ms).max
|
47
|
+
chart_width = (total_width * 0.25).to_i
|
48
|
+
rows = sections.map { |section|
|
49
|
+
[
|
50
|
+
section.kind == "view" ? section.file : "#{section.file}:#{section.line}",
|
51
|
+
"█" * (section.self_ms * (chart_width-1) / max_time),
|
52
|
+
"%.1fms" % section.self_ms,
|
53
|
+
]
|
54
|
+
}
|
55
|
+
time_width = rows.map { |cols| cols[2].size }.max + 1
|
56
|
+
label_width = total_width - chart_width - time_width
|
57
|
+
rows.each { |cols| cols[0] = truncate_backwards(cols[0], label_width) }
|
58
|
+
template = "%-#{label_width}s%#{chart_width}s%#{time_width}s"
|
59
|
+
rows.map { |cols| format(template, *cols) }.join("\n")
|
60
|
+
end
|
61
|
+
|
62
|
+
def truncate_backwards(string, width)
|
63
|
+
string.size > width ? "…" + string[-(width - 1)..-1] : string
|
64
|
+
end
|
65
|
+
|
43
66
|
def inject_server_timing(data, headers)
|
44
67
|
return if !data || !data[:send_server_timing] || !(sections = data[:sections])
|
45
|
-
|
68
|
+
sections = sections.sort_by(&:self_ms).reverse[0,10]
|
69
|
+
headers["Server-Timing"] = format_server_timing_header(sections)
|
70
|
+
if data[:name] && RorVsWild.logger.level <= Logger::Severity::DEBUG
|
71
|
+
RorVsWild.logger.debug(["┤ #{data[:name]} ├".center(80, "─"),
|
72
|
+
format_server_timing_ascii(sections),
|
73
|
+
"─" * 80, nil].join("\n")
|
74
|
+
)
|
75
|
+
end
|
46
76
|
end
|
47
77
|
end
|
48
78
|
end
|
@@ -15,8 +15,7 @@ module RorVsWild
|
|
15
15
|
module V4
|
16
16
|
def process(commands, &block)
|
17
17
|
string = commands.map(&:first).join("\n")
|
18
|
-
|
19
|
-
RorVsWild.agent.measure_section(string, appendable_command: appendable, kind: "redis") do
|
18
|
+
RorVsWild.agent.measure_section(string, kind: "redis") do
|
20
19
|
super(commands, &block)
|
21
20
|
end
|
22
21
|
end
|
@@ -24,8 +23,7 @@ module RorVsWild
|
|
24
23
|
|
25
24
|
module V5
|
26
25
|
def send_command(command, &block)
|
27
|
-
|
28
|
-
RorVsWild.agent.measure_section(command[0], appendable_command: appendable, kind: "redis") do
|
26
|
+
RorVsWild.agent.measure_section(command[0], kind: "redis") do
|
29
27
|
super(command, &block)
|
30
28
|
end
|
31
29
|
end
|
@@ -38,8 +36,6 @@ module RorVsWild
|
|
38
36
|
RorVsWild.agent.measure_section("multi", kind: "redis") { super }
|
39
37
|
end
|
40
38
|
end
|
41
|
-
|
42
|
-
APPENDABLE_COMMANDS = [:auth, :select]
|
43
39
|
end
|
44
40
|
end
|
45
41
|
end
|
data/lib/rorvswild/queue.rb
CHANGED
@@ -27,6 +27,10 @@ module RorVsWild
|
|
27
27
|
push_to(requests, data) if !@request_sampling_rate || rand <= @request_sampling_rate
|
28
28
|
end
|
29
29
|
|
30
|
+
def push_error(data)
|
31
|
+
client.post_async("/errors", error: data)
|
32
|
+
end
|
33
|
+
|
30
34
|
def push_to(array, data)
|
31
35
|
mutex.synchronize do
|
32
36
|
wakeup_thread if array.push(data).size >= FLUSH_TRESHOLD || !thread
|
data/lib/rorvswild/section.rb
CHANGED
@@ -2,8 +2,8 @@
|
|
2
2
|
|
3
3
|
module RorVsWild
|
4
4
|
class Section
|
5
|
-
attr_reader :
|
6
|
-
attr_accessor :kind, :file, :line, :calls, :
|
5
|
+
attr_reader :start_ms, :commands, :gc_start_ms
|
6
|
+
attr_accessor :kind, :file, :line, :calls, :children_ms, :total_ms, :gc_time_ms
|
7
7
|
|
8
8
|
def self.start(&block)
|
9
9
|
section = Section.new
|
@@ -15,8 +15,8 @@ module RorVsWild
|
|
15
15
|
def self.stop(&block)
|
16
16
|
return unless stack && section = stack.pop
|
17
17
|
block.call(section) if block_given?
|
18
|
-
section.
|
19
|
-
current.
|
18
|
+
section.stop
|
19
|
+
current.children_ms += section.total_ms if current
|
20
20
|
RorVsWild.agent.add_section(section)
|
21
21
|
end
|
22
22
|
|
@@ -28,17 +28,52 @@ module RorVsWild
|
|
28
28
|
(sections = stack) && sections.last
|
29
29
|
end
|
30
30
|
|
31
|
+
def self.start_gc_timing
|
32
|
+
section = Section.new
|
33
|
+
section.calls = GC.count
|
34
|
+
section.file, section.line = "ruby/gc.c", 42
|
35
|
+
section.add_command("GC.start")
|
36
|
+
section.kind = "gc"
|
37
|
+
section
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.stop_gc_timing(section)
|
41
|
+
section.total_ms = gc_total_ms - section.gc_start_ms
|
42
|
+
section.calls = GC.count - section.calls
|
43
|
+
section
|
44
|
+
end
|
45
|
+
|
46
|
+
if GC.respond_to?(:total_time)
|
47
|
+
def self.gc_total_ms
|
48
|
+
GC.total_time / 1_000_000.0 # nanosecond -> millisecond
|
49
|
+
end
|
50
|
+
else
|
51
|
+
def self.gc_total_ms
|
52
|
+
GC::Profiler.total_time * 1000 # second -> millisecond
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
31
56
|
def initialize
|
57
|
+
@start_ms = RorVsWild.clock_milliseconds
|
58
|
+
@end_ms = nil
|
59
|
+
@gc_start_ms = Section.gc_total_ms
|
60
|
+
@gc_end_ms = nil
|
61
|
+
@gc_time_ms = 0
|
32
62
|
@calls = 1
|
33
|
-
@
|
34
|
-
@
|
63
|
+
@total_ms = 0
|
64
|
+
@children_ms = 0
|
35
65
|
@kind = "code"
|
36
|
-
@started_at = RorVsWild.clock_milliseconds
|
37
66
|
location = RorVsWild.agent.locator.find_most_relevant_location(caller_locations)
|
38
67
|
@file = RorVsWild.agent.locator.relative_path(location.path)
|
39
68
|
@line = location.lineno
|
40
|
-
@
|
41
|
-
|
69
|
+
@commands = Set.new
|
70
|
+
end
|
71
|
+
|
72
|
+
def stop
|
73
|
+
@gc_end_ms = self.class.gc_total_ms
|
74
|
+
@gc_time_ms = @gc_end_ms - @gc_start_ms
|
75
|
+
@end_ms = RorVsWild.clock_milliseconds
|
76
|
+
@total_ms = @end_ms - @start_ms - gc_time_ms
|
42
77
|
end
|
43
78
|
|
44
79
|
def sibling?(section)
|
@@ -47,35 +82,33 @@ module RorVsWild
|
|
47
82
|
|
48
83
|
def merge(section)
|
49
84
|
self.calls += section.calls
|
50
|
-
self.
|
51
|
-
self.
|
52
|
-
|
53
|
-
|
54
|
-
self.command = self.command.dup if self.command.frozen?
|
55
|
-
self.command << "\n" + section.command
|
56
|
-
end
|
57
|
-
else
|
58
|
-
self.command = section.command
|
59
|
-
end
|
60
|
-
self.appendable_command = appendable_command && section.appendable_command
|
85
|
+
self.total_ms += section.total_ms
|
86
|
+
self.children_ms += section.children_ms
|
87
|
+
self.gc_time_ms += section.gc_time_ms
|
88
|
+
commands.merge(section.commands)
|
61
89
|
end
|
62
90
|
|
63
|
-
def
|
64
|
-
|
91
|
+
def self_ms
|
92
|
+
total_ms - children_ms
|
65
93
|
end
|
66
94
|
|
67
|
-
|
95
|
+
def as_json(options = nil)
|
96
|
+
{calls: calls, total_runtime: total_ms, children_runtime: children_ms, kind: kind, started_at: start_ms, file: file, line: line, command: command}
|
97
|
+
end
|
68
98
|
|
69
|
-
def
|
70
|
-
|
99
|
+
def to_json(options = {})
|
100
|
+
as_json.to_json(options)
|
71
101
|
end
|
72
102
|
|
73
|
-
def
|
74
|
-
|
103
|
+
def add_command(command)
|
104
|
+
commands << command
|
75
105
|
end
|
76
106
|
|
77
|
-
|
78
|
-
|
107
|
+
COMMAND_MAX_SIZE = 5_000
|
108
|
+
|
109
|
+
def command
|
110
|
+
string = @commands.join("\n")
|
111
|
+
string.size > COMMAND_MAX_SIZE ? string[0, COMMAND_MAX_SIZE] + " [TRUNCATED]" : string
|
79
112
|
end
|
80
113
|
end
|
81
114
|
end
|
data/lib/rorvswild/version.rb
CHANGED
data/lib/rorvswild.rb
CHANGED
@@ -26,8 +26,14 @@ module RorVsWild
|
|
26
26
|
@logger ||= initialize_logger
|
27
27
|
end
|
28
28
|
|
29
|
-
def self.measure(
|
30
|
-
|
29
|
+
def self.measure(method_or_code = nil, &block)
|
30
|
+
if block
|
31
|
+
measure_block(method_or_code, &block)
|
32
|
+
elsif method_or_code.is_a?(Method) || method_or_code.is_a?(UnboundMethod)
|
33
|
+
measure_method(method_or_code)
|
34
|
+
else
|
35
|
+
measure_code(method_or_code)
|
36
|
+
end
|
31
37
|
end
|
32
38
|
|
33
39
|
def self.measure_code(code)
|
@@ -38,6 +44,10 @@ module RorVsWild
|
|
38
44
|
agent ? agent.measure_block(name , &block) : block.call
|
39
45
|
end
|
40
46
|
|
47
|
+
def self.measure_method(method)
|
48
|
+
agent.measure_method(method) if agent
|
49
|
+
end
|
50
|
+
|
41
51
|
def self.catch_error(context = nil, &block)
|
42
52
|
agent ? agent.catch_error(context, &block) : block.call
|
43
53
|
end
|
@@ -67,7 +77,7 @@ module RorVsWild
|
|
67
77
|
end
|
68
78
|
|
69
79
|
def self.clock_milliseconds
|
70
|
-
Process.clock_gettime(Process::CLOCK_MONOTONIC, :
|
80
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
|
71
81
|
end
|
72
82
|
|
73
83
|
def self.check
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rorvswild
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexis Bernard
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2024-
|
12
|
+
date: 2024-06-14 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: Performances and errors insights for rails developers.
|
15
15
|
email:
|