Meet LaraDumps: The Powerful Tool For Laravel Debugging

Meet LaraDumps: The Powerful Tool For Laravel Debugging

Introduction

Debugging is the process of identifying and fixing errors, bugs, or defects in software code. It is an essential part of software development and involves finding and correcting issues that prevent software from functioning as intended.

When a software program is being developed, errors can occur due to various reasons, such as?coding mistakes,?unexpected inputs, or incompatibility with other software components. Debugging involves analyzing the software code, identifying the root cause of the error, and applying a fix to resolve it.

In Laravel, we're used to debugging our applications using different functions like dd() or info() if we want to write the output to the log channel. However, there's a better and easier approach to do this. In this article, we will take a look at a package called Laradumps created by Luan Freitas .


What Is LaraDumps?

LaraDumps is a user-friendly application that aims to enhance your coding and?debugging experience?in?Laravel PHP. By utilizing LaraDumps, you can observe the outcome of your debugging efforts presented within a?dedicated desktop application.


Whenever LaraDumps is triggered, you will get the debugging output in a beautiful and nice-looking window like the image below:


Installation

To start using LaraDumps, you have to:

  1. Download and install the required desktop application on your device
  2. Integrate the LaraDumps Laravel package into your project

Installing the desktop application

Installing the Laravel package

Using a command line interface, navigate to your Laravel project where you want to use this package and run the following command:


After that, if all goes well you can move to the next step.

Open up your LaraDumps desktop application and type the following command in your terminal at your project path to configure LaraDumps:

This command creates a laradumps.yaml file that contains the configuration that LaraDumps will use for your project. This file is also important because it tells LaraDumps how to communicate with the desktop application.

If this command doesn't work on Windows for some reason, then just run:

After that, open the resultant laradumps.yaml file, and update the app.project_path key to include the full absolute path to your project, for example:

