rorvswild 1.5.1 → 1.5.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9273a6bd33ffb223f1d894975c3d25ad0e4f291295e3267fb6d995ad367b777a
4
- data.tar.gz: 3e32db66b9ee0984352b5e559efa94b3b6a2f35b9c43af0631a1c95a3ecdb6ba
3
+ metadata.gz: 916cb5126d5199d7a1102a88638a22a1d6016d3e7b840097a7126a1fabdf58af
4
+ data.tar.gz: c083a04454fa230329e99014c6daaf20239247619d24ab6a1511df2e0ed83bff
5
5
  SHA512:
6
- metadata.gz: 53433ea46f20730ee3813ecac8437761fb700645e2c9e4ced1a69c67dafe22e1f6ec3905fa7d320798b984fdaecd1c4c252c6c2373a465f4788a0a9e905edebe
7
- data.tar.gz: 8b27c4b3eb3e4f37a5e2c4dbacce88c52ff022ecd7cacf328fe39f7466bef8aaa9d35739c369481368f5ac147b62d73ab41a2d6b0a4ea979720ef0a8ab94215a
6
+ metadata.gz: 6b49155f8d473586b276d20e12c18f9f302fe3137a96fbcdcb07d123a4bccf084040ce3d092432441460a3e6ac05078dfda306967818f2de717dbb74191ec69c
7
+ data.tar.gz: 963bccf81ed0f4ed215693e97055df9dc0486f104cefb4a83a2af6c1c5d6a5403048720c4f43e8c45ae77cbb788e534322f5656a4b9354cc45a7f87364af34b9
data/README.md CHANGED
@@ -32,11 +32,11 @@ Signup on https://www.rorvswild.com and create an app to get one.
32
32
 
33
33
  * Add in your Gemfile `gem "rorvswild"`
34
34
  * Run `bundle install` in you terminal
35
- * Run `rorvswild-setup API_KEY` in you terminal
35
+ * Run `rorvswild-install API_KEY` in you terminal
36
36
  * Deploy/Restart your app
37
37
  * Make a few requests and refresh your app page on rorvswild.com to view the dashboard.
38
38
 
39
- The `rorvswild-setup` command creates a `config/rorvswild.yml` file.
39
+ The `rorvswild-install` command creates a `config/rorvswild.yml` file.
40
40
 
41
41
  If you prefer to use an initializer, you can do the following:
42
42
 
@@ -167,6 +167,32 @@ Finally here is the list of all plugins you can ignore :
167
167
  - Resque
168
168
  - Sidekiq
169
169
 
170
+ #### Change logger
171
+
172
+ By default RorVsWild uses `Rails.logger` or standard output. However in some cases you want to isolate RorVsWild's logs.
173
+ To do that, you have to specifiy the log destination via the `logger` option :
174
+
175
+ ```yaml
176
+ # config/rorvswild.yml
177
+ production:
178
+ api_key: API_KEY
179
+ logger: log/rorvswild.yml
180
+ ```
181
+
182
+ Here is the equivalent if you prefer initialising RorVsWild manually :
183
+
184
+ ```ruby
185
+ # config/initializers/rorvswild.rb
186
+ RorVsWild.start(api_key: "API_KEY", logger: "log/rorvswild.log")
187
+ ```
188
+
189
+ In the case you want a custom logger such as Syslog, you can only do it by initialising it manually :
190
+
191
+ ```ruby
192
+ # config/initializers/rorvswild.rb
193
+ RorVsWild.start(api_key: "API_KEY", logger: Logger::Syslog.new)
194
+ ```
195
+
170
196
  ## Contributing
171
197
 
172
198
  1. Fork it ( https://github.com/[my-github-username]/rorvswild/fork )
@@ -40,7 +40,7 @@ module RorVsWild
40
40
  end
41
41
 
42
42
  def self.initialize_logger(destination = nil)
43
- if destination.is_a?(Logger)
43
+ if destination.respond_to?(:info) && destination.respond_to?(:warn) && destination.respond_to?(:error)
44
44
  destination
45
45
  elsif destination
46
46
  Logger.new(destination)
@@ -54,6 +54,16 @@ module RorVsWild
54
54
  def self.clock_milliseconds
55
55
  Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond)
