Search code examples
phpguzzlemonologaws-php-sdkguzzle6

Response logging in AWS PHP SDK v3


In v2 of the AWS PHP SDK, I was able to setup logging of request and response information by simply doing this:

<?php
use Monolog\Logger;
use Guzzle\Log\MonologLogAdapter;
use Guzzle\Plugin\Log\LogPlugin;
use Aws\S3\S3Client;
$monolog = new Logger('main');
$monolog_adapter = new MonologLogAdapter($monolog);
$log_plugin = new LogPlugin($monolog_adapter);
$s3_client = S3Client::factory(['region' => 'us-east-1']);
$s3_client->addSubscriber($log_plugin);
var_dump($s3_client->doesObjectExist('my-bucket', 'object-that-doesnt-exist'));

# This is the log entry I want in the v3 version:
# [2015-10-30 14:47:20] main.ERROR: myhostname aws-sdk-php2/2.8.20 Guzzle/3.9.3 curl/7.43.0 PHP/5.5.23 - [2015-10-30T14:47:20+00:00] "HEAD /my-bucket/object-that-doesnt-exist HTTP/1.1" 404  ...
# bool(false)

In v3, I cannot seem to find the solution. Middlewares do not seem helpful as they only fire before the request is sent, and thus I cannot access the response HTTP code.

Guzzle v6 has this feature built into its Middlewares, but I do not know how to get it to work with the aws-php-sdk. https://github.com/guzzle/guzzle/blob/master/src/Middleware.php#L180

The closest I got was this:

<?php
use Monolog\Logger;
use GuzzleHttp\MessageFormatter;
use GuzzleHttp\Middleware;
use GuzzleHttp\HandlerStack;
use Aws\S3\S3Client;
$monolog = new Logger('main');
$guzzle_formatter = new MessageFormatter(MessageFormatter::CLF);
$guzzle_log_middleware = Middleware::log($monolog, $guzzle_formatter);
$guzzle_stack = HandlerStack::create();
$guzzle_stack->push($guzzle_log_middleware);
$s3_client = new S3Client([
    'region' => 'us-east-1',
    'version' => '2006-03-01',
    'http_handler' => $guzzle_stack,
]);
var_dump($s3_client->doesObjectExist('my-bucket', 'object-that-doesnt-exist'));

# [2015-10-30 15:10:12] main.INFO: myhostname aws-sdk-php/3.9.2 - [30/Oct/2015:15:10:12 +0000] "HEAD /my-bucket/object-that-doesnt-exist HTTP/1.1" 404  [] []
# bool(true)

However, while the logging works, doesObjectExist() now returns the incorrect value because this handler does not throw an exception for 404, which the aws-php-sdk expects to happen. Some other simple requests like uploading to S3 seemed to work at first glance. Not sure where else there could be issues with this method.


Solution

  • The handler used in the SDK is a bit different from the one used in Guzzle. You're creating a Guzzle handler correctly, and to pass that into the SDK, you would need to create an adapter like so:

    <?php
    
    use Aws\Handler\GuzzleV6\GuzzleHandler;
    use Aws\S3\S3Client;
    use Monolog\Logger;
    use GuzzleHttp\Client;
    use GuzzleHttp\MessageFormatter;
    use GuzzleHttp\Middleware;
    use GuzzleHttp\HandlerStack;
    
    $guzzle_stack = HandlerStack::create();
    $guzzle_stack->push(Middleware::log(
        new Logger('main'), 
        new MessageFormatter(MessageFormatter::CLF)
    ));
    
    $handler = new GuzzleHandler(new Client(['handler' => $guzzle_stack]));
    
    $s3_client = new S3Client([
        'region' => 'us-east-1',
        'version' => '2006-03-01',
        'http_handler' => $handler,
    ]);
    
    var_dump($s3_client->doesObjectExist('my-bucket', 'object-that-doesnt-exist'));
    

    The GuzzleHandler object converts HTTP errors to exceptions.