Custom error and exception handler for Artisan command - php

I'm trying to send errors and exceptions to raygun.io from a Laravel 4 artisan command, but Laravel appears to have it's own exception handler in place.
Is there a way for me to specify a custom method in my Command? Currently, I'm trying to specify a custom handler for errors and exceptions as follows:
<?php
class ParseCommand extends Command
{
/**
* The console command name.
*
* #var string
*/
protected $name = 'my:parse';
protected $descriptino = '...';
protected $raygun = null;
/**
* __construct
*/
public function __construct()
{
parent::__construct();
// Setup custom error and exception handlers
$raygun_api_key = \Config::get('tms.raygun_api_key');
$this->raygun = new RaygunClient("MUzf+furi8E9tffcHAaJVw==");
set_exception_handler([$this, 'exceptionHandler']);
set_error_handler([$this, 'errorHandler']);
}
/**
* Custom exception handler.
*
* #param $exception
*/
public function exceptionHandler($exception)
{
$this->raygun->SendException($exception);
}
/**
* Custom error handler.
*
* #param $errno
* #param $errstr
* #param $errfile
* #param $errline
*/
public function errorHandler($errno, $errstr, $errfile, $errline)
{
$this->raygun->SendError($errno, $errstr, $errfile, $errline);
}
/**
* Execute the console command.
*
* #return mixed
*/
public function fire()
{
$start_time = microtime(true);
throw new \Exception("Oopsie!");
// Omitted for brevity...
}
}
Off course the handlers never execute, as Artisan is grabbing them with it's own custom implementation.

The files in the folder app/start are only executed while booting the Laravel framework when the according environment is run. This means that app/start/local.php is run when the environment is equal to local and app/start/staging.php is run when the environment is equal to staging. Also the app/start/global.php file is run every time and app/start/artisan.php is run on every artisan execution.
From the documentation: http://laravel.com/docs/errors place the handler
App::error(function(Exception $exception)
{
Log::error($exception);
});
in app/start/artisan for your artisan-only exception handlers.

Related

Composer install gives Uncaught TypeError

I am facing this error "Uncaught TypeError: Argument 1 passed to Illuminate\Log\Logger
::__construct() must be an instance of Psr\Log\LoggerInterface, instance of Mono
log\Logger given,"
when i run php artisan command. my php version is 7.3.9
I had this issue last night, tried with php 7.3 and 7.4 in the end i just used the latest php 8.1 and this issue went away.
You could try going to illuminate/log/Logger.php and adding use Monolog\Logger as Monolog; at the beginning of the file. After that, change the constructor from this:
/**
* Create a new log writer instance.
*
* #param \Psr\Log\LoggerInterface $logger
* #param \Illuminate\Contracts\Events\Dispatcher|null $dispatcher
* #return void
*/
public function __construct(LoggerInterface $logger, Dispatcher $dispatcher = null)
{
$this->logger = $logger;
$this->dispatcher = $dispatcher;
}
to this:
/**
* Create a new log writer instance.
*
* #param \Monolog\Logger $logger
* #param \Illuminate\Contracts\Events\Dispatcher|null $dispatcher
* #return void
*/
public function __construct(Monolog $logger, Dispatcher $dispatcher = null)
{
$this->logger = $logger;
$this->dispatcher = $dispatcher;
}

How to call a handle method into an routes.php file?

