Logging Guzzle Requests

I’m working on a project that involves consuming a Json REST Api – it’s sometimes useful to log the requests being made – both for debugging and historical purposes.

I’m using the popular Guzzle package to consume the Api, which has the middleware concept built in – allowing developers to register hooks during the request lifecycle, and in our case – log them.

According to the Guzzle documentation, the way to do this is to pass a new HandlerStack with our logging middleware into our Client instance.

The syntax for creating a new Guzzle instance is as follows:

The $handlerStack will eventually hold the middleware that handles the logging.

Setting up the log file

Before I can set up the middleware, I need to instantiate something that handles writing our log messages to file. I’ll use the Monolog package to handle this – it makes it easy to achieve my desired criteria of having a daily log file next to my default laravel.log.

In my AppServiceProvider I’ll set up a helper function to create the logger:

Setting up the middleware

Guzzle’s logging middleware requires a logger (that I’ve just created above) and a MessageFormatter instance that controls what gets logged.

I’ll set up a helper function to create the middleware:

The $messageFormat is a string that “Formats log messages using variable substitutions for requests, responses, and other transactional data.” Possible substitutions can be seen here – but I’ve come up with some handy ones:

Logging the request:  {method} {uri} HTTP/{version} {req_body}
Logging the response:  RESPONSE: {code} - {res_body}

Creating the HandlerStack

Now that I have a way to easily new up an instance of Guzzle’s logging middleware, I can create a new HandlerStack to push the middleware onto:

Logging the request and response separately

I decided to log the request and response in two separate log entries. It seems like the only way to accomplish this is to push multiple logging middlewares to Guzzle, so I set up a helper function to create a HandlerStack with all the required logging middleware from an array of message format strings that I would like to log.

And there we have it! Now, adding multiple loggers to our Guzzle Client is as easy as the code below:

A short note on working with Guzzle responses

After setting up the logger, I realised that I was no longer able to access the response body – it turns out it was my mistake. 

Previously, I was accessing the response content using the following line:

But it turns out that this gets the “remaining contents of the body as a string” – and since the middleware already accessed the body in order to log it, there isn’t any content remaining to retrieve.

The correct way to access the response content is to cast the body to a string:

Resources

Share: Share on FacebookTweet about this on TwitterShare on LinkedIn
  • Spir

    Also there is that middleware:
    https://github.com/rtheunissen/guzzle-log-middleware

    I use it in production to log only failed request.

    • Definitely a good alternative – I’ll add it to the resources. Thanks!

  • artem moseev

    You can’t get content twice because it is “stream”. You need rewind stream for reading content second (etc) time:
    $stream = $response->getBody();
    $stream->rewind();
    $content = $stream->getContents();

  • Volodymyr

    >$this->logger = with(new MonologLogger(‘api-consumer’))->…

    What the function “with()” for?

    • It’s a helper function that simply returns whatever was passed into it – it makes chaining more readable!

      • Volodymyr

        Starting from PHP 5.4, You can use just round brackets:

        (new MonologLogger(‘api-consumer’))->WhatEverFunctionInLogger();