skip to Main Content

I am working with the Laravel 9 application. I have created a custom Exception. I want to report the General Exception to the sentry and this custom Exception to another vendor like Papertrail.

The Handler.php is not calling the reportable closure function when the application throws a custom exception i.e ServiceException.

By the way, the Laravel documentation for errors is also not understandable

Handler.php

<?php

namespace AppExceptions;

use IlluminateFoundationExceptionsHandler as ExceptionHandler;
use InertiaInertia;
use Throwable;
use Exception;
use AppExceptionsServiceException;

class Handler extends ExceptionHandler
{
    /**
     * A list of the exception types that are not reported.
     *
     * @var array
     */
    protected $dontReport = [
        // ServiceException::class
    ];

    /**
     * A list of the inputs that are never flashed for validation exceptions.
     *
     * @var array
     */
    protected $dontFlash = [
        'current_password',
        'password',
        'password_confirmation',
    ];

    /**
     * Register the exception handling callbacks for the application.
     *
     * @return void
     */
    public function register()
    {
        $this->reportable(function (Throwable $e) {
            // this block is calling for Exception but not for custom Exception like ServiceException.
            if ($this->shouldReport($e) && app()->bound('sentry')) {
                app('sentry')->captureException($e);
            }
        });

        $this->reportable(function (ServiceException $e) {
            // this block is not calling when I throw ServiceException.
            echo "Send this ServiceException to papertrail app."; // this line is never called.
            die;
        });
    }

    public function render($request, Throwable $e)
    {
        $response = parent::render($request, $e);
        if ($request->isJson()) {
            //prevent error for local and staging.
            if (! app()->environment(['local', 'staging']) && in_array($response->status(), [500, 503, 404, 403])) {
                Log::error('API Error Handler', [$response->getOriginalContent()]);
                $message = trans('message.error_description_500');
                if ($response->status() == 404) {
                    $message = trans('message.data_not_found');
                } elseif ($response->status() == 403) {
                    $message = trans('message.you_are_not_allowed_perform');
                } elseif ($response->status() == 503) {
                    $message = trans('message.error_description_503');
                }
                return response()->json([
                    'message' => $message,
                ], $response->status());
            }
        }
        return $response;
    }
}

ServiceException.php

<?php

namespace AppExceptions;

use Exception;

class ServiceException extends Exception
{
    /**
     * Report the exception.
     *
     * @return void
     */
    public function report()
    {
        //
    }

    /**
     * Render the exception into an HTTP response.
     *
     * @param  IlluminateHttpRequest  $request
     * @return IlluminateHttpResponse
     */
    public function render($request, $exception)
    {
        if (! $request->ajax()) {
            // view('error_handler', compact('exception'));
        }

        return response()->json([
            'code' => $exception->getCode(),
            'status' => 'error',
            'message' => $exception->getMessage(),
            'data' => 'sample data',
        ]);
    }
}

AnyController.php

public function anyFunction() {
    // throw new Exception('Unhandled Exception.'); // It will call the $this->reportable(function (Throwable $e) { block.
    // throw new ServiceException('Unhandled ServiceException.'); // It will call the $this->reportable(function (Throwable $e) { block.

    try {
        $this->service->aFunctionThatThrowException(); // this function will throw ServiceException.
    } catch (Exception $e) {
        Log::error('controller_fun_error', ['error' => $e->getMessage()]);
        report($e);
        return $this->failResponse();
    }
}

AnyService.php

public function aFunctionThatThrowException() {
    try {
        throw new ServiceException('Throwing ServiceException...)');
    } catch (ServiceException | Exception $e) {
        Log::error('service_fun_error', ['error' => $e->getMessage()]);
        throw $e;
    }
}

2

Answers


  1. I’m not intirely sure, but I don’t think the error will be reported if you put a try catch around it yourself.

    Login or Signup to reply.
  2. Create a new helper functions file eg: app/Helpers/Common.php and create a service provider HelperServiceProvider in app/Providers/HelperServiceProvider.php use the code below :

    <?php
    
    namespace AppProviders;
    
    use IlluminateSupportServiceProvider;
    
    class AppServiceProvider extends ServiceProvider
    {
        /**
         * Register any application services.
         *
         * @return void
         */
        public function register()
        {
            //
        }
    
        /**
         * Bootstrap any application services.
         *
         * @return void
         */
        public function boot()
        {
            require_once __DIR__ . '/../Helpers/Common.php';
        }
    }
    

    Now copy the below mentioned code to the app/Helpers/Common.php file :

    if (! function_exists('throwResponse')) {
        function throwResponse($message='Exceptions',$data=[],$statusCode=500){
            if(request()->wantsJson()) {
                if ((gettype($message) !== 'string') && ($message instanceof Exception)) {
                    if($message->getMessage()){
                        $data      = (!empty($message->getTrace()))   ? $message->getTrace()   : [];
                        $message   = (!empty($message->getMessage())) ? $message->getMessage() : "Something went wrong";
                        $data      = $data?:[$message];
                        $statusCode = 500;
                    }else{
                        throw new IlluminateHttpExceptionsHttpResponseException($message->getResponse());
                    }
                }
                $errStatus = (in_array($statusCode,[200,201])) ? false : true;
    
                $response = ['code'=>(int)$statusCode,
                             'error'=>$errStatus,
                             'message'=>$message];
    
                if(!empty($data)){
                    $response['data'] = $data;
                }
                if($statusCode == 200 && $data == "empty"){
                    $response['data'] = [];
                }           
                throw new IlluminateHttpExceptionsHttpResponseException(response()->json($response,$statusCode));
            } else{
                if(is_object($message)){
                    throw $message;
                }else{
                    return $message;
                }
            }
        }
        
    }
    

    Now you can easily call the throwResponse function from anywhere in the project :
    for normal response

    throwResponse(‘Message for the response’,[‘user_id’=>1],200);

    {
      "code":200,
      "error":false,
      "message":"Message for the response",
      "data":{
           "user_id":1
       }
    }
    

    or

    throwResponse(‘unauthorized’,null,401);

    {
      "code":401,
      "error":true,
      "message":"unauthroized",
    }
    

    or for exceptions simply pass the exception $e

    throwResponse($e);

    {
      "code":500,
      "error":true,
      "message":"exception message",
      "data":{
           exception data
        }
    }
    

    The response will be

    for example :

       public function exampleFunction(Request $request){
         try{
             
             if(empty($request->userId)){
                throwResponse('Validation error',null,401);
             }
              
             $userData = User::find($request->userId);
             if(!empty($userData)){
                 throwResponse('User data',$userData,401);
             }else{
                 throwResponse('Invalid user id',null,422);
             }                          
         }catch(Exception $e){
             throwResponse($e);
        }
      }
    

    Change responses according to your need

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search