From d18ef7f6fe5d34b6833445284eff60e5f83f5fe1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Kud=C4=9Blka?= Date: Sun, 3 Apr 2022 22:53:00 +0200 Subject: [PATCH 01/15] Update ErrorLogger.php --- src/ErrorLogger.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/ErrorLogger.php b/src/ErrorLogger.php index 1d6640c..e651915 100644 --- a/src/ErrorLogger.php +++ b/src/ErrorLogger.php @@ -76,10 +76,9 @@ protected function sendEmail($message): void && $this->mailer ) { - $exceptionFile = $this->getExceptionFile($message); - if (!file_exists($exceptionFile)) { - $exceptionFile = null; - } + $exceptionFile = $message instanceof \Throwable + ? $this->getExceptionFile($message) + : null; $line = static::formatLogLine($message, $exceptionFile); $logFile = $this->directory . '/email-sent'; From ccb380f239a4d334851d49f8e491adc6c34d3f36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Kud=C4=9Blka?= Date: Mon, 4 Apr 2022 07:45:37 +0200 Subject: [PATCH 02/15] Update ErrorLogger.php --- src/ErrorLogger.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ErrorLogger.php b/src/ErrorLogger.php index e651915..baefe2c 100644 --- a/src/ErrorLogger.php +++ b/src/ErrorLogger.php @@ -87,7 +87,9 @@ protected function sendEmail($message): void @unlink($logFile); } - $messageHash = md5(preg_replace('~(Resource id #)\d+~', '$1', $message)); + $messageHash = preg_replace('~(Resource id #)\d+~', '$1', $message); + $messageHash = preg_replace('~(PID: )\d+~', '$1', $messageHash); + $messageHash = md5($messageHash); if ( // ještě se vejdeme do limitu v rámci aktuálního requestu From c395a4edbe6af66c152be2339e0ca2d74bd24590 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Kud=C4=9Blka?= Date: Fri, 3 Jun 2022 23:53:19 +0200 Subject: [PATCH 03/15] Update ErrorLogger.php --- src/ErrorLogger.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ErrorLogger.php b/src/ErrorLogger.php index baefe2c..c22c32f 100644 --- a/src/ErrorLogger.php +++ b/src/ErrorLogger.php @@ -44,7 +44,7 @@ class ErrorLogger extends Logger protected ?Container $container = null; - public static function install($email, $maxEmailsPerDay = NULL, $maxEmailsPerRequest = NULL, $sensitiveFields = [], $includeErrorMessage = true): ?Logger + public static function install($email, $maxEmailsPerDay = NULL, $maxEmailsPerRequest = NULL, $sensitiveFields = [], $includeErrorMessage = true): ?self { if (!Debugger::$productionMode) { return null; From 202bc2a34302525545b4f9dea37494871eff7698 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Lohnisk=C3=BD?= Date: Tue, 4 Jul 2023 21:42:17 +0200 Subject: [PATCH 04/15] Unnecessary dependencies removed --- src/ErrorLogger.php | 178 +++++++++++++------------------------------- 1 file changed, 50 insertions(+), 128 deletions(-) diff --git a/src/ErrorLogger.php b/src/ErrorLogger.php index c22c32f..9c0edcf 100644 --- a/src/ErrorLogger.php +++ b/src/ErrorLogger.php @@ -3,60 +3,44 @@ namespace ADT; use DateTime; -use Exception; -use Nette\DI\Container; use RuntimeException; use Tracy\Debugger; -use Tracy\Dumper; use Tracy\Helpers; use Tracy\Logger; class ErrorLogger extends Logger { /** - * Maximální počet odeslaných emailů denně + * Maximum number of emails per day * @var int */ protected int $maxEmailsPerDay; /** - * Maximální počet odeslaných emailů v rámci jednoho requestu + * Maximum number of emails per request * @var int */ protected int $maxEmailsPerRequest; /** - * Počet odeslaných emailů v rámci aktuálního requestu + * Number of emails in current request * @var int */ protected int $sentEmailsPerRequest = 0; /** - * Pole s citlivými údaji, jejižch hodnoty se nemají zobrazovat ve výpisu. - * @var array - */ - protected array $sensitiveFields = []; - - /** - * Ma se vlozit error message do emailu + * Include exception file as an attachment? */ protected bool $includeErrorMessage = true; - protected ?Container $container = null; - - public static function install($email, $maxEmailsPerDay = NULL, $maxEmailsPerRequest = NULL, $sensitiveFields = [], $includeErrorMessage = true): ?self + public static function install($email, $maxEmailsPerDay = NULL, $maxEmailsPerRequest = NULL, $includeErrorMessage = true): ?self { - if (!Debugger::$productionMode) { - return null; - } - Debugger::$email = $email; $logger = new static(Debugger::$logDirectory, Debugger::$email, Debugger::getBlueScreen()); $logger->maxEmailsPerDay = $maxEmailsPerDay ?: 10; $logger->maxEmailsPerRequest = $maxEmailsPerRequest ?: 10; - $logger->sensitiveFields = $sensitiveFields; $logger->includeErrorMessage = $includeErrorMessage; Debugger::setLogger($logger); @@ -64,107 +48,58 @@ public static function install($email, $maxEmailsPerDay = NULL, $maxEmailsPerReq return $logger; } - public function setup(Container $container) - { - $this->container = $container; - } - protected function sendEmail($message): void { if ( - $this->email + !$this->email + || + !$this->mailer + ) { + return; + } + + $exceptionFile = $message instanceof \Throwable + ? $this->getExceptionFile($message) + : null; + $line = static::formatLogLine($message, $exceptionFile); + $logFile = $this->directory . '/email-sent'; + + // Delete email-sent file from yesterday + if (date('Y-m-d', @filemtime($logFile)) < (new DateTime('midnight'))->format('Y-m-d')) { + @unlink($logFile); + } + + $messageHash = preg_replace('~(Resource id #)\d+~', '$1', $message); + $messageHash = preg_replace('~(PID: )\d+~', '$1', $messageHash); + $messageHash = md5($messageHash); + + if ($this->sentEmailsPerRequest >= $this->maxEmailsPerRequest) { + // Limit per request exceeded + return; + } + + if ( + ($logContent = @file_get_contents($logFile)) && - $this->mailer + (strstr($logContent, $messageHash) !== false) ) { - $exceptionFile = $message instanceof \Throwable - ? $this->getExceptionFile($message) - : null; - $line = static::formatLogLine($message, $exceptionFile); - $logFile = $this->directory . '/email-sent'; - - // we delete email-sent file from yesterday - if (date('Y-m-d', @filemtime($logFile)) < (new DateTime('midnight'))->format('Y-m-d')) { - @unlink($logFile); - } + // Duplicate error + return; + } - $messageHash = preg_replace('~(Resource id #)\d+~', '$1', $message); - $messageHash = preg_replace('~(PID: )\d+~', '$1', $messageHash); - $messageHash = md5($messageHash); - - if ( - // ještě se vejdeme do limitu v rámci aktuálního requestu - $this->sentEmailsPerRequest < $this->maxEmailsPerRequest - && - // tento hash jsme ještě neposlali - ( - !($logContent = @file_get_contents($logFile)) - || - (strstr($logContent, $messageHash) === false) - ) - && - // ještě se vejdeme do limitu v rámci aktuálního dne - substr_count($logContent, date('Y-m-d')) < $this->maxEmailsPerDay - ) { - if (!@file_put_contents($logFile, $line . ' ' . $messageHash . PHP_EOL, FILE_APPEND | LOCK_EX)) { - throw new RuntimeException("Unable to write to log file '" . $logFile . "'. Is directory writable?"); - } - - // sestavíme zprávu - if (is_array($message)) { - $stringMessage = implode(' ', $message); - } else { - $stringMessage = $message; - } - - $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); - if (count($backtrace) > 3) { //pokud jsou 3 tak jde pouze o exception a je ulozena nette chybova stranka - $backtraceString = ""; - - for ($i = 0; $i < count($backtrace); $i++) { - $backtraceData = $backtrace[$i] + [ - 'file' => '_unknown_', - 'line' => '_unknown_', - 'function' => '_unknown_', - ]; - - $backtraceString = "#$i {$backtraceData['file']}({$backtraceData['line']}): " - . (isset($backtraceData['class']) ? $backtraceData['class'] . '::' : '') - . "{$backtraceData['function']}()\n"; - } - - $stringMessage .= "\n\n" . $backtraceString; - } - - - // přidáme doplnující info - referer, browser... - $stringMessage .= "\n\n" . - (isset($_SERVER['HTTP_HOST']) ? 'LINK:' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] . "\n" : '') . - 'SERVER:' . Dumper::toText($_SERVER) . "\n\n" . - 'GET:' . Dumper::toText($_GET, [Dumper::DEPTH => 10]) . "\n\n" . - 'POST:' . Dumper::toText($this->hideSensitiveFieldValue($_POST), [Dumper::DEPTH => 10]); - - if ($this->container && ($securityUser = $this->container->getByType('\Nette\Security\User', FALSE))) { - // obalujeme do try protoze SecurityUser je zavisly na databazi a pokud je chyba v db, tak nam error nedojde - try { - $stringMessage .= "\n\n" . - 'securityUser:' . Dumper::toText($securityUser->identity, [Dumper::DEPTH => 1]); - } catch (Exception $e) {} - } - - if ($this->container && ($git = $this->container->getByType('\ADT\TracyGit\Git', FALSE)) !== NULL && ($gitInfo = $git->getInfo())) { - $stringMessage .= "\n\n"; - - foreach ($gitInfo as $key => $value) { - $stringMessage .= $key . ": " . $value . "\n"; - } - } - - // odešleme chybu emailem - call_user_func($this->mailer, $stringMessage, implode(', ', (array)$this->email), $exceptionFile); - - $this->sentEmailsPerRequest++; - } + if (substr_count($logContent, date('Y-m-d')) >= $this->maxEmailsPerDay) { + // Limit per day exceeded + return; + } + + if (!@file_put_contents($logFile, $line . ' ' . $messageHash . PHP_EOL, FILE_APPEND | LOCK_EX)) { + throw new RuntimeException("Unable to write to log file '" . $logFile . "'. Is directory writable?"); } + + + call_user_func($this->mailer, $message, implode(', ', (array)$this->email), $exceptionFile); + + $this->sentEmailsPerRequest++; } /** @@ -217,17 +152,4 @@ public function defaultMailer($message, string $email, ?string $attachment = nul mail($email, $parts['subject'], $parts['body'], $parts['headers']); } - protected function hideSensitiveFieldValue($array): array - { - $sensitiveFields = $this->sensitiveFields; - $replacement = '*****'; - - array_walk_recursive($array, function (&$value, $key) use ($sensitiveFields, $replacement) { - if (in_array($key, $sensitiveFields, TRUE)) { - $value = $replacement; - } - }); - - return $array; - } } From fab0f1c266503b6c2ebcfb6f5f45dec5faa8495a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Lohnisk=C3=BD?= Date: Tue, 4 Jul 2023 21:47:43 +0200 Subject: [PATCH 05/15] Update README.md --- README.md | 43 +++++++------------------------------------ 1 file changed, 7 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 646300b..e9c76ab 100644 --- a/README.md +++ b/README.md @@ -6,45 +6,16 @@ Sends more info about the error than [Tracy\Logger](https://github.com/nette/tra Installation ------------ -```` +````bash composer require adt/error-logger ```` -Place this to your bootstrap.php after calling `$configurator->enableDebugger()` and before calling `$configurator->createContainer()`: -```` +Place this to your bootstrap.php after calling `$configurator->enableDebugger()`: + +````php $logger = \ADT\ErrorLogger::install($email = 'errors@example.com', $maxEmailsPerDay = 10, $maxEmailsPerRequest = 10); -```` -and this after calling `$configurator->createContainer()`: -``` -if ($logger) { - $logger->setup($container); +if (!\Tracy\Debugger::$productionMode) { + // Do not send emails + $logger->mailer = null; } -``` - -**Sensitive fields:** - -You can specify keys of array, which will be hidden in POST dump. - -Example: - -```` -$logger = \ADT\ErrorLogger::install( - 'errors@example.com', - 10, - 10, - $sensitiveFields = [ - 'password', - ] -); ```` - -POST dump: - -``` -POST:array (4) - username => "my_username" (11) - password => "*****" (5) - login => "Sign in" (7) - _do => "signForm-submit" (15) -``` - From b345902f12db5126b0657063ef54a9e49c6ec40b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Lohnisk=C3=BD?= Date: Tue, 4 Jul 2023 21:51:28 +0200 Subject: [PATCH 06/15] Update composer.json --- composer.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 17e1686..61dbee9 100644 --- a/composer.json +++ b/composer.json @@ -12,8 +12,7 @@ ], "require": { "php": ">=7.4", - "tracy/tracy": ">=2.6.0", - "nette/di": "^2.4|^3.0" + "tracy/tracy": ">=2.6.0" }, "suggest": { "adt/tracy-git": "Useful for displaying information about currently deployed application version." From 457497724dbf35c588275705d5d7b43780e10f4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Kud=C4=9Blka?= Date: Fri, 7 Jul 2023 17:10:11 +0200 Subject: [PATCH 07/15] Allow to set From header via Logger::$fromEmail --- src/ErrorLogger.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ErrorLogger.php b/src/ErrorLogger.php index 9c0edcf..766c612 100644 --- a/src/ErrorLogger.php +++ b/src/ErrorLogger.php @@ -138,12 +138,13 @@ public function defaultMailer($message, string $email, ?string $attachment = nul ["\r\n", "\n"], ["\n", PHP_EOL], [ - 'headers' => implode("\n", [ + 'headers' => implode("\n", array_filter([ + ($this->fromEmail ? 'From: ' . $this->fromEmail : ''), 'X-Mailer: Tracy', 'MIME-Version: 1.0', 'Content-Type: multipart/mixed; boundary="' . $separator . '"', 'Content-Transfer-Encoding: 7bit', - ]) . "\n", + ])) . "\n", 'subject' => "PHP: An error occurred on the server $host", 'body' => $body ] From 026316181678e33874d3de401243adfb6776db8f Mon Sep 17 00:00:00 2001 From: Tomas Kudelka Date: Sat, 5 Aug 2023 16:16:58 +0200 Subject: [PATCH 08/15] refactorization --- .gitignore | 3 ++ src/ErrorLogger.php | 90 ++++++++++++++++++++++++++------------------- 2 files changed, 55 insertions(+), 38 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..87d072d --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/.idea +/vendor +/composer.lock \ No newline at end of file diff --git a/src/ErrorLogger.php b/src/ErrorLogger.php index 766c612..45bec73 100644 --- a/src/ErrorLogger.php +++ b/src/ErrorLogger.php @@ -8,40 +8,55 @@ use Tracy\Helpers; use Tracy\Logger; -class ErrorLogger extends Logger +final class ErrorLogger extends Logger { /** * Maximum number of emails per day * @var int */ - protected int $maxEmailsPerDay; + public int $maxEmailsPerDay; /** * Maximum number of emails per request * @var int */ - protected int $maxEmailsPerRequest; + public int $maxEmailsPerRequest; /** - * Number of emails in current request - * @var int + * Regular expression which removes matches before checking if email was already sent + * @var string */ - protected int $sentEmailsPerRequest = 0; + public string $errorMessageSanitizeRegex; /** * Include exception file as an attachment? */ - protected bool $includeErrorMessage = true; + public bool $includeExceptionFile; - public static function install($email, $maxEmailsPerDay = NULL, $maxEmailsPerRequest = NULL, $includeErrorMessage = true): ?self + /** + * Number of emails in current request + * @var int + */ + private int $sentEmailsPerRequest = 0; + + public static function install( + $email, + $maxEmailsPerDay = 100, + $maxEmailsPerRequest = 10, + $includeExceptionFile = true, + $errorMessageSanitizeRegex = '~\d|(/[^\s]*)|(\w+://)~', // removes all numbers, absolut paths and protocols + $emailSnooze = 'midnight' + ): ?self { Debugger::$email = $email; - $logger = new static(Debugger::$logDirectory, Debugger::$email, Debugger::getBlueScreen()); + $logger = new self(Debugger::$logDirectory, Debugger::$email, Debugger::getBlueScreen()); - $logger->maxEmailsPerDay = $maxEmailsPerDay ?: 10; - $logger->maxEmailsPerRequest = $maxEmailsPerRequest ?: 10; - $logger->includeErrorMessage = $includeErrorMessage; + $logger->maxEmailsPerDay = $maxEmailsPerDay; + $logger->maxEmailsPerRequest = $maxEmailsPerRequest; + $logger->includeExceptionFile = $includeExceptionFile; + $logger->errorMessageSanitizeRegex = $errorMessageSanitizeRegex; + $logger->emailSnooze = $emailSnooze; Debugger::setLogger($logger); @@ -61,17 +76,15 @@ protected function sendEmail($message): void $exceptionFile = $message instanceof \Throwable ? $this->getExceptionFile($message) : null; - $line = static::formatLogLine($message, $exceptionFile); + $line = self::formatLogLine($message, $exceptionFile); $logFile = $this->directory . '/email-sent'; // Delete email-sent file from yesterday - if (date('Y-m-d', @filemtime($logFile)) < (new DateTime('midnight'))->format('Y-m-d')) { + if (date('Y-m-d', @filemtime($logFile)) < (new DateTime($this->emailSnooze))->format('Y-m-d')) { @unlink($logFile); } - $messageHash = preg_replace('~(Resource id #)\d+~', '$1', $message); - $messageHash = preg_replace('~(PID: )\d+~', '$1', $messageHash); - $messageHash = md5($messageHash); + $messageHash = md5($this->sanitizeString($message)); if ($this->sentEmailsPerRequest >= $this->maxEmailsPerRequest) { // Limit per request exceeded @@ -105,33 +118,30 @@ protected function sendEmail($message): void /** * @internal */ - public function defaultMailer($message, string $email, ?string $attachment = null): void + public function defaultMailer($message, string $email, ?string $exceptionFile = null): void { $host = preg_replace('#[^\w.-]+#', '', $_SERVER['HTTP_HOST'] ?? php_uname('n')); $separator = md5(time()); $eol = "\n"; - $body = ''; - if ($this->includeErrorMessage) { - $body = - "--" . $separator . $eol . - - // Text email - "Content-Type: text/plain; charset=\"UTF-8\"" . $eol . - "Content-Transfer-Encoding: 8bit" . $eol . $eol . - $this->formatMessage($message) . "\n\nsource: " . Helpers::getSource() . $eol . - "--" . $separator . $eol; - - if ($attachment) { - $body .= - // Attachment - "Content-Type: application/octet-stream; name=\"" . basename($attachment) . "\"" . $eol . - "Content-Transfer-Encoding: base64" . $eol . - "Content-Disposition: attachment" . $eol . $eol . - chunk_split(base64_encode(file_get_contents($attachment))) . $eol . - "--" . $separator . "--"; - } + $body = + "--" . $separator . $eol . + + // Text email + "Content-Type: text/plain; charset=\"UTF-8\"" . $eol . + "Content-Transfer-Encoding: 8bit" . $eol . $eol . + $this->formatMessage($message) . "\n\nsource: " . Helpers::getSource() . $eol . + "--" . $separator . $eol; + + if ($exceptionFile && $this->includeExceptionFile) { + $body .= + // Attachment + "Content-Type: application/octet-stream; name=\"" . basename($exceptionFile) . "\"" . $eol . + "Content-Transfer-Encoding: base64" . $eol . + "Content-Disposition: attachment" . $eol . $eol . + chunk_split(base64_encode(file_get_contents($exceptionFile))) . $eol . + "--" . $separator . "--"; } $parts = str_replace( @@ -153,4 +163,8 @@ public function defaultMailer($message, string $email, ?string $attachment = nul mail($email, $parts['subject'], $parts['body'], $parts['headers']); } + private function sanitizeString($string): string + { + return preg_replace($this->errorMessageSanitizeRegex, '', $string); + } } From bcc564e02256a7b441454ea9abe075255bf3111e Mon Sep 17 00:00:00 2001 From: Tomas Kudelka Date: Sat, 5 Aug 2023 16:19:30 +0200 Subject: [PATCH 09/15] readme --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e9c76ab..3343142 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,14 @@ composer require adt/error-logger Place this to your bootstrap.php after calling `$configurator->enableDebugger()`: ````php -$logger = \ADT\ErrorLogger::install($email = 'errors@example.com', $maxEmailsPerDay = 10, $maxEmailsPerRequest = 10); +$logger = \ADT\ErrorLogger::install( + $email = 'errors@example.com', + $maxEmailsPerDay = 100, + $maxEmailsPerRequest = 10, + $includeExceptionFile = true, + $errorMessageSanitizeRegex = '~\d|(/[^\s]*)|(\w+://)~', // removes all numbers, absolut paths and protocols + $emailSnooze = 'midnight' +); if (!\Tracy\Debugger::$productionMode) { // Do not send emails $logger->mailer = null; From d870b19f70b65403e18cea4a29592e7d56dc2463 Mon Sep 17 00:00:00 2001 From: Tomas Kudelka Date: Sat, 5 Aug 2023 17:04:10 +0200 Subject: [PATCH 10/15] refactorization --- src/ErrorLogger.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/ErrorLogger.php b/src/ErrorLogger.php index 45bec73..efa197f 100644 --- a/src/ErrorLogger.php +++ b/src/ErrorLogger.php @@ -2,7 +2,6 @@ namespace ADT; -use DateTime; use RuntimeException; use Tracy\Debugger; use Tracy\Helpers; @@ -45,7 +44,7 @@ public static function install( $maxEmailsPerRequest = 10, $includeExceptionFile = true, $errorMessageSanitizeRegex = '~\d|(/[^\s]*)|(\w+://)~', // removes all numbers, absolut paths and protocols - $emailSnooze = 'midnight' + $emailSnooze = '1 day' ): ?self { Debugger::$email = $email; @@ -79,8 +78,12 @@ protected function sendEmail($message): void $line = self::formatLogLine($message, $exceptionFile); $logFile = $this->directory . '/email-sent'; + $snooze = is_numeric($this->emailSnooze) + ? $this->emailSnooze + : strtotime($this->emailSnooze) - time(); + // Delete email-sent file from yesterday - if (date('Y-m-d', @filemtime($logFile)) < (new DateTime($this->emailSnooze))->format('Y-m-d')) { + if (($filemtime = @filemtime($this->directory . '/email-sent')) && ($filemtime + $snooze < time())) { @unlink($logFile); } From 40abaf85775d33bcd3afd7db6b5424d569f1a6c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Kud=C4=9Blka?= Date: Sun, 6 Aug 2023 08:24:47 +0200 Subject: [PATCH 11/15] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 3343142..37f1622 100644 --- a/README.md +++ b/README.md @@ -14,10 +14,10 @@ Place this to your bootstrap.php after calling `$configurator->enableDebugger()` ````php $logger = \ADT\ErrorLogger::install( - $email = 'errors@example.com', - $maxEmailsPerDay = 100, - $maxEmailsPerRequest = 10, - $includeExceptionFile = true, + $email = 'errors@example.com', + $maxEmailsPerDay = 100, + $maxEmailsPerRequest = 10, + $includeExceptionFile = true, $errorMessageSanitizeRegex = '~\d|(/[^\s]*)|(\w+://)~', // removes all numbers, absolut paths and protocols $emailSnooze = 'midnight' ); From a404d1ca14b1c06c080a2d550d4fe1f5e9bf0fd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Kud=C4=9Blka?= Date: Sun, 6 Aug 2023 08:25:38 +0200 Subject: [PATCH 12/15] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 37f1622..78319e0 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ $logger = \ADT\ErrorLogger::install( $maxEmailsPerRequest = 10, $includeExceptionFile = true, $errorMessageSanitizeRegex = '~\d|(/[^\s]*)|(\w+://)~', // removes all numbers, absolut paths and protocols - $emailSnooze = 'midnight' + $emailSnooze = '1 day' ); if (!\Tracy\Debugger::$productionMode) { // Do not send emails From 827b39265771f4776811d83b236089058c4db957 Mon Sep 17 00:00:00 2001 From: Tomas Kudelka Date: Mon, 7 Aug 2023 22:22:07 +0200 Subject: [PATCH 13/15] refactorization --- src/ErrorLogger.php | 51 +++++++++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/src/ErrorLogger.php b/src/ErrorLogger.php index efa197f..9997660 100644 --- a/src/ErrorLogger.php +++ b/src/ErrorLogger.php @@ -2,6 +2,7 @@ namespace ADT; +use DateTime; use RuntimeException; use Tracy\Debugger; use Tracy\Helpers; @@ -72,30 +73,33 @@ protected function sendEmail($message): void return; } + if ($this->sentEmailsPerRequest >= $this->maxEmailsPerRequest) { + // Limit per request exceeded + return; + } + $exceptionFile = $message instanceof \Throwable ? $this->getExceptionFile($message) : null; $line = self::formatLogLine($message, $exceptionFile); - $logFile = $this->directory . '/email-sent'; + + $messageHash = md5($this->sanitizeString($message)); + + // ERROR SNOOZE + + $errorSnoozeLog = $this->directory . '/error-snooze.log'; $snooze = is_numeric($this->emailSnooze) ? $this->emailSnooze : strtotime($this->emailSnooze) - time(); // Delete email-sent file from yesterday - if (($filemtime = @filemtime($this->directory . '/email-sent')) && ($filemtime + $snooze < time())) { - @unlink($logFile); - } - - $messageHash = md5($this->sanitizeString($message)); - - if ($this->sentEmailsPerRequest >= $this->maxEmailsPerRequest) { - // Limit per request exceeded - return; + if (($filemtime = @filemtime($errorSnoozeLog)) && ($filemtime + $snooze < time())) { + @unlink($errorSnoozeLog); } if ( - ($logContent = @file_get_contents($logFile)) + ($logContent = @file_get_contents($errorSnoozeLog)) && (strstr($logContent, $messageHash) !== false) ) { @@ -103,15 +107,29 @@ protected function sendEmail($message): void return; } + self::writeToLogFile($errorSnoozeLog, $line . ' ' . $messageHash); + + // MAX EMAILS PER DY + + $maxEmailsPerDayLog = $this->directory . '/max-emails-per-day.log'; + + // delete file from yesterday + if (date('Y-m-d', @filemtime($maxEmailsPerDayLog)) < (new DateTime('midnight'))->format('Y-m-d')) { + @unlink($maxEmailsPerDayLog); + } + + $logContent = @file_get_contents($errorSnoozeLog); + if (substr_count($logContent, date('Y-m-d')) >= $this->maxEmailsPerDay) { // Limit per day exceeded return; } - if (!@file_put_contents($logFile, $line . ' ' . $messageHash . PHP_EOL, FILE_APPEND | LOCK_EX)) { - throw new RuntimeException("Unable to write to log file '" . $logFile . "'. Is directory writable?"); + if (!@file_put_contents($errorSnoozeLog, $line . ' ' . $messageHash . PHP_EOL, FILE_APPEND | LOCK_EX)) { + throw new RuntimeException("Unable to write to log file '" . $errorSnoozeLog . "'. Is directory writable?"); } + // SEND EMAIL call_user_func($this->mailer, $message, implode(', ', (array)$this->email), $exceptionFile); @@ -170,4 +188,11 @@ private function sanitizeString($string): string { return preg_replace($this->errorMessageSanitizeRegex, '', $string); } + + private static function writeToLogFile($filename, $data) + { + if (!@file_put_contents($filename, $data . PHP_EOL, FILE_APPEND | LOCK_EX)) { + throw new RuntimeException("Unable to write to log file '" . $filename . "'. Is directory writable?"); + } + } } From 06c5e9b798f7cd45635b72144eb68b082dbc0f9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Kud=C4=9Blka?= Date: Mon, 7 Aug 2023 22:41:59 +0200 Subject: [PATCH 14/15] Update ErrorLogger.php --- src/ErrorLogger.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ErrorLogger.php b/src/ErrorLogger.php index 9997660..9f7ac14 100644 --- a/src/ErrorLogger.php +++ b/src/ErrorLogger.php @@ -109,7 +109,7 @@ protected function sendEmail($message): void self::writeToLogFile($errorSnoozeLog, $line . ' ' . $messageHash); - // MAX EMAILS PER DY + // MAX EMAILS PER DAY $maxEmailsPerDayLog = $this->directory . '/max-emails-per-day.log'; @@ -118,16 +118,16 @@ protected function sendEmail($message): void @unlink($maxEmailsPerDayLog); } - $logContent = @file_get_contents($errorSnoozeLog); + $logContent = @file_get_contents($maxEmailsPerDayLog); - if (substr_count($logContent, date('Y-m-d')) >= $this->maxEmailsPerDay) { + file_put_contents('adasd', count(file($maxEmailsPerDayLog))); + + if (count(file($maxEmailsPerDayLog)) >= $this->maxEmailsPerDay) { // Limit per day exceeded return; } - if (!@file_put_contents($errorSnoozeLog, $line . ' ' . $messageHash . PHP_EOL, FILE_APPEND | LOCK_EX)) { - throw new RuntimeException("Unable to write to log file '" . $errorSnoozeLog . "'. Is directory writable?"); - } + self::writeToLogFile($maxEmailsPerDayLog, $line . ' ' . $messageHash); // SEND EMAIL From d28cd227d99538ea5c716856a96a8d2535ce9e6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Kud=C4=9Blka?= Date: Wed, 9 Aug 2023 23:47:46 +0200 Subject: [PATCH 15/15] Update ErrorLogger.php --- src/ErrorLogger.php | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/ErrorLogger.php b/src/ErrorLogger.php index 9f7ac14..6b8cfc4 100644 --- a/src/ErrorLogger.php +++ b/src/ErrorLogger.php @@ -114,15 +114,9 @@ protected function sendEmail($message): void $maxEmailsPerDayLog = $this->directory . '/max-emails-per-day.log'; // delete file from yesterday - if (date('Y-m-d', @filemtime($maxEmailsPerDayLog)) < (new DateTime('midnight'))->format('Y-m-d')) { + if (($filemtime = @filemtime($maxEmailsPerDayLog)) && date('Y-m-d', $filemtime) < (new DateTime('midnight'))->format('Y-m-d')) { @unlink($maxEmailsPerDayLog); - } - - $logContent = @file_get_contents($maxEmailsPerDayLog); - - file_put_contents('adasd', count(file($maxEmailsPerDayLog))); - - if (count(file($maxEmailsPerDayLog)) >= $this->maxEmailsPerDay) { + } elseif (($lines = @file($maxEmailsPerDayLog)) && count($lines) >= $this->maxEmailsPerDay) { // Limit per day exceeded return; }