From 1022b5fdf9f68424885ff6f8b923d5762406a201 Mon Sep 17 00:00:00 2001 From: LogMANOriginal Date: Thu, 31 Oct 2019 18:49:45 +0100 Subject: [PATCH] core: Add an option to suppress error reporting (#1179) Error reporting currently takes place for each error. This can result in many error messages if a server has connectivity issues (i.e. when it re-connects to the internet every 24 hours). This commit adds a new option to the configuration file to define the number of error reports to suppress before returning an error message to the user. Error reports are cached and therefore automatically purged after 24 hours. A successful bridge request does **not** clear the error count as sporadic issues can be the result of actual problems on the server. The implementation currently makes no assumption on the type of error, which means it also suppresses bridge errors in debug mode. The default value is, however, set to 1 which means all errors are reported. References #994 --- actions/DisplayAction.php | 114 ++++++++++++++++++++------------------ config.default.ini.php | 3 + lib/Configuration.php | 4 ++ lib/error.php | 34 ++++++++++++ 4 files changed, 100 insertions(+), 55 deletions(-) diff --git a/actions/DisplayAction.php b/actions/DisplayAction.php index 8ac5fe8d..fc5e9da0 100644 --- a/actions/DisplayAction.php +++ b/actions/DisplayAction.php @@ -146,20 +146,61 @@ class DisplayAction extends ActionAbstract { } catch(Error $e) { error_log($e); - if(Configuration::getConfig('error', 'output') === 'feed') { - $item = new \FeedItem(); + if(logBridgeError($bridge::NAME, $e->getCode()) >= Configuration::getConfig('error', 'report_limit')) { + if(Configuration::getConfig('error', 'output') === 'feed') { + $item = new \FeedItem(); - // Create "new" error message every 24 hours - $this->userData['_error_time'] = urlencode((int)(time() / 86400)); + // Create "new" error message every 24 hours + $this->userData['_error_time'] = urlencode((int)(time() / 86400)); - // Error 0 is a special case (i.e. "trying to get property of non-object") - if($e->getCode() === 0) { - $item->setTitle( - 'Bridge encountered an unexpected situation! (' - . $this->userData['_error_time'] - . ')' + // Error 0 is a special case (i.e. "trying to get property of non-object") + if($e->getCode() === 0) { + $item->setTitle( + 'Bridge encountered an unexpected situation! (' + . $this->userData['_error_time'] + . ')' + ); + } else { + $item->setTitle( + 'Bridge returned error ' + . $e->getCode() + . '! (' + . $this->userData['_error_time'] + . ')' + ); + } + + $item->setURI( + (isset($_SERVER['REQUEST_URI']) ? parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) : '') + . '?' + . http_build_query($this->userData) ); - } else { + + $item->setTimestamp(time()); + $item->setContent(buildBridgeException($e, $bridge)); + + $items[] = $item; + } elseif(Configuration::getConfig('error', 'output') === 'http') { + header('Content-Type: text/html', true, $e->getCode()); + die(buildTransformException($e, $bridge)); + } + } + } catch(Exception $e) { + error_log($e); + + if(logBridgeError($bridge::NAME, $e->getCode()) >= Configuration::getConfig('error', 'report_limit')) { + if(Configuration::getConfig('error', 'output') === 'feed') { + $item = new \FeedItem(); + + // Create "new" error message every 24 hours + $this->userData['_error_time'] = urlencode((int)(time() / 86400)); + + $item->setURI( + (isset($_SERVER['REQUEST_URI']) ? parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) : '') + . '?' + . http_build_query($this->userData) + ); + $item->setTitle( 'Bridge returned error ' . $e->getCode() @@ -167,51 +208,14 @@ class DisplayAction extends ActionAbstract { . $this->userData['_error_time'] . ')' ); + $item->setTimestamp(time()); + $item->setContent(buildBridgeException($e, $bridge)); + + $items[] = $item; + } elseif(Configuration::getConfig('error', 'output') === 'http') { + header('Content-Type: text/html', true, $e->getCode()); + die(buildTransformException($e, $bridge)); } - - $item->setURI( - (isset($_SERVER['REQUEST_URI']) ? parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) : '') - . '?' - . http_build_query($this->userData) - ); - - $item->setTimestamp(time()); - $item->setContent(buildBridgeException($e, $bridge)); - - $items[] = $item; - } elseif(Configuration::getConfig('error', 'output') === 'http') { - header('Content-Type: text/html', true, $e->getCode()); - die(buildTransformException($e, $bridge)); - } - } catch(Exception $e) { - error_log($e); - - if(Configuration::getConfig('error', 'output') === 'feed') { - $item = new \FeedItem(); - - // Create "new" error message every 24 hours - $this->userData['_error_time'] = urlencode((int)(time() / 86400)); - - $item->setURI( - (isset($_SERVER['REQUEST_URI']) ? parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) : '') - . '?' - . http_build_query($this->userData) - ); - - $item->setTitle( - 'Bridge returned error ' - . $e->getCode() - . '! (' - . $this->userData['_error_time'] - . ')' - ); - $item->setTimestamp(time()); - $item->setContent(buildBridgeException($e, $bridge)); - - $items[] = $item; - } elseif(Configuration::getConfig('error', 'output') === 'http') { - header('Content-Type: text/html', true, $e->getCode()); - die(buildTransformException($e, $bridge)); } } diff --git a/config.default.ini.php b/config.default.ini.php index 61b53931..7d0bdaaa 100644 --- a/config.default.ini.php +++ b/config.default.ini.php @@ -70,6 +70,9 @@ password = "" ; "none" = No errors are reported output = "feed" +; Defines how often an error must occur before it is reported to the user +report_limit = 1 + ; --- Cache specific configuration --------------------------------------------- [SQLiteCache] diff --git a/lib/Configuration.php b/lib/Configuration.php index 969e9bac..8978ea70 100644 --- a/lib/Configuration.php +++ b/lib/Configuration.php @@ -204,6 +204,10 @@ final class Configuration { if(!is_string(self::getConfig('error', 'output'))) self::reportConfigurationError('error', 'output', 'Is not a valid String'); + if(!is_numeric(self::getConfig('error', 'report_limit')) + || self::getConfig('error', 'report_limit') < 1) + self::reportConfigurationError('admin', 'report_limit', 'Value is invalid'); + } /** diff --git a/lib/error.php b/lib/error.php index 9a0756f9..4b7110f0 100644 --- a/lib/error.php +++ b/lib/error.php @@ -41,3 +41,37 @@ function returnClientError($message){ function returnServerError($message){ returnError($message, 500); } + +/** + * Stores bridge-specific errors in a cache file. + * + * @param string $bridgeName The name of the bridge that failed. + * @param int $code The error code + * + * @return int The total number the same error has appeared + */ +function logBridgeError($bridgeName, $code) { + $cacheFac = new CacheFactory(); + $cacheFac->setWorkingDir(PATH_LIB_CACHES); + + $cache = $cacheFac->create(Configuration::getConfig('cache', 'type')); + $cache->setScope('error_reporting'); + $cache->setkey($bridgeName . '_' . $code); + $cache->purgeCache(86400); // 24 hours + + if($report = $cache->loadData()) { + $report = json_decode($report, true); + $report['time'] = time(); + $report['count']++; + } else { + $report = array( + 'error' => $code, + 'time' => time(), + 'count' => 1, + ); + } + + $cache->saveData(json_encode($report)); + + return $report['count']; +}