chrisk-samuel 0.2.0

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/.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,5 @@
1
+ .DS_Store
2
+ .yardoc
3
+ /coverage
4
+ /doc
5
+ /pkg
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2009 Chris Kampmeier
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,62 @@
1
+ = Samuel
2
+
3
+ Samuel is a gem for automatic logging of your Net::HTTP requests. It's named for
4
+ the serial diarist Mr. Pepys, who was known to reliably record events both
5
+ quotidian and remarkable.
6
+
7
+ Should a Great Plague, Fire, or Whale befall an important external web service
8
+ you use, you'll be sure to have a tidy record of it.
9
+
10
+ == Usage:
11
+
12
+ When Rails is loaded, Samuel configures a few things automatically. So all you
13
+ need to do is this:
14
+
15
+ # config/environment.rb
16
+ config.gem "samuel"
17
+
18
+ And Samuel will automatically use Rails's logger and an ActiveRecord-like format.
19
+
20
+ For non-Rails projects, you'll have to manually configure logging, like this:
21
+
22
+ require 'samuel'
23
+ Samuel.logger = Logger.new('http_requests.log')
24
+
25
+ If you don't assign a logger, Samuel will configure a default logger on +STDOUT+.
26
+
27
+ == Configuration
28
+
29
+ There are two ways to specify configuration options for Samuel: global and
30
+ inline. Global configs look like this:
31
+
32
+ Samuel.config[:label] = "Twitter API"
33
+ Samuel.config[:filtered_params] = :password
34
+
35
+ You should put global configuration somewhere early-on in your program. If
36
+ you're using Rails, <tt>config/initializers/samuel.rb</tt> will do the trick.
37
+
38
+ Alternatively, an inline configuration block temporarily overrides any global
39
+ configuration for a set of HTTP requests:
40
+
41
+ Samuel.with_config :label => "Twitter API" do
42
+ Net::HTTP.start("twitter.com") { |http| http.get("/help/test") }
43
+ end
44
+
45
+ Right now, there are two configuration changes you can make in either style:
46
+
47
+ * +:label+ - This is the very first part of each log entry, and it gets
48
+ <tt>"Request"</tt> appended to it. By default, it's <tt>"HTTP"</tt> -- but if
49
+ you want your log to say +Twitter API Request+ instead of the default +HTTP
50
+ Request+, set this to <tt>"Twitter API"</tt>.
51
+ * +:filtered_params+ - This works just like Rails's +filter_parameter_logging+
52
+ method. Set it to a symbol, string, or array of them, and Samuel will filter
53
+ the value of query parameters that have any of these patterns as a substring
54
+ by replacing the value with <tt>[FILTERED]</tt> in your logs. By default, no
55
+ filtering is enabled.
56
+
57
+ Samuel logs successful HTTP requests at the +INFO+ level; Failed requests log at
58
+ the +WARN+ level. This isn't currently configurable, but it's on the list.
59
+
60
+ == License
61
+
62
+ Copyright 2009 Chris Kampmeier. See +LICENSE+ for details.
data/Rakefile ADDED
@@ -0,0 +1,62 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "samuel"
8
+ gem.summary = %Q{An automatic logger for HTTP requests in Ruby}
9
+ gem.description = %Q{An automatic logger for HTTP requests in Ruby. Adds Net::HTTP request logging to your Rails logs, and more.}
10
+ gem.email = "chris@kampers.net"
11
+ gem.homepage = "http://github.com/chrisk/samuel"
12
+ gem.authors = ["Chris Kampmeier"]
13
+ gem.rubyforge_project = "samuel"
14
+ gem.add_development_dependency "thoughtbot-shoulda"
15
+ gem.add_development_dependency "yard"
16
+ gem.add_development_dependency "mocha"
17
+ gem.add_development_dependency "fakeweb"
18
+ end
19
+ Jeweler::GemcutterTasks.new
20
+ Jeweler::RubyforgeTasks.new do |rubyforge|
21
+ rubyforge.doc_task = "yardoc"
22
+ end
23
+ rescue LoadError
24
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
25
+ end
26
+
27
+ require 'rake/testtask'
28
+ Rake::TestTask.new(:test) do |test|
29
+ test.libs << 'lib' << 'test'
30
+ test.pattern = 'test/**/*_test.rb'
31
+ test.verbose = false
32
+ test.warning = true
33
+ end
34
+
35
+ begin
36
+ require 'rcov/rcovtask'
37
+ Rcov::RcovTask.new do |test|
38
+ test.libs << 'test'
39
+ test.pattern = 'test/**/*_test.rb'
40
+ test.rcov_opts << "--sort coverage"
41
+ test.rcov_opts << "--exclude gems"
42
+ test.verbose = false
43
+ test.warning = true
44
+ end
45
+ rescue LoadError
46
+ task :rcov do
47
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
48
+ end
49
+ end
50
+
51
+ task :test => :check_dependencies
52
+
53
+ task :default => :test
54
+
55
+ begin
56
+ require 'yard'
57
+ YARD::Rake::YardocTask.new
58
+ rescue LoadError
59
+ task :yardoc do
60
+ abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
61
+ end
62
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.0
@@ -0,0 +1,10 @@
1
+ class Net::HTTP
2
+
3
+ alias request_without_samuel request
4
+ def request(req, body = nil, &block)
5
+ Samuel.log_request(self, req) do
6
+ request_without_samuel(req, body, &block)
7
+ end
8
+ end
9
+
10
+ end
@@ -0,0 +1,90 @@
1
+ module Samuel
2
+ class Request
3
+
4
+ attr_accessor :response
5
+
6
+ def initialize(http, request, proc)
7
+ @http, @request, @proc = http, request, proc
8
+ end
9
+
10
+ def execute_and_log!
11
+ # If an exception is raised in the Benchmark block, it'll interrupt the
12
+ # benchmark. Instead, use an inner block to record it as the "response"
13
+ # for raising after the benchmark (and logging) is done.
14
+ @seconds = Benchmark.realtime do
15
+ begin; @response = @proc.call; rescue Exception => @response; end
16
+ end
17
+ Samuel.logger.add(log_level, log_message)
18
+ raise @response if @response.is_a?(Exception)
19
+ end
20
+
21
+ private
22
+
23
+ def log_message
24
+ bold = "\e[1m"
25
+ blue = "\e[34m"
26
+ underline = "\e[4m"
27
+ reset = "\e[0m"
28
+ label = Samuel.config[:label]
29
+ " #{bold}#{blue}#{underline}#{label} request (#{milliseconds}ms) " +
30
+ "#{response_summary}#{reset} #{method} #{uri}"
31
+ end
32
+
33
+ def milliseconds
34
+ (@seconds * 1000).round
35
+ end
36
+
37
+ def uri
38
+ "#{scheme}://#{@http.address}#{port_if_not_default}#{filtered_path}"
39
+ end
40
+
41
+ def filtered_path
42
+ path_without_query, query = @request.path.split("?")
43
+ if query
44
+ patterns = [Samuel.config[:filtered_params]].flatten
45
+ patterns.map { |pattern|
46
+ pattern_for_regex = Regexp.escape(pattern.to_s)
47
+ [/([^&]*#{pattern_for_regex}[^&=]*)=(?:[^&]+)/, '\1=[FILTERED]']
48
+ }.each { |filter| query.gsub!(*filter) }
49
+ "#{path_without_query}?#{query}"
50
+ else
51
+ @request.path
52
+ end
53
+ end
54
+
55
+ def scheme
56
+ @http.use_ssl? ? "https" : "http"
57
+ end
58
+
59
+ def port_if_not_default
60
+ ssl, port = @http.use_ssl?, @http.port
61
+ if (!ssl && port == 80) || (ssl && port == 443)
62
+ ""
63
+ else
64
+ ":#{port}"
65
+ end
66
+ end
67
+
68
+ def method
69
+ @request.method.to_s.upcase
70
+ end
71
+
72
+ def response_summary
73
+ if response.is_a?(Exception)
74
+ response.class
75
+ else
76
+ "[#{response.code} #{response.message}]"
77
+ end
78
+ end
79
+
80
+ def log_level
81
+ error_classes = [Exception, Net::HTTPClientError, Net::HTTPServerError]
82
+ if error_classes.any? { |klass| response.is_a?(klass) }
83
+ level = Logger::WARN
84
+ else
85
+ level = Logger::INFO
86
+ end
87
+ end
88
+
89
+ end
90
+ end
data/lib/samuel.rb ADDED
@@ -0,0 +1,52 @@
1
+ require "logger"
2
+ require "net/http"
3
+ require "net/https"
4
+ require "benchmark"
5
+
6
+ require "samuel/net_http"
7
+ require "samuel/request"
8
+
9
+
10
+ module Samuel
11
+ extend self
12
+
13
+ attr_writer :config, :logger
14
+
15
+ def logger
16
+ @logger = nil if !defined?(@logger)
17
+ return @logger if !@logger.nil?
18
+
19
+ if defined?(RAILS_DEFAULT_LOGGER)
20
+ @logger = RAILS_DEFAULT_LOGGER
21
+ else
22
+ @logger = Logger.new(STDOUT)
23
+ end
24
+ end
25
+
26
+ def config
27
+ Thread.current[:__samuel_config] ? Thread.current[:__samuel_config] : @config
28
+ end
29
+
30
+ def log_request(http, request, &block)
31
+ request = Request.new(http, request, block)
32
+ request.execute_and_log!
33
+ request.response
34
+ end
35
+
36
+ def with_config(options = {})
37
+ original_config = config.dup
38
+ nested = !Thread.current[:__samuel_config].nil?
39
+
40
+ Thread.current[:__samuel_config] = original_config.merge(options)
41
+ yield
42
+ Thread.current[:__samuel_config] = nested ? original_config : nil
43
+ end
44
+
45
+ def reset_config
46
+ Thread.current[:__samuel_config] = nil
47
+ @config = {:label => "HTTP", :filtered_params => []}
48
+ end
49
+
50
+ end
51
+
52
+ Samuel.reset_config
data/samuel.gemspec ADDED
@@ -0,0 +1,69 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{samuel}
8
+ s.version = "0.2.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Chris Kampmeier"]
12
+ s.date = %q{2009-09-13}
13
+ s.description = %q{An automatic logger for HTTP requests in Ruby. Adds Net::HTTP request logging to your Rails logs, and more.}
14
+ s.email = %q{chris@kampers.net}
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/samuel.rb",
27
+ "lib/samuel/net_http.rb",
28
+ "lib/samuel/request.rb",
29
+ "samuel.gemspec",
30
+ "test/request_test.rb",
31
+ "test/samuel_test.rb",
32
+ "test/test_helper.rb",
33
+ "test/thread_test.rb"
34
+ ]
35
+ s.homepage = %q{http://github.com/chrisk/samuel}
36
+ s.rdoc_options = ["--charset=UTF-8"]
37
+ s.require_paths = ["lib"]
38
+ s.rubyforge_project = %q{samuel}
39
+ s.rubygems_version = %q{1.3.5}
40
+ s.summary = %q{An automatic logger for HTTP requests in Ruby}
41
+ s.test_files = [
42
+ "test/request_test.rb",
43
+ "test/samuel_test.rb",
44
+ "test/test_helper.rb",
45
+ "test/thread_test.rb"
46
+ ]
47
+
48
+ if s.respond_to? :specification_version then
49
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
50
+ s.specification_version = 3
51
+
52
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
53
+ s.add_development_dependency(%q<thoughtbot-shoulda>, [">= 0"])
54
+ s.add_development_dependency(%q<yard>, [">= 0"])
55
+ s.add_development_dependency(%q<mocha>, [">= 0"])
56
+ s.add_development_dependency(%q<fakeweb>, [">= 0"])
57
+ else
58
+ s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
59
+ s.add_dependency(%q<yard>, [">= 0"])
60
+ s.add_dependency(%q<mocha>, [">= 0"])
61
+ s.add_dependency(%q<fakeweb>, [">= 0"])
62
+ end
63
+ else
64
+ s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
65
+ s.add_dependency(%q<yard>, [">= 0"])
66
+ s.add_dependency(%q<mocha>, [">= 0"])
67
+ s.add_dependency(%q<fakeweb>, [">= 0"])
68
+ end
69
+ end
@@ -0,0 +1,178 @@
1
+ require 'test_helper'
2
+
3
+ class RequestTest < Test::Unit::TestCase
4
+
5
+ context "making an HTTP request" do
6
+ setup { setup_test_logger
7
+ FakeWeb.clean_registry
8
+ Samuel.reset_config }
9
+ teardown { teardown_test_logger }
10
+
11
+ context "to GET http://example.com/test, responding with a 200 in 53ms" do
12
+ setup do
13
+ FakeWeb.register_uri(:get, "http://example.com/test", :status => [200, "OK"])
14
+ Benchmark.stubs(:realtime).yields.returns(0.053)
15
+ open "http://example.com/test"
16
+ end
17
+
18
+ should_log_lines 1
19
+ should_log_at_level :info
20
+ should_log_including "HTTP request"
21
+ should_log_including "(53ms)"
22
+ should_log_including "[200 OK]"
23
+ should_log_including "GET http://example.com/test"
24
+ end
25
+
26
+ context "on a non-standard port" do
27
+ setup do
28
+ FakeWeb.register_uri(:get, "http://example.com:8080/test", :status => [200, "OK"])
29
+ open "http://example.com:8080/test"
30
+ end
31
+
32
+ should_log_including "GET http://example.com:8080/test"
33
+ end
34
+
35
+ context "with SSL" do
36
+ setup do
37
+ FakeWeb.register_uri(:get, "https://example.com/test", :status => [200, "OK"])
38
+ open "https://example.com/test"
39
+ end
40
+
41
+ should_log_including "HTTP request"
42
+ should_log_including "GET https://example.com/test"
43
+ end
44
+
45
+ context "with SSL on a non-standard port" do
46
+ setup do
47
+ FakeWeb.register_uri(:get, "https://example.com:80/test", :status => [200, "OK"])
48
+ open "https://example.com:80/test"
49
+ end
50
+
51
+ should_log_including "HTTP request"
52
+ should_log_including "GET https://example.com:80/test"
53
+ end
54
+
55
+ context "that raises" do
56
+ setup do
57
+ FakeWeb.register_uri(:get, "http://example.com/test", :exception => Errno::ECONNREFUSED)
58
+ begin
59
+ Net::HTTP.start("example.com") { |http| http.get("/test") }
60
+ rescue Errno::ECONNREFUSED => @exception
61
+ end
62
+ end
63
+
64
+ should_log_at_level :warn
65
+ should_log_including "HTTP request"
66
+ should_log_including "GET http://example.com/test"
67
+ should_log_including "Errno::ECONNREFUSED"
68
+ should_log_including %r|\d+ms|
69
+ should_raise_exception Errno::ECONNREFUSED
70
+ end
71
+
72
+ context "that responds with a 500-level code" do
73
+ setup do
74
+ FakeWeb.register_uri(:get, "http://example.com/test", :status => [502, "Bad Gateway"])
75
+ Net::HTTP.start("example.com") { |http| http.get("/test") }
76
+ end
77
+
78
+ should_log_at_level :warn
79
+ end
80
+
81
+ context "that responds with a 400-level code" do
82
+ setup do
83
+ FakeWeb.register_uri(:get, "http://example.com/test", :status => [404, "Not Found"])
84
+ Net::HTTP.start("example.com") { |http| http.get("/test") }
85
+ end
86
+
87
+ should_log_at_level :warn
88
+ end
89
+
90
+ context "inside a configuration block with :label => 'Example'" do
91
+ setup do
92
+ FakeWeb.register_uri(:get, "http://example.com/test", :status => [200, "OK"])
93
+ Samuel.with_config :label => "Example" do
94
+ open "http://example.com/test"
95
+ end
96
+ end
97
+
98
+ should_log_including "Example request"
99
+ should_have_config_afterwards_including :label => "HTTP"
100
+ end
101
+
102
+ context "inside a configuration block with :filter_params" do
103
+ setup do
104
+ FakeWeb.register_uri(:get, "http://example.com/test?password=secret&username=chrisk",
105
+ :status => [200, "OK"])
106
+ @uri = "http://example.com/test?password=secret&username=chrisk"
107
+ end
108
+
109
+ context "=> :password" do
110
+ setup { Samuel.with_config(:filtered_params => :password) { open @uri } }
111
+ should_log_including "http://example.com/test?password=[FILTERED]&username=chrisk"
112
+ end
113
+
114
+ context "=> :ass" do
115
+ setup { Samuel.with_config(:filtered_params => :ass) { open @uri } }
116
+ should_log_including "http://example.com/test?password=[FILTERED]&username=chrisk"
117
+ end
118
+
119
+ context "=> ['pass', 'name']" do
120
+ setup { Samuel.with_config(:filtered_params => %w(pass name)) { open @uri } }
121
+ should_log_including "http://example.com/test?password=[FILTERED]&username=[FILTERED]"
122
+ end
123
+ end
124
+
125
+ context "with a global config including :label => 'Example'" do
126
+ setup do
127
+ FakeWeb.register_uri(:get, "http://example.com/test", :status => [200, "OK"])
128
+ Samuel.config[:label] = "Example"
129
+ open "http://example.com/test"
130
+ end
131
+
132
+ should_log_including "Example request"
133
+ should_have_config_afterwards_including :label => "Example"
134
+ end
135
+
136
+ context "with a global config including :label => 'Example' but inside config block that changes it to 'Example 2'" do
137
+ setup do
138
+ FakeWeb.register_uri(:get, "http://example.com/test", :status => [200, "OK"])
139
+ Samuel.config[:label] = "Example"
140
+ Samuel.with_config(:label => "Example 2") { open "http://example.com/test" }
141
+ end
142
+
143
+ should_log_including "Example 2 request"
144
+ should_have_config_afterwards_including :label => "Example"
145
+ end
146
+
147
+ context "inside a config block of :label => 'Example 2' nested inside a config block of :label => 'Example'" do
148
+ setup do
149
+ FakeWeb.register_uri(:get, "http://example.com/test", :status => [200, "OK"])
150
+ Samuel.with_config :label => "Example" do
151
+ Samuel.with_config :label => "Example 2" do
152
+ open "http://example.com/test"
153
+ end
154
+ end
155
+ end
156
+
157
+ should_log_including "Example 2 request"
158
+ should_have_config_afterwards_including :label => "HTTP"
159
+ end
160
+
161
+ context "wth a global config including :label => 'Example' but inside a config block of :label => 'Example 3' nested inside a config block of :label => 'Example 2'" do
162
+ setup do
163
+ FakeWeb.register_uri(:get, "http://example.com/test", :status => [200, "OK"])
164
+ Samuel.config[:label] = "Example"
165
+ Samuel.with_config :label => "Example 2" do
166
+ Samuel.with_config :label => "Example 3" do
167
+ open "http://example.com/test"
168
+ end
169
+ end
170
+ end
171
+
172
+ should_log_including "Example 3 request"
173
+ should_have_config_afterwards_including :label => "Example"
174
+ end
175
+
176
+ end
177
+
178
+ end
@@ -0,0 +1,42 @@
1
+ require 'test_helper'
2
+
3
+ class SamuelTest < Test::Unit::TestCase
4
+
5
+ context "logger configuration" do
6
+ setup do
7
+ Samuel.logger = nil
8
+ if Object.const_defined?(:RAILS_DEFAULT_LOGGER)
9
+ Object.send(:remove_const, :RAILS_DEFAULT_LOGGER)
10
+ end
11
+ end
12
+
13
+ teardown do
14
+ Samuel.logger = nil
15
+ end
16
+
17
+ context "when Rails's logger is available" do
18
+ setup { Object.const_set(:RAILS_DEFAULT_LOGGER, :mock_logger) }
19
+
20
+ should "use the same logger" do
21
+ assert_equal :mock_logger, Samuel.logger
22
+ end
23
+ end
24
+
25
+ context "when Rails's logger is not available" do
26
+ should "use a new Logger instance pointed to STDOUT" do
27
+ assert_instance_of Logger, Samuel.logger
28
+ assert_equal STDOUT, Samuel.logger.instance_variable_get(:"@logdev").dev
29
+ end
30
+ end
31
+ end
32
+
33
+
34
+ context ".reset_config" do
35
+ should "reset the config to default vaules" do
36
+ Samuel.config = {:foo => "bar"}
37
+ Samuel.reset_config
38
+ assert_equal({:label => "HTTP", :filtered_params => []}, Samuel.config)
39
+ end
40
+ end
41
+
42
+ end
@@ -0,0 +1,66 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+ require 'mocha'
5
+ require 'open-uri'
6
+ require 'fakeweb'
7
+
8
+ FakeWeb.allow_net_connect = false
9
+
10
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
11
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
12
+ require 'samuel'
13
+
14
+ class Test::Unit::TestCase
15
+ TEST_LOG_PATH = File.join(File.dirname(__FILE__), 'test.log')
16
+
17
+ def self.should_log_lines(expected_count)
18
+ should "log #{expected_count} line#{'s' unless expected_count == 1}" do
19
+ lines = File.readlines(TEST_LOG_PATH)
20
+ assert_equal expected_count, lines.length
21
+ end
22
+ end
23
+
24
+ def self.should_log_including(what)
25
+ should "log a line including #{what.inspect}" do
26
+ contents = File.read(TEST_LOG_PATH)
27
+ if what.is_a?(Regexp)
28
+ assert_match what, contents
29
+ else
30
+ assert contents.include?(what),
31
+ "Expected #{contents.inspect} to include #{what.inspect}"
32
+ end
33
+ end
34
+ end
35
+
36
+ def self.should_log_at_level(level)
37
+ level = level.to_s.upcase
38
+ should "log at the #{level} level" do
39
+ assert File.read(TEST_LOG_PATH).include?(" #{level} -- :")
40
+ end
41
+ end
42
+
43
+ def self.should_raise_exception(klass)
44
+ should "raise an #{klass} exception" do
45
+ assert @exception.is_a?(klass)
46
+ end
47
+ end
48
+
49
+ def self.should_have_config_afterwards_including(config)
50
+ config.each_pair do |key, value|
51
+ should "continue afterwards with Samuel.config[#{key.inspect}] set to #{value.inspect}" do
52
+ assert_equal value, Samuel.config[key]
53
+ end
54
+ end
55
+ end
56
+
57
+ def setup_test_logger
58
+ FileUtils.rm_rf TEST_LOG_PATH
59
+ FileUtils.touch TEST_LOG_PATH
60
+ Samuel.logger = Logger.new(TEST_LOG_PATH)
61
+ end
62
+
63
+ def teardown_test_logger
64
+ FileUtils.rm_rf TEST_LOG_PATH
65
+ end
66
+ end
@@ -0,0 +1,32 @@
1
+ require 'test_helper'
2
+
3
+ class ThreadTest < Test::Unit::TestCase
4
+
5
+ context "when logging multiple requests at once" do
6
+ setup do
7
+ @log = StringIO.new
8
+ Samuel.logger = Logger.new(@log)
9
+ FakeWeb.register_uri(:get, /example\.com/, :status => [200, "OK"])
10
+ threads = []
11
+ 5.times do |i|
12
+ threads << Thread.new(i) do |n|
13
+ Samuel.with_config :label => "Example #{n}" do
14
+ Thread.pass
15
+ open "http://example.com/#{n}"
16
+ end
17
+ end
18
+ end
19
+ threads.each { |t| t.join }
20
+ @log.rewind
21
+ end
22
+
23
+ should "not let configuration blocks interfere with eachother" do
24
+ @log.each_line do |line|
25
+ matches = %r|Example (\d+).*example\.com/(\d+)|.match(line)
26
+ assert_not_nil matches
27
+ assert_equal matches[1], matches[2]
28
+ end
29
+ end
30
+ end
31
+
32
+ end
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: chrisk-samuel
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Chris Kampmeier
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-09-13 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: thoughtbot-shoulda
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: yard
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: mocha
37
+ type: :development
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: "0"
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: fakeweb
47
+ type: :development
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "0"
54
+ version:
55
+ description: An automatic logger for HTTP requests in Ruby. Adds Net::HTTP request logging to your Rails logs, and more.
56
+ email: chris@kampers.net
57
+ executables: []
58
+
59
+ extensions: []
60
+
61
+ extra_rdoc_files:
62
+ - LICENSE
63
+ - README.rdoc
64
+ files:
65
+ - .document
66
+ - .gitignore
67
+ - LICENSE
68
+ - README.rdoc
69
+ - Rakefile
70
+ - VERSION
71
+ - lib/samuel.rb
72
+ - lib/samuel/net_http.rb
73
+ - lib/samuel/request.rb
74
+ - samuel.gemspec
75
+ - test/request_test.rb
76
+ - test/samuel_test.rb
77
+ - test/test_helper.rb
78
+ - test/thread_test.rb
79
+ has_rdoc: false
80
+ homepage: http://github.com/chrisk/samuel
81
+ licenses:
82
+ post_install_message:
83
+ rdoc_options:
84
+ - --charset=UTF-8
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: "0"
92
+ version:
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: "0"
98
+ version:
99
+ requirements: []
100
+
101
+ rubyforge_project: samuel
102
+ rubygems_version: 1.3.5
103
+ signing_key:
104
+ specification_version: 3
105
+ summary: An automatic logger for HTTP requests in Ruby
106
+ test_files:
107
+ - test/request_test.rb
108
+ - test/samuel_test.rb
109
+ - test/test_helper.rb
110
+ - test/thread_test.rb