issue #15: adding warning threshold to server update, and separating notification/status functionality

adding warning threshold to insert form and adding tooltips

adding warning_threshold fields to install
This commit is contained in:
Pepijn Over 2014-03-21 16:38:48 +01:00 committed by Pepijn Over
parent 7d06195992
commit 14388657f2
21 changed files with 623 additions and 445 deletions

View File

@ -192,13 +192,13 @@ function psm_log_uptime($server_id, $status, $latency) {
/**
* Parses a string from the language file with the correct variables replaced in the message
*
* @param string $status is either 'on' or 'off'
* @param boolean $status
* @param string $type is either 'sms' or 'email'
* @param array $server information about the server which may be placed in a message: %KEY% will be replaced by your value
* @return string parsed message
*/
function psm_parse_msg($status, $type, $vars) {
$message = '';
$status = ($status == true) ? 'on' : 'off';
$message = psm_get_lang('notifications', $status . '_' . $type);

3
src/lang/bg.lang.php Normal file → Executable file
View File

@ -96,6 +96,7 @@ $sm_lang = array(
'port' => 'Порт',
'type' => 'Тип',
'pattern' => 'Търсене на образец/схема',
'pattern_description' => 'If this pattern is not found on the website, the server will be marked offline. Regular expressions are allowed.',
'last_check' => 'Последна проверка',
'last_online' => 'Последно на линия',
'monitoring' => 'Мониторинг',
@ -108,6 +109,8 @@ $sm_lang = array(
'week' => 'Week',
'day' => 'Day',
'hour' => 'Hour',
'warning_threshold' => 'Warning threshold',
'warning_threshold_description' => 'Number of failed checks required before it is marked offline.',
),
'config' => array(
'general' => 'Основни настройки',

View File

@ -96,6 +96,7 @@ $sm_lang = array(
'port' => 'Porta',
'type' => 'Tipo',
'pattern' => 'Search string/pattern',
'pattern_description' => 'If this pattern is not found on the website, the server will be marked offline. Regular expressions are allowed.',
'last_check' => 'Última verificação',
'last_online' => 'Última vez online',
'monitoring' => 'Monitoramento',
@ -108,6 +109,8 @@ $sm_lang = array(
'week' => 'Week',
'day' => 'Day',
'hour' => 'Hour',
'warning_threshold' => 'Warning threshold',
'warning_threshold_description' => 'Number of failed checks required before it is marked offline.',
),
'config' => array(
'general' => 'Geral',

View File

@ -96,6 +96,7 @@ $sm_lang = array(
'port' => 'Port',
'type' => 'Type',
'pattern' => 'Search string/pattern',
'pattern_description' => 'If this pattern is not found on the website, the server will be marked offline. Regular expressions are allowed.',
'last_check' => 'Letzter Check',
'last_online' => 'Letztes mal Online',
'monitoring' => 'Monitoring',
@ -108,6 +109,8 @@ $sm_lang = array(
'week' => 'Week',
'day' => 'Day',
'hour' => 'Hour',
'warning_threshold' => 'Warning threshold',
'warning_threshold_description' => 'Number of failed checks required before it is marked offline.',
),
'config' => array(
'general' => 'General',

View File

@ -96,6 +96,7 @@ $sm_lang = array(
'port' => 'Port',
'type' => 'Type',
'pattern' => 'Search string/pattern',
'pattern_description' => 'If this pattern is not found on the website, the server will be marked offline. Regular expressions are allowed.',
'last_check' => 'Last check',
'last_online' => 'Last online',
'monitoring' => 'Monitoring',
@ -108,6 +109,8 @@ $sm_lang = array(
'week' => 'Week',
'day' => 'Day',
'hour' => 'Hour',
'warning_threshold' => 'Warning threshold',
'warning_threshold_description' => 'Number of failed checks required before it is marked offline.',
),
'config' => array(
'general' => 'General',

View File

@ -96,6 +96,7 @@ $sm_lang = array(
'port' => 'Port',
'type' => 'Type',
'pattern' => 'Rechercher un texte/motif',
'pattern_description' => 'If this pattern is not found on the website, the server will be marked offline. Regular expressions are allowed.',
'last_check' => 'Dernière vérification',
'last_online' => 'Dernière fois OK',
'monitoring' => 'Serveillé',
@ -108,6 +109,8 @@ $sm_lang = array(
'week' => 'Semaine',
'day' => 'Jour',
'hour' => 'Heure',
'warning_threshold' => 'Warning threshold',
'warning_threshold_description' => 'Number of failed checks required before it is marked offline.',
),
'config' => array(
'general' => 'Général',

View File

@ -96,6 +96,7 @@ $sm_lang = array(
'port' => 'Port',
'type' => 'Type',
'pattern' => 'Search string/regex',
'pattern_description' => 'If this pattern is not found on the website, the server will be marked offline. Regular expressions are allowed.',
'last_check' => '최근체크',
'last_online' => '최근접속',
'monitoring' => '확인중',
@ -108,6 +109,8 @@ $sm_lang = array(
'week' => 'Week',
'day' => 'Day',
'hour' => 'Hour',
'warning_threshold' => 'Warning threshold',
'warning_threshold_description' => 'Number of failed checks required before it is marked offline.',
),
'config' => array(
'general' => '일반',

View File

@ -96,6 +96,7 @@ $sm_lang = array(
'port' => 'Poort',
'type' => 'Type',
'pattern' => 'Zoek voor tekst/regex',
'pattern_description' => 'If this pattern is not found on the website, the server will be marked offline. Regular expressions are allowed.',
'last_check' => 'Laatst gecontroleerd',
'last_online' => 'Laatst online',
'monitoring' => 'Monitoring',
@ -108,6 +109,8 @@ $sm_lang = array(
'week' => 'Week',
'day' => 'Day',
'hour' => 'Hour',
'warning_threshold' => 'Warning threshold',
'warning_threshold_description' => 'Number of failed checks required before it is marked offline.',
),
'config' => array(
'general' => 'Algemeen',

View File

@ -66,7 +66,9 @@ abstract class AbstractServerController extends AbstractController {
`s`.`last_online`,
`s`.`active`,
`s`.`email`,
`s`.`sms`
`s`.`sms`,
`s`.`warning_threshold`,
`s`.`warning_threshold_counter`
FROM `".PSM_DB_PREFIX."servers` AS `s`
{$sql_join}
ORDER BY `active` ASC, `status` DESC, `type` ASC, `label` ASC";

View File

@ -86,6 +86,10 @@ class ServerController extends AbstractServerController {
// add link to label
$servers[$x]['ip'] = '<a href="'.$servers[$x]['ip'].'" target="_blank">'.$servers[$x]['ip'].'</a>';
}
if($servers[$x]['status'] == 'on' && $servers[$x]['warning_threshold_counter'] > 0) {
$servers[$x]['status'] = 'warning';
}
}
// add servers to template
$this->tpl->addTemplateDataRepeat($this->getTemplateId(), 'servers', $servers);
@ -108,13 +112,16 @@ class ServerController extends AbstractServerController {
$server_id = isset($_GET['id']) ? intval($_GET['id']) : 0;
$tpl_data = array();
$tpl_data = array(
'url_go_back' => psm_build_url(array('mod' => 'server')),
);
switch(intval($server_id)) {
case 0:
// insert mode
$tpl_data['titlemode'] = psm_get_lang('system', 'insert');
$tpl_data['edit_server_id'] = '0';
$tpl_data['edit_value_warning_threshold'] = '1';
break;
default:
// edit mode
@ -135,6 +142,7 @@ class ServerController extends AbstractServerController {
'edit_value_ip' => $edit_server['ip'],
'edit_value_port' => $edit_server['port'],
'edit_value_pattern' => $edit_server['pattern'],
'edit_value_warning_threshold' => $edit_server['warning_threshold'],
'edit_type_selected_' . $edit_server['type'] => 'selected="selected"',
'edit_active_selected_' . $edit_server['active'] => 'selected="selected"',
'edit_email_selected_' . $edit_server['email'] => 'selected="selected"',
@ -164,6 +172,7 @@ class ServerController extends AbstractServerController {
'port' => intval($_POST['port']),
'type' => in_array($_POST['type'], array('website', 'service')) ? $_POST['type'] : 'website',
'pattern' => $_POST['pattern'],
'warning_threshold' => intval($_POST['warning_threshold']),
'active' => in_array($_POST['active'], array('yes', 'no')) ? $_POST['active'] : 'no',
'email' => in_array($_POST['email'], array('yes', 'no')) ? $_POST['email'] : 'no',
'sms' => in_array($_POST['sms'], array('yes', 'no')) ? $_POST['sms'] : 'no',
@ -216,14 +225,18 @@ class ServerController extends AbstractServerController {
'label_port' => psm_get_lang('servers', 'port'),
'label_type' => psm_get_lang('servers', 'type'),
'label_pattern' => psm_get_lang('servers', 'pattern'),
'label_pattern_description' => psm_get_lang('servers', 'pattern_description'),
'label_last_check' => psm_get_lang('servers', 'last_check'),
'label_rtime' => psm_get_lang('servers', 'rtime'),
'label_last_online' => psm_get_lang('servers', 'last_online'),
'label_monitoring' => psm_get_lang('servers', 'monitoring'),
'label_send_email' => psm_get_lang('servers', 'send_email'),
'label_send_sms' => psm_get_lang('servers', 'send_sms'),
'label_warning_threshold' => psm_get_lang('servers', 'warning_threshold'),
'label_warning_threshold_description' => psm_get_lang('servers', 'warning_threshold_description'),
'label_action' => psm_get_lang('system', 'action'),
'label_save' => psm_get_lang('system', 'save'),
'label_go_back' => psm_get_lang('system', 'go_back'),
'label_edit' => psm_get_lang('system', 'edit') . ' ' . psm_get_lang('servers', 'server'),
'label_delete' => psm_get_lang('system', 'delete') . ' ' . psm_get_lang('servers', 'server'),
'label_yes' => psm_get_lang('system', 'yes'),

View File

@ -61,6 +61,8 @@ class StatusController extends AbstractServerController {
'offline_fg' => '#f7cece',
'online_bg' => '#53a000',
'online_fg' => '#d8f7ce',
'warning_bg' => '#FAA732',
'warning_fg' => '#F3F3B1',
'label_last_check' => psm_get_lang('servers', 'last_check'),
'label_last_online' => psm_get_lang('servers', 'last_online'),
'label_rtime' => psm_get_lang('servers', 'rtime'),
@ -76,6 +78,9 @@ class StatusController extends AbstractServerController {
if ($server['status'] == "off") {
$offline[$server['server_id']] = $server;
} elseif($server['warning_threshold_counter'] > 0) {
$server['class_warning'] = 'warning';
$offline[$server['server_id']] = $server;
} else {
$online[$server['server_id']] = $server;
}

View File

@ -167,7 +167,7 @@ class Installer {
PSM_DB_PREFIX . 'servers' => "CREATE TABLE `" . PSM_DB_PREFIX . "servers` (
`server_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`ip` varchar(100) NOT NULL,
`port` int(5) NOT NULL,
`port` int(5) unsigned NOT NULL,
`label` varchar(255) NOT NULL,
`type` enum('service','website') NOT NULL default 'service',
`pattern` varchar(255) NOT NULL,
@ -179,6 +179,8 @@ class Installer {
`active` enum('yes','no') NOT NULL default 'yes',
`email` enum('yes','no') NOT NULL default 'yes',
`sms` enum('yes','no') NOT NULL default 'no',
`warning_threshold` mediumint(1) unsigned NOT NULL DEFAULT '1',
`warning_threshold_counter` mediumint(1) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`server_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;",
PSM_DB_PREFIX . 'servers_uptime' => "CREATE TABLE IF NOT EXISTS `" . PSM_DB_PREFIX . "servers_uptime` (
@ -248,7 +250,11 @@ class Installer {
$queries = array();
$queries[] = "ALTER TABLE `" . PSM_DB_PREFIX . "log` CHANGE `log_id` `log_id` INT( 11 ) UNSIGNED NOT NULL AUTO_INCREMENT;";
$queries[] = "ALTER TABLE `" . PSM_DB_PREFIX . "log` CHANGE `server_id` `server_id` INT( 11 ) UNSIGNED NOT NULL;";
$queries[] = "ALTER TABLE `" . PSM_DB_PREFIX . "servers` CHANGE `server_id` `server_id` INT( 11 ) UNSIGNED NOT NULL AUTO_INCREMENT;";
$queries[] = "ALTER TABLE `" . PSM_DB_PREFIX . "servers` ADD `warning_threshold` MEDIUMINT( 1 ) UNSIGNED NOT NULL DEFAULT '1';";
$queries[] = "ALTER TABLE `" . PSM_DB_PREFIX . "servers` ADD `warning_threshold_counter` MEDIUMINT( 1 ) UNSIGNED NOT NULL DEFAULT '0';";
$queries[] = "ALTER TABLE `" . PSM_DB_PREFIX . "users` CHANGE `user_id` `user_id` INT( 11 ) UNSIGNED NOT NULL AUTO_INCREMENT;";
$queries[] = "ALTER TABLE `" . PSM_DB_PREFIX . "users`
ADD `user_name` varchar(64) COLLATE utf8_general_ci NOT NULL COMMENT 'user\'s name, unique' AFTER `user_id`,

40
src/psm/Util/Updater/Autorun.class.php Normal file → Executable file
View File

@ -23,7 +23,7 @@
* @license http://www.gnu.org/licenses/gpl.txt GNU GPL v3
* @version Release: @package_version@
* @link http://www.phpservermonitor.org/
* @since phpservermon 2.2.0
* @since phpservermon 2.2.0
**/
namespace psm\Util\Updater;
@ -76,42 +76,14 @@ class Autorun {
$servers = $this->db->query($sql);
$updater = new Status($this->db);
$updater = new StatusUpdater($this->db);
$notifier = new StatusNotifier($this->db);
foreach($servers as $server) {
$status_org = $server['status'];
// remove the old status from the array to avoid confusion between the new and old status
unset($server['status']);
$updater->setServer($server, $status_org);
// check server status
// it returns the new status, and performs the update check automatically.
$status_new = $updater->getStatus();
$status_old = ($server['status'] == 'on') ? true : false;
$status_new = $updater->update($server['server_id']);
// notify the nerds if applicable
$updater->notify();
// update server status
$save = array(
'last_check' => date('Y-m-d H:i:s'),
'status' => $status_new,
'error' => $updater->getError(),
'rtime' => $updater->getRtime(),
);
// if the server is on, add the last_online value
if($save['status'] == 'on') {
$save['last_online'] = date('Y-m-d H:i:s');
}
$this->db->save(
PSM_DB_PREFIX . 'servers',
$save,
array('server_id' => $server['server_id'])
);
$log_status = ($status_new == 'on') ? 1 : 0;
psm_log_uptime($server['server_id'], $log_status, $updater->getRtime());
$notifier->notify($server['server_id'], $status_old, $status_new);
}
}

View File

@ -1,389 +0,0 @@
<?php
/**
* PHP Server Monitor
* Monitor your servers and websites.
*
* This file is part of PHP Server Monitor.
* PHP Server Monitor is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PHP Server Monitor is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PHP Server Monitor. If not, see <http://www.gnu.org/licenses/>.
*
* @package phpservermon
* @author Pepijn Over <pep@neanderthal-technology.com>
* @copyright Copyright (c) 2008-2014 Pepijn Over <pep@neanderthal-technology.com>
* @license http://www.gnu.org/licenses/gpl.txt GNU GPL v3
* @version Release: @package_version@
* @link http://www.phpservermonitor.org/
**/
/**
* The status class is for checking a server and notifying if necessary.
*
* You will need to provide an array with all
* server information to the setServer() method, run update() and notify() if you want to.
* If you are looking for a check-all, see the Autorun class.
* @see \psm\Util\Updater\Autorun
*/
namespace psm\Util\Updater;
use psm\Service\Database;
class Status {
public $error;
public $notify;
public $rtime = 0;
public $server;
public $status_org = false;
public $status_new = false;
public $db;
function __construct(Database $db) {
$this->db = $db;
}
/**
* Set a new server
*
* @param array $server
* @param string $status_org either 'on' or 'off'
*/
public function setServer($server, $status_org) {
$this->clearResults();
$this->server = $server;
$this->status_org = $status_org;
}
/**
* Get the new status of the selected server. If the update has not been performed yet it will do so first
*
* @return string
*/
public function getStatus() {
if(!$this->server) {
return false;
}
if(!$this->status_new) {
$this->update();
}
return $this->status_new;
}
/**
* The function its all about. This one checks whether the given ip and port are up and running!
* If the server check fails it will try one more time
*
* @param int $max_runs how many times should the script recheck the server if unavailable. default is 2
* @return string new status
*/
public function update($max_runs = 2) {
switch($this->server['type']) {
case 'service':
$result = $this->updateService($max_runs);
break;
case 'website':
$result = $this->updateWebsite($max_runs);
break;
}
return $result;
}
protected function updateService($max_runs, $run = 1) {
// save response time
$time = explode(' ', microtime());
$starttime = $time[1] + $time[0];
@$fp = fsockopen ($this->server['ip'], $this->server['port'], $errno, $errstr, 10);
$time = explode(" ", microtime());
$endtime = $time[1] + $time[0];
$this->rtime = ($endtime - $starttime);
$this->status_new = ($fp === false) ? 'off' : 'on';
$this->error = $errstr;
// add the error to the server array for when parsing the messages
$this->server['error'] = $this->error;
@fclose($fp);
// check if server is available and rerun if asked.
if($this->status_new == 'off' && $run < $max_runs) {
return $this->updateService($max_runs, $run + 1);
}
return $this->status_new;
}
protected function updateWebsite($max_runs, $run = 1) {
// save response time
$time = explode(' ', microtime());
$starttime = $time[1] + $time[0];
// We're only interested in the header, because that should tell us plenty!
// unless we have a pattern to search for!
$curl_result = psm_curl_get(
$this->server['ip'],
true,
($this->server['pattern'] == '' ? false : true)
);
$time = explode(" ", microtime());
$endtime = $time[1] + $time[0];
$this->rtime = ($endtime - $starttime);
// the first line would be the status code..
$status_code = strtok($curl_result, "\r\n");
// keep it general
// $code[1][0] = status code
// $code[2][0] = name of status code
preg_match_all("/[A-Z]{2,5}\/\d\.\d\s(\d{3})\s(.*)/", $status_code, $code_matches);
if(empty($code_matches[0])) {
// somehow we dont have a proper response.
$this->server['error'] = $this->error = 'no response from server';
$this->status_new = 'off';
} else {
$code = $code_matches[1][0];
$msg = $code_matches[2][0];
// All status codes starting with a 4 or higher mean trouble!
if(substr($code, 0, 1) >= '4') {
$this->server['error'] = $this->error = $code . ' ' . $msg;
$this->status_new = 'off';
} else {
$this->status_new = 'on';
}
}
if($this->server['pattern'] != '') {
// Check to see if the pattern was found.
if(!preg_match("/{$this->server['pattern']}/i", $curl_result)) {
$this->server['error'] = $this->error = 'Pattern not found.';
$this->status_new = 'off';
}
}
// check if server is available and rerun if asked.
if($this->status_new == 'off' && $run < $max_runs) {
return $this->updateWebsite($max_runs, $run + 1);
}
return $this->status_new;
}
/**
* This function initializes the sending (text msg & email) and logging
*
*/
public function notify() {
if(psm_get_conf('email_status') == false && psm_get_conf('sms_status') == false && psm_get_conf('log_status') == false) {
// seems like we have nothing to do. skip the rest
return false;
}
$notify = false;
// check which type of alert the user wants
switch(psm_get_conf('alert_type')) {
case 'always':
if($this->status_new == 'off') {
// server is offline. we are in error state.
$notify = true;
}
break;
case 'offline':
// only send a notification if the server goes down for the first time!
if($this->status_new == 'off' && $this->status_org == 'on') {
$notify = true;
}
break;
case 'status':
if($this->status_new != $this->status_org) {
// status has been changed!
$notify = true;
}
break;
}
// first add to log (we use the same text as the SMS message because its short..)
if(psm_get_conf('log_status')) {
psm_add_log(
$this->server['server_id'],
'status',
psm_parse_msg($this->status_new, 'sms', $this->server)
);
}
if(!$notify) {
return false;
}
// check if email is enabled for this server
if(psm_get_conf('email_status') && $this->server['email'] == 'yes') {
// send email
$this->notifyByEmail();
}
// check if sms is enabled for this server
if(psm_get_conf('sms_status') && $this->server['sms'] == 'yes') {
// yay lets wake those nerds up!
$this->notifyByTxtMsg();
}
return true;
}
/**
* This functions performs the email notifications
*
* @return boolean
*/
protected function notifyByEmail() {
$userlist = array();
$users = $this->getUsers($this->server['server_id']);
if (empty($users)) {
return false;
}
// build mail object with some default values
$mail = psm_build_mail();
$mail->Subject = psm_parse_msg($this->status_new, 'email_subject', $this->server);
$mail->Priority = 1;
$body = psm_parse_msg($this->status_new, 'email_body', $this->server);
$mail->Body = $body;
$mail->AltBody = str_replace('<br/>', "\n", $body);
// go through empl
foreach ($users as $user) {
// we sent a seperate email to every single user.
$userlist[] = $user['user_id'];
$mail->AddAddress($user['email'], $user['name']);
$mail->Send();
$mail->ClearAddresses();
}
if(psm_get_conf('log_email')) {
// save to log
psm_add_log($this->server['server_id'], 'email', $body, implode(',', $userlist));
}
}
/**
* This functions performs the text message notifications
*
* @return unknown
*/
protected function notifyByTxtMsg() {
// send sms to all users for this server using defined gateway
$users = $this->getUsers($this->server['server_id']);
if (empty($users)) {
return false;
}
// we have to build an userlist for the log table..
$userlist = array();
// open the right class
// not making this any more dynamic, because perhaps some gateways need custom settings (like Mollie)
switch(strtolower(psm_get_conf('sms_gateway'))) {
case 'mosms':
$sms = new \psm\Txtmsg\Mosms();
break;
case 'inetworx':
$sms = new \psm\Txtmsg\Inetworx();
break;
case 'mollie':
$sms = new \psm\Txtmsg\Mollie();
$sms->setGateway(1);
break;
case 'spryng':
$sms = new \psm\Txtmsg\Spryng();
break;
case 'clickatell':
$sms = new \psm\Txtmsg\Clickatell();
break;
case 'textmarketer':
$sms = new \psm\Txtmsg\Textmarketer();
break;
}
// copy login information from the config file
$sms->setLogin(psm_get_conf('sms_gateway_username'), psm_get_conf('sms_gateway_password'));
$sms->setOriginator(psm_get_conf('sms_from'));
// add all users to the recipients list
foreach ($users as $user) {
$userlist[] = $user['user_id'];
$sms->addRecipients($user['mobile']);
}
$message = psm_parse_msg($this->status_new, 'sms', $this->server);
// Send sms
$result = $sms->sendSMS($message);
if(psm_get_conf('log_sms')) {
// save to log
psm_add_log($this->server['server_id'], 'sms', $message, implode(',', $userlist));
}
return $result;
}
/**
* Get the error returned by the update function
*
* @return string
*/
public function getError() {
return $this->error;
}
/**
* Get the response time of the server
*
* @return string
*/
public function getRtime() {
return $this->rtime;
}
/**
* Clear all the results that are left from the previous run
*
*/
protected function clearResults() {
$this->error = '';
$this->status_org = false;
$this->status_new = false;
}
/**
* Get all users for the provided server id
* @param int $server_id
* @return array
*/
public function getUsers($server_id) {
// find all the users with this server listed
$users = $this->db->query("
SELECT `u`.`user_id`, `u`.`name`,`u`.`email`, `u`.`mobile`
FROM `".PSM_DB_PREFIX."users` AS `u`
JOIN `".PSM_DB_PREFIX."users_servers` AS `us` ON (
`us`.`user_id`=`u`.`user_id`
AND `us`.`server_id` = {$server_id}
)
");
return $users;
}
}

View File

@ -0,0 +1,292 @@
<?php
/**
* PHP Server Monitor
* Monitor your servers and websites.
*
* This file is part of PHP Server Monitor.
* PHP Server Monitor is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PHP Server Monitor is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PHP Server Monitor. If not, see <http://www.gnu.org/licenses/>.
*
* @package phpservermon
* @author Pepijn Over <pep@neanderthal-technology.com>
* @copyright Copyright (c) 2008-2014 Pepijn Over <pep@neanderthal-technology.com>
* @license http://www.gnu.org/licenses/gpl.txt GNU GPL v3
* @version Release: @package_version@
* @link http://www.phpservermonitor.org/
**/
/**
* The status updater is for sending notifications to the users.
*
* @see \psm\Util\Updater\StatusUpdater
* @see \psm\Util\Updater\Autorun
*/
namespace psm\Util\Updater;
use psm\Service\Database;
class StatusNotifier {
/**
* Database service
* @var \psm\Service\Database $db
*/
protected $db;
/**
* Send emails?
* @var boolean $send_emails
*/
protected $send_emails = false;
/**
* Send sms?
* @var boolean $send_sms
*/
protected $send_sms = false;
/**
* Save log records?
* @var boolean $save_log
*/
protected $save_logs = false;
/**
* Server id
* @var int $server_id
*/
protected $server_id;
/**
* Server information
* @var array $server
*/
protected $server;
/**
* Old status
* @var boolean $status_old
*/
protected $status_old;
/**
* New status
* @var boolean $status_new
*/
protected $status_new;
function __construct(Database $db) {
$this->db = $db;
$this->send_emails = psm_get_conf('email_status');
$this->send_sms = psm_get_conf('sms_status');
$this->save_logs = psm_get_conf('log_status');
}
/**
* This function initializes the sending (text msg & email) and logging
*
* @param int $server_id
* @param boolean $status_old
* @param boolean $status_new
* @return boolean
*/
public function notify($server_id, $status_old, $status_new) {
if(!$this->send_emails && !$this->send_sms && !$this->save_logs) {
// seems like we have nothing to do. skip the rest
return false;
}
$this->server_id = $server_id;
$this->status_old = $status_old;
$this->status_new = $status_new;
// get server info from db
$this->server = $this->db->selectRow(PSM_DB_PREFIX . 'servers', array(
'server_id' => $server_id,
), array(
'server_id', 'ip', 'port', 'label', 'type', 'pattern', 'status', 'error', 'active', 'email', 'sms',
));
if(empty($this->server)) {
return false;
}
$notify = false;
// check which type of alert the user wants
switch(psm_get_conf('alert_type')) {
case 'always':
if($status_new == false) {
// server is offline. we are in error state.
$notify = true;
}
break;
case 'offline':
// only send a notification if the server goes down for the first time!
if($status_new == false && $status_old == true) {
$notify = true;
}
break;
case 'status':
if($status_new != $status_old) {
// status has been changed!
$notify = true;
}
break;
}
// first add to log (we use the same text as the SMS message because its short..)
if($this->save_logs) {
psm_add_log(
$this->server_id,
'status',
psm_parse_msg($status_new, 'sms', $this->server)
);
}
if(!$notify) {
return false;
}
// check if email is enabled for this server
if($this->send_emails && $this->server['email'] == 'yes') {
// send email
$this->notifyByEmail();
}
// check if sms is enabled for this server
if($this->send_sms && $this->server['sms'] == 'yes') {
// yay lets wake those nerds up!
$this->notifyByTxtMsg();
}
return $notify;
}
/**
* This functions performs the email notifications
*
* @return boolean
*/
protected function notifyByEmail() {
$userlist = array();
$users = $this->getUsers($this->server_id);
if (empty($users)) {
return false;
}
// build mail object with some default values
$mail = psm_build_mail();
$mail->Subject = psm_parse_msg($this->status_new, 'email_subject', $this->server);
$mail->Priority = 1;
$body = psm_parse_msg($this->status_new, 'email_body', $this->server);
$mail->Body = $body;
$mail->AltBody = str_replace('<br/>', "\n", $body);
// go through empl
foreach ($users as $user) {
// we sent a seperate email to every single user.
$userlist[] = $user['user_id'];
$mail->AddAddress($user['email'], $user['name']);
$mail->Send();
$mail->ClearAddresses();
}
if(psm_get_conf('log_email')) {
// save to log
psm_add_log($this->server_id, 'email', $body, implode(',', $userlist));
}
}
/**
* This functions performs the text message notifications
*
* @return unknown
*/
protected function notifyByTxtMsg() {
// send sms to all users for this server using defined gateway
$users = $this->getUsers($this->server_id);
if (empty($users)) {
return false;
}
// we have to build an userlist for the log table..
$userlist = array();
// open the right class
// not making this any more dynamic, because perhaps some gateways need custom settings (like Mollie)
switch(strtolower(psm_get_conf('sms_gateway'))) {
case 'mosms':
$sms = new \psm\Txtmsg\Mosms();
break;
case 'inetworx':
$sms = new \psm\Txtmsg\Inetworx();
break;
case 'mollie':
$sms = new \psm\Txtmsg\Mollie();
$sms->setGateway(1);
break;
case 'spryng':
$sms = new \psm\Txtmsg\Spryng();
break;
case 'clickatell':
$sms = new \psm\Txtmsg\Clickatell();
break;
case 'textmarketer':
$sms = new \psm\Txtmsg\Textmarketer();
break;
}
// copy login information from the config file
$sms->setLogin(psm_get_conf('sms_gateway_username'), psm_get_conf('sms_gateway_password'));
$sms->setOriginator(psm_get_conf('sms_from'));
// add all users to the recipients list
foreach ($users as $user) {
$userlist[] = $user['user_id'];
$sms->addRecipients($user['mobile']);
}
$message = psm_parse_msg($this->status_new, 'sms', $this->server);
// Send sms
$result = $sms->sendSMS($message);
if(psm_get_conf('log_sms')) {
// save to log
psm_add_log($this->server_id, 'sms', $message, implode(',', $userlist));
}
return $result;
}
/**
* Get all users for the provided server id
* @param int $server_id
* @return array
*/
public function getUsers($server_id) {
// find all the users with this server listed
$users = $this->db->query("
SELECT `u`.`user_id`, `u`.`name`,`u`.`email`, `u`.`mobile`
FROM `".PSM_DB_PREFIX."users` AS `u`
JOIN `".PSM_DB_PREFIX."users_servers` AS `us` ON (
`us`.`user_id`=`u`.`user_id`
AND `us`.`server_id` = {$server_id}
)
");
return $users;
}
}

View File

@ -0,0 +1,232 @@
<?php
/**
* PHP Server Monitor
* Monitor your servers and websites.
*
* This file is part of PHP Server Monitor.
* PHP Server Monitor is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PHP Server Monitor is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PHP Server Monitor. If not, see <http://www.gnu.org/licenses/>.
*
* @package phpservermon
* @author Pepijn Over <pep@neanderthal-technology.com>
* @copyright Copyright (c) 2008-2014 Pepijn Over <pep@neanderthal-technology.com>
* @license http://www.gnu.org/licenses/gpl.txt GNU GPL v3
* @version Release: @package_version@
* @link http://www.phpservermonitor.org/
**/
/**
* The status class is for checking the status of a server.
*
* @see \psm\Util\Updater\StatusNotifier
* @see \psm\Util\Updater\Autorun
*/
namespace psm\Util\Updater;
use psm\Service\Database;
class StatusUpdater {
public $error = '';
public $rtime = 0;
public $status_new = false;
/**
* Database service
* @var \psm\Service\Database $db
*/
protected $db;
/**
* Server id to check
* @var int $server_id
*/
protected $server_id;
/**
* Server information
* @var array $server
*/
protected $server;
function __construct(Database $db) {
$this->db = $db;
}
/**
* The function its all about. This one checks whether the given ip and port are up and running!
* If the server check fails it will try one more time, depending on the $max_runs.
*
* @param int $server_id
* @param int $max_runs how many times should the script recheck the server if unavailable. default is 2
* @return boolean TRUE if server is up, FALSE otherwise
*/
public function update($server_id, $max_runs = 2) {
$this->server_id = $server_id;
$this->error = '';
$this->rtime = '';
// get server info from db
$this->server = $this->db->selectRow(PSM_DB_PREFIX . 'servers', array(
'server_id' => $server_id,
), array(
'server_id', 'ip', 'port', 'label', 'type', 'pattern', 'status', 'active', 'warning_threshold', 'warning_threshold_counter',
));
if(empty($this->server)) {
return false;
}
switch($this->server['type']) {
case 'service':
$this->status_new = $this->updateService($max_runs);
break;
case 'website':
$this->status_new = $this->updateWebsite($max_runs);
break;
}
// update server status
$save = array(
'last_check' => date('Y-m-d H:i:s'),
'error' => $this->error,
'rtime' => $this->rtime,
);
if($this->status_new == true) {
// if the server is on, add the last_online value and reset the error threshold counter
$save['status'] = 'on';
$save['last_online'] = date('Y-m-d H:i:s');
$save['warning_threshold_counter'] = 0;
} else {
// server is offline, increase the error counter
$save['warning_threshold_counter'] = $this->server['warning_threshold_counter'] + 1;
if($save['warning_threshold_counter'] < $this->server['warning_threshold']) {
// the server is offline but the error threshold has not been met yet.
// so we are going to leave the status "on" for now while we are in a sort of warning state..
$save['status'] = 'on';
} else {
$save['status'] = 'off';
}
}
$this->db->save(PSM_DB_PREFIX . 'servers', $save, array('server_id' => $this->server_id));
psm_log_uptime($this->server_id, (int) $this->status_new, $this->rtime);
return $this->status_new;
}
/**
* Check the current server as a service
* @param int $max_runs
* @param int $run
* @return boolean
*/
protected function updateService($max_runs, $run = 1) {
$errno = 0;
// save response time
$starttime = microtime(true);
$fp = fsockopen ($this->server['ip'], $this->server['port'], $errno, $this->error, 10);
$status = ($fp === false) ? false : true;
$this->rtime = (microtime(true) - $starttime);
fclose($fp);
// check if server is available and rerun if asked.
if(!$status && $run < $max_runs) {
return $this->updateService($max_runs, $run + 1);
}
return $status;
}
/**
* Check the current server as a website
* @param int $max_runs
* @param int $run
* @return boolean
*/
protected function updateWebsite($max_runs, $run = 1) {
$starttime = microtime(true);
// We're only interested in the header, because that should tell us plenty!
// unless we have a pattern to search for!
$curl_result = psm_curl_get(
$this->server['ip'],
true,
($this->server['pattern'] == '' ? false : true)
);
$this->rtime = (microtime(true) - $starttime);
// the first line would be the status code..
$status_code = strtok($curl_result, "\r\n");
// keep it general
// $code[1][0] = status code
// $code[2][0] = name of status code
$code_matches = array();
preg_match_all("/[A-Z]{2,5}\/\d\.\d\s(\d{3})\s(.*)/", $status_code, $code_matches);
if(empty($code_matches[0])) {
// somehow we dont have a proper response.
$this->error = 'no response from server';
$result = false;
} else {
$code = $code_matches[1][0];
$msg = $code_matches[2][0];
// All status codes starting with a 4 or higher mean trouble!
if(substr($code, 0, 1) >= '4') {
$this->error = $code . ' ' . $msg;
$result = false;
} else {
$result = true;
}
}
if($this->server['pattern'] != '') {
// Check to see if the pattern was found.
if(!preg_match("/{$this->server['pattern']}/i", $curl_result)) {
$this->error = 'Pattern not found.';
$result = false;
}
}
// check if server is available and rerun if asked.
if(!$result && $run < $max_runs) {
return $this->updateWebsite($max_runs, $run + 1);
}
return $result;
}
/**
* Get the error returned by the update function
*
* @return string
*/
public function getError() {
return $this->error;
}
/**
* Get the response time of the server
*
* @return string
*/
public function getRtime() {
return $this->rtime;
}
}

View File

@ -22,6 +22,7 @@
<script type="text/javascript">
$(document).bind('ready', function(){
psm_flash_message();
psm_tooltips();
});
</script>
</head>

View File

@ -71,40 +71,40 @@
<div class="control-group">
<label class="control-label" for="label">{label_label}</label>
<div class="controls">
<input type="text" name="label" value="{edit_value_label}" maxlength="255" />
<input type="text" id="label" name="label" value="{edit_value_label}" maxlength="255" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="ip">{label_domain}</label>
<div class="controls">
<input type="text" name="ip" value="{edit_value_ip}" maxlength="100" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="label">{label_port}</label>
<div class="controls">
<input type="text" name="port" value="{edit_value_port}" maxlength="5" size="5" />
<input type="text" id="ip" name="ip" value="{edit_value_ip}" maxlength="100" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="type">{label_type}</label>
<div class="controls">
<select name="type">
<select id="type" name="type">
<option value="service" {edit_type_selected_service}>Service</option>
<option value="website" {edit_type_selected_website}>Website</option>
</select>
</div>
</div>
<div class="control-group">
<label class="control-label" for="port">{label_port}</label>
<div class="controls">
<input class="input-mini" type="text" id="port" name="port" value="{edit_value_port}" maxlength="5" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="pattern">{label_pattern}</label>
<div class="controls">
<input type="text" name="pattern" value="{edit_value_pattern}" maxlength="255" />
<input type="text" id="pattern" name="pattern" value="{edit_value_pattern}" maxlength="255" data-toggle="tooltip" title="{label_pattern_description}" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="active">{label_monitoring}</label>
<div class="controls">
<select name="active">
<select id="active" name="active">
<option value="yes" {edit_active_selected_yes}>{label_yes}</option>
<option value="no" {edit_active_selected_no}>{label_no}</option>
</select>
@ -113,7 +113,7 @@
<div class="control-group">
<label class="control-label" for="email">{label_send_email}</label>
<div class="controls">
<select name="email">
<select id="email" name="email">
<option value="yes" {edit_email_selected_yes}>{label_yes}</option>
<option value="no" {edit_email_selected_no}>{label_no}</option>
</select>
@ -122,15 +122,21 @@
<div class="control-group">
<label class="control-label" for="sms">{label_send_sms}</label>
<div class="controls">
<select name="sms">
<select id="sms" name="sms">
<option value="yes" {edit_sms_selected_yes}>{label_yes}</option>
<option value="no" {edit_sms_selected_no}>{label_no}</option>
</select>
</div>
</div>
<div class="control-group">
<label class="control-label" for="warning_threshold">{label_warning_threshold}</label>
<div class="controls">
<input class="input-mini" type="text" id="warning_threshold" name="warning_threshold" value="{edit_value_warning_threshold}" maxlength="5" data-toggle="tooltip" title="{label_warning_threshold_description}" />
</div>
</div>
<div class="form-actions">
<button class="btn btn-success" type="submit">Save</button>
<button class="btn" onclick="history.back();return false;" >Cancel</button>
<button class="btn btn-success" type="submit">{label_save}</button>
<a class="btn" href="{url_go_back}" >{label_go_back}</a>
</div>
</fieldset>
</form>

View File

@ -35,6 +35,12 @@
border: 2px solid {offline_fg};
}
.offline .entity.warning {
background: {warning_bg};
color: {warning_fg};
border: 2px solid {warning_fg};
}
.online {
margin-left: 320px;
}
@ -50,7 +56,7 @@
</style>
<div class="offline">
<!--%tpl_repeat_servers_offline-->
<div class="entity">
<div class="entity {class_warning}">
<h2>{label}</h2>
<p>{label_last_online}: {last_online_nice}</p>
<p>{label_last_check}: {last_checked_nice}</p>

3
static/css/style.css Normal file → Executable file
View File

@ -20,6 +20,9 @@ body.install{
.label-status-off{
background-color: #B94A48;
}
.label-status-warning{
background-color: #FAA732;
}
.label a{
color:#FFF;
text-decoration:none;

10
static/js/scripts.js Normal file → Executable file
View File

@ -1,11 +1,19 @@
function sm_delete(id, mod) {
var del = confirm("Are you sure you want to delete this record?");
if (del == true) {
if (del === true) {
var loc = 'index.php?action=delete&id=' + id + '&mod=' + mod;
window.location = loc;
}
}
function psm_tooltips() {
$('input[data-toggle="tooltip"]').tooltip({
'trigger':'focus',
'placement': 'right',
'container': 'body'
});
}
function trim(str) {
return str.replace(/^\s+|\s+$/g,"");
}