Skip to content

Commit

Permalink
Merge pull request #119 from anfly0/psr3_logging_trasports
Browse files Browse the repository at this point in the history
Psr3 logging trasports
  • Loading branch information
robbieaverill authored Dec 17, 2019
2 parents 7c01a9a + 12130c9 commit 3a37375
Show file tree
Hide file tree
Showing 6 changed files with 333 additions and 12 deletions.
16 changes: 11 additions & 5 deletions UsageExampleV2.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,8 @@ $httpClient = new GuzzleHttp\Client([

// If synchronous message delivery is wanted use Raygun4php\Transports\GuzzleSync
$transport = new Raygun4php\Transports\GuzzleAsync($httpClient);

$client = new Raygun4php\RaygunClient($transport);


// Create and register error handlers
function error_handler($errno, $errstr, $errfile, $errline )
{
Expand Down Expand Up @@ -47,9 +45,17 @@ function fatal_error()
}
}

set_exception_handler('exception_handler');
set_error_handler("error_handler");
register_shutdown_function("fatal_error");
function flush_on_shutdown()
{
global $transport;
$transport->wait();
}

set_exception_handler('exception_handler');
set_error_handler("error_handler");
register_shutdown_function("fatal_error");

// This is needed to if guzzleAsync is used as transport to make sure all request are resolved.
register_shutdown_function("flush_on_shutdown");

```
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
],
"require": {
"php": "^7.1",
"guzzlehttp/guzzle": "~6.0"
"guzzlehttp/guzzle": "~6.0",
"psr/log": "^1.1"
},
"require-dev": {
"phpunit/phpunit": "^7.0",
Expand Down
52 changes: 48 additions & 4 deletions src/Raygun4php/Transports/GuzzleAsync.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,21 @@
use Raygun4php\Interfaces\RaygunMessageInterface;
use Raygun4php\Interfaces\TransportInterface;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Exception\TransferException;
use GuzzleHttp\Promise;
use Psr\Http\Message\ResponseInterface;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;

class GuzzleAsync implements TransportInterface
class GuzzleAsync implements TransportInterface, LoggerAwareInterface
{
/**
* @var LoggerInterface
*/
private $logger;

/**
* @var ClientInterface
*/
Expand All @@ -27,11 +37,12 @@ class GuzzleAsync implements TransportInterface
public function __construct(ClientInterface $httpClient)
{
$this->httpClient = $httpClient;
$this->logger = new NullLogger();
}

/**
* Asynchronously transmits the message to the raygun API.
* Relies on the destructor of this object to settle any pending requests.
* Relies on the wait() method of this object being called to settle any pending requests.
*
* @param RaygunMessageInterface $message
* @return boolean
Expand All @@ -42,14 +53,47 @@ public function transmit(RaygunMessageInterface $message): bool

try {
$this->httpPromises[] = $this->httpClient
->requestAsync('POST', '/entries', ['body' => $messageJson]);
->requestAsync('POST', '/entries', ['body' => $messageJson])
->then(
function (ResponseInterface $response) use ($messageJson) {
$responseCode = $response->getStatusCode();
if ($responseCode !== 202) {
$logMsg = "Expected response code 202 but got {$responseCode}";
if ($responseCode < 400) {
$this->logger->warning($logMsg, json_decode($messageJson, true));
} else {
$this->logger->error($logMsg, json_decode($messageJson, true));
}
}
},
function (RequestException $exception) use ($messageJson) {
$this->logger->error($exception->getMessage(), json_decode($messageJson, true));
}
)
;
} catch (TransferException $th) {
return false;
}
return true;
}

public function __destruct()
/**
* @param LoggerInterface $logger
* @return void
*/
public function setLogger(LoggerInterface $logger): void
{
$this->logger = $logger;
}

/**
* Calling this method will settle any pending request.
* Calling this method should typically handled by a function registered as a shutdown function.
* @see https://www.php.net/manual/en/function.register-shutdown-function.php
*
* @return void
*/
public function wait(): void
{
Promise\settle($this->httpPromises)->wait(false);
}
Expand Down
33 changes: 31 additions & 2 deletions src/Raygun4php/Transports/GuzzleSync.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,17 @@
use Raygun4php\Interfaces\TransportInterface;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\Exception\TransferException;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;

class GuzzleSync implements TransportInterface
class GuzzleSync implements TransportInterface, LoggerAwareInterface
{
/**
* @var LoggerInterface
*/
private $logger;

/**
* @var ClientInterface
*/
Expand All @@ -21,6 +29,7 @@ class GuzzleSync implements TransportInterface
public function __construct(ClientInterface $httpClient)
{
$this->httpClient = $httpClient;
$this->logger = new NullLogger();
}

/**
Expand All @@ -37,10 +46,30 @@ public function transmit(RaygunMessageInterface $message): bool
$httpResponse = $this->httpClient
->request('POST', '/entries', ['body' => $messageJson]);
} catch (TransferException $th) {
$this->logger->error($th->getMessage(), json_decode($messageJson, true));
return false;
}

$responseCode = $httpResponse->getStatusCode();
return $responseCode === 202;

if ($responseCode !== 202) {
$logMsg = "Expected response code 202 but got {$responseCode}";
if ($responseCode < 400) {
$this->logger->warning($logMsg, json_decode($messageJson, true));
} else {
$this->logger->error($logMsg, json_decode($messageJson, true));
}
return false;
}
return true;
}

/**
* @param LoggerInterface $logger
* @return void
*/
public function setLogger(LoggerInterface $logger): void
{
$this->logger = $logger;
}
}
81 changes: 81 additions & 0 deletions tests/Transports/GuzzleAsyncTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?php

namespace Raygun4php\Tests\Transports;

use GuzzleHttp\Client;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;
use PHPUnit\Framework\TestCase;
use Psr\Log\Test\TestLogger;
use Raygun4php\RaygunMessage;
use Raygun4php\Transports\GuzzleAsync;

class GuzzleAsyncTest extends TestCase
{

public function testTransmitLogsErrorIfResponseCodeIs400()
{
$mock = new MockHandler([
new Response(400)
]);

$handler = HandlerStack::create($mock);
$client = new Client(['handler' => $handler]);

$transport = new GuzzleAsync($client);
$message = new RaygunMessage();

$logger = new TestLogger();
$transport->setLogger($logger);

$transport->transmit($message);
$transport->wait();

$this->assertTrue($logger->hasErrorRecords());
}

public function testTransmitLogsWarningIfResponseCodeIs200()
{
$mock = new MockHandler([
new Response(200)
]);

$handler = HandlerStack::create($mock);
$client = new Client(['handler' => $handler]);

$transport = new GuzzleAsync($client);
$message = new RaygunMessage();

$logger = new TestLogger();
$transport->setLogger($logger);

$transport->transmit($message);
$transport->wait();

$this->assertTrue($logger->hasWarningRecords());
}

public function testTransmitLogsErrorIfHttpClientThrowsException()
{
$mock = new MockHandler([
new ConnectException('Connection failed', new Request('POST', 'test'))
]);

$handler = HandlerStack::create($mock);
$client = new Client(['handler' => $handler]);

$transport = new GuzzleAsync($client);
$message = new RaygunMessage();

$logger = new TestLogger();
$transport->setLogger($logger);

$transport->transmit($message);
$transport->wait();

$this->assertTrue($logger->hasErrorRecords());
}
}
Loading

0 comments on commit 3a37375

Please sign in to comment.