request_recorder 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -3,4 +3,6 @@ gemspec
3
3
 
4
4
  gem "rake"
5
5
  gem "rspec", "~>2"
6
+ gem "activerecord", "2.3.14"
6
7
  gem "sqlite3"
8
+ gem "fakeredis"
data/Gemfile.lock CHANGED
@@ -1,8 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- request_recorder (0.0.1)
5
- activerecord (= 2.3.14)
4
+ request_recorder (0.0.2)
6
5
  rack
7
6
 
8
7
  GEM
@@ -12,8 +11,11 @@ GEM
12
11
  activesupport (= 2.3.14)
13
12
  activesupport (2.3.14)
14
13
  diff-lcs (1.1.3)
14
+ fakeredis (0.4.0)
15
+ redis (~> 3.0.0)
15
16
  rack (1.4.1)
16
17
  rake (0.9.2)
18
+ redis (3.0.1)
17
19
  rspec (2.6.0)
18
20
  rspec-core (~> 2.6.0)
19
21
  rspec-expectations (~> 2.6.0)
@@ -28,6 +30,8 @@ PLATFORMS
28
30
  ruby
29
31
 
30
32
  DEPENDENCIES
33
+ activerecord (= 2.3.14)
34
+ fakeredis
31
35
  rake
32
36
  request_recorder!
33
37
  rspec (~> 2)
data/Readme.md CHANGED
@@ -4,15 +4,22 @@ Install
4
4
  =======
5
5
 
6
6
  gem install request_recorder
7
- # generate a add_recorded_requests migration and paste content of MIGRATION
7
+
8
+ Add to your middleware stack:
9
+
10
+ require "request_recorder"
11
+ use RequestRecorder::Middleware, :store => RequestRecorder::RedisLogger.new(Redis.new)
12
+
13
+ ### No Redis, No problem
14
+ If you do not have redis, you can write your own logger, you only need a .write method,
15
+ see [RedisLogger](https://github.com/grosser/request_recorder/blob/master/lib/request_recorder/redis_logger.rb)
8
16
 
9
17
  Usage
10
18
  =====
11
19
 
12
- - Add it to the bottom of you middleware stack
13
- - request a page with __request_recording=10 -> record next 10 requests from my browser
14
- - RequestRecorded::Requests gets a new entry with all the logging info from rails + activerecord
15
- - go to the database or build a nice frontend for RequestRecorded::Requests
20
+ - request a page with `/something?__request_recording=10` -> record next 10 requests from my browser
21
+ - redis 'request_recorder' gets a new entry with all the logging info from rails + activerecord
22
+ - go to redis or build a nice frontend
16
23
 
17
24
  Author
18
25
  ======
@@ -1,3 +1,4 @@
1
+ require "stringio"
1
2
  require "rack/request"
2
3
  require "rack/response"
3
4
 
@@ -8,6 +9,7 @@ module RequestRecorder
8
9
 
9
10
  def initialize(app, options={})
10
11
  @app = app
12
+ @store = options.fetch(:store)
11
13
  end
12
14
 
13
15
  def call(env)
@@ -17,29 +19,28 @@ module RequestRecorder
17
19
  (env["HTTP_COOKIE"] && env["HTTP_COOKIE"].include?(MARKER))
18
20
  )
19
21
 
20
- result = logging_to_recorded do
21
- @app.call(env)
22
+ result = nil
23
+ log = capture_logging do
24
+ result = @app.call(env)
22
25
  end
23
26
 
24
27
  steps_left, id = read_state_from_env(env)
25
28
  return [500, {}, "__request_recording exceeded maximum value #{MAX_STEPS}"] if steps_left > MAX_STEPS
26
- id = persist_log(id, @recorder.log)
29
+ id = persist_log(id, log)
27
30
  response_with_data_in_cookie(result, steps_left, id)
28
31
  end
29
32
 
30
33
  private
31
34
 
32
35
  def persist_log(id, log)
33
- record = (id ? Log.find(id) : Log.new(:log => ""))
34
- record.log += log.join("\n") + "\n\n"
35
- record.save!
36
- record.id
36
+ @store.write(id, log)
37
37
  end
38
38
 
39
39
  def read_state_from_env(env)
40
40
  request = Rack::Request.new(env)
41
41
  if request.cookies[MARKER]
42
- request.cookies[MARKER].split(":").map(&:to_i)
42
+ steps, id = request.cookies[MARKER].split(":")
43
+ [steps.to_i, id]
43
44
  else
