-
Notifications
You must be signed in to change notification settings - Fork 6
Add support for an optional onError callback #17
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
Conversation
… into feature/psr-logger
… into feature/psr-logger
… into feature/psr-logger
|
@oscarotero this is done, approve and merge it when you can ;) |
| * @param FormatterInterface[] $formatters | ||
| */ | ||
| public function __construct(?array $formatters = null) | ||
| public function __construct(?array $formatters = null, ?LoggerInterface $logger = null) |
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 the logger shouldn't be passed in the constructor because it's an optional feature. It should be a method (for example, $middleware->logger(...)).
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.
Dependencies belong in constructors... how else can we have dependency inversion?
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 agree. But in this case it's an optional feature. People may want to log the errors or not, so I see this as a configuration, not a core dependency of the middleware.
That being said, maybe you're right in your comment about the premise of this feature and it would be better to simply create a specific middleware for this.
@filisko ?
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.
A constructor parameter with a default value of null has no cost. (With PHP named parameters, it doesn't even cost writing null to fill it in.) A method that has to accept a parameter to update the object means the object is no longer readonly. Thus, a method for an optional is far more expensive to create, maintain, and operate than a constructor parameter.
| /** | ||
| * Set a custom log callback | ||
| */ | ||
| public function logCallback(callable $callback): self |
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 logger() could accept a callable or a LoggerInterface, so we don't need two methods for the same purpose.
Other option is ->logger($logger, $callback), but to me is more elegant to have only one handler for logging (the callback can have access to the logger by 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.
ok, but then it wouldn't be about logging anymore, but a hook for when an error happens, right? Because inside the callback you can put anything, there is no LoggerInterface enforcement anymore so we should change the name.
How does this look like? onError
$errorHandler->onError(function( Throwable $error, ServerRequestInterface $request) use($logger, $other): void {
$logger->error('Whoops!');
// $other stuff...
});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 looks good to me. Maybe an onError callback is enough to cover all casuistry and we don't need a specific method for logger.
| } catch (Throwable $error) { | ||
| if ($this->logger) { | ||
| if ($this->logCallback) { | ||
| ($this->logCallback)($this->logger, $error, $request); |
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.
If the logger is callback, I'd do $this->logger($error, $request). The callback is a callable with access to a logger (or anything else).
| $this->logger->critical('Uncaught exception', [ | ||
| 'message' => $error->getMessage(), | ||
| 'file' => $error->getFile(), | ||
| 'line' => $error->getLine(), |
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.
Probably I'd include some info about the request: url, method, and uuid (https://github.com/middlewares/uuid).
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, funny that I added it and then forgot to put it back
|
I am actually going to reject the premise of this PR entirely and say that: Logging exceptions and formatting exceptions are two entirely processes with entirely different goals. This entire PR has become a complicated way to avoid writing a custom middleware: public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
try {
return $handler->handle($request);
} catch (Throwable $exception) {
$this->logger->critical('Uncaught {error}', [
'error' => $exception->getMessage(),
'exception' => $exception, // If you use Monolog, this is correct
]);
throw $exception;
}
} |
|
@oscarotero I like what @shadowhand said, thanks (will add you more frequent here 😄 ) ! I'll just leave the .gitattributes change. |
Hi,
This adds support for an optional PSR-3 compliant logger.
The logger is passed as an optional parameter to the constructor. And it also includes a
logCallbackoption to fully customize how logging happens (see the changelog and readme).Thanks!