Getting Started with Resource Monitoring in Laravel 9
Most systems already exist that provide us with a way to monitor the CPU and memory usage of the system. However, they might not be very flexible to support our daily needs. <!--more--> Developers more often are faced with problems of resource management, where the machines freeze or hang when all the available resources have been consumed.
Albeit, it's possible to monitor these resources using, let's say Windows task manager and Linux's system monitor, this has proven to be a hurdle in a shared hosting.
In this tutorial, we will learn how to build a Laravel system that has the ability to monitor the resource usage of the shared hosting server.
Table of contents
- Getting started with the resource monitoring in Laravel 9
- Introduction
- Table of contents
- Prerequisites
- Objectives
- Setting up the Laravel 9 application
- Configuring the resource manager packages
- Adding the controllers
- Conclusion
Prerequisites
To be able to understand and follow this tutorial, the reader should have at least the following knowledge:
- Basic knowledge in Laravel. In this tutorial, we will be using Laravel 9.
- Basic knowledge in object oriented programming in PHP.
- Composer should be locally installed to be able to download and install third party packages.
Objectives
By the end of this tutorial, you should be able to be in a position to build a resource manager for your system.
Setting up the Laravel 9 application
Laravel is a PHP framework that is used to build web applications. It is a popular choice among developers for building web applications.
To install Laravel in your local machine, you have various options.
- Install Laravel using the official Laravel installer.
- Using the composer package manager.
In this tutorial, we will be using the Laravel installer, however you may follow official documentation to install Laravel using the composer package manager.
Let's begin by running the following commands to make installer visible within my project root:
export PATH="$PATH:$HOME/.config/composer/vendor/bin"
NOTE that the path is relative to the home directory of the user, and this may change depending on your installations setup.
Next, install the resource manager application by executing the following installer command:
laravel new resource-manager
The installation may take a while depending on your internet connection. Once complete, cd
into the project root directory and run the following command to start the application:
php artisan serve
The above command starts the Laravel application on the default port of http://localhost:8000
.
It's important to note that the above port only works if it's not in use.
You can change the port by running the following command:
php artisan serve --port=<PORT>
Configuring the resource manager packages
Now that we have our Laravel application running, we need to install the resource manager packages.
Let's start by installing a package known as Spatie server monitor
. This package will give us all the functionalities we need to ensure that we can run the resource scans.
composer require spatie/laravel-server-monitor:^1.0
Output:
Discovered Package: laravel/sail
Discovered Package: laravel/sanctum
Discovered Package: laravel/tinker
Discovered Package: nesbot/carbon
Discovered Package: nunomaduro/collision
Discovered Package: spatie/laravel-blink
Discovered Package: spatie/laravel-ignition
Discovered Package: spatie/laravel-server-monitor
Package manifest generated successfully.
...
Once complete, the new package will be added on the composer.json
file as shown below:
"spatie/laravel-server-monitor": "^1.0"
Next, update the config/app.php
file to include the following line:
'providers' => [
...
Spatie\ServerMonitor\ServerMonitorServiceProvider::class,
...
],
We add the providers array to ensure that the package is loaded.
Now that we have installed the package, we need to publish the assets. This is done by running the following command:
php artisan vendor:publish --all # to publish all the assets
# use this command if you want to publish only the assets for the given tag
php artisan vendor:publish --provider="Spatie\ServerMonitor\ServerMonitorServiceProvider" --tag="migrations"
When successful, the following database tables will be created:
...
// hosts table
Schema::create('hosts', function (Blueprint $table) {
// unique identifier for the table
$table->increments('id');
// name of the host
$table->string('name');
//
$table->string('ssh_user')->nullable();
$table->integer('port')->nullable();
// ip address of the host
$table->string('ip')->nullable();
// custom properties for the host
$table->json('custom_properties')->nullable();
$table->timestamps();
});
The above table will be used to store the hosts that we will be monitoring.
The other table created is the checks
table. This table will be used to store the checks that we will be running on the hosts.
...
Schema::create('checks', function (Blueprint $table) {
// unique identifier for the table
$table->increments('id');
// host id
$table->integer('host_id')->unsigned();
// using host id as foreign key
$table->foreign('host_id')->references('id')->on('hosts')->onDelete('cascade');
// type
$table->string('type');
// status
$table->string('status')->nullable();
// is enabled
$table->boolean('enabled')->default(true);
// last run message
$table->text('last_run_message')->nullable();
// last run output
$table->json('last_run_output')->nullable();
// last time it ran
$table->timestamp('last_ran_at')->nullable();
// next time it will run
$table->integer('next_run_in_minutes')->nullable();
// notification
$table->timestamp('started_throttling_failing_notifications_at')->nullable();
// custom properties for the check
$table->json('custom_properties')->nullable();
// the check will be created when the host is created
$table->timestamps();
});
In other words, the hosts
will store all the required details about the computers or servers being monitored while the checks
table stores the information about the checks that will be run on the hosts.
With the above command, we can see that the following assets are being published in the config/server-monitor.php
file:
<?php
return [
...
// the checks that can be performed by our system
'checks' => [
// diskspace memory check
'diskspace' => Spatie\ServerMonitor\CheckDefinitions\Diskspace::class,
// elasticsearch check
'elasticsearch' => Spatie\ServerMonitor\CheckDefinitions\Elasticsearch::class,
// Memcache checks
'memcached' => Spatie\ServerMonitor\CheckDefinitions\Memcached::class,
// mysql database checks
'mysql' => Spatie\ServerMonitor\CheckDefinitions\MySql::class,
],
...
];
In the above file, we have added the following checks:
- The
diskspace
: This will check the disk space of the system. - The
elasticsearch
: This will check the elastic search server. - The
memcached
: This will check the memcached server. - The
mysql
: This will check the mysql database.
Adding the controllers
With server monitor setup complete, let's now proceed and add a few controllers to our application.
The goal of the controllers is to handle the logic of the resource manager.
We want our controllers to be able to handle the following:
- Handle the
apache status
check on our server. - Check the database connection.
- Check the MySQL database.
- Check for our RAM status/usage.
Therefore, we need to create 4 controller for each of the tasks above.
The reason we're creating the 4 controllers instead of 1 controller with multiple methods is because the package installed has an interface which only takes a single method.
Run the following commands to add the controllers:
# add the controller for the apache status check
php artisan make:controller ApacheCheckerController
# add the controller for the database connection check
php artisan make:controller DatabaseCheckerController
# add the controller for the mysql database check
php artisan make:controller MySqlCheckerController
# add the controller for the ram check
php artisan make:controller RamCheckerController
Next, open the ApacheCheckerController.php
file and add the following code:
<?php
...
// import the
use Spatie\ServerMonitor\CheckDefinitions\CheckDefinition;
use Symfony\Component\Process\Process;
class ApacheCheckerController extends CheckDefinition
{
// use this command to check the status of Apache2 on your server
public $command = 'sudo systemctl status apache2';
// resolve the execution
public function resolve(Process $process)
{
// the output will contain the status if it;s active na running
if (str_contains($process->getOutput(), 'active (running)')) {
// if it;s running, then success
$this->check->succeed('is running');
return;
}
// if the check fails, then it;s not running
$this->check->fail('is not running');
}
}
In the above controller, we have added the following:
- The
command
: This is the command that will be executed to check the status of Apache2. - The
resolve
: This is the method that will be called when the command is executed.
Next, open the DatabaseCheckerController.php
file and add the following code:
<?php
...
//import the checkDefinition class
use Spatie\ServerMonitor\CheckDefinitions\CheckDefinition;
use Symfony\Component\Process\Process;
class RamCheckerController extends CheckDefinition
{
public $command = "";
// use this method to calculate the RAM percentage
protected function getRAMUsagePercentage(): float
{
$ram = shell_exec("grep 'RAM ' /proc/stat | awk '{ramUsage=($2+$4)*100/($2+$4+$5)} END {print ramUsage}'");
return (float) $ram;
}
public function resolve(Process $process)
{
// assign the ram percentage
$ramPercentage = $this->getRAMUsagePercentage();
// get the exact usage
$ramUsage = round($ramPercentage, 2);
//init the message
$message = "My RAM usage at {$ramUsage}%";
//get the ram usage threshold
$ram_usage_threshold = config('server-monitor.cpu_usage_threshold');
// check for any failures of the RAM percentage against its usage threshold
if ($ramPercentage >= $ram_usage_threshold['fail']) {
$this->check->fail($message);
return;
}
// check for any warnings of the RAM percentage against its usage threshold
if ($ramPercentage >= $ram_usage_threshold['warning']) {
$this->check->warn($message);
return;
}
// otherwise if success, return the message
$this->check->succeed($message);
}
}
In the above controller, we have added the following:
- The
command
: This is the command that will be executed to check the status of RAM usage and remaining percentage. - The resolve`: This is the method that will be called when the command is executed.
- In the resolve method, we have added the following:
- The
getRAMUsagePercentage
: This method will be used to calculate the RAM usage percentage. - The RAM usage is then rounded to 2 decimal places.
- We have the message to be displayed in the check.
- The RAM usage threshold is then checked against the usage.
- The
Now that we have controllers defined, next run the following commands to add the remote hosts to the server monitor:
# add the remote hosts to the server monitor
php artisan server-monitor:add-hosts
Output:
Lets add a host!
What is the name of the host:
> section.io
Should a custom ssh user be used? (yes/no) [no]:
> yes
Which user?:
> admin
Should a custom port be used? (yes/no) [no]:
> 8080
Should a specific ip address be used? (yes/no) [no]:
> yes
Which ip address?:
> http://localhost:8080
Which checks should be performed? [<all checks>]:
[0] <all checks>
[1] diskspace
[2] elasticsearch
[3] memcached
[4] mysql
> 1
Host `section.io` added
Update the above yes or no questions depending on the requirements of the host.
Next, let's proceed and run the diskspace check.
# run the diskspace check
php artisan server-monitor:run-checks
Expected Output:
Start running 1 checks...
section.io: performing check `diskspace`...
....
You'll notice that the above check is specific to diskspace
since we selected that check in our host configuration.
Conclusion
In this tutorial, we learned how to build a resource manager for your Laravel system.
We have extensively discussed the various main resources to be monitored in Laravel. In this tutorial, we covered the following:
- CPU usage
- Database traffics
Happy coding!
Peer Review Contributions by: Miller Juma