56
56
  end
57
+
58
+ def self.check
59
+ api_key = RorVsWild.agent.config[:api_key]
60
+ return puts "You API key is missing and has to be defined in config/rorvswild.yml." if !api_key || api_key.empty?
61
+ puts case response = agent.client.post("/jobs", jobs: [{sections: [], name: "RorVsWild.check", runtime: 0}])
62
+ when Net::HTTPOK then "Connection to RorVsWild works fine !"
63
+ when Net::HTTPUnauthorized then "Wrong API key"
64
+ else puts "Something went wrong: #{response.inspect}"
65
+ end
66
+ end
57
67
  end
58
68
 
59
69
  if defined?(Rails)
@@ -48,11 +48,11 @@ module RorVsWild
48
48
  end
49
49
 
50
50
  def measure_block(name, kind = "code".freeze, &block)
51
- data[:name] ? measure_section(name, kind: kind, &block) : measure_job(name, &block)
51
+ current_data ? measure_section(name, kind: kind, &block) : measure_job(name, &block)
52
52
  end
53
53
 
54
54
  def measure_section(name, kind: "code", appendable_command: false, &block)
55
- return block.call unless data[:name]
55
+ return block.call unless current_data
56
56
  begin
57
57
  RorVsWild::Section.start do |section|
58
58
  section.appendable_command = appendable_command
@@ -66,29 +66,27 @@ module RorVsWild
66
66
  end
67
67
 
68
68
  def measure_job(name, parameters: nil, &block)
69
- return measure_section(name, &block) if data[:name] # For recursive jobs
69
+ return measure_section(name, &block) if current_data # For recursive jobs
70
70
  return block.call if ignored_job?(name)
71
- initialize_data(name)
71
+ initialize_data[:name] = name
72
72
  begin
73
73
  block.call
74
74
  rescue Exception => ex
75
75
  push_exception(ex, parameters: parameters)
76
76
  raise
77
77
  ensure
78
- data[:runtime] = RorVsWild.clock_milliseconds - data[:started_at]
78
+ current_data[:runtime] = RorVsWild.clock_milliseconds - current_data[:started_at]
79
79
  post_job
80
80
  end
81
81
  end
82
82
 
83
- def start_request(payload)
84
- return if data[:name]
85
- initialize_data(payload[:name])
86
- data[:path] = payload[:path]
83
+ def start_request
84
+ current_data || initialize_data
87
85
  end
88
86
 
89
87
  def stop_request
90
- return unless data[:name]
91
- data[:runtime] = RorVsWild.clock_milliseconds - data[:started_at]
88
+ return unless current_data
89
+ current_data[:runtime] = RorVsWild.clock_milliseconds - current_data[:started_at]
92
90
  post_request
93
91
  end
94
92
 
@@ -107,21 +105,21 @@ module RorVsWild
107
105
 
108
106
  def push_exception(exception, options = nil)
109
107
  return if ignored_exception?(exception)
110
- data[:error] = exception_to_hash(exception)
111
- data[:error].merge!(options) if options
112
- data[:error]
108
+ current_data[:error] = exception_to_hash(exception)
109
+ current_data[:error].merge!(options) if options
110
+ current_data[:error]
113
111
  end
114
112
 
115
- def data
116
- Thread.current[:rorvswild_data] ||= {}
113
+ def current_data
114
+ Thread.current[:rorvswild_data]
117
115
  end
118
116
 
119
117
  def add_section(section)
120
- return unless data[:sections]
121
- if sibling = data[:sections].find { |s| s.sibling?(section) }
118
+ return unless current_data[:sections]
119
+ if sibling = current_data[:sections].find { |s| s.sibling?(section) }
122
120
  sibling.merge(section)
123
121
  else
124
- data[:sections] << section
122
+ current_data[:sections] << section
125
123
  end
126
124
  end
127
125
 
