rack-httperflog 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.rdoc +48 -0
- data/Rakefile +47 -0
- data/VERSION +1 -0
- data/lib/rack/httperflog.rb +125 -0
- data/rack-httperflog.gemspec +65 -0
- data/spec/lib/html_paths_extractor_spec.rb +15 -0
- data/spec/lib/httperflog_spec.rb +57 -0
- data/spec/lib/logger_spec.rb +49 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +57 -0
- metadata +100 -0
data/.document
ADDED
data/.gitignore
ADDED
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
data/spec/spec_helper.rb
ADDED
@@ -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
|