rorvswild 1.7.0 → 1.8.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 +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:
|