5

I want to log 404 errors in Laravel 5.7, but I don't understand how to turn this on. Additional to logging 404 errors, I'd like to log the URL that was requested. Other errors are logged correctly.

.env

APP_DEBUG=true
LOG_CHANNEL=stack

config/logging.php

'stack' => [
    'driver' => 'stack',
    'channels' => ['daily'],
],

Per the Error Handling documentation:

The $dontReport property of the exception handler contains an array of exception types that will not be logged. For example, exceptions resulting from 404 errors, as well as several other types of errors, are not written to your log files. You may add other exception types to this array as needed:

In app/Exceptions/Handler the $dontReport array is empty.

I have customized the 404 view by having a Blade file resources/views/errors/404.blade.php

Based on this answer I've tried this code in app/Exceptions/Handler, but nothing shows up in the logs:

public function report(Exception $exception)
{
    if ($this->isHttpException($exception)) {
        if ($exception instanceof NotFoundHttpException) {
            Log::warning($message);
            return response()->view('error.404', [], 404);
        }
        return $this->renderHttpException($exception);
    }

    parent::report($exception);
}

UPDATE after accepting Mozammil's answer which works fine. I've shortened his answer to the below. Don't forget to add use Illuminate\Support\Facades\Log to the Handler file.

public function render($request, Exception $exception)
{
    if ($exception instanceof \Symfony\Component\HttpKernel\Exception\NotFoundHttpException) {
        Log::warning('404: ' . $request->url());
        return response()->view('errors.404', [], 404);
    }
    return parent::render($request, $exception);
}
Karl Hill
  • 12,937
  • 5
  • 58
  • 95
eskimo
  • 2,421
  • 5
  • 45
  • 81
  • 1
    Possible duplicate of [Handler not catching autohorization and token mismatch exception. Laravel](https://stackoverflow.com/questions/50127081/handler-not-catching-autohorization-and-token-mismatch-exception-laravel) – ceejayoz Jan 27 '19 at 19:45
  • It's a little confusing, but the framework has an *additional* set of ignored exception types in `$internalDontReport`. You'll have to set that. See the duplicate thread above. – ceejayoz Jan 27 '19 at 19:45

3 Answers3

9

I have a similar requirement. Here's how I achieved it.

I have a helper method to determine if it's a 404.

private function is404($exception)
{
    return $exception instanceof \Illuminate\Database\Eloquent\ModelNotFoundException
            || $exception instanceof \Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
}

I also have another method to actually log the 404.

private function log404($request) 
{
    $error = [
        'url'    => $request->url(),
        'method' => $request->method(),
        'data'   => $request->all(),
    ];

    $message = '404: ' . $error['url'] . "\n" . json_encode($error, JSON_PRETTY_PRINT);

    Log::debug($message);
}

Then, to log the error, I just do something like this in the render() method:

public function render($request, Exception $exception)
{
    if($this->is404($exception)) {
        $this->log404($request);
    }

    return parent::render($request, $exception);
}

I didn't know about the $internalDontReport. However, in all cases, my implementation worked for me :)

Mozammil
  • 8,520
  • 15
  • 29
2

I use Telescope

Laravel Telescope
Laravel Telescope is an elegant debug assistant for the Laravel framework. Telescope provides insight into the requests coming into your application, exceptions, log entries, database queries, queued jobs, mail, notifications, cache operations, scheduled tasks, variable dumps and more.

https://laravel.com/docs/5.7/telescope

1

I attend to catch all kind of 4xx errors so, I edit in the app/Exceptions/Handler.php file by adding the below code in the render function

if($exception instanceof \Illuminate\Database\Eloquent\ModelNotFoundException ||
        $exception instanceof \Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException ||
        $exception instanceof \Symfony\Component\HttpKernel\Exception\NotFoundHttpException){
        $error = [
            'message'=> $exception->getMessage(),
            'type'   => \get_class($exception),
            'url'    => $request->url(),
            'method' => $request->method(),
            'data'   => $request->all(),
        ];

        $message = $exception->getStatusCode().' : ' . $error['url'] . "\n" . \json_encode($error, JSON_PRETTY_PRINT);
        //Store the object in DB or log file
        \Log::debug($message);
    }

this Code will catch Exception for [ModelNotFoundException, MethodNotAllowedHttpException, NotFoundHttpException] - in short words this will catch 404 error, model not found in DB and bad method - and create an object called $error and you will be able to store it in what ever you want.

So the app/Exceptions/Handler.php will be like

<?php

namespace App\Exceptions;

use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
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
     *
     * @throws \Exception
     */
    public function report(Throwable $exception)
    {
        parent::report($exception);
    }

    /**
     * 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)
    {

        if($exception instanceof \Illuminate\Database\Eloquent\ModelNotFoundException ||
            $exception instanceof \Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException ||
            $exception instanceof \Symfony\Component\HttpKernel\Exception\NotFoundHttpException){
            $error = [
                'message'=> $exception->getMessage(),
                'type'   => \get_class($exception),
                'url'    => $request->url(),
                'method' => $request->method(),
                'data'   => $request->all(),
            ];

            $message = $exception->getStatusCode().' : ' . $error['url'] . "\n" . \json_encode($error, JSON_PRETTY_PRINT);

            \Log::debug($message);
        }
        return parent::render($request, $exception);
    }
}

P.S. I am using laravel 8 but I am sure it will work in most popular versions.

vipmaa
  • 1,022
  • 16
  • 25