44
45
  [env["QUERY_STRING"][/#{MARKER}=(\d+)/, 1].to_i, nil]
45
46
  end
@@ -51,27 +52,30 @@ module RequestRecorder
51
52
  if to_go <= 1
52
53
  response.delete_cookie(MARKER)
53
54
  else
54
- response.set_cookie(MARKER, {:value => "#{to_go.to_i - 1}:#{id}", :path => "/", :expires => Time.now+24*60*60})
55
+ response.set_cookie(MARKER, {:value => "#{to_go.to_i - 1}:#{id}", :expires => Time.now+24*60*60, :httponly => true})
55
56
  end
56
57
 
57
58
  response.finish # finish writes out the response in the expected format.
58
59
  end
59
60
 
60
- def logging_to_recorded
61
- @recorder = Recorder.new
61
+ def capture_logging
62
+ recorder = StringIO.new
62
63
  old = [
63
64
  ActiveRecord::Base.logger.instance_variable_get("@log"),
64
65
  ActiveRecord::Base.logger.auto_flushing,
65
66
  ActiveRecord::Base.logger.level
66
67
  ]
67
- ActiveRecord::Base.logger.instance_variable_set("@log", @recorder)
68
+ ActiveRecord::Base.logger.instance_variable_set("@log", recorder)
68
69
  ActiveRecord::Base.logger.auto_flushing = true
69
70
  ActiveRecord::Base.logger.level = Logger::DEBUG
70
71
  yield
72
+ recorder.string
71
73
  ensure
72
- ActiveRecord::Base.logger.instance_variable_set("@log", old[0])
73
- ActiveRecord::Base.logger.auto_flushing = old[1]
74
- ActiveRecord::Base.logger.level = old[2]
74
+ if old
75
+ ActiveRecord::Base.logger.instance_variable_set("@log", old[0])
76
+ ActiveRecord::Base.logger.auto_flushing = old[1]
77
+ ActiveRecord::Base.logger.level = old[2]
78
+ end
75
79
  end
76
80
  end
77
81
  end
@@ -0,0 +1,16 @@
1
+ module RequestRecorder
2
+ class RedisLogger
3
+ KEY = "request_recorder"
4
+
5
+ def initialize(redis)
6
+ @redis = redis
7
+ end
8
+
9
+ def write(id, text)
10
+ old = (id ? @redis.hget(KEY, id) : "")
11
+ id = "#{Time.now.to_i}_#{Process.pid}" unless id
12
+ @redis.hset(KEY, id, old.to_s + text)
13
+ id
14
+ end
15
+ end
16
+ end
@@ -1,3 +1,3 @@
1
1
  module RequestRecorder
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -1,7 +1,6 @@
1
1
  require "request_recorder/version"
2
- require "request_recorder/log"
3
2
  require "request_recorder/middleware"
4
- require "request_recorder/recorder"
3
+ require "request_recorder/redis_logger"
5
4
 
6
5
  module RequestRecorder
7
6
  end
@@ -9,6 +9,5 @@ Gem::Specification.new name, RequestRecorder::VERSION do |s|
9
9
  s.homepage = "http://github.com/grosser/#{name}"
10
10
  s.files = `git ls-files`.split("\n")
11
11
  s.license = "MIT"
12
- s.add_dependency "activerecord", "2.3.14"
13
12
  s.add_dependency "rack"
14
13
  end
@@ -7,7 +7,10 @@ describe RequestRecorder do
7
7
  Car.first
8
8
  [200, {}, "assadasd"]
9
9
  } }
10
- let(:existing_request){ RequestRecorder::Log.create(:log => "BEFORE") }
10
+ let(:middleware){ RequestRecorder::Middleware.new(inner_app, :store => RequestRecorder::RedisLogger.new(redis)) }
11
+ let(:redis){ FakeRedis::Redis.new }
12
+ let(:redis_key){ RequestRecorder::RedisLogger::KEY }
13
+ let(:existing_request_id){ redis.hset(redis_key, "123_456", "BEFORE") ; "123_456"}
11
14
 
12
15
  before do
13
16
  ActiveRecord::Base.logger.instance_variable_set("@log", original_logger)
@@ -16,7 +19,7 @@ describe RequestRecorder do
16
19
  end
17
20
 
18
21
  after do
19
- RequestRecorder::Log.delete_all
22
+ redis.flushall
20
23
  end
21
24
 
22
25
  it "has a VERSION" do
@@ -24,13 +27,11 @@ describe RequestRecorder do
24
27
  end
25
28
 
26
29
  it "records activerecord queries" do
27
- middleware = RequestRecorder::Middleware.new(inner_app)
28
30
  middleware.call(activate_logger)
29
- RequestRecorder::Log.last.log.should include "SELECT"
31
+ stored.values.last.should include "SELECT"
30
32
  end
31
33
 
32
34
  it "blows up if you go over the maximum" do
