refactor(realtime): drop the utopia/logger error path, Sentry spans only

This commit is contained in:
Prem Palanisamy
2026-05-12 22:06:22 +01:00
parent 0a6949ff87
commit f451f507f6
4 changed files with 2 additions and 69 deletions
+1 -1
View File
@@ -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,
+1 -2
View File
@@ -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)) {
-19
View File
@@ -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();
-47
View File
@@ -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));