rorvswild 1.5.0 → 1.5.5

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: 875777242efff56c2c1e19d2cf7248e7cb08f8f69c8c35e305e2fc2131b7563f
4
- data.tar.gz: c04de4df6091f8b364fffd020deaf1fc50983dde67f57e45c23d4db8af867d71
3
+ metadata.gz: c48c5689b1cc41d4954efcf44a2c415ee4a803da60f6beb36424f9103d06d72e
4
+ data.tar.gz: 62da47461a2d4dc9e182aebe765d6dda46e188ea57687bcd8298e61acf8d51d6
5
5
  SHA512:
6
- metadata.gz: 4ab22a6282828a0b9f682cdffe2484e63074a68fc4c1bb53b7c8a0a02b0817ef2cf74001491d7345b8a1de29328ddf4e9178bd303a594e835de0423fd625e551
7
- data.tar.gz: d3e3846d7a7e6d39b51795e14e238826fee503a0a0cfcfd6b56875b30b5dd0f3774453e8de408e6947b16172d0a852850e1f99615987416d098317975281df02
6
+ metadata.gz: e00fa04cd7566a8f64fe7d69ebc2a36acabec87619eee6e05ef2534ea429614a2be1ac7cd102b45440f5aa81333cdc6595f30b77c277ef7b7c2b832785ac48b8
7
+ data.tar.gz: 8e1b010d4057131da1178041640b095dea3f90c685f50d4f8c15fcda2ab0257c37cce986e72a5eca68154ecb39d78f1fd3e5912d2493f9a03400182b676563af
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 )
@@ -20,7 +20,7 @@ module RorVsWild
20
20
  end
21
21
 
22
22
  def self.logger
23
- @logger ||= Logger.new(STDOUT)
23
+ @logger ||= initialize_logger
24
24
  end
25
25
 
26
26
  def self.measure_code(code)
@@ -39,17 +39,31 @@ module RorVsWild
39
39
  agent.record_error(exception, extra_details) if agent
40
40
  end
41
41
 
42
- def self.initialize_logger(destination)
43
- if destination
42
+ def self.initialize_logger(destination = nil)
43
+ if destination.respond_to?(:info) && destination.respond_to?(:warn) && destination.respond_to?(:error)
44
+ destination
45
+ elsif destination
44
46
  Logger.new(destination)
45
47
  elsif defined?(Rails)
46
- Logger.new(Rails.root + "log/rorvswild.log")
48
+ Rails.logger
49
+ else
50
+ Logger.new(STDOUT)
47
51
  end
48
52
  end
49
53
 
50
54
  def self.clock_milliseconds
51
55
  Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond)
52
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
53
67
  end
54
68
 
55
69
  if defined?(Rails)
@@ -37,7 +37,7 @@ module RorVsWild
37
37
  for name in RorVsWild::Plugin.constants
38
38
  next if config[:ignore_plugins] && config[:ignore_plugins].include?(name.to_s)
39
39
  if (plugin = RorVsWild::Plugin.const_get(name)).respond_to?(:setup)
40
- RorVsWild.logger.info("Load plugin #{name}")
40
+ RorVsWild.logger.info("Setup RorVsWild::Plugin::#{name}")
41
41
  plugin.setup
42
42
  end
43
43
  end
@@ -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,21 @@ 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)
8
7
  ::ActionController::Base.around_action(&method(:around_action))
9
8
  ::ActionController::Base.rescue_from(StandardError) { |ex| RorVsWild::Plugin::ActionController.after_exception(ex, self) }
10
9
  @installed = true
11
10
  end
12
11
 
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
12
  def self.around_action(controller, block)
13
+ controller_action = "#{controller.class}##{controller.action_name}"
14
+ return block.call if RorVsWild.agent.ignored_request?(controller_action)
23
15
  begin
24
16
  RorVsWild::Section.start do |section|
25
17
  method_name = controller.method_for_action(controller.action_name)
26
18
  section.file, section.line = controller.method(method_name).source_location
27
19
  section.file = RorVsWild.agent.locator.relative_path(section.file)
28
20
  section.command = "#{controller.class}##{method_name}"
29
- section.kind = "code".freeze
21
+ RorVsWild.agent.current_data[:name] = controller_action
30
22
  end
31
23
  block.call
32
24
  ensure
@@ -34,15 +26,13 @@ module RorVsWild
34
26
  end
35
27
  end
36
28
 
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])
29
+ def self.after_exception(exception, controller)
30
+ if hash = RorVsWild.agent.push_exception(exception)
31
+ hash[:session] = controller.session.to_hash
32
+ hash[:parameters] = controller.request.filtered_parameters
33
+ hash[:environment_variables] = extract_http_headers(controller.request.filtered_env)
41
34
  end
42
- end
43
-
44
- def finish(name, id, payload)
45
- RorVsWild.agent.stop_request
35
+ raise exception
46
36
  end
47
37
 
48
38
  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.0".freeze
2
+ VERSION = "1.5.5".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.0
4
+ version: 1.5.5
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-02-14 00:00:00.000000000 Z
11
+ date: 2020-05-29 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