1
0
Fork 0
mirror of https://github.com/rest-client/rest-client.git synced 2022-11-09 13:49:40 -05:00

First try(cherry picked from commit eece9eda0487969e582ef97e6a41f86780a53d08)

This commit is contained in:
Julien Kirch 2010-01-05 21:03:27 +01:00
parent 5cee63c615
commit 16a4dbf9dd
4 changed files with 129 additions and 92 deletions

View file

@ -88,16 +88,14 @@ module RestClient
attr_accessor :proxy
end
# Print log of RestClient calls. Value can be stdout, stderr, or a filename.
# Setup the log for RestClient calls.
# Value should be a logger but can can be stdout, stderr, or a filename.
# You can also configure logging by the environment variable RESTCLIENT_LOG.
def self.log=(log)
@@log = log
end
def self.log # :nodoc:
return ENV['RESTCLIENT_LOG'] if ENV['RESTCLIENT_LOG']
return @@log if defined? @@log
nil
def self.log= log
if log.is_a? String
warn "[warning] You should set the log with a logger"
end
@@log = create_log log
end
def self.version
@ -105,4 +103,49 @@ module RestClient
return File.read(version_path).chomp if File.file?(version_path)
"0.0.0"
end
# Create a log that respond to << like a logger
# param can be 'stdout', 'stderr', a string (then we will log to that file) or a logger (then we return it)
def self.create_log param
if param
if param.is_a? String
if param == 'stdout'
stdout_logger = Class.new do
def << obj
STDOUT.puts obj
end
end
stdout_logger.new
elsif param == 'stderr'
stderr_logger = Class.new do
def << obj
STDERR.puts obj
end
end
stderr_logger.new
else
file_logger = Class.new do
attr_writer :target_file
def << obj
File.open(@target_file, 'a') { |f| f.puts obj }
end
end
logger = file_logger.new
logger.target_file = param
logger
end
else
param
end
end
end
@@env_log = create_log ENV['RESTCLIENT_LOG']
@@log = nil
def self.log # :nodoc:
@@env_log || @@log
end
end

View file

@ -73,13 +73,13 @@ module RestClient
target_value = value.to_s
final[target_key] = MIME::Types.type_for_extension target_value
elsif 'ACCEPT' == target_key.upcase
# Accept can be composed of several comma-separated values
if value.is_a? Array
target_values = value
else
target_values = value.to_s.split ','
end
final[target_key] = target_values.map{ |ext| MIME::Types.type_for_extension(ext.to_s.strip)}.join(', ')
# Accept can be composed of several comma-separated values
if value.is_a? Array
target_values = value
else
target_values = value.to_s.split ','
end
final[target_key] = target_values.map{ |ext| MIME::Types.type_for_extension(ext.to_s.strip)}.join(', ')
else
final[target_key] = value.to_s
end
@ -148,12 +148,12 @@ module RestClient
net.read_timeout = @timeout if @timeout
net.open_timeout = @open_timeout if @open_timeout
display_log request_log
log_request
net.start do |http|
res = http.request(req, payload) { |http_response| fetch_body(http_response) }
result = process_result(res)
display_log response_log(res)
log_response res
if result.kind_of?(String) or @method == :head
Response.new(result, res)
@ -183,12 +183,14 @@ module RestClient
http_response.read_body do |chunk|
@tf.write(chunk)
size += chunk.size
if size == 0
display_log("#{@method} #{@url} done (0 length file)")
elsif total == 0
display_log("#{@method} #{@url} (zero content length)")
else
display_log("#{@method} #{@url} %d%% done (%d of %d)" % [(size * 100) / total, size, total])
if RestClient.log
if size == 0
RestClient.log << "#{@method} #{@url} done (0 length file)"
elsif total == 0
RestClient.log << "#{@method} #{@url} (zero content length)"
else
RestClient.log << "#{@method} #{@url} %d%% done (%d of %d)" % [(size * 100) / total, size, total]
end
end
end
@tf.close
@ -236,30 +238,20 @@ module RestClient
end
end
def request_log
def log_request
if RestClient.log
out = []
out << "RestClient.#{method} #{url.inspect}"
out << "headers: #{processed_headers.inspect}"
out << "payload: #{payload.short_inspect}" if payload
out.join(', ')
out << payload.short_inspect if payload
out << processed_headers.inspect.gsub(/^\{/, '').gsub(/\}$/, '')
RestClient.log << out.join(', ')
end
end
def response_log(res)
size = @raw_response ? File.size(@tf.path) : (res.body.nil? ? 0 : res.body.size)
"# => #{res.code} #{res.class.to_s.gsub(/^Net::HTTP/, '')} | #{(res['Content-type'] || '').gsub(/;.*$/, '')} #{size} bytes"
end
def display_log(msg)
return unless log_to = RestClient.log
if log_to == 'stdout'
STDOUT.puts msg
elsif log_to == 'stderr'
STDERR.puts msg
else
File.open(log_to, 'a') { |f| f.puts msg }
def log_response res
if RestClient.log
size = @raw_response ? File.size(@tf.path) : (res.body.nil? ? 0 : res.body.size)
RestClient.log << "# => #{res.code} #{res.class.to_s.gsub(/^Net::HTTP/, '')} | #{(res['Content-type'] || '').gsub(/;.*$/, '')} #{size} bytes"
end
end
@ -274,7 +266,7 @@ module MIME
# Return the first found content-type for a value considered as an extension or the value itself
def type_for_extension ext
candidates = @extension_index[ext]
candidates = @extension_index[ext]
candidates.empty? ? ext : candidates[0].content_type
end

