-
Notifications
You must be signed in to change notification settings - Fork 38
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor raygun client #117
Refactor raygun client #117
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added some cursory comments. Some other notes:
- breaking changes - all good, this is 2.x-dev already in master
- "Raygun" prefixes on existing classes - I think
Raygun4php\Client
would probably be better thanRaygun4php\RaygunClient
, especially since you've changed the constructor signature so people's implementations will break obviously anyway, this is the right time to rename classes if you want to do so - "It would probably be nice to have a client factory." - yes, agreed, particularly since you have provided both sync and async transport options
Thanks for the PR!
I'd like to get some feedback from the Raygun team before this gets merged in, but I'm happy to provide some suggestions along the way.
{ | ||
public function build(\Exception $exception): void; | ||
|
||
public function toJson(): string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I've mentioned this before, but perhaps we should use JsonSerializable here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mentioned in #116 my reasoning behind toJson()
is to not have to deal with the encoding issus solved by toJsonRemoveUnicodeSequences()
and removeNullBytes()
.
It is at mather of taste, but I like it when an object takes care of all aspects of serializing itself.
$this->httpPromises[] = $this->httpClient | ||
->requestAsync('POST', '/entries', ['body' => $messageJson]); | ||
} catch (TransferException $th) { | ||
return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Providing some pluggability here somehow would probably be a good thing, this will be hard to debug for people having failed API calls
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that is definitely true.
One idea is to implement PSR-3 LoggerAwareInterface and add appropriate logging
} | ||
|
||
$responseCode = $httpResponse->getStatusCode(); | ||
return $responseCode === 202; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is 202 always returned from the Raygun API?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, but 202 is the only one that signifies success.
success = true
fail = false
I've merged #116 for you |
@robbieaverill I'm looking into some of the things you commented on. But I don't think I will push any more commits to this pr before the Raygun team has taken a look. |
cc @MindscapeHQ/external-php-admins for review when you have a chance |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work with this, these changes are looking good and the transmission of data a lot more reliable. I've just pointed out a few minor stylistic issues and some questions around how things work. The tests are good, I assume you've tested this with a sample app and it's all working as expected?
There were a couple of items in the PR description which I feel might need addressing:
- Might be some dead code left in RaygunClient. Is this still relevant? Ideally any unused code would be deleted
- Readme needs updating. Could this be done as part of this PR? Would we need separate docs for v1.x?
src/Raygun4php/RaygunMessage.php
Outdated
|
||
private function toJsonRemoveUnicodeSequences($struct) | ||
{ | ||
return preg_replace_callback("/\\\\u([a-f0-9]{4})/", function ($matches) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would good to have a comment explaining exactly what's happening here...
It looks like we're replacing all instances of unicode strings with UTF-8 encoded strings. Is this a standard operation? Why UCS-4LE
? Why is the V
(unsigned long) format string used?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a leftover from version 1, and I'm not really sure of the what's and the why's of this implementation. The change I made was to move this method from the client class to the message class.
Anyhow, there is definitely room for improvements regarding this method, but I think it is a bit out of scope for this pr.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 I agree, the improvements to this are out of scope
$this->httpPromises[] = $this->httpClient | ||
->requestAsync('POST', '/entries', ['body' => $messageJson]); | ||
} catch (TransferException $th) { | ||
return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we do something besides just returning false here? Could the exception at least be logged if in debug mode?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes.
One idea is to implement PSR-3 LoggerAwareInterface and add appropriate logging.
Do you have any other suggestions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could create a callback (e.g onTransmissionFailure($th, $message)
) which can be defined in the initial RaygunClient setup. That way developers could choose what to do with the exception. If in debug mode we could log the exception - the LoggerAwareInterface
looks really good.
* Synchronously transmits the message to the raygun API. | ||
* | ||
* @param RaygunMessageInterface $message | ||
* @return boolean False if request fails or of the response status code is not 202. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/s "... fails or if the response status ..."
$httpResponse = $this->httpClient | ||
->request('POST', '/entries', ['body' => $messageJson]); | ||
} catch (TransferException $th) { | ||
return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above, would be good to log something if the request fails
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above, PSR-3.
$this->transportMock = $this->getMockBuilder(TransportInterface::class) | ||
->setMethods(['transmit']) | ||
->getMock(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Delete extra space here
$client->SendException(new \Exception('test')); | ||
$raygunMessage = $transportStub->getMessage(); | ||
|
||
$this->assertJsonMatchesSchemaString($this->jsonSchema, json_decode($raygunMessage->toJson())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this necessary? It looks like it's encoding as JSON, then decoding again: json_decode($raygunMessage->toJson())
- is this to do with the removal of unicode chars and null strings?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I think it is.
The reason for this is that I want the test to be decoupled from the implementation of RaygunMessage.
The test is essentially asserting that in the client $transport->transmit($message)
is called with a message the can produce a valid JSON representation of itself.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 Cool, makes sense
public function removeNullBytes($string) | ||
{ | ||
return str_replace("\0", '', $string); | ||
return $this->transport->transmit($message); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great job deleting this spaghetti code. This is so much better! 😀
* 202 if accepted, 403 if invalid JSON payload | ||
* @throws Raygun4PhpException | ||
* @return bool Returns true if the transmission attempt is successful. | ||
* However, this does not guarantee that the message is delivered. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this mean that it can return true when it has not delivered the data? If it does return true and the message has not been delivered, is there any way to know this (e.g. logging)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, you could have a case where some async implementation of TransportInterface
successfully queues a message for delivery and returns True, but the actual delivery fails for whatever reason. The natural place to log such an event would be in the transport
implementation.
@samuel-holt I have done some basic testing, and have not noticed any problems. I rechecked the client class, and there seems to be some dead code left, but I will remove it. The documentation most definitely needs to be separate from v1.x as the instantiation of the client is completely different. For now, I can add a separate usage example for v2.x. |
Ok, I have pushed some minor changes and synced this branch with the master Maybe this is a good point to merge and open up new issues for:
|
@anfly0 I agree, these things can be done in a separate PR |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 Awesome work improving the transport, a much needed refactor. As you mentioned, this PR is getting big and handling the transport logging in a separate PR is a good approach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM too, thank you for contributing, and for persisting with us through review!
Hi!
This pull request builds on the changes made in pr #116
Backwards compatibility with 1.x will be broken by this pr!
The purpose of this pr is to move the message transmission implementation, from the RaygunClient to a new separate class.
These changes have the benefit of making any future changes to the transmission mechanism much more straightforward and safer.
As an added bonus, this pr implements two 'transports' built on guzzle.
One async and one sync, thus closing #111
My thinking is that this pr is a solid stepping stone towards releasing 2.0.
Things that are missing or need discussing:
Anyhow, I'm looking forward to hearing what you guys have to say.