Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trying to log request body, it logs the response instead #596

Closed
nthx opened this issue Jul 14, 2016 · 14 comments
Closed

Trying to log request body, it logs the response instead #596

nthx opened this issue Jul 14, 2016 · 14 comments

Comments

@nthx
Copy link

nthx commented Jul 14, 2016

Hi.

I'm trying to make 0.9.2 print both request & response bodies.
This is not documented, but discussed over in the #277 PR.
I think, I've made proper setup. I'm using Faraday via Saorin..

  @client = Saorin::Client.new(:url => @endpoint) do |connection|
    connection.response :logger, @logger, :bodies => true
  end

To my eye it looks, debug output doesn't print request body, but prints response body (not expected).
(and it follows printing response body again, as expected).

So I get sth like that in the log: (note value for request. It's duplicate of response actually.

post https://foo.bar.com/api/3.0/json-rpc
request User-Agent: "Faraday v0.9.2"
Content-Type: "application/json"
request {"result":{"accessGranted":false},"id":"foo","jsonrpc":"2.0"}
Status 200
response server: "nginx"
date: "Thu, 14 Jul 2016 21:28:21 GMT"
content-type: "application/json"
transfer-encoding: "chunked"
connection: "close"
response {"result":{"accessGranted":false},"id":"foo","jsonrpc":"2.0"}

Check this code of faraday/response/logger.rb:

    def call(env)
      info "#{env.method} #{env.url.to_s}"
      debug('request') { dump_headers env.request_headers }
      debug('request') { dump_body(env[:body]) } if env[:body] && log_body?(:request)
      super
    end

    def on_complete(env)
      info('Status') { env.status.to_s }
      debug('response') { dump_headers env.response_headers }
      debug('response') { dump_body env[:body] } if env[:body] && log_body?(:response)
    end

If I read it correctly, line: debug('request') { dump_body(env[:body]... prints not the proper var.

And, actually inspecting env[], I can't find request body nowhere :-( Only request_headers, request_options and response data.

Since, I don't believe nobody noticed that before, it's probably I've made some mistake. But where?

@stevenjack
Copy link

@nthx I'm seeing this as well..

@nthx
Copy link
Author

nthx commented Jul 28, 2016

@stve - does the report makes sense to you?

@nthx
Copy link
Author

nthx commented Jul 28, 2016

maybe it needs request configuration too? Haven't tried that though..

@client = Saorin::Client.new(:url => @endpoint) do |connection|
  connection.response :logger, @logger, :bodies => true
  connection.request :logger, @logger, :bodies => true
end

@LouisStAmour
Copy link

LouisStAmour commented Aug 10, 2016

It's a standard race condition, I think. What's happening here is that env[:body] was once set to the request's body. But by the time the log method or dump_body executes, the response body has replaced the request body inside env[:body] and no further variables/copies are made of the original request body, not that it would necessarily fix things. env is global to the request, we shouldn't assume middleware is executing synchronously and in order before the call is made.

An easy fix would be to use two env values to track bodies, one for request, and one for response.

We don't have this bug with headers because there are two separate values there: request_headers and response_headers. So why not follow their lead...

Alternatively, make a second env value called request_body and store the request body twice in both env.request_body and env.body. That way any code that relies on the existing behaviour keeps it, but updated code such as our logging function here can use request_body if it exists.

If this doesn't get fixed upstream soon, I'm very likely going to patch Faraday and use my own fork. I can't have unreliable logging...

@iMacTia
Copy link
Member

iMacTia commented Aug 23, 2016

@nthx, sorry if I missed it, but which logger are you using?
Code looks fine, the only "issue" I can see is with procs used to evaluate the message. This is usually not an issue, unless their evaluation happens AFTER the request is processed.
I'm not sure this is possible with the standard (synchronous) logger, so I would like to know which one you're using :)

@nthx
Copy link
Author

nthx commented Aug 29, 2016

Actually, I've been using my own logger in this case. It has worked for other messages, so I didn't think it might cause an issue.
I will verify with standard logger and re-check my own, and let you know.

@iMacTia
Copy link
Member

iMacTia commented Oct 13, 2016

Hi @nthx, any luck with your tests? Did you discover anything new?
I would like to close this issue and understand if the problem lies on Faraday or the logger

@iMacTia
Copy link
Member

iMacTia commented Nov 4, 2016

I'm going to close this assuming the fault lies on the logger as I tested the standard one and is working fine for me.

@nthx feel free to reopen in case you have any new evidence pointing to Faraday as the possible cause

@iMacTia iMacTia closed this as completed Nov 4, 2016
@LouisStAmour
Copy link

I still had this bug, using the Faraday built-in Logger at the time, but I solved it by writing my own logger in middleware, and later by switching from using Faraday to something simpler.

@llxff
Copy link

llxff commented Feb 16, 2017

Hi @iMacTia, I stuck with this problem too. I have found that problem reproduced when you define adapter before logger.

This code log request body:

Faraday.new(url: url) do |faraday|
  faraday.response :logger, ::Logger.new(STDOUT), bodies: true
  faraday.adapter Faraday.default_adapter
end

This don't:

Faraday.new(url: url) do |faraday|
  faraday.adapter Faraday.default_adapter
  faraday.response :logger, ::Logger.new(STDOUT), bodies: true
end

@iMacTia
Copy link
Member

iMacTia commented Feb 16, 2017

Hi @llxff,

yes that's expected as the middlewares order is critical and adapter should always be at the bottom.
If you put the adapter BEFORE, than the request will be performed before the logger adapter is reached, causing the response being logged twice.
Also, I'm now reading back @nthx issue with this and I just realised he's missing the adapter in his middlewares stack:

@client = Saorin::Client.new(:url => @endpoint) do |connection|
    connection.response :logger, @logger, :bodies => true
  end

I've also checked the code in Saorin gem and it looks completely wrong for the same exact reason: https://github.com/mashiro/saorin/blob/master/lib/saorin/client/faraday.rb#L16

@nthx
Copy link
Author

nthx commented Feb 19, 2017

Makes sense. I can't yet verify it again, but have another thought... I've read my initial report and it says:

This is not documented, but discussed over in the #277 PR.

Is this still the case, that there is no documentation on how actually configure logging of responses?
If the docs were there, then there would be no doubt on how to do it.

May you please create a ticket to update the docs? Or reopen this one maybe?

Also - who should contact Saorin guys?

@iMacTia
Copy link
Member

iMacTia commented Feb 20, 2017

Hi @nthx you're very right our documentation is currently not detailed enough (actually, we're using the Readme as a "documentation").
In your specific case, there's the 3rd example in the https://github.com/lostisland/faraday/blob/master/README.md#basic-use section which shows how to use the logger middleware, but I agree that's not enough.
We're planning to have a revamped Wiki in the near future which should help mitigating this sort of issues.

As per Saorin, I suggest you open an issue on their page providing examples with the failing code and reporting my comment, which should help them to track down the issue.
I prefer you doing this as you're actively using their gem and though will be able to provide any additional information they could need.

Thanks

@benja83
Copy link

benja83 commented Mar 14, 2017

Hi,

I've just saw this issue and I understand why my request was not well signed.

We created a middleware that add a signature before making the request.
As we define the adapter before using the middleware, the request was sent before adding the authorisation header.

The side effect was that the middleware was using the env.body to build the signature and so it was using the response body to build the signature.

As I was defining the adapter at the top of the connection, my logs were also wrong and I was thinking that my signature script was also wrong.

Best regards!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants