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 1/3] 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 2/3] 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 3/3] 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."