Core: Exceptions handling and monolog

Created on 19 Nov 2018  路  5Comments  路  Source: api-platform/core

Hi,

I have a problem with application exceptions (supported by configuration) which are directly pushing into monolog as a request.CRITICAL error level logs.

I use data persisters and providers because in the backend is running another storage than simple database which can be mapped by Doctrine.

In the config:

api_platform:
    exception_to_status:
        Application\Exception\Http\BadRequestException: 400

In the data persister:

try {
    $lead = $this->leadService->insertLead($data);
} catch (DomainException $e) {
    $this->logger->warning($e->getMessage());

    throw new BadRequestException($e->getMessage());
}

Response code in the API is correct = 400, because API Platform catch BadRequestException and change the code to 400. What is wrong... In the logs are written 2 another exceptions:

  • app.WARN [....] which is invoked by $this->logger->warning($e->getMessage());
  • request.CRITICAL [...] which is invoked by throw new BadRequestException($e->getMessage());

In the core should be some logic which doesn't allow to write request channel logs on throws supported by API, or exceptions support should be done another way. It's not a good idea to disable request channel on production, because there may be written some other exceptions unsupported by the application.

Most helpful comment

I can confirm @bartosz-malec's report. This is quite annoying for setup like Slack notification.

This config ignore 400 HTTP error:

monolog:
    handlers:
        # Buffer the logs. Use them only on errors.
        main:
            type: fingers_crossed
            action_level: error
            handler: buffer
            excluded_http_codes:
                - 400
                - 401
                - 403
                - 404
                - 405

But the exceptions from the ApiPlatform are not considered as HTTP errors.

Here is a possible workaround with this subscriber:

use ApiPlatform\Core\Exception\InvalidArgumentException;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\KernelEvents;

final class ApiToHttpExceptionSubscriber implements EventSubscriberInterface
{
    /**
     * {@inheritdoc}
     */
    public static function getSubscribedEvents()
    {
        return [
            KernelEvents::EXCEPTION => 'onKernelException',
        ];
    }

    public function onKernelException(GetResponseForExceptionEvent $event): void
    {
        $exception = $event->getException();

        if ($exception instanceof InvalidArgumentException) {
            $event->setException(
                new BadRequestHttpException(
                    $exception->getMessage(),
                    $exception
                )
            );
        }
    }
}

All 5 comments

I can confirm @bartosz-malec's report. This is quite annoying for setup like Slack notification.

This config ignore 400 HTTP error:

monolog:
    handlers:
        # Buffer the logs. Use them only on errors.
        main:
            type: fingers_crossed
            action_level: error
            handler: buffer
            excluded_http_codes:
                - 400
                - 401
                - 403
                - 404
                - 405

But the exceptions from the ApiPlatform are not considered as HTTP errors.

Here is a possible workaround with this subscriber:

use ApiPlatform\Core\Exception\InvalidArgumentException;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\KernelEvents;

final class ApiToHttpExceptionSubscriber implements EventSubscriberInterface
{
    /**
     * {@inheritdoc}
     */
    public static function getSubscribedEvents()
    {
        return [
            KernelEvents::EXCEPTION => 'onKernelException',
        ];
    }

    public function onKernelException(GetResponseForExceptionEvent $event): void
    {
        $exception = $event->getException();

        if ($exception instanceof InvalidArgumentException) {
            $event->setException(
                new BadRequestHttpException(
                    $exception->getMessage(),
                    $exception
                )
            );
        }
    }
}

Any updates about it?

Is there a better solution to avoid logging domain issued exceptions as CRITICAL than the above?

I'm facing the same issue, as I process the logs and send to datadog, and having 404 errors generate a critical is not viable. Is there an 'elegant' solution for it?

I'd definitely go with a listener as suggested by @soullivaneuh I don't think that there's much we can do on api-platform for this.

Was this page helpful?
0 / 5 - 0 ratings