Skip to content

Commit

Permalink
Added support for PSR-3 (#272)
Browse files Browse the repository at this point in the history
* Added support for PSR-3

Co-authored-by: Greg Holmes <[email protected]>
  • Loading branch information
dragonmantank and Greg Holmes authored Mar 1, 2021
1 parent 0994517 commit 799e66d
Show file tree
Hide file tree
Showing 8 changed files with 200 additions and 6 deletions.
17 changes: 14 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -814,8 +814,20 @@ If you have a conflicting package installation that cannot co-exist with our rec

See the [Packagist page for client-implementation](https://packagist.org/providers/php-http/client-implementation) for options.

Contributing
------------
### Enabling Request/Response Logging

Our client library has support for logging the request and response for debugging via PSR-3 compatible logging mechanisms. If the `debug` option is passed into the client and a PSR-3 compatible logger is set in our client's service factory, we will use the logger for debugging purposes.

```php
$client = new \Vonage\Client(new \Vonage\Client\Credentials\Basic('abcd1234', 's3cr3tk3y'), ['debug' => true]);
$logger = new \Monolog\Logger('test');
$logger->pushHandler(new \Monolog\Handler\StreamHandler(__DIR__ . '/log.txt', \Monolog\Logger::DEBUG));
$client->getFactory()->set(\PSR\Log\LoggerInterface::class, $logger);
```

**ENABLING DEBUGING LOGGING HAS THE POTENTIAL FOR LOGGING SENSITIVE INFORMATION, DO NOT ENABLE IN PRODUCTION**

## Contributing

This library is actively developed, and we love to hear from you! Please feel free to [create an issue][issues] or [open a pull request][pulls] with your questions, comments, suggestions and feedback.

Expand All @@ -828,4 +840,3 @@ This library is actively developed, and we love to hear from you! Please feel fr
[spec]: https://github.com/Nexmo/client-library-specification
[issues]: https://github.com/Vonage/vonage-php-core/issues
[pulls]: https://github.com/Vonage/vonage-php-core/pulls

3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
"composer/package-versions-deprecated": "^1.11",
"psr/container": "^1.0",
"psr/http-client-implementation": "^1.0",
"vonage/nexmo-bridge": "^0.1.0"
"vonage/nexmo-bridge": "^0.1.0",
"psr/log": "^1.1"
},
"require-dev": {
"guzzlehttp/guzzle": ">=6",
Expand Down
59 changes: 57 additions & 2 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
use RuntimeException;
use Vonage\Account\ClientFactory;
use Vonage\Application\ClientFactory as ApplicationClientFactory;
Expand All @@ -41,6 +43,7 @@
use Vonage\Conversion\ClientFactory as ConversionClientFactory;
use Vonage\Entity\EntityInterface;
use Vonage\Insights\ClientFactory as InsightsClientFactory;
use Vonage\Logger\LoggerAwareInterface;
use Vonage\Message\Client as MessageClient;
use Vonage\Numbers\ClientFactory as NumbersClientFactory;
use Vonage\Redact\ClientFactory as RedactClientFactory;
Expand Down Expand Up @@ -68,6 +71,7 @@
use function str_replace;
use function strpos;
use function unserialize;
use Vonage\Logger\LoggerTrait;

/**
* Vonage API Client, allows access to the API from PHP.
Expand All @@ -86,8 +90,10 @@
* @property string restUrl
* @property string apiUrl
*/
class Client
class Client implements LoggerAwareInterface
{
use LoggerTrait;

public const VERSION = '2.5.0';
public const BASE_API = 'https://api.nexmo.com';
public const BASE_REST = 'https://rest.nexmo.com';
Expand All @@ -106,15 +112,25 @@ class Client
*/
protected $client;

/**
* @var bool
*/
protected $debug = false;

/**
* @var ContainerInterface
*/
protected $factory;

/**
* @var LoggerInterface
*/
protected $logger;

/**
* @var array
*/
protected $options = ['show_deprecations' => false];
protected $options = ['show_deprecations' => false, 'debug' => false];

/**
* Create a new API client using the provided credentials.
Expand Down Expand Up @@ -176,6 +192,10 @@ public function __construct(CredentialsInterface $credentials, $options = [], ?C
$this->apiUrl = $options['base_api_url'];
}

if (isset($options['debug'])) {
$this->debug = $options['debug'];
}

$this->setFactory(
new MapFactory(
[
Expand Down Expand Up @@ -532,6 +552,32 @@ public function send(RequestInterface $request): ResponseInterface
/** @noinspection PhpUnnecessaryLocalVariableInspection */
$response = $this->client->sendRequest($request);

if ($this->debug) {
$id = uniqid();
$request->getBody()->rewind();
$response->getBody()->rewind();
$this->log(
LogLevel::DEBUG,
'Request ' . $id,
[
'url' => $request->getUri()->__toString(),
'headers' => $request->getHeaders(),
'body' => explode("\n", $request->getBody()->__toString())
]
);
$this->log(
LogLevel::DEBUG,
'Response ' . $id,
[
'headers ' => $response->getHeaders(),
'body' => explode("\n", $response->getBody()->__toString())
]
);

$request->getBody()->rewind();
$response->getBody()->rewind();
}

return $response;
}

Expand Down Expand Up @@ -637,4 +683,13 @@ protected function getVersion(): string
{
return Versions::getVersion('vonage/client-core');
}

public function getLogger(): ?LoggerInterface
{
if (!$this->logger && $this->getFactory()->has(LoggerInterface::class)) {
$this->setLogger($this->getFactory()->get(LoggerInterface::class));
}

return $this->logger;
}
}
9 changes: 9 additions & 0 deletions src/Client/Factory/MapFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
namespace Vonage\Client\Factory;

use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface;
use RuntimeException;
use Vonage\Client;
use Vonage\Logger\LoggerAwareInterface;

use function is_callable;
use function sprintf;
Expand Down Expand Up @@ -120,11 +122,18 @@ public function make($key)
$instance->setClient($this->client);
}

