rorvswild 1.0.1 → 1.1.0

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
  SHA1:
3
- metadata.gz: 3f8e0e177bc8b3c9645a79f0b4d39fcf27ed804f
4
- data.tar.gz: 31e58a5359e4b691d80d23c23dddfaedb9a3fc76
3
+ metadata.gz: 97aed7e941905d99050aa05b33a2d318b49e1e74
4
+ data.tar.gz: ed86f80358c77f008f3e72301f99c175de6988d3
5
5
  SHA512:
6
- metadata.gz: 39a57beba2498edf1ea8e1790a45991f434cfe89e925717a55c0353500d1d62a4068149510ebb24e197d82c9fa10ae9252bedea1316a0ad17694244688501382
7
- data.tar.gz: bd19b326fb647010c5fba1db667804c50742b12c97ff97d58509a99b7922aed9e80ce170a78165cee50e0a9cc96a8eab45b0d046a0a03e6c964bf904d8739a50
6
+ metadata.gz: b2fd50627532be3543aeb2b1279bcb2e513f1a459749d53e59efd08a434bf5a863167279e446e8a574bc2d608e842f4f862cd50a8f23bbdb6eedebfa3251c192
7
+ data.tar.gz: c6ce663a5ba4c0e15b3da29b875a13ec607aada3d2de8855fb8ed305b6da1d0246579234405aa7e9570b1fb6f3a017f96f265eca32f6980c57929558fa45830e
data/Gemfile CHANGED
@@ -13,3 +13,5 @@ gem "actionpack"
13
13
  gem "activejob"
14
14
 
15
15
  gem "delayed_job"
16
+ gem "sidekiq"
17
+ gem "resque"
@@ -6,33 +6,32 @@ module RorVsWild
6
6
 
7
7
  def self.default_config
8
8
  {
9
- api_url: "https://www.rorvswild.com/api",
9
+ api_url: "https://www.rorvswild.com/api/v1",
10
10
  ignored_exceptions: [],
11
11
  }
12
12
  end
13
13
 
14
14
  attr_reader :api_url, :api_key, :app_id, :app_root, :ignored_exceptions
15
15
 
16
- attr_reader :app_root_regex, :client
16
+ attr_reader :app_root_regex, :client, :queue
17
17
 
18
18
  def initialize(config)
19
19
  config = self.class.default_config.merge(config)
20
20
  @ignored_exceptions = config[:ignored_exceptions]
21
21
  @app_root = config[:app_root]
22
- @logger = config[:logger]
23
22
  @client = Client.new(config)
23
+ @queue = Queue.new(client)
24
24
  cleanup_data
25
25
 
26
26
  if defined?(Rails)
27
- @logger ||= Rails.logger
28
27
  @app_root ||= Rails.root.to_s
29
28
  config = Rails.application.config
30
29
  @ignored_exceptions ||= %w[ActionController::RoutingError] + config.action_dispatch.rescue_responses.map { |(key,value)| key }
31
30
  end
32
31
 
33
- @logger ||= Logger.new(STDERR)
34
32
  @app_root_regex = app_root ? /\A#{app_root}/ : nil
35
33
 
34
+ RorVsWild.logger.info("Start RorVsWild #{RorVsWild::VERSION} from #{app_root}")
36
35
  setup_plugins
37
36
  end
38
37
 
@@ -75,13 +74,13 @@ module RorVsWild
75
74
  end
76
75
  end
77
76
 
78
- def measure_job(name, &block)
77
+ def measure_job(name, parameters: nil, &block)
79
78
  return block.call if data[:name] # Prevent from recursive jobs
80
79
  initialize_data(name)
81
80
  begin
82
81
  block.call
83
82
  rescue Exception => ex
84
- data[:error] = exception_to_hash(ex) if !ignored_exception?(ex)
83
+ push_exception(ex, parameters: parameters)
85
84
  raise
86
85
  ensure
87
86
  data[:runtime] = (Time.now - data[:started_at]) * 1000
@@ -114,9 +113,11 @@ module RorVsWild
114
113
  post_error(exception_to_hash(exception, extra_details))
115
114
  end
116
115
 
117
- def push_exception(exception)
116
+ def push_exception(exception, options = nil)
118
117
  return if ignored_exception?(exception)
119
118
  data[:error] = exception_to_hash(exception)
119
+ data[:error].merge!(options) if options
120
+ data[:error]
120
121
  end
121
122
 
122
123
  def data
@@ -152,11 +153,11 @@ module RorVsWild
152
153
  end
153
154
 
154
155
  def post_request
155
- client.post_async("/requests".freeze, request: cleanup_data)
156
+ queue.push_request(cleanup_data)
156
157
  end
