Troubleshooting Errors and Performance Issues in Laravel - Papertrail Blog

The revolution will be verbosely {,b}logged

Troubleshooting Errors and Performance Issues in Laravel

Posted by Daljeet Singh on

In a perfect world, there wouldn’t be any errors or bugs in production applications. However, we don’t live in a perfect world, and from experience, you know there is no such thing as a bug-free application. If you are using the Laravel framework, you can leverage its log tracking and error logging to catch bugs early and enhance the performance of your Laravel-based application.

Laravel comes pre-packaged with tools to help you track and monitor events. This reduces the effort required to track down those bugs. It comes with a stackable logging system built on top of the popular Monolog library. It also allows you to set up multiple channels based on the severity of the log or event. These channels include stack (stacked), single, daily, Slack, syslog, monolog, SolarWinds® Papertrail®, and so on.

Single Server Environment

Configuring logging for a single server production environment is simple and straightforward. Since the data is always retained on the server, we do not have to worry about keeping the logs offsite. Laravel handles the log rotation, so you do not have to manually maintain that information either. The following configuration logs debug level errors and exceptions to a log file.

return [

    'default' => env('LOG_CHANNEL', 'stack'),

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

        'daily' => [
            'driver' => 'daily',
            'path' => storage_path('logs/laravel.log'),
            'level' => 'debug',
            'days' => 14,
        ]
    ]

];

Production Environments

Production environments are dynamic and they often scale up and down, which means that the servers will be created or destroyed with increases and decreases in user traffic or load. This means you cannot rely on file-based logging because storage is ephemeral and load balancers make it quite difficult to track down which web server received a request. In order to aggregate and save the logs for any retention period, you’ll have to set up a dedicated syslog server or use a service like Papertrail, which can store logs and make them accessible in a web browser.

A screenshot of logs in Papertrail.

While setting up a logs server is easy, it’s not beneficial for everyone. A decent amount of Linux knowledge and a dedicated server is required, especially if you’re managing more than one production environment.

I like Papertrail for its ease of setup and use. You just have to set up the logging channel to “papertrail” and add two configurations into your environment file (.env).

PAPERTRAIL_URL=logsXXX.papertrailapp.com
PAPERTRAIL_PORT=52204

You should be able to get the values for these settings in your Papertrail account. There is also documentation on the Laravel site about configuring the Papertrail channel. 

Once set up you can easily monitor and search your logs.

Common Errors

5XX Server Errors

These are usually server side or hard errors which are thrown on the server side. These errors usually mean something unexpected happened and your program didn’t know how to handle the situation. The error could be caused by many things and we’ll describe a few common ones below.

Code Syntax Errors

These errors are easy to detect if you have debug turned on or if you’re looking at the error log. Errors usually start with syntax error, unexpected… and will give you the name of the file and line number of the code that caused the error.

PHP version Compatibility

PHP 5.6 and 7.0 hit EOL (end of life) last year and chances are your server isn’t using those versions or won’t be for much longer. I’ve listed a few tools below which you can use to check your code for compatibility.

  • php7mar – PHP 7 Migration Assistant Report (MAR) (Recommended)
  • phpstan – PHP Static Analysis and compatibility check
  • phan – A static analyzer, PHP 7 checker

504 Gateway Time-out

These errors usually happen when you’re running the PHP outside of Apache/Nginx as a separate process (for example, FPM or CGI) and the response isn’t returned to your web server in a timely manner. Performance tracking middleware defined in the Performance issues section later in the article might be helpful for you for tracking these issues.

Database Connection Issues

This can be solved by checking the credentials for DB connection in your environment file and making sure that the credentials are correct, the application communicates with the database server, and the database/tables exist.

The following are a few log messages thrown by this issue:

SQLSTATE[HY000] [1045] Access denied for user [USERNAME]

SQLSTATE[HY000] [2002] Operation timed out

4XX Client Errors

These errors are considered soft errors and are usually thrown when we receive an invalid request from a client.

404 Page Not Found

This error usually means that Laravel was not able to find the controller, controller method or a 404 error was thrown by your custom code. Some common steps to debug these would be to confirm that the route, controller, and method exist. If they all exist, then check to see if your code is throwing a 404 error.

Some common 404 errors are as follows:

