How do you log all API calls using Guzzle 6
Asked Answered
B

4

27

I'm trying to use guzzle 6 which works fine but I'm lost when it comes to how to log all the api calls. I would like to simply log timing, logged in user from session, url and any other usual pertinent info that has to do with the API call. I can't seem to find any documentation for Guzzle 6 that refers to this, only guzzle 3 (Where they've changed the logging addSubscriber call). This is how my current API calls are:

$client = new GuzzleHttp\Client(['defaults' => ['verify' => false]]);
$res = $client->get($this->url . '/api/details', ['form_params' => ['file' => $file_id]]);
Braithwaite answered 20/9, 2015 at 15:39 Comment(0)
L
72

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.

Lumpfish answered 20/9, 2015 at 22:24 Comment(5)
Where do you specify the name of the log file in this code? Thanks for posting this!Braithwaite
I didn't set the handler in example. You can chose which kind of handler you will use in logger. If you want to log your messages to file, you should pick StreamHandler. check the monolog documentation for other options. You can pass the handler while creating Logger or set it after via pushHandler method. check this example @BraithwaiteLumpfish
This worked as mentioned! but @Lumpfish Can you please help to do the same in laravel where I use single line API call like $response = Http::withBody( json_encode($reqArray), 'application/json')->withToken($token)->post($SearchByNameApi); I also ask question regarding this #67920540 i feel happy if you help me to achieve thisChickenhearted
If you log the response then you need to rewind the response body, otherwise you will get empty data. $response->getBody()->rewind(); and then $response->getBody()->getContents();. Or you can also rewind adding another handler: $mapResponse = Middleware::mapResponse( function(ResponseInterface $response) { $response->getBody()->rewind(); return $response; } ); $stack->push($mapResponse);Territus
@NuryagdyMustapayev $responseBody = (string)$response->getBody(); does the same: rewind and deliver contentJaimie
C
8

@KingKongFrog This is the way to specify the name of the log file

$logger = new Logger('MyLog');
$logger->pushHandler(new StreamHandler(__DIR__ . '/test.log'), Logger::DEBUG);

$stack->push(Middleware::log(
$logger,
new MessageFormatter('{req_body} - {res_body}')
));
Coheir answered 30/8, 2017 at 8:44 Comment(1)
To work properly use Monolog\Handler\StreamHandler; needs to be added. Good example.Verwoerd
L
1

For Guzzle 7 I did this::

require './guzzle_7.2.0.0/vendor/autoload.php';
require './monolog/vendor/autoload.php';

use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Pool;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;

use GuzzleHttp\MessageFormatter;
use Monolog\Logger;
use Monolog\Handler\StreamHandler;

use GuzzleHttp\TransferStats;

//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
$logger = null;
$messageFormat = 
            //['REQUEST: ', 'METHOD: {method}', 'URL: {uri}', 'HTTP/{version}', 'HEADERS: {req_headers}', 'Payload: {req_body}', 'RESPONSE: ', 'STATUS: {code}', 'BODY: {res_body}'];
            'REQUEST: urldecode(req_body)';
$handlerStack = \GuzzleHttp\HandlerStack::create(); 
$handlerStack->push(createGuzzleLoggingMiddleware($messageFormat));
function getLogger() {
    global $logger;
    if ($logger==null) {
        $logger = new Logger('api-consumer');
        $logger->pushHandler(new \Monolog\Handler\RotatingFileHandler('./TataAigHealthErrorMiddlewarelog.txt'));
    }
    var_dump($logger);
    return $logger;
    }
function createGuzzleLoggingMiddleware(string $messageFormat){
    return \GuzzleHttp\Middleware::log(getLogger(), new \GuzzleHttp\MessageFormatter($messageFormat));
}

function createLoggingHandlerStack(array $messageFormats){  
    global $logger;
    $stack = \GuzzleHttp\HandlerStack::create();
    var_dump($logger);
    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(createGuzzleLoggingMiddleware($messageFormat) );
    });
    return $stack;
}
//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$

$client = new Client(['verify' => false, 'handler' => $tapMiddleware($handlerStack)]);

WOW !!

Levulose answered 2/11, 2020 at 19:54 Comment(0)
M
1

unshift() is indeed better than push() in reverse order ...

$handlers = HandlerStack::create();
$logger = new Logger('Logger');
$templates = [
    '{code} >> {req_headers}',
    '{code} >> {req_body}',
    '{code} << {res_headers}',
    '{code} << {res_body}'
];
foreach ($templates as $template) {
    $handlers->unshift($this->getMiddleware($logger, $template));
}
$client = new Client([
    RequestOptions::DEBUG => false,
    'handler' => $handlers
]);

Using this function to obtain the Middleware:

private function getMiddleware(Logger $logger, string $template): callable {
    return Middleware::log($logger, new MessageFormatter($template));
}

Logger comes from "monolog/monolog": "^1.27.1".

And these are all supported variable substitutions.

Morphogenesis answered 13/1, 2023 at 17:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.