Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 47 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,21 @@
[![Quality Score](https://img.shields.io/scrutinizer/g/ericmakesstuff/laravel-server-monitor.svg?style=flat-square)](https://scrutinizer-ci.com/g/ericmakesstuff/laravel-server-monitor)
[![Total Downloads](https://img.shields.io/packagist/dt/ericmakesstuff/laravel-server-monitor.svg?style=flat-square)](https://packagist.org/packages/ericmakesstuff/laravel-server-monitor)

This Laravel 5 package will periodically monitor the health of your server. Currently, it provides healthy/alarm status notifications for Disk Usage.
This Laravel 5 package will periodically monitor the health of your server. Currently, it provides healthy/alarm status notifications for Disk Usage, as well as an HTTP Ping function to monitor the health of external services.

Once installed, monitoring your server is very easy. Just issue this artisan command:

``` bash
php artisan monitor:run
```

You can run only certain monitors at a time:

``` bash
php artisan monitor:run DiskUsage
php artisan monitor:run DiskUsage,HttpPing
```

## Installation and usage

You can install this package via composer using:
Expand All @@ -35,6 +42,43 @@ To publish the config file to app/config/server-monitor.php run:

`php artisan vendor:publish --provider="EricMakesStuff\ServerMonitor\ServerMonitorServiceProvider"`

## Monitor Configuration

After publishing the configuration file, you can edit the `'monitors'` section of app/config/server-monitor.php.

The default monitor configurations are:

```php
'monitors' => [
/*
* DiskUsage will alert when the free space on the device exceeds the alarmPercentage.
* path is any valid file path, and the monitor will look at the usage of that disk partition.
*
* You may add as many DiskUsage monitors as you require.
*/
'DiskUsage' => [
[
'path' => base_path(),
'alarmPercentage' => 75,
],
],
/*
* HttpPing will perform an HTTP request to the configured URL and alert if the response code
* is not 200, or if the optional checkPhrase is not found in the response.
*/
'HttpPing' => [
[
'url' => 'http://www.example.com/',
],
[
'url' => 'http://www.example.com/',
'checkPhrase' => 'Example Domain',
'timeout' => 10,
'allowRedirects' => false,
],
],
```

## Scheduling

After you have performed the basic installation you can start using the monitor:run command. In most cases you'll want to schedule this command so you don't have to manually run monitor:run every time you want to know the health of your server.
Expand All @@ -47,10 +91,11 @@ The commands can, like an other command, be scheduled in Laravel's console kerne
protected function schedule(Schedule $schedule)
{
$schedule->command('monitor:run')->daily()->at('10:00');
$schedule->command('monitor:run HttpPing')->hourly();
}
```

Of course, the hour used in the code above is just an example. Adjust it to your own preferences.
Of course, the schedules used in the code above are just an example. Adjust them to your own preferences.

## Testing

Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
},
"require": {
"illuminate/support": "^5.1",
"illuminate/console": "^5.1"
"illuminate/console": "^5.1",
"guzzlehttp/guzzle": "~6.0"
},
"require-dev": {
"orchestra/testbench": "^3.2",
Expand Down
19 changes: 18 additions & 1 deletion config/server-monitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,21 @@
'alarmPercentage' => 75,
],
],
/*
* HttpPing will perform an HTTP request to the configured URL and alert if the response code
* is not 200, or if the optional checkPhrase is not found in the response.
*/
'HttpPing' => [
[
'url' => 'http://www.example.com/',
],
[
'url' => 'http://www.example.com/',
'checkPhrase' => 'Example Domain',
'timeout' => 10,
'allowRedirects' => false,
],
],
],

'notifications' => [
Expand All @@ -43,7 +58,9 @@
*/
'events' => [
'whenDiskUsageHealthy' => ['log'],
'whenDiskUsageAlarm' => ['log', 'mail']
'whenDiskUsageAlarm' => ['log', 'mail'],
'whenHttpPingUp' => ['log'],
'whenHttpPingDown' => ['log', 'mail'],
],

/*
Expand Down
7 changes: 5 additions & 2 deletions src/Commands/RunCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class RunCommand extends BaseCommand
/**
* @var string
*/
protected $signature = 'monitor:run';
protected $signature = 'monitor:run {monitor? : Comma-delimited list of names of specific monitors to run}';

/**
* @var string
Expand All @@ -19,7 +19,10 @@ class RunCommand extends BaseCommand

public function handle()
{
$monitors = ServerMonitorFactory::createForMonitorConfig(config('server-monitor.monitors'));
$monitors = ServerMonitorFactory::createForMonitorConfig(
config('server-monitor.monitors'),
explode(',', $this->argument('monitor'))
);

$monitors->each(function (BaseMonitor $monitor) {
$monitor->runMonitor();
Expand Down
19 changes: 19 additions & 0 deletions src/Events/HttpPingDown.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace EricMakesStuff\ServerMonitor\Events;

use EricMakesStuff\ServerMonitor\Monitors\HttpPingMonitor;

class HttpPingDown
{
/** @var \EricMakesStuff\ServerMonitor\Monitors\HttpPingMonitor|null */
public $httpPingMonitor;

/**
* @param \EricMakesStuff\ServerMonitor\Monitors\HttpPingMonitor|null $httpPingMonitor
*/
public function __construct(HttpPingMonitor $httpPingMonitor = null)
{
$this->httpPingMonitor = $httpPingMonitor;
}
}
19 changes: 19 additions & 0 deletions src/Events/HttpPingUp.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace EricMakesStuff\ServerMonitor\Events;

use EricMakesStuff\ServerMonitor\Monitors\HttpPingMonitor;

class HttpPingUp
{
/** @var \EricMakesStuff\ServerMonitor\Monitors\HttpPingMonitor|null */
public $httpPingMonitor;

/**
* @param \EricMakesStuff\ServerMonitor\Monitors\HttpPingMonitor $httpPingMonitor
*/
public function __construct(HttpPingMonitor $httpPingMonitor)
{
$this->httpPingMonitor = $httpPingMonitor;
}
}
5 changes: 5 additions & 0 deletions src/Exceptions/InvalidConfiguration.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,9 @@ public static function cannotFindMonitor($monitorName)
{
return new static("Could not find monitor named `{$monitorName}`.");
}

public static function noUrlConfigured()
{
return new static ("No URL Configured.");
}
}
123 changes: 123 additions & 0 deletions src/Monitors/HttpPingMonitor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
<?php

namespace EricMakesStuff\ServerMonitor\Monitors;

use EricMakesStuff\ServerMonitor\Events\HttpPingDown;
use EricMakesStuff\ServerMonitor\Events\HttpPingUp;
use EricMakesStuff\ServerMonitor\Exceptions\InvalidConfiguration;
use GuzzleHttp\Client as Guzzle;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\ConnectException;

class HttpPingMonitor extends BaseMonitor
{
/** @var int */
protected $responseCode;

/** @var string */
protected $responseContent;

/** @var bool */
protected $responseContainsPhrase = false;

/** @var string */
protected $url;

/** @var bool|string */
protected $checkPhrase = false;

/** @var int */
protected $timeout = 5;

/** @var bool */
protected $allowRedirects = true;

/**
* @param array $config
*/
public function __construct(array $config)
{
if (!empty($config['url'])) {
$this->url = $config['url'];
}

if (!empty($config['checkPhrase'])) {
$this->checkPhrase = $config['checkPhrase'];
}

if (!empty($config['timeout'])) {
$this->timeout = $config['timeout'];
}

if (!empty($config['allowRedirects'])) {
$this->allowRedirects = $config['allowRedirects'];
}
}

/**
* @throws InvalidConfiguration
*/
public function runMonitor()
{
if (empty($this->url)) {
throw InvalidConfiguration::noUrlConfigured();
}

try {
$guzzle = new Guzzle([
'timeout' => $this->timeout,
'allow_redirects' => $this->allowRedirects,
]);
$response = $guzzle->get($this->url);
$this->responseCode = $response->getStatusCode();
$this->responseContent = (string)$response->getBody();
} catch (ClientException $e) {
$response = $e->getResponse();
$this->responseCode = $response->getStatusCode();
} catch (ConnectException $e) {
}

if ($this->responseCode != '200'
|| ! $this->checkResponseContains($this->responseContent, $this->checkPhrase)) {
event(new HttpPingDown($this));
} else {
event(new HttpPingUp($this));
}
}

protected function checkResponseContains($html, $phrase)
{
if (!$phrase) {
return true;
}

$this->responseContainsPhrase = str_contains($html, $phrase);

return $this->responseContainsPhrase;
}

public function getResponseContainsPhrase()
{
return $this->responseContainsPhrase;
}

public function getCheckPhrase()
{
return $this->checkPhrase;
}

public function getResponseCode()
{
return $this->responseCode;
}

public function getResponseContent()
{
return $this->responseContent;
}

public function getUrl()
{
return $this->url;
}
}
12 changes: 9 additions & 3 deletions src/Monitors/ServerMonitorFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,18 @@ class ServerMonitorFactory
{
/**
* @param array $monitorConfiguration
* @param array $filter
* @return mixed
* @throws \EricMakesStuff\ServerMonitor\Exceptions\InvalidConfiguration
*/
public static function createForMonitorConfig(array $monitorConfiguration)
public static function createForMonitorConfig(array $monitorConfiguration, array $filter = [])
{
return collect($monitorConfiguration)->map(function($monitorConfigs, $monitorName) {
$monitors = collect($monitorConfiguration);

if (count($filter) && !empty($filter[0])) {
$monitors = $monitors->only($filter);
}

return $monitors->map(function($monitorConfigs, $monitorName) {
if (file_exists(__DIR__.'/'.ucfirst($monitorName).'Monitor.php')) {
$className = '\\EricMakesStuff\\ServerMonitor\\Monitors\\'.ucfirst($monitorName).'Monitor';
return collect($monitorConfigs)->map(function($monitorConfig) use ($className) {
Expand Down
30 changes: 29 additions & 1 deletion src/Notifications/EventHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

namespace EricMakesStuff\ServerMonitor\Notifications;

use Illuminate\Events\Dispatcher;
use EricMakesStuff\ServerMonitor\Events\HttpPingDown;
use EricMakesStuff\ServerMonitor\Events\HttpPingUp;
use EricMakesStuff\ServerMonitor\Events\DiskUsageAlarm;
use EricMakesStuff\ServerMonitor\Events\DiskUsageHealthy;
use Illuminate\Events\Dispatcher;

class EventHandler
{
Expand Down Expand Up @@ -36,6 +38,22 @@ public function whenDiskUsageHealthy(DiskUsageHealthy $event)
$this->notifier->diskUsageHealthy($event->diskUsageMonitor);
}

/**
* @param \EricMakesStuff\ServerMonitor\Events\HttpPingDown $event
*/
public function whenHttpPingDown(HttpPingDown $event)
{
$this->notifier->httpPingDown($event->httpPingMonitor);
}

/**
* @param \EricMakesStuff\ServerMonitor\Events\HttpPingUp $event
*/
public function whenHttpPingUp(HttpPingUp $event)
{
$this->notifier->httpPingUp($event->httpPingMonitor);
}

/**
* Register the listeners for the subscriber.
*
Expand All @@ -54,5 +72,15 @@ public function subscribe(Dispatcher $events)
DiskUsageAlarm::class,
static::class.'@whenDiskUsageAlarm'
);

$events->listen(
HttpPingUp::class,
static::class.'@whenHttpPingUp'
);

$events->listen(
HttpPingDown::class,
static::class.'@whenHttpPingDown'
);
}
}
Loading