FriendsOfSymfony / FOSRestBundle

This Bundle provides various tools to rapidly develop RESTful API's with Symfony
http://symfony.com/doc/master/bundles/FOSRestBundle/index.html
MIT License
2.79k stars 703 forks source link

Handled exceptions being logged as critical #2270

Open xDaizu opened 4 years ago

xDaizu commented 4 years ago

I am configuring the FOSRest Bundle to handle domain exceptions as shown in:

https://symfony.com/doc/current/bundles/FOSRestBundle/4-exception-controller-support.html

But exceptions are still logged as

request.CRITICAL: Uncaught PHP Exception Symfony\Component\Messenger\Exception\HandlerFailedException: "Yadda-yadda-yadda" at /var/www/app/apps/api/vendor/symfony/messenger/Middleware/HandleMessageMiddleware.php line 80 (...)

which is logged by the default Symfony\Component\HttpKernel\EventListener\ErrorListener::logKernelException listener.

I think this is contrary to the design philosophy of the exception controller, which is effectively handling the exception by deciding to return an error code and a message to the browser.

Is there any way to avoid this and prevent logging exceptions that ARE known and handled by the FOSRestBundle?

xabbuh commented 4 years ago

Which version do you use? Can you create a small example application that allows to reproduce your issue?

xDaizu commented 4 years ago

Sure, @xabbuh, I think here are all the relevant parts:

Using: "symfony/framework-bundle": "5.0.*", (installed 5.0.10) "friendsofsymfony/rest-bundle": "^3.0", (installed 3.0.2)

config/packages/monolog.yaml

monolog:
    handlers:
        main:
            type: fingers_crossed
            action_level: error
            handler: nested
            excluded_http_codes: [404, 405]
            buffer_size: 50
        nested:
            type: stream
            path: "%kernel.logs_dir%/%kernel.environment%.log"
            level: debug
        console:
            type: console
            process_psr_3_messages: false
            channels: ["!event", "!doctrine"]

config/packages/fos_rest.yaml

fos_rest:
  body_listener:
    decoders:
      json: fos_rest.decoder.json
  exception:
    enabled: true
    map_exception_codes: true
    codes:
      DomainException: 401
    messages:
      DomainException: true

src/Controller/Open/TestController


namespace App\Api\Controller\Open;

use Swagger\Annotations as SWG;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Annotation\Route;

class TestController extends AbstractController
{
    /**
     * @Route("/", name="test", methods={"GET"})
     * @Route("/test", name="test", methods={"GET"})
     * @SWG\Response(
     *     response=200,
     *     description="Test check",
     *     @SWG\Schema(
     *         type="object",
     *         @SWG\Property(
     *             property="status",
     *             type="string"
     *         )
     *     )
     * )
     */
    public function index()
    {
        throw new \DomainException('potato');
        return new JsonResponse(['status' => 'ok']);
    }
}

and after browsing that route we get:

Response, perfect, as expected:

{
  "code": 401,
  "message": "potato"
}

but also this line in var/log/prod.log:

[2020-09-14T11:39:15.845220+01:00] request.CRITICAL: Uncaught PHP Exception DomainException: "potato" at /var/www/app/apps/api/src/Controller/Open/TestController.php line 29 {"exception":"[object] (DomainException(code: 0): potato at /var/www/app/apps/api/src/Controller/Open/TestController.php:29)"} []

which is the line I would like to avoid.

InjustFr commented 3 years ago

Hi

Any news on this ? I'm facing the same issue

Or @xDaizu, did you find a way to avoid the error logging ?

hsdid commented 2 years ago

Similar situation handled exception in fos_rest.yaml returns code 400 but still Uncaught PHP Exception occurs. Any news ?

WissameMekhilef commented 2 years ago

This might be the same issue like this one -- https://github.com/FriendsOfSymfony/FOSRestBundle/issues/2369

It's still very much an issue, has anyone found a workaround?

InjustFr commented 2 years ago

@WissameMekhilef my workaround was to implement an ActivationStrategyInterface to filter the exceptions processed by Monolog. Here's a code snippet:

namespace App\Infrastructure\Logging;

use Doctrine\ORM\EntityNotFoundException;
use Monolog\Handler\FingersCrossed\ActivationStrategyInterface;
use Monolog\Level;
use Monolog\LogRecord;
use Symfony\Component\HttpFoundation\RequestStack;

class MonologApiLoggingStrategy implements ActivationStrategyInterface
{
    public function __construct(private RequestStack $requestStack)
    {
    }

    public function isHandlerActivated(LogRecord $record): bool
    {
        $request = $this->requestStack->getMainRequest();
        if ($request && preg_match('/^\/api/', $request->getPathInfo())) {
            if (
                isset($record->context['exception'])
                &&
                (
                    $record->context['exception'] instanceof \InvalidArgumentException
                    || $record->context['exception'] instanceof EntityNotFoundException
                )
            ) {
                return false;
            }
        }

        return $record['level'] >= Level::Critical;
    }
}
shakaran commented 1 year ago

Not sure if this helps, but the logging should be entering in monolog.nested part, where you can exclude via channels in that prod.log file generated with the name of the controller specifically, with your example it should be:

monolog:
    handlers:
        main:
            type: fingers_crossed
            action_level: error
            handler: nested
            excluded_http_codes: [404, 405]
            buffer_size: 50
        nested:
            type: stream
            path: "%kernel.logs_dir%/%kernel.environment%.log"
            level: debug
            channels: ["!event", "!doctrine", "!TestController"]
        console:
            type: console
            process_psr_3_messages: false
            channels: ["!event", "!doctrine"]