View file

@ -15,7 +15,7 @@ describe RestClient::Request do
@net.stub!(:start).and_yield(@http)
@net.stub!(:use_ssl=)
@net.stub!(:verify_mode=)
RestClient.log = 'test.log'
RestClient.log = nil
end
it "accept */* mimetype, preferring xml" do
@ -150,7 +150,7 @@ describe RestClient::Request do
it "transmits the request with Net::HTTP" do
@http.should_receive(:request).with('req', 'payload')
@request.should_receive(:process_result)
@request.should_receive(:response_log)
@request.should_receive(:log_response)
@request.transmit(@uri, 'req', 'payload')
end
@ -289,71 +289,63 @@ describe RestClient::Request do
end
it "logs a get request" do
['RestClient.get "http://url", headers: {"Accept-encoding"=>"gzip, deflate", "Accept"=>"*/*; q=0.5, application/xml"}',
'RestClient.get "http://url", headers: {"Accept"=>"*/*; q=0.5, application/xml", "Accept-encoding"=>"gzip, deflate}'].should include
RestClient::Request.new(:method => :get, :url => 'http://url').request_log
log = RestClient.log = []
RestClient::Request.new(:method => :get, :url => 'http://url').log_request
['RestClient.get "http://url", "Accept-encoding"=>"gzip, deflate", "Accept"=>"*/*; q=0.5, application/xml"',
'RestClient.get "http://url", "Accept"=>"*/*; q=0.5, application/xml", "Accept-encoding"=>"gzip, deflate"'].should include(log[0])
end
it "logs a post request with a small payload" do
['RestClient.post "http://url", headers: {"Accept-encoding"=>"gzip, deflate", "Content-Length"=>"3", "Accept"=>"*/*; q=0.5, application/xml"}, paylod: "foo"',
'RestClient.post "http://url", headers: {"Accept"=>"*/*; q=0.5, application/xml", "Accept-encoding"=>"gzip, deflate", "Content-Length"=>"3"}, paylod: "foo"'].should include
RestClient::Request.new(:method => :post, :url => 'http://url', :payload => 'foo').request_log
log = RestClient.log = []
RestClient::Request.new(:method => :post, :url => 'http://url', :payload => 'foo').log_request
['RestClient.post "http://url", "foo", "Accept-encoding"=>"gzip, deflate", "Content-Length"=>"3", "Accept"=>"*/*; q=0.5, application/xml"',
'RestClient.post "http://url", "foo", "Accept"=>"*/*; q=0.5, application/xml", "Accept-encoding"=>"gzip, deflate", "Content-Length"=>"3"'].should include(log[0])
end
it "logs a post request with a large payload" do
['RestClient.post "http://url", headers: {"Accept-encoding"=>"gzip, deflate", "Content-Length"=>"1000", "Accept"=>"*/*; q=0.5, application/xml"}, paylod: 1000 byte length',
'RestClient.post "http://url", headers: {"Accept"=>"*/*; q=0.5, application/xml", "Accept-encoding"=>"gzip, deflate", "Content-Length"=>"1000"}, paylod: 1000 byte length'].should include
RestClient::Request.new(:method => :post, :url => 'http://url', :payload => ('x' * 1000)).request_log
log = RestClient.log = []
RestClient::Request.new(:method => :post, :url => 'http://url', :payload => ('x' * 1000)).log_request
['RestClient.post "http://url", 1000 byte length, "Accept-encoding"=>"gzip, deflate", "Content-Length"=>"1000", "Accept"=>"*/*; q=0.5, application/xml"',
'RestClient.post "http://url", 1000 byte length, "Accept"=>"*/*; q=0.5, application/xml", "Accept-encoding"=>"gzip, deflate", "Content-Length"=>"1000"'].should include(log[0])
end
it "logs input headers as a hash" do
['RestClient.get "http://url", headers: {"Accept-encoding"=>"gzip, deflate", "Accept"=>"text/plain"}',
'RestClient.get "http://url", headers: {"Accept"=>"text/plain", "Accept-encoding"=>"gzip, deflate"}'].should include
RestClient::Request.new(:method => :get, :url => 'http://url', :headers => { :accept => 'text/plain' })
log = RestClient.log = []
RestClient::Request.new(:method => :get, :url => 'http://url', :headers => { :accept => 'text/plain' }).log_request
['RestClient.get "http://url", "Accept-encoding"=>"gzip, deflate", "Accept"=>"text/plain"',
'RestClient.get "http://url", "Accept"=>"text/plain", "Accept-encoding"=>"gzip, deflate"'].should include(log[0])
end
it "logs a response including the status code, content type, and result body size in bytes" do
log = RestClient.log = []
res = mock('result', :code => '200', :class => Net::HTTPOK, :body => 'abcd')
res.stub!(:[]).with('Content-type').and_return('text/html')
@request.response_log(res).should == "# => 200 OK | text/html 4 bytes"
@request.log_response res
log[0].should == "# => 200 OK | text/html 4 bytes"
end
it "logs a response with a nil Content-type" do
log = RestClient.log = []
res = mock('result', :code => '200', :class => Net::HTTPOK, :body => 'abcd')
res.stub!(:[]).with('Content-type').and_return(nil)
@request.response_log(res).should == "# => 200 OK | 4 bytes"
@request.log_response res
log[0].should == "# => 200 OK | 4 bytes"
end
it "logs a response with a nil body" do
log = RestClient.log = []
res = mock('result', :code => '200', :class => Net::HTTPOK, :body => nil)
res.stub!(:[]).with('Content-type').and_return('text/html; charset=utf-8')
@request.response_log(res).should == "# => 200 OK | text/html 0 bytes"
@request.log_response res
log[0].should == "# => 200 OK | text/html 0 bytes"
end
it "strips the charset from the response content type" do
log = RestClient.log = []
res = mock('result', :code => '200', :class => Net::HTTPOK, :body => 'abcd')
res.stub!(:[]).with('Content-type').and_return('text/html; charset=utf-8')
@request.response_log(res).should == "# => 200 OK | text/html 4 bytes"
end
it "displays the log to stdout" do
RestClient.stub!(:log).and_return('stdout')
STDOUT.should_receive(:puts).with('xyz')
@request.display_log('xyz')
end
it "displays the log to stderr" do
RestClient.stub!(:log).and_return('stderr')
STDERR.should_receive(:puts).with('xyz')
@request.display_log('xyz')
end
it "append the log to the requested filename" do
RestClient.stub!(:log).and_return('/tmp/restclient.log')
f = mock('file handle')
File.should_receive(:open).with('/tmp/restclient.log', 'a').and_yield(f)
f.should_receive(:puts).with('xyz')
@request.display_log('xyz')
@request.log_response res
log[0].should == "# => 200 OK | text/html 4 bytes"
end
it "set read_timeout" do

