Use initialized spans for isolated error export

This commit is contained in:
Chirag Aggarwal
2026-04-30 13:02:42 +05:30
parent 03e11991ac
commit db55141535
5 changed files with 143 additions and 112 deletions
+30 -24
View File
@@ -35,6 +35,7 @@ use Utopia\Queue\Publisher;
use Utopia\Queue\Queue;
use Utopia\Registry\Registry;
use Utopia\Span\Span;
use Utopia\Span\Storage\Coroutine as SpanCoroutineStorage;
use Utopia\System\System;
use Utopia\Telemetry\Adapter\None as NoTelemetry;
@@ -276,34 +277,39 @@ $container->set('logError', function () {
Console::error('[Error] Line: ' . $error->getLine());
Console::error('[Error] Trace: ' . $error->getTraceAsString());
// Export a standalone error span without mutating the active CLI task span.
$span = new Span($action);
// Export through Span::init(), then restore the active CLI task span.
$activeSpan = Span::current();
$span = Span::init($action);
$span->set('level', 'error');
$span->set('logger', $namespace);
$span->set('server.name', System::getEnv('_APP_LOGGING_SERVICE_IDENTIFIER', \gethostname()));
$span->set('release', System::getEnv('_APP_VERSION', 'UNKNOWN'));
$span->set('environment', System::getEnv('_APP_ENV', 'development') === 'production' ? 'production' : 'staging');
$span->set('appwrite.error.publish', true);
$span->set('appwrite.error.action', $action);
$span->set('error.message', $error->getMessage());
$span->set('verboseType', get_class($error));
$span->set('error.code', $error->getCode());
$span->set('error.file', $error->getFile());
$span->set('error.line', $error->getLine());
$span->set('error.trace', $error->getTraceAsString());
$span->set('error.detailedTrace', \json_encode($error->getTrace()) ?: null);
try {
$span->set('level', 'error');
$span->set('logger', $namespace);
$span->set('server.name', System::getEnv('_APP_LOGGING_SERVICE_IDENTIFIER', \gethostname()));
$span->set('release', System::getEnv('_APP_VERSION', 'UNKNOWN'));
$span->set('environment', System::getEnv('_APP_ENV', 'development') === 'production' ? 'production' : 'staging');
$span->set('appwrite.error.publish', true);
$span->set('appwrite.error.action', $action);
$span->set('error.message', $error->getMessage());
$span->set('verboseType', get_class($error));
$span->set('error.code', $error->getCode());
$span->set('error.file', $error->getFile());
$span->set('error.line', $error->getLine());
$span->set('error.trace', $error->getTraceAsString());
$span->set('error.detailedTrace', \json_encode($error->getTrace()) ?: null);
if ($error->getPrevious() !== null) {
if ($error->getPrevious()->getMessage() != $error->getMessage()) {
$span->set('error.previous.message', $error->getPrevious()->getMessage());
if ($error->getPrevious() !== null) {
if ($error->getPrevious()->getMessage() != $error->getMessage()) {
$span->set('error.previous.message', $error->getPrevious()->getMessage());
}
$span->set('error.previous.file', $error->getPrevious()->getFile());
$span->set('error.previous.line', $error->getPrevious()->getLine());
}
$span->set('error.previous.file', $error->getPrevious()->getFile());
$span->set('error.previous.line', $error->getPrevious()->getLine());
}
$span->setError($error);
$span->finish();
$span->setError($error);
$span->finish();
} finally {
(new SpanCoroutineStorage())->set($activeSpan);
}
};
}, []);
+33 -27
View File
@@ -26,6 +26,7 @@ use Utopia\Pools\Group;
use Utopia\Queue\Publisher;
use Utopia\Registry\Registry;
use Utopia\Span\Span;
use Utopia\Span\Storage\Coroutine as SpanCoroutineStorage;
use Utopia\Storage\Device\Telemetry as TelemetryDevice;
use Utopia\System\System;
use Utopia\Telemetry\Adapter as Telemetry;
@@ -352,38 +353,43 @@ return function (Container $container): void {
$container->set('logError', function (Document $project) {
return function (Throwable $error, string $namespace, string $action, ?array $extras = null) use ($project) {
// Export a standalone error span without mutating the active job span.
$span = new Span($action);
// Export through Span::init(), then restore the active job span.
$activeSpan = Span::current();
$span = Span::init($action);
$span->set('level', 'error');
$span->set('logger', $namespace);
$span->set('server.name', System::getEnv('_APP_LOGGING_SERVICE_IDENTIFIER', \gethostname()));
$span->set('release', System::getEnv('_APP_VERSION', 'UNKNOWN'));
$span->set('environment', System::getEnv('_APP_ENV', 'development') === 'production' ? 'production' : 'staging');
$span->set('appwrite.error.publish', true);
$span->set('appwrite.error.action', $action);
$span->set('code', $error->getCode());
$span->set('verboseType', \get_class($error));
$span->set('projectId', $project->getId());
$span->set('error.message', $error->getMessage());
$span->set('error.file', $error->getFile());
$span->set('error.line', $error->getLine());
$span->set('error.trace', $error->getTraceAsString());
try {
$span->set('level', 'error');
$span->set('logger', $namespace);
$span->set('server.name', System::getEnv('_APP_LOGGING_SERVICE_IDENTIFIER', \gethostname()));
$span->set('release', System::getEnv('_APP_VERSION', 'UNKNOWN'));
$span->set('environment', System::getEnv('_APP_ENV', 'development') === 'production' ? 'production' : 'staging');
$span->set('appwrite.error.publish', true);
$span->set('appwrite.error.action', $action);
$span->set('code', $error->getCode());
$span->set('verboseType', \get_class($error));
$span->set('projectId', $project->getId());
$span->set('error.message', $error->getMessage());
$span->set('error.file', $error->getFile());
$span->set('error.line', $error->getLine());
$span->set('error.trace', $error->getTraceAsString());
if ($error->getPrevious() !== null) {
if ($error->getPrevious()->getMessage() != $error->getMessage()) {
$span->set('error.previous.message', $error->getPrevious()->getMessage());
if ($error->getPrevious() !== null) {
if ($error->getPrevious()->getMessage() != $error->getMessage()) {
$span->set('error.previous.message', $error->getPrevious()->getMessage());
}
$span->set('error.previous.file', $error->getPrevious()->getFile());
$span->set('error.previous.line', $error->getPrevious()->getLine());
}
$span->set('error.previous.file', $error->getPrevious()->getFile());
$span->set('error.previous.line', $error->getPrevious()->getLine());
}
foreach (($extras ?? []) as $key => $value) {
$span->set($key, \is_scalar($value) || $value === null ? $value : (\json_encode($value) ?: null));
}
foreach (($extras ?? []) as $key => $value) {
$span->set($key, \is_scalar($value) || $value === null ? $value : (\json_encode($value) ?: null));
}
$span->setError($error);
$span->finish();
$span->setError($error);
$span->finish();
} finally {
(new SpanCoroutineStorage())->set($activeSpan);
}
Console::warning("Failed: {$error->getMessage()}");
Console::warning($error->getTraceAsString());
+30 -24
View File
@@ -38,6 +38,7 @@ use Utopia\DSN\DSN;
use Utopia\Pools\Group;
use Utopia\Registry\Registry;
use Utopia\Span\Span;
use Utopia\Span\Storage\Coroutine as SpanCoroutineStorage;
use Utopia\System\System;
use Utopia\Telemetry\Adapter\None as NoTelemetry;
use Utopia\WebSocket\Adapter;
@@ -281,34 +282,39 @@ $server = new Server($adapter);
if (!function_exists('logError')) {
function logError(Throwable $error, string $action, array $tags = [], ?Document $project = null, ?Document $user = null, ?Authorization $authorization = null): void
{
// Export a standalone error span without mutating the active connection span.
$span = new Span($action);
// Export through Span::init(), then restore the active connection span.
$activeSpan = Span::current();
$span = Span::init($action);
$span->set('level', 'error');
$span->set('logger', 'realtime');
$span->set('server.name', System::getEnv('_APP_LOGGING_SERVICE_IDENTIFIER', \gethostname()));
$span->set('release', System::getEnv('_APP_VERSION', 'UNKNOWN'));
$span->set('environment', System::getEnv('_APP_ENV', 'development') === 'production' ? 'production' : 'staging');
$span->set('appwrite.error.publish', true);
$span->set('appwrite.error.action', $action);
$span->set('code', $error->getCode());
$span->set('verboseType', get_class($error));
$span->set('projectId', $project?->getId() ?: 'n/a');
$span->set('userId', $user?->getId() ?: 'n/a');
try {
$span->set('level', 'error');
$span->set('logger', 'realtime');
$span->set('server.name', System::getEnv('_APP_LOGGING_SERVICE_IDENTIFIER', \gethostname()));
$span->set('release', System::getEnv('_APP_VERSION', 'UNKNOWN'));
$span->set('environment', System::getEnv('_APP_ENV', 'development') === 'production' ? 'production' : 'staging');
$span->set('appwrite.error.publish', true);
$span->set('appwrite.error.action', $action);
$span->set('code', $error->getCode());
$span->set('verboseType', get_class($error));
$span->set('projectId', $project?->getId() ?: 'n/a');
$span->set('userId', $user?->getId() ?: 'n/a');
foreach ($tags as $key => $value) {
$span->set($key, \is_scalar($value) ? ($value ?: 'n/a') : (\json_encode($value) ?: 'n/a'));
foreach ($tags as $key => $value) {
$span->set($key, \is_scalar($value) ? ($value ?: 'n/a') : (\json_encode($value) ?: 'n/a'));
}
$span->set('error.message', $error->getMessage());
$span->set('error.file', $error->getFile());
$span->set('error.line', $error->getLine());
$span->set('error.trace', $error->getTraceAsString());
$span->set('error.detailedTrace', \json_encode($error->getTrace()) ?: null);
$span->set('roles', \json_encode($authorization?->getRoles() ?? []) ?: null);
$span->setError($error);
$span->finish();
} finally {
(new SpanCoroutineStorage())->set($activeSpan);
}
$span->set('error.message', $error->getMessage());
$span->set('error.file', $error->getFile());
$span->set('error.line', $error->getLine());
$span->set('error.trace', $error->getTraceAsString());
$span->set('error.detailedTrace', \json_encode($error->getTrace()) ?: null);
$span->set('roles', \json_encode($authorization?->getRoles() ?? []) ?: null);
$span->setError($error);
$span->finish();
Console::error('[Error] Type: ' . get_class($error));
Console::error('[Error] Message: ' . $error->getMessage());
Console::error('[Error] File: ' . $error->getFile());
+25 -19
View File
@@ -15,6 +15,7 @@ use Utopia\Queue\Adapter\Swoole;
use Utopia\Queue\Broker\Pool as BrokerPool;
use Utopia\Queue\Server;
use Utopia\Span\Span;
use Utopia\Span\Storage\Coroutine as SpanCoroutineStorage;
use Utopia\System\System;
Runtime::enableCoroutine();
@@ -115,26 +116,31 @@ $worker
->action(function (Throwable $error, Document $project, Authorization $authorization) use ($queueName) {
$version = System::getEnv('_APP_VERSION', 'UNKNOWN');
$action = 'appwrite-queue-' . $queueName;
// Export a standalone error span without mutating the active worker span.
$span = new Span($action);
// Export through Span::init(), then restore the active worker span.
$activeSpan = Span::current();
$span = Span::init($action);
$span->set('level', 'error');
$span->set('logger', 'appwrite-worker');
$span->set('server.name', System::getEnv('_APP_LOGGING_SERVICE_IDENTIFIER', \gethostname()));
$span->set('release', $version);
$span->set('environment', System::getEnv('_APP_ENV', 'development') === 'production' ? 'production' : 'staging');
$span->set('appwrite.error.publish', true);
$span->set('appwrite.error.action', $action);
$span->set('verboseType', get_class($error));
$span->set('code', $error->getCode());
$span->set('projectId', $project->getId());
$span->set('error.message', $error->getMessage());
$span->set('error.file', $error->getFile());
$span->set('error.line', $error->getLine());
$span->set('error.trace', $error->getTraceAsString());
$span->set('roles', \json_encode($authorization->getRoles()) ?: null);
$span->setError($error);
$span->finish();
try {
$span->set('level', 'error');
$span->set('logger', 'appwrite-worker');
$span->set('server.name', System::getEnv('_APP_LOGGING_SERVICE_IDENTIFIER', \gethostname()));
$span->set('release', $version);
$span->set('environment', System::getEnv('_APP_ENV', 'development') === 'production' ? 'production' : 'staging');
$span->set('appwrite.error.publish', true);
$span->set('appwrite.error.action', $action);
$span->set('verboseType', get_class($error));
$span->set('code', $error->getCode());
$span->set('projectId', $project->getId());
$span->set('error.message', $error->getMessage());
$span->set('error.file', $error->getFile());
$span->set('error.line', $error->getLine());
$span->set('error.trace', $error->getTraceAsString());
$span->set('roles', \json_encode($authorization->getRoles()) ?: null);
$span->setError($error);
$span->finish();
} finally {
(new SpanCoroutineStorage())->set($activeSpan);
}
Console::error('[Error] Type: ' . get_class($error));
Console::error('[Error] Message: ' . $error->getMessage());
@@ -15,6 +15,7 @@ use Utopia\Agents\Agent;
use Utopia\Database\Document;
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
use Utopia\Span\Span;
use Utopia\Span\Storage\Coroutine as SpanCoroutineStorage;
use Utopia\System\System;
use Utopia\Validator\ArrayList;
use Utopia\Validator\Text;
@@ -102,24 +103,30 @@ class Create extends CreateDocumentAction
$error = 'Error while generating embedding';
$totalErrors += 1;
// Export each failed text independently without overwriting the request span.
$span = new Span('vectorsDB.createTextEmbeddings');
$span->set('level', 'error');
$span->set('logger', 'http');
$span->set('server.name', System::getEnv('_APP_LOGGING_SERVICE_IDENTIFIER', \gethostname()));
$span->set('release', System::getEnv('_APP_VERSION', 'UNKNOWN'));
$span->set('environment', System::getEnv('_APP_ENV', 'development') === 'production' ? 'production' : 'staging');
$span->set('appwrite.error.publish', true);
$span->set('appwrite.error.action', 'vectorsDB.createTextEmbeddings');
$span->set('embeddingModel', $model);
$span->set('code', $e->getCode());
$span->set('projectId', $project->getId());
$span->set('error.message', $e->getMessage());
$span->set('error.file', $e->getFile());
$span->set('error.line', $e->getLine());
$span->set('error.trace', $e->getTraceAsString());
$span->setError($e);
$span->finish();
// Export through Span::init(), then restore the active request span.
$activeSpan = Span::current();
$span = Span::init('vectorsDB.createTextEmbeddings');
try {
$span->set('level', 'error');
$span->set('logger', 'http');
$span->set('server.name', System::getEnv('_APP_LOGGING_SERVICE_IDENTIFIER', \gethostname()));
$span->set('release', System::getEnv('_APP_VERSION', 'UNKNOWN'));
$span->set('environment', System::getEnv('_APP_ENV', 'development') === 'production' ? 'production' : 'staging');
$span->set('appwrite.error.publish', true);
$span->set('appwrite.error.action', 'vectorsDB.createTextEmbeddings');
$span->set('embeddingModel', $model);
$span->set('code', $e->getCode());
$span->set('projectId', $project->getId());
$span->set('error.message', $e->getMessage());
$span->set('error.file', $e->getFile());
$span->set('error.line', $e->getLine());
$span->set('error.trace', $e->getTraceAsString());
$span->setError($e);
$span->finish();
} finally {
(new SpanCoroutineStorage())->set($activeSpan);
}
}
$results[] = new Document([