corn 0.5.6 → 0.5.7.beta1

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: 2128d61b559f2364bb060b87e258069ed0573622
4
- data.tar.gz: 84dadacc4a71ad7b6c33209ef3cf1c5829e91936
3
+ metadata.gz: 8cd2ed0bc9b102eca18ed7e80ea7a9313702fc02
4
+ data.tar.gz: 6ce6d074da698b05112110f83635b497f8453735
5
5
  SHA512:
6
- metadata.gz: fa94880e60a3bf2e53e8901fc13e62d74424708c67d1f0c9848bbc63bcf825fc5c286298ca3ea0da847a315cc516fbb075ead74f4f1fd881ce17d4d3ee5a1ac0
7
- data.tar.gz: 7791a5595a58ac89cf35ec041112ee78999e14f17665f8adf168f8f32b3bb78f28b75d2e3dc7f46ac58f7a4ecad7a612f88a4bc5ebe105a57c3c3857d46a9713
6
+ metadata.gz: 07ad76f726b438be79b29f51144c913fd1f413abbd221c2c0beff3c9453db7a439441de4080bc4ebb111c330ef5c6c7f727709f8605b0aeca26925f3920eb22e
7
+ data.tar.gz: 5d216ec62d5c8d3ccc111d7aee67b3740a3b1c4899023479ed725b27fe3855fd6c27afbaa8322d673d321c28d94471aa2590a65592532d190ad96ce84e6311d6
data/lib/corn.rb CHANGED
@@ -33,9 +33,12 @@ module Corn
33
33
  :rack_middleware => Rack::SlowRequestProfiler,
34
34
  :rack_slow_request_profiler => Rack::SlowRequestProfiler,
35
35
  :slow_request_threshold => 5,
36
+ :fast_request_threshold => lambda { [Corn.sampling_interval * 5, Corn.slow_request_threshold.to_f / 5].max },
36
37
  :profiling => true,
37
38
  :sampling_interval => 0.1,
38
- :post_interval => 2
39
+ :post_interval => 2,
40
+ :post_fast_request_interval => 60, #seconds
41
+ :fast_request_sampling_limit => 1024 * 1024 * 2 #2MB
39
42
  })
40
43
 
41
44
  module_function
data/lib/corn/post.rb CHANGED
@@ -5,9 +5,12 @@ require 'time'
5
5
 
6
6
  module Corn
7
7
  class Post
8
- def initialize(interval)
8
+ def initialize(interval, sampling_limit, sampling_time)
9
9
  @queue = Queue.new
10
10
  @thread = start_post_thread(interval)
11
+ @sampling_limit = sampling_limit
12
+ @sampling_time = sampling_time
13
+ reset_sampling
11
14
  end
12
15
 
13
16
  def terminate
@@ -24,8 +27,21 @@ module Corn
24
27
  Thread.start do
25
28
  begin
26
29
  loop do
27
- http_post(@queue.pop)
28
- sleep interval
30
+ d = @queue.pop
31
+ case d[:action]
32
+ when :post
33
+ http_post([d])
34
+ sleep interval
35
+ when :sampling
36
+ @sampling << d
37
+ if Time.now - @sampling_start > @sampling_time
38
+ http_post(@sampling.items, :sampling)
39
+ reset_sampling
40
+ sleep interval
41
+ end
42
+ else
43
+ Corn.logger.info("Corn: Ignore unknown action: #{d[:action]}")
44
+ end
29
45
  end
30
46
  rescue => e
31
47
  Corn.logger.error("Corn post thread stopped by error #{e.message}\n#{e.backtrace.join("\n")}")
@@ -34,14 +50,25 @@ module Corn
34
50
  end
35
51
 
36
52
  def enqueue(data)
37
- return if data.nil?
53
+ return if data.nil? || data.empty?
38
54
  @queue << data
39
55
  end
40
56
 
41
- def http_post(data)
57
+ def http_post(reports, type=nil)
42
58
  uri = URI.parse(submit_url)
43
59
  req = Net::HTTP::Post.new(uri.path)
44
- req.set_form_data(data.merge('client_id' => Corn.client_id))
60
+ form_data = [['client_id', Corn.client_id]]
61
+ if type
62
+ form_data << ['type', type]
63
+ end
64
+ reports.each_with_index do |rep, i|
65
+ [:name, :start_at, :end_at, :data].each do |k|
66
+ if v = rep[k]
67
+ form_data << ["reports[][#{k}]", v]
68
+ end
69
+ end
70
+ end
71
+ req.set_form_data(form_data)
45
72
 
46
73
  http = Net::HTTP.new(uri.host, uri.port)
47
74
  if uri.scheme == 'https'
@@ -55,7 +82,7 @@ module Corn
55
82
  end
56
83
  end
57
84
  res = http.request(req)
58
- Corn.logger.info("Corn report submitted to #{submit_url}")
85
+ Corn.logger.info("Corn reports(#{reports.size}) submitted to #{submit_url}")
59
86
  unless res.is_a?(Net::HTTPSuccess)
60
87
  Corn.logger.error("Post failed: #{res.message}(#{res.code}), response body: \n#{res.body}")
61
88
  end
@@ -66,5 +93,11 @@ module Corn
66
93
  def submit_url
67
94
  Corn.submit_url
68
95
  end
96
+
97
+ private
98
+ def reset_sampling
99
+ @sampling = ReservoirSampling.new(@sampling_limit)
100
+ @sampling_start = Time.now
101
+ end
69
102
  end