@@ -139,11 +137,8 @@ module RorVsWild
139
137
 
140
138
  private
141
139
 
142
- def initialize_data(name)
143
- data[:name] = name
144
- data[:sections] = []
145
- data[:section_stack] = []
146
- data[:started_at] = RorVsWild.clock_milliseconds
140
+ def initialize_data
141
+ Thread.current[:rorvswild_data] = {sections: [], section_stack: [], started_at: RorVsWild.clock_milliseconds}
147
142
  end
148
143
 
149
144
  def cleanup_data
@@ -153,7 +148,7 @@ module RorVsWild
153
148
  end
154
149
 
155
150
  def post_request
156
- queue.push_request(cleanup_data)
151
+ (data = cleanup_data) && data[:name] && queue.push_request(data)
157
152
  end
158
153
 
159
154
  def post_job
@@ -21,12 +21,13 @@ module RorVsWild
21
21
  @connection_count = 0
22
22
  @mutex = Mutex.new
23
23
  @config = config
24
+ @headers = {"Content-Type" => "application/json", "X-Gem-Version" => RorVsWild::VERSION}
25
+ @headers["X-Rails-Version"] = Rails.version if defined?(Rails)
24
26
  end
25
27
 
26
28
  def post(path, data)
27
29
  uri = URI(api_url + path)
28
- post = Net::HTTP::Post.new(uri.path, "X-Gem-Version".freeze => RorVsWild::VERSION)
29
- post.content_type = "application/json".freeze
30
+ post = Net::HTTP::Post.new(uri.path, @headers)
30
31
  post.basic_auth(nil, api_key)
31
32
  post.body = data.to_json
32
33
  transmit(post)
@@ -46,6 +47,7 @@ module RorVsWild
46
47
 
47
48
  def take_or_create_connection
48
49
  if http = take_connection
50
+ http.start unless http.active?
49
51
  http
50
52
  elsif @connection_count < max_connections
51
53
  @connection_count += 1
@@ -57,6 +59,8 @@ module RorVsWild
57
59
  if http = take_or_create_connection
58
60
  http.request(request)
59
61
  end
62
+ rescue Exception => ex
63
+ RorVsWild.logger.error(ex.full_message)
60
64
  ensure
61
65
  release_connection(http)
62
66
  end
@@ -65,6 +69,7 @@ module RorVsWild
65
69
  uri = URI(api_url)
66
70
  http = Net::HTTP.new(uri.host, uri.port)
67
71
  http.open_timeout = timeout
72
+ http.keep_alive_timeout = 5
68
73
 
69
74
  if uri.scheme == HTTPS
70
75
  # Disable peer verification while there is a memory leak with OpenSSL
@@ -38,6 +38,7 @@ production:
38
38
  # - Redis
39
39
  # - Resque
40
40
  # - Sidekiq
41
+ # logger: log/rorvswild.log # By default it uses Rails.logger or Logger.new(STDOUT)
41
42
  YAML
42
43
  end
43
44
  end
@@ -34,15 +34,15 @@ module RorVsWild
34
34
  end
35
35
 
36
36
  def relative_path(path)
37
- path.index(current_path) == 0 ? path.sub(current_path, "".freeze) : path
37
+ path.start_with?(current_path) ? path.sub(current_path, "".freeze) : path
38
38
  end
39
39
 
40
40
  def relevant_path?(path)
41
- path.index(current_path) == 0 && !irrelevant_path?(path)
41
+ path.start_with?(current_path) && !irrelevant_path?(path)
42
42
  end
43
43
 
44
44
  def irrelevant_path?(path)
45
- irrelevant_paths.any? { |irrelevant_path| path.index(irrelevant_path) }
45
+ path.start_with?(*irrelevant_paths)
46
46
  end
47
47
 
48
48
  def irrelevant_paths
@@ -52,7 +52,7 @@ module RorVsWild
52
52
  private
53
53
 
54
54
  def initialize_irrelevant_paths