I want to print a log message when i run php artisan make:greetings command in my command line it should return a message in my log file , for that how to call a handle method inside the routes.php file, for that i am writing some code but i am getting a following error please help me to fix this issue
Error
TypeError
Argument 2 passed to Illuminate\Foundation\Console\Kernel::command() must be an instance of Closure, array given,
called in C:\apiato-project\apiato\vendor\laravel\framework\src\Illuminate\Support\Facades\Facade.php on line 261
at C:\apiato-project\apiato\vendor\laravel\framework\src\Illuminate\Foundation\Console\Kernel.php:191
187▕ * #param string $signature
188▕ * #param \Closure $callback
189▕ * #return \Illuminate\Foundation\Console\ClosureCommand
190▕ */
➜ 191▕ public function command($signature, Closure $callback)
192▕ {
193▕ $command = new ClosureCommand($signature, $callback);
194▕
195▕ Artisan::starting(function ($artisan) use ($command) {
1 C:\apiato-project\apiato\vendor\laravel\framework\src\Illuminate\Support\Facades\Facade.php:261
Illuminate\Foundation\Console\Kernel::command("make:greetings", ["App\Console\Commands\Hello"])
2 C:\apiato-project\apiato\app\Ship\Commands\Routes.php:24
Illuminate\Support\Facades\Facade::__callStatic("command")
routes.php
Artisan::command('make:greetings',[Hello::class,'handle'=>true]);
Hello.php
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Log;
class Hello extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'make:greetings';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Command description';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return int
*/
public function handle()
{
return Log::info("welcome message");
}
}
The second argument have to be a closure and you are passing an array, This closure is used to pass data to your handle method and as you dont have any arguments in your handle method use call method istead of command, Try this:
Artisan::call('make:greetings');
and also don't forget to register your command in App\Console\Kernel class:
protected $commands = [
'App\Console\Commands\Hello',
];

show site under maintenance view page for all Error/Exceptions in laravel application

I am beginner to laravel. I came across one laravel application. In that I need to handle all types of exceptions/ errors that are getting. Exceptions like ViewExceptions, ErrorExceptions etc. I need to show one view page(site under maintenance) for all those system exceptions, errors and for all database or coding exceptions and errors.
I have checked Laravel Error handling and also googled for solutions. But more I searched I am getting confused for solution. As the application is already on production, I can't make changes to each controller to handle the exceptions. I am guessing, I need to make changes in App/Exception/Handler class only but not sure how that will work.
Form search I got that I have to make changes like in Handler class:
/**
* Render an exception into an HTTP response.
*
* #param \Illuminate\Http\Request $request
* #param \Throwable $exception
* #return \Illuminate\Http\Response
*/
public function render($request, Throwable $exception)
{
if ($exception instanceof CustomException) {
return response()->view('errors.site_down', [], 500);
}
return parent::render($request, $exception);
}
Above code not showing if there is ViewException.
I have observed that in .env APP_DEBUG is true and in config/app it's false. Does that affect?
How all exceptions or errors will redirect to site_down page? also please guide me exception and error handling in laravel. I am getting more confused.
Thanks in advance.
Just get rid of the if statement:
/**
* Render an exception into an HTTP response.
*
* #param \Illuminate\Http\Request $request
* #param \Throwable $exception
* #return \Illuminate\Http\Response
*/
public function render($request, Throwable $exception)
{
return response()->view('errors.site_down', [], 503);
}
You will also probably want to return 503, if you are trying to claim the site is down for maintenance.
In critique of this approach, I think it is dishonest and transparent to your users to claim the site is in maintenance for your errors, and this will not pay itself off in the long run.
Add a blade page on resources/views/errors/503.blade.php
You may publish Laravel's error page templates using the vendor:publish Artisan command. Once the templates have been published, you may customize them to your liking :
php artisan vendor:publish --tag=laravel-errors
This command will create all your custom error page on resources/views/errors/ directory. You can customize as you want.
See official documentation here
For custom exceptions first you have to make a custom exception file preferably in the exceptions folder App\Exceptions\CustomException.php
<?php
namespace App\Exceptions;
use Exception;
class CustomException extends Exception
{
//
}
Then in your exceptions handler file App\Exceptions\Handler.php
<?php
namespace App\Exceptions;
use Exception;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use App\Exceptions\CustomException as CustomException;
use Throwable;
class Handler extends ExceptionHandler
{
/**
* A list of the exception types that are not reported.
*
* #var array
*/
protected $dontReport = [
//
];
/**
* A list of the inputs that are never flashed for validation exceptions.
*
* #var array
*/
protected $dontFlash = [
'password',
'password_confirmation',
];
/**
* Report or log an exception.
*
* #param \Throwable $exception
* #return void
*/
public function report(Throwable $exception)
{
parent::report($exception);
}
/**
* Render an exception into an HTTP response.
*
* #param \Illuminate\Http\Request $request
* #param \Throwable $exception
* #return \Illuminate\Http\Response
*/
public function render($request, Throwable $exception)
{
// Thrown when a custom exception occurs.
if ($exception instanceof CustomException) {
return response()->view('error.page.path', [], 500);
}
// Thrown when an exception occurs.
if ($exception instanceof Exception) {
response()->view('errors.page.path', [], 500);
}
return parent::render($request, $exception);
}
}
Remember to use App\Exceptions\CustomException; custom exceptions file where ever you need to throw a custom exception like so:
use App\Exceptions\CustomException;
function test(){
throw new CustomException('This is an error');
}

Laravel request validation throwing HttpResponseException in version 5.2

I'm trying to update Laravel from version 5.1 to 5.2 in my project, I have followed this upgrade guide from the documentation, but now I'm getting this HttpResponseException when a validation fails
* Handle a failed validation attempt.
*
* #param \Illuminate\Contracts\Validation\Validator $validator
* #return mixed
*
* #throws \Illuminate\Http\Exception\HttpResponseException
*/
protected function failedValidation(Validator $validator)
{
throw new HttpResponseException($this->response(
$this->formatErrors($validator)
));
}
In 5.1, the framework redirected to the previous url automatically with the validation errors.
This is my validation request
namespace domain\funcao\formRequest;
use autodoc\Http\Requests\Request;
class StoreFuncaoRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'codigo' => 'required|max:255|unique:funcao,codigo,'.$this->input('id').',id,deleted_at,NULL',
'nome' => 'required|max:255|unique:funcao,nome,'.$this->input('id').',id,deleted_at,NULL'
];
}
}
I have already updated my Exceptions Handler according to the guide
class Handler extends ExceptionHandler
{
/**
* A list of the exception types that should not be reported.
*
* #var array
*/
protected $dontReport = [
\Illuminate\Auth\Access\AuthorizationException\AuthorizationException::class,
\Illuminate\Database\Eloquent\ModelNotFoundException::class,
\Illuminate\Foundation\ValidationException\ValidationException::class,
\Symfony\Component\HttpKernel\Exception\HttpException::class,
];
...
}
Did someone had this problem??
I found the cause for this error, I was calling PrettyPageHandler from Whoops manually in my Exception Handler class.
class Handler extends ExceptionHandler
{
/**
* A list of the exception types that should not be reported.
*
* #var array
*/
protected $dontReport = [
\Illuminate\Auth\Access\AuthorizationException\AuthorizationException::class,
\Illuminate\Database\Eloquent\ModelNotFoundException::class,
\Illuminate\Foundation\ValidationException\ValidationException::class,
\Symfony\Component\HttpKernel\Exception\HttpException::class,
];
...
/**
* Render an exception into an HTTP response.
*
* #param \Illuminate\Http\Request $request
* #param \Exception $e
* #return \Illuminate\Http\Response
*/
public function render($request, Exception $e)
{
// I just needed to remove this call to get rid of the problem
if (config('app.debug'))
{
return $this->renderExceptionWithWhoops($e);
}
return parent::render($request, $e);
}
/**
* Render an exception using Whoops.
*
* #param \Exception $e
* #return \Illuminate\Http\Response
*/
protected function renderExceptionWithWhoops(Exception $e)
{
$whoops = new \Whoops\Run;
$whoops->pushHandler(new \Whoops\Handler\PrettyPageHandler());
return new \Illuminate\Http\Response(
$whoops->handleException($e),
$e->getStatusCode(),
$e->getHeaders()
);
}
}
I'm still using Whoops, but now automatically through Laravel Exceptions
This was the first question I came across when I had this problem although for me it was with Sentry not Whoops.
Here's a couple of exceptions and how I dealt with them:
public function render($request, Exception $e)
{
if ($e instanceof TokenMismatchException) {
return redirect()->back()->withInput()->with('error', 'Your Session has Expired');
}
if ($e instanceof HttpResponseException) {
return $e->getResponse();
}
return response()->view('errors.500', [
'sentryID' => $this->sentryID,
], 500);
}
I handle the HttpResponseException by simply returning the response the same way the ExceptionHandler class does.
All you have to do is, just write your business logics inside the protected failedValidation() inside your custom FormRequest class like follows
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Contracts\Validation\Validator;
/**
* [failedValidation [Overriding the event validator for custom error response]]
* #param Validator $validator [description]
* #return [object][object of various validation errors]
*/
public function failedValidation(Validator $validator) {
// write your business logic here otherwise it will give same old JSON response
throw new HttpResponseException(response()->json($validator->errors(), 422));
}

