How do I log guzzle multi requests?

28 Views Asked by At

I have this code for creating a Guzzle client with logging:

$loggerMiddleware = new Logger(function ($level, $message, array $context) { ... }

$handler = new CurlMultiHandler();
$stack = HandlerStack::create($handler);
$stack->push($loggerMiddleware);
$client = new Client(['handler' => $stack]);

Now, when I use the other kind of handler, $handler = new CurlHandler();, the Logger function gives me a fully details $context array which has details about the request and repsonse.

The problem is, when I switch to $handler = new CurlMultiHandler();, the $context array no longer has a usable Response, $context['response'] is just meaningless when it's the MultiHandler.

How do I write a logger function where I can get the response back for CurlMultiHandler?

Edit: When I'm in this Logger callback with the useless $context['response'], I notice that I can check $context['reason'] and I see this message:

cURL error 61: Unrecognized content encoding type. libcurl understands deflate, gzip content encodings. (see https://curl.haxx.se/libcurl/c/libcurl-errors.html) for https://courierservices.saasc.uk/api/couriers/v1/Test/create-label

1

There are 1 best solutions below

0
Eyad Bereh On

In Laravel, you can listen to the Illuminate\Http\Client\Events\ResponseReceived event if you're using the built-in Laravel HTTP client (which uses Guzzle's HTTP client under the hood). This event provides two public properties:

  • $request: an instance of Illuminate\Http\Client\Request class, which you can use to further access more details about the outgoing request being done.
  • $response: an instance of Illuminate\Http\Client\Response class, which you can use to further access more details about the incoming response.

You may want to create a listener that listen to this event, for example:

<?php

namespace App\Listeners;

use Illuminate\Http\Client\Events\ResponseReceived;

class LogGuzzleResponse
{
    /**
     * Handle the event.
     */
    public function handle(ResponseReceived $event): void
    {
        info($event->request->headers());
        info($event->request->body());

        info($event->response->headers());
        info($event->response->body());
    }
}

And then you can bind this listener to the event inside the $listen attribute of your App\Providers\EventServiceProvider class as follows:

<?php

namespace App\Providers;

use App\Listeners\LogGuzzleResponse;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Http\Client\Events\ResponseReceived;

class EventServiceProvider extends ServiceProvider
{
    /**
     * The event to listener mappings for the application.
     *
     * @var array<class-string, array<int, class-string>>
     */
    protected $listen = [
        ResponseReceived::class => [
            LogGuzzleResponse::class
        ]
    ];
}

As you can see, this approach doesn't require you to use any middleware at all, and it works seamlessly.