From 81c7f2ba27c1d36d35d8020bad198f22ccd2f0df Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Fri, 20 Nov 2015 12:01:21 +1300 Subject: [PATCH 1/2] Optionally log check failures Gives more granular control over monitoring failures --- code/EnvironmentCheckSuite.php | 8 +++ code/EnvironmentChecker.php | 43 +++++++++++++++ composer.json | 4 ++ readme.md | 24 +++++++++ tests/EnvironmentCheckerTest.php | 89 ++++++++++++++++++++++++++++++++ 5 files changed, 168 insertions(+) create mode 100644 tests/EnvironmentCheckerTest.php diff --git a/code/EnvironmentCheckSuite.php b/code/EnvironmentCheckSuite.php index a3e6968..641febd 100644 --- a/code/EnvironmentCheckSuite.php +++ b/code/EnvironmentCheckSuite.php @@ -173,6 +173,13 @@ class EnvironmentCheckSuite extends Object { if(!is_array($names)) $names = array($names); foreach($names as $name) self::inst($name)->push($check, $title); } + + /** + * Unregisters all checks. + */ + static function reset() { + self::$instances = array(); + } } /** @@ -203,6 +210,7 @@ class EnvironmentCheckSuiteResult extends ViewableData { $this->details->push(new ArrayData(array( 'Check' => $checkIdentifier, 'Status' => $this->statusText($status), + 'StatusCode' => $status, 'Message' => $message, ))); diff --git a/code/EnvironmentChecker.php b/code/EnvironmentChecker.php index 0f90108..a6eb6d5 100644 --- a/code/EnvironmentChecker.php +++ b/code/EnvironmentChecker.php @@ -41,6 +41,26 @@ class EnvironmentChecker extends RequestHandler { */ public static $email_results = false; + /** + * @var bool Log results via {@link SS_Log} + */ + private static $log_results_warning = false; + + /** + * @var int Maps to {@link Zend_Log} levels. Defaults to Zend_Log::WARN + */ + private static $log_results_warning_level = 4; + + /** + * @var bool Log results via {@link SS_Log} + */ + private static $log_results_error = false; + + /** + * @var int Maps to {@link Zend_Log} levels. Defaults to Zend_Log::ALERT + */ + private static $log_results_error_level = 1; + /** * @param string $checkSuiteName * @param string $title @@ -151,6 +171,21 @@ class EnvironmentChecker extends RequestHandler { $email->send(); } + // Optionally log errors and warnings individually + foreach($result->Details() as $detail) { + if($this->config()->log_results_warning && $detail->StatusCode == EnvironmentCheck::WARNING) { + $this->log( + sprintf('EnvironmentChecker warning at "%s" check. Message: %s', $detail->Check, $detail->Message), + $this->config()->log_results_warning_level + ); + } elseif($this->config()->log_results_error && $detail->StatusCode == EnvironmentCheck::ERROR) { + $this->log( + sprintf('EnvironmentChecker error at "%s" check. Message: %s', $detail->Check, $detail->Message), + $this->config()->log_results_error_level + ); + } + } + // output the result as JSON if requested if( $this->getRequest()->getExtension() == 'json' @@ -166,6 +201,14 @@ class EnvironmentChecker extends RequestHandler { return $response; } + /** + * @param string $message + * @param int $level + */ + public function log($message, $level) { + SS_Log::log($message, $level); + } + /** * Set the HTTP status code that should be returned when there's an error. * diff --git a/composer.json b/composer.json index e1cd044..c8fc288 100644 --- a/composer.json +++ b/composer.json @@ -17,6 +17,10 @@ { "silverstripe/framework": "~3.1" }, + "require-dev": + { + "hafriedlander/phockito": "dev-master" + }, "extra": { "branch-alias": { "dev-master": "1.1.x-dev" diff --git a/readme.md b/readme.md index af1b8e6..7f6c487 100644 --- a/readme.md +++ b/readme.md @@ -83,6 +83,30 @@ EnvironmentCheckSuite: * `SMTPConnectCheck`: Checks if the SMTP connection configured through PHP.ini works as expected. * `SolrIndexCheck`: Checks if the Solr cores of given class are available. +## Monitoring Checks + +Checks will return an appropriate HTTP status code, so are easy to hook into common uptime montoring +solutions like pingdom.com. + +You can also have the environment checker email results with the following configuration: + +```yml +EnvironmentChecker: + email_results: true + to_email_address: support@test.com + from_email_address: admin@test.com +``` + +Errors can be logged via the standard SilverStripe logging. Each check will cause an individual log entry. +You can choose to enable logging separately for warnings and errors, +identified through the result of `EnvironmentCheck->check()`. + +```yml +EnvironmentChecker: + log_results_warning: true + log_results_error: true +``` + ## Authentication By default, accessing the `dev/check` URL will not require authentication on CLI and dev environments, but if you're diff --git a/tests/EnvironmentCheckerTest.php b/tests/EnvironmentCheckerTest.php new file mode 100644 index 0000000..2fac2ed --- /dev/null +++ b/tests/EnvironmentCheckerTest.php @@ -0,0 +1,89 @@ +update('EnvironmentChecker', 'log_results_warning', true); + Config::inst()->update('EnvironmentChecker', 'log_results_error', true); + EnvironmentCheckSuite::register('test suite', new EnvironmentCheckerTest_CheckNoErrors()); + $checker = Phockito::spy( + 'EnvironmentChecker', + 'test suite', + 'test' + ); + + $response = $checker->index(); + Phockito::verify($checker, 0)->log(anything(), anything()); + EnvironmentCheckSuite::reset(); + } + + public function testLogsWithWarnings() { + Config::inst()->update('EnvironmentChecker', 'log_results_warning', true); + Config::inst()->update('EnvironmentChecker', 'log_results_error', false); + EnvironmentCheckSuite::register('test suite', new EnvironmentCheckerTest_CheckWarnings()); + EnvironmentCheckSuite::register('test suite', new EnvironmentCheckerTest_CheckErrors()); + $checker = Phockito::spy( + 'EnvironmentChecker', + 'test suite', + 'test' + ); + + $response = $checker->index(); + Phockito::verify($checker, 1)->log(containsString('warning'), anything()); + Phockito::verify($checker, 0)->log(containsString('error'), anything()); + EnvironmentCheckSuite::reset(); + } + + public function testLogsWithErrors() { + Config::inst()->update('EnvironmentChecker', 'log_results_error', false); + Config::inst()->update('EnvironmentChecker', 'log_results_error', true); + EnvironmentCheckSuite::register('test suite', new EnvironmentCheckerTest_CheckWarnings()); + EnvironmentCheckSuite::register('test suite', new EnvironmentCheckerTest_CheckErrors()); + $checker = Phockito::spy( + 'EnvironmentChecker', + 'test suite', + 'test' + ); + + $response = $checker->index(); + Phockito::verify($checker, 0)->log(containsString('warning'), anything()); + Phockito::verify($checker, 1)->log(containsString('error'), anything()); + EnvironmentCheckSuite::reset(); + } + +} + +class EnvironmentCheckerTest_CheckNoErrors implements EnvironmentCheck, TestOnly{ + public function check() { + return array(EnvironmentCheck::OK, ''); + } +} + +class EnvironmentCheckerTest_CheckWarnings implements EnvironmentCheck, TestOnly{ + public function check() { + return array(EnvironmentCheck::WARNING, "test warning"); + } +} + +class EnvironmentCheckerTest_CheckErrors implements EnvironmentCheck, TestOnly{ + public function check() { + return array(EnvironmentCheck::ERROR, "test error"); + } +} \ No newline at end of file From ea047df63d414d482e3c80153c38ee352d498149 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Fri, 20 Nov 2015 12:07:07 +1300 Subject: [PATCH 2/2] Use config API --- code/EnvironmentChecker.php | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/code/EnvironmentChecker.php b/code/EnvironmentChecker.php index a6eb6d5..19e519c 100644 --- a/code/EnvironmentChecker.php +++ b/code/EnvironmentChecker.php @@ -29,17 +29,17 @@ class EnvironmentChecker extends RequestHandler { /** * @var null|string */ - public static $to_email_address = null; + private static $to_email_address = null; /** * @var null|string */ - public static $from_email_address = null; + private static $from_email_address = null; /** * @var bool */ - public static $email_results = false; + private static $email_results = false; /** * @var bool Log results via {@link SS_Log} @@ -166,8 +166,8 @@ class EnvironmentChecker extends RequestHandler { "ErrorCode" => $this->errorCode, ))->renderWith("EnvironmentChecker"); - if (self::$email_results && !$result->ShouldPass()) { - $email = new Email(self::$from_email_address, self::$to_email_address, $this->title, $resultText); + if ($this->config()->email_results && !$result->ShouldPass()) { + $email = new Email($this->config()->from_email_address, $this->config()->to_email_address, $this->title, $resultText); $email->send(); } @@ -219,44 +219,56 @@ class EnvironmentChecker extends RequestHandler { } /** + * @deprecated * @param string $from */ public static function set_from_email_address($from) { - self::$from_email_address = $from; + Deprecation::notice('2.0', 'Use config API instead'); + Config::inst()->update('EnvironmentChecker', 'from_email_address', $from); } /** + * @deprecated * @return null|string */ public static function get_from_email_address() { - return self::$from_email_address; + Deprecation::notice('2.0', 'Use config API instead'); + return Config::inst()->get('EnvironmentChecker', 'from_email_address'); } /** + * @deprecated * @param string $to */ public static function set_to_email_address($to) { - self::$to_email_address = $to; + Deprecation::notice('2.0', 'Use config API instead'); + Config::inst()->update('EnvironmentChecker', 'to_email_address', $to); } /** + * @deprecated * @return null|string */ public static function get_to_email_address() { - return self::$to_email_address; + Deprecation::notice('2.0', 'Use config API instead'); + return Config::inst()->get('EnvironmentChecker', 'to_email_address'); } /** + * @deprecated * @param bool $results */ public static function set_email_results($results) { - self::$email_results = $results; + Deprecation::notice('2.0', 'Use config API instead'); + Config::inst()->update('EnvironmentChecker', 'email_results', $results); } /** + * @deprecated * @return bool */ public static function get_email_results() { - return self::$email_results; + Deprecation::notice('2.0', 'Use config API instead'); + return Config::inst()->get('EnvironmentChecker', 'email_results'); } }