Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* httpclient_support: (36 commits) Regenerate gemspec Rename an internal module to make a more accurate historical reference :) Rename an internal method for clarity Rakefile: less sudo Rakefile: Add httpclient as a development dependency Rakefile: remove YARD as a development dependency, since we do a begin/rescue around the task definition Rakefile: update gem description for HTTPClient support Some RDoc syntax fixes in the README Add info to the README about HTTPClient support Move internal code out of the top-level module, so it only contains the end-user API Stop saving logged requests, so the GC can remove them Reorder methods so all the config methods are together again Refactor Samuel.load_drivers to be more concise Reorganize code into a consistent module/filesystem structure Extend loaded HTTP drivers using modules instead of dynamically requiring files Always load all LogEntry subclasses, now that they can be safely loaded without loading the HTTP drivers Check classes using strings, so this file can be safely required when Net::HTTP isn't loaded Make sure Net::HTTP requests are still logged when Net::HTTP raises during the connection stage Only load extensions for the HTTP drivers already loaded. We're not using benchmark anymore ... Conflicts: README.rdoc
- Loading branch information
Showing
17 changed files
with
587 additions
and
158 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
module Samuel | ||
module Diary | ||
extend self | ||
|
||
def record_request(http, request, time_requested) | ||
@requests ||= [] | ||
@requests.push({:request => request, :time_requested => time_requested}) | ||
end | ||
|
||
def record_response(http, request, response, time_responded) | ||
time_requested = @requests.detect { |r| r[:request] == request }[:time_requested] | ||
@requests.reject! { |r| r[:request] == request } | ||
log_request_and_response(http, request, response, time_requested, time_responded) | ||
end | ||
|
||
private | ||
|
||
def log_request_and_response(http, request, response, time_started, time_ended) | ||
log_entry_class = case http.class.to_s | ||
when "Net::HTTP" then LogEntries::NetHttp | ||
when "HTTPClient" then LogEntries::HttpClient | ||
else raise NotImplementedError | ||
end | ||
log_entry = log_entry_class.new(http, request, response, time_started, time_ended) | ||
log_entry.log! | ||
end | ||
|
||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
module Samuel | ||
module DriverPatches | ||
|
||
module HTTPClient | ||
def self.included(klass) | ||
methods_to_wrap = %w(initialize do_get_block do_get_stream) | ||
methods_to_wrap.each do |method| | ||
klass.send(:alias_method, "#{method}_without_samuel", method) | ||
klass.send(:alias_method, method, "#{method}_with_samuel") | ||
end | ||
end | ||
|
||
def initialize_with_samuel(*args) | ||
initialize_without_samuel(*args) | ||
@request_filter << LoggingFilter.new(self) | ||
end | ||
|
||
def do_get_block_with_samuel(req, proxy, conn, &block) | ||
begin | ||
do_get_block_without_samuel(req, proxy, conn, &block) | ||
rescue Exception => e | ||
Samuel::Diary.record_response(self, req, e, Time.now) | ||
raise | ||
end | ||
end | ||
|
||
def do_get_stream_with_samuel(req, proxy, conn) | ||
begin | ||
do_get_stream_without_samuel(req, proxy, conn) | ||
rescue Exception => e | ||
Samuel::Diary.record_response(self, req, e, Time.now) | ||
raise | ||
end | ||
end | ||
|
||
class LoggingFilter | ||
def initialize(http_client_instance) | ||
@http_client_instance = http_client_instance | ||
end | ||
|
||
def filter_request(request) | ||
Samuel::Diary.record_request(@http_client_instance, request, Time.now) | ||
end | ||
|
||
def filter_response(request, response) | ||
Samuel::Diary.record_response(@http_client_instance, request, response, Time.now) | ||
nil # this returns command symbols like :retry, etc. | ||
end | ||
end | ||
end | ||
|
||
end | ||
end | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
module Samuel | ||
module DriverPatches | ||
|
||
module NetHTTP | ||
def self.included(klass) | ||
methods_to_wrap = %w(request connect) | ||
methods_to_wrap.each do |method| | ||
klass.send(:alias_method, "#{method}_without_samuel", method) | ||
klass.send(:alias_method, method, "#{method}_with_samuel") | ||
end | ||
end | ||
|
||
def request_with_samuel(request, body = nil, &block) | ||
Samuel::Diary.record_request(self, request, Time.now) | ||
|
||
response, exception_raised = nil, false | ||
begin | ||
response = request_without_samuel(request, body, &block) | ||
rescue Exception => response | ||
exception_raised = true | ||
end | ||
|
||
Samuel::Diary.record_response(self, request, response, Time.now) | ||
|
||
raise response if exception_raised | ||
response | ||
end | ||
|
||
def connect_with_samuel | ||
connect_without_samuel | ||
rescue Exception => response | ||
fake_request = Object.new | ||
def fake_request.path; ""; end | ||
def fake_request.method; "CONNECT"; end | ||
Samuel::Diary.record_request(self, fake_request, Time.now) | ||
Samuel::Diary.record_response(self, fake_request, response, Time.now) | ||
raise | ||
end | ||
end | ||
|
||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
module Samuel | ||
module Loader | ||
extend self | ||
|
||
def apply_driver_patches | ||
loaded = { :net_http => defined?(Net::HTTP), | ||
:http_client => defined?(HTTPClient) } | ||
|
||
Net::HTTP.send(:include, DriverPatches::NetHTTP) if loaded[:net_http] | ||
HTTPClient.send(:include, DriverPatches::HTTPClient) if loaded[:http_client] | ||
|
||
if loaded.values.none? | ||
require 'net/http' | ||
apply_driver_patches | ||
end | ||
end | ||
|
||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
module Samuel | ||
module LogEntries | ||
|
||
class Base | ||
def initialize(http, request, response, time_requested, time_responded) | ||
@http, @request, @response = http, request, response | ||
@seconds = time_responded - time_requested | ||
end | ||
|
||
def log! | ||
Samuel.logger.add(log_level, log_message) | ||
end | ||
|
||
|
||
protected | ||
|
||
def log_message | ||
bold = "\e[1m" | ||
blue = "\e[34m" | ||
underline = "\e[4m" | ||
reset = "\e[0m" | ||
" #{bold}#{blue}#{underline}#{label} request (#{milliseconds}ms) " + | ||
"#{response_summary}#{reset} #{method} #{uri}" | ||
end | ||
|
||
def milliseconds | ||
(@seconds * 1000).round | ||
end | ||
|
||
def uri | ||
"#{scheme}://#{host}#{port_if_not_default}#{path}#{'?' if query}#{filtered_query}" | ||
end | ||
|
||
def label | ||
return Samuel.config[:label] if Samuel.config[:label] | ||
|
||
pair = Samuel.config[:labels].detect { |domain, label| host.include?(domain) } | ||
pair[1] if pair | ||
end | ||
|
||
def response_summary | ||
if @response.is_a?(Exception) | ||
@response.class | ||
else | ||
"[#{status_code} #{status_message}]" | ||
end | ||
end | ||
|
||
def log_level | ||
error? ? Logger::WARN : Logger::INFO | ||
end | ||
|
||
def ssl? | ||
scheme == 'https' | ||
end | ||
|
||
def filtered_query | ||
return "" if query.nil? | ||
patterns = [Samuel.config[:filtered_params]].flatten | ||
patterns.map { |pattern| | ||
pattern_for_regex = Regexp.escape(pattern.to_s) | ||
[/([^&]*#{pattern_for_regex}[^&=]*)=(?:[^&]+)/, '\1=[FILTERED]'] | ||
}.inject(query) { |filtered, filter| filtered.gsub(*filter) } | ||
end | ||
|
||
def port_if_not_default | ||
if (!ssl? && port == 80) || (ssl? && port == 443) | ||
"" | ||
else | ||
":#{port}" | ||
end | ||
end | ||
end | ||
|
||
end | ||
end |
Oops, something went wrong.