You can take a look at the full configuration options at (https://laradumps.dev/get-started/configuration.html)

With all that set up, let's move on to the exciting part, DEBUGGING !!!

Note: all the sections that have (undocumented) inside their titles, means that these features aren't documented inside the official LaraDumps website, but I've taken a look at the vendor files and saw how these features work and documented them here.


Usage

Basics

First of all, make sure that your LaraDumps desktop application is open and running. By default, you should see the following screen when you open the application:

To dump output into this application, all you need to do is to use the ds() function. You can use this function everywhere instead of dd() or other debugging functions.

Let's head over to our routes/web.php file and define a GET route called test. Inside the callback function, let's just invoke the ds() function. Here's an example:

Now, visit the route /test in the browser then open the LaraDumps application and the output will be shown as follows:

Nice, here we have a beautiful interface where each message is being rendered and viewed in a pretty manner. Each time you reload the page, the new output will be appended to the screen.

However, it may be cumbersome to manually switch to the LaraDumps each time to see the dump output, so we can instead let the application get invoked automatically. This can be enabled either by clicking the small green signal icon and choosing the (AUTO INVOKE APP) option as follows:

Or you can do that by setting the observers.auto_invoke_app option inside your laradumps.yaml file to be true:

There are other available functions as well:

  • dsd(): dump and die, acts exactly like ds(), but it stops execution.
  • dsq(): dump quietly, acts exactly like ds(), but it doesn't invoke the application

Dumping SQL Queries

A common use case for debugging is the capture of SQL queries. There are several ways to do this.

The first way is to place your code between the calls of queriesOn() and queriesOff() methods. The queriesOn() method takes an optional argument which is a string that will be used as a label to describe the function of a query.

For example, the following code:

Will dump the following message to the application:

The other way to debug an SQL query is by using the ds() method as a chain on the query builder instance. For example, the following code dumps the query at every stage so that we can see how it's changing as we add more constraints:

Eventually, we will see 3 messages in the application's window:

By default, LaraDumps will only dump queries that you explicitly tell it to dump (just like in our previous case). However, you can configure the package to make it dump all queries without any call to the ds() helper, all you have to do is enable the (QUERIES) option after clicking the green signal icon in the top right of the screen:

Or you can configure the observers.queries option in your laradumps.yaml file to be true. By default, it's false:

You can fine-tune the behavior even more by triggering the application only when an SQL query takes more than a specified number of milliseconds to execute. To do this, you need to enable the slow queries observer. This can be done either by enabling the (SLOW QUERIES) switch in the application, or you can change the observers.slow_queries option in the YAML file as follows:

To configure the threshold of the execution time that will trigger the application, you can set the value of the slow_queries.threshold_in_ms option in the YAML file. For example, here we're setting it to be 100 milliseconds:

Notice that the queries observer and the slow queries observer work independently of each other. This means that you don't need to enable the queries observer for the slow queries observer to work.

Dumping Models

Sometimes, it may be necessary to debug and inspect model values. For example, we may need to inspect the model for the user whose email is [email protected], so we go ahead and write the following code:

Which will dump the following message to the application:

Multiple models can also be dumped at the same time, just pass each model as a separate argument to the model() method:

And you will get the following output:

Debugging HTTP requests

Inspecting and debugging HTTP requests is also possible with LaraDumps. The mechanism is similar to the one we've seen with SQL: place your code between calls to httpOn() and httpOff() methods. An example would look like this:

The output consists of two parts, a request section:

And a response section:

It is worth noticing that the httpOn() method takes a string parameter that serves as a label that gets displayed in the panels.

As you can see, each time you want to inspect an HTTP request, you have to manually call the httpOn() and httpOff() methods. This behavior may not be suitable for all developers, as some may want to inspect HTTP requests globally, in this case, you have to set the observers.http option inside your laradumps.yaml file:

Note: the HTTP observer is designed to work only with the built-in HTTP client provided by the Laravel framework. This means that if you try to make HTTP requests in other ways (for example, using the curl_*() functions), then the HTTP observer won't be triggered.

Inspecting collections

It shouldn't be a surprise that we can also inspect collections with the help of this package. For example:

Will dump the following messages to the application:

Notice that LaraDumps registers the ds() method as a macro method, and it's available on collections in Laravel.

Dumping logs

LaraDumps can also be triggered when logs are being produced. By default, this behavior is disabled but can be enabled through the observers.logs option inside the YAML file as follows:

However, logging can also be fine-tuned to include only specific types of logging messages (also called logging levels), and this can be done through the option. By default, this option looks as follows:

The first 8 options are the standard logging levels defined under section 6.2.1 of RFC 5424 (and they're used by PSR-3), and the remaining two vendor and deprecated_message logging levels are non-standard.

By default, only error, critical, and notice logging levels are enabled, but you can enable the rest of the logging levels as per your needs.

For example, here we need to enable both info and debug logging levels for LaraDumps to get invoked:

The output will look like this:

Measuring execution time

Place your code within the call of time() method and stopTime() method and let the package do the rest. Here's an example:

And you will get the total elapsed time for the execution as follows:

Note that the parameter which is passed to time() and stopTime() methods is the checkpoint name, it needs to be the same in both calls.

Dumping tables

A very nice feature is the ability to dump iterables in a beautiful and user-friendly searchable table. For example, let's say that we want to get some users from Github API using an HTTP request, and then inspect the output inside a table. Our code will look like this:

The output we get is the following:

Dumping cache

To enable cache dumping, you must enable the cache observer. By default, there's no option inside the YAML file to do this, so you will need to add it manually as follows:

The nice thing about the cache observer is that it listens to four different types of events related to the cache:

  • KeyWritten: triggered when a new value is assigned to a key
  • KeyForgotten: triggered when a key and its assigned value are removed from the cache storage
  • CacheMissed: triggered when you try to access a key that doesn't exist in the cache storage
  • CacheHit: triggered when you try to access a key that exists in the cache storage

Let's take a look at the following example for a better demonstration:

This should give the following result:

Sometimes, you may not want to enable the cache observer globally. In this case, you can use the cacheOn() and cacheOff() methods, for example:

This should give the following output:

Notice that the last call to Cache::get() wasn't dumped.

Monitoring jobs

You can configure LaraDumps to monitor jobs as well. This can be done through the observers.jobs option inside the YAML file:

This observer is triggered when any of the following job-related events gets triggered:

  • JobQueued: triggered when a job has been dispatched and added to a queue
  • JobProcessing: triggered when a job is dequeued and is started
  • JobProcessed: triggered when a job has been processed successfully
  • JobFailed: triggered when a job has failed due to some error

Let's take a look at an example. Here we have the NotifyUserForOrderUpdates job, which looks as follows:

Now let's dispatch this job using the following code:

We should see the following result:

As with the previous situations, you have jobsOn() and jobsOff() methods available for situations where you don't want to enable the jobs observer globally.

Working with commands

To monitor commands using LaraDumps, you have to make sure that the observers.commands option in your YAML file is enabled:

After that whenever you run any command from within your project or use any Artisan command, LaraDumps gets automatically invoked. For example, if you run the command:

You will see the following screen:

As with the previous situations, you have commandsOn() and commandsOff() methods available for situations where you don't want to enable the commands observer globally.

Working with mails

When it comes to debugging mails in Laravel, then LaraDumps can also help you as well. All you have to do is to enable the observers.mail option inside your laradumps.yaml file:

And that's it. Now LaraDumps will be triggered every time a mail is sent.

For example, here we have a WelcomeMail class:

To send this mail, we can use the following code:

This will cause the following output to be dumped inside the LaraDumps desktop application:

As you can see, the Header tab contains general information about the mail (e.g. subject, destination, sender), and also there's a View Content button, if you click it, you will get a popup window that contains a preview of the mail sent:

There's also a Dump tab, which contains detailed information about the mail object:

You can also use the mailable() method to quickly dump the contents of a mail, for example:

Gives the following output:

Working with gates (undocumented)

In Laravel, a Gate is a mechanism that authorizes user actions against a given resource. This is also known as "permissions".

If you have used packages such as spatie/laravel-permission or santigarcor/laratrust to manage roles and permissions, these packages use gates under the hood to provide this behavior, which makes the gates observer of LaraDumps a perfect choice to debug possible related issues in your code.

All you need to do is to enable the observers.gate observer inside your laradumps.yaml file:

For simplicity, I'm just going to define a simple gate like this inside the boot() method of the App\Providers\AppServiceProvider class:

Then, I'll use the can middleware on a test route to ensure that only users who have this ability will access this route:

If I try to access this route, I'll get the following output inside the LaraDumps application:

As you can see, each time this gate is used (and by that, I mean the GateEvaluated event was triggered), then LaraDumps gets invoked.

If you use one of the aforementioned packages to manage roles and permissions, then you don't need to worry about all that. Just enable the gate observer and you're good to go.

As with the previous situations in the cache and HTTP observers, you have gateOn() and gateOff() methods available for situations where you don't want to enable the gate observer globally.

Dumping from within Blade template files (undocumented)

LaraDumps defines a Blade directive called @ds() which you can use inside any Blade file to dump content, for example:

Will give the following output:

Dumping strings

You can use LaraDumps to dump strings, for example:

This will give the following output:

Dumping routes

By using the routes() method, you can dump the defined routes inside your project into a nice table, for example:

Will give the following output:

Using LaraDumps with original dump functions

So far, we've used the ds() function to invoke LaraDumps. However, we can configure LaraDumps to be invoked with the usual dumping functions available in Laravel such as dump(), dd(), and ddd(). This can be easily done through the observers.dump option inside file:

This way, anytime you use one of the aforementioned functions, you will invoke LaraDumps.

Using LaraDumps for benchmarking

LaraDumps ships with a benchmark() method that can be used to run benchmarks. Using this method, you can benchmark a single function, for example:

This will yield the following output:

As you can see, the result involves an array that has 4 different keys, but the most important two keys are the (Total Time) and (Result) keys:

  • The (Total Time) key contains a value that represents the time the function took to execute.
  • The (Result) key is the returned value from the executed function.

To the left of the results section, you can see the word (Closure 0), this is the name of the function that got executed. We can give it a custom name by passing an associative array as follows:

And this should give the following output:

The benchmarking method is also useful in case you want to compare the benchmarking results of two or more functions, for example:

This should give the following output:

In this case, we can see that the last section in the result contains the name of the fastest function in terms of execution time.


Miscellaneous options

Labeling your dumps

As you add more dumps, things may become very messy because you will get many dumps and you won't know which dump belongs to which invocation. In this case, it may be a good idea to label your dumps using the label() method. Let's take a look at the following example:

Output into different screens

You can group and organize your dumps into different screens for easier access. This can be done using the toScreen() method or the s() method, for example:

This will give the following output:

Notice the tabs in the window, they allow you to switch between different screens.

Customizing the colors (partially undocumented)

You can customize the border color of the dumped message for easier recognition. All you need is to use the method that describes the message type and the output will have the corresponding border color, for example, the danger() method will cause the message to have a red border.

If you enable the config.color_in_screen option inside the YAML file, you will cause each message of certain types to be grouped in separate screens, the output will look as follows:

Verifying whether a JSON string is valid or invalid

Using the isJson() method, you can verify whether a JSON string is valid or not. Here's an example:

This gives the following output:

Verifying if a string appears in the dump

Using the contains() method allows you to verify if a given string appears in the dump, for example:

Notice that the wholeWord parameter means that an entire match must be found for the specified word, while the caseSensitive parameter controls whether the search is case-sensitive or not.

Writing markdown

LaraDumps has a markdown() method that can be used to dump markdown content. For example:

Gives the following output:

Dumping phpinfo()

You can use the phpinfo() method to dump the information of your PHP installation into a nice-looking table, for example:

Adding intervals between dumps (undocumented)

Sometimes, you may find it useful to add time intervals between dumps. In this case, you can go ahead and set the config.sleep option inside the YAML. For example, here we're adding a 5 seconds interval between dumps:

Now if we run the following code:

And here's the output:

Notice the differences in times, the first dump was delayed 5 seconds, the second one was delayed 5 seconds from the first, and the third one was delayed 5 seconds from the second one.


Deployment to production

This whole library is just meant for debugging purposes, we're not interested in having it active in our production environment, and therefore any calls to ds() must be removed from the code before deployment.

Luckily, you don't have to make any effort to memorize where you have made this call as you can simply call the command:

Where PATHS represents a list of comma-separated paths of project directories to scan for any invocations of ds() function and points you to their locations in case they exist. For example, if we want to scan app, resources, and routes folders, then we'll need to write:

Depending on where you have called ds(), you may see an error message like follows:

However, be careful that this check mechanism isn't very accurate because it actually performs a text search which may result in false positives in several cases such as:

  • If there exists a commented invocation for ds() function
  • If there exists a constant, user-defined function or a class whose name begins with the prefix ds

This means that the following code:

Would still cause the following false positive errors:

Therefore, even though the documentation recommends using this check in a deployment pipeline, I strongly advise against the usage of this command in such scenarios.

In my opinion, the solution to this problem would be to programmatically parse each PHP file inside the directories to check if there exists a call to the ds() function. This can be done using the PHP-Parser library by Nikita Popov. But of course, that's a whole other story I may write about in the future.


Conclusion

In conclusion, debugging is an essential part of software development, and with the help of tools such as LaraDumps, developers can efficiently identify and fix errors in their Laravel applications. By leveraging the extensive features of LaraDumps, developers can save time and streamline the?debugging process, allowing them to focus on building high-quality software. With its easy-to-use interface and powerful set of tools, LaraDumps is a valuable asset for any?Laravel developer?looking to improve their?debugging workflow.

要查看或添加评论,请登录

Eyad Bereh的更多文章