Remove utopia logger dependency

This commit is contained in:
Chirag Aggarwal
2026-04-30 10:18:54 +05:30
parent 8ffe48d948
commit eeea533a26
34 changed files with 351 additions and 621 deletions
+33 -39
View File
@@ -28,13 +28,13 @@ use Utopia\Database\Document;
use Utopia\Database\Validator\Authorization;
use Utopia\DI\Container;
use Utopia\DSN\DSN;
use Utopia\Logger\Log;
use Utopia\Platform\Service;
use Utopia\Pools\Group;
use Utopia\Queue\Broker\Pool as BrokerPool;
use Utopia\Queue\Publisher;
use Utopia\Queue\Queue;
use Utopia\Registry\Registry;
use Utopia\Span\Span;
use Utopia\System\System;
use Utopia\Telemetry\Adapter\None as NoTelemetry;
@@ -267,8 +267,8 @@ $container->set('queueForFunctions', function (Publisher $publisher) {
$container->set('queueForDeletes', function (Publisher $publisher) {
return new Delete($publisher);
}, ['publisher']);
$container->set('logError', function (Registry $register) {
return function (Throwable $error, string $namespace, string $action) use ($register) {
$container->set('logError', function () {
return function (Throwable $error, string $namespace, string $action) {
Console::error('[Error] Timestamp: ' . date('c', time()));
Console::error('[Error] Type: ' . get_class($error));
Console::error('[Error] Message: ' . $error->getMessage());
@@ -276,48 +276,42 @@ $container->set('logError', function (Registry $register) {
Console::error('[Error] Line: ' . $error->getLine());
Console::error('[Error] Trace: ' . $error->getTraceAsString());
$logger = $register->get('logger');
$span = Span::current();
$shouldFinish = false;
if ($span === null) {
$span = Span::init($action);
$shouldFinish = true;
}
if ($logger) {
$version = System::getEnv('_APP_VERSION', 'UNKNOWN');
Span::add('level', 'error');
Span::add('logger', $namespace);
Span::add('server.name', System::getEnv('_APP_LOGGING_SERVICE_IDENTIFIER', \gethostname()));
Span::add('release', System::getEnv('_APP_VERSION', 'UNKNOWN'));
Span::add('environment', System::getEnv('_APP_ENV', 'development') === 'production' ? 'production' : 'staging');
Span::add('appwrite.error.publish', true);
Span::add('appwrite.error.action', $action);
Span::add('error.message', $error->getMessage());
Span::add('error.type', get_class($error));
Span::add('error.code', $error->getCode());
Span::add('error.file', $error->getFile());
Span::add('error.line', $error->getLine());
Span::add('error.trace', $error->getTraceAsString());
Span::add('error.detailedTrace', \json_encode($error->getTrace()) ?: null);
$log = new Log();
$log->setNamespace($namespace);
$log->setServer(System::getEnv('_APP_LOGGING_SERVICE_IDENTIFIER', \gethostname()));
$log->setVersion($version);
$log->setType(Log::TYPE_ERROR);
$log->setMessage($error->getMessage());
$log->addTag('code', $error->getCode());
$log->addTag('verboseType', get_class($error));
$log->addExtra('file', $error->getFile());
$log->addExtra('line', $error->getLine());
$log->addExtra('trace', $error->getTraceAsString());
$log->addExtra('detailedTrace', $error->getTrace());
if ($error->getPrevious() !== null) {
if ($error->getPrevious()->getMessage() != $error->getMessage()) {
$log->addExtra('previousMessage', $error->getPrevious()->getMessage());
}
$log->addExtra('previousFile', $error->getPrevious()->getFile());
$log->addExtra('previousLine', $error->getPrevious()->getLine());
if ($error->getPrevious() !== null) {
if ($error->getPrevious()->getMessage() != $error->getMessage()) {
Span::add('error.previous.message', $error->getPrevious()->getMessage());
}
Span::add('error.previous.file', $error->getPrevious()->getFile());
Span::add('error.previous.line', $error->getPrevious()->getLine());
}
$log->setAction($action);
$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());
}
Span::error($error);
if ($shouldFinish) {
$span->finish();
}
};
}, ['register']);
}, []);
$container->set('executor', fn () => new Executor(), []);
+37 -86
View File
@@ -57,10 +57,6 @@ use Utopia\Domains\Domain;
use Utopia\DSN\DSN;
use Utopia\Http\Http;
use Utopia\Locale\Locale;
use Utopia\Logger\Adapter\Sentry;
use Utopia\Logger\Log;
use Utopia\Logger\Log\User;
use Utopia\Logger\Logger;
use Utopia\Platform\Service;
use Utopia\Span\Span;
use Utopia\System\System;
@@ -69,7 +65,7 @@ use Utopia\Validator\Text;
Config::setParam('cookieSamesite', Response::COOKIE_SAMESITE_NONE);
function router(Http $utopia, Database $dbForPlatform, callable $getProjectDB, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Event $queueForEvents, Bus $bus, Executor $executor, Reader $geodb, callable $isResourceBlocked, array $platform, string $previewHostname, Authorization $authorization, ?Key $apiKey, DeleteEvent $queueForDeletes, int $executionsRetentionCount)
function router(Http $utopia, Database $dbForPlatform, callable $getProjectDB, SwooleRequest $swooleRequest, Request $request, Response $response, Event $queueForEvents, Bus $bus, Executor $executor, Reader $geodb, callable $isResourceBlocked, array $platform, string $previewHostname, Authorization $authorization, ?Key $apiKey, DeleteEvent $queueForDeletes, int $executionsRetentionCount)
{
$host = $request->getHostname();
if (!empty($previewHostname)) {
@@ -146,7 +142,7 @@ function router(Http $utopia, Database $dbForPlatform, callable $getProjectDB, S
/**
* Set projectId to update the Error hook logger, since x-appwrite-project is not available when executing custom domain function
*/
$log->addTag('projectId', $project->getId());
Span::add('projectId', $project->getId());
}
if (array_key_exists('proxy', $project->getAttribute('services', []))) {
@@ -830,7 +826,6 @@ Http::init()
->inject('swooleRequest')
->inject('request')
->inject('response')
->inject('log')
->inject('project')
->inject('dbForPlatform')
->inject('getProjectDB')
@@ -849,7 +844,7 @@ Http::init()
->inject('authorization')
->inject('queueForDeletes')
->inject('executionsRetentionCount')
->action(function (Http $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Document $project, Database $dbForPlatform, callable $getProjectDB, Locale $locale, array $localeCodes, Reader $geodb, Event $queueForEvents, Bus $bus, Executor $executor, array $platform, callable $isResourceBlocked, string $previewHostname, Document $devKey, ?Key $apiKey, Cors $cors, Authorization $authorization, DeleteEvent $queueForDeletes, int $executionsRetentionCount) {
->action(function (Http $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Document $project, Database $dbForPlatform, callable $getProjectDB, Locale $locale, array $localeCodes, Reader $geodb, Event $queueForEvents, Bus $bus, Executor $executor, array $platform, callable $isResourceBlocked, string $previewHostname, Document $devKey, ?Key $apiKey, Cors $cors, Authorization $authorization, DeleteEvent $queueForDeletes, int $executionsRetentionCount) {
/*
* Appwrite Router
*/
@@ -857,7 +852,7 @@ Http::init()
$platformHostnames = $platform['hostnames'] ?? [];
// Only run Router when external domain
if (!\in_array($hostname, $platformHostnames) || !empty($previewHostname)) {
if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $log, $queueForEvents, $bus, $executor, $geodb, $isResourceBlocked, $platform, $previewHostname, $authorization, $apiKey, $queueForDeletes, $executionsRetentionCount)) {
if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $bus, $executor, $geodb, $isResourceBlocked, $platform, $previewHostname, $authorization, $apiKey, $queueForDeletes, $executionsRetentionCount)) {
$utopia->getRoute()?->label('router', true);
}
}
@@ -1131,7 +1126,6 @@ Http::options()
->inject('swooleRequest')
->inject('request')
->inject('response')
->inject('log')
->inject('dbForPlatform')
->inject('getProjectDB')
->inject('queueForEvents')
@@ -1148,14 +1142,14 @@ Http::options()
->inject('authorization')
->inject('queueForDeletes')
->inject('executionsRetentionCount')
->action(function (Http $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, Bus $bus, Executor $executor, Reader $geodb, callable $isResourceBlocked, array $platform, string $previewHostname, Document $project, Document $devKey, ?Key $apiKey, Cors $cors, Authorization $authorization, DeleteEvent $queueForDeletes, int $executionsRetentionCount) {
->action(function (Http $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, Bus $bus, Executor $executor, Reader $geodb, callable $isResourceBlocked, array $platform, string $previewHostname, Document $project, Document $devKey, ?Key $apiKey, Cors $cors, Authorization $authorization, DeleteEvent $queueForDeletes, int $executionsRetentionCount) {
/*
* Appwrite Router
*/
$platformHostnames = $platform['hostnames'] ?? [];
// Only run Router when external domain
if (!in_array($request->getHostname(), $platformHostnames) || !empty($previewHostname)) {
if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $log, $queueForEvents, $bus, $executor, $geodb, $isResourceBlocked, $platform, $previewHostname, $authorization, $apiKey, $queueForDeletes, $executionsRetentionCount)) {
if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $bus, $executor, $geodb, $isResourceBlocked, $platform, $previewHostname, $authorization, $apiKey, $queueForDeletes, $executionsRetentionCount)) {
$utopia->getRoute()?->label('router', true);
}
}
@@ -1184,12 +1178,10 @@ Http::error()
->inject('request')
->inject('response')
->inject('project')
->inject('logger')
->inject('log')
->inject('bus')
->inject('devKey')
->inject('authorization')
->action(function (Throwable $error, Http $utopia, Request $request, Response $response, Document $project, ?Logger $logger, Log $log, Bus $bus, Document $devKey, Authorization $authorization) {
->action(function (Throwable $error, Http $utopia, Request $request, Response $response, Document $project, Bus $bus, Document $devKey, Authorization $authorization) {
$version = System::getEnv('_APP_VERSION', 'UNKNOWN');
$route = $utopia->getRoute();
$class = \get_class($error);
@@ -1232,27 +1224,8 @@ Http::error()
$providerConfig = System::getEnv('_APP_EXPERIMENT_LOGGING_CONFIG', '');
if (!empty($providerConfig) && $error->getCode() >= 400 && $error->getCode() < 500) {
// Register error logger
try {
$loggingProvider = new DSN($providerConfig);
$providerName = $loggingProvider->getScheme();
if (!empty($providerName) && $providerName === 'sentry') {
$key = $loggingProvider->getPassword();
$projectId = $loggingProvider->getUser() ?? '';
$host = 'https://' . $loggingProvider->getHost();
$sampleRate = $loggingProvider->getParam('sample', 0.01);
$adapter = new Sentry($projectId, $key, $host);
$logger = new Logger($adapter);
$logger->setSample($sampleRate);
$publish = true;
} else {
throw new \Exception('Invalid experimental logging provider');
}
} catch (\Throwable $th) {
Console::warning('Failed to initialize logging provider: ' . $th->getMessage());
}
$publish = true;
Span::add('appwrite.error.experimental', true);
}
/**
@@ -1277,7 +1250,7 @@ Http::error()
}
}
if ($logger && $publish) {
if ($publish) {
try {
/** @var Utopia\Database\Document $user */
$user = $utopia->getResource('user');
@@ -1285,12 +1258,6 @@ Http::error()
// All good, user is optional information for logger
}
if (isset($user) && !$user->isEmpty()) {
$log->setUser(new User($user->getId()));
} else {
$log->setUser(new User('guest-' . hash('sha256', $request->getIP())));
}
try {
$dsn = new DSN($project->getAttribute('database', 'console'));
} catch (\InvalidArgumentException) {
@@ -1298,30 +1265,26 @@ Http::error()
$dsn = new DSN('mysql://' . $project->getAttribute('database', 'console'));
}
$log->setNamespace("http");
$log->setServer(System::getEnv('_APP_LOGGING_SERVICE_IDENTIFIER', \gethostname()));
$log->setVersion($version);
$log->setType(Log::TYPE_ERROR);
$log->setMessage($error->getMessage());
$log->addTag('database', $dsn->getHost());
$log->addTag('method', $route?->getMethod() ?? $request->getMethod());
$log->addTag('url', $request->getURI());
$log->addTag('verboseType', get_class($error));
$log->addTag('code', $error->getCode());
$tags = $log->getTags();
if (!isset($tags['projectId'])) {
$log->addTag('projectId', $project->getId());
}
$log->addTag('hostname', $request->getHostname());
$log->addTag('locale', (string)$request->getParam('locale', $request->getHeader('x-appwrite-locale', '')));
$log->addExtra('file', $error->getFile());
$log->addExtra('line', $error->getLine());
$log->addExtra('trace', $error->getTraceAsString());
$log->addExtra('roles', $authorization->getRoles());
Span::add('level', 'error');
Span::add('logger', 'http');
Span::add('server.name', System::getEnv('_APP_LOGGING_SERVICE_IDENTIFIER', \gethostname()));
Span::add('release', $version);
Span::add('environment', System::getEnv('_APP_ENV', 'development') === 'production' ? 'production' : 'staging');
Span::add('appwrite.error.publish', true);
Span::add('database', $dsn->getHost());
Span::add('method', $route?->getMethod() ?? $request->getMethod());
Span::add('url', $request->getURI());
Span::add('verboseType', get_class($error));
Span::add('code', $error->getCode());
Span::add('projectId', $project->getId());
Span::add('hostname', $request->getHostname());
Span::add('locale', (string)$request->getParam('locale', $request->getHeader('x-appwrite-locale', '')));
Span::add('userId', isset($user) && !$user->isEmpty() ? $user->getId() : 'guest-' . hash('sha256', $request->getIP()));
Span::add('error.message', $error->getMessage());
Span::add('error.file', $error->getFile());
Span::add('error.line', $error->getLine());
Span::add('error.trace', $error->getTraceAsString());
Span::add('roles', \json_encode($authorization->getRoles()) ?: null);
try {
/* add queries to log */
@@ -1396,7 +1359,7 @@ Http::error()
}
if (!empty($formattedQueries)) {
$log->addExtra('queries', $formattedQueries);
Span::add('queries', \json_encode($formattedQueries) ?: null);
}
}
} catch (Throwable $_) {
@@ -1416,18 +1379,8 @@ Http::error()
$action = 'http.' . $request->getMethod() . '.' . $path;
}
$log->setAction($action);
$log->addTag('service', $action);
$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());
}
Span::add('appwrite.error.action', $action);
Span::add('service', $action);
}
/** Wrap all exceptions inside Appwrite\Extend\Exception */
@@ -1536,7 +1489,6 @@ Http::get('/robots.txt')
->inject('swooleRequest')
->inject('request')
->inject('response')
->inject('log')
->inject('dbForPlatform')
->inject('getProjectDB')
->inject('queueForEvents')
@@ -1550,13 +1502,13 @@ Http::get('/robots.txt')
->inject('authorization')
->inject('queueForDeletes')
->inject('executionsRetentionCount')
->action(function (Http $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, Bus $bus, Executor $executor, Reader $geodb, callable $isResourceBlocked, array $platform, string $previewHostname, ?Key $apiKey, Authorization $authorization, DeleteEvent $queueForDeletes, int $executionsRetentionCount) {
->action(function (Http $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, Bus $bus, Executor $executor, Reader $geodb, callable $isResourceBlocked, array $platform, string $previewHostname, ?Key $apiKey, Authorization $authorization, DeleteEvent $queueForDeletes, int $executionsRetentionCount) {
$platformHostnames = $platform['hostnames'] ?? [];
if (in_array($request->getHostname(), $platformHostnames) || !empty($previewHostname)) {
$template = new View(__DIR__ . '/../views/general/robots.phtml');
$response->text($template->render(false));
} else {
if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $log, $queueForEvents, $bus, $executor, $geodb, $isResourceBlocked, $platform, $previewHostname, $authorization, $apiKey, $queueForDeletes, $executionsRetentionCount)) {
if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $bus, $executor, $geodb, $isResourceBlocked, $platform, $previewHostname, $authorization, $apiKey, $queueForDeletes, $executionsRetentionCount)) {
$utopia->getRoute()?->label('router', true);
}
}
@@ -1570,7 +1522,6 @@ Http::get('/humans.txt')
->inject('swooleRequest')
->inject('request')
->inject('response')
->inject('log')
->inject('dbForPlatform')
->inject('getProjectDB')
->inject('queueForEvents')
@@ -1584,13 +1535,13 @@ Http::get('/humans.txt')
->inject('authorization')
->inject('queueForDeletes')
->inject('executionsRetentionCount')
->action(function (Http $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, Bus $bus, Executor $executor, Reader $geodb, callable $isResourceBlocked, array $platform, string $previewHostname, ?Key $apiKey, Authorization $authorization, DeleteEvent $queueForDeletes, int $executionsRetentionCount) {
->action(function (Http $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, Bus $bus, Executor $executor, Reader $geodb, callable $isResourceBlocked, array $platform, string $previewHostname, ?Key $apiKey, Authorization $authorization, DeleteEvent $queueForDeletes, int $executionsRetentionCount) {
$platformHostnames = $platform['hostnames'] ?? [];
if (in_array($request->getHostname(), $platformHostnames) || !empty($previewHostname)) {
$template = new View(__DIR__ . '/../views/general/humans.phtml');
$response->text($template->render(false));
} else {
if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $log, $queueForEvents, $bus, $executor, $geodb, $isResourceBlocked, $platform, $previewHostname, $authorization, $apiKey, $queueForDeletes, $executionsRetentionCount)) {
if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $bus, $executor, $geodb, $isResourceBlocked, $platform, $previewHostname, $authorization, $apiKey, $queueForDeletes, $executionsRetentionCount)) {
$utopia->getRoute()?->label('router', true);
}
}
+31 -64
View File
@@ -29,8 +29,6 @@ use Utopia\Database\Query;
use Utopia\Http\Adapter\Swoole\Server;
use Utopia\Http\Files;
use Utopia\Http\Http;
use Utopia\Logger\Log;
use Utopia\Logger\Log\User;
use Utopia\Span\Span;
use Utopia\System\System;
@@ -552,72 +550,41 @@ $swooleAdapter->onRequest(function ($utopiaRequest, $utopiaResponse) use ($files
$version = System::getEnv('_APP_VERSION', 'UNKNOWN');
$logger = $app->getResource("logger");
if ($logger) {
try {
/** @var Utopia\Database\Document $user */
$user = $app->getResource('user');
} catch (\Throwable $_th) {
// All good, user is optional information for logger
}
$route = $app->getRoute();
$sdk = $route?->getLabel("sdk", false);
$route = $app->getRoute();
$log = $app->getResource("log");
if (isset($user) && !$user->isEmpty()) {
$log->setUser(new User($user->getId()));
} else {
$log->setUser(new User('guest-' . hash('sha256', $request->getIP())));
}
$log->setNamespace("http");
$log->setServer(System::getEnv('_APP_LOGGING_SERVICE_IDENTIFIER', \gethostname()));
$log->setVersion($version);
$log->setType(Log::TYPE_ERROR);
$log->setMessage($th->getMessage());
$log->addTag('method', $route?->getMethod() ?? $request->getMethod());
$log->addTag('url', $route?->getPath() ?? $request->getURI());
$log->addTag('verboseType', get_class($th));
$log->addTag('code', $th->getCode());
// $log->addTag('projectId', $project->getId()); // TODO: Figure out how to get ProjectID, if it becomes relevant
$log->addTag('hostname', $request->getHostname());
$log->addTag('locale', (string)$request->getParam('locale', $request->getHeader('x-appwrite-locale', '')));
$log->addExtra('file', $th->getFile());
$log->addExtra('line', $th->getLine());
$log->addExtra('trace', $th->getTraceAsString());
$log->addExtra('roles', isset($authorization) ? $authorization->getRoles() : []);
$sdk = $route?->getLabel("sdk", false);
$action = 'UNKNOWN_NAMESPACE.UNKNOWN.METHOD';
if (!empty($sdk)) {
if (\is_array($sdk)) {
$sdk = $sdk[0];
}
/** @var Appwrite\SDK\Method $sdk */
$action = $sdk->getNamespace() . '.' . $sdk->getMethodName();
} elseif ($route === null) {
$path = ltrim(parse_url($request->getURI(), PHP_URL_PATH) ?? '/', '/') ?: 'root';
$action = 'http.' . $request->getMethod() . '.' . $path;
}
$log->setAction($action);
$log->addTag('service', $action);
$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());
$action = 'UNKNOWN_NAMESPACE.UNKNOWN.METHOD';
if (!empty($sdk)) {
if (\is_array($sdk)) {
$sdk = $sdk[0];
}
/** @var Appwrite\SDK\Method $sdk */
$action = $sdk->getNamespace() . '.' . $sdk->getMethodName();
} elseif ($route === null) {
$path = ltrim(parse_url($request->getURI(), PHP_URL_PATH) ?? '/', '/') ?: 'root';
$action = 'http.' . $request->getMethod() . '.' . $path;
}
Span::add('level', 'error');
Span::add('logger', 'http');
Span::add('server.name', System::getEnv('_APP_LOGGING_SERVICE_IDENTIFIER', \gethostname()));
Span::add('release', $version);
Span::add('environment', System::getEnv('_APP_ENV', 'development') === 'production' ? 'production' : 'staging');
Span::add('appwrite.error.publish', true);
Span::add('appwrite.error.action', $action);
Span::add('method', $route?->getMethod() ?? $request->getMethod());
Span::add('url', $route?->getPath() ?? $request->getURI());
Span::add('verboseType', get_class($th));
Span::add('code', $th->getCode());
Span::add('hostname', $request->getHostname());
Span::add('locale', (string)$request->getParam('locale', $request->getHeader('x-appwrite-locale', '')));
Span::add('service', $action);
Span::add('error.message', $th->getMessage());
Span::add('error.file', $th->getFile());
Span::add('error.line', $th->getLine());
Span::add('error.trace', $th->getTraceAsString());
Span::add('roles', isset($authorization) ? (\json_encode($authorization->getRoles()) ?: null) : '[]');
$swooleResponse = $utopiaResponse->getSwooleResponse();
$swooleResponse->setStatusCode(500);
-109
View File
@@ -9,7 +9,6 @@ use MaxMind\Db\Reader;
use Swoole\Database\PDOProxy;
use Utopia\Cache\Adapter\Redis as RedisCache;
use Utopia\Config\Config;
use Utopia\Console;
use Utopia\Database\Adapter\MariaDB;
use Utopia\Database\Adapter\Mongo;
use Utopia\Database\Adapter\MySQL;
@@ -19,11 +18,6 @@ use Utopia\Database\PDO;
use Utopia\Domains\Validator\PublicDomain;
use Utopia\DSN\DSN;
use Utopia\Http\Http;
use Utopia\Logger\Adapter\AppSignal;
use Utopia\Logger\Adapter\LogOwl;
use Utopia\Logger\Adapter\Raygun;
use Utopia\Logger\Adapter\Sentry;
use Utopia\Logger\Logger;
use Utopia\Messaging\Adapter\Email\SMTP;
use Utopia\Mongo\Client as MongoClient;
use Utopia\Pools\Adapter\Stack as StackPool;
@@ -46,109 +40,6 @@ if (!Http::isProduction()) {
PublicDomain::allow(['request-catcher-webhook']);
}
$register->set('logger', function () {
// Register error logger
$providerName = System::getEnv('_APP_LOGGING_PROVIDER', '');
$providerConfig = System::getEnv('_APP_LOGGING_CONFIG', '');
if (empty($providerConfig)) {
return;
}
try {
$loggingProvider = new DSN($providerConfig);
$providerName = $loggingProvider->getScheme();
$providerConfig = match ($providerName) {
'sentry' => ['key' => $loggingProvider->getPassword(), 'projectId' => $loggingProvider->getUser() ?? '', 'host' => 'https://' . $loggingProvider->getHost()],
'logowl' => ['ticket' => $loggingProvider->getUser() ?? '', 'host' => $loggingProvider->getHost()],
default => ['key' => $loggingProvider->getHost()],
};
} catch (Throwable $th) {
// Fallback for older Appwrite versions up to 1.5.x that use _APP_LOGGING_PROVIDER and _APP_LOGGING_CONFIG environment variables
Console::warning('Using deprecated logging configuration. Please update your configuration to use DSN format.' . $th->getMessage());
$configChunks = \explode(";", $providerConfig);
$providerConfig = match ($providerName) {
'sentry' => [ 'key' => $configChunks[0], 'projectId' => $configChunks[1] ?? '', 'host' => '',],
'logowl' => ['ticket' => $configChunks[0], 'host' => ''],
default => ['key' => $providerConfig],
};
}
if (empty($providerName)) {
return;
}
if (!Logger::hasProvider($providerName)) {
throw new Exception(Exception::GENERAL_SERVER_ERROR, "Logging provider not supported. Logging is disabled");
}
try {
$adapter = match ($providerName) {
'sentry' => new Sentry($providerConfig['projectId'], $providerConfig['key'], $providerConfig['host']),
'logowl' => new LogOwl($providerConfig['ticket'], $providerConfig['host']),
'raygun' => new Raygun($providerConfig['key']),
'appsignal' => new AppSignal($providerConfig['key']),
default => null
};
} catch (Throwable $th) {
$adapter = null;
}
if ($adapter === null) {
Console::error("Logging provider not supported. Logging is disabled");
return;
}
return new Logger($adapter);
});
$register->set('realtimeLogger', function () {
// Register error logger for realtime, falls back to default logging config
$providerConfig = System::getEnv('_APP_LOGGING_CONFIG_REALTIME', '')
?: System::getEnv('_APP_LOGGING_CONFIG', '');
if (empty($providerConfig)) {
return;
}
$loggingProvider = new DSN($providerConfig);
$providerName = $loggingProvider->getScheme();
$providerConfig = match ($providerName) {
'sentry' => ['key' => $loggingProvider->getPassword(), 'projectId' => $loggingProvider->getUser() ?? '', 'host' => 'https://' . $loggingProvider->getHost()],
'logowl' => ['ticket' => $loggingProvider->getUser() ?? '', 'host' => $loggingProvider->getHost()],
default => ['key' => $loggingProvider->getHost()],
};
if (empty($providerName)) {
return;
}
if (!Logger::hasProvider($providerName)) {
throw new Exception(Exception::GENERAL_SERVER_ERROR, "Logging provider not supported. Logging is disabled");
}
try {
$adapter = match ($providerName) {
'sentry' => new Sentry($providerConfig['projectId'], $providerConfig['key'], $providerConfig['host']),
'logowl' => new LogOwl($providerConfig['ticket'], $providerConfig['host']),
'raygun' => new Raygun($providerConfig['key']),
'appsignal' => new AppSignal($providerConfig['key']),
default => null
};
} catch (Throwable $th) {
$adapter = null;
}
if ($adapter === null) {
Console::error("Logging provider not supported. Logging is disabled");
return;
}
return new Logger($adapter);
});
$register->set('pools', function () {
$group = new Group();
-4
View File
@@ -45,10 +45,6 @@ global $register;
global $container;
$container = new Container();
$container->set('logger', function ($register) {
return $register->get('logger');
}, ['register']);
$container->set('hooks', function ($register) {
return $register->get('hooks');
}, ['register']);
-7
View File
@@ -48,7 +48,6 @@ use Utopia\Domains\Domain;
use Utopia\DSN\DSN;
use Utopia\Http\Http;
use Utopia\Locale\Locale;
use Utopia\Logger\Log;
use Utopia\Pools\Group;
use Utopia\Queue\Publisher;
use Utopia\Storage\Device;
@@ -67,12 +66,6 @@ return function (Container $container): void {
return $utopia;
}, ['utopia']);
$container->set('log', fn () => new Log(), []);
$container->set('logger', function ($register) {
return $register->get('logger');
}, ['register']);
$container->set('authorization', function () {
return new Authorization();
}, []);
+79
View File
@@ -1,10 +1,89 @@
<?php
use Appwrite\Extend\Exception;
use Utopia\Console;
use Utopia\DSN\DSN;
use Utopia\Span\Exporter;
use Utopia\Span\Exporter\SentryField;
use Utopia\Span\Span;
use Utopia\Span\Storage;
use Utopia\System\System;
Span::setStorage(new Storage\Coroutine());
$loggingConfig = System::getEnv('_APP_LOGGING_CONFIG', '');
if (\str_ends_with($_SERVER['SCRIPT_NAME'] ?? '', 'realtime.php')) {
$loggingConfig = System::getEnv('_APP_LOGGING_CONFIG_REALTIME', '') ?: $loggingConfig;
}
$addSentryExporter = function (string $loggingConfig, ?callable $sampler = null): void {
try {
$loggingProvider = new DSN($loggingConfig);
$providerName = $loggingProvider->getScheme();
if ($providerName !== 'sentry') {
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Logging provider not supported. Logging is disabled');
}
$dsn = 'https://' . $loggingProvider->getPassword() . '@' . $loggingProvider->getHost() . '/' . ($loggingProvider->getUser() ?? '');
Span::addExporter(
new Exporter\Sentry(
dsn: $dsn,
environment: System::getEnv('_APP_ENV', 'development') === 'production' ? 'production' : 'staging',
release: System::getEnv('_APP_VERSION', 'UNKNOWN'),
serverName: System::getEnv('_APP_LOGGING_SERVICE_IDENTIFIER', \gethostname()),
classifier: fn (string $key): SentryField => match ($key) {
'appwrite.error.action',
'appwrite.error.publish',
'code',
'database',
'dnsDomain',
'embeddingModel',
'error.code',
'error.type',
'hostname',
'locale',
'method',
'projectId',
'service',
'type',
'url',
'userId',
'verboseType' => SentryField::Tag,
default => SentryField::Context,
},
),
sampler: $sampler ?? fn (Span $span): bool => $span->getError() !== null
&& $span->get('appwrite.error.publish') === true
&& $span->get('appwrite.error.experimental') !== true,
);
} catch (Throwable $th) {
Console::warning('Failed to initialize logging provider: ' . $th->getMessage());
}
};
if (!empty($loggingConfig)) {
$addSentryExporter($loggingConfig);
}
$experimentalLoggingConfig = System::getEnv('_APP_EXPERIMENT_LOGGING_CONFIG', '');
if (!empty($experimentalLoggingConfig)) {
$sampleRate = 0.01;
try {
$sampleRate = (float) (new DSN($experimentalLoggingConfig))->getParam('sample', $sampleRate);
} catch (Throwable) {
}
$addSentryExporter(
$experimentalLoggingConfig,
fn (Span $span): bool => $span->getError() !== null
&& $span->get('appwrite.error.experimental') === true
&& \mt_rand() / \mt_getrandmax() <= $sampleRate,
);
}
Span::addExporter(new Exporter\Pretty(), function (Span $span): bool {
if (\str_starts_with($span->getAction(), 'listener.')) {
return $span->getError() !== null;
+36 -44
View File
@@ -22,10 +22,10 @@ use Utopia\Database\Document;
use Utopia\Database\Validator\Authorization;
use Utopia\DI\Container;
use Utopia\DSN\DSN;
use Utopia\Logger\Log;
use Utopia\Pools\Group;
use Utopia\Queue\Publisher;
use Utopia\Registry\Registry;
use Utopia\Span\Span;
use Utopia\Storage\Device\Telemetry as TelemetryDevice;
use Utopia\System\System;
use Utopia\Telemetry\Adapter as Telemetry;
@@ -36,8 +36,6 @@ use Utopia\Telemetry\Adapter as Telemetry;
* must be fresh for each worker job.
*/
return function (Container $container): void {
$container->set('log', fn () => new Log(), []);
$container->set('usage', fn () => new Context(), []);
$container->set('authorization', function () {
@@ -352,51 +350,45 @@ return function (Container $container): void {
return new TelemetryDevice($telemetry, getDevice(APP_STORAGE_CACHE . '/app-' . $project->getId()));
}, ['project', 'telemetry']);
$container->set('logError', function (Registry $register, Document $project) {
return function (Throwable $error, string $namespace, string $action, ?array $extras = null) use ($register, $project) {
$logger = $register->get('logger');
$container->set('logError', function (Document $project) {
return function (Throwable $error, string $namespace, string $action, ?array $extras = null) use ($project) {
$span = Span::current();
$shouldFinish = false;
if ($span === null) {
$span = Span::init($action);
$shouldFinish = true;
}
if ($logger) {
$version = System::getEnv('_APP_VERSION', 'UNKNOWN');
Span::add('level', 'error');
Span::add('logger', $namespace);
Span::add('server.name', System::getEnv('_APP_LOGGING_SERVICE_IDENTIFIER', \gethostname()));
Span::add('release', System::getEnv('_APP_VERSION', 'UNKNOWN'));
Span::add('environment', System::getEnv('_APP_ENV', 'development') === 'production' ? 'production' : 'staging');
Span::add('appwrite.error.publish', true);
Span::add('appwrite.error.action', $action);
Span::add('code', $error->getCode());
Span::add('verboseType', \get_class($error));
Span::add('projectId', $project->getId());
Span::add('error.message', $error->getMessage());
Span::add('error.file', $error->getFile());
Span::add('error.line', $error->getLine());
Span::add('error.trace', $error->getTraceAsString());
$log = new Log();
$log->setNamespace($namespace);
$log->setServer(System::getEnv('_APP_LOGGING_SERVICE_IDENTIFIER', \gethostname()));
$log->setVersion($version);
$log->setType(Log::TYPE_ERROR);
$log->setMessage($error->getMessage());
$log->addTag('code', $error->getCode());
$log->addTag('verboseType', \get_class($error));
$log->addTag('projectId', $project->getId());
$log->addExtra('file', $error->getFile());
$log->addExtra('line', $error->getLine());
$log->addExtra('trace', $error->getTraceAsString());
if ($error->getPrevious() !== null) {
if ($error->getPrevious()->getMessage() != $error->getMessage()) {
$log->addExtra('previousMessage', $error->getPrevious()->getMessage());
}
$log->addExtra('previousFile', $error->getPrevious()->getFile());
$log->addExtra('previousLine', $error->getPrevious()->getLine());
if ($error->getPrevious() !== null) {
if ($error->getPrevious()->getMessage() != $error->getMessage()) {
Span::add('error.previous.message', $error->getPrevious()->getMessage());
}
Span::add('error.previous.file', $error->getPrevious()->getFile());
Span::add('error.previous.line', $error->getPrevious()->getLine());
}
foreach (($extras ?? []) as $key => $value) {
$log->addExtra($key, $value);
}
foreach (($extras ?? []) as $key => $value) {
Span::add($key, \is_scalar($value) || $value === null ? $value : (\json_encode($value) ?: null));
}
$log->setAction($action);
$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());
}
Span::error($error);
if ($shouldFinish) {
$span->finish();
}
Console::warning("Failed: {$error->getMessage()}");
@@ -409,7 +401,7 @@ return function (Container $container): void {
Console::warning("Previous File: {$error->getPrevious()->getFile()} Line: {$error->getPrevious()->getLine()}");
}
};
}, ['register', 'project']);
}, ['project']);
$container->set('getAudit', function (Database $dbForPlatform, callable $getProjectDB) {
return function (Document $project) use ($dbForPlatform, $getProjectDB) {
+29 -36
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;
@@ -282,45 +281,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
{
global $register;
$logger = $register->get('realtimeLogger');
if ($logger && !$error instanceof Exception) {
$version = System::getEnv('_APP_VERSION', 'UNKNOWN');
$log = new Log();
$log->setNamespace("realtime");
$log->setServer(System::getEnv('_APP_LOGGING_SERVICE_IDENTIFIER', \gethostname()));
$log->setVersion($version);
$log->setType(Log::TYPE_ERROR);
$log->setMessage($error->getMessage());
$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');
if (!$error instanceof Exception) {
$span = Span::current();
$shouldFinish = false;
if ($span === null) {
$span = Span::init($action);
$shouldFinish = true;
}
$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() ?? []);
Span::add('level', 'error');
Span::add('logger', 'realtime');
Span::add('server.name', System::getEnv('_APP_LOGGING_SERVICE_IDENTIFIER', \gethostname()));
Span::add('release', System::getEnv('_APP_VERSION', 'UNKNOWN'));
Span::add('environment', System::getEnv('_APP_ENV', 'development') === 'production' ? 'production' : 'staging');
Span::add('appwrite.error.publish', true);
Span::add('appwrite.error.action', $action);
Span::add('code', $error->getCode());
Span::add('verboseType', get_class($error));
Span::add('projectId', $project?->getId() ?: 'n/a');
Span::add('userId', $user?->getId() ?: 'n/a');
$log->setAction($action);
foreach ($tags as $key => $value) {
Span::add($key, \is_scalar($value) ? ($value ?: 'n/a') : (\json_encode($value) ?: 'n/a'));
}
$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());
Span::add('error.message', $error->getMessage());
Span::add('error.file', $error->getFile());
Span::add('error.line', $error->getLine());
Span::add('error.trace', $error->getTraceAsString());
Span::add('error.detailedTrace', \json_encode($error->getTrace()) ?: null);
Span::add('roles', \json_encode($authorization?->getRoles() ?? []) ?: null);
Span::error($error);
if ($shouldFinish) {
$span->finish();
}
}
+27 -31
View File
@@ -9,13 +9,12 @@ use Swoole\Runtime;
use Utopia\Console;
use Utopia\Database\Document;
use Utopia\Database\Validator\Authorization;
use Utopia\Logger\Log;
use Utopia\Logger\Logger;
use Utopia\Platform\Service;
use Utopia\Pools\Group;
use Utopia\Queue\Adapter\Swoole;
use Utopia\Queue\Broker\Pool as BrokerPool;
use Utopia\Queue\Server;
use Utopia\Span\Span;
use Utopia\System\System;
Runtime::enableCoroutine();
@@ -35,8 +34,6 @@ $container->set('authorization', function () {
$container->set('project', fn () => new Document([]), []);
$container->set('log', fn () => new Log(), []);
$container->set('consumer', function (Group $pools) {
return new BrokerPool(consumer: $pools->get('consumer'));
}, ['pools']);
@@ -113,37 +110,36 @@ try {
$worker
->error()
->inject('error')
->inject('logger')
->inject('log')
->inject('project')
->inject('authorization')
->action(function (Throwable $error, ?Logger $logger, Log $log, Document $project, Authorization $authorization) use ($queueName) {
->action(function (Throwable $error, Document $project, Authorization $authorization) use ($queueName) {
$version = System::getEnv('_APP_VERSION', 'UNKNOWN');
$action = 'appwrite-queue-' . $queueName;
$span = Span::current();
$shouldFinish = false;
if ($span === null) {
$span = Span::init($action);
$shouldFinish = true;
}
if ($logger) {
$log->setNamespace('appwrite-worker');
$log->setServer(System::getEnv('_APP_LOGGING_SERVICE_IDENTIFIER', \gethostname()));
$log->setVersion($version);
$log->setType(Log::TYPE_ERROR);
$log->setMessage($error->getMessage());
$log->setAction('appwrite-queue-' . $queueName);
$log->addTag('verboseType', get_class($error));
$log->addTag('code', $error->getCode());
$log->addTag('projectId', $project->getId());
$log->addExtra('file', $error->getFile());
$log->addExtra('line', $error->getLine());
$log->addExtra('trace', $error->getTraceAsString());
$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());
}
Span::add('level', 'error');
Span::add('logger', 'appwrite-worker');
Span::add('server.name', System::getEnv('_APP_LOGGING_SERVICE_IDENTIFIER', \gethostname()));
Span::add('release', $version);
Span::add('environment', System::getEnv('_APP_ENV', 'development') === 'production' ? 'production' : 'staging');
Span::add('appwrite.error.publish', true);
Span::add('appwrite.error.action', $action);
Span::add('verboseType', get_class($error));
Span::add('code', $error->getCode());
Span::add('projectId', $project->getId());
Span::add('error.message', $error->getMessage());
Span::add('error.file', $error->getFile());
Span::add('error.line', $error->getLine());
Span::add('error.trace', $error->getTraceAsString());
Span::add('roles', \json_encode($authorization->getRoles()) ?: null);
Span::error($error);
if ($shouldFinish) {
$span->finish();
}
Console::error('[Error] Type: ' . get_class($error));