From d523c7425aefc2dcddf990cf0d016573da007a9d Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Tue, 12 May 2026 13:31:33 +0530 Subject: [PATCH] Log abuse timelimit fail-open errors --- app/controllers/shared/api.php | 7 ++++-- app/init/resources/request.php | 45 ++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 7b7d394908..923b878c44 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -499,8 +499,9 @@ Http::init() ->inject('telemetry') ->inject('platform') ->inject('authorization') + ->inject('logError') ->inject('cacheControlForStorage') - ->action(function (Http $utopia, Request $request, Response $response, Document $project, User $user, Event $queueForEvents, AuditContext $auditContext, Delete $queueForDeletes, EventDatabase $queueForDatabase, Context $usage, Func $queueForFunctions, Database $dbForProject, callable $timelimit, Document $resourceToken, string $mode, ?Key $apiKey, array $plan, Document $devKey, Telemetry $telemetry, array $platform, Authorization $authorization, callable $cacheControlForStorage) { + ->action(function (Http $utopia, Request $request, Response $response, Document $project, User $user, Event $queueForEvents, AuditContext $auditContext, Delete $queueForDeletes, EventDatabase $queueForDatabase, Context $usage, Func $queueForFunctions, Database $dbForProject, callable $timelimit, Document $resourceToken, string $mode, ?Key $apiKey, array $plan, Document $devKey, Telemetry $telemetry, array $platform, Authorization $authorization, callable $logError, callable $cacheControlForStorage) { $response->setUser($user); $request->setUser($user); @@ -580,7 +581,9 @@ Http::init() if ($shouldCheckAbuse) { $isRateLimited = $abuse->check(); } - } catch (\Throwable) { + } catch (\Throwable $th) { + \call_user_func($logError, $th, 'http', 'api.abuse.timelimit'); + continue; } diff --git a/app/init/resources/request.php b/app/init/resources/request.php index 6ed377d9ae..a090b5523a 100644 --- a/app/init/resources/request.php +++ b/app/init/resources/request.php @@ -34,6 +34,7 @@ use Utopia\Auth\Proofs\Token; use Utopia\Auth\Store; use Utopia\Cache\Cache; use Utopia\Config\Config; +use Utopia\Console; use Utopia\Database\Adapter\Pool as DatabasePool; use Utopia\Database\Database; use Utopia\Database\DateTime as DatabaseDateTime; @@ -48,6 +49,7 @@ use Utopia\Locale\Locale; use Utopia\Logger\Log; use Utopia\Pools\Group; use Utopia\Queue\Publisher; +use Utopia\Registry\Registry; use Utopia\Storage\Device; use Utopia\System\System; use Utopia\Telemetry\Adapter as Telemetry; @@ -70,6 +72,49 @@ return function (Container $container): void { return $register->get('logger'); }, ['register']); + $container->set('logError', function (Registry $register, Request $request, Document $project, Authorization $authorization) { + return function (Throwable $error, string $namespace, string $action, ?array $extras = null) use ($register, $request, $project, $authorization) { + $logger = $register->get('logger'); + + if (!$logger) { + return; + } + + $log = new Log(); + $log->setNamespace($namespace); + $log->setServer(System::getEnv('_APP_LOGGING_SERVICE_IDENTIFIER', \gethostname())); + $log->setVersion(System::getEnv('_APP_VERSION', 'UNKNOWN')); + $log->setType(Log::TYPE_ERROR); + $log->setMessage($error->getMessage()); + $log->setAction($action); + + $log->addTag('code', $error->getCode()); + $log->addTag('verboseType', \get_class($error)); + $log->addTag('projectId', $project->getId()); + $log->addTag('method', $request->getMethod()); + $log->addTag('url', $request->getURI()); + + $log->addExtra('file', $error->getFile()); + $log->addExtra('line', $error->getLine()); + $log->addExtra('trace', $error->getTraceAsString()); + $log->addExtra('roles', $authorization->getRoles()); + + foreach (($extras ?? []) as $key => $value) { + $log->addExtra($key, $value); + } + + $isProduction = System::getEnv('_APP_ENV', 'development') === 'production'; + $log->setEnvironment($isProduction ? Log::ENVIRONMENT_PRODUCTION : Log::ENVIRONMENT_STAGING); + + try { + $responseCode = $logger->addLog($log); + Console::info('Error log pushed with status code: ' . $responseCode); + } catch (Throwable $th) { + Console::error('Error pushing log: ' . $th->getMessage()); + } + }; + }, ['register', 'request', 'project', 'authorization']); + $container->set('authorization', function () { return new Authorization(); }, []);