Error MessagePossible Reason(s)
404 | Not Found1. Route is not defined
2. No results were found when findOrFail() was called for a model
Class [CLASS_NAME] does not existController class does not exist or the path to it is incorrect
Method [METHOD_NAME] does not existMethod does not exist or the path to it is incorrect

Note: findOrFail() callback on a model returns a 404 error if no matching result is found in the database.

419 Page Expired

Laravel comes pre-loaded with a CSRF protection and it requires you to pass that token with all your non-GET requests. This requires a valid session to be maintained on the server side.

If you wish to exclude any requests from CSRF verification, then add those requests to your VerifyCsrfToken middleware.

/**
* The URIs that should be excluded from CSRF verification.
*
* @var array
*/
protected $except = [
    'foo/bar',
    'foo/*',
    'http://example.com/foo/bar',
    'http://example.com/foo/*',
];

422 Unprocessable Entity

This error usually means that the data you posted using AJAX was invalid for this request. This happens when you have a Request Rules setup. Laravel validates each request before it passes onto your controller method. The issue may be in your data or the request rule used for the request.

When an AJAX request is made JSON content type request it will return an error message like following, explaining what the issue is.

{
	"message": "The given data was invalid.",
	"errors": {
		"name": ["The name field is required."],
		"email": ["The email field is required."]
	}
}

Out of Memory Error

Memory limits on PHP applications exist for a reason. You do not want to allow your application an unlimited amount of memory. This error message exists for that very reason. If you’re receiving an out of memory error it means that there is a memory leak in your application. Maybe you forgot to reset an object, and the size continues to increase until the application doesn’t have any memory left to run.

Allowed memory size of [SIZE] bytes exhausted (tried to allocate [SIZE] bytes)

The following loop will keep running until the program runs out of memory:

$data = [];
$i = 100;

while($i > 100) {
    $data[] = time();
    $i++;
}

Performance Issues

Slow Queries

A single slow query can slow down your entire application. You did everything you could think of and made sure that all of your queries were using indexes and didn’t do anything; however, maybe you still missed something… How do you monitor for that? It’s simple enough in Laravel. Add the following code to your AppServiceProvider::boot() method:

   public function boot()
    {
        \DB::listen(function($sql) {
            if($sql->time > 1000){
                \Log::info(“SLOW QUERY DETECTED:”);
                \Log::info($sql->sql);
                \Log::info($sql->bindings);
                \Log::info($sql->time);
            }
        });
    }

This will log every query that takes longer than a second (1000 ms) to execute. You can adjust the time accordingly to fit your needs. Running an explain on your query will provide you with some insights as to why your query is running slow.

Slow Response Time

Tracking slow response time in Laravel is relatively simple. You can define a middleware like the following example and include it in your requests.

<?php

//File Name: app/Middlewares/Performance.php

namespace App\Http\Middleware;

use Closure;

class Performance
{
    public function handle($request, Closure $next)
    {
        return $next($request);
    }

    public function terminate($request, $response)
    {
        $execution_time  = microtime(true) - LARAVEL_START;
        if($execution_time > 1){ // You can change the 1 to a desired amount in seconds
            \Log::info("Slow Response[{$execution_time}]: You should log some information here.");
        }
    }
}

After creating the middleware do not forget to include it in your Kernel.php like this:

    protected $routeMiddleware = [
        'auth' => \App\Http\Middleware\Authenticate::class,
        .... 
        'performance' => \App\Http\Middleware\PerformanceTracker::class,
    ];

You can also include it in your web or API route groups if you want to include it in all requests on web/API.

Caching

Caching your content is another way to optimize your application. You don’t have to fetch data from your database if it doesn’t change often. Laravel provides drivers for file, db, memcache, and redis backends. By default, Laravel uses a file-based caching system. Configuring caching in Laravel is easy and can be done in minutes.

Recap

In this article, you learned how we can use logging to reduce the time and effort spent on debugging your code while improving the performance of your application at the same time.

As you see, you can use logging to reduce the time and effort spent debugging your code while improving the performance of your application at the same time.

Data is your friend and it’s there waiting for you to make use of it! Tools like SolarWinds® Papertrail® make it easier to access logs and debug problems. Check out the Papertrail free trial.