if ($instance instanceof LoggerAwareInterface && $this->has(LoggerInterface::class)) {
$instance->setLogger($this->get(LoggerInterface::class));
}

return $instance;
}

public function set($key, $value): void
{
$this->map[$key] = $value;
if (!is_callable($value)) {
$this->cache[$key] = $value;
}
}
}
21 changes: 21 additions & 0 deletions src/Logger/LoggerAwareInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace Vonage\Logger;

use Psr\Log\LoggerInterface;

interface LoggerAwareInterface
{
public function getLogger(): ?LoggerInterface;

/**
* @param string|int $level Level of message that we are logging
* @param array<mixed> $context Additional information for context
*/
public function log($level, string $message, array $context = []): void;

/**
* @return self
*/
public function setLogger(LoggerInterface $logger);
}
35 changes: 35 additions & 0 deletions src/Logger/LoggerTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace Vonage\Logger;

use Psr\Log\LoggerInterface;

trait LoggerTrait
{
/**
* @var LoggerInterface
*/
protected $logger;

public function getLogger(): ?LoggerInterface
{
return $this->logger;
}

/**
* @param string|int $level Level of message that we are logging
* @param array<mixed> $context Additional information for context
*/
public function log($level, string $message, array $context = []): void
{
$logger = $this->getLogger();
if ($logger) {
$logger->log($level, $message, $context);
}
}

public function setLogger(LoggerInterface $logger)
{
$this->logger = $logger;
}
}
16 changes: 16 additions & 0 deletions test/ClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use Laminas\Diactoros\Response;
use PHPUnit\Framework\TestCase;
use Psr\Http\Client\ClientExceptionInterface;
use Psr\Log\LoggerInterface;
use RuntimeException;
use Vonage\Client;
use Vonage\Client\Credentials\Basic;
Expand Down Expand Up @@ -664,6 +665,21 @@ public function testGenericDeleteMethod($url, $params): void
$this->assertRequestBodyIsEmpty($request);
}

public function testLoggerIsNullWhenNotSet(): void
{
$client = new Client($this->basic_credentials, [], $this->http);
$this->assertNull($client->getLogger());
}

public function testCanGetLoggerWhenOneIsSet(): void
{
$client = new Client($this->basic_credentials, [], $this->http);
$logger = $this->prophesize(LoggerInterface::class);
$client->getFactory()->set(LoggerInterface::class, $logger->reveal());

$this->assertNotNull($client->getLogger());
}

public function genericDeleteProvider(): array
{
$baseUrl = 'https://rest.nexmo.com';
Expand Down
46 changes: 46 additions & 0 deletions test/Logger/LoggerTraitTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

namespace VonageTest\Logger;

use Psr\Log\LoggerInterface;
use Vonage\Logger\LoggerTrait;
use PHPUnit\Framework\TestCase;

class LoggerTraitTest extends TestCase
{
public function testCanSetAndGetLogger()
{
/** @var LoggerTrait $trait */
$trait = $this->getMockForTrait(LoggerTrait::class);
$logger = $this->prophesize(LoggerInterface::class)->reveal();
$trait->setLogger($logger);

$this->assertSame($logger, $trait->getLogger());
}

public function testNoLoggerReturnsNull()
{
/** @var LoggerTrait $trait */
$trait = $this->getMockForTrait(LoggerTrait::class);

$this->assertNull($trait->getLogger());
}

public function testCanLogMessageWithLogger()
{
/** @var LoggerTrait $trait */
$trait = $this->getMockForTrait(LoggerTrait::class);
$logger = $this->prophesize(LoggerInterface::class)->reveal();
$trait->setLogger($logger);

$this->assertNull($trait->log('debug', 'This is a message'));
}

public function testLoggingAcceptsMessageWithLogger()
{
/** @var LoggerTrait $trait */
$trait = $this->getMockForTrait(LoggerTrait::class);

$this->assertNull($trait->log('debug', 'This is a message'));
}
}

0 comments on commit 799e66d

Please sign in to comment.