55
- array = ["RUBYLIB", "GEM_HOME", "GEM_PATH", "BUNDLER_ORIG_PATH", "BUNDLER_ORIG_GEM_PATH"].flat_map do |name|
55
+ array = ["RUBYLIB", "GEM_HOME", "GEM_PATH", "BUNDLER_ORIG_GEM_PATH"].flat_map do |name|
56
56
  ENV[name].split(":".freeze) if ENV[name]
57
57
  end
58
58
  array += [heroku_ruby_lib_path] if File.exists?(heroku_ruby_lib_path)
@@ -4,29 +4,23 @@ module RorVsWild
4
4
  def self.setup
5
5
  return if @installed
6
6
  return unless defined?(::ActionController::Base)
7
- ActiveSupport::Notifications.subscribe("process_action.action_controller", new)
7
+ ::ActionController::API.around_action(&method(:around_action))
8
8
  ::ActionController::Base.around_action(&method(:around_action))
9
+ ::ActionController::API.rescue_from(StandardError) { |ex| RorVsWild::Plugin::ActionController.after_exception(ex, self) }
9
10
  ::ActionController::Base.rescue_from(StandardError) { |ex| RorVsWild::Plugin::ActionController.after_exception(ex, self) }
10
11
  @installed = true
11
12
  end
12
13
 
13
- def self.after_exception(exception, controller)
14
- if hash = RorVsWild.agent.push_exception(exception)
15
- hash[:session] = controller.session.to_hash
16
- hash[:parameters] = controller.request.filtered_parameters
17
- hash[:environment_variables] = extract_http_headers(controller.request.filtered_env)
18
- end
19
- raise exception
20
- end
21
-
22
14
  def self.around_action(controller, block)
15
+ controller_action = "#{controller.class}##{controller.action_name}"
16
+ return block.call if RorVsWild.agent.ignored_request?(controller_action)
23
17
  begin
24
18
  RorVsWild::Section.start do |section|
25
- method_name = controller.method_for_action(controller.action_name)
19
+ method_name = controller.send(:method_for_action, controller.action_name)
26
20
  section.file, section.line = controller.method(method_name).source_location
27
21
  section.file = RorVsWild.agent.locator.relative_path(section.file)
28
22
  section.command = "#{controller.class}##{method_name}"
29
- section.kind = "code".freeze
23
+ RorVsWild.agent.current_data[:name] = controller_action
30
24
  end
31
25
  block.call
32
26
  ensure
@@ -34,15 +28,13 @@ module RorVsWild
34
28
  end
35
29
  end
36
30
 
37
- # Payload: controller, action, params, format, method, path
38
- def start(name, id, payload)
39
- if !RorVsWild.agent.ignored_request?(name = "#{payload[:controller]}##{payload[:action]}")
40
- RorVsWild.agent.start_request(name: name, path: payload[:path])
31
+ def self.after_exception(exception, controller)
32
+ if hash = RorVsWild.agent.push_exception(exception)
33
+ hash[:session] = controller.session.to_hash
34
+ hash[:parameters] = controller.request.filtered_parameters
35
+ hash[:environment_variables] = extract_http_headers(controller.request.filtered_env)
41
36
  end
42
- end
43
-
44
- def finish(name, id, payload)
45
- RorVsWild.agent.stop_request
37
+ raise exception
46
38
  end
47
39
 
48
40
  def self.extract_http_headers(headers)
@@ -1,6 +1,6 @@
1
1
  module RorVsWild
2
2
  module Plugin
3
- module ActiveJob
3
+ class ActiveJob
4
4
  def self.setup
5
5
  return if @installed
6
6
  return unless defined?(::ActiveJob::Base)
@@ -9,7 +9,17 @@ module RorVsWild
9
9
  end
10
10
 
11
11
  def self.around_perform(job, block)
12
- RorVsWild.agent.measure_job(job.class.name, parameters: job.arguments, &block)
12
+ RorVsWild.agent.measure_job(job.class.name, parameters: job.arguments) do
13
+ begin
14
+ section = RorVsWild::Section.start
15
+ section.command = "#{job.class}#perform"
16
+ section.file, section.line = job.method(:perform).source_location
17
+ section.file = RorVsWild.agent.locator.relative_path(section.file)
18
+ block.call
19
+ ensure
20
+ RorVsWild::Section.stop
21
+ end
22
+ end
13
23
  end
