rorvswild 1.10.1 → 1.11.1
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/README.md +14 -15
- data/lib/rorvswild/agent.rb +0 -2
- data/lib/rorvswild/client.rb +3 -1
- data/lib/rorvswild/execution.rb +13 -34
- data/lib/rorvswild/installer.rb +45 -30
- data/lib/rorvswild/local/javascript/local.js +20 -1
- data/lib/rorvswild/local/local.html.erb +21 -16
- data/lib/rorvswild/local/middleware.rb +7 -1
- data/lib/rorvswild/local/queue.rb +1 -1
- data/lib/rorvswild/local/stylesheet/local.css +39 -8
- data/lib/rorvswild/local.rb +1 -1
- data/lib/rorvswild/plugin/active_record.rb +5 -0
- data/lib/rorvswild/plugin/rack.rb +41 -0
- data/lib/rorvswild/plugin/{middleware.rb → rails_engine.rb} +7 -17
- data/lib/rorvswild/section.rb +41 -15
- data/lib/rorvswild/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 78dcaca37ba08f20d8b6fa091902f46973d48db05feabce1ab4600bd4afb48c3
|
|
4
|
+
data.tar.gz: 626507452a31fe1e63fab2826d239c4d13f03c36e8bda1690deb1ba766733bc6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 89a838d0e59c7a552ef0b961efe32420e9f271dbff74ca9427be809dc07b8a5b6158be53c10aac5bb3c69cfb6d1682e034b5b3d5f01898814e68f2443b3ffa6e
|
|
7
|
+
data.tar.gz: 35e531b0cfe704c0641ac075713893a46a55aefd453cc6fea5a34f2f3b814639096834bb8e9a9adfb11d2041693282da525a2e2b47c3d8c830e9003050e43bdd
|
data/README.md
CHANGED
|
@@ -1,26 +1,25 @@
|
|
|
1
1
|
|
|
2
|
-
#
|
|
2
|
+
# RoRvsWild
|
|
3
3
|
|
|
4
4
|
[](https://badge.fury.io/rb/rorvswild)
|
|
5
|
-
[](https://codeclimate.com/github/BaseSecrete/rorvswild/maintainability)
|
|
6
5
|
|
|
7
|
-
<img align="right" width="120px" src="./images/rorvswild_logo.
|
|
6
|
+
<img align="right" width="120px" src="./images/rorvswild_logo.png">
|
|
8
7
|
|
|
9
|
-
*RoRvsWild* is a
|
|
8
|
+
*RoRvsWild* is a Ruby gem to monitor performances and exceptions in Ruby on Rails applications.
|
|
10
9
|
|
|
11
|
-
This gem has a double mode
|
|
12
|
-
It can be used without an account to monitor your requests
|
|
13
|
-
It can also be used in your production and staging environments with an account on https://rorvswild.com. With such an account you also get
|
|
10
|
+
This gem has a double mode: **development** and **production**.
|
|
11
|
+
It can be used without an account to monitor the performance of your requests in your development environment.
|
|
12
|
+
It can also be used in your production and staging environments with an account on https://rorvswild.com. With such an account, you also get additional benefits, including 30-day trace, background job monitoring, exception monitoring, and notifications.
|
|
14
13
|
|
|
15
14
|
## Development mode
|
|
16
15
|
|
|
17
16
|
### Install the gem
|
|
18
17
|
|
|
19
18
|
* Add in your Gemfile `gem "rorvswild"`
|
|
20
|
-
* Run `bundle install` in
|
|
21
|
-
* Restart your local server and you’ll see a small button in the bottom left corner of your page.
|
|
19
|
+
* Run `bundle install` in your terminal.
|
|
20
|
+
* Restart your local server, and you’ll see a small button in the bottom left corner of your page.
|
|
22
21
|
|
|
23
|
-
<img width="
|
|
22
|
+
<img width="218px" src="./images/rorvswild_local_button.png" alt="RoRvsWild Local button">
|
|
24
23
|
|
|
25
24
|
Click on the button, or navigate to http://localhost:3000/rorvswild to see the details panel:
|
|
26
25
|
|
|
@@ -29,13 +28,13 @@ Click on the button, or navigate to http://localhost:3000/rorvswild to see the d
|
|
|
29
28
|
## Production mode
|
|
30
29
|
|
|
31
30
|
**To monitor your production or staging environment, you need an API key.**
|
|
32
|
-
|
|
31
|
+
Sign up on https://www.rorvswild.com and create an app to get one.
|
|
33
32
|
|
|
34
33
|
* Add in your Gemfile `gem "rorvswild"`
|
|
35
|
-
* Run `bundle install` in
|
|
36
|
-
* Run `rorvswild-install API_KEY` in
|
|
37
|
-
* Deploy/Restart your app
|
|
38
|
-
* Make a few requests and refresh your app page on rorvswild.com to view the dashboard.
|
|
34
|
+
* Run `bundle install` in your terminal.
|
|
35
|
+
* Run `rorvswild-install API_KEY` in your terminal.
|
|
36
|
+
* Deploy/Restart your app.
|
|
37
|
+
* Make a few requests, and refresh your app page on rorvswild.com to view the dashboard.
|
|
39
38
|
|
|
40
39
|

|
|
41
40
|
|
data/lib/rorvswild/agent.rb
CHANGED
|
@@ -113,12 +113,10 @@ module RorVsWild
|
|
|
113
113
|
|
|
114
114
|
def start_execution(execution)
|
|
115
115
|
Thread.current[:rorvswild_execution] ||= execution
|
|
116
|
-
RorVsWild::Section.start
|
|
117
116
|
end
|
|
118
117
|
|
|
119
118
|
def stop_execution
|
|
120
119
|
return unless execution = current_execution
|
|
121
|
-
RorVsWild::Section.stop
|
|
122
120
|
execution.stop
|
|
123
121
|
case execution
|
|
124
122
|
when Execution::Job then queue_job
|
data/lib/rorvswild/client.rb
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require "set"
|
|
4
4
|
require "uri"
|
|
5
|
+
require "zlib"
|
|
5
6
|
require "json/ext"
|
|
6
7
|
require "net/http"
|
|
7
8
|
|
|
@@ -24,6 +25,7 @@ module RorVsWild
|
|
|
24
25
|
@mutex = Mutex.new
|
|
25
26
|
@config = config
|
|
26
27
|
@headers = {
|
|
28
|
+
"Content-Encoding" => "deflate",
|
|
27
29
|
"Content-Type" => "application/json",
|
|
28
30
|
"X-RorVsWild-Version" => RorVsWild::VERSION,
|
|
29
31
|
"X-Ruby-Version" => RUBY_VERSION,
|
|
@@ -36,7 +38,7 @@ module RorVsWild
|
|
|
36
38
|
uri = URI(api_url + path)
|
|
37
39
|
post = Net::HTTP::Post.new(uri.path, @headers)
|
|
38
40
|
post.basic_auth(nil, api_key)
|
|
39
|
-
post.body = JSON.generate(data)
|
|
41
|
+
post.body = Zlib.deflate(JSON.generate(data), Zlib::BEST_SPEED)
|
|
40
42
|
transmit(post)
|
|
41
43
|
end
|
|
42
44
|
|
data/lib/rorvswild/execution.rb
CHANGED
|
@@ -2,21 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
module RorVsWild
|
|
4
4
|
class Execution
|
|
5
|
-
attr_reader :parameters, :sections, :section_stack, :error_context, :runtime
|
|
5
|
+
attr_reader :parameters, :sections, :section_stack, :error_context, :runtime, :root_section, :queue_section
|
|
6
6
|
|
|
7
7
|
attr_accessor :error, :name
|
|
8
8
|
|
|
9
9
|
def initialize(name, parameters)
|
|
10
|
+
@root_section = Section::Root.new
|
|
11
|
+
|
|
10
12
|
@name = name
|
|
11
13
|
@parameters = parameters
|
|
12
14
|
@runtime = nil
|
|
13
15
|
@error = nil
|
|
14
16
|
@error_context = nil
|
|
15
17
|
|
|
16
|
-
@started_at = RorVsWild.clock_milliseconds
|
|
17
|
-
@gc_section = Section.start_gc_timing
|
|
18
18
|
@environment = Host.to_h
|
|
19
|
-
@section_stack = []
|
|
19
|
+
@section_stack = [@root_section]
|
|
20
20
|
@sections = []
|
|
21
21
|
end
|
|
22
22
|
|
|
@@ -30,20 +30,18 @@ module RorVsWild
|
|
|
30
30
|
|
|
31
31
|
def add_queue_time(queue_time_ms)
|
|
32
32
|
return unless queue_time_ms
|
|
33
|
-
@
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
section.gc_time_ms = 0
|
|
37
|
-
section.file = "queue"
|
|
38
|
-
section.line = 0
|
|
39
|
-
section.kind = "queue"
|
|
40
|
-
add_section(section)
|
|
33
|
+
@queue_section = Section::Queue.new(queue_time_ms)
|
|
34
|
+
add_section(@queue_section)
|
|
35
|
+
@queue_section
|
|
41
36
|
end
|
|
42
37
|
|
|
43
38
|
def stop
|
|
44
|
-
Section.
|
|
45
|
-
|
|
46
|
-
|
|
39
|
+
Section.stop # root section
|
|
40
|
+
if @root_section.gc_time_ms > 0
|
|
41
|
+
add_section(Section::GarbageCollection.new(@root_section.gc_time_ms, @root_section.gc_calls))
|
|
42
|
+
end
|
|
43
|
+
@runtime = @root_section.total_ms + @root_section.gc_time_ms
|
|
44
|
+
@runtime += @queue_section.total_ms if @queue_section
|
|
47
45
|
end
|
|
48
46
|
|
|
49
47
|
def as_json(options = nil)
|
|
@@ -66,25 +64,6 @@ module RorVsWild
|
|
|
66
64
|
|
|
67
65
|
private
|
|
68
66
|
|
|
69
|
-
def start_gc_timing
|
|
70
|
-
section = Section.new
|
|
71
|
-
section.calls = GC.count
|
|
72
|
-
section.file, section.line = "ruby/gc.c", 0
|
|
73
|
-
section.add_command("GC.start")
|
|
74
|
-
section.kind = "gc"
|
|
75
|
-
section
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
if GC.respond_to?(:total_time)
|
|
79
|
-
def gc_total_ms
|
|
80
|
-
GC.total_time / 1_000_000.0 # nanosecond -> millisecond
|
|
81
|
-
end
|
|
82
|
-
else
|
|
83
|
-
def gc_total_ms
|
|
84
|
-
GC::Profiler.total_time * 1000 # second -> millisecond
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
|
|
88
67
|
class Job < Execution
|
|
89
68
|
def add_exception(exception)
|
|
90
69
|
super(exception)
|
data/lib/rorvswild/installer.rb
CHANGED
|
@@ -22,44 +22,59 @@ development:
|
|
|
22
22
|
# widget: top-left, top-right, bottom-left, bottom-right or hidden
|
|
23
23
|
|
|
24
24
|
# Open files in your text editor by clicking from the local widget.
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
|
|
25
|
+
# Leave commented to auto-detect from RAILS_EDITOR or EDITOR env vars (Rails 8.1+).
|
|
26
|
+
# Or set explicitly:
|
|
27
|
+
# editor_url: <%= ENV.fetch("RORVSWILD_EDITOR_URL", "vscode://file${path}:${line}") %>
|
|
28
|
+
# for VSCode: "vscode://file${path}:${line}"
|
|
29
|
+
# for Sublime: "subl://${path}:${line}"
|
|
29
30
|
|
|
30
31
|
production:
|
|
31
|
-
api_key: #{api_key}
|
|
32
|
-
|
|
33
|
-
#
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
#
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
#
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
#
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
32
|
+
api_key: <%= ENV["RORVSWILD_API_KEY"] || "#{api_key}" %>
|
|
33
|
+
|
|
34
|
+
# Do not monitor the following actions.
|
|
35
|
+
ignore_requests:
|
|
36
|
+
- SecretController#index
|
|
37
|
+
|
|
38
|
+
# Do not monitor the following jobs.
|
|
39
|
+
ignore_jobs:
|
|
40
|
+
- SecretJob
|
|
41
|
+
|
|
42
|
+
# Do not monitor the following exceptions.
|
|
43
|
+
ignore_exceptions:
|
|
44
|
+
# Noisy exceptions such as ActionNotFound, UnknownHttpMethod, etc are ignored by default.
|
|
45
|
+
- <%= ActionDispatch::ExceptionWrapper.rescue_responses.keys.join("\\n - ") %>
|
|
46
|
+
- AnotherNoisyError
|
|
47
|
+
|
|
48
|
+
# In case you want less details.
|
|
49
|
+
ignore_plugins:
|
|
50
|
+
# - ActionController
|
|
51
|
+
# - ActionMailer
|
|
52
|
+
# - ActionView
|
|
53
|
+
# - ActiveJob
|
|
54
|
+
# - ActiveRecord
|
|
55
|
+
# - DelayedJob
|
|
56
|
+
# - Elasticsearch
|
|
57
|
+
# - Faktory
|
|
58
|
+
# - Mongo
|
|
59
|
+
# - NetHttp
|
|
60
|
+
# - Rack
|
|
61
|
+
# - RailsCache
|
|
62
|
+
# - RailsError
|
|
63
|
+
# - Redis
|
|
64
|
+
# - Resque
|
|
65
|
+
# - Sidekiq
|
|
66
|
+
|
|
52
67
|
# logger: log/rorvswild.log # By default it uses Rails.logger or Logger.new(STDOUT)
|
|
53
|
-
|
|
54
|
-
#
|
|
55
|
-
#
|
|
56
|
-
#
|
|
68
|
+
|
|
69
|
+
# Deployment tracking is working without any actions from your part if the Rails app
|
|
70
|
+
# is inside a Git repository, or deployed with Capistrano, Kamal, Heroku or Scalingo.
|
|
71
|
+
# In the other cases, you can provide the following details.
|
|
57
72
|
# deployment:
|
|
58
73
|
# revision: <%= "Anything that will return the deployment version" %> # Mandatory
|
|
59
74
|
# description: <%= "Eventually if you have a description such as a Git message" %>
|
|
60
75
|
# author: <%= "Author's name of the deployment" %>
|
|
61
76
|
# email: <%= "emailOf@theAuthor.example" %>
|
|
62
|
-
|
|
77
|
+
|
|
63
78
|
# Sampling allows to send a fraction of jobs and requests.
|
|
64
79
|
# If your app is sending hundred of millions of requests per month,
|
|
65
80
|
# you will probably get the same precision if you send only a fraction of it.
|
|
@@ -74,6 +74,18 @@ RorVsWild.Local.prototype.toggleCommand = function(event) {
|
|
|
74
74
|
document.querySelector(event.currentTarget.dataset.target).classList.toggle("is-open")
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
RorVsWild.Local.prototype.toggleLowImpactSections = function(event) {
|
|
78
|
+
var button = event.currentTarget
|
|
79
|
+
var sections = document.querySelectorAll(".rorvswild-local-panel__details__section[data-low-impact]")
|
|
80
|
+
var isHidden = sections[0].classList.contains("is-hidden")
|
|
81
|
+
|
|
82
|
+
sections.forEach(function(section) {
|
|
83
|
+
section.classList.toggle("is-hidden")
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
button.textContent = isHidden ? "↑ Hide low impact sections" : "↓ View low impact sections"
|
|
87
|
+
}
|
|
88
|
+
|
|
77
89
|
RorVsWild.Local.prototype.expand = function() {
|
|
78
90
|
this.active = true
|
|
79
91
|
this.goToRequestDetail(event)
|
|
@@ -107,6 +119,7 @@ RorVsWild.Local.formatImpact = function(impact) {
|
|
|
107
119
|
}
|
|
108
120
|
|
|
109
121
|
RorVsWild.Local.formatDateTime = function(date) {
|
|
122
|
+
if (!date || isNaN(date.getTime())) return ""
|
|
110
123
|
var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
|
|
111
124
|
var minutes = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes()
|
|
112
125
|
var hours = date.getHours() < 10 ? "0" + date.getHours() : date.getHours()
|
|
@@ -189,9 +202,11 @@ RorVsWild.Local.Request.prototype.runtime = function() {
|
|
|
189
202
|
RorVsWild.Local.Request.prototype.sections = function() {
|
|
190
203
|
return this.data.sections.map(function(section) {
|
|
191
204
|
var runtime = (section.total_runtime - section.children_runtime)
|
|
205
|
+
var impactValue = runtime * 100 / this.data.runtime
|
|
192
206
|
return {
|
|
193
207
|
id: RorVsWild.Local.nextId(),
|
|
194
|
-
impact: RorVsWild.Local.formatImpact(
|
|
208
|
+
impact: RorVsWild.Local.formatImpact(impactValue),
|
|
209
|
+
isLowImpact: impactValue < 1,
|
|
195
210
|
language: RorVsWild.Local.kindToLanguage(section.kind),
|
|
196
211
|
totalRuntime: RorVsWild.Local.relevantRounding(section.total_runtime),
|
|
197
212
|
asyncRuntime: RorVsWild.Local.relevantRounding(section.async_runtime),
|
|
@@ -212,6 +227,10 @@ RorVsWild.Local.Request.prototype.sections = function() {
|
|
|
212
227
|
}.bind(this)).sort(function(a, b) { return b.selfRuntime - a.selfRuntime })
|
|
213
228
|
}
|
|
214
229
|
|
|
230
|
+
RorVsWild.Local.Request.prototype.hasLowImpactSections = function() {
|
|
231
|
+
return this.sections().some(function(section) { return section.isLowImpact })
|
|
232
|
+
}
|
|
233
|
+
|
|
215
234
|
RorVsWild.Local.Request.prototype.sectionsImpactPerKind = function() {
|
|
216
235
|
var total = 0
|
|
217
236
|
var perKind = this.sections().reduce(function(object, section) {
|
|
@@ -148,6 +148,11 @@
|
|
|
148
148
|
{{#sections}}
|
|
149
149
|
{{> RorVsWild.Local.Section}}
|
|
150
150
|
{{/sections}}
|
|
151
|
+
{{#hasLowImpactSections}}
|
|
152
|
+
<div class="rorvswild-local-panel__toggle-low-impact">
|
|
153
|
+
<button data-events="click->toggleLowImpactSections" class="rorvswild-local-panel__toggle-low-impact__button">↓ view low impact sections</button>
|
|
154
|
+
</div>
|
|
155
|
+
{{/hasLowImpactSections}}
|
|
151
156
|
</div>
|
|
152
157
|
</script>
|
|
153
158
|
|
|
@@ -162,7 +167,7 @@
|
|
|
162
167
|
</script>
|
|
163
168
|
|
|
164
169
|
<script type="x-tmpl-mustache" data-partial="RorVsWild.Local.Section">
|
|
165
|
-
<div class="rorvswild-local-panel__details__section" id="section-{{id}}">
|
|
170
|
+
<div class="rorvswild-local-panel__details__section {{#isLowImpact}}is-hidden{{/isLowImpact}}" {{#isLowImpact}}data-low-impact{{/isLowImpact}} id="section-{{id}}">
|
|
166
171
|
<div class="rorvswild-local-panel__details__section__main">
|
|
167
172
|
<span class="rorvswild-local-panel__details__section__file">
|
|
168
173
|
<button data-events="click->toggleCommand" data-target="#section-{{id}}" class="rorvswild-local-panel__details__section__kind"><span>{{kind}}</button>
|
|
@@ -181,32 +186,32 @@
|
|
|
181
186
|
|
|
182
187
|
<div class="rorvswild-local-panel__details__section__code">
|
|
183
188
|
<dl>
|
|
184
|
-
{{#isAsync}}
|
|
185
|
-
<div>
|
|
186
|
-
<dt title="Time spent as non blocking IO">Async runtime</dt>
|
|
187
|
-
<dd>{{asyncRuntime}}<small>ms</small></dd>
|
|
188
|
-
</div>
|
|
189
|
-
{{/isAsync}}
|
|
190
189
|
<div>
|
|
191
|
-
<dt title="self
|
|
192
|
-
<dd title="{{selfRuntime}}
|
|
190
|
+
<dt title="self runtime / calls">Average runtime</dt>
|
|
191
|
+
<dd title="{{selfRuntime}} / {{calls}}">{{averageRuntime}}<small>ms</small></dd>
|
|
193
192
|
</div>
|
|
194
193
|
<div>
|
|
195
|
-
<dt
|
|
196
|
-
<dd
|
|
194
|
+
<dt>Calls</dt>
|
|
195
|
+
<dd class="dd--calls">{{calls}}<small>x</small></dd>
|
|
197
196
|
</div>
|
|
198
197
|
<div>
|
|
199
198
|
<dt title="total - children">Self runtime</dt>
|
|
200
199
|
<dd title="{{totalRuntime}} - {{childrenRuntime}}">{{selfRuntime}}<small>ms</small></dd>
|
|
201
200
|
</div>
|
|
202
201
|
<div>
|
|
203
|
-
<dt>
|
|
204
|
-
<dd
|
|
202
|
+
<dt title="total - self">Children runtime</dt>
|
|
203
|
+
<dd title="{{totalRuntime}} - {{selfRuntime}}">{{childrenRuntime}}<small>ms</small></dd>
|
|
205
204
|
</div>
|
|
206
205
|
<div>
|
|
207
|
-
<dt title="self
|
|
208
|
-
<dd title="{{selfRuntime}}
|
|
206
|
+
<dt title="self + children">Total runtime</dt>
|
|
207
|
+
<dd title="{{selfRuntime}} + {{childrenRuntime}}">{{totalRuntime}}<small>ms</small></dd>
|
|
209
208
|
</div>
|
|
209
|
+
{{#isAsync}}
|
|
210
|
+
<div>
|
|
211
|
+
<dt title="Time spent as non blocking IO">Async runtime</dt>
|
|
212
|
+
<dd>{{asyncRuntime}}<small>ms</small></dd>
|
|
213
|
+
</div>
|
|
214
|
+
{{/isAsync}}
|
|
210
215
|
</dl>
|
|
211
216
|
{{#command}}
|
|
212
217
|
<pre><code class="{{language}}">{{command}}</code></pre>
|
|
@@ -335,5 +340,5 @@
|
|
|
335
340
|
{{/currentError}}
|
|
336
341
|
</script>
|
|
337
342
|
|
|
338
|
-
<link rel="stylesheet" media="all" href="/rorvswild.css"
|
|
343
|
+
<link rel="stylesheet" media="all" href="/rorvswild.css">
|
|
339
344
|
<script src="/rorvswild.js"></script>
|
|
@@ -79,7 +79,13 @@ module RorVsWild
|
|
|
79
79
|
end
|
|
80
80
|
|
|
81
81
|
def editor_url
|
|
82
|
-
|
|
82
|
+
config[:editor_url] || rails_editor_url
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def rails_editor_url
|
|
86
|
+
if editor = defined?(ActiveSupport::Editor) && ActiveSupport::Editor.current
|
|
87
|
+
editor.url_for("${path}", 999999.999999).gsub("999999.999999", "${line}").gsub("999999", "${line}")
|
|
88
|
+
end
|
|
83
89
|
end
|
|
84
90
|
|
|
85
91
|
def inject_into(html)
|
|
@@ -39,7 +39,7 @@ module RorVsWild
|
|
|
39
39
|
private
|
|
40
40
|
|
|
41
41
|
def push_to(data, name)
|
|
42
|
-
data[:queued_at] = Time.now
|
|
42
|
+
data[:queued_at] = Time.now.iso8601(3)
|
|
43
43
|
data[:uuid] = SecureRandom.uuid
|
|
44
44
|
File.open(File.join(@directoy, "#{name}.ndjson"), "a") { |file| file.write(JSON.dump(data) + "\n") }
|
|
45
45
|
end
|
|
@@ -126,6 +126,7 @@
|
|
|
126
126
|
color: rgb(146 149 159) !important;
|
|
127
127
|
cursor: pointer !important;
|
|
128
128
|
line-height: 48px !important;
|
|
129
|
+
margin: 0 !important;
|
|
129
130
|
}
|
|
130
131
|
|
|
131
132
|
.rorvswild-local-panel__header nav li:hover {
|
|
@@ -350,6 +351,10 @@ h2.rorvswild-local-panel__title {
|
|
|
350
351
|
display: block !important;
|
|
351
352
|
}
|
|
352
353
|
|
|
354
|
+
.rorvswild-local-panel__details__section.is-hidden {
|
|
355
|
+
display: none !important;
|
|
356
|
+
}
|
|
357
|
+
|
|
353
358
|
.rorvswild-local-panel__details__section:hover {
|
|
354
359
|
background: rgb(26 29 36) !important;
|
|
355
360
|
transition: all .3s !important;
|
|
@@ -433,30 +438,31 @@ a.rorvswild-local-panel__file__name:hover::after { opacity: 1; }
|
|
|
433
438
|
.rorvswild-local-panel__details__section__code dl {
|
|
434
439
|
display: flex;
|
|
435
440
|
align-items: baseline;
|
|
436
|
-
justify-content: flex-end;
|
|
437
441
|
flex-wrap: wrap;
|
|
438
442
|
margin: 0;
|
|
439
443
|
padding: 0;
|
|
440
|
-
text-align:
|
|
444
|
+
text-align: center;
|
|
441
445
|
gap: 12px 24px;
|
|
442
446
|
}
|
|
443
447
|
|
|
448
|
+
.rorvswild-local-panel__details__section__code dl > * {
|
|
449
|
+
flex: 1;
|
|
450
|
+
}
|
|
451
|
+
|
|
444
452
|
.rorvswild-local-panel__details__section__code dt {
|
|
445
453
|
white-space: nowrap;
|
|
446
|
-
margin: 0;
|
|
454
|
+
margin: 4px 0 0;
|
|
447
455
|
text-transform: uppercase;
|
|
448
456
|
letter-spacing: 1px;
|
|
449
457
|
font-size: 9px !important;
|
|
458
|
+
line-height: 12px;
|
|
459
|
+
font-weight: 400;
|
|
450
460
|
}
|
|
451
461
|
|
|
452
462
|
.rorvswild-local-panel__details__section__code dd {
|
|
453
463
|
margin: 0;
|
|
454
|
-
color: rgb(182 202 255) !important;
|
|
455
|
-
font-weight: 700;
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
.rorvswild-local-panel__details__section__code dd.dd--calls {
|
|
459
464
|
color: rgb(199 203 214) !important;
|
|
465
|
+
font-weight: 700;
|
|
460
466
|
}
|
|
461
467
|
|
|
462
468
|
.rorvswild-local-panel__details__section__code dl + pre[class*="language-"] {
|
|
@@ -593,6 +599,31 @@ span.rorvswild-local-panel__details__section__kind {
|
|
|
593
599
|
overflow-wrap: break-word !important;
|
|
594
600
|
}
|
|
595
601
|
|
|
602
|
+
.rorvswild-local-panel__toggle-low-impact {
|
|
603
|
+
padding: 12px !important;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
.rorvswild-local-panel__toggle-low-impact__button {
|
|
607
|
+
background: transparent !important;
|
|
608
|
+
color: rgb(199 203 214) !important;
|
|
609
|
+
border: 1px solid rgb(72 75 80) !important;
|
|
610
|
+
box-shadow: none !important;
|
|
611
|
+
padding: 0px 8px !important;
|
|
612
|
+
font-size: 10px !important;
|
|
613
|
+
line-height: 24px !important;
|
|
614
|
+
text-transform: uppercase !important;
|
|
615
|
+
letter-spacing: 1px !important;
|
|
616
|
+
cursor: pointer !important;
|
|
617
|
+
font-weight: 700 !important;
|
|
618
|
+
transition: all 0.2s !important;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
.rorvswild-local-panel__toggle-low-impact__button:hover {
|
|
622
|
+
background: transparent !important;
|
|
623
|
+
color: rgb(223 228 242) !important;
|
|
624
|
+
border-color: rgb(147 149 156) !important;
|
|
625
|
+
}
|
|
626
|
+
|
|
596
627
|
/* Panel Footer */
|
|
597
628
|
.rorvswild-local-panel__footer {
|
|
598
629
|
width: 100% !important;
|
data/lib/rorvswild/local.rb
CHANGED
|
@@ -6,7 +6,7 @@ module RorVsWild
|
|
|
6
6
|
def self.start(config = {})
|
|
7
7
|
queue = RorVsWild::Local::Queue.new(config[:queue] || {})
|
|
8
8
|
RorVsWild.start(config.merge(queue: queue))
|
|
9
|
-
Rails.application.config.middleware.unshift(RorVsWild::Local::Middleware,
|
|
9
|
+
Rails.application.config.middleware.unshift(RorVsWild::Local::Middleware, config)
|
|
10
10
|
end
|
|
11
11
|
end
|
|
12
12
|
end
|
|
@@ -50,6 +50,9 @@ module RorVsWild
|
|
|
50
50
|
SQL_ONE_LINE_COMMENT_REGEX =/--.*$/
|
|
51
51
|
SQL_MULTI_LINE_COMMENT_REGEX = /\/\*.*?\*\//m
|
|
52
52
|
|
|
53
|
+
# Catch Regexp::TimeoutError without breaking before Ruby 3.2
|
|
54
|
+
REGEXP_TIMEOUT_ERROR = defined?(Regexp::TimeoutError) ? Regexp::TimeoutError : RegexpError
|
|
55
|
+
|
|
53
56
|
def normalize_sql_query(sql)
|
|
54
57
|
sql = sql.to_s.gsub(SQL_STRING_REGEX, "?")
|
|
55
58
|
sql.gsub!(SQL_PARAMETER_REGEX, "?")
|
|
@@ -59,6 +62,8 @@ module RorVsWild
|
|
|
59
62
|
sql.gsub!(SQL_MULTI_LINE_COMMENT_REGEX, "")
|
|
60
63
|
sql.strip!
|
|
61
64
|
sql
|
|
65
|
+
rescue REGEXP_TIMEOUT_ERROR
|
|
66
|
+
nil
|
|
62
67
|
end
|
|
63
68
|
end
|
|
64
69
|
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RorVsWild
|
|
4
|
+
module Plugin
|
|
5
|
+
class Rack
|
|
6
|
+
@installed = false
|
|
7
|
+
|
|
8
|
+
def self.setup(agent)
|
|
9
|
+
return if @installed
|
|
10
|
+
return if !defined?(ActiveSupport::Notifications.subscribe)
|
|
11
|
+
ActiveSupport::Notifications.subscribe("process_middleware.action_dispatch", new)
|
|
12
|
+
@installed = true
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def start(name, id, payload)
|
|
16
|
+
section = RorVsWild::Section.start
|
|
17
|
+
section.kind = "rack"
|
|
18
|
+
if location = source_location(payload[:middleware])
|
|
19
|
+
section.file = location[0]
|
|
20
|
+
section.line = location[1]
|
|
21
|
+
section.commands << payload[:middleware]
|
|
22
|
+
else
|
|
23
|
+
section.file = payload[:middleware]
|
|
24
|
+
section.line = 0
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def finish(name, id, payload)
|
|
29
|
+
RorVsWild::Section.stop
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def source_location(middleware_name)
|
|
35
|
+
middleware = Kernel.const_get(middleware_name)
|
|
36
|
+
middleware.instance_method(:call).source_location
|
|
37
|
+
rescue NameError
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module RorVsWild
|
|
4
4
|
module Plugin
|
|
5
|
-
|
|
5
|
+
module RailsEngine
|
|
6
6
|
module RequestQueueTime
|
|
7
7
|
|
|
8
8
|
ACCEPTABLE_HEADERS = [
|
|
@@ -49,26 +49,20 @@ module RorVsWild
|
|
|
49
49
|
@installed = false
|
|
50
50
|
|
|
51
51
|
def self.setup(agent)
|
|
52
|
-
return if @installed
|
|
53
|
-
Rails.
|
|
52
|
+
return if @installed || !defined?(Rails::Engine)
|
|
53
|
+
Rails::Engine.prepend(self)
|
|
54
54
|
@installed = true
|
|
55
55
|
end
|
|
56
56
|
|
|
57
|
-
def initialize(app, config)
|
|
58
|
-
@app, @config = app, config
|
|
59
|
-
end
|
|
60
|
-
|
|
61
57
|
def call(env)
|
|
62
|
-
execution = RorVsWild::Execution::Request.new(env["
|
|
58
|
+
execution = RorVsWild::Execution::Request.new(env["REQUEST_URI"])
|
|
63
59
|
execution.add_queue_time(calculate_queue_time(env))
|
|
64
60
|
RorVsWild.agent.start_execution(execution)
|
|
65
|
-
section =
|
|
66
|
-
section.file, section.line =
|
|
61
|
+
section = execution.root_section
|
|
62
|
+
section.file, section.line = method(:call).super_method.source_location
|
|
67
63
|
section.commands << "Rails::Engine#call"
|
|
68
|
-
|
|
69
|
-
[code, headers, body]
|
|
64
|
+
super
|
|
70
65
|
ensure
|
|
71
|
-
RorVsWild::Section.stop
|
|
72
66
|
RorVsWild.agent.stop_execution
|
|
73
67
|
end
|
|
74
68
|
|
|
@@ -79,10 +73,6 @@ module RorVsWild
|
|
|
79
73
|
|
|
80
74
|
((Time.now.to_f - queue_time_from_header) * 1000).round if queue_time_from_header
|
|
81
75
|
end
|
|
82
|
-
|
|
83
|
-
def rails_engine_location
|
|
84
|
-
@rails_engine_location = ::Rails::Engine.instance_method(:call).source_location
|
|
85
|
-
end
|
|
86
76
|
end
|
|
87
77
|
end
|
|
88
78
|
end
|
data/lib/rorvswild/section.rb
CHANGED
|
@@ -28,21 +28,6 @@ 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", 0
|
|
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
31
|
if GC.respond_to?(:total_time)
|
|
47
32
|
def self.gc_total_ms
|
|
48
33
|
GC.total_time / 1_000_000.0 # nanosecond -> millisecond
|
|
@@ -111,5 +96,46 @@ module RorVsWild
|
|
|
111
96
|
string = @commands.to_a.join("\n")
|
|
112
97
|
string.size > COMMAND_MAX_SIZE ? string[0, COMMAND_MAX_SIZE] + " [TRUNCATED]" : string
|
|
113
98
|
end
|
|
99
|
+
|
|
100
|
+
class Root < Section
|
|
101
|
+
attr_reader :gc_calls
|
|
102
|
+
|
|
103
|
+
def initialize
|
|
104
|
+
super
|
|
105
|
+
@gc_count = GC.count
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def stop
|
|
109
|
+
super
|
|
110
|
+
@gc_calls = GC.count - @gc_count
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
class GarbageCollection < Section
|
|
115
|
+
def initialize(total_ms, calls)
|
|
116
|
+
@total_ms = total_ms
|
|
117
|
+
@calls = calls > 0 ? calls : 1
|
|
118
|
+
@kind = "gc"
|
|
119
|
+
@file, @line = "ruby/gc.c", 0
|
|
120
|
+
@commands = Set.new
|
|
121
|
+
@children_ms = 0
|
|
122
|
+
@async_ms = 0
|
|
123
|
+
add_command("GC.start")
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
class Queue < Section
|
|
128
|
+
def initialize(total_ms)
|
|
129
|
+
@total_ms = total_ms
|
|
130
|
+
@gc_time_ms = 0
|
|
131
|
+
@file = "queue"
|
|
132
|
+
@line = 0
|
|
133
|
+
@kind = "queue"
|
|
134
|
+
@calls = 1
|
|
135
|
+
@children_ms = 0
|
|
136
|
+
@gc_time_ms = 0
|
|
137
|
+
@async_ms = 0
|
|
138
|
+
end
|
|
139
|
+
end
|
|
114
140
|
end
|
|
115
141
|
end
|
data/lib/rorvswild/version.rb
CHANGED
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.11.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alexis Bernard
|
|
@@ -55,10 +55,11 @@ files:
|
|
|
55
55
|
- lib/rorvswild/plugin/delayed_job.rb
|
|
56
56
|
- lib/rorvswild/plugin/elasticsearch.rb
|
|
57
57
|
- lib/rorvswild/plugin/faktory.rb
|
|
58
|
-
- lib/rorvswild/plugin/middleware.rb
|
|
59
58
|
- lib/rorvswild/plugin/mongo.rb
|
|
60
59
|
- lib/rorvswild/plugin/net_http.rb
|
|
60
|
+
- lib/rorvswild/plugin/rack.rb
|
|
61
61
|
- lib/rorvswild/plugin/rails_cache.rb
|
|
62
|
+
- lib/rorvswild/plugin/rails_engine.rb
|
|
62
63
|
- lib/rorvswild/plugin/rails_error.rb
|
|
63
64
|
- lib/rorvswild/plugin/redis.rb
|
|
64
65
|
- lib/rorvswild/plugin/resque.rb
|
|
@@ -88,7 +89,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
88
89
|
- !ruby/object:Gem::Version
|
|
89
90
|
version: '0'
|
|
90
91
|
requirements: []
|
|
91
|
-
rubygems_version:
|
|
92
|
+
rubygems_version: 4.0.3
|
|
92
93
|
specification_version: 4
|
|
93
94
|
summary: Ruby on Rails applications monitoring
|
|
94
95
|
test_files: []
|