diff --git a/README.md b/README.md index 27e0dea..46e354a 100644 --- a/README.md +++ b/README.md @@ -498,7 +498,7 @@ $ restclient put http://example.com/resource < input_body ## Logging -To enable logging you can: +To enable logging globally you can: - set RestClient.log with a Ruby Logger, or - set an environment variable to avoid modifying the code (in this case you can use a file name, "stdout" or "stderr"): @@ -506,7 +506,14 @@ To enable logging you can: ```ruby $ RESTCLIENT_LOG=stdout path/to/my/program ``` -Either produces logs like this: + +You can also set individual loggers when instantiating a Resource: + +```ruby +resource = RestClient::Resource.new 'http://example.com/resource', log: Logger.new(STDOUT) +``` + +All options produce logs like this: ```ruby RestClient.get "http://some/resource" diff --git a/lib/restclient/request.rb b/lib/restclient/request.rb index 144c3fe..7f16614 100644 --- a/lib/restclient/request.rb +++ b/lib/restclient/request.rb @@ -131,6 +131,7 @@ module RestClient end end + @log = args[:log] @tf = nil # If you are a raw request, this is your tempfile @max_redirects = args[:max_redirects] || 10 @processed_headers = make_headers headers @@ -525,19 +526,24 @@ module RestClient redacted_uri.to_s end + # Default to the global logger if there's not a request-specific one + def log + @log || RestClient.log + end + def log_request - return unless RestClient.log + return unless log out = [] out << "RestClient.#{method} #{redacted_url.inspect}" out << payload.short_inspect if payload out << processed_headers.to_a.sort.map { |(k, v)| [k.inspect, v.inspect].join("=>") }.join(", ") - RestClient.log << out.join(', ') + "\n" + log << out.join(', ') + "\n" end def log_response res - return unless RestClient.log + return unless log size = if @raw_response File.size(@tf.path) @@ -545,7 +551,7 @@ module RestClient res.body.nil? ? 0 : res.body.size end - RestClient.log << "# => #{res.code} #{res.class.to_s.gsub(/^Net::HTTP/, '')} | #{(res['Content-type'] || '').gsub(/;.*$/, '')} #{size} bytes\n" + log << "# => #{res.code} #{res.class.to_s.gsub(/^Net::HTTP/, '')} | #{(res['Content-type'] || '').gsub(/;.*$/, '')} #{size} bytes\n" end # Return a hash of headers whose keys are capitalized strings @@ -776,13 +782,13 @@ module RestClient http_response.read_body do |chunk| @tf.write chunk size += chunk.size - if RestClient.log + if log if size == 0 - RestClient.log << "%s %s done (0 length file)\n" % [@method, @url] + log << "%s %s done (0 length file)\n" % [@method, @url] elsif total == 0 - RestClient.log << "%s %s (zero content length)\n" % [@method, @url] + log << "%s %s (zero content length)\n" % [@method, @url] else - RestClient.log << "%s %s %d%% done (%d of %d)\n" % [@method, @url, (size * 100) / total, size, total] + log << "%s %s %d%% done (%d of %d)\n" % [@method, @url, (size * 100) / total, size, total] end end end diff --git a/lib/restclient/resource.rb b/lib/restclient/resource.rb index 955f682..a5c41ac 100644 --- a/lib/restclient/resource.rb +++ b/lib/restclient/resource.rb @@ -51,7 +51,8 @@ module RestClient Request.execute(options.merge( :method => :get, :url => url, - :headers => headers), &(block || @block)) + :headers => headers, + :log => log), &(block || @block)) end def head(additional_headers={}, &block) @@ -59,7 +60,8 @@ module RestClient Request.execute(options.merge( :method => :head, :url => url, - :headers => headers), &(block || @block)) + :headers => headers, + :log => log), &(block || @block)) end def post(payload, additional_headers={}, &block) @@ -68,7 +70,8 @@ module RestClient :method => :post, :url => url, :payload => payload, - :headers => headers), &(block || @block)) + :headers => headers, + :log => log), &(block || @block)) end def put(payload, additional_headers={}, &block) @@ -77,7 +80,8 @@ module RestClient :method => :put, :url => url, :payload => payload, - :headers => headers), &(block || @block)) + :headers => headers, + :log => log), &(block || @block)) end def patch(payload, additional_headers={}, &block) @@ -86,7 +90,8 @@ module RestClient :method => :patch, :url => url, :payload => payload, - :headers => headers), &(block || @block)) + :headers => headers, + :log => log), &(block || @block)) end def delete(additional_headers={}, &block) @@ -94,7 +99,8 @@ module RestClient Request.execute(options.merge( :method => :delete, :url => url, - :headers => headers), &(block || @block)) + :headers => headers, + :log => log), &(block || @block)) end def to_s @@ -121,6 +127,10 @@ module RestClient options[:open_timeout] end + def log + options[:log] || RestClient.log + end + # Construct a subresource, preserving authentication. # # Example: diff --git a/lib/restclient/response.rb b/lib/restclient/response.rb index 1f0ba89..2683fb5 100644 --- a/lib/restclient/response.rb +++ b/lib/restclient/response.rb @@ -38,6 +38,10 @@ module RestClient "" end + def log + request.log + end + def self.create(body, net_http_res, request) result = self.new(body || '') @@ -54,8 +58,8 @@ module RestClient begin encoding = Encoding.find(charset) if charset rescue ArgumentError - if RestClient.log - RestClient.log << "No such encoding: #{charset.inspect}" + if response.log + response.log << "No such encoding: #{charset.inspect}" end end diff --git a/spec/unit/request_spec.rb b/spec/unit/request_spec.rb index fbce5ee..9854f79 100644 --- a/spec/unit/request_spec.rb +++ b/spec/unit/request_spec.rb @@ -687,6 +687,12 @@ describe RestClient::Request, :include_helpers do RestClient::Request.new(:method => :get, :url => 'http://user:password@url', :headers => {:user_agent => 'rest-client'}).log_request expect(log[0]).to eq %Q{RestClient.get "http://user:REDACTED@url", "Accept"=>"*/*", "Accept-Encoding"=>"gzip, deflate", "User-Agent"=>"rest-client"\n} end + + it 'logs to a passed logger, if provided' do + logger = double('logger', '<<' => true) + expect(logger).to receive(:<<) + RestClient::Request.new(:method => :get, :url => 'http://user:password@url', log: logger).log_request + end end it "strips the charset from the response content type" do diff --git a/spec/unit/resource_spec.rb b/spec/unit/resource_spec.rb index 3777767..676e95d 100644 --- a/spec/unit/resource_spec.rb +++ b/spec/unit/resource_spec.rb @@ -7,37 +7,37 @@ describe RestClient::Resource do context "Resource delegation" do it "GET" do - expect(RestClient::Request).to receive(:execute).with(:method => :get, :url => 'http://some/resource', :headers => {'X-Something' => '1'}, :user => 'jane', :password => 'mypass') + expect(RestClient::Request).to receive(:execute).with(:method => :get, :url => 'http://some/resource', :headers => {'X-Something' => '1'}, :user => 'jane', :password => 'mypass', :log => nil) @resource.get end it "HEAD" do - expect(RestClient::Request).to receive(:execute).with(:method => :head, :url => 'http://some/resource', :headers => {'X-Something' => '1'}, :user => 'jane', :password => 'mypass') + expect(RestClient::Request).to receive(:execute).with(:method => :head, :url => 'http://some/resource', :headers => {'X-Something' => '1'}, :user => 'jane', :password => 'mypass', :log => nil) @resource.head end it "POST" do - expect(RestClient::Request).to receive(:execute).with(:method => :post, :url => 'http://some/resource', :payload => 'abc', :headers => {:content_type => 'image/jpg', 'X-Something' => '1'}, :user => 'jane', :password => 'mypass') + expect(RestClient::Request).to receive(:execute).with(:method => :post, :url => 'http://some/resource', :payload => 'abc', :headers => {:content_type => 'image/jpg', 'X-Something' => '1'}, :user => 'jane', :password => 'mypass', :log => nil) @resource.post 'abc', :content_type => 'image/jpg' end it "PUT" do - expect(RestClient::Request).to receive(:execute).with(:method => :put, :url => 'http://some/resource', :payload => 'abc', :headers => {:content_type => 'image/jpg', 'X-Something' => '1'}, :user => 'jane', :password => 'mypass') + expect(RestClient::Request).to receive(:execute).with(:method => :put, :url => 'http://some/resource', :payload => 'abc', :headers => {:content_type => 'image/jpg', 'X-Something' => '1'}, :user => 'jane', :password => 'mypass', :log => nil) @resource.put 'abc', :content_type => 'image/jpg' end it "PATCH" do - expect(RestClient::Request).to receive(:execute).with(:method => :patch, :url => 'http://some/resource', :payload => 'abc', :headers => {:content_type => 'image/jpg', 'X-Something' => '1'}, :user => 'jane', :password => 'mypass') + expect(RestClient::Request).to receive(:execute).with(:method => :patch, :url => 'http://some/resource', :payload => 'abc', :headers => {:content_type => 'image/jpg', 'X-Something' => '1'}, :user => 'jane', :password => 'mypass', :log => nil) @resource.patch 'abc', :content_type => 'image/jpg' end it "DELETE" do - expect(RestClient::Request).to receive(:execute).with(:method => :delete, :url => 'http://some/resource', :headers => {'X-Something' => '1'}, :user => 'jane', :password => 'mypass') + expect(RestClient::Request).to receive(:execute).with(:method => :delete, :url => 'http://some/resource', :headers => {'X-Something' => '1'}, :user => 'jane', :password => 'mypass', :log => nil) @resource.delete end it "overrides resource headers" do - expect(RestClient::Request).to receive(:execute).with(:method => :get, :url => 'http://some/resource', :headers => {'X-Something' => '2'}, :user => 'jane', :password => 'mypass') + expect(RestClient::Request).to receive(:execute).with(:method => :get, :url => 'http://some/resource', :headers => {'X-Something' => '2'}, :user => 'jane', :password => 'mypass', :log => nil) @resource.get 'X-Something' => '2' end end diff --git a/spec/unit/response_spec.rb b/spec/unit/response_spec.rb index 096c2ab..1d62d76 100644 --- a/spec/unit/response_spec.rb +++ b/spec/unit/response_spec.rb @@ -238,4 +238,16 @@ describe RestClient::Response, :include_helpers do end end + describe "logging" do + it "uses the request's logger" do + stub_request(:get, 'http://some/resource').to_return(body: 'potato', status: 200) + + logger = double('logger', '<<' => true) + request = RestClient::Request.new(url: 'http://some/resource', method: :get, log: logger) + + expect(logger).to receive(:<<) + + request.execute + end + end end