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

Documentation generated by phpDocumentor 1.3.0RC3