request_recorder 0.0.1 → 0.0.2

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