PHP: Ignoring errors and notices in a specific class

My site is completely custom, as such I like to know when I have poorly written code. I use set_exception_handler and set_error_handler to use custom classes to log errors to a file. This includes notices and warnings.
Within my own code, this is fine as I get very few logs and those that I do get are things I actually want to fix.
However, i've just started using simplePie and because it's PHP4 compatible I get tons of notices, primarily for things like calling functions statically or passing things by reference incorrectly.
It's too much for me to go through and fix simplePie, if it wasn't I wouldn't be using it in the first place.
Is there a way that I can specifically ignore errors generated by a certain file or class? Here's an overview of what of my very basic exception handling looks like:
set_exception_handler("CustomExceptionHandler");
set_error_handler("customErrorHandler");
/**
* CustomExceptionHandler()
*
* This is used if an exception is thrown that isn't caught.
*
* #param object $e The exception as an object
*/
function CustomExceptionHandler(Exception $e) {
exitToError($e->getMessage());
}
/**
* customErrorHandler()
*
* This is called for any errors no matter what their level.
*/
function customErrorHandler($errno, $errstr, $errfile, $errline) {
if(in_array($errno, array(E_USER_ERROR, E_RECOVERABLE_ERROR))) {
throw new CustomErrorException($errstr, 0, $errno, $errfile, $errline);
} else {
CustomException::logError($errstr, $errno, $errfile, $errline);
}
return FALSE;
}
/**
* class CustomErrorException
*
* Used by custom_error_handler() to convert all fatal
* errors to exceptions.
*
* #see custom_error_handler()
* #see http://www.php.net/manual/en/class.errorexception.php
*/
class CustomErrorException extends CustomException {
/**
* $severity
*
* The severity level of the exception
*
* #access protected
* #var int
*/
protected $severity;
/**
* __construct()
*
* Constructs the new exception
*
* #access public
* #param string $message The Exception message
* #param int $code The Exception code
* #param int $severity The severity level of the exception
* #param string $filename The filename where the exception was thrown
* #param int $lineno The line number where the exception was thrown
*/
public function __construct($message, $code = null, $severity = E_ERROR, $filename = null, $lineno= null) {
$this->message = $message;
$this->code = $code;
$this->severity = (int)$severity;
$this->file = $filename;
$this->line = $lineno;
self::logError($this->message,$this->code,$this->file,$this->line,$this->getTraceAsString());
}
}
/**
* class CustomException
*
* Overwrites Exception to give us more control on how
* exceptions are handled and logged.
*
* #see http://www.php.net/manual/en/language.exceptions.extending.php
*/
class CustomException extends Exception {
/**
* __construct
*
* We call the parent contruct as we still want it to do all its magic. We just want
* overwrite this method so that we can log the error exactly how we want.
*/
public function __construct($message, $code = 0, Exception $previous = NULL) {
parent::__construct($message, $code);
self::logError($this->getMessage(),$this->getCode(),$this->getFile(),$this->getLine(),$this->getTraceAsString());
}
/**
* __toString()
*
* We overwrite this function so that we can use our stringBuilder function.
*/
public function __toString() {
return self::stringBuilder($this->getMessage(),$this->getCode(),$this->getFile(),$this->getLine(),$this->getTraceAsString());
}
/**
* stringBuilder()
*
* We use this method so that we have a standard method of building error
* strings that anything can tap into.
*
* #access public
* #param string $message the exception message
* #param int $code the code assigned to this exception
* #param string $file the file where the exception occurred
* #param int $line the line where the exception occurred
* #param string $trace backtrace
*/
public function stringBuilder($message, $code, $file, $line, $trace='') {
//return "[".date("d-M-Y H:i:s")."] ".$this->getMessage()." in ".$this->getFile().":".$this->getLine()."\nStack trace:\n".$this->getTraceAsString()."\n";
return "[".date("d-M-Y H:i:s")."] ".$message." in ".$file.":".$line."\n";
}
/**
* logError()
*
* We use a method so that we have a standard way of saving errors
* to a log.
*
* We use XML because it's easy to parse.
*
* #access public
* #param string $message the exception message
* #param int $code the code assigned to this exception
* #param string $file the file where the exception occurred
* #param int $line the line where the exception occurred
* #param string $trace backtrace
* #todo We could improve it to write to the xml file using DomDocument
* as laid out here http://www.xml-training-guide.com/append-delete-data-from-xml-using-php.html
*/
public function logError($message, $code, $file, $line, $trace='') {
//Save it to a standard text file to guarentee saving the error
file_put_contents(ROOT_URL.ERROR_LOG_TXT,self::stringBuilder($message, $code, $file, $line, $trace),FILE_APPEND);
}
}
and here is an example of two of the errors simplePie throws up:
[01-Aug-2010 00:50:33] Assigning the return value of new by reference is deprecated in ***\SimplePie.php:738
[01-Aug-2010 00:50:34] Non-static method SimplePie_Misc::parse_date() should not be called statically in ***\SimplePie.php:60
Is there a way that I can specifically ignore errors generated by a certain file or class?
Should be easy! You could check in your custom error handler
function customErrorHandler($errno, $errstr, $errfile, $errline)
whether $errfile is in one of the simplePie files, and in that case return true; silently.
You could inspect the $errfile parameter passed to your error handler to see if the error originates from somewhere inside simplePie.
Documentation: http://php.net/manual/en/function.set-error-handler.php
You have to remove these errors.
1. Remove & in assignments like $foo =& new Object()
2. You can't access method in statticly way if it's not a static method so instead Object::method() you should try using Object->method() or try to change function method() to static function method()
Or the best solution - try to find library in php5

Categories