rorvswild 1.5.0 → 1.5.5

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 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