View file

@ -33,21 +33,31 @@ describe RestClient do
RestClient.log = nil
end
it "gets the log source from the RESTCLIENT_LOG environment variable" do
ENV.stub!(:[]).with('RESTCLIENT_LOG').and_return('from env')
RestClient.log = 'from class method'
RestClient.log.should == 'from env'
it "uses << if the log is not a string" do
log = RestClient.log = []
log.should_receive(:<<).with('xyz')
RestClient.log << 'xyz'
end
it "sets a destination for log output, used if no environment variable is set" do
ENV.stub!(:[]).with('RESTCLIENT_LOG').and_return(nil)
RestClient.log = 'from class method'
RestClient.log.should == 'from class method'
it "displays the log to stdout" do
RestClient.log = 'stdout'
STDOUT.should_receive(:puts).with('xyz')
RestClient.log << 'xyz'
end
it "returns nil (no logging) if neither are set (default)" do
ENV.stub!(:[]).with('RESTCLIENT_LOG').and_return(nil)
RestClient.log.should == nil
it "displays the log to stderr" do
RestClient.log = 'stderr'
STDERR.should_receive(:puts).with('xyz')
RestClient.log << 'xyz'
end
it "append the log to the requested filename" do
RestClient.log = '/tmp/restclient.log'
f = mock('file handle')
File.should_receive(:open).with('/tmp/restclient.log', 'a').and_yield(f)
f.should_receive(:puts).with('xyz')
RestClient.log << 'xyz'
end
end
end