157
158
 
158
159
  def post_job
159
- client.post_async("/jobs".freeze, job: cleanup_data)
160
+ queue.push_job(cleanup_data)
160
161
  end
161
162
 
162
163
  def post_error(hash)
@@ -9,7 +9,7 @@ module RorVsWild
9
9
  end
10
10
 
11
11
  def self.around_perform(job, block)
12
- RorVsWild.measure_block(job.class.name, &block)
12
+ RorVsWild.agent.measure_job(job.class.name, parameters: job.arguments, &block)
13
13
  end
14
14
  end
15
15
  end
@@ -9,7 +9,7 @@ module RorVsWild
9
9
  end
10
10
 
11
11
  def self.around_perform(job, &block)
12
- RorVsWild.measure_block(job.name) { block.call(job) }
12
+ RorVsWild.agent.measure_job(job.name, parameters: job.payload_object) { block.call(job) }
13
13
  end
14
14
  end
15
15
  end
@@ -6,7 +6,7 @@ module RorVsWild
6
6
  end
7
7
 
8
8
  def around_perform_rorvswild(*args, &block)
9
- RorVsWild.measure_block(to_s, &block)
9
+ RorVsWild.agent.measure_job(to_s, parameters: args, &block)
10
10
  end
11
11
  end
12
12
  end
@@ -11,7 +11,8 @@ module RorVsWild
11
11
 
12
12
  def call(worker, item, queue, &block)
13
13
  # Wrapped contains the real class name of the ActiveJob wrapper
14
- RorVsWild.measure_block(item["wrapped".freeze] || item["class".freeze], &block)
14
+ name = item["wrapped".freeze] || item["class".freeze]
15
+ RorVsWild.agent.measure_job(name, parameters: item["args".freeze], &block)
15
16
  end
16
17
  end
17
18
  end
@@ -0,0 +1,71 @@
1
+ module RorVsWild
2
+ class Queue
3
+ SLEEP_TIME = 10
4
+ FLUSH_TRESHOLD = 10
5
+
6
+ attr_reader :mutex, :thread, :client
7
+ attr_reader :requests, :jobs
8
+
9
+ def initialize(client)
10
+ @jobs = []
11
+ @requests = []
12
+ @client = client
13
+ @mutex = Mutex.new
14
+ end
15
+
16
+ def push_job(data)
17
+ push_to(jobs, data)
18
+ end
19
+
20
+ def push_request(data)
21
+ push_to(requests, data)
22
+ end
23
+
24
+ def push_to(array, data)
25
+ mutex.synchronize do
26
+ wakeup_thread if array.push(data).size >= FLUSH_TRESHOLD
27
+ end
28
+ end
29
+
30
+ def pull_jobs
31
+ mutex.synchronize do
32
+ if jobs.size > 0
33
+ result = jobs
34
+ @jobs = []
35
+ return result
36
+ end
37
+ end
38
+ end
39
+
40
+ def pull_requests
41
+ mutex.synchronize do
42
+ if requests.size > 0
43
+ result = requests
44
+ @requests = []
45
+ return result
46
+ end
47
+ end
48
+ end
49
+
50
+ def flush_indefinetely
51
+ sleep(SLEEP_TIME) and flush while true
52
+ rescue Exception => ex
53
+ RorVsWild.logger.error(ex)
54
+ raise
55
+ end
56
+
57
+ def flush
58
+ RorVsWild.logger.info("flush")
59
+ data = pull_jobs and client.post("/jobs", jobs: data)
60
+ data = pull_requests and client.post("/requests", requests: data)
61
+ end
62
+
63
+ def start_thread
64
+ @thread = Thread.new { flush_indefinetely }
65
+ end
66
+
67
+ def wakeup_thread
68
+ (thread && thread.alive?) ? thread.wakeup : start_thread
69
+ end
70
+ end
71
+ end
@@ -1,3 +1,3 @@
1
1
  module RorVsWild
2
- VERSION = "1.0.1".freeze
2
+ VERSION = "1.1.0".freeze
3
3
  end
data/lib/rorvswild.rb CHANGED
@@ -3,17 +3,26 @@ require "rorvswild/location"
3
3
  require "rorvswild/section"
4
4
  require "rorvswild/client"
5
5
  require "rorvswild/plugins"
6
+ require "rorvswild/queue"
6
7
  require "rorvswild/agent"
7
8
 
8
9
  module RorVsWild
9
10
  def self.start(config)
11
+ @logger = initialize_logger(config[:logger])
10
12
  @agent = Agent.new(config)
13
+ rescue Exception => ex
14
+ logger.error(ex)
15
+ raise
11
16
  end
12
17
 
