How to Log All API Calls Using Guzzle 6

How do you log all API calls using Guzzle 6

You can use any logger which implements PSR-3 interface with Guzzle 6

I used Monolog as logger and builtin middleware of Guzzle with MessageFormatter in below example.

use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
use GuzzleHttp\MessageFormatter;
use Monolog\Logger;

$stack = HandlerStack::create();
$stack->push(
Middleware::log(
new Logger('Logger'),
new MessageFormatter('{req_body} - {res_body}')
)
);
$client = new \GuzzleHttp\Client(
[
'base_uri' => 'http://httpbin.org',
'handler' => $stack,
]
);

echo (string) $client->get('ip')->getBody();

The details about the log middleware and message formatter has not well documented yet. But you can check the list which variables you can use in MessageFormatter

Also there is a guzzle-logmiddleware which allows you to customize formatter etc.

Is possible to log all Guzzle requests globally?

Yep, you can. Just pass your global instance of Guzzle's HTTP client to your OAuth provider. See this code for details.

For logging itself there is a question already.

Laravel - Log Guzzle requests to file

TLDR;

There’s an easy way to log all Guzzle requests by passing second parameter to Client and then it will log all the requests. But that’s ugly way if you have many methods using Guzzle Client to send request to third party server. I’ve done it using Laravel’s Service Container.

Long way via Laravel’s Service Container

When I used Guzzle client in my project and used handler to log all requests it looks good. But later on there were many methods in many different classes so I have to write logger logic every where. Then I thought why don’t to leverage Laravel’s Service Container and bind an object once and use it everywhere.

Here’s how I did it. In your AppServiceContainer.php’s boot method we will add all our code. And then in Controllers we will use our Client object.

Add this use statements on top of the AppServiceContainer.php file.

use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\MessageFormatter;
use GuzzleHttp\Middleware;
use Illuminate\Support\ServiceProvider;
use Monolog\Handler\RotatingFileHandler;
use Monolog\Logger;

Add below code to your AppServiceContainer.php’s boot method

/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
$this->app->bind('GuzzleClient', function () {

$messageFormats = [
'REQUEST: {method} - {uri} - HTTP/{version} - {req_headers} - {req_body}',
'RESPONSE: {code} - {res_body}',
];

$stack = HandlerStack::create();

collect($messageFormats)->each(function ($messageFormat) use ($stack) {
// We'll use unshift instead of push, to add the middleware to the bottom of the stack, not the top
$stack->unshift(
Middleware::log(
with(new Logger('guzzle-log'))->pushHandler(
new RotatingFileHandler(storage_path('logs/guzzle-log.log'))
),
new MessageFormatter($messageFormat)
)
);
});

return function ($config) use ($stack){
return new Client(array_merge($config, ['handler' => $stack]));
};
});
}

Explanation

If you have noticed above code, In first line of boot method we are telling Laravel that we want to register this code as a GuzzleClient in your Service Container.

In last return statement we are returning a function that will accept one argument $config. We used this function as a proxy so that we can pass an argument to it and that can be used in Client Object.

return function ($config) use ($stack){
return new Client(array_merge($config, ['handler' => $stack]));
};

Rest of the code is building Guzzle’s handler object to Log all requests to a file called guzzle-log.log using Logger object of Monolog library. If you have daily logs enabled, a date will be appended to file name like guzzle-log-2019-08-11.log.
Usage

We have binded our object to Service Container, now it’s time to use this container everywhere in our code, and make it looks clean.

For demo purpose I’ve used it directly in routes/web.php file. You can use anywhere.

 Route::get('/', function () {

$client = app('GuzzleClient')(['base_uri' => 'http://httpbin.org/']);

$request = $client->get('get',[
'query' => ['foo'=>'bar', 'baz' => 'baz2'] ,
'headers' => [ 'accept' => 'application/json']
]);
$response = json_decode((string) $request->getBody());
return response()->json($response);
});

As you can see I’m making an object $client using app() helper. Also you can pass any valid arguments array that Guzzle client supports as a second parameter. Here I’ve passed base_uri.

Log file entry

Source: http://shyammakwana.me/laravel/laravel-log-guzzle-requests-to-file-using-service-container.html

Get Api Data using Guzzle client

You should use guzzle as a tag as well, I would have answered that day, you need to change your code,

use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;

public function yourFunction()
{
try {
$client = new Client();
$guzzleResponse = $client->get(
'http://localhost:1080/busy/public/api/material', [
'headers' => [
'APP_KEY'=>'QAWLhIK2p5'
],
]);
if ($guzzleResponse->getStatusCode() == 200) {
$response = json_decode($guzzleResponse->getBody(),true);
}

} catch (RequestException $e) {
// you can catch here 400 response errors and 500 response errors
// see this https://stackoverflow.com/questions/25040436/guzzle-handle-400-bad-request/25040600
} catch(Exception $e){
//other errors
}
}

It is as easy as that, for more info, just see docs

How do I get the body of SENT data with Guzzle PHP?

You can do this work by creating a Middleware.

use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
use Psr\Http\Message\RequestInterface;

$stack = HandlerStack::create();
// my middleware
$stack->push(Middleware::mapRequest(function (RequestInterface $request) {
$contentsRequest = (string) $request->getBody();
//var_dump($contentsRequest);

return $request;
}));

$client = new Client([
'base_uri' => 'http://www.example.com/api/',
'handler' => $stack
]);

$response = $client->request('POST', 'itemupdate', [
'auth' => [$username, $password],
'json' => [
"key" => "value",
"key2" => "value",
]
]);

This, however, is triggered before to receive the response. You may want to do something like this:

$stack->push(function (callable $handler) {
return function (RequestInterface $request, array $options) use ($handler) {
return $handler($request, $options)->then(
function ($response) use ($request) {
// work here
$contentsRequest = (string) $request->getBody();
//var_dump($contentsRequest);
return $response;
}
);
};
});

Guzzle 6, get request string

As per Guzzle documentation there is debug option, here is the link from guzzle documentation
http://guzzle.readthedocs.org/en/latest/request-options.html#debug

$client->request('GET', '/get', ['debug' => true]);


Related Topics



Leave a reply



Submit