rorvswild 1.8.1 → 1.9.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 +4 -4
- data/lib/rorvswild/deployment.rb +1 -1
- data/lib/rorvswild/host.rb +1 -1
- data/lib/rorvswild/local/javascript/local.js +4 -3
- data/lib/rorvswild/local/local.html.erb +6 -0
- data/lib/rorvswild/plugin/action_view.rb +8 -4
- data/lib/rorvswild/plugin/active_record.rb +12 -0
- data/lib/rorvswild/plugin/middleware.rb +65 -1
- data/lib/rorvswild/section.rb +4 -3
- data/lib/rorvswild/version.rb +1 -1
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e4752356e6d6e1b7b9883b55c5f9f29223dedd2c31cc4abdac85065215b1b05b
|
4
|
+
data.tar.gz: 254eaff9c5412c5d1e121644d0993f0a8557748ac25370a9266ce1e61fe9f031
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b4b7acb9cc0fe303310648985dda337a3ab11c941af8c0e4d06199404064eee3c9a5cd93993f94e701fbc121f7f633123395fd89e5ddd3e28b52cd9cfa2e65e5
|
7
|
+
data.tar.gz: 404254bcfd4f9bb5c165da7955d712f1435514c061f70b019c84fbc1973626b71935a87ee8b1eae9b9b2741d79e74d2cfaef8378472f65b2a22ca78e03a99590
|
data/lib/rorvswild/agent.rb
CHANGED
@@ -114,8 +114,8 @@ module RorVsWild
|
|
114
114
|
end
|
115
115
|
end
|
116
116
|
|
117
|
-
def start_request
|
118
|
-
current_data || initialize_data
|
117
|
+
def start_request(queue_time_ms = 0)
|
118
|
+
current_data || initialize_data(queue_time_ms)
|
119
119
|
end
|
120
120
|
|
121
121
|
def stop_request
|
@@ -195,9 +195,9 @@ module RorVsWild
|
|
195
195
|
|
196
196
|
private
|
197
197
|
|
198
|
-
def initialize_data
|
198
|
+
def initialize_data(queue_time_ms = 0)
|
199
199
|
Thread.current[:rorvswild_data] = {
|
200
|
-
started_at: RorVsWild.clock_milliseconds,
|
200
|
+
started_at: RorVsWild.clock_milliseconds - queue_time_ms,
|
201
201
|
gc_section: Section.start_gc_timing,
|
202
202
|
environment: Host.to_h,
|
203
203
|
section_stack: [],
|
data/lib/rorvswild/deployment.rb
CHANGED
data/lib/rorvswild/host.rb
CHANGED
@@ -189,11 +189,12 @@ RorVsWild.Local.Request.prototype.runtime = function() {
|
|
189
189
|
RorVsWild.Local.Request.prototype.sections = function() {
|
190
190
|
return this.data.sections.map(function(section) {
|
191
191
|
var runtime = (section.total_runtime - section.children_runtime)
|
192
|
-
|
192
|
+
return {
|
193
193
|
id: RorVsWild.Local.nextId(),
|
194
194
|
impact: RorVsWild.Local.formatImpact(runtime * 100 / this.data.runtime),
|
195
195
|
language: RorVsWild.Local.kindToLanguage(section.kind),
|
196
196
|
totalRuntime: RorVsWild.Local.relevantRounding(section.total_runtime),
|
197
|
+
asyncRuntime: RorVsWild.Local.relevantRounding(section.async_runtime),
|
197
198
|
childrenRuntime: RorVsWild.Local.relevantRounding(section.children_runtime),
|
198
199
|
selfRuntime: RorVsWild.Local.relevantRounding(runtime),
|
199
200
|
runtime: RorVsWild.Local.relevantRounding(runtime),
|
@@ -204,9 +205,9 @@ RorVsWild.Local.Request.prototype.sections = function() {
|
|
204
205
|
file: section.file,
|
205
206
|
line: section.line,
|
206
207
|
location: section.kind == "view" ? section.file : section.file + ":" + section.line,
|
207
|
-
locationUrl: RorVsWild.Local.pathToUrl(this.data.environment.cwd, section.file, section.line)
|
208
|
+
locationUrl: RorVsWild.Local.pathToUrl(this.data.environment.cwd, section.file, section.line),
|
209
|
+
isAsync: RorVsWild.Local.relevantRounding(section.async_runtime) > 0,
|
208
210
|
}
|
209
|
-
return object
|
210
211
|
}.bind(this)).sort(function(a, b) { return b.selfRuntime - a.selfRuntime })
|
211
212
|
}
|
212
213
|
|
@@ -179,6 +179,12 @@
|
|
179
179
|
|
180
180
|
<div class="rorvswild-local-panel__details__section__code">
|
181
181
|
<dl>
|
182
|
+
{{#isAsync}}
|
183
|
+
<div>
|
184
|
+
<dt title="Time spent as non blocking IO">Async runtime</dt>
|
185
|
+
<dd>{{asyncRuntime}}<small>ms</small></dd>
|
186
|
+
</div>
|
187
|
+
{{/isAsync}}
|
182
188
|
<div>
|
183
189
|
<dt title="self + children">Total runtime</dt>
|
184
190
|
<dd title="{{selfRuntime}} + {{childrenRuntime}}">{{totalRuntime}}<small>ms</small></dd>
|
@@ -1,11 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module RorVsWild
|
2
4
|
module Plugin
|
3
5
|
class ActionView
|
4
6
|
def self.setup
|
5
7
|
return if @installed
|
6
8
|
return unless defined?(::ActiveSupport::Notifications.subscribe)
|
7
|
-
ActiveSupport::Notifications.subscribe("render_partial.action_view", new)
|
8
|
-
ActiveSupport::Notifications.subscribe("render_template.action_view",
|
9
|
+
ActiveSupport::Notifications.subscribe("render_partial.action_view", plugin = new)
|
10
|
+
ActiveSupport::Notifications.subscribe("render_template.action_view", plugin)
|
11
|
+
ActiveSupport::Notifications.subscribe("render_collection.action_view", plugin)
|
9
12
|
@installed = true
|
10
13
|
end
|
11
14
|
|
@@ -15,10 +18,11 @@ module RorVsWild
|
|
15
18
|
|
16
19
|
def finish(name, id, payload)
|
17
20
|
RorVsWild::Section.stop do |section|
|
18
|
-
section.kind = "view"
|
21
|
+
section.kind = "view"
|
19
22
|
section.commands << RorVsWild.agent.locator.relative_path(payload[:identifier])
|
20
23
|
section.file = section.command
|
21
|
-
section.line =
|
24
|
+
section.line = 0
|
25
|
+
section.calls = payload[:count] if payload[:count] # render collection
|
22
26
|
end
|
23
27
|
end
|
24
28
|
end
|
@@ -29,6 +29,18 @@ module RorVsWild
|
|
29
29
|
RorVsWild::Section.stop
|
30
30
|
end
|
31
31
|
|
32
|
+
# Async queries
|
33
|
+
def publish_event(event)
|
34
|
+
section = Section.new
|
35
|
+
section.total_ms = event.payload[:lock_wait]
|
36
|
+
section.async_ms = event.duration - event.payload[:lock_wait]
|
37
|
+
section.gc_time_ms = event.respond_to?(:gc_time) ? event.gc_time : 0 # gc_time since Rails 7.2.0
|
38
|
+
section.commands << normalize_sql_query(event.payload[:sql])
|
39
|
+
section.kind = "sql"
|
40
|
+
(parent = Section.current) && parent.children_ms += section.total_ms
|
41
|
+
RorVsWild.agent.add_section(section)
|
42
|
+
end
|
43
|
+
|
32
44
|
SQL_STRING_REGEX = /'((?:''|\\'|[^'])*)'/
|
33
45
|
SQL_NUMERIC_REGEX = /(?<!\w)\d+(\.\d+)?(?!\w)/
|
34
46
|
SQL_PARAMETER_REGEX = /\$\d+/
|
@@ -3,6 +3,49 @@
|
|
3
3
|
module RorVsWild
|
4
4
|
module Plugin
|
5
5
|
class Middleware
|
6
|
+
module RequestQueueTime
|
7
|
+
|
8
|
+
ACCEPTABLE_HEADERS = [
|
9
|
+
'HTTP_X_REQUEST_START',
|
10
|
+
'HTTP_X_QUEUE_START',
|
11
|
+
'HTTP_X_MIDDLEWARE_START'
|
12
|
+
].freeze
|
13
|
+
|
14
|
+
MINIMUM_TIMESTAMP = 1577836800.freeze # 2020/01/01 UTC
|
15
|
+
DIVISORS = [1_000_000, 1_000, 1].freeze
|
16
|
+
|
17
|
+
def parse_queue_time_header(env)
|
18
|
+
return unless env
|
19
|
+
|
20
|
+
earliest = nil
|
21
|
+
|
22
|
+
ACCEPTABLE_HEADERS.each do |header|
|
23
|
+
if (header_value = env[header])
|
24
|
+
timestamp = parse_timestamp(header_value.delete_prefix("t="))
|
25
|
+
if timestamp && (!earliest || timestamp < earliest)
|
26
|
+
earliest = timestamp
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
[earliest, Time.now.to_f].min if earliest
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def parse_timestamp(timestamp)
|
37
|
+
timestamp = timestamp.to_f
|
38
|
+
return unless timestamp.finite?
|
39
|
+
|
40
|
+
DIVISORS.each do |divisor|
|
41
|
+
t = timestamp / divisor
|
42
|
+
return t if t > MINIMUM_TIMESTAMP
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
include RequestQueueTime
|
48
|
+
|
6
49
|
def self.setup
|
7
50
|
return if @installed
|
8
51
|
Rails.application.config.middleware.unshift(RorVsWild::Plugin::Middleware, nil) if defined?(Rails)
|
@@ -14,8 +57,10 @@ module RorVsWild
|
|
14
57
|
end
|
15
58
|
|
16
59
|
def call(env)
|
17
|
-
|
60
|
+
queue_time_ms = calculate_queue_time(env)
|
61
|
+
RorVsWild.agent.start_request(queue_time_ms || 0)
|
18
62
|
RorVsWild.agent.current_data[:path] = env["ORIGINAL_FULLPATH"]
|
63
|
+
add_queue_time_section(queue_time_ms)
|
19
64
|
section = RorVsWild::Section.start
|
20
65
|
section.file, section.line = rails_engine_location
|
21
66
|
section.commands << "Rails::Engine#call"
|
@@ -28,6 +73,25 @@ module RorVsWild
|
|
28
73
|
|
29
74
|
private
|
30
75
|
|
76
|
+
def add_queue_time_section(queue_time_ms)
|
77
|
+
return unless queue_time_ms
|
78
|
+
|
79
|
+
section = Section.new
|
80
|
+
section.stop
|
81
|
+
section.total_ms = queue_time_ms
|
82
|
+
section.gc_time_ms = 0
|
83
|
+
section.file = "request-queue"
|
84
|
+
section.line = 0
|
85
|
+
section.kind = "queue"
|
86
|
+
RorVsWild.agent.add_section(section)
|
87
|
+
end
|
88
|
+
|
89
|
+
def calculate_queue_time(env)
|
90
|
+
queue_time_from_header = parse_queue_time_header(env)
|
91
|
+
|
92
|
+
((Time.now.to_f - queue_time_from_header) * 1000).round if queue_time_from_header
|
93
|
+
end
|
94
|
+
|
31
95
|
def rails_engine_location
|
32
96
|
@rails_engine_location = ::Rails::Engine.instance_method(:call).source_location
|
33
97
|
end
|
data/lib/rorvswild/section.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
module RorVsWild
|
4
4
|
class Section
|
5
5
|
attr_reader :start_ms, :commands, :gc_start_ms
|
6
|
-
attr_accessor :kind, :file, :line, :calls, :children_ms, :total_ms, :gc_time_ms
|
6
|
+
attr_accessor :kind, :file, :line, :calls, :children_ms, :total_ms, :gc_time_ms, :async_ms
|
7
7
|
|
8
8
|
def self.start(&block)
|
9
9
|
section = Section.new
|
@@ -31,7 +31,7 @@ module RorVsWild
|
|
31
31
|
def self.start_gc_timing
|
32
32
|
section = Section.new
|
33
33
|
section.calls = GC.count
|
34
|
-
section.file, section.line = "ruby/gc.c",
|
34
|
+
section.file, section.line = "ruby/gc.c", 0
|
35
35
|
section.add_command("GC.start")
|
36
36
|
section.kind = "gc"
|
37
37
|
section
|
@@ -62,6 +62,7 @@ module RorVsWild
|
|
62
62
|
@calls = 1
|
63
63
|
@total_ms = 0
|
64
64
|
@children_ms = 0
|
65
|
+
@async_ms = 0
|
65
66
|
@kind = "code"
|
66
67
|
location = RorVsWild.agent.locator.find_most_relevant_location(caller_locations)
|
67
68
|
@file = RorVsWild.agent.locator.relative_path(location.path)
|
@@ -93,7 +94,7 @@ module RorVsWild
|
|
93
94
|
end
|
94
95
|
|
95
96
|
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
|
+
{calls: calls, total_runtime: total_ms, children_runtime: children_ms, async_runtime: async_ms, kind: kind, started_at: start_ms, file: file, line: line, command: command}
|
97
98
|
end
|
98
99
|
|
99
100
|
def to_json(options = {})
|
data/lib/rorvswild/version.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rorvswild
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexis Bernard
|
8
8
|
- Antoine Marguerie
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2025-01-30 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: Performances and errors insights for rails developers.
|
15
15
|
email:
|
@@ -71,7 +71,7 @@ licenses:
|
|
71
71
|
metadata:
|
72
72
|
source_code_uri: https://github.com/BaseSecrete/rorvswild
|
73
73
|
changelog_uri: https://github.com/BaseSecrete/rorvswild/blob/master/CHANGELOG.md
|
74
|
-
post_install_message:
|
74
|
+
post_install_message:
|
75
75
|
rdoc_options: []
|
76
76
|
require_paths:
|
77
77
|
- lib
|
@@ -86,8 +86,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
86
86
|
- !ruby/object:Gem::Version
|
87
87
|
version: '0'
|
88
88
|
requirements: []
|
89
|
-
rubygems_version: 3.5.
|
90
|
-
signing_key:
|
89
|
+
rubygems_version: 3.5.22
|
90
|
+
signing_key:
|
91
91
|
specification_version: 4
|
92
92
|
summary: Ruby on Rails applications monitoring
|
93
93
|
test_files: []
|