diff --git a/classes/hook_callbacks.php b/classes/hook_callbacks.php index 5d71fd4..07f1417 100644 --- a/classes/hook_callbacks.php +++ b/classes/hook_callbacks.php @@ -35,5 +35,7 @@ public static function before_http_headers(\core\hook\output\before_http_headers if (class_exists('\core\check\manager')) { \tool_heartbeat\check\cachecheck::ping('web'); } + + lib::process_error_log_ping(); } } diff --git a/classes/lib.php b/classes/lib.php index a46d73d..fb48b19 100644 --- a/classes/lib.php +++ b/classes/lib.php @@ -100,5 +100,33 @@ public static function record_cache_checked(int $valueincache, int $valueindb, s error_log("Heartbeat cache was checked: " . json_encode($details)); // @codingStandardsIgnoreEnd } + + /** + * Handles error logging pinging. This happens on a regular schedule e.g. every 30 mins. + * This is used in conjunction with external monitoring services to monitor if the error log is fresh + * (or alternatively if it is stale, because the logs are not coming through anymore). + */ + public static function process_error_log_ping() { + $lastpinged = get_config('tool_heartbeat', 'errorloglastpinged') ?: 0; + $errorperiod = get_config('tool_heartbeat', 'errorlog'); + + // If zero/null - disabled - don't do anything. + if (empty($errorperiod)) { + return; + } + + if (($lastpinged + $errorperiod) < time()) { + // Update the last pinged time. + set_config('errorloglastpinged', time(), 'tool_heartbeat'); + + // Log to error_log. + $now = userdate(time()); + $period = format_time($errorperiod); + + // @codingStandardsIgnoreStart + error_log("Heartbeat error log test $now, next test expected in $period"); + // @codingStandardsIgnoreEnd + } + } } diff --git a/lib.php b/lib.php index 7114c3c..d916a92 100644 --- a/lib.php +++ b/lib.php @@ -31,6 +31,7 @@ function tool_heartbeat_before_http_headers() { if (class_exists('\core\check\manager')) { \tool_heartbeat\check\cachecheck::ping('web'); } + \tool_heartbeat\lib::process_error_log_ping(); } /** diff --git a/tests/lib_test.php b/tests/lib_test.php index fdd487a..9858aa3 100644 --- a/tests/lib_test.php +++ b/tests/lib_test.php @@ -47,4 +47,63 @@ public function test_get_allowed_ips() { set_config('allowedips_forced', '', 'tool_heartbeat'); $this->assertEquals('', lib::get_allowed_ips()); } + + /** + * Provides values to test error log ping. + * @return array + */ + public function process_error_log_ping_provider(): array { + return [ + 'no period set - disabled' => [ + 'errorloglastpinged' => null, + 'errorlog' => null, + 'expectedtimebefore' => null, + ], + 'only period set' => [ + 'errorloglastpinged' => null, + 'errorlog' => 1 * MINSECS, + // Update to latest time. + 'expectedtimebefore' => time() + 10, + ], + 'period has passed, time should change' => [ + 'errorloglastpinged' => 1, + 'errorlog' => 1 * MINSECS, + // Update to latest time. + 'expectedtimebefore' => time() + 10, + ], + 'period not passed yet, time unchanged' => [ + 'errorloglastpinged' => time(), + 'errorlog' => 1 * MINSECS, + // Remain unchanged, i.e. exactly equal. + 'expectedtimebefore' => time(), + ], + ]; + } + + /** + * Tests process_error_log_ping function + * + * @param int|null $errorloglastpinged next error value to set + * @param int|null $errorlog error log value to set + * @param bool $expectrun + * @dataProvider process_error_log_ping_provider + */ + public function test_process_error_log_ping(?int $errorloglastpinged, ?int $errorlog, ?int $expectedtimebefore) { + $this->resetAfterTest(true); + set_config('errorloglastpinged', $errorloglastpinged, 'tool_heartbeat'); + set_config('errorlog', $errorlog, 'tool_heartbeat'); + lib::process_error_log_ping(); + + $valueafter = get_config('tool_heartbeat', 'errorloglastpinged'); + + // Assert the time was not set at all. + if (is_null($expectedtimebefore)) { + $this->assertFalse($valueafter); + } else { + // New value should have set current time as the last pinged time. + // We use less than and add some buffer in the test cases to account + // for tests that might happen over a few seconds. + $this->assertLessThanOrEqual($expectedtimebefore, $valueafter); + } + } }