14
24
  end
15
25
  end
@@ -0,0 +1,31 @@
1
+ module RorVsWild
2
+ module Plugin
3
+ class Middleware
4
+ def self.setup
5
+ return if @installed
6
+ Rails.application.config.middleware.unshift(RorVsWild::Plugin::Middleware, nil) if defined?(Rails)
7
+ @installed = true
8
+ end
9
+
10
+ def initialize(app, config)
11
+ @app, @config = app, config
12
+ end
13
+
14
+ def call(env)
15
+ RorVsWild.agent.start_request
16
+ RorVsWild.agent.current_data[:path] = env["ORIGINAL_FULLPATH".freeze]
17
+ section = RorVsWild::Section.start
18
+ section.file, section.line = rails_engine_location
19
+ section.command = "Rails::Engine#call".freeze
20
+ @app.call(env)
21
+ ensure
22
+ RorVsWild::Section.stop
23
+ RorVsWild.agent.stop_request
24
+ end
25
+
26
+ def rails_engine_location
27
+ @rails_engine_location = ::Rails::Engine.instance_method(:call).source_location
28
+ end
29
+ end
30
+ end
31
+ end
@@ -58,7 +58,6 @@ module RorVsWild
58
58
  end
59
59
 
60
60
  def flush
61
- RorVsWild.logger.info("RorVsWild::Queue#flush".freeze)
62
61
  data = pull_jobs and client.post("/jobs", jobs: data)
63
62
  data = pull_requests and client.post("/requests", requests: data)
64
63
  end
@@ -6,12 +6,12 @@ module RorVsWild
6
6
  def self.start(&block)
7
7
  section = Section.new
8
8
  block.call(section) if block_given?
9
- stack.push(section)
9
+ stack && stack.push(section)
10
10
  section
11
11
  end
12
12
 
13
13
  def self.stop(&block)
14
- section = stack.pop
14
+ return unless stack && section = stack.pop
15
15
  block.call(section) if block_given?
16
16
  section.total_runtime = RorVsWild.clock_milliseconds - section.started_at
17
17
  current.children_runtime += section.total_runtime if current
@@ -19,17 +19,18 @@ module RorVsWild
19
19
  end
20
20
 
21
21
  def self.stack
22
- RorVsWild.agent.data[:section_stack] ||= []
22
+ (data = RorVsWild.agent.current_data) && data[:section_stack]
23
23
  end
24
24
 
25
25
  def self.current
26
- stack.last
26
+ (sections = stack) && sections.last
27
27
  end
28
28
 
29
29
  def initialize
30
30
  @calls = 1
31
31
  @total_runtime = 0
32
32
  @children_runtime = 0
33
+ @kind = "code".freeze
33
34
  @started_at = RorVsWild.clock_milliseconds
34
35
  location = RorVsWild.agent.locator.find_most_relevant_location(caller_locations)
35
36
  @file = RorVsWild.agent.locator.relative_path(location.path)
@@ -1,3 +1,3 @@
1
1
  module RorVsWild
2
- VERSION = "1.5.1".freeze
2
+ VERSION = "1.5.6".freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rorvswild
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.1
4
+ version: 1.5.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexis Bernard
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-04 00:00:00.000000000 Z
11
+ date: 2020-06-09 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Performances and quality insights for rails developers.
14
14
  email:
@@ -46,6 +46,7 @@ files:
46
46
  - lib/rorvswild/plugin/delayed_job.rb
47
47
  - lib/rorvswild/plugin/elasticsearch.rb
48
48
  - lib/rorvswild/plugin/faktory.rb
49
+ - lib/rorvswild/plugin/middleware.rb
49
50
  - lib/rorvswild/plugin/mongo.rb
50
51
  - lib/rorvswild/plugin/net_http.rb
51
52
  - lib/rorvswild/plugin/redis.rb