rorvswild 1.9.2 → 1.10.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/lib/rorvswild/agent.rb +33 -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/installer.rb +1 -1
- data/lib/rorvswild/local/local.html.erb +1 -1
- data/lib/rorvswild/local/queue.rb +26 -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 +4 -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 +3 -1
- data/lib/rorvswild.rb +3 -1
- metadata +6 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ec6464a7193ffe1e78cc6d84804a74e37dd66e20f086b357215e143cca8e3339
|
|
4
|
+
data.tar.gz: 0547a433e44c778c2f7199be0e6532325e572ac868f85b2209dd99eea1ba4593
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5929a6e6deb9fab72c05e5446363ed3cab3368c2b3c7a2e68ef9e4fa58b0fcc1736421936b6153a8eab650f33a4337bb691744af4739bd99dad63db9c1dbdb2d
|
|
7
|
+
data.tar.gz: d5533fe4bc53ec97eed6d52e8637a7f231ffed0d56af0716d7e1713d0d3042d88620c201d50edb61e29af26bd786d666d30a403d54ff9b64d046b15ae180fb71
|
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,32 @@ 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
|
|
116
|
+
RorVsWild::Section.start
|
|
119
117
|
end
|
|
120
118
|
|
|
121
|
-
def
|
|
122
|
-
return unless
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
119
|
+
def stop_execution
|
|
120
|
+
return unless execution = current_execution
|
|
121
|
+
RorVsWild::Section.stop
|
|
122
|
+
execution.stop
|
|
123
|
+
case execution
|
|
124
|
+
when Execution::Job then queue_job
|
|
125
|
+
when Execution::Request then queue_request
|
|
126
|
+
end
|
|
127
127
|
end
|
|
128
128
|
|
|
129
129
|
def catch_error(context = nil, &block)
|
|
@@ -136,44 +136,21 @@ module RorVsWild
|
|
|
136
136
|
end
|
|
137
137
|
|
|
138
138
|
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]
|
|
139
|
+
if !ignored_exception?(exception) && current_execution&.error&.exception != exception
|
|
140
|
+
queue_error(Error.new(exception, context).as_json)
|
|
141
|
+
end
|
|
148
142
|
end
|
|
149
143
|
|
|
150
144
|
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
|
|
145
|
+
current_execution && current_execution.merge_error_context(hash)
|
|
164
146
|
end
|
|
165
147
|
|
|
166
148
|
def current_data
|
|
167
149
|
Thread.current[:rorvswild_data]
|
|
168
150
|
end
|
|
169
151
|
|
|
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
|
|
152
|
+
def current_execution
|
|
153
|
+
Thread.current[:rorvswild_execution]
|
|
177
154
|
end
|
|
178
155
|
|
|
179
156
|
def ignored_request?(name)
|
|
@@ -186,7 +163,8 @@ module RorVsWild
|
|
|
186
163
|
|
|
187
164
|
def ignored_exception?(exception)
|
|
188
165
|
return false unless config[:ignore_exceptions]
|
|
189
|
-
|
|
166
|
+
class_name = exception.class.to_s
|
|
167
|
+
config[:ignore_exceptions].any? { |str_or_regex| str_or_regex === class_name }
|
|
190
168
|
end
|
|
191
169
|
|
|
192
170
|
#######################
|
|
@@ -195,47 +173,24 @@ module RorVsWild
|
|
|
195
173
|
|
|
196
174
|
private
|
|
197
175
|
|
|
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
176
|
def cleanup_data
|
|
209
|
-
result = Thread.current[:
|
|
210
|
-
Thread.current[:
|
|
177
|
+
result = Thread.current[:rorvswild_execution]
|
|
178
|
+
Thread.current[:rorvswild_execution] = nil
|
|
211
179
|
result
|
|
212
180
|
end
|
|
213
181
|
|
|
214
182
|
def queue_request
|
|
215
|
-
(
|
|
216
|
-
|
|
183
|
+
if (execution = cleanup_data) && execution.name
|
|
184
|
+
queue.push_request(execution.as_json)
|
|
185
|
+
end
|
|
217
186
|
end
|
|
218
187
|
|
|
219
188
|
def queue_job
|
|
220
|
-
queue.push_job(cleanup_data)
|
|
189
|
+
queue.push_job(cleanup_data.as_json)
|
|
221
190
|
end
|
|
222
191
|
|
|
223
192
|
def queue_error(hash)
|
|
224
193
|
queue.push_error(hash)
|
|
225
194
|
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
195
|
end
|
|
241
196
|
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
|
data/lib/rorvswild/installer.rb
CHANGED
|
@@ -52,7 +52,7 @@ production:
|
|
|
52
52
|
# logger: log/rorvswild.log # By default it uses Rails.logger or Logger.new(STDOUT)
|
|
53
53
|
#
|
|
54
54
|
# # Deployment tracking is working without any actions from your part if the Rails app
|
|
55
|
-
# # is inside a Git
|
|
55
|
+
# # is inside a Git repository, is deployed via Capistrano.
|
|
56
56
|
# # In the other cases, you can provide the following details.
|
|
57
57
|
# deployment:
|
|
58
58
|
# revision: <%= "Anything that will return the deployment version" %> # Mandatory
|
|
@@ -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,30 @@ 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
|
+
lines = buffer.reverse.join.lines
|
|
66
|
+
offset = [lines.size - 1, desired_lines].min
|
|
67
|
+
lines[-offset..-1]
|
|
54
68
|
end
|
|
55
69
|
end
|
|
56
70
|
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)
|
|
@@ -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,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.10.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alexis Bernard
|
|
@@ -27,6 +27,8 @@ files:
|
|
|
27
27
|
- lib/rorvswild/agent.rb
|
|
28
28
|
- lib/rorvswild/client.rb
|
|
29
29
|
- lib/rorvswild/deployment.rb
|
|
30
|
+
- lib/rorvswild/error.rb
|
|
31
|
+
- lib/rorvswild/execution.rb
|
|
30
32
|
- lib/rorvswild/host.rb
|
|
31
33
|
- lib/rorvswild/installer.rb
|
|
32
34
|
- lib/rorvswild/local.rb
|
|
@@ -56,6 +58,8 @@ files:
|
|
|
56
58
|
- lib/rorvswild/plugin/middleware.rb
|
|
57
59
|
- lib/rorvswild/plugin/mongo.rb
|
|
58
60
|
- lib/rorvswild/plugin/net_http.rb
|
|
61
|
+
- lib/rorvswild/plugin/rails_cache.rb
|
|
62
|
+
- lib/rorvswild/plugin/rails_error.rb
|
|
59
63
|
- lib/rorvswild/plugin/redis.rb
|
|
60
64
|
- lib/rorvswild/plugin/resque.rb
|
|
61
65
|
- lib/rorvswild/plugin/sidekiq.rb
|
|
@@ -84,7 +88,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
84
88
|
- !ruby/object:Gem::Version
|
|
85
89
|
version: '0'
|
|
86
90
|
requirements: []
|
|
87
|
-
rubygems_version: 3.6.
|
|
91
|
+
rubygems_version: 3.6.9
|
|
88
92
|
specification_version: 4
|
|
89
93
|
summary: Ruby on Rails applications monitoring
|
|
90
94
|
test_files: []
|