13
18
  def self.agent
14
19
  @agent
15
20
  end
16
21
 
22
+ def self.logger
23
+ @logger ||= Logger.new(STDOUT)
24
+ end
25
+
17
26
  def self.measure_code(code)
18
27
  agent ? agent.measure_code(code) : eval(code)
19
28
  end
@@ -29,6 +38,14 @@ module RorVsWild
29
38
  def self.record_error(exception, extra_details = nil)
30
39
  agent.record_error(exception, extra_details) if agent
31
40
  end
41
+
42
+ def self.initialize_logger(destination)
43
+ if destination
44
+ Logger.new(destination)
45
+ elsif defined?(Rails)
46
+ Logger.new(Rails.root + "log/rorvswild.log")
47
+ end
48
+ end
32
49
  end
33
50
 
34
51
  if defined?(Rails)
@@ -2,7 +2,6 @@ require File.expand_path("#{File.dirname(__FILE__)}/helper")
2
2
 
3
3
  class RorVsWild::MeasureNestedSectionsTest < Minitest::Test
4
4
  include RorVsWildAgentHelper
5
- include TopTests
6
5
 
7
6
  def test_measure_section
8
7
  result = agent.measure_block("root") do
@@ -8,14 +8,25 @@ class RorVsWild::Plugin::ActiveJobTest < Minitest::Test
8
8
  class SampleJob < ::ActiveJob::Base
9
9
  queue_as :default
10
10
 
11
- def perform
11
+ def perform(arg)
12
+ raise "Exception" unless arg
12
13
  end
13
14
  end
14
15
 
15
16
  def test_callback
16
17
  ActiveJob::Base.logger = Logger.new("/dev/null")
17
18
  agent.expects(:post_job)
18
- SampleJob.perform_now
19
+ SampleJob.perform_now(1)
20
+ assert_equal("RorVsWild::Plugin::ActiveJobTest::SampleJob", agent.data[:name])
21
+ end
22
+
23
+ def test_callback_on_exception
24
+ ActiveJob::Base.logger = Logger.new("/dev/null")
25
+ agent.expects(:post_job)
26
+ SampleJob.perform_now(false)
27
+ rescue
28
+ ensure
29
+ assert_equal([false], agent.data[:error][:parameters])
19
30
  end
20
31
  end
21
32
 
@@ -6,30 +6,39 @@ class RorVsWild::Plugin::DelayedJobTest < Minitest::Test
6
6
  include RorVsWildAgentHelper
7
7
 
8
8
  class SampleJob
9
+ def initialize(arg)
10
+ @arg = arg
11
+ end
12
+
9
13
  def perform
14
+ raise "Exception" unless @arg
10
15
  end
11
16
  end
12
17
 
18
+ Delayed::Worker.delay_jobs = false
19
+
13
20
  class SampleBackend
14
21
  include Delayed::Backend::Base
15
22
 
16
- attr_accessor :id, :attempts
23
+ attr_accessor :handler
17
24
 
18
25
  def initialize(options)
19
- end
20
-
21
- def payload_object
22
- SampleJob.new
23
- end
24
-
25
- def destroy
26
+ @payload_object = options[:payload_object]
26
27
  end
27
28
  end
28
29
 
29
30
  def test_callback
30
31
  agent.expects(:post_job)
31
- Delayed::Worker.delay_jobs = false
32
- SampleBackend.enqueue(SampleJob.new)
32
+ SampleBackend.enqueue(SampleJob.new(true))
33
+ assert_equal("RorVsWild::Plugin::DelayedJobTest::SampleJob", agent.data[:name])
34
+ end
35
+
36
+ def test_callback_on_exception
37
+ agent.expects(:post_job)
38
+ SampleBackend.enqueue(job = SampleJob.new(false))
39
+ rescue
40
+ ensure
41
+ assert_equal(job, agent.data[:error][:parameters])
33
42
  end
34
43
  end
35
44
 
