I am using Laravel 5.5, and I realized that in this version, the errors seems a bit 'user-friendly'... How to get the detailed error messages again?
For example: before, with this code:
abort(500, 'The server is on fire');
i saw this message "The server is on fire". Now, all I see is "Whoops, looks like something went wrong."
Thanks in advance!
The reason you're getting this error is because you're aborting with a 500 code. What Laravel will eventually do is check if there is a an error view relating to that error code (which there is) and in turn display that view.
Out of the box Laravel comes with a 404, 419, 429, 500, 503 error views.
I would suggest using a code that is more appropriate for your situation (if possible). Here's a list of some of the error codes https://httpstatuses.com/.
Failing that you could override the default behaviour by adding the following to your app/Exceptions/Handler.php class:
/**
* Render the given HttpException.
*
* #param \Symfony\Component\HttpKernel\Exception\HttpException $e
* #return \Symfony\Component\HttpFoundation\Response
*/
protected function renderHttpException(HttpException $e)
{
$status = $e->getStatusCode();
if ($status == 500 && config('app.debug')) {
return $this->convertExceptionToResponse($e);
}
return parent::renderHttpException($e);
Essentially, this will bypass looking for the 500.blade.php error view and should then display the stack with whoops. Please note that this is not tested against an actual 500 error so I'm not sure if it will work for that (I can't think of why it wouldn't but I just wanted to mention it).
Related
I have an application built in laravel 5.8 which is in production mode. As the site is live I don't want to display any errors to our users. But If some error occurs then I want the log number or any reference that indicates what error was thrown at that particular time.
So I wanted to know if there is any way to display "Oops something went wrong ref#123456" to our users. So that they can send us a screenshot or reference number and we can track what actually happend by checking our log file.
Thanks in advance. Happy coding.
I thing that you can do it saving the logs in database and render its id.
You can do it in App\Exceptions\Handler:
https://laravel.com/docs/5.8/errors
For example:
/**
* Render an exception into an HTTP response.
*
* #param \Illuminate\Http\Request $request
* #param \Throwable $exception
* #return \Symfony\Component\HttpFoundation\Response
*
* #throws \Throwable
*/
public function render($request, Throwable $exception)
{
// Create log in db
$log = Log::create([
'message' => $exception->getMessage(),
'code' => $exception->getCode(),
'line' => $exception->getLine(),
]);
// Print log id in logs
logger("LogId {$log->id}");
//Return view error with log id
return return response()->view('errors', ['logId' => $log->id]);
}
maybe you want something more professional than logging the exception, and laravel have a great package for it named telescope you got all your exceptions and queries or events redis and ... so many. you can authorize the users that only admins can access telescope information. and because its a lot of info probably you want prune the records with a seceule:
$schedule->command('telescope:prune --hours=48')->daily();
all of this you can find it in docs: https://laravel.com/docs/telescope
It should be as simple as using uniqueid() function to create an id for an exception, and returning a view in the render part of your app.
public function render($request, Exception $exception)
{
$errorCode = uniqid('error_');
Log::error("$errorCode", [
//... The log information here
]);
return view('welcome', compact('errorCode'));
}
As an example above I am using the default welcome.blade.php page, and then showing the content below:
Error occurred #error_5ec385d7c4d25
It means you can actually search your logs for this error code to know what went wrong.
If there's an error anywhere in my code, such as in the routes file or a view, then instead of displaying the 'pretty' error message I get a dump of JS in the browser.
The error message is in there, but I have to hunt for it.
I'm using Laravel 5.8 in Homestead.
.env has APP_DEBUG=true set. I've also tried directly editing config/app.php to set debug but it doesn't work.
I'm quite new to Laravel so at a loss as to what to look at next...
Here's the first few lines of what gets dumped to the screen, please also check the attached screenshot below.
window.data = {"report":{"notifier":"Laravel Client","language":"PHP","framework_version":"6.0.3","language_version":"7.3.7-2+ubuntu18.04.1+deb.sury.org+1","exception_class":"Facade\\Ignition\\Exceptions\\ViewException","seen_at":1573633009,"message":"htmlspecialchars() expects parameter 1 to be string, array given (View: \/home\/vagrant\/pinyin\/resources\/views\/cards\/cards.blade.php)","glows":[],"solutions":[],"stacktrace":[{"line_number":251,"method":"handleError","class":"Illuminate\\Foundation\\Bootstrap\\HandleExceptions","code_snippet":{"236":"","237":"if (! function_exists(\u0027e\u0027)) {","238":" \/**","239":" * Encode HTML special characters in a string.","240":" *","241":" * #param \\Illuminate\\Contracts\\Support\\Htmlable|string $value","242":" * #param bool $doubleEncode","243":" * #return string","244":" *\/","245":" function e($value, $doubleEncode = true)","246":" {","247":" if ($value instanceof Htmlable)
Found the fix. In the webpack.mix.js file add the following to BrowserSync options:
mix.browserSync({
snippetOptions: {
rule: {
match: /<\/body>/i,
fn: function (snippet, match) {
return snippet + match;
}
}
}
});
Solution from: https://github.com/facade/ignition/issues/16#issuecomment-527260360
Found via: https://github.com/laravel/framework/issues/29909
Update 3: This problem from 9 months ago persists with Laravel 5.8 and Postgresql 11 on Windows 10 in a Laragon environment and Apache 2.4 on an Ubuntu machine. Does the Eloquent Model instance delete() method simply ignore foreign key constraints? It's baffling:
I have two tables in a Postgresql 9.3 database, companies and sites. There is a one-to-many relationship between them with companies on the one side. There is a foreign key constraint that prevents the deletion of a company if sites have been assigned to it. If I attempt to delete the company with the ID 'KSL' using an SQL query directly on the database, I get the expected error:
ERROR: update or delete on table "companies" violates foreign key constraint "sites_company_id_fkey" on table "sites"
DETAIL: Key (company_id)=(KSL) is still referenced from table "sites".
I have defined an artisan command whose handler method has a simple try/catch block:
public function handle()
{
$company = Company::find('KSL');
try{
$company->delete();
}catch(\PDOException $e){
$this->info($e->getMessage());
}
}
When I run the command from the console, I get the expected error message:
SQLSTATE[23503]: Foreign key violation: 7 ERROR: update or delete on table "companies" violates foreign key constraint "sites_company_id_fkey" on table "sites"
DETAIL: Key (company_id)=(KSL) is still referenced from table "sites". (SQL: delete from "companies" where "company_id" = KSL)
reflecting the native error message generated by Postgresql.
However, when I call the delete method from a Controller using an Ajax call using a similar try/catch block, the exception is not caught and the call fails with no details of the error.
I simplified the controller method to make it the same as the console handler:
public function deleteModel(Request $request) {
try {
$id = 'KSL';
$company = Company::find($id);
$result = $company->delete();
return 'success';
} catch (\PDOException $e) {
return $e->getMessage();
}
}
Normally I would get the value of $id from the request argument.
If I use a get request with a RESTful URL in the browser, I get a "The connection was reset" message in Firefox and a similar message in Chrome.
I have referred back to an old question of mine which I thought had the solution, but running composer dump-autoload had no effect. I have cleared the cache, re-installed Laravel 5.5, updated my installation, and called composer dump-autoload again several times but the absence of any exception or logged error message gives me no clue. Debug is set to true for this development app.
I passed a handler to the PHP native function register_shutdown_function like this in the autoload.php file in the bootstrap folder:
register_shutdown_function(function () {
$error = error_get_last();
file_put_contents(__DIR__.'/../storage/crash.log', var_export($error, true));
});
Only the word 'NULL' appears in the crash.log. I checked the Apache 2.4 error.log file and the specific error log for this Laravel app but there no relevant details recorded there.
Here is the Exception Handler:
<?php
namespace App\Exceptions;
use Exception;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
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.
*
* This is a great spot to send exceptions to Sentry, Bugsnag, etc.
*
* #param \Exception $exception
* #return void
*/
public function report(Exception $exception)
{
parent::report($exception);
}
/**
* Render an exception into an HTTP response.
*
* #param \Illuminate\Http\Request $request
* #param \Exception $exception
* #return \Illuminate\Http\Response
*/
public function render($request, Exception $exception)
{
return parent::render($request, $exception);
}
}
UPDATE 1:
I got a clue from this question: Stack size for Apache under Windows. I quickly tested my online applications (all running on Linux machines) and there is no problem. The exception is thrown correctly and a nice clear message is displayed for the user. My local environment is Windows and it looks like Apache suffers from this connection reset error more than in a Linux environment. I've increased the stack size in Apache as suggested by the answer to that question but it still doesn't work. I still get a connection reset error. I've re-installed Apache with the latest binaries from Apache lounge I'm running PHP 7.3. Can anyone shed some light on this?
UPDATE 2:
An answer from Lucas to this question encouraged me to change server. When I ran php artisan serve from the console and then call the ParentTable->delete() method, I got the expected exception with no crashing. There is clearly something wrong with my Apache configuration. Unfortunately the accepted answer to that question doesn't solve my problem. I increased the stack size but the problem persists.
I have a middleware that automatically logs all incoming requests. It also sends me an email when the status is 500. However, $response->getContent() only returns "Server Error" when debugging mode is disabled.
Is there some way to get more detailed information about the cause, like
$exception->getMessage() vs. $exception->getTraceAsString()
are available for the Exception class
current code:
if($response->getStatusCode() == 500) {
ErrorHandler::sendEmail('Incoming Request Error 500', $response->getContent());
}
You can interrogate the exception in the ExceptionHandler class before reporting and rendering take place: Source Line 37.
For example:
public function report(Exception $exception)
{
logger($exception->getMessage());
parent::report($exception);
}
I'm looking for a modern (Laravel 5.4) way to display custom 500 error page only for HTTP (non ajax/fetch) response. I read some threads but each response looks like a trick or is outdated. There is probably something to modify in \App\Exceptions\Handler, but I did not find the "right way".
Is there a simple way to display a specific page on fatal error (uncatched, returning 500) in Laravel 5.4?
In other words, when I have a syntax error on one of my controller, it displays "Whoops something went wrong" with some HTML and 500 error code. I would like to display something else, with the same rules as default behavior (ideally only for HTML browser, not for ajax/fetch, etc.).
EDIT: only in production environment.
Laravel makes it easy to display custom error pages for various HTTP status codes. For example, if you wish to customize the error page for 404 HTTP status codes, create a resources/views/errors/404.blade.php. This file will be served on all 404 errors generated by your application. The views within this directory should be named to match the HTTP status code they correspond to. The HttpException instance raised by the abort function will be passed to the view as an $exception variable.
https://laravel.com/docs/5.4/errors#custom-http-error-pages
From the selected "best answer" of this thread: https://laracasts.com/discuss/channels/general-discussion/custom-error-page-er500
You could modify \App\Exceptions\Handler::render():
public function render($request, Exception $exception)
{
if (config('app.debug') && !$this->isHttpException($exception)) {
$exception = new \Symfony\Component\HttpKernel\Exception\HttpException(500);
}
return parent::render($request, $exception);
}
Your exception will be reported in the logs as usually, but woops page will be replaced by your 500.blade.php view.
Sometimes you have to catch the specific exception in order to render the error view. in Laravel 5.4 you can do this by editing the report() method in the App\Exceptions\Handler class
public function report(Exception $exception)
{
if ($exception instanceof CustomException) {
// here you can log the error and return the view, redirect, etc...
}
return parent::report($exception);
}