70
103
  end
data/lib/corn/profiler.rb CHANGED
@@ -3,8 +3,9 @@ require 'sampling_prof'
3
3
 
4
4
  module Corn
5
5
  class Profiler
6
- def initialize(post_interval, sampling_interval)
7
- @post = Post.new(post_interval)
6
+ def initialize(post_interval, post_sampling_limit, post_sampling_time,
7
+ sampling_interval)
8
+ @post = Post.new(post_interval, post_sampling_limit, post_sampling_time)
8
9
  @prof = SamplingProf.new(sampling_interval)
9
10
  at_exit { terminate }
10
11
  end
@@ -31,9 +31,9 @@ module Corn
31
31
  name = "#{name}?#{@env[:query_string]}"
32
32
  end
33
33
  {
34
- 'report[name]' => name,
35
- 'report[start_at]' => @env[:start_time].iso8601,
36
- 'report[end_at]' => end_at.iso8601
34
+ :name => name,
35
+ :start_at => @env[:start_time].iso8601,
36
+ :end_at => end_at.iso8601
37
37
  }
38
38
  end
39
39
  end
@@ -1,4 +1,6 @@
1
+ require 'thread'
1
2
  require 'corn/profiler'
3
+ require 'corn/reservoir_sampling'
2
4
  require 'corn/rack/request_env'
3
5
 
4
6
  module Corn
@@ -7,8 +9,11 @@ module Corn
7
9
  class ProfilingApp
8
10
  def initialize(app)
9
11
  @@prof ||= Profiler.new(Corn.post_interval,
12
+ Corn.fast_request_sampling_limit,
13
+ Corn.post_fast_request_interval,
10
14
  Corn.sampling_interval)
11
15
  @app = app
16
+
12
17
  Corn.logger.info("Corn sampling interval: #{Corn.sampling_interval}")
13
18
  Corn.logger.info("Corn slow request threshold: #{Corn.slow_request_threshold}")
14
19
  end
@@ -29,11 +34,20 @@ module Corn
29
34
  def output_handler(env)
30
35
  request_env = RequestEnv.new(env)
31
36
  lambda do |data|
32
- if request_env.time > Corn.slow_request_threshold
33
- request_env.to_report.merge("data" => data)
37
+ t = request_env.time
38
+ if t < fast_request_threshold || t > slow_request_threshold
39
+ action = t > Corn.slow_request_threshold ? :post : :sampling
40
+ request_env.to_report.merge(:data => data, :action => action)
34
41
  end
35
42
  end
36
43
  end
44
+
45
+ def fast_request_threshold
46
+ @frt ||= Corn.fast_request_threshold
47
+ end
48
+ def slow_request_threshold
49
+ @srt ||= Corn.slow_request_threshold
50
+ end
37
51
  end
38
52
 
39
53
  def initialize(app)
@@ -44,6 +58,7 @@ module Corn
44
58
  @app.call(env)
45
59
  end
46
60
 
61
+ # for test
47
62
  def terminate
48
63
  @app.terminate if @app.respond_to?(:terminate)
49
64
  end
@@ -0,0 +1,29 @@
1
+ module Corn
2
+ class ReservoirSampling
3
+ attr_reader :items
4
+ def initialize(limit)
5
+ @limit = limit
6
+ @items = []
7
+ @size = -1
8
+ @count = 0
9
+ end
10
+
11
+ def <<(item)
12
+ @count += 1
13
+ if @size < 0 && bytesize < @limit
14
+ items << item
15
+ else
16
+ @size = items.size
17
+ j = rand(@count).to_i
18
+ if j < @size
19
+ items[j] = item
20
+ end
21
+ end
22
+ end
23
+
24
+ private
25
+ def bytesize
26
+ items.map{|d|d[:data].bytesize}.reduce(:+) || 0
27
+ end
28
+ end
29
+ end
@@ -56,7 +56,7 @@ Corn.config({
56
56
  # called. So you can also use it to turn on profiling by a request parameter.
57
57
  # For example: Corn.config(:profiling => lambda {|env| env["QUERY_STRING"] =~ /corn_profiling=true/ })
58
58
  # This configuration will be checked for every request, so don't do anything
59
- # expense here.
59
+ # expensive here.
60
60
  # :profiling => true,
61
61
  })
62
62
  # Install corn rack middleware for profiling slow requests
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: corn
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.6
4
+ version: 0.5.7.beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Xiao Li
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-10 00:00:00.000000000 Z
11
+ date: 2014-07-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sampling_prof
@@ -38,6 +38,7 @@ files:
38
38
  - lib/corn/post.rb
39
39
  - lib/corn/profiler.rb
40
40
  - lib/corn/rack.rb
41
+ - lib/corn/reservoir_sampling.rb
41
42
  - lib/corn/rack/request_env.rb
42
43
  - lib/corn/rack/slow_request_profiler.rb
43
44
  - lib/generators/corn/config/config_generator.rb
@@ -56,9 +57,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
56
57
  version: '0'
57
58
  required_rubygems_version: !ruby/object:Gem::Requirement
58
59
  requirements:
59
- - - '>='
60
+ - - '>'
60
61
  - !ruby/object:Gem::Version
61
- version: '0'
62
+ version: 1.3.1
62
63
  requirements: []
63
64
  rubyforge_project:
64
65
  rubygems_version: 2.1.9