@@ -0,0 +1,32 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../helper")
2
+
3
+ require "resque"
4
+
5
+ class RorVsWild::Plugin::ResqueTest < Minitest::Test
6
+ include RorVsWildAgentHelper
7
+
8
+ Resque.inline = true
9
+
10
+ class SampleJob < Resque::Job
11
+ @queue = :default
12
+
13
+ def self.perform(arg)
14
+ raise "Exception" unless arg
15
+ end
16
+ end
17
+
18
+ def test_callback
19
+ agent.expects(:post_job)
20
+ Resque.enqueue(SampleJob, true)
21
+ assert_equal("RorVsWild::Plugin::ResqueTest::SampleJob", agent.data[:name])
22
+ end
23
+
24
+ def test_callback_on_exception
25
+ agent.expects(:post_job)
26
+ Resque.enqueue(SampleJob, false)
27
+ rescue
28
+ ensure
29
+ assert_equal([false], agent.data[:error][:parameters])
30
+ end
31
+ end
32
+
@@ -0,0 +1,36 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../helper")
2
+
3
+ require "sidekiq"
4
+ require "sidekiq/testing"
5
+
6
+ class RorVsWild::Plugin::SidekiqTest < Minitest::Test
7
+ include RorVsWildAgentHelper
8
+
9
+ Sidekiq::Testing.server_middleware do |chain|
10
+ chain.add(RorVsWild::Plugin::Sidekiq)
11
+ end
12
+
13
+ class SampleJob
14
+ include ::Sidekiq::Worker
15
+
16
+ # SampleSidekiqJob.perform_async(1)
17
+ def perform(arg)
18
+ raise "Exception" unless arg
19
+ end
20
+ end
21
+
22
+ def test_callback
23
+ agent.expects(:post_job)
24
+ Sidekiq::Testing.inline! { SampleJob.perform_async(1) }
25
+ assert_equal("RorVsWild::Plugin::SidekiqTest::SampleJob", agent.data[:name])
26
+ end
27
+
28
+ def test_callback_on_exception
29
+ agent.expects(:post_job)
30
+ Sidekiq::Testing.inline! { SampleJob.perform_async(false) }
31
+ rescue
32
+ ensure
33
+ assert_equal([false], agent.data[:error][:parameters])
34
+ end
35
+ end
36
+
@@ -0,0 +1,52 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/helper")
2
+
3
+ class QueueTest < Minitest::Test
4
+ def test_push_job
5
+ queue.thread.expects(:wakeup)
6
+ 10.times { queue.push_job(1) }
7
+ assert_equal(10, queue.jobs.size)
8
+ end
9
+
10
+ def test_push_request
11
+ queue.thread.expects(:wakeup)
12
+ 10.times { queue.push_request(1) }
13
+ assert_equal(10, queue.requests.size)
14
+ end
15
+
16
+ def test_pull_jobs
17
+ queue.push_job(1)
18
+ assert_equal([1], queue.pull_jobs)
19
+ refute(queue.pull_jobs)
20
+ end
21
+
22
+ def test_pull_requests
23
+ queue.push_request(1)
24
+ assert_equal([1], queue.pull_requests)
25
+ refute(queue.pull_requests)
26
+ end
27
+
28
+ def test_flush_when_jobs_are_present
29
+ queue.client.expects(:post)
30
+ queue.push_job(1)
31
+ queue.flush
32
+ end
33
+
34
+ def test_flush_when_requests_are_present
35
+ queue.client.expects(:post)
36
+ queue.push_request(1)
37
+ queue.flush
38
+ end
39
+
40
+ def test_flush_when_empty
41
+ queue.client.expects(:post).never
42
+ queue.flush
43
+ end
44
+
45
+ def queue
46
+ @queue ||= RorVsWild::Queue.new(client)
47
+ end
48
+
49
+ def client
50
+ @client ||= RorVsWild::Client.new({})
51
+ end
52
+ 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.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexis Bernard
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-07-14 00:00:00.000000000 Z
11
+ date: 2017-08-02 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Performances and quality insights for rails developers.
14
14
  email:
@@ -42,6 +42,7 @@ files:
42
42
  - lib/rorvswild/plugin/resque.rb
43
43
  - lib/rorvswild/plugin/sidekiq.rb
44
44
  - lib/rorvswild/plugins.rb
45
+ - lib/rorvswild/queue.rb
45
46
  - lib/rorvswild/rails_loader.rb
46
47
  - lib/rorvswild/section.rb
47
48
  - lib/rorvswild/version.rb
@@ -57,6 +58,9 @@ files:
57
58
  - test/plugin/mongo_test.rb
58
59
  - test/plugin/net_http_test.rb
59
60
  - test/plugin/redis_test.rb
61
+ - test/plugin/resque_test.rb
62
+ - test/plugin/sidekiq_test.rb
63
+ - test/queue_test.rb
60
64
  - test/rorvswild_test.rb
61
65
  - test/run.rb
62
66
  - test/section_test.rb
@@ -96,6 +100,9 @@ test_files:
96
100
  - test/plugin/mongo_test.rb
97
101
  - test/plugin/net_http_test.rb
98
102
  - test/plugin/redis_test.rb
103
+ - test/plugin/resque_test.rb
104
+ - test/plugin/sidekiq_test.rb
105
+ - test/queue_test.rb
99
106
  - test/rorvswild_test.rb
100
107
  - test/run.rb
101
108
  - test/section_test.rb