33
- middleware = RequestRecorder::Middleware.new(inner_app)
34
35
  status, headers, body = middleware.call("QUERY_STRING" => "__request_recording=99999")
35
36
  status.should == 500
36
37
  body.should include "maximum"
@@ -38,47 +39,92 @@ describe RequestRecorder do
38
39
 
39
40
  context "subsequent requests" do
40
41
  it "sets cookie in first step" do
41
- middleware = RequestRecorder::Middleware.new(inner_app)
42
42
  status, headers, body = middleware.call(activate_logger)
43
- generated = RequestRecorder::Log.last
44
- headers["Set-Cookie"].should include "__request_recording=9%3A#{generated.id}; path=/; expires="
43
+ generated_id = stored.keys.last
44
+ headers["Set-Cookie"].should include "__request_recording=9%3A#{generated_id}; expires="
45
+ headers["Set-Cookie"].should include "; HttpOnly"
45
46
  end
46
47
 
47
48
  it "appends to existing log" do
48
- middleware = RequestRecorder::Middleware.new(inner_app)
49
- middleware.call("HTTP_COOKIE" => "__request_recording=8:#{existing_request.id}")
50
- existing_request.reload
51
- existing_request.log.should include "SELECT"
52
- existing_request.log.should include "BEFORE"
49
+ middleware.call("HTTP_COOKIE" => "__request_recording=8:#{existing_request_id}")
50
+ existing_request = redis.hget(redis_key, existing_request_id)
51
+ existing_request.should include "SELECT"
52
+ existing_request.should include "BEFORE"
53
+ end
54
+
55
+ it "creates a new log if redis dies" do
56
+ existing_request_id # store key
57
+ redis.flushall
58
+ middleware.call("HTTP_COOKIE" => "__request_recording=8:#{existing_request_id}")
59
+ existing_request = redis.hget(redis_key, existing_request_id)
60
+ existing_request.should include "SELECT"
61
+ existing_request.should_not include "BEFORE"
53
62
  end
54
63
 
55
64
  it "decrements cookie on each step" do
56
- middleware = RequestRecorder::Middleware.new(inner_app)
57
- status, headers, body = middleware.call("HTTP_COOKIE" => "__request_recording=2:#{existing_request.id};foo=bar")
58
- headers["Set-Cookie"].should include "__request_recording=1%3A#{existing_request.id}; path=/; expires="
65
+ status, headers, body = middleware.call("HTTP_COOKIE" => "__request_recording=2:#{existing_request_id};foo=bar")
66
+ headers["Set-Cookie"].should include "__request_recording=1%3A#{existing_request_id}; expires="
59
67
  end
60
68
 
61
69
  it "removes cookie if final step is reached" do
62
- middleware = RequestRecorder::Middleware.new(inner_app)
63
- status, headers, body = middleware.call("HTTP_COOKIE" => "__request_recording=1:#{existing_request.id};foo=bar")
70
+ status, headers, body = middleware.call("HTTP_COOKIE" => "__request_recording=1:#{existing_request_id};foo=bar")
64
71
  headers["Set-Cookie"].should include "__request_recording=; expires="
65
72
  end
66
73
  end
67
74
 
68
75
  it "should not record if __request_recording is not given" do
69
- middleware = RequestRecorder::Middleware.new(inner_app)
70
76
  middleware.call(
71
77
  "QUERY_STRING" => "stuff=hello", "HTTP_COOKIE" => "bar=foo"
72
78
  )
73
- RequestRecorder::Log.count.should == 0
79
+ stored.count.should == 0
74
80
  end
75
81
 
76
82
  it "restores the AR logger after executing" do
77
- middleware = RequestRecorder::Middleware.new(inner_app)
78
83
  middleware.call(activate_logger)
79
84
 
80
85
  ActiveRecord::Base.logger.instance_variable_get("@log").object_id.should == original_logger.object_id
81
86
  ActiveRecord::Base.logger.auto_flushing.should == 1000
82
87
  ActiveRecord::Base.logger.level.should == Logger::ERROR
83
88
  end
