Source for file monitor-defs.php

Documentation is available at monitor-defs.php

  1. <?php
  2. /* ******************************************************************** */
  3. /* CATALYST PHP Source Code */
  4. /* -------------------------------------------------------------------- */
  5. /* This program is free software; you can redistribute it and/or modify */
  6. /* it under the terms of the GNU General Public License as published by */
  7. /* the Free Software Foundation; either version 2 of the License, or */
  8. /* (at your option) any later version. */
  9. /* */
  10. /* This program is distributed in the hope that it will be useful, */
  11. /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
  12. /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
  13. /* GNU General Public License for more details. */
  14. /* */
  15. /* You should have received a copy of the GNU General Public License */
  16. /* along with this program; if not, write to: */
  17. /* The Free Software Foundation, Inc., 59 Temple Place, Suite 330, */
  18. /* Boston, MA 02111-1307 USA */
  19. /* -------------------------------------------------------------------- */
  20. /* */
  21. /* Filename: monitor-defs.php */
  22. /* Author: Paul Waite */
  23. /* Description: A generic set of monitor classes to enable convenient */
  24. /* checking of systems and services. */
  25. /* */
  26. /* ******************************************************************** */
  27. /** @package monitor */
  28. include_once("datetime-defs.php");
  29. /** Lockfile manager */
  30. ("lockfile-defs.php");
  31.  
  32. // ----------------------------------------------------------------------
  33. // DEFINITIONS & CONSTANTS
  34. // Condition types..
  35.  
  36.  
  37.  
  38. /** Condition for a passed test */
  39. ("COND_OK", 0);
  40. /** Warning condition */
  41. ("COND_WARNING", 1);
  42. /** Critical error condition */
  43. ("COND_CRITICAL", 2);
  44. /** Condition is undefined */
  45. ("COND_UNKNOWN", -1);
  46. /** Aggregate: no conditions */
  47. ("COND_NONE", -2);
  48. /** Aggregate: all conditions */
  49. ("COND_ALL", -3);
  50.  
  51. /** Array of condition descriptions */
  52. = array(
  53. COND_UNKNOWN => "UNKNOWN",
  54. COND_OK => "OK",
  55. COND_WARNING => "WARNING",
  56. COND_CRITICAL => "CRITICAL"
  57. );
  58.  
  59. // ----------------------------------------------------------------------
  60. /**
  61. * A generic monitor class which is used to derive the specific classes
  62. * which deal with monitoring particular things, such as Postgres,
  63. * file space, file activity etc. Apart from a few utility methods
  64. * this is mainly a container for messages, and the current condition
  65. * level of the monitor.
  66. * @package monitor
  67. * @access private
  68. */
  69. class generic_monitor {
  70. /** Type of monitor this is */
  71.  
  72. var $type = "unspec";
  73. /** Current condition of this monitor */
  74.  
  75. var $condition = COND_UNKNOWN;
  76. /** Condition to set, on failure. */
  77.  
  78. var $fail_condition = COND_CRITICAL;
  79. /** Set of messages for email, per condition */
  80.  
  81. var $report_msgs = array();
  82. /** Set of messages for SMS, per condition */
  83.  
  84. var $smstxt_msgs = array();
  85. /** Conditions which we should ignore */
  86.  
  87. var $suppressed_conditions = array();
  88. // ....................................................................
  89. /** Define a new generic monitor object. */
  90.  
  91. function generic_monitor($type="") {
  92. global $condition_desc;
  93. if ($type != "") {
  94. $this->type = $type;
  95. }
  96. // Initialise all known messages to blank..
  97. foreach ($condition_desc as $cond => $desc) {
  98. $this->set_messages($cond, "");
  99. }
  100. }
  101. // ....................................................................
  102. /** Set the error condition messages for email and SMS.
  103. * @param integer $condition Condition messages are to be set for
  104. * @param string $report Report text if error raised
  105. * @param string $smstxt SMS txt if error raised
  106. */
  107. function set_messages($condition, $report, $smstxt="") {
  108. $this->report_msgs[$condition] = $report;
  109. $this->smstxt_msgs[$condition] = $smstxt;
  110. } // set_default_messages
  111. // ....................................................................
  112. /** Set the default error condition messages for email and SMS. We
  113. * only set these messages if there are none already set.
  114. * @param integer $condition Condition messages are to be set for
  115. * @param string $report Report text if error raised
  116. * @param string $smstxt SMS txt if error raised
  117. */
  118. function set_default_messages($condition, $report, $smstxt="") {
  119. if (!isset($this->report_msgs[$condition]) || $this->report_msgs[$condition] == "") {
  120. $this->report_msgs[$condition] = $report;
  121. }
  122. if (!isset($this->smstxt_msgs[$condition]) || $this->smstxt_msgs[$condition] == "") {
  123. $this->smstxt_msgs[$condition] = $smstxt;
  124. }
  125. } // set_default_messages
  126. // ....................................................................
  127. /** Suppress the given condition, so it won't be notified */
  128.  
  129. function suppress_condition($condition) {
  130. if (!in_array($condition, $this->suppressed_conditions)) {
  131. $this->suppressed_conditions[] = $condition;
  132. }
  133. } // suppress_condition
  134. // ....................................................................
  135. /** Append the given addendum to the end of all the messages
  136. * that are stored. Used to append dynamic values to the ends
  137. * of static message content.
  138. * @param string $addendum String to append to all monitor messages.
  139. */
  140. function all_messages_append($addendum) {
  141. $newmsgs = array();
  142. foreach ($this->report_msgs as $cond => $msg) {
  143. $newmsgs[$cond] = $msg . $addendum;
  144. }
  145. $this->report_msgs = $newmsgs;
  146. $newmsgs = array();
  147. foreach ($this->smstxt_msgs as $cond => $msg) {
  148. $newmsgs[$cond] = $msg . $addendum;
  149. }
  150. $this->smstxt_msgs = $newmsgs;
  151. } // all_messages_append
  152. // ....................................................................
  153. /** Set the monitor condition.
  154. * @param integer $condition Condition to set the monitor to.
  155. */
  156. function set_condition($condition) {
  157. $this->condition = $condition;
  158. } // set_condition
  159. // ....................................................................
  160. /** Set the monitor condition value to use for 'failed' status. This
  161. * can be set for certain monitors, such as the 'postgres_monitor' which
  162. * basically returns a boolean status of Ok/Failed. For more complex
  163. * multi-condition monitors it is not used. Allows you to be more flexible
  164. * in what gets returned.
  165. * @param integer $condition Condition to set the monitor to on failure
  166. */
  167. function set_fail_condition($condition) {
  168. $this->fail_condition = $condition;
  169. } // set_fail_condition
  170. // ....................................................................
  171. /** Return condition message for current condition
  172. * @return string The monitor message which is to be reported via email
  173. */
  174. function reportmsg() {
  175. $msg = "";
  176. if (isset($this->report_msgs[$this->condition])) {
  177. $msg = $this->report_msgs[$this->condition];
  178. }
  179. return $msg;
  180. } // reportmsg
  181. // ....................................................................
  182. /** Return the sms text message for current condition
  183. * @return string The monitor message which is to be reported via SMS
  184. */
  185. function smstxtmsg() {
  186. $msg = "";
  187. if (isset($this->smstxt_msgs[$this->condition])) {
  188. $msg = $this->smstxt_msgs[$this->condition];
  189. }
  190. return $msg;
  191. } // smstxtmsg
  192. // ....................................................................
  193. /** Make the check.
  194. * @return integer The condition level determined by the checking process.
  195. */
  196. function check() {
  197. // Return condition..
  198. return $this->condition;
  199. } // check
  200.  
  201. } // generic_monitor class
  202. // ----------------------------------------------------------------------
  203.  
  204. /**
  205. * A monitor class to exec a script/program on the OS. This allows you
  206. * to hook up an external script or program to the monitoring system
  207. * with the flexibility to determine success/failure by return value
  208. * or by comparing output with an expected (regex) pattern. The default
  209. * test is to test the output of the script/program and if it is nullstring
  210. * (''), then the check is deemed to be successful, otherwise not.
  211. * There is also a flag, in the constructor ($publish_output) which,
  212. * if true, directs the monitor to include any script output in the email
  213. * or SMS messages. This can sometimes be useful for providing extra
  214. * information in error reports.
  215. * @package monitor
  216. */
  217. class exec_monitor extends generic_monitor {
  218. var $execpath = "";
  219. var $execparms = "";
  220. var $success_value = "";
  221. var $success_regex = "";
  222. var $publish_output = false;
  223. // ....................................................................
  224. /**
  225. * Define a new exec check object.
  226. * @param string $exec Script/program to execute, including any parameters
  227. * @param string $success_regex Regex to match with the output of script/program
  228. * @param boolean $publish_output Publish script/program output in all messages
  229. */
  230. function exec_monitor($exec, $success_regex="", $publish_output=false) {
  231. $this->generic_monitor("exec");
  232. $bits = explode(" ", $exec);
  233. $this->execpath = array_shift($bits);
  234. $this->execparms = implode(" ", $bits);
  235. $this->success_regex = $success_regex;
  236. $this->publish_output = $publish_output;
  237. } // exec_monitor
  238. // ....................................................................
  239. /**
  240. * Allows you to specify a string value which, if returned as output by
  241. * the called script/program, will indicate success.
  242. * The default value for success is already nullstring, so no need to
  243. * specify it in that particular case.
  244. * @param integer $code Return value which indicates success
  245. */
  246. function set_success_value($success="") {
  247. $this->success_value = $success;
  248. } // set_success_value
  249. // ....................................................................
  250. /**
  251. * Allows you to specify a regular expression which will be applied to
  252. * the output of the executed script/program and if matched will be
  253. * taken to mean the check was successful. If specified, this takes
  254. * the place of the default behaviour of checking the return code.
  255. * @param string $regex Regular expression to match on output for success
  256. */
  257. function set_success_regex($success_regex) {
  258. $this->success_regex = $success_regex;
  259. } // set_success_regex
  260. // ....................................................................
  261. /** Make the check by executing the script/program which has been
  262. * specified. We check that this exists and is executable, and raise
  263. * warnings if not. The success/failure of the check is determined
  264. * by the settings, but is either done via return code or by returned
  265. * output matching.
  266. * @return integer Condition determined by this check
  267. */
  268. function check() {
  269. if (file_exists($this->execpath)) {
  270. if (is_executable($this->execpath)) {
  271. $prog = $this->execpath;
  272. if ($this->execparms != "") {
  273. $prog .= " $this->execparms";
  274. }
  275. // Execute it..
  276. $output = shell_exec($prog);
  277.  
  278. // Check for success or failure..
  279. if ($this->success_regex != "") {
  280. $matches = array();
  281. $success = (preg_match("/$this->success_regex/", $output, $matches) == 1);
  282. }
  283. else {
  284. $success = ($this->success_value == $output);
  285. }
  286.  
  287. if ($success === false) {
  288. $this->set_condition($this->fail_condition);
  289. $this->set_default_messages(
  290. $this->fail_condition,
  291. "$this->execpath failed",
  292. "$this->execpath FAILED"
  293. );
  294. }
  295. else {
  296. $this->set_condition(COND_OK);
  297. $this->set_default_messages(
  298. COND_OK,
  299. "$this->execpath succeeded",
  300. "$this->execpath OK"
  301. );
  302. }
  303. if ($this->publish_output && $output != "") {
  304. $this->all_messages_append( " " . $output);
  305. }
  306. }
  307. else {
  308. $this->set_condition(COND_WARNING);
  309. $this->set_default_messages(
  310. COND_WARNING,
  311. "$this->execpath not executable"
  312. );
  313. }
  314. }
  315. else {
  316. $this->set_condition(COND_WARNING);
  317. $this->set_default_messages(
  318. COND_WARNING,
  319. "$this->execpath not found"
  320. );
  321. }
  322. // Return condition..
  323. return $this->condition;
  324. } // check
  325.  
  326.  
  327.  
  328. } // exec_monitor class
  329. // ----------------------------------------------------------------------
  330.  
  331. /**
  332. * A monitor class to check when files/directories were last modified.
  333. * This is a general class which can be used to set limits on how long
  334. * a file or directory can remain un-modified before warnings and/or
  335. * errors are issued.
  336. * @package monitor
  337. */
  338. class file_monitor extends generic_monitor {
  339. // Public
  340. // Private
  341. /** Path to the file to monitor
  342. @access private */
  343. var $filepath = "";
  344. /** Seconds before warning message
  345. @access private */
  346. var $warnsecs = 0;
  347. /** Seconds before error condition
  348. @access private */
  349. var $critsecs = 0;
  350. // ....................................................................
  351. /**
  352. * Define a new file check object.
  353. * @param string $filepath Path to file or directory to check
  354. * @param integer $warnmins Minutes file can be idle before warning issued
  355. * @param integer $critmins Minutes file can be idle before critical error raised
  356. */
  357. function file_monitor($filepath, $warnmins, $critmins) {
  358. $this->generic_monitor("file");
  359. $this->filepath = $filepath;
  360. $this->warnsecs = $warnmins * 60;
  361. $this->critsecs = $critmins * 60;
  362. } // file_monitor
  363. // ....................................................................
  364. /** Make the check on the time the file was last modified and if this
  365. * is longer than this->warnsecs ago but less than this->errsecs then
  366. * issue a warning. Otherwise if it is longer than this->errsecs ago
  367. * then we issue an error message.
  368. * @return integer Condition determined by this check
  369. */
  370. function check() {
  371. clearstatcache();
  372. if (file_exists($this->filepath)) {
  373. $idlesecs = time() - filemtime($this->filepath);
  374. $hours = floor($idlesecs / 3600);
  375. $mins = floor(($idlesecs % 3600) / 60);
  376. $idletime = $hours . "hrs $mins" . "mins";
  377. if ($idlesecs >= $this->warnsecs && $idlesecs < $this->critsecs) {
  378. $this->set_condition(COND_WARNING);
  379. $this->set_default_messages(
  380. COND_WARNING,
  381. "$this->filepath idle for",
  382. "$this->filepath IDLE"
  383. );
  384. }
  385. elseif ($idlesecs > $this->critsecs) {
  386. $this->set_condition($this->fail_condition);
  387. $this->set_default_messages(
  388. $this->fail_condition,
  389. "$this->filepath idle for",
  390. "$this->filepath IDLE"
  391. );
  392. }
  393. else {
  394. $this->set_condition(COND_OK);
  395. $this->set_default_messages(
  396. COND_OK,
  397. "$this->filepath modified at",
  398. "$this->filepath MOD AT"
  399. );
  400. }
  401. $this->all_messages_append(" $idletime");
  402. }
  403. else {
  404. $this->set_condition(COND_WARNING);
  405. $this->set_default_messages(
  406. COND_WARNING,
  407. "$this->filepath not found"
  408. );
  409. }
  410. // Return condition..
  411. return $this->condition;
  412. } // check
  413.  
  414.  
  415.  
  416. } // file_monitor class
  417. // ----------------------------------------------------------------------
  418.  
  419. /**
  420. * A monitor class to check if a given process is running. This can be
  421. * achieved by consulting a pidfile, or by checking the process status
  422. * listing for the given process name (the default behaviour).
  423. * @package monitor
  424. */
  425. class process_monitor extends generic_monitor {
  426. // Public
  427. // Private
  428. /** Name of the process being monitored.
  429. @access private */
  430. var $procname = "";
  431. /** Path to the PID file containing a process ID for the running process. Leave
  432. this as nullstring to check using the $procname case-insensitively by searching the full process listing for the
  433. process name.
  434. @access private */
  435. var $pidfile = "";
  436. /** The 'ps' command to use for a specific process ID#. This allows override
  437. of the default, in cases of use on systems requiring differing path or options.
  438. @access private */
  439. var $ps_pid_cmd = "ps --no-headers -p";
  440. /** The 'ps' command to use for an 'all processes list. This allows override
  441. of the default, in cases of use on systems requiring differing path or options.
  442. @access private */
  443. var $ps_all_cmd = "ps ax";
  444. // ....................................................................
  445. /**
  446. * Defines a new process monitoring object and provides matching info.
  447. * @param string $procname Name of the process to search for using 'ps'.
  448. * @param string $pidfile Path to PID file, or nullstring if matching on $procname.
  449. * @param string $ps_all_cmd The 'ps' command to use for 'all processes' listing.
  450. * @param string $ps_pid_cmd The 'ps' command to use for a specific process.
  451. */
  452. function process_monitor($procname, $pidfile="", $ps_all_cmd="", $ps_pid_cmd="") {
  453. $this->generic_monitor("proc");
  454. $this->procname = $procname;
  455. $this->pidfile = $pidfile;
  456. if ($ps_all_cmd != "") {
  457. $this->ps_all_cmd = $ps_all_cmd;
  458. }
  459. if ($ps_pid_cmd != "") {
  460. $this->ps_pid_cmd = $ps_pid_cmd;
  461. }
  462. } // file_monitor
  463. // ....................................................................
  464. /** Make the check on the time the file was last modified and if this
  465. * is longer than this->warnsecs ago but less than this->errsecs then
  466. * issue a warning. Otherwise if it is longer than this->errsecs ago
  467. * then we issue an error message.
  468. * @return integer Condition determined by this check
  469. */
  470. function check() {
  471. if ($this->procname != "") {
  472. $ps = "";
  473. // Default is to match procname in process listing..
  474. if ($this->pidfile == "") {
  475. $ps = shell_exec("$this->ps_all_cmd");
  476. if (stristr($ps, $this->procname) === false) {
  477. $this->set_condition($this->fail_condition);
  478. $this->set_default_messages(
  479. $this->fail_condition,
  480. "Process ($this->procname) is not running.",
  481. "Proc ($this->procname) not running."
  482. );
  483. }
  484. else {
  485. $this->set_condition(COND_OK);
  486. $this->set_default_messages(
  487. COND_OK,
  488. "Process ($this->procname) is running.",
  489. "Proc ($this->procname) ok."
  490. );
  491. }
  492. }
  493. // Search for specific PIDfile & process ID..
  494. else {
  495. if (file_exists($this->pidfile)) {
  496. $pid = trim(shell_exec("cat $this->pidfile"));
  497. if ($pid != "") {
  498. $ps = shell_exec("$this->ps_pid_cmd $pid");
  499. }
  500. if ($ps == "") {
  501. $this->set_condition($this->fail_condition);
  502. $this->set_default_messages(
  503. $this->fail_condition,
  504. "Process $this->procname ($pid) is not running.",
  505. "Proc $this->procname ($pid) dead."
  506. );
  507. }
  508. else {
  509. $this->set_condition(COND_OK);
  510. $this->set_default_messages(
  511. COND_OK,
  512. "Process $this->procname ($pid) is running.",
  513. "Proc $this->procname ($pid) ok."
  514. );
  515. }
  516. }
  517. else {
  518. $this->set_condition($this->fail_condition);
  519. $this->set_default_messages(
  520. $this->fail_condition,
  521. "Process $this->procname no pidfile ($this->pidfile).",
  522. "Proc $this->procname no pidfile."
  523. );
  524. }
  525. }
  526. }
  527. // Return condition..
  528. return $this->condition;
  529. } // check
  530.  
  531.  
  532.  
  533. } // process_monitor class
  534. // ----------------------------------------------------------------------
  535.  
  536. /**
  537. * A monitor class to check if Postgres is up and about. You need to
  538. * specify a database and a user (and if required, a password) which can
  539. * be use to test-connect to Postgres. Optionally you can specify the
  540. * host and port number if connection is over TCP.
  541. * @package monitor
  542. */
  543. class postgres_monitor extends generic_monitor {
  544. // Public
  545. // Private
  546. /** Database connection resource ID
  547. @access private */
  548. var $dbid = false;
  549. /** Name of the database to connect to
  550. @access private */
  551. var $dbname = "";
  552. /** Username to connect as
  553. @access private */
  554. var $user = "";
  555. /** Password of username to connect as
  556. @access private */
  557. var $password = "";
  558. /** For TCP connections: hostname to connect to
  559. @access private */
  560. var $host = "";
  561. /** For TCP connections: port to connect to
  562. @access private */
  563. var $port = "";
  564. // ....................................................................
  565. /**
  566. * Define a new Postgres monitor object.
  567. * @param string $dbname Name of the Postgres database
  568. * @param string $user Username to connect as
  569. * @param string $password User password, if required
  570. * @param string $host Hostname for TCP connections
  571. * @param string $port Port number for TCP connections
  572. */
  573. function postgres_monitor($dbname, $user, $password="", $host="", $port="") {
  574. $this->generic_monitor("postgres");
  575. $this->dbname = $dbname;
  576. $this->user = $user;
  577. $this->password = $password;
  578. $this->host = $host;
  579. $this->port = $port;
  580. } // postgres_monitor
  581. // ....................................................................
  582. /** Make the check, as to whether we can connect to the Postgres DB.
  583. * If not then return false, else return true.
  584. * @return boolean True if Postgres could be connected to.
  585. */
  586. function check() {
  587. if ($this->connect()) {
  588. $this->disconnect();
  589. $this->set_condition(COND_OK);
  590. $this->set_default_messages(
  591. COND_OK,
  592. "Postgres ($this->dbname) connection success.",
  593. "POSTGRES ($this->dbname) OK"
  594. );
  595. }
  596. else {
  597. $this->set_condition($this->fail_condition);
  598. $this->set_default_messages(
  599. $this->fail_condition,
  600. "Postgres ($this->dbname) connection failed.",
  601. "POSTGRES ($this->dbname) FAILED"
  602. );
  603. }
  604. // Return condition..
  605. return $this->condition;
  606. } // check
  607. // ....................................................................
  608. /** Connect to the DB. If we succeed, return true, else false.
  609. * @access private
  610. */
  611. function connect() {
  612. $connstr = "";
  613. if ($this->host != "") $connstr .= " host=" . $this->host;
  614. if ($this->port != 0 ) $connstr .= " port=" . $this->port;
  615. $connstr .= " dbname=" . $this->dbname;
  616. $connstr .= " user=" . $this->user;
  617. if ($this->password != "") $connstr .= " password=" . $this->password;
  618. $connstr = trim($connstr);
  619. $this->dbid = pg_connect("$connstr");
  620. return ($this->dbid !== false);
  621. } // connect
  622. // ....................................................................
  623. /** Disconnect from the DB.
  624. * @access private
  625. */
  626. function disconnect() {
  627. if ($this->dbid !== false) {
  628. pg_close($this->dbid);
  629. $this->dbid = false;
  630. }
  631. } // diconnect
  632.  
  633. } // postgres_monitor class
  634. // ----------------------------------------------------------------------
  635.  
  636. /** A monitor class to check if the search engine is up and about
  637. * @package monitor
  638. */
  639. class searchengine_monitor extends generic_monitor {
  640. // Public
  641. // Private
  642. /** The search engine search object
  643. @access private */
  644. var $searcher;
  645. /** Expected no. of hits
  646. @access private */
  647. var $hits = 0;
  648. /** Search engine host
  649. @access private */
  650. var $host = "";
  651. /** Search engine port
  652. @access private */
  653. var $port = "";
  654. /** Search engine host abbreviation
  655. @access private */
  656. var $host_abbrev = "";
  657. // ....................................................................
  658. /**
  659. * Define a new Search Engine monitor object. We register the query to use
  660. * and the number of hits we expect. You can also specify the hostname
  661. * and port of the Search server here, although Axyl users can leave these
  662. * out (blank) if they have configured them with setup-system.php.
  663. * @param string $searcher Search object, ready to execute
  664. * @param integer $hits No of results expected back from search
  665. * @param string $host Hostname of the server
  666. * @param string $port Port number of the server
  667. */
  668. function searchengine_monitor($searcher, $hits, $host="", $port="") {
  669. $this->generic_monitor("searchengine");
  670. $this->searcher = $searcher;
  671. $this->hits = $hits;
  672. // Retreive Axyl search engine connection information if available..
  673. if ($host == "" && class_exists("configuration")) {
  674. $config = new configuration("sys_control");
  675. $host = $config->value("Search Engine Host");
  676. $port = $config->value("Search Engine Port");
  677. }
  678. $this->host = $host;
  679. $this->port = $port;
  680. // Abbreviated version of hostname for messages..
  681. $bits = explode(".", $this->host);
  682. $this->host_abbrev = $bits[0];
  683. } // searchengine_monitor
  684. // ....................................................................
  685. /** Make the check on Lucene by firing the query off and checking for
  686. * the expected number of hits coming back.
  687. * @return boolean True if Lucene delivered correct number of hits.
  688. */
  689. function check() {
  690. $res = false;
  691. if (is_object($this->searcher) && method_exists($this->searcher, "execute")) {
  692. $this->searcher->execute();
  693. // VALID RESPONSE..
  694. if ($this->searcher->response->valid) {
  695. if ($this->searcher->hitcount() == $this->hits) {
  696. $res = true;
  697. $this->set_condition(COND_OK);
  698. $this->set_default_messages(
  699. COND_OK,
  700. "Search Engine ($this->host_abbrev:$this->port) hits: " . $this->searcher->hitcount() . "/" . $this->hits,
  701. "SRCH ENG $this->host_abbrev HITS: " . $this->searcher->hitcount() . "/" . $this->hits
  702. );
  703. }
  704. else {
  705. $this->set_condition($this->fail_condition);
  706. $this->set_default_messages(
  707. $this->fail_condition,
  708. "Search Engine ($this->luhost_abbrev:$this->luport) hits: " . $this->lusearch->hitcount() . "/" . $this->luhits,
  709. "SRCH ENG $this->host_abbrev HITS: " . $this->searcher->hitcount() . "/" . $this->hits
  710. );
  711. }
  712. }
  713. // INVALID RESPONSES..
  714. else {
  715. if ($this->searcher->response->error_message != "") {
  716. $this->set_condition($this->fail_condition);
  717. $this->set_default_messages(
  718. $this->fail_condition,
  719. "Search Engine ($this->host_abbrev:$this->port) error: " . $this->searcher->response->error_message,
  720. "SRCH ENG $this->host_abbrev ERROR: " . $this->searcher->response->error_message
  721. );
  722. }
  723. else {
  724. $this->set_condition($this->fail_condition);
  725. $this->set_default_messages(
  726. $this->fail_condition,
  727. "Search Engine ($this->host_abbrev:$this->port) failed. Search engine/network problems?",
  728. "SRCH ENG $this->host_abbrev UNKNOWN FAILURE."
  729. );
  730. }
  731. }
  732. }
  733. // Return condition..
  734. return $this->condition;
  735. } // check
  736.  
  737. } // searchengine_monitor class
  738. // ----------------------------------------------------------------------
  739.  
  740. /**
  741. * Class which checks for a disk free space condition.
  742. * @package monitor
  743. */
  744. class diskspace_monitor extends generic_monitor {
  745. // Public
  746. // Private
  747. /** Directory to check
  748. @access private */
  749. var $fsdir = "";
  750. /** Threshold (bytes) before warning condition
  751. @access private */
  752. var $warnspace = 0;
  753. /** Threshold (bytes) before error condition
  754. @access private */
  755. var $minspace = 0;
  756. // ....................................................................
  757. /**
  758. * @param integer $fsdir A directory on the filesystem to check
  759. * @param integer $warnspace The threshold to warn of low space (bytes)
  760. * @param integer $minspace The threshold for critical errors (bytes)
  761. */
  762. function diskspace_monitor($fsdir, $warnspace, $minspace) {
  763. $this->generic_monitor("diskspace");
  764. $this->fsdir = $fsdir;
  765. $this->warnspace = $warnspace;
  766. $this->minspace = $minspace;
  767. }
  768. // ....................................................................
  769. /**
  770. * Check the space on the filesystem of the directory specified.
  771. * @return object The report generated by the checking process.
  772. */
  773. function check() {
  774. if (file_exists($this->fsdir)) {
  775. $df = disk_free_space($this->fsdir);
  776. $MB = floor($df / MEGABYTE) . "MB";
  777. if ($df < $this->warnspace) {
  778. $this->set_condition(COND_WARNING);
  779. $this->set_default_messages(
  780. COND_WARNING,
  781. "Filesystem of $this->fsdir low on space",
  782. "FILESYS OF $this->fsdir LOW"
  783. );
  784. }
  785. elseif ($df < $this->minspace) {
  786. $this->set_condition($this->fail_condition);
  787. $this->set_default_messages(
  788. $this->fail_condition,
  789. "Filesystem of $this->fsdir critical!",
  790. "FILESYS OF $this->fsdir CRIT!"
  791. );
  792. }
  793. else {
  794. $this->set_condition(COND_OK);
  795. $this->set_default_messages(
  796. COND_OK,
  797. "Filesystem of $this->fsdir ok",
  798. "FILESYS OF $this->fsdir OK"
  799. );
  800. }
  801. $this->all_messages_append(" $MB");
  802. }
  803. else {
  804. $this->set_condition(COND_WARNING);
  805. $this->set_default_messages(
  806. COND_WARNING,
  807. "$this->fsdir not found.",
  808. "$this->fsdir NOT FOUND"
  809. );
  810. }
  811. // Return condition..
  812. return $this->condition;
  813. } // check
  814.  
  815. } // diskspace_monitor class
  816. // ----------------------------------------------------------------------
  817.  
  818. /** The monitor class. This is the entity which contains the details
  819. * of what is to be monitored, how it is to be monitored and what to
  820. * do if a given condition arises.
  821. * @package monitor
  822. */
  823. class monitor {
  824. // Public
  825. /** The name of this monitor instance */
  826.  
  827. var $name = "";
  828. /** Address to email monitor messages */
  829.  
  830. var $emailto = "";
  831. /** Address monitor messages come from */
  832.  
  833. var $emailfrom = "";
  834. /** Address to email SMS txt messages */
  835.  
  836. var $emailpager = "";
  837. /** Whether to emit a status message to stdout. If true the monitor will
  838. * emit the current status, plus the message associated with the highest
  839. * priority (most severe) condition in the monitor. Format will be:
  840. * 'CRITICAL: some message goes here'. */
  841.  
  842. var $emit_status = false;
  843. /** Monitor lockfile path */
  844.  
  845. var $lockfilepath = "";
  846.  
  847. // Private
  848. /** Local hostname we are running monitor on
  849. @access private */
  850. var $hostname = "";
  851. /** Whether to use a lockfile
  852. @access private */
  853. var $use_lockfile = true;
  854. /** Monitor lockfile object
  855. @access private */
  856. var $lockfile;
  857. /** True if we are locked via lockfile
  858. @access private */
  859. var $locked = false;
  860. /** Monitor highest priority condition
  861. @access private */
  862. var $condition = COND_OK;
  863. /** Monitor highest priority message */
  864.  
  865. var $message = "";
  866. /** Report staging for email
  867. @access private */
  868. var $reportmsg = "";
  869. /** Report staging for SMS txt
  870. @access private */
  871. var $smstxtmsg = "";
  872. /** Threshold condition for emailing
  873. @access private */
  874. var $email_condition_threshold = COND_WARNING;
  875. /** Threshold condition for paging
  876. @access private */
  877. var $pager_condition_threshold = COND_CRITICAL;
  878. /** The current Unix timestamp
  879. @access private */
  880. var $tinow;
  881. /** Condition to stop on. If this condition is defined then we
  882. stop checking monitors the first time it is raised.
  883. @access private */
  884. var $stop_on_condition = COND_NONE;
  885. /** Schedule of named timeslots for this monitor
  886. @access private */
  887. var $schedule;
  888. /** Array of monitors which do the work
  889. @access private */
  890. var $monitors = array();
  891. // ....................................................................
  892. /**
  893. * Create a new monitor object. This is the container for all of the
  894. * monitors which you can define and use to monitor a complete system.
  895. * @param string $name Name of this monitor instance (message prefix)
  896. * @param string $emailto Email address to send monitor messages to
  897. * @param string $emailfrom Email from-address for monitor messages
  898. * @param string $emailpager Email address for pager TXT messages
  899. * @param string $lockfilepath Path to lockfile (optional)
  900. */
  901. function monitor($name="", $emailto="", $emailfrom="", $emailpager="", $lockfilepath="") {
  902. // Determine hostname..
  903. $returnlines = "";
  904. exec("hostname", $returnlines);
  905. if (isset($returnlines[0]) && $returnlines[0] != "") {
  906. $this->hostname = $returnlines[0];
  907. }
  908.  
  909. // Deal with parameters..
  910. if ($name == "") {
  911. $name = "Monitor";
  912. }
  913. if ($emailto == "") {
  914. if (defined("WEBMASTER_EMAIL")) {
  915. $emailto = WEBMASTER_EMAIL;
  916. if (defined("APP_NAME")) {
  917. $emailto = "\"" . APP_NAME . "\" <$emailto>";
  918. }
  919. }
  920. }
  921. if ($emailfrom == "") {
  922. if (defined("WEBMASTER_EMAIL")) {
  923. $emailfrom = WEBMASTER_EMAIL;
  924. if (defined("APP_NAME")) {
  925. $emailfrom = "\"" . APP_NAME . "\" <$emailfrom>";
  926. }
  927. }
  928. }
  929.  
  930. // Set lockfile path. We also interpret the value 'nolockfile'
  931. // for this parameter as disabling the locking feature..
  932. if ($lockfilepath == "") {
  933. $lockfilepath = str_replace(" ", "_", $name);
  934. if ($lockfilepath == "") {
  935. $lockfilepath = "monitor";
  936. if ( defined("APP_PREFIX")) {
  937. $lockfilepath .= "_" . APP_PREFIX;
  938. }
  939. }
  940. $lockfilepath .= ".LCK";
  941. }
  942. elseif ($lockfilepath == "nolockfile") {
  943. $this->use_lockfile = false;
  944. }
  945.  
  946. // Store all the parameters..
  947. $this->name = $name;
  948. $this->lockfilepath = $lockfilepath;
  949. $this->emailto = $emailto;
  950. $this->emailfrom = $emailfrom;
  951. $this->emailpager = $emailpager;
  952.  
  953. // Other settings..
  954. $this->tinow = time();
  955. $this->schedule = new schedule();
  956. } // monitor
  957. // ....................................................................
  958. /** Clear all the monitors. */
  959.  
  960. function clear() {
  961. $this->monitors = array();
  962. $this->reportmsg = "";
  963. $this->smstxtmsg = "";
  964. $this->condition = COND_OK;
  965. $this->message = "";
  966. } // clear
  967. // ....................................................................
  968. /** Control the emission of status and status message associated with
  969. * the most sever monitor error. The monitor defaults to not doing this
  970. * so you should call this method without parameters to turn it on.
  971. * @param boolean $mode If true then turn on status emission mode.
  972. */
  973. function set_emit_status($mode=true) {
  974. $this->emit_status = $mode;
  975. } // set_emit_status
  976. // ....................................................................
  977. /**
  978. * Lock the monitor. This is a private method which tries to lock the
  979. * monitor using the lockfile assigned to it.
  980. * @return boolean True if lock was obtained.
  981. * @access private
  982. */
  983. function lock() {
  984. global $_ENV;
  985. $LCK = new lockfile($this->lockfilepath);
  986. $LCK->set_timelimits(5, 15);
  987. if ($LCK->create()) {
  988. $this->locked = true;
  989. $this->lockfile = $LCK;
  990. }
  991. else {
  992. $lockmon = new generic_monitor();
  993. switch ($LCK->errorcode) {
  994. case LCK_E_CREFAIL:
  995. case LCK_E_FROZEN:
  996. case LCK_E_READFAIL:
  997. $lockmon->set_condition(COND_CRITICAL);
  998. $lockmon->set_default_messages(
  999. COND_CRITICAL,
  1000. $LCK->errormsg(),
  1001. $LCK->errormsg()
  1002. );
  1003. $this->raise_condition($lockmon);
  1004. break;
  1005. case LCK_E_KILLED:
  1006. case LCK_E_KILLED9:
  1007. case LCK_E_IMMORTAL:
  1008. case LCK_E_ORPHAN:
  1009. $lockmon->set_condition(COND_WARNING);
  1010. $lockmon->set_default_messages(
  1011. COND_WARNING,
  1012. $LCK->errormsg(),
  1013. $LCK->errormsg()
  1014. );
  1015. $this->raise_condition($lockmon);
  1016. break;
  1017. }
  1018. }
  1019. return $this->locked;
  1020. } // lock
  1021. // ....................................................................
  1022. /**
  1023. * Unlock the monitor. This is a private method which deletes the
  1024. * lockfile which was being used to block multiple instances.
  1025. * @access private
  1026. */
  1027. function unlock() {
  1028. $res = true;
  1029. if ($this->locked) {
  1030. if ($this->lockfile->remove()) {
  1031. $this->locked = false;
  1032. }
  1033. }
  1034. return $res;
  1035. } // unlock
  1036. // ....................................................................
  1037. /**
  1038. * Sets the threshold at which we will send messages to email & pager.
  1039. * Any conditions equal or worse than the threshold will be sent if
  1040. * the message is not nullstring.
  1041. * @param integer $email_cond Conditions >= this will be reported via email
  1042. * @param integer $pager_cond Conditions >= this will be reported via pager
  1043. */
  1044. function set_condition_thresholds($email_cond, $pager_cond) {
  1045. $this->email_condition_threshold = $email_cond;
  1046. $this->pager_condition_threshold = $pager_cond;
  1047. }
  1048. // ....................................................................
  1049. /** Set the condition to stop checking monitor on. If this is set to something
  1050. * other than COND_NONE, then the first time a monitor is raised to this
  1051. * condition the checking process is stopped.
  1052. * @param int $cond Condition to stop the checking process on.
  1053. */
  1054. function set_stop_on_condition($cond) {
  1055. $this->stop_on_condition = $cond;
  1056. } // set_stop_on_condition
  1057. // ....................................................................
  1058. /**
  1059. * Raise a condition. The single parameter to this method is a monitor
  1060. * object which will have had its check() method called. This contains the
  1061. * resulting condition and any messages to notify.
  1062. * @param object $monitor Monitor object which has had its check() method run
  1063. */
  1064. function raise_condition($monitor) {
  1065. global $condition_desc;
  1066.  
  1067. // Set overall condition, if escalated..
  1068. if ($monitor->condition > $this->condition) {
  1069. $this->condition = $monitor->condition;
  1070. $this->message = $monitor->reportmsg();
  1071. }
  1072.  
  1073. // Report content..
  1074. if ($monitor->reportmsg() != ""
  1075. && $monitor->condition >= $this->email_condition_threshold) {
  1076. $this->reportmsg .= "\r\n" . $condition_desc[$monitor->condition] . ": " . $monitor->reportmsg() . "\r\n";
  1077. }
  1078.  
  1079. // SMS message content..
  1080. if ($monitor->smstxtmsg() != ""
  1081. && $monitor->condition >= $this->pager_condition_threshold) {
  1082. if ($this->smstxtmsg != "") $this->smstxtmsg .= " ";
  1083. $this->smstxtmsg .= $monitor->smstxtmsg();
  1084. }
  1085. } // raise_condition
  1086. // ....................................................................
  1087. /** Method to send notification(s).. */
  1088.  
  1089. function notify() {
  1090. global $condition_desc;
  1091.  
  1092. // Send to mailbox if above email threshold, and we have someone to
  1093. // email to, and we have something to say..
  1094. if ($this->condition >= $this->email_condition_threshold
  1095. && $this->emailto != ""
  1096. && $this->reportmsg != "") {
  1097. $subject = "$this->name ($this->hostname): Monitor Status: " . $condition_desc[$this->condition];
  1098. $headers = "From: $this->emailfrom\n";
  1099. $headers .= "Reply-To: $this->emailfrom\n";
  1100. $headers .= "Errors-To: $this->emailfrom\n";
  1101. $headers .= "Content-Type: text/plain\n";
  1102. $headers .= "X-Mailer: PHP/" . phpversion();
  1103. mail($this->emailto, $subject, $this->reportmsg, $headers);
  1104. }
  1105.  
  1106. // Send to pager if above pager threshold, and we have someone to
  1107. // email-page, and we have something to TXT..
  1108. if ($this->condition >= $this->pager_condition_threshold
  1109. && $this->emailpager != ""
  1110. && $this->smstxtmsg != "") {
  1111. $subject = "$this->name ($this->hostname): " . $condition_desc[$this->condition];
  1112. $headers = "From: $this->emailfrom\n";
  1113. mail($this->emailpager, $subject, $this->smstxtmsg, $headers);
  1114. }
  1115. } // notify
  1116. // ....................................................................
  1117. /** Iterate through all our monitors, checking in each case. Each
  1118. * monitor will implement its own kind of checking and set its condition afterward.
  1119. * We also check to see if we have to abort monitor checking on a given monitor condition.
  1120. */
  1121. function check_all_monitors() {
  1122. // Iterate through our monitors..
  1123. foreach ($this->monitors as $mon) {
  1124. $mon->check();
  1125. if (!in_array($mon->condition, $mon->suppressed_conditions)) {
  1126. $this->raise_condition( $mon );
  1127. if ($this->stop_on_condition != COND_NONE && $mon->condition == $this->stop_on_condition) {
  1128. break;
  1129. }
  1130. }
  1131. }
  1132. } // check_all_monitors
  1133. // ....................................................................
  1134. /**
  1135. * Check all monitors. Just iterate through them and raise the conditions
  1136. * contained in the reports each one returns. After collecting the
  1137. * details, we notify anyone which needs to know. If any condition
  1138. * returned from a check is CRITICAL, then the rule is we stop processing
  1139. * any further checks. Processing is done in order of definition of the
  1140. * monitors added, so put your critical ones first.
  1141. * NOTE: This method always performs a lock() before processing all the
  1142. * monitors, then performs an unlock() at the end.
  1143. */
  1144. function check() {
  1145. global $condition_desc;
  1146. // Process if we are not in a 'skip' timeslot..
  1147. $timeslot = $this->schedule->timeslot($this->tinow);
  1148. switch ($timeslot) {
  1149. case "skip":
  1150. return RET_OK;
  1151. break;
  1152. case "warnings":
  1153. $this->set_condition_thresholds(COND_WARN, COND_WARN);
  1154. break;
  1155. case "critical":
  1156. $this->set_condition_thresholds(COND_CRITICAL, COND_CRITICAL);
  1157. break;
  1158. case "verbose":
  1159. $this->set_condition_thresholds(COND_ALL, COND_CRITICAL);
  1160. break;
  1161. case "testing":
  1162. $this->set_condition_thresholds(COND_ALL, COND_ALL);
  1163. break;
  1164. } // switch
  1165.  
  1166. // Lock the monitor, if we are using a lockfile. If this
  1167. // fails then it is regarded as a critical error..
  1168. if ($this->use_lockfile) {
  1169. if ($this->lock()) {
  1170. $this->check_all_monitors();
  1171. // Unlock monitor now..
  1172. $this->unlock();
  1173. }
  1174. else {
  1175. // Lock failed, notify them & die..
  1176. $this->notify();
  1177. }
  1178. }
  1179. // If no lockfile, just do it..
  1180. else {
  1181. $this->check_all_monitors();
  1182. }
  1183.  
  1184. // Notify people who want it..
  1185. $this->notify();
  1186.  
  1187. // Emit stuff if we have been asked to..
  1188. if ($this->emit_status) {
  1189. echo $condition_desc[$this->condition] . ": $this->message";
  1190. }
  1191.  
  1192. // Provide return code for caller..
  1193. return $this->condition;
  1194. } // check
  1195. // ....................................................................
  1196. /**
  1197. * Add a time slot to the schedule. This requires two times as per 24hr
  1198. * clock which define a time interval during the day, and gives it a
  1199. * name. You can define any number of these. Timeslots have to be in HH:MM
  1200. * format, separated by a dash "-", eg: '07:30-11:45'.
  1201. * @param mixed $start Start time for timeslot, string datetime or Unix timestamp
  1202. * @param mixed $end End time for timeslot, string datetime or Unix timestamp
  1203. * @param string $name The name or ID associated with this timeslot.
  1204. */
  1205. function add_timeslot($start, $end, $name) {
  1206. $this->schedule->add_timeslot($start, $end, $name);
  1207. } // add_timeslot
  1208. // ....................................................................
  1209. /**
  1210. * Add a new monitor. Eg. file_monitor, postgres_monitor etc. This just
  1211. * stuffs the object in an array ready to be checked.
  1212. * @param object $monitor New monitor object to add to our list
  1213. */
  1214. function add_monitor($monitor) {
  1215. $this->monitors[] = $monitor;
  1216. } // add_monitor
  1217.  
  1218. } // monitor class
  1219. // ----------------------------------------------------------------------
  1220.  
  1221. ?>

Documentation generated by phpDocumentor 1.3.0RC3