Skip to content

Commit f4336a6

Browse files
committed
Merge pull request #3 from ericmakesstuff/feature-http-ping-monitor
Add new monitor: HTTP Ping
2 parents f51b12b + 18f6cde commit f4336a6

File tree

16 files changed

+486
-11
lines changed

16 files changed

+486
-11
lines changed

README.md

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,21 @@
66
[![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)
77
[![Total Downloads](https://img.shields.io/packagist/dt/ericmakesstuff/laravel-server-monitor.svg?style=flat-square)](https://packagist.org/packages/ericmakesstuff/laravel-server-monitor)
88

9-
This Laravel 5 package will periodically monitor the health of your server. Currently, it provides healthy/alarm status notifications for Disk Usage.
9+
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.
1010

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

1313
``` bash
1414
php artisan monitor:run
1515
```
1616

17+
You can run only certain monitors at a time:
18+
19+
``` bash
20+
php artisan monitor:run DiskUsage
21+
php artisan monitor:run DiskUsage,HttpPing
22+
```
23+
1724
## Installation and usage
1825

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

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

45+
## Monitor Configuration
46+
47+
After publishing the configuration file, you can edit the `'monitors'` section of app/config/server-monitor.php.
48+
49+
The default monitor configurations are:
50+
51+
```php
52+
'monitors' => [
53+
/*
54+
* DiskUsage will alert when the free space on the device exceeds the alarmPercentage.
55+
* path is any valid file path, and the monitor will look at the usage of that disk partition.
56+
*
57+
* You may add as many DiskUsage monitors as you require.
58+
*/
59+
'DiskUsage' => [
60+
[
61+
'path' => base_path(),
62+
'alarmPercentage' => 75,
63+
],
64+
],
65+
/*
66+
* HttpPing will perform an HTTP request to the configured URL and alert if the response code
67+
* is not 200, or if the optional checkPhrase is not found in the response.
68+
*/
69+
'HttpPing' => [
70+
[
71+
'url' => 'http://www.example.com/',
72+
],
73+
[
74+
'url' => 'http://www.example.com/',
75+
'checkPhrase' => 'Example Domain',
76+
'timeout' => 10,
77+
'allowRedirects' => false,
78+
],
79+
],
80+
```
81+
3882
## Scheduling
3983

4084
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.
@@ -47,10 +91,11 @@ The commands can, like an other command, be scheduled in Laravel's console kerne
4791
protected function schedule(Schedule $schedule)
4892
{
4993
$schedule->command('monitor:run')->daily()->at('10:00');
94+
$schedule->command('monitor:run HttpPing')->hourly();
5095
}
5196
```
5297

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

55100
## Testing
56101

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
},
2424
"require": {
2525
"illuminate/support": "^5.1",
26-
"illuminate/console": "^5.1"
26+
"illuminate/console": "^5.1",
27+
"guzzlehttp/guzzle": "~6.0"
2728
},
2829
"require-dev": {
2930
"orchestra/testbench": "^3.2",

config/server-monitor.php

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,21 @@
2626
'alarmPercentage' => 75,
2727
],
2828
],
29+
/*
30+
* HttpPing will perform an HTTP request to the configured URL and alert if the response code
31+
* is not 200, or if the optional checkPhrase is not found in the response.
32+
*/
33+
'HttpPing' => [
34+
[
35+
'url' => 'http://www.example.com/',
36+
],
37+
[
38+
'url' => 'http://www.example.com/',
39+
'checkPhrase' => 'Example Domain',
40+
'timeout' => 10,
41+
'allowRedirects' => false,
42+
],
43+
],
2944
],
3045

3146
'notifications' => [
@@ -43,7 +58,9 @@
4358
*/
4459
'events' => [
4560
'whenDiskUsageHealthy' => ['log'],
46-
'whenDiskUsageAlarm' => ['log', 'mail']
61+
'whenDiskUsageAlarm' => ['log', 'mail'],
62+
'whenHttpPingUp' => ['log'],
63+
'whenHttpPingDown' => ['log', 'mail'],
4764
],
4865

4966
/*

src/Commands/RunCommand.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ class RunCommand extends BaseCommand
1010
/**
1111
* @var string
1212
*/
13-
protected $signature = 'monitor:run';
13+
protected $signature = 'monitor:run {monitor? : Comma-delimited list of names of specific monitors to run}';
1414

1515
/**
1616
* @var string
@@ -19,7 +19,10 @@ class RunCommand extends BaseCommand
1919

2020
public function handle()
2121
{
22-
$monitors = ServerMonitorFactory::createForMonitorConfig(config('server-monitor.monitors'));
22+
$monitors = ServerMonitorFactory::createForMonitorConfig(
23+
config('server-monitor.monitors'),
24+
explode(',', $this->argument('monitor'))
25+
);
2326

2427
$monitors->each(function (BaseMonitor $monitor) {
2528
$monitor->runMonitor();

src/Events/HttpPingDown.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
namespace EricMakesStuff\ServerMonitor\Events;
4+
5+
use EricMakesStuff\ServerMonitor\Monitors\HttpPingMonitor;
6+
7+
class HttpPingDown
8+
{
9+
/** @var \EricMakesStuff\ServerMonitor\Monitors\HttpPingMonitor|null */
10+
public $httpPingMonitor;
11+
12+
/**
13+
* @param \EricMakesStuff\ServerMonitor\Monitors\HttpPingMonitor|null $httpPingMonitor
14+
*/
15+
public function __construct(HttpPingMonitor $httpPingMonitor = null)
16+
{
17+
$this->httpPingMonitor = $httpPingMonitor;
18+
}
19+
}

src/Events/HttpPingUp.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
namespace EricMakesStuff\ServerMonitor\Events;
4+
5+
use EricMakesStuff\ServerMonitor\Monitors\HttpPingMonitor;
6+
7+
class HttpPingUp
8+
{
9+
/** @var \EricMakesStuff\ServerMonitor\Monitors\HttpPingMonitor|null */
10+
public $httpPingMonitor;
11+
12+
/**
13+
* @param \EricMakesStuff\ServerMonitor\Monitors\HttpPingMonitor $httpPingMonitor
14+
*/
15+
public function __construct(HttpPingMonitor $httpPingMonitor)
16+
{
17+
$this->httpPingMonitor = $httpPingMonitor;
18+
}
19+
}

src/Exceptions/InvalidConfiguration.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,9 @@ public static function cannotFindMonitor($monitorName)
1414
{
1515
return new static("Could not find monitor named `{$monitorName}`.");
1616
}
17+
18+
public static function noUrlConfigured()
19+
{
20+
return new static ("No URL Configured.");
21+
}
1722
}

src/Monitors/HttpPingMonitor.php

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
<?php
2+
3+
namespace EricMakesStuff\ServerMonitor\Monitors;
4+
5+
use EricMakesStuff\ServerMonitor\Events\HttpPingDown;
6+
use EricMakesStuff\ServerMonitor\Events\HttpPingUp;
7+
use EricMakesStuff\ServerMonitor\Exceptions\InvalidConfiguration;
8+
use GuzzleHttp\Client as Guzzle;
9+
use GuzzleHttp\Exception\ClientException;
10+
use GuzzleHttp\Exception\ConnectException;
11+
12+
class HttpPingMonitor extends BaseMonitor
13+
{
14+
/** @var int */
15+
protected $responseCode;
16+
17+
/** @var string */
18+
protected $responseContent;
19+
20+
/** @var bool */
21+
protected $responseContainsPhrase = false;
22+
23+
/** @var string */
24+
protected $url;
25+
26+
/** @var bool|string */
27+
protected $checkPhrase = false;
28+
29+
/** @var int */
30+
protected $timeout = 5;
31+
32+
/** @var bool */
33+
protected $allowRedirects = true;
34+
35+
/**
36+
* @param array $config
37+
*/
38+
public function __construct(array $config)
39+
{
40+
if (!empty($config['url'])) {
41+
$this->url = $config['url'];
42+
}
43+
44+
if (!empty($config['checkPhrase'])) {
45+
$this->checkPhrase = $config['checkPhrase'];
46+
}
47+
48+
if (!empty($config['timeout'])) {
49+
$this->timeout = $config['timeout'];
50+
}
51+
52+
if (!empty($config['allowRedirects'])) {
53+
$this->allowRedirects = $config['allowRedirects'];
54+
}
55+
}
56+
57+
/**
58+
* @throws InvalidConfiguration
59+
*/
60+
public function runMonitor()
61+
{
62+
if (empty($this->url)) {
63+
throw InvalidConfiguration::noUrlConfigured();
64+
}
65+
66+
try {
67+
$guzzle = new Guzzle([
68+
'timeout' => $this->timeout,
69+
'allow_redirects' => $this->allowRedirects,
70+
]);
71+
$response = $guzzle->get($this->url);
72+
$this->responseCode = $response->getStatusCode();
73+
$this->responseContent = (string)$response->getBody();
74+
} catch (ClientException $e) {
75+
$response = $e->getResponse();
76+
$this->responseCode = $response->getStatusCode();
77+
} catch (ConnectException $e) {
78+
}
79+
80+
if ($this->responseCode != '200'
81+
|| ! $this->checkResponseContains($this->responseContent, $this->checkPhrase)) {
82+
event(new HttpPingDown($this));
83+
} else {
84+
event(new HttpPingUp($this));
85+
}
86+
}
87+
88+
protected function checkResponseContains($html, $phrase)
89+
{
90+
if (!$phrase) {
91+
return true;
92+
}
93+
94+
$this->responseContainsPhrase = str_contains($html, $phrase);
95+
96+
return $this->responseContainsPhrase;
97+
}
98+
99+
public function getResponseContainsPhrase()
100+
{
101+
return $this->responseContainsPhrase;
102+
}
103+
104+
public function getCheckPhrase()
105+
{
106+
return $this->checkPhrase;
107+
}
108+
109+
public function getResponseCode()
110+
{
111+
return $this->responseCode;
112+
}
113+
114+
public function getResponseContent()
115+
{
116+
return $this->responseContent;
117+
}
118+
119+
public function getUrl()
120+
{
121+
return $this->url;
122+
}
123+
}

src/Monitors/ServerMonitorFactory.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,18 @@ class ServerMonitorFactory
88
{
99
/**
1010
* @param array $monitorConfiguration
11+
* @param array $filter
1112
* @return mixed
12-
* @throws \EricMakesStuff\ServerMonitor\Exceptions\InvalidConfiguration
1313
*/
14-
public static function createForMonitorConfig(array $monitorConfiguration)
14+
public static function createForMonitorConfig(array $monitorConfiguration, array $filter = [])
1515
{
16-
return collect($monitorConfiguration)->map(function($monitorConfigs, $monitorName) {
16+
$monitors = collect($monitorConfiguration);
17+
18+
if (count($filter) && !empty($filter[0])) {
19+
$monitors = $monitors->only($filter);
20+
}
21+
22+
return $monitors->map(function($monitorConfigs, $monitorName) {
1723
if (file_exists(__DIR__.'/'.ucfirst($monitorName).'Monitor.php')) {
1824
$className = '\\EricMakesStuff\\ServerMonitor\\Monitors\\'.ucfirst($monitorName).'Monitor';
1925
return collect($monitorConfigs)->map(function($monitorConfig) use ($className) {

src/Notifications/EventHandler.php

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22

33
namespace EricMakesStuff\ServerMonitor\Notifications;
44

5-
use Illuminate\Events\Dispatcher;
5+
use EricMakesStuff\ServerMonitor\Events\HttpPingDown;
6+
use EricMakesStuff\ServerMonitor\Events\HttpPingUp;
67
use EricMakesStuff\ServerMonitor\Events\DiskUsageAlarm;
78
use EricMakesStuff\ServerMonitor\Events\DiskUsageHealthy;
9+
use Illuminate\Events\Dispatcher;
810

911
class EventHandler
1012
{
@@ -36,6 +38,22 @@ public function whenDiskUsageHealthy(DiskUsageHealthy $event)
3638
$this->notifier->diskUsageHealthy($event->diskUsageMonitor);
3739
}
3840

41+
/**
42+
* @param \EricMakesStuff\ServerMonitor\Events\HttpPingDown $event
43+
*/
44+
public function whenHttpPingDown(HttpPingDown $event)
45+
{
46+
$this->notifier->httpPingDown($event->httpPingMonitor);
47+
}
48+
49+
/**
50+
* @param \EricMakesStuff\ServerMonitor\Events\HttpPingUp $event
51+
*/
52+
public function whenHttpPingUp(HttpPingUp $event)
53+
{
54+
$this->notifier->httpPingUp($event->httpPingMonitor);
55+
}
56+
3957
/**
4058
* Register the listeners for the subscriber.
4159
*
@@ -54,5 +72,15 @@ public function subscribe(Dispatcher $events)
5472
DiskUsageAlarm::class,
5573
static::class.'@whenDiskUsageAlarm'
5674
);
75+
76+
$events->listen(
77+
HttpPingUp::class,
78+
static::class.'@whenHttpPingUp'
79+
);
80+
81+
$events->listen(
82+
HttpPingDown::class,
83+
static::class.'@whenHttpPingDown'
84+
);
5785
}
5886
}

0 commit comments

Comments
 (0)