89
+
90
+ it "fails with a nice message if logging_to_recorded blows up" do
91
+ StringIO.should_receive(:new).and_raise("Oooops")
92
+ expect{
93
+ middleware.call(activate_logger)
94
+ }.to raise_error "Oooops"
95
+ end
96
+
97
+ it "integrates" do
98
+ stored.size.should == 0
99
+
100
+ # request 1 - start + decrement + log
101
+ status, headers, body = middleware.call({"QUERY_STRING" => "__request_recording=3"})
102
+ stored.size.should == 1
103
+ stored.values.last.scan("SELECT").size.should == 1
104
+ cookie = headers["Set-Cookie"].split(";").first
105
+
106
+ # request 2 - decrement + log
107
+ status, headers, body = middleware.call({"HTTP_COOKIE" => cookie})
108
+ stored.size.should == 1
109
+ stored.values.last.scan("SELECT").size.should == 2
110
+ cookie = headers["Set-Cookie"].split(";").first
111
+
112
+ # request 3 - remove cookie + log
113
+ status, headers, body = middleware.call({"HTTP_COOKIE" => cookie})
114
+ stored.size.should == 1
115
+ stored.values.last.scan("SELECT").size.should == 3
116
+ cookie = headers["Set-Cookie"].split(";").first
117
+ cookie.should == "__request_recording="
118
+
119
+ # request 4 - no more logging
120
+ status, headers, body = middleware.call({})
121
+ stored.size.should == 1
122
+ stored.values.last.scan("SELECT").size.should == 3
123
+ end
124
+
125
+ private
126
+
127
+ def stored
128
+ redis.hgetall(redis_key)
129
+ end
84
130
  end
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,8 @@
1
1
  require "request_recorder"
2
2
 
3
+ require "active_record"
4
+ require "fakeredis"
5
+
3
6
  ActiveRecord::Base.logger = ActiveSupport::BufferedLogger.new("/dev/null")
4
7
 
5
8
  # connect
@@ -11,9 +14,6 @@ ActiveRecord::Base.establish_connection(
11
14
  # create tables
12
15
  ActiveRecord::Schema.verbose = false
13
16
  ActiveRecord::Schema.define(:version => 1) do
14
- eval(File.read(File.expand_path("../../MIGRATION", __FILE__)))
15
- AddRecordedRequests.up
16
-
17
17
  create_table :cars do |t|
18
18
  t.timestamps
19
19
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: request_recorder
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -11,22 +11,6 @@ bindir: bin
11
11
  cert_chain: []
12
12
  date: 2012-10-19 00:00:00.000000000 Z
13
13
  dependencies:
14
- - !ruby/object:Gem::Dependency
15
- name: activerecord
16
- requirement: !ruby/object:Gem::Requirement
17
- none: false
18
- requirements:
19
- - - '='
20
- - !ruby/object:Gem::Version
21
- version: 2.3.14
22
- type: :runtime
23
- prerelease: false
24
- version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
- requirements:
27
- - - '='
28
- - !ruby/object:Gem::Version
29
- version: 2.3.14
30
14
  - !ruby/object:Gem::Dependency
31
15
  name: rack
32
16
  requirement: !ruby/object:Gem::Requirement
@@ -52,13 +36,11 @@ files:
52
36
  - .travis.yml
53
37
  - Gemfile
54
38
  - Gemfile.lock
55
- - MIGRATION
56
39
  - Rakefile
57
40
  - Readme.md
58
41
  - lib/request_recorder.rb
59
- - lib/request_recorder/log.rb
60
42
  - lib/request_recorder/middleware.rb
61
- - lib/request_recorder/recorder.rb
43
+ - lib/request_recorder/redis_logger.rb
62
44
  - lib/request_recorder/version.rb
63
45
  - request_recorder.gemspec
64
46
  - spec/request_recorder_spec.rb
@@ -78,7 +60,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
78
60
  version: '0'
79
61
  segments:
80
62
  - 0
81
- hash: -1997442405915248740
63
+ hash: -3099537396771962597
82
64
  required_rubygems_version: !ruby/object:Gem::Requirement
83
65
  none: false
84
66
  requirements:
@@ -87,7 +69,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
87
69
  version: '0'
88
70
  segments:
89
71
  - 0
90
- hash: -1997442405915248740
72
+ hash: -3099537396771962597
91
73
  requirements: []
92
74
  rubyforge_project:
93
75
  rubygems_version: 1.8.24
data/MIGRATION DELETED
@@ -1,12 +0,0 @@
1
- class AddRecordedRequests < ActiveRecord::Migration
2
- def self.up
3
- create_table :recorded_request_log do |t|
4
- t.text "log"
5
- t.timestamp :created_at
6
- end
7
- end
8
-
9
- def self.down
10
- drop_table :recorded_request_log
11
- end
12
- end
@@ -1,7 +0,0 @@
1
- require "active_record"
2
-
3
- module RequestRecorder
4
- class Log < ActiveRecord::Base
5
- set_table_name "recorded_request_log" # TODO use self.table_name = in rails 3
6
- end
7
- end
@@ -1,13 +0,0 @@
1
- module RequestRecorder
2
- class Recorder
3
- attr_reader :log
4
-
5
- def initialize
6
- @log = []
7
- end
8
-
9
- def write(s)
10
- @log << s
11
- end
12
- end
13
- end