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

Documentation generated by phpDocumentor 1.3.0RC3