rorvswild 1.9.1 → 1.10.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 +31 -78
- data/lib/rorvswild/client.rb +1 -1
- data/lib/rorvswild/deployment.rb +17 -10
- data/lib/rorvswild/error.rb +40 -0
- data/lib/rorvswild/execution.rb +134 -0
- data/lib/rorvswild/local/local.html.erb +1 -1
- data/lib/rorvswild/local/queue.rb +24 -12
- data/lib/rorvswild/local.rb +2 -1
- data/lib/rorvswild/locator.rb +3 -1
- data/lib/rorvswild/metrics.rb +1 -0
- data/lib/rorvswild/plugin/action_controller.rb +12 -34
- data/lib/rorvswild/plugin/action_mailer.rb +4 -2
- data/lib/rorvswild/plugin/action_view.rb +6 -2
- data/lib/rorvswild/plugin/active_job.rb +3 -1
- data/lib/rorvswild/plugin/active_record.rb +5 -3
- data/lib/rorvswild/plugin/delayed_job.rb +3 -1
- data/lib/rorvswild/plugin/elasticsearch.rb +1 -1
- data/lib/rorvswild/plugin/faktory.rb +1 -1
- data/lib/rorvswild/plugin/middleware.rb +7 -62
- data/lib/rorvswild/plugin/mongo.rb +42 -10
- data/lib/rorvswild/plugin/net_http.rb +1 -1
- data/lib/rorvswild/plugin/rails_cache.rb +30 -0
- data/lib/rorvswild/plugin/rails_error.rb +21 -0
- data/lib/rorvswild/plugin/redis.rb +1 -1
- data/lib/rorvswild/plugin/resque.rb +3 -1
- data/lib/rorvswild/plugin/sidekiq.rb +17 -2
- data/lib/rorvswild/rails_loader.rb +4 -0
- data/lib/rorvswild/section.rb +4 -4
- data/lib/rorvswild/version.rb +1 -1
- data/lib/rorvswild.rb +3 -1
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f56b7bc131f07c6010a47ec4e9bf635c21d0b560b472ade68740cca05b4550fd
|
4
|
+
data.tar.gz: 5d72ca9672beb7cfe60cd81febb84aa9c5556259de713443ec7eac46d376f86a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f5a6174758d7ef8617cf0e210fe4ad235e22153314add1dbc57fe62ece456bf4111a7586f8c104d7742491fd29ae24d04710121931787e8393e372eeb4ddad64
|
7
|
+
data.tar.gz: 94e9525e22117bc39cbae29459e6b1ec75bb12e54d21d605098d14e4fe8b0bcf3deeaab377aa6124c412bf0742912917e94a2522fea96091cdda5c18f7db22ae
|
data/lib/rorvswild/agent.rb
CHANGED
@@ -15,7 +15,7 @@ module RorVsWild
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def self.default_ignored_exceptions
|
18
|
-
if defined?(
|
18
|
+
if defined?(ActionDispatch::ExceptionWrapper)
|
19
19
|
ActionDispatch::ExceptionWrapper.rescue_responses.keys
|
20
20
|
else
|
21
21
|
[]
|
@@ -48,7 +48,7 @@ module RorVsWild
|
|
48
48
|
next if config[:ignore_plugins] && config[:ignore_plugins].include?(name.to_s)
|
49
49
|
if (plugin = RorVsWild::Plugin.const_get(name)).respond_to?(:setup)
|
50
50
|
RorVsWild.logger.debug("Setup RorVsWild::Plugin::#{name}")
|
51
|
-
plugin.setup
|
51
|
+
plugin.setup(self)
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end
|
@@ -58,7 +58,7 @@ module RorVsWild
|
|
58
58
|
end
|
59
59
|
|
60
60
|
def measure_block(name = nil, kind = "code".freeze, &block)
|
61
|
-
|
61
|
+
current_execution ? measure_section(name, kind: kind, &block) : measure_job(name, &block)
|
62
62
|
end
|
63
63
|
|
64
64
|
def measure_method(method)
|
@@ -85,7 +85,7 @@ module RorVsWild
|
|
85
85
|
end
|
86
86
|
|
87
87
|
def measure_section(name, kind: "code", &block)
|
88
|
-
return block.call unless
|
88
|
+
return block.call unless current_execution
|
89
89
|
begin
|
90
90
|
RorVsWild::Section.start do |section|
|
91
91
|
section.commands << name
|
@@ -98,32 +98,30 @@ module RorVsWild
|
|
98
98
|
end
|
99
99
|
|
100
100
|
def measure_job(name, parameters: nil, &block)
|
101
|
-
return measure_section(name, &block) if
|
101
|
+
return measure_section(name, &block) if current_execution # For recursive jobs
|
102
102
|
return block.call if ignored_job?(name)
|
103
|
-
|
103
|
+
start_execution(Execution::Job.new(name, parameters))
|
104
104
|
begin
|
105
105
|
block.call
|
106
106
|
rescue Exception => ex
|
107
|
-
|
107
|
+
current_execution.add_exception(ex)
|
108
108
|
raise
|
109
109
|
ensure
|
110
|
-
|
111
|
-
current_data[:sections] << gc if gc.calls > 0
|
112
|
-
current_data[:runtime] = RorVsWild.clock_milliseconds - current_data[:started_at]
|
113
|
-
queue_job
|
110
|
+
stop_execution
|
114
111
|
end
|
115
112
|
end
|
116
113
|
|
117
|
-
def
|
118
|
-
|
114
|
+
def start_execution(execution)
|
115
|
+
Thread.current[:rorvswild_execution] ||= execution
|
119
116
|
end
|
120
117
|
|
121
|
-
def
|
122
|
-
return unless
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
queue_request
|
118
|
+
def stop_execution
|
119
|
+
return unless execution = current_execution
|
120
|
+
execution.stop
|
121
|
+
case execution
|
122
|
+
when Execution::Job then queue_job
|
123
|
+
when Execution::Request then queue_request
|
124
|
+
end
|
127
125
|
end
|
128
126
|
|
129
127
|
def catch_error(context = nil, &block)
|
@@ -136,44 +134,21 @@ module RorVsWild
|
|
136
134
|
end
|
137
135
|
|
138
136
|
def record_error(exception, context = nil)
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
def push_exception(exception, options = nil)
|
143
|
-
return if ignored_exception?(exception)
|
144
|
-
return unless current_data
|
145
|
-
current_data[:error] = exception_to_hash(exception)
|
146
|
-
current_data[:error].merge!(options) if options
|
147
|
-
current_data[:error]
|
137
|
+
if !ignored_exception?(exception) && current_execution&.error&.exception != exception
|
138
|
+
queue_error(Error.new(exception, context).as_json)
|
139
|
+
end
|
148
140
|
end
|
149
141
|
|
150
142
|
def merge_error_context(hash)
|
151
|
-
|
152
|
-
end
|
153
|
-
|
154
|
-
def error_context
|
155
|
-
current_data[:error_context] if current_data
|
156
|
-
end
|
157
|
-
|
158
|
-
def error_context=(hash)
|
159
|
-
current_data[:error_context] = hash if current_data
|
160
|
-
end
|
161
|
-
|
162
|
-
def send_server_timing=(boolean)
|
163
|
-
current_data[:send_server_timing] = boolean if current_data
|
143
|
+
current_execution && current_execution.merge_error_context(hash)
|
164
144
|
end
|
165
145
|
|
166
146
|
def current_data
|
167
147
|
Thread.current[:rorvswild_data]
|
168
148
|
end
|
169
149
|
|
170
|
-
def
|
171
|
-
|
172
|
-
if sibling = current_data[:sections].find { |s| s.sibling?(section) }
|
173
|
-
sibling.merge(section)
|
174
|
-
else
|
175
|
-
current_data[:sections] << section
|
176
|
-
end
|
150
|
+
def current_execution
|
151
|
+
Thread.current[:rorvswild_execution]
|
177
152
|
end
|
178
153
|
|
179
154
|
def ignored_request?(name)
|
@@ -186,7 +161,8 @@ module RorVsWild
|
|
186
161
|
|
187
162
|
def ignored_exception?(exception)
|
188
163
|
return false unless config[:ignore_exceptions]
|
189
|
-
|
164
|
+
class_name = exception.class.to_s
|
165
|
+
config[:ignore_exceptions].any? { |str_or_regex| str_or_regex === class_name }
|
190
166
|
end
|
191
167
|
|
192
168
|
#######################
|
@@ -195,47 +171,24 @@ module RorVsWild
|
|
195
171
|
|
196
172
|
private
|
197
173
|
|
198
|
-
def initialize_data(queue_time_ms = 0)
|
199
|
-
Thread.current[:rorvswild_data] = {
|
200
|
-
started_at: RorVsWild.clock_milliseconds - queue_time_ms,
|
201
|
-
gc_section: Section.start_gc_timing,
|
202
|
-
environment: Host.to_h,
|
203
|
-
section_stack: [],
|
204
|
-
sections: [],
|
205
|
-
}
|
206
|
-
end
|
207
|
-
|
208
174
|
def cleanup_data
|
209
|
-
result = Thread.current[:
|
210
|
-
Thread.current[:
|
175
|
+
result = Thread.current[:rorvswild_execution]
|
176
|
+
Thread.current[:rorvswild_execution] = nil
|
211
177
|
result
|
212
178
|
end
|
213
179
|
|
214
180
|
def queue_request
|
215
|
-
(
|
216
|
-
|
181
|
+
if (execution = cleanup_data) && execution.name
|
182
|
+
queue.push_request(execution.as_json)
|
183
|
+
end
|
217
184
|
end
|
218
185
|
|
219
186
|
def queue_job
|
220
|
-
queue.push_job(cleanup_data)
|
187
|
+
queue.push_job(cleanup_data.as_json)
|
221
188
|
end
|
222
189
|
|
223
190
|
def queue_error(hash)
|
224
191
|
queue.push_error(hash)
|
225
192
|
end
|
226
|
-
|
227
|
-
def exception_to_hash(exception, context = nil)
|
228
|
-
file, line = locator.find_most_relevant_file_and_line_from_exception(exception)
|
229
|
-
context = context ? error_context.merge(context) : error_context if error_context
|
230
|
-
{
|
231
|
-
line: line.to_i,
|
232
|
-
file: locator.relative_path(file),
|
233
|
-
message: exception.message[0,1_000_000],
|
234
|
-
backtrace: exception.backtrace || ["No backtrace"],
|
235
|
-
exception: exception.class.to_s,
|
236
|
-
context: context,
|
237
|
-
environment: Host.to_h,
|
238
|
-
}
|
239
|
-
end
|
240
193
|
end
|
241
194
|
end
|
data/lib/rorvswild/client.rb
CHANGED
data/lib/rorvswild/deployment.rb
CHANGED
@@ -4,6 +4,8 @@ require "open3"
|
|
4
4
|
|
5
5
|
module RorVsWild
|
6
6
|
module Deployment
|
7
|
+
@revision = @description = @author = @email = nil
|
8
|
+
|
7
9
|
def self.load_config(config)
|
8
10
|
read
|
9
11
|
if hash = config[:deployment]
|
@@ -35,7 +37,7 @@ module RorVsWild
|
|
35
37
|
end
|
36
38
|
|
37
39
|
def self.rails
|
38
|
-
Rails.version if defined?(Rails)
|
40
|
+
Rails.version if defined?(Rails) && Rails.respond_to?(:version)
|
39
41
|
end
|
40
42
|
|
41
43
|
def self.rorvswild
|
@@ -47,7 +49,7 @@ module RorVsWild
|
|
47
49
|
end
|
48
50
|
|
49
51
|
def self.read
|
50
|
-
read_from_heroku || read_from_scalingo || read_from_git || read_from_capistrano
|
52
|
+
read_from_heroku || read_from_scalingo || read_from_kamal || read_from_git || read_from_capistrano
|
51
53
|
end
|
52
54
|
|
53
55
|
private
|
@@ -65,10 +67,7 @@ module RorVsWild
|
|
65
67
|
def self.read_from_git
|
66
68
|
return unless @revision = normalize_string(shell("git rev-parse HEAD"))
|
67
69
|
return @revision unless log_stdout = shell("git log -1 --pretty=%an%n%ae%n%B")
|
68
|
-
|
69
|
-
@author = normalize_string(lines[0])
|
70
|
-
@email = normalize_string(lines[1])
|
71
|
-
@description = lines[2..-1] && normalize_string(lines[2..-1].join)
|
70
|
+
parse_git_log(log_stdout.lines)
|
72
71
|
@revision
|
73
72
|
end
|
74
73
|
|
@@ -76,13 +75,15 @@ module RorVsWild
|
|
76
75
|
return unless File.readable?("REVISION")
|
77
76
|
return unless @revision = File.read("REVISION")
|
78
77
|
return unless stdout = shell("git --git-dir ../../repo log --format=%an%n%ae%n%B -n 1 #{@revision}")
|
79
|
-
|
80
|
-
@author = normalize_string(lines[0])
|
81
|
-
@email = normalize_string(lines[1])
|
82
|
-
@description = lines[2..-1] && normalize_string(lines[2..-1].join)
|
78
|
+
parse_git_log(stdout.lines)
|
83
79
|
@revision
|
84
80
|
end
|
85
81
|
|
82
|
+
def self.read_from_kamal
|
83
|
+
return unless ENV["KAMAL_VERSION"]
|
84
|
+
@revision = ENV["KAMAL_VERSION"]
|
85
|
+
end
|
86
|
+
|
86
87
|
def self.normalize_string(string)
|
87
88
|
if string
|
88
89
|
string = string.strip
|
@@ -94,5 +95,11 @@ module RorVsWild
|
|
94
95
|
stdout, _, process = Open3.capture3(command) rescue nil
|
95
96
|
stdout if process && process.success?
|
96
97
|
end
|
98
|
+
|
99
|
+
def self.parse_git_log(lines)
|
100
|
+
@author = normalize_string(lines[0])
|
101
|
+
@email = normalize_string(lines[1])
|
102
|
+
@description = lines[2..-1] && normalize_string(lines[2..-1].join)
|
103
|
+
end
|
97
104
|
end
|
98
105
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RorVsWild
|
4
|
+
class Error
|
5
|
+
attr_reader :exception
|
6
|
+
|
7
|
+
attr_accessor :details
|
8
|
+
|
9
|
+
def initialize(exception, context = nil)
|
10
|
+
@exception = exception
|
11
|
+
@file, @line = locator.find_most_relevant_file_and_line_from_exception(exception)
|
12
|
+
@context = extract_context(context)
|
13
|
+
end
|
14
|
+
|
15
|
+
def locator
|
16
|
+
RorVsWild.agent.locator
|
17
|
+
end
|
18
|
+
|
19
|
+
def as_json(options = nil)
|
20
|
+
hash = {
|
21
|
+
line: @line.to_i,
|
22
|
+
file: locator.relative_path(@file),
|
23
|
+
message: exception.message[0,1_000_000],
|
24
|
+
backtrace: exception.backtrace || ["No backtrace"],
|
25
|
+
exception: exception.class.to_s,
|
26
|
+
context: @context,
|
27
|
+
environment: Host.to_h,
|
28
|
+
}
|
29
|
+
hash.merge!(details) if details
|
30
|
+
hash
|
31
|
+
end
|
32
|
+
|
33
|
+
def extract_context(given_context)
|
34
|
+
hash = defined?(ActiveSupport::ExecutionContext) ? ActiveSupport::ExecutionContext.to_h : {}
|
35
|
+
hash.merge!(RorVsWild.agent&.current_execution&.error_context || {})
|
36
|
+
hash.merge!(given_context) if given_context.is_a?(Hash)
|
37
|
+
hash
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RorVsWild
|
4
|
+
class Execution
|
5
|
+
attr_reader :parameters, :sections, :section_stack, :error_context, :runtime
|
6
|
+
|
7
|
+
attr_accessor :error, :name
|
8
|
+
|
9
|
+
def initialize(name, parameters)
|
10
|
+
@name = name
|
11
|
+
@parameters = parameters
|
12
|
+
@runtime = nil
|
13
|
+
@error = nil
|
14
|
+
@error_context = nil
|
15
|
+
|
16
|
+
@started_at = RorVsWild.clock_milliseconds
|
17
|
+
@gc_section = Section.start_gc_timing
|
18
|
+
@environment = Host.to_h
|
19
|
+
@section_stack = []
|
20
|
+
@sections = []
|
21
|
+
end
|
22
|
+
|
23
|
+
def add_section(section)
|
24
|
+
if sibling = @sections.find { |s| s.sibling?(section) }
|
25
|
+
sibling.merge(section)
|
26
|
+
else
|
27
|
+
@sections << section
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def add_queue_time(queue_time_ms)
|
32
|
+
return unless queue_time_ms
|
33
|
+
@started_at -= queue_time_ms
|
34
|
+
section = Section.new
|
35
|
+
section.total_ms = queue_time_ms
|
36
|
+
section.gc_time_ms = 0
|
37
|
+
section.file = "queue"
|
38
|
+
section.line = 0
|
39
|
+
section.kind = "queue"
|
40
|
+
add_section(section)
|
41
|
+
end
|
42
|
+
|
43
|
+
def stop
|
44
|
+
Section.stop_gc_timing(@gc_section)
|
45
|
+
@sections << @gc_section if @gc_section.calls > 0 && @gc_section.total_ms > 0
|
46
|
+
@runtime = RorVsWild.clock_milliseconds - @started_at
|
47
|
+
end
|
48
|
+
|
49
|
+
def as_json(options = nil)
|
50
|
+
{
|
51
|
+
name: name,
|
52
|
+
runtime: @runtime,
|
53
|
+
error: @error && @error.as_json(options),
|
54
|
+
sections: @sections.map(&:as_json),
|
55
|
+
environment: Host.to_h,
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
def add_exception(exception)
|
60
|
+
@error = Error.new(exception) if !RorVsWild.agent.ignored_exception?(exception) && !@error
|
61
|
+
end
|
62
|
+
|
63
|
+
def merge_error_context(hash)
|
64
|
+
@error_context = @error_context ? @error_context.merge(hash) : hash
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
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
|
+
class Job < Execution
|
89
|
+
def add_exception(exception)
|
90
|
+
super(exception)
|
91
|
+
@error && @error.details = {parameters: parameters, job: {name: name}}
|
92
|
+
@error
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
class Request < Execution
|
97
|
+
attr_reader :path
|
98
|
+
|
99
|
+
attr_accessor :controller
|
100
|
+
|
101
|
+
def initialize(path)
|
102
|
+
@path = path
|
103
|
+
super(nil, nil)
|
104
|
+
end
|
105
|
+
|
106
|
+
def add_exception(exception)
|
107
|
+
super(exception)
|
108
|
+
@error && @error.details = {
|
109
|
+
parameters: controller.request.filtered_parameters,
|
110
|
+
request: {
|
111
|
+
headers: headers,
|
112
|
+
name: "#{controller.class}##{controller.action_name}",
|
113
|
+
method: controller.request.method,
|
114
|
+
url: controller.request.url,
|
115
|
+
}
|
116
|
+
}
|
117
|
+
@error
|
118
|
+
end
|
119
|
+
|
120
|
+
def headers
|
121
|
+
controller.request.filtered_env.reduce({}) do |hash, (name, value)|
|
122
|
+
if name.start_with?("HTTP_") && name != "HTTP_COOKIE"
|
123
|
+
hash[name.delete_prefix("HTTP_").split("_").each(&:capitalize!).join("-")] = value
|
124
|
+
end
|
125
|
+
hash
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def as_json(options = nil)
|
130
|
+
super(options).merge(path: @path)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -11,7 +11,7 @@
|
|
11
11
|
<div class="rorvswild-local-panel__header">
|
12
12
|
<div class="rorvswild-local-panel__width-limiter">
|
13
13
|
<a href="https://www.rorvswild.com" class="rorvswild-local-panel__logo">
|
14
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 34.83 30.83">
|
14
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 34.83 30.83" fill="none" width="24px" height="24px">
|
15
15
|
<polygon points="17.41 9.41 13.41 9.41 9.41 13.41 17.41 21.41 25.41 13.41 21.41 9.41 17.41 9.41"/>
|
16
16
|
<polyline points="1.41 21.41 9.41 29.41 17.41 21.41 25.41 29.41 33.41 21.41"/>
|
17
17
|
<polyline points="9.41 5.41 5.41 1.41 1.41 5.41"/>
|
@@ -3,6 +3,13 @@
|
|
3
3
|
module RorVsWild
|
4
4
|
module Local
|
5
5
|
class Queue
|
6
|
+
def initialize(config = {})
|
7
|
+
@config = config
|
8
|
+
dir = File.directory?("tmp") ? "tmp" : Dir.tmpdir
|
9
|
+
@directoy = File.join(dir, "rorvswild", @config[:prefix].to_s)
|
10
|
+
FileUtils.mkpath(@directoy)
|
11
|
+
end
|
12
|
+
|
6
13
|
def push_job(data)
|
7
14
|
push_to(data, "jobs")
|
8
15
|
push_error(data[:error]) if data[:error]
|
@@ -34,23 +41,28 @@ module RorVsWild
|
|
34
41
|
def push_to(data, name)
|
35
42
|
data[:queued_at] = Time.now
|
36
43
|
data[:uuid] = SecureRandom.uuid
|
37
|
-
|
38
|
-
array.unshift(data)
|
39
|
-
array.pop if array.size > 100
|
40
|
-
save_data(array, name)
|
41
|
-
end
|
42
|
-
|
43
|
-
def save_data(data, name)
|
44
|
-
File.open(File.join(directoy, "#{name}.json"), "w") { |file| JSON.dump(data, file) }
|
44
|
+
File.open(File.join(@directoy, "#{name}.ndjson"), "a") { |file| file.write(JSON.dump(data) + "\n") }
|
45
45
|
end
|
46
46
|
|
47
47
|
def load_data(name)
|
48
|
-
|
48
|
+
return [] unless File.readable?(path = File.join(@directoy, "#{name}.ndjson"))
|
49
|
+
return [] unless lines = read_last_lines(path, 100)
|
50
|
+
lines.reverse.map { |line| JSON.parse(line, symbolize_names: true) }
|
49
51
|
end
|
50
52
|
|
51
|
-
def
|
52
|
-
|
53
|
-
|
53
|
+
def read_last_lines(path, desired_lines, max_read_size = 4096 * desired_lines)
|
54
|
+
read_lines, buffer = 0, []
|
55
|
+
File.open(path, "rb") do |file|
|
56
|
+
file.seek(0, IO::SEEK_END)
|
57
|
+
pos = file.pos
|
58
|
+
while pos > 0 && read_lines <= desired_lines
|
59
|
+
read_size = max_read_size < pos ? max_read_size : pos
|
60
|
+
file.seek(pos -= read_size, IO::SEEK_SET)
|
61
|
+
buffer << file.read(read_size)
|
62
|
+
read_lines += buffer.last.count("\n")
|
63
|
+
end
|
64
|
+
end
|
65
|
+
buffer.reverse.join.lines[1..desired_lines]
|
54
66
|
end
|
55
67
|
end
|
56
68
|
end
|
data/lib/rorvswild/local.rb
CHANGED
@@ -4,7 +4,8 @@ require "rorvswild/local/queue"
|
|
4
4
|
module RorVsWild
|
5
5
|
module Local
|
6
6
|
def self.start(config = {})
|
7
|
-
|
7
|
+
queue = RorVsWild::Local::Queue.new(config[:queue] || {})
|
8
|
+
RorVsWild.start(config.merge(queue: queue))
|
8
9
|
Rails.application.config.middleware.unshift(RorVsWild::Local::Middleware, nil)
|
9
10
|
end
|
10
11
|
end
|
data/lib/rorvswild/locator.rb
CHANGED
@@ -12,7 +12,9 @@ module RorVsWild
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def find_most_relevant_location(locations)
|
15
|
-
locations.find { |l|
|
15
|
+
locations.find { |l| l.path && relevant_path?(l.path) } ||
|
16
|
+
locations.find { |l| l.path && !l.path.start_with?(rorvswild_lib_path) } ||
|
17
|
+
locations.first
|
16
18
|
end
|
17
19
|
|
18
20
|
def find_most_relevant_file_and_line_from_exception(exception)
|
data/lib/rorvswild/metrics.rb
CHANGED
@@ -1,15 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module RorVsWild
|
2
4
|
module Plugin
|
3
5
|
class ActionController
|
4
|
-
|
6
|
+
@installed = false
|
7
|
+
|
8
|
+
def self.setup(agent)
|
5
9
|
return if @installed
|
6
10
|
return unless defined?(::ActionController::Base)
|
7
11
|
::ActionController::Base.around_action(&method(:around_action))
|
8
|
-
::ActionController::Base.rescue_from(StandardError) { |ex| RorVsWild::Plugin::ActionController.after_exception(ex, self) }
|
9
|
-
|
10
12
|
if defined?(::ActionController::API) && ::ActionController::API.respond_to?(:around_action)
|
11
13
|
::ActionController::API.around_action(&method(:around_action))
|
12
|
-
::ActionController::API.rescue_from(StandardError) { |ex| RorVsWild::Plugin::ActionController.after_exception(ex, self) }
|
13
14
|
end
|
14
15
|
@installed = true
|
15
16
|
end
|
@@ -24,42 +25,19 @@ module RorVsWild
|
|
24
25
|
section.file = RorVsWild.agent.locator.relative_path(section.file)
|
25
26
|
section.commands << "#{controller.class}##{method_name}"
|
26
27
|
end
|
27
|
-
|
28
|
+
if execution = RorVsWild.agent.current_execution
|
29
|
+
execution.name = controller_action
|
30
|
+
execution.controller = controller
|
31
|
+
end
|
28
32
|
end
|
29
33
|
block.call
|
34
|
+
rescue => exception
|
35
|
+
RorVsWild.agent.current_execution&.add_exception(exception)
|
36
|
+
raise
|
30
37
|
ensure
|
31
38
|
RorVsWild::Section.stop
|
32
39
|
end
|
33
40
|
end
|
34
|
-
|
35
|
-
def self.after_exception(exception, controller)
|
36
|
-
if hash = RorVsWild.agent.push_exception(exception)
|
37
|
-
hash[:session] = controller.session.to_hash
|
38
|
-
hash[:parameters] = controller.request.filtered_parameters
|
39
|
-
hash[:request] = {
|
40
|
-
headers: extract_http_headers(controller.request.filtered_env),
|
41
|
-
name: "#{controller.class}##{controller.action_name}",
|
42
|
-
method: controller.request.method,
|
43
|
-
url: controller.request.url,
|
44
|
-
}
|
45
|
-
end
|
46
|
-
raise exception
|
47
|
-
end
|
48
|
-
|
49
|
-
def self.extract_http_headers(headers)
|
50
|
-
headers.reduce({}) do |hash, (name, value)|
|
51
|
-
if name.index("HTTP_".freeze) == 0 && name != "HTTP_COOKIE".freeze
|
52
|
-
hash[format_header_name(name)] = value
|
53
|
-
end
|
54
|
-
hash
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
HEADER_REGEX = /^HTTP_/.freeze
|
59
|
-
|
60
|
-
def self.format_header_name(name)
|
61
|
-
name.sub(HEADER_REGEX, ''.freeze).split("_".freeze).map(&:capitalize).join("-".freeze)
|
62
|
-
end
|
63
41
|
end
|
64
42
|
end
|
65
43
|
end
|
@@ -1,9 +1,11 @@
|
|
1
1
|
module RorVsWild
|
2
2
|
module Plugin
|
3
3
|
class ActionMailer
|
4
|
-
|
4
|
+
@installed = false
|
5
|
+
|
6
|
+
def self.setup(agent)
|
5
7
|
return if @installed
|
6
|
-
return unless defined?(
|
8
|
+
return unless defined?(ActiveSupport::Notifications.subscribe)
|
7
9
|
ActiveSupport::Notifications.subscribe("deliver.action_mailer", new)
|
8
10
|
@installed = true
|
9
11
|
end
|
@@ -3,9 +3,11 @@
|
|
3
3
|
module RorVsWild
|
4
4
|
module Plugin
|
5
5
|
class ActionView
|
6
|
-
|
6
|
+
@installed = false
|
7
|
+
|
8
|
+
def self.setup(agent)
|
7
9
|
return if @installed
|
8
|
-
return unless defined?(
|
10
|
+
return unless defined?(ActiveSupport::Notifications.subscribe)
|
9
11
|
ActiveSupport::Notifications.subscribe("render_partial.action_view", plugin = new)
|
10
12
|
ActiveSupport::Notifications.subscribe("render_template.action_view", plugin)
|
11
13
|
ActiveSupport::Notifications.subscribe("render_collection.action_view", plugin)
|
@@ -14,11 +16,13 @@ module RorVsWild
|
|
14
16
|
|
15
17
|
def start(name, id, payload)
|
16
18
|
return if !payload[:identifier]
|
19
|
+
return if payload[:count] == 0 # render empty collection
|
17
20
|
RorVsWild::Section.start
|
18
21
|
end
|
19
22
|
|
20
23
|
def finish(name, id, payload)
|
21
24
|
return if !payload[:identifier]
|
25
|
+
return if payload[:count] == 0 # render empty collection
|
22
26
|
RorVsWild::Section.stop do |section|
|
23
27
|
section.kind = "view"
|
24
28
|
section.commands << RorVsWild.agent.locator.relative_path(payload[:identifier])
|
@@ -3,14 +3,16 @@
|
|
3
3
|
module RorVsWild
|
4
4
|
module Plugin
|
5
5
|
class ActiveRecord
|
6
|
-
|
6
|
+
@installed = false
|
7
|
+
|
8
|
+
def self.setup(agent)
|
7
9
|
return if @installed
|
8
10
|
setup_callback
|
9
11
|
@installed = true
|
10
12
|
end
|
11
13
|
|
12
14
|
def self.setup_callback
|
13
|
-
return unless defined?(
|
15
|
+
return unless defined?(ActiveSupport::Notifications.subscribe)
|
14
16
|
ActiveSupport::Notifications.subscribe("sql.active_record", new)
|
15
17
|
end
|
16
18
|
|
@@ -38,7 +40,7 @@ module RorVsWild
|
|
38
40
|
section.commands << normalize_sql_query(event.payload[:sql])
|
39
41
|
section.kind = "sql"
|
40
42
|
(parent = Section.current) && parent.children_ms += section.total_ms
|
41
|
-
RorVsWild.agent.add_section(section)
|
43
|
+
execution = RorVsWild.agent.current_execution and execution.add_section(section)
|
42
44
|
end
|
43
45
|
|
44
46
|
SQL_STRING_REGEX = /'((?:''|\\'|[^'])*)'/
|
@@ -46,7 +46,9 @@ module RorVsWild
|
|
46
46
|
|
47
47
|
include RequestQueueTime
|
48
48
|
|
49
|
-
|
49
|
+
@installed = false
|
50
|
+
|
51
|
+
def self.setup(agent)
|
50
52
|
return if @installed
|
51
53
|
Rails.application.config.middleware.unshift(RorVsWild::Plugin::Middleware, nil) if defined?(Rails)
|
52
54
|
@installed = true
|
@@ -57,10 +59,9 @@ module RorVsWild
|
|
57
59
|
end
|
58
60
|
|
59
61
|
def call(env)
|
60
|
-
|
61
|
-
|
62
|
-
RorVsWild.agent.
|
63
|
-
add_queue_time_section(queue_time_ms)
|
62
|
+
execution = RorVsWild::Execution::Request.new(env["ORIGINAL_FULLPATH"])
|
63
|
+
execution.add_queue_time(calculate_queue_time(env))
|
64
|
+
RorVsWild.agent.start_execution(execution)
|
64
65
|
section = RorVsWild::Section.start
|
65
66
|
section.file, section.line = rails_engine_location
|
66
67
|
section.commands << "Rails::Engine#call"
|
@@ -68,24 +69,11 @@ module RorVsWild
|
|
68
69
|
[code, headers, body]
|
69
70
|
ensure
|
70
71
|
RorVsWild::Section.stop
|
71
|
-
|
72
|
+
RorVsWild.agent.stop_execution
|
72
73
|
end
|
73
74
|
|
74
75
|
private
|
75
76
|
|
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
77
|
def calculate_queue_time(env)
|
90
78
|
queue_time_from_header = parse_queue_time_header(env)
|
91
79
|
|
@@ -95,49 +83,6 @@ module RorVsWild
|
|
95
83
|
def rails_engine_location
|
96
84
|
@rails_engine_location = ::Rails::Engine.instance_method(:call).source_location
|
97
85
|
end
|
98
|
-
|
99
|
-
def format_server_timing_header(sections)
|
100
|
-
sections.map do |section|
|
101
|
-
if section.kind == "view"
|
102
|
-
"#{section.kind};dur=#{section.self_ms.round};desc=\"#{section.file}\""
|
103
|
-
else
|
104
|
-
"#{section.kind};dur=#{section.self_ms.round};desc=\"#{section.file}:#{section.line}\""
|
105
|
-
end
|
106
|
-
end.join(", ")
|
107
|
-
end
|
108
|
-
|
109
|
-
def format_server_timing_ascii(sections, total_width = 80)
|
110
|
-
max_time = sections.map(&:self_ms).max
|
111
|
-
chart_width = (total_width * 0.25).to_i
|
112
|
-
rows = sections.map { |section|
|
113
|
-
[
|
114
|
-
section.kind == "view" ? section.file : "#{section.file}:#{section.line}",
|
115
|
-
"█" * (section.self_ms * (chart_width-1) / max_time),
|
116
|
-
"%.1fms" % section.self_ms,
|
117
|
-
]
|
118
|
-
}
|
119
|
-
time_width = rows.map { |cols| cols[2].size }.max + 1
|
120
|
-
label_width = total_width - chart_width - time_width
|
121
|
-
rows.each { |cols| cols[0] = truncate_backwards(cols[0], label_width) }
|
122
|
-
template = "%-#{label_width}s%#{chart_width}s%#{time_width}s"
|
123
|
-
rows.map { |cols| format(template, *cols) }.join("\n")
|
124
|
-
end
|
125
|
-
|
126
|
-
def truncate_backwards(string, width)
|
127
|
-
string.size > width ? "…" + string[-(width - 1)..-1] : string
|
128
|
-
end
|
129
|
-
|
130
|
-
def inject_server_timing(data, headers)
|
131
|
-
return if !data || !data[:send_server_timing] || !(sections = data[:sections])
|
132
|
-
sections = sections.sort_by(&:self_ms).reverse[0,10]
|
133
|
-
headers["Server-Timing"] = format_server_timing_header(sections)
|
134
|
-
if data[:name] && RorVsWild.logger.level <= Logger::Severity::DEBUG
|
135
|
-
RorVsWild.logger.debug(["┤ #{data[:name]} ├".center(80, "─"),
|
136
|
-
format_server_timing_ascii(sections),
|
137
|
-
"─" * 80, nil].join("\n")
|
138
|
-
)
|
139
|
-
end
|
140
|
-
end
|
141
86
|
end
|
142
87
|
end
|
143
88
|
end
|
@@ -1,7 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module RorVsWild
|
2
4
|
module Plugin
|
3
5
|
class Mongo
|
4
|
-
|
6
|
+
@installed = false
|
7
|
+
|
8
|
+
def self.setup(agent)
|
5
9
|
return if @installed
|
6
10
|
return if !defined?(::Mongo::Monitoring::Global)
|
7
11
|
::Mongo::Monitoring::Global.subscribe(::Mongo::Monitoring::COMMAND, Mongo.new)
|
@@ -10,13 +14,10 @@ module RorVsWild
|
|
10
14
|
|
11
15
|
attr_reader :commands
|
12
16
|
|
13
|
-
def initialize
|
14
|
-
@commands = {}
|
15
|
-
end
|
16
|
-
|
17
17
|
def started(event)
|
18
|
-
RorVsWild::Section.start
|
19
|
-
|
18
|
+
section = RorVsWild::Section.start
|
19
|
+
section.kind = "mongo"
|
20
|
+
section.commands << normalize_query(event.command).to_json
|
20
21
|
end
|
21
22
|
|
22
23
|
def failed(event)
|
@@ -28,9 +29,40 @@ module RorVsWild
|
|
28
29
|
end
|
29
30
|
|
30
31
|
def after_query(event)
|
31
|
-
RorVsWild::Section.stop
|
32
|
-
|
33
|
-
|
32
|
+
RorVsWild::Section.stop
|
33
|
+
end
|
34
|
+
|
35
|
+
QUERY_ROOT_KEYS = %w[
|
36
|
+
insert update delete findAndModify bulkWrite
|
37
|
+
find aggregate count distinct
|
38
|
+
create drop listCollections listDatabases dropDatabase
|
39
|
+
startSession commitTransaction abortTransaction
|
40
|
+
filter getMore collection sort
|
41
|
+
]
|
42
|
+
|
43
|
+
def normalize_query(query)
|
44
|
+
query = query.slice(*QUERY_ROOT_KEYS)
|
45
|
+
query["filter"] = normalize_hash(query["filter"]) if query["filter"]
|
46
|
+
query["getMore"] = normalize_value(query["getMore"]) if query["getMore"]
|
47
|
+
query
|
48
|
+
end
|
49
|
+
|
50
|
+
def normalize_hash(hash)
|
51
|
+
(hash = hash.to_h).each { |key, val| hash[key] = normalize_value(val) }
|
52
|
+
end
|
53
|
+
|
54
|
+
def normalize_array(array)
|
55
|
+
array.map { |value| normalize_value(value) }
|
56
|
+
end
|
57
|
+
|
58
|
+
def normalize_value(value)
|
59
|
+
case value
|
60
|
+
when Hash then normalize_hash(value.to_h)
|
61
|
+
when Array then normalize_array(value)
|
62
|
+
when FalseClass then false
|
63
|
+
when TrueClass then true
|
64
|
+
when NilClass then nil
|
65
|
+
else "?"
|
34
66
|
end
|
35
67
|
end
|
36
68
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RorVsWild
|
4
|
+
module Plugin
|
5
|
+
class RailsCache
|
6
|
+
@installed = false
|
7
|
+
|
8
|
+
def self.setup(agent)
|
9
|
+
return if @installed
|
10
|
+
return unless defined?(ActiveSupport::Notifications.subscribe)
|
11
|
+
plugin = new
|
12
|
+
for name in ["write", "read", "delete", "write_multi", "read_multi", "delete_multi", "increment", "decrement"]
|
13
|
+
ActiveSupport::Notifications.subscribe("cache_#{name}.active_support", plugin)
|
14
|
+
end
|
15
|
+
@installed = true
|
16
|
+
end
|
17
|
+
|
18
|
+
def start(name, id, payload)
|
19
|
+
RorVsWild::Section.start do |section|
|
20
|
+
section.commands << name.split(".")[0].delete_prefix("cache_")
|
21
|
+
section.kind = "cache"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def finish(name, id, payload)
|
26
|
+
RorVsWild::Section.stop
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RorVsWild
|
4
|
+
module Plugin
|
5
|
+
class RailsError
|
6
|
+
@installed = false
|
7
|
+
|
8
|
+
def self.setup(agent)
|
9
|
+
return if @installed
|
10
|
+
return if !defined?(Rails.error)
|
11
|
+
return if !defined?(ActiveSupport::ErrorReporter)
|
12
|
+
Rails.error.subscribe(new)
|
13
|
+
@installed = true
|
14
|
+
end
|
15
|
+
|
16
|
+
def report(error, handled: nil, severity: nil, context: nil, source: nil)
|
17
|
+
RorVsWild.record_error(error, context)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -1,18 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module RorVsWild
|
2
4
|
module Plugin
|
3
5
|
class Sidekiq
|
4
|
-
|
6
|
+
INTERNAL_EXCEPTIONS = ["Sidekiq::JobRetry::Handled", "Sidekiq::JobRetry::Skip"]
|
7
|
+
|
8
|
+
def self.setup(agent)
|
5
9
|
if defined?(::Sidekiq)
|
6
10
|
::Sidekiq.configure_server do |config|
|
7
11
|
config.server_middleware { |chain| chain.add(Sidekiq) }
|
8
12
|
end
|
13
|
+
# Prevent RailsError plugin from sending internal Sidekiq exceptions captured by ActiveSupport::ErrorReporter.
|
14
|
+
agent.config[:ignore_exceptions].concat(INTERNAL_EXCEPTIONS)
|
9
15
|
end
|
10
16
|
end
|
11
17
|
|
12
18
|
def call(worker, item, queue, &block)
|
13
19
|
# Wrapped contains the real class name of the ActiveJob wrapper
|
14
20
|
name = item["wrapped".freeze] || item["class".freeze]
|
15
|
-
RorVsWild.agent.measure_job(name, parameters: item["args".freeze]
|
21
|
+
RorVsWild.agent.measure_job(name, parameters: item["args".freeze]) do
|
22
|
+
section = RorVsWild::Section.start
|
23
|
+
section.commands << "#{name}#perform"
|
24
|
+
if perform_method = worker.method(:perform)
|
25
|
+
section.file, section.line = worker.method(:perform).source_location
|
26
|
+
section.file = RorVsWild.agent.locator.relative_path(section.file)
|
27
|
+
end
|
28
|
+
block.call
|
29
|
+
RorVsWild::Section.stop
|
30
|
+
end
|
16
31
|
end
|
17
32
|
end
|
18
33
|
end
|
@@ -15,6 +15,10 @@ module RorVsWild
|
|
15
15
|
elsif Rails.env.development?
|
16
16
|
require "rorvswild/local"
|
17
17
|
RorVsWild::Local.start(config || {})
|
18
|
+
elsif Rails.env.test?
|
19
|
+
require "rorvswild/local"
|
20
|
+
path = "tests/#{DateTime.now.iso8601}"
|
21
|
+
RorVsWild::Local.start({widget: "hidden", queue: {prefix: path}}.merge(config || {}))
|
18
22
|
end
|
19
23
|
end
|
20
24
|
|
data/lib/rorvswild/section.rb
CHANGED
@@ -13,15 +13,15 @@ module RorVsWild
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def self.stop(&block)
|
16
|
-
return
|
16
|
+
return if !(sections = stack) || !(section = sections.pop)
|
17
17
|
block.call(section) if block_given?
|
18
18
|
section.stop
|
19
19
|
current.children_ms += section.total_ms if current
|
20
|
-
RorVsWild.agent.add_section(section)
|
20
|
+
execution = RorVsWild.agent.current_execution and execution.add_section(section)
|
21
21
|
end
|
22
22
|
|
23
23
|
def self.stack
|
24
|
-
|
24
|
+
execution = RorVsWild.agent.current_execution and execution.section_stack
|
25
25
|
end
|
26
26
|
|
27
27
|
def self.current
|
@@ -94,7 +94,7 @@ module RorVsWild
|
|
94
94
|
end
|
95
95
|
|
96
96
|
def as_json(options = nil)
|
97
|
-
{calls: calls, total_runtime: total_ms, children_runtime: children_ms, async_runtime: async_ms, kind: kind,
|
97
|
+
{calls: calls, total_runtime: total_ms, children_runtime: children_ms, async_runtime: async_ms, kind: kind, file: file, line: line, command: command}
|
98
98
|
end
|
99
99
|
|
100
100
|
def to_json(options = {})
|
data/lib/rorvswild/version.rb
CHANGED
data/lib/rorvswild.rb
CHANGED
@@ -7,6 +7,8 @@ require "rorvswild/section"
|
|
7
7
|
require "rorvswild/client"
|
8
8
|
require "rorvswild/plugins"
|
9
9
|
require "rorvswild/queue"
|
10
|
+
require "rorvswild/error"
|
11
|
+
require "rorvswild/execution"
|
10
12
|
require "rorvswild/agent"
|
11
13
|
|
12
14
|
module RorVsWild
|
@@ -61,7 +63,7 @@ module RorVsWild
|
|
61
63
|
end
|
62
64
|
|
63
65
|
def self.send_server_timing=(boolean)
|
64
|
-
|
66
|
+
warn "[DEPRECATION] `RorVsWild.send_server_timing=` is deprecated and is no longer supported."
|
65
67
|
end
|
66
68
|
|
67
69
|
def self.initialize_logger(destination = nil)
|
metadata
CHANGED
@@ -1,15 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rorvswild
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexis Bernard
|
8
8
|
- Antoine Marguerie
|
9
|
-
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
13
12
|
dependencies: []
|
14
13
|
description: Performances and errors insights for rails developers.
|
15
14
|
email:
|
@@ -28,6 +27,8 @@ files:
|
|
28
27
|
- lib/rorvswild/agent.rb
|
29
28
|
- lib/rorvswild/client.rb
|
30
29
|
- lib/rorvswild/deployment.rb
|
30
|
+
- lib/rorvswild/error.rb
|
31
|
+
- lib/rorvswild/execution.rb
|
31
32
|
- lib/rorvswild/host.rb
|
32
33
|
- lib/rorvswild/installer.rb
|
33
34
|
- lib/rorvswild/local.rb
|
@@ -57,6 +58,8 @@ files:
|
|
57
58
|
- lib/rorvswild/plugin/middleware.rb
|
58
59
|
- lib/rorvswild/plugin/mongo.rb
|
59
60
|
- lib/rorvswild/plugin/net_http.rb
|
61
|
+
- lib/rorvswild/plugin/rails_cache.rb
|
62
|
+
- lib/rorvswild/plugin/rails_error.rb
|
60
63
|
- lib/rorvswild/plugin/redis.rb
|
61
64
|
- lib/rorvswild/plugin/resque.rb
|
62
65
|
- lib/rorvswild/plugin/sidekiq.rb
|
@@ -71,7 +74,6 @@ licenses:
|
|
71
74
|
metadata:
|
72
75
|
source_code_uri: https://github.com/BaseSecrete/rorvswild
|
73
76
|
changelog_uri: https://github.com/BaseSecrete/rorvswild/blob/master/CHANGELOG.md
|
74
|
-
post_install_message:
|
75
77
|
rdoc_options: []
|
76
78
|
require_paths:
|
77
79
|
- lib
|
@@ -86,8 +88,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
86
88
|
- !ruby/object:Gem::Version
|
87
89
|
version: '0'
|
88
90
|
requirements: []
|
89
|
-
rubygems_version: 3.
|
90
|
-
signing_key:
|
91
|
+
rubygems_version: 3.6.7
|
91
92
|
specification_version: 4
|
92
93
|
summary: Ruby on Rails applications monitoring
|
93
94
|
test_files: []
|