rack-httperflog 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Emmanuel Oga
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,48 @@
1
+ = rack/httperflog
2
+
3
+ Generates a replay log of the actions performed by the web application.
4
+
5
+ When a url is requested, it is logged to the replay log (if the response status is not an error).
6
+
7
+ Then, if the response content type is html, paths for the images, scripts, stylesheets and iframes are extracted and logged as well.
8
+
9
+ == Usage
10
+
11
+ On your rack configuration, add the middleware providing the following parameters:
12
+
13
+ ...
14
+ use ReplayLogger, :ping_urls, "/log/path", "/flag/path"
15
+ ...
16
+
17
+ ping_urls:: pass :ping_urls for making the middleware perform an http get to validate each path parsed from the html body returns a status 200. WARNING: only use if your http server can handle more than one concurrent connection (e.g.: you are using passenger or have a cluster of load balanced mongrels). Any other value avoids performing the check requests.
18
+ log_path:: path to the log file that will contain the session log.
19
+ flag_path:: the logging will be performed only when the file pointed by flag_path exists.
20
+
21
+ == On Rails
22
+
23
+ Rails::Initializer.run do |config|
24
+ config.gem 'rack-httperflog', :lib => "rack/httperflog"
25
+
26
+ config.middleware.use "Rack::Httperflog", :ping_urls, Rails.root.join("log", "wsess.log"), Rails.root.join("log", "wsess.record")
27
+ end
28
+
29
+ == Notes
30
+
31
+ The log will not contain any newlines (which signal separate sessions on httperf's wsesslog format). If you want to generated separated logs, simple echo a new line in the session log with a command like:
32
+
33
+ echo '' >> log/path
34
+
35
+ == Note on Patches/Pull Requests
36
+
37
+ * Fork the project.
38
+ * Make your feature addition or bug fix.
39
+ * Add tests for it. This is important so I don't break it in a
40
+ future version unintentionally.
41
+ * Commit, do not mess with rakefile, version, or history.
42
+ (if you want to have your own version, that is fine but
43
+ bump version in a commit by itself I can ignore when I pull)
44
+ * Send me a pull request. Bonus points for topic branches.
45
+
46
+ == Copyright
47
+
48
+ Copyright (c) 2009 Emmanuel Oga. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,47 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "rack-httperflog"
8
+ gem.summary = %Q{generates a replay log in httperfs' wsesslog format}
9
+ gem.description = %Q{rack middleware to generate a replay log}
10
+ gem.email = "EmmanuelOga@gmail.com"
11
+ gem.homepage = "http://github.com/EmmanuelOga/rack-httperflog"
12
+ gem.authors = ["Emmanuel Oga"]
13
+ gem.add_development_dependency "rspec", ">= 1.2.9"
14
+ gem.add_dependency "nokogiri", ">= 1.3.3"
15
+ gem.add_dependency "rack", ">= 1.0.0"
16
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
17
+ end
18
+ Jeweler::GemcutterTasks.new
19
+ rescue LoadError
20
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
21
+ end
22
+
23
+ require 'spec/rake/spectask'
24
+ Spec::Rake::SpecTask.new(:spec) do |spec|
25
+ spec.libs << 'lib' << 'spec'
26
+ spec.spec_files = FileList['spec/**/*_spec.rb']
27
+ end
28
+
29
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
30
+ spec.libs << 'lib' << 'spec'
31
+ spec.pattern = 'spec/**/*_spec.rb'
32
+ spec.rcov = true
33
+ end
34
+
35
+ task :spec => :check_dependencies
36
+
37
+ task :default => :spec
38
+
39
+ require 'rake/rdoctask'
40
+ Rake::RDocTask.new do |rdoc|
41
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
42
+
43
+ rdoc.rdoc_dir = 'rdoc'
44
+ rdoc.title = "rack-httperflog #{version}"
45
+ rdoc.rdoc_files.include('README*')
46
+ rdoc.rdoc_files.include('lib/**/*.rb')
47
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.1
@@ -0,0 +1,125 @@
1
+ require "net/http"
2
+ require "nokogiri"
3
+ require "rack"
4
+
5
+ module Rack
6
+ # Httperflog is a middleware that will log the request and all the
7
+ # img, iframes, css and js paths founds in its body if the response is an html document in
8
+ # a format appropriate for using it as an httperf session log.
9
+ #
10
+ # use Httperflog :ping_urls, "log/path", "flag/path"
11
+ #
12
+ # ping_urls :: pass :ping_urls for making the middleware perform an http get
13
+ # to validate each path found inside the html body. WARNING: only use if your
14
+ # http server can handle more than one concurrent connection (e.g.: you are
15
+ # using passenger or have a cluster of load balanced mongrels). Any other value
16
+ # avoids performing the requests.
17
+ # log_path :: path to the log file that will contain the session log.
18
+ # flag_path :: the logging will be performed only when the file pointed by
19
+ # flag_path exists.
20
+ class Httperflog < Struct.new(:app, :ping_urls, :log_path, :flag_path)
21
+ def call(env)
22
+ status, headers, response = app.call(env)
23
+
24
+ Httperflog::Logger.new(request_to_log(env), response_to_log(status, headers, response), log_file, ping_urls).perform_logging if logging_enabled?
25
+
26
+ [status, headers, response]
27
+ end
28
+
29
+ # Logging will be enabled if file in flag_path exists.
30
+ def logging_enabled?
31
+ ::File.file?(flag_path)
32
+ end
33
+
34
+ # Log file opened on append mode.
35
+ def log_file
36
+ @lof_file ||= ::File.open(log_path, "a")
37
+ end
38
+
39
+ # Extract the Rack::Request object needed by the logger
40
+ def request_to_log(env)
41
+ env["rack.request"].class <= Rack::Request ? env["rack.request"] : Rack::Request.new(env)
42
+ end
43
+
44
+ # Extract the Rack::Response object needed by the logger
45
+ def response_to_log(status, headers, response)
46
+ r = response.class <= Rack::Response ? response : Rack::Response.new(response, status, headers)
47
+ r.status = r.status.to_i # avoid problems with Rack::Response methods that expect the status code to be an integer.
48
+ r
49
+ end
50
+
51
+ # Extracts the lines to log from the rack request and response and logs
52
+ # them to a file on log_path path.
53
+ #
54
+ # Logger.new("log/path", :ping_urls, request, response)
55
+ #
56
+ # log_path :: path to the log file to log the lines
57
+ # ping_urls :: provide :ping_urls to perform an http get to each path found inside
58
+ # the body of the response. Provide any other value to avoid this check.
59
+ # request :: a Rack::Request instance
60
+ # response :: a Rack::Response instance
61
+ class Logger < Struct.new(:request, :response, :file, :ping_urls)
62
+
63
+ # Perform the logging of each log line to a file
64
+ def perform_logging
65
+ each { |line| file << line }
66
+ file.flush
67
+ end
68
+
69
+ # yields each line for the log
70
+ def each
71
+ return if response.server_error? || response.client_error?
72
+
73
+ form_data = " contents=\"#{ Rack::Utils.build_query(request.params) }\"" if request.form_data? && !request.params.empty?
74
+
75
+ yield "#{ request.path_info } method=#{ request.request_method.to_s.upcase }#{ form_data }\n"
76
+
77
+ paths_to_log.each do |path|
78
+ yield " #{ path }\n" if path != request.path_info && (ping_urls != :ping_urls || UrlHelper.url_status_is?("200", request.host, request.port, path))
79
+ end
80
+ end
81
+
82
+ # uses a HtmlPathsExtractor object to parse the response if it contains html, and extracts all the relevant paths.
83
+ def paths_to_log
84
+ response.content_type =~ /html/ ? HtmlPathsExtractor.new(response.body).paths : Array.new
85
+ end
86
+ end
87
+
88
+ # Extract each path linked inside the source html document
89
+ #
90
+ # HtmlPathsExtractor.new(source)
91
+ #
92
+ # source :: an html document
93
+ class HtmlPathsExtractor < Struct.new(:source)
94
+
95
+ # return all link, script, img and iframe paths found in the html document
96
+ def paths
97
+ links = attributes_from_nodes("href", "link")
98
+ scripts = attributes_from_nodes("src", "script")
99
+ imgs = attributes_from_nodes("src", "img")
100
+ iframes = attributes_from_nodes("src", "iframe")
101
+ links + scripts + imgs + iframes
102
+ end
103
+
104
+ # parse the source html
105
+ def parsed_body
106
+ @parsed_body ||= Nokogiri(source.to_s)
107
+ end
108
+
109
+ # extract the attribute attribute_name from all the html nodes of type node_type.
110
+ # returns only non-empty attributes that do not start with http (quick way to avoid
111
+ # paths that point to an external host).
112
+ def attributes_from_nodes(attribute_name, node_type)
113
+ (parsed_body / node_type).map { |node| node[attribute_name].to_s.strip }.select { |path| path =~ /\S/ && path !~ /^http:\/\// }
114
+ end
115
+ end
116
+
117
+ module UrlHelper
118
+ # Checks if the status code returned by a GET to http://host:port/path is the one provided in the first param.
119
+ def url_status_is?(status, host, port, path)
120
+ Net::HTTP.start(host, port) {|http| http.get(path) }.code.to_s.strip == status.to_s rescue false
121
+ end
122
+ extend self
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,65 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{rack-httperflog}
8
+ s.version = "0.1.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Emmanuel Oga"]
12
+ s.date = %q{2009-10-28}
13
+ s.description = %q{rack middleware to generate a replay log}
14
+ s.email = %q{EmmanuelOga@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "lib/rack/httperflog.rb",
27
+ "rack-httperflog.gemspec",
28
+ "spec/lib/html_paths_extractor_spec.rb",
29
+ "spec/lib/httperflog_spec.rb",
30
+ "spec/lib/logger_spec.rb",
31
+ "spec/spec.opts",
32
+ "spec/spec_helper.rb"
33
+ ]
34
+ s.homepage = %q{http://github.com/EmmanuelOga/rack-httperflog}
35
+ s.rdoc_options = ["--charset=UTF-8"]
36
+ s.require_paths = ["lib"]
37
+ s.rubygems_version = %q{1.3.5}
38
+ s.summary = %q{generates a replay log in httperfs' wsesslog format}
39
+ s.test_files = [
40
+ "spec/spec_helper.rb",
41
+ "spec/lib/html_paths_extractor_spec.rb",
42
+ "spec/lib/httperflog_spec.rb",
43
+ "spec/lib/logger_spec.rb"
44
+ ]
45
+
46
+ if s.respond_to? :specification_version then
47
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
48
+ s.specification_version = 3
49
+
50
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
51
+ s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
52
+ s.add_runtime_dependency(%q<nokogiri>, [">= 1.3.3"])
53
+ s.add_runtime_dependency(%q<rack>, [">= 1.0.0"])
54
+ else
55
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
56
+ s.add_dependency(%q<nokogiri>, [">= 1.3.3"])
57
+ s.add_dependency(%q<rack>, [">= 1.0.0"])
58
+ end
59
+ else
60
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
61
+ s.add_dependency(%q<nokogiri>, [">= 1.3.3"])
62
+ s.add_dependency(%q<rack>, [">= 1.0.0"])
63
+ end
64
+ end
65
+
@@ -0,0 +1,15 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Rack::Httperflog::HtmlPathsExtractor do
4
+ before :each do
5
+ @extractor = Rack::Httperflog::HtmlPathsExtractor.new(fixture_markup)
6
+ end
7
+
8
+ it "should list all the known paths on the markup (w/o path of broken markup)" do
9
+ @extractor.paths.length.should == 4
10
+ @extractor.paths.should include("/some/css.css")
11
+ @extractor.paths.should include("/some/js.js")
12
+ @extractor.paths.should include("/some/img.jpg")
13
+ @extractor.paths.should include("/some/iframe.html")
14
+ end
15
+ end
@@ -0,0 +1,57 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Rack::Httperflog do
4
+ before :each do
5
+ @log = ::Tempfile.new("log")
6
+ @flag = ::Tempfile.new("flag")
7
+ end
8
+
9
+ it "only logs when the flag_path file is set" do
10
+ Rack::Httperflog.new(app, :pings_urls, "/some/path", "/fake/path").should_not be_logging_enabled
11
+ Rack::Httperflog.new(app, :pings_urls, "/some/path", @flag.path).should be_logging_enabled
12
+ end
13
+
14
+ it "extracts a rack request from the env" do
15
+ rr = Rack::Request.new("some" => "env")
16
+
17
+ r1 = Rack::Httperflog.new.request_to_log("rack.request" => rr)
18
+ r2 = Rack::Httperflog.new.request_to_log("some" => "env")
19
+
20
+ r1.should be_an_instance_of(Rack::Request)
21
+ r2.should be_an_instance_of(Rack::Request)
22
+
23
+ r1.env["some"].should == r2.env["some"]
24
+ end
25
+
26
+ it "extracts a rack response from the response of the app (with integer status code)" do
27
+ rr = Rack::Response.new("Body", "200", "Content-Length" => "4")
28
+
29
+ r1 = Rack::Httperflog.new.response_to_log("200", { "Content-Type"=>"text/html", "Content-Length" => "4" }, rr)
30
+ r2 = Rack::Httperflog.new.response_to_log("200", { "Content-Type"=>"text/html", "Content-Length" => "4" }, ["Body"])
31
+
32
+ r1.should be_an_instance_of(Rack::Response)
33
+ r2.should be_an_instance_of(Rack::Response)
34
+
35
+ r1.status.should == 200
36
+ r2.status.should == 200
37
+
38
+ r1.headers.should == { "Content-Type"=>"text/html", "Content-Length" => "4" }
39
+ r2.headers.should == { "Content-Type"=>"text/html", "Content-Length" => "4" }
40
+
41
+ r1.body.should == ["Body"]
42
+ r2.body.should == ["Body"]
43
+ end
44
+
45
+ it "returns the same status headers and response that the rack application generated" do
46
+ response_without_middleware = Rack::MockRequest.new(app).get("")
47
+ response_with_middleware = Rack::MockRequest.new(app_with_middleware).get("")
48
+
49
+ response_with_middleware.status.should == app.call({})[0]
50
+ response_with_middleware.headers.should == app.call({})[1]
51
+ response_with_middleware.body.should == app.call({})[2]
52
+
53
+ response_without_middleware.body.should == response_with_middleware.body
54
+ response_without_middleware.status.should == response_with_middleware.status
55
+ response_without_middleware.headers.should == response_with_middleware.headers
56
+ end
57
+ end
@@ -0,0 +1,49 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Rack::Httperflog::Logger do
4
+ before :each do
5
+ @log = ::Tempfile.new("log")
6
+ end
7
+
8
+ def request_and_response(app, method, url)
9
+ mock = Rack::MockRequest.new(app)
10
+
11
+ request = Rack::Request.new Rack::MockRequest.env_for(url, :method => method)
12
+ response = mock.send(method, url)
13
+
14
+ [request, response]
15
+ end
16
+
17
+ it "should log lines matching the request information (only for good requests)" do
18
+ req, resp = request_and_response(app(fixture_markup, "text/html", 500), "get", "/some/url")
19
+ Rack::Httperflog::Logger.new(req, resp, @log, :dont_ping_urls).perform_logging
20
+
21
+ req, resp = request_and_response(app, "get", "/some/url")
22
+ Rack::Httperflog::Logger.new(req, resp, @log, :dont_ping_urls).perform_logging
23
+
24
+ req, resp = request_and_response(app(fixture_markup), "post", "/some/url?some=params")
25
+ Rack::Httperflog::Logger.new(req, resp, @log, :dont_ping_urls).perform_logging
26
+
27
+ @log.flush; @log.rewind
28
+
29
+ lines = @log.read.split("\n")
30
+
31
+ lines[0].should =~ /\/some\/url method=GET/
32
+ lines[1].should =~ /\/some\/url method=POST contents="some=params"/
33
+ lines[2].should =~ / \/some\/css.css/
34
+ lines[3].should =~ / \/some\/js.js/
35
+ lines[4].should =~ / \/some\/img.jpg/
36
+ lines[5].should =~ / \/some\/iframe.html/
37
+ end
38
+
39
+ it "should use the url_exist? helper on each path if :ping_urls is set" do
40
+ req, resp = request_and_response(app(fixture_markup), "post", "/some/url?some=params")
41
+
42
+ Rack::Httperflog::UrlHelper.should_receive(:url_status_is?).with("200", req.host, req.port, "/some/css.css")
43
+ Rack::Httperflog::UrlHelper.should_receive(:url_status_is?).with("200", req.host, req.port, "/some/js.js")
44
+ Rack::Httperflog::UrlHelper.should_receive(:url_status_is?).with("200", req.host, req.port, "/some/img.jpg")
45
+ Rack::Httperflog::UrlHelper.should_receive(:url_status_is?).with("200", req.host, req.port, "/some/iframe.html")
46
+
47
+ Rack::Httperflog::Logger.new(req, resp, @log, :ping_urls).perform_logging
48
+ end
49
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --backtrace
@@ -0,0 +1,57 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+
4
+ require 'tempfile'
5
+ require 'rubygems'
6
+
7
+ require 'rack'
8
+ require 'rack/mock'
9
+ require 'rack/httperflog'
10
+
11
+ require 'spec'
12
+ require 'spec/autorun'
13
+
14
+ module HttperflogAppsHelper
15
+ def app(body = "Hello World!", content_type = "text/html", status = 200)
16
+ lambda do
17
+ [status, { "Content-Length" => body.length.to_s, "Content-Type" => content_type }, body]
18
+ end
19
+ end
20
+
21
+ def app_with_middleware
22
+ app, flag_path, log_path = app(), @flag.path, @log.path
23
+
24
+ Rack::Builder.app do
25
+ use Rack::Httperflog, :dont_ping_urls, log_path, flag_path
26
+ run app
27
+ end
28
+ end
29
+ end
30
+
31
+ module Fixtures
32
+ MARKUP = <<-EOMARKUP
33
+ <html>
34
+ <head>
35
+ <link href="/some/css.css" type="text/css"></link>
36
+ <link href="" type="text/css"></link>
37
+ <script src="/some/js.js" type "text/javascript></script>
38
+ <script src="" type "text/javascript></script>
39
+ </head>
40
+ <body>
41
+ <img src="/some/img.jpg" />
42
+ <img src="
43
+ " />
44
+ <iframe src=" "></iframe>
45
+ <iframe src="/some/iframe.html"></iframe>
46
+ </body>
47
+ </html>
48
+ EOMARKUP
49
+
50
+ def fixture_markup
51
+ MARKUP
52
+ end
53
+ end
54
+
55
+ Spec::Runner.configure do |config|
56
+ config.include HttperflogAppsHelper, Fixtures
57
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-httperflog
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Emmanuel Oga
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-28 00:00:00 -02:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.2.9
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: nokogiri
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.3.3
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: rack
37
+ type: :runtime
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 1.0.0
44
+ version:
45
+ description: rack middleware to generate a replay log
46
+ email: EmmanuelOga@gmail.com
47
+ executables: []
48
+
49
+ extensions: []
50
+
51
+ extra_rdoc_files:
52
+ - LICENSE
53
+ - README.rdoc
54
+ files:
55
+ - .document
56
+ - .gitignore
57
+ - LICENSE
58
+ - README.rdoc
59
+ - Rakefile
60
+ - VERSION
61
+ - lib/rack/httperflog.rb
62
+ - rack-httperflog.gemspec
63
+ - spec/lib/html_paths_extractor_spec.rb
64
+ - spec/lib/httperflog_spec.rb
65
+ - spec/lib/logger_spec.rb
66
+ - spec/spec.opts
67
+ - spec/spec_helper.rb
68
+ has_rdoc: true
69
+ homepage: http://github.com/EmmanuelOga/rack-httperflog
70
+ licenses: []
71
+
72
+ post_install_message:
73
+ rdoc_options:
74
+ - --charset=UTF-8
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: "0"
82
+ version:
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: "0"
88
+ version:
89
+ requirements: []
90
+
91
+ rubyforge_project:
92
+ rubygems_version: 1.3.5
93
+ signing_key:
94
+ specification_version: 3
95
+ summary: generates a replay log in httperfs' wsesslog format
96
+ test_files:
97
+ - spec/spec_helper.rb
98
+ - spec/lib/html_paths_extractor_spec.rb
99
+ - spec/lib/httperflog_spec.rb
100
+ - spec/lib/logger_spec.rb