From f451f507f617201373ffd6cb24ebb8a20ee200d9 Mon Sep 17 00:00:00 2001 From: Prem Palanisamy Date: Tue, 12 May 2026 22:06:22 +0100 Subject: [PATCH] refactor(realtime): drop the utopia/logger error path, Sentry spans only --- app/config/variables.php | 2 +- app/init/realtime/span.php | 3 +-- app/init/registers.php | 19 --------------- app/realtime.php | 47 -------------------------------------- 4 files changed, 2 insertions(+), 69 deletions(-) diff --git a/app/config/variables.php b/app/config/variables.php index a4c0032bb0..ff865540ba 100644 --- a/app/config/variables.php +++ b/app/config/variables.php @@ -297,7 +297,7 @@ return [ ], [ 'name' => '_APP_LOGGING_CONFIG_REALTIME', - 'description' => 'Optional separate logging DSN for the Realtime server, so its errors can be routed to a dedicated project. Same DSN format as `_APP_LOGGING_CONFIG`; falls back to `_APP_LOGGING_CONFIG` when empty. When the provider is Sentry (`sentry://PROJECT_ID:SENTRY_API_KEY@SENTRY_HOST/`), Realtime errors are exported as spans to that Sentry project.', + 'description' => 'Optional separate logging DSN for the Realtime server so its errors go to a dedicated Sentry project. Same DSN format as `_APP_LOGGING_CONFIG`; falls back to `_APP_LOGGING_CONFIG` when empty. Realtime errors are exported as spans, so only the Sentry provider (`sentry://PROJECT_ID:SENTRY_API_KEY@SENTRY_HOST/`) takes effect here — other providers configured via `_APP_LOGGING_CONFIG` apply to the HTTP server and workers only.', 'introduction' => '1.8.1', 'default' => '', 'required' => false, diff --git a/app/init/realtime/span.php b/app/init/realtime/span.php index fada5f18a0..236dd0de05 100644 --- a/app/init/realtime/span.php +++ b/app/init/realtime/span.php @@ -9,8 +9,7 @@ use Utopia\System\System; /** * Export Realtime error spans to a dedicated Sentry project (`_APP_LOGGING_CONFIG_REALTIME`, falling * back to `_APP_LOGGING_CONFIG`) — only here, not in app/init/span.php, so the HTTP/worker/CLI - * servers keep reporting to the default project. The `realtimeLogger` registry skips the Sentry - * logger for the same condition so each Realtime error is reported once; keep the two in sync. + * servers keep reporting to the default project. Only error-bearing spans are sampled. */ $loggingConfig = System::getEnv('_APP_LOGGING_CONFIG_REALTIME', '') ?: System::getEnv('_APP_LOGGING_CONFIG', ''); if (empty($loggingConfig)) { diff --git a/app/init/registers.php b/app/init/registers.php index 28eb880562..83c4b7a5f8 100644 --- a/app/init/registers.php +++ b/app/init/registers.php @@ -110,25 +110,6 @@ $register->set('logger', static fn () => $createLogger( System::getEnv('_APP_LOGGING_PROVIDER', ''), )); -$register->set('realtimeLogger', static function () use ($createLogger): ?Logger { - $providerConfig = System::getEnv('_APP_LOGGING_CONFIG_REALTIME', '') ?: System::getEnv('_APP_LOGGING_CONFIG', ''); - if (empty($providerConfig)) { - return null; - } - - // Sentry Realtime errors are exported as spans by app/init/realtime/span.php (same condition), - // not via utopia/logger — building both would report each error to Sentry twice. - try { - if ((new DSN($providerConfig))->getScheme() === 'sentry') { - return null; - } - } catch (Throwable) { - // Legacy ;-delimited config, not a DSN; $createLogger handles it. - } - - return $createLogger($providerConfig); -}); - $register->set('pools', function () { $group = new Group(); diff --git a/app/realtime.php b/app/realtime.php index b0edf608f6..64c6470ea8 100644 --- a/app/realtime.php +++ b/app/realtime.php @@ -35,7 +35,6 @@ use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; use Utopia\DI\Container; use Utopia\DSN\DSN; -use Utopia\Logger\Log; use Utopia\Pools\Group; use Utopia\Registry\Registry; use Utopia\Span\Span; @@ -320,58 +319,12 @@ if (!function_exists('recordRealtimeErrorSpan')) { } } -if (!function_exists('pushRealtimeErrorLog')) { - /** Push a Realtime error to the utopia/logger provider — non-Sentry providers only; Sentry goes via recordRealtimeErrorSpan(). */ - function pushRealtimeErrorLog(Throwable $error, string $action, array $tags, ?Document $project, ?Document $user, ?Authorization $authorization): void - { - global $register; - - $logger = $register->get('realtimeLogger'); - if (!$logger) { - return; - } - - $log = new Log(); - $log->setNamespace('realtime'); - $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() ?: 'n/a'); - $log->addTag('userId', $user?->getId() ?: 'n/a'); - foreach ($tags as $key => $value) { - $log->addTag($key, $value ?: 'n/a'); - } - - $log->addExtra('file', $error->getFile()); - $log->addExtra('line', $error->getLine()); - $log->addExtra('trace', $error->getTraceAsString()); - $log->addExtra('detailedTrace', $error->getTrace()); - $log->addExtra('roles', $authorization?->getRoles() ?? []); - - $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()); - } - } -} - // Allows overriding if (!function_exists('logError')) { function logError(Throwable $error, string $action, array $tags = [], ?Document $project = null, ?Document $user = null, ?Authorization $authorization = null): void { if (!$error instanceof Exception) { recordRealtimeErrorSpan($error, $action, $tags, $project, $user, $authorization); - pushRealtimeErrorLog($error, $action, $tags, $project, $user, $authorization); } Console::error('[Error] Type: ' . get_class($error));