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

Documentation generated by phpDocumentor 1.3.0RC3