diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php index edbb9aa5a..a18c2e885 100644 --- a/app/controllers/api/database.php +++ b/app/controllers/api/database.php @@ -245,13 +245,16 @@ App::get('/v1/database/collections/:collectionId') $response->dynamic($collection, Response::MODEL_COLLECTION); }); - App::get('/v1/database/usage') +App::get('/v1/database/usage') ->desc('Get usage stats for the database') ->groups(['api', 'database']) ->label('scope', 'collections.read') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'database') ->label('sdk.method', 'getUsage') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_DATABASE_USAGE) ->param('range', '30d', new WhiteList(['24h', '7d', '30d', '90d'], true), 'Date range.', true) ->inject('response') ->inject('dbForInternal') @@ -261,11 +264,11 @@ App::get('/v1/database/collections/:collectionId') /** @var Utopia\Database\Database $dbForInternal */ /** @var Utopia\Registry\Registry $register */ - $stats = []; + $usage = []; if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') { $period = [ '24h' => [ - 'period' => '30m', + 'period' => '15m', 'limit' => 48, ], '7d' => [ @@ -285,6 +288,8 @@ App::get('/v1/database/collections/:collectionId') Authorization::disable(); $metrics = [ + 'database.documents.count', + 'database.collections.count', 'database.collections.create', 'database.collections.read', 'database.collections.update', @@ -295,6 +300,7 @@ App::get('/v1/database/collections/:collectionId') 'database.documents.delete' ]; + $stats = []; foreach ($metrics as $metric) { $requestDocs = $dbForInternal->find('stats', [ new Query('period', Query::TYPE_EQUAL, [$period[$range]['period']]), @@ -312,85 +318,24 @@ App::get('/v1/database/collections/:collectionId') $stats[$metric] = array_reverse($stats[$metric]); } - $documentsCount = $dbForInternal->findOne('stats', [new Query('metric', Query::TYPE_EQUAL, ['database.documents.count'])], 0, ['time'], [Database::ORDER_DESC]); - $documentsTotal = $documentsCount ? $documentsCount->getAttribute('value', 0) : 0; - - $collectionsCount = $dbForInternal->findOne('stats', [new Query('metric', Query::TYPE_EQUAL, ['database.collections.count'])], 0, ['time'], [Database::ORDER_DESC]); - $collectionsTotal = $collectionsCount ? $collectionsCount->getAttribute('value', 0) : 0; - Authorization::reset(); - $documentsCreate = $stats["database.documents.create"] ?? []; - $documentsRead = $stats["database.documents.read"] ?? []; - $documentsUpdate = $stats["database.documents.update"] ?? []; - $documentsDelete = $stats["database.documents.delete"] ?? []; - $collectionsCreate = $stats["database.collections.create"] ?? []; - $collectionsRead = $stats["database.collections.read"] ?? []; - $collectionsUpdate = $stats["database.collections.update"] ?? []; - $collectionsDelete = $stats["database.collections.delete"] ?? []; - - $response->json([ + $usage = new Document([ 'range' => $range, - 'documents.create' => [ - 'data' => $documentsCreate, - 'total' => \array_sum(\array_map(function ($item) { - return $item['value']; - }, $documentsCreate)), - ], - 'documents.read' => [ - 'data' => $documentsRead, - 'total' => \array_sum(\array_map(function ($item) { - return $item['value']; - }, $documentsRead)), - ], - 'documents.update' => [ - 'data' => $documentsUpdate, - 'total' => \array_sum(\array_map(function ($item) { - return $item['value']; - }, $documentsUpdate)), - ], - 'documents.delete' => [ - 'data' => $documentsDelete, - 'total' => \array_sum(\array_map(function ($item) { - return $item['value']; - }, $documentsDelete)), - ], - 'collections.create' => [ - 'data' => $collectionsCreate, - 'total' => \array_sum(\array_map(function ($item) { - return $item['value']; - }, $collectionsCreate)), - ], - 'collections.read' => [ - 'data' => $collectionsRead, - 'total' => \array_sum(\array_map(function ($item) { - return $item['value']; - }, $collectionsRead)), - ], - 'collections.update' => [ - 'data' => $collectionsUpdate, - 'total' => \array_sum(\array_map(function ($item) { - return $item['value']; - }, $collectionsUpdate)), - ], - 'collections.delete' => [ - 'data' => $collectionsDelete, - 'total' => \array_sum(\array_map(function ($item) { - return $item['value']; - }, $collectionsDelete)), - ], - 'documentCount' => [ - 'data' => [], - 'total' => $documentsTotal, - ], - 'collectionCount' => [ - 'data' => [], - 'total' => $collectionsTotal, - ] + 'documents.count' => $stats["database.documents.count"], + 'collections.count' => $stats["database.collections.count"], + 'documents.create' => $stats["database.documents.create"], + 'documents.read' => $stats["database.documents.read"], + 'documents.update' => $stats["database.documents.update"], + 'documents.delete' => $stats["database.documents.delete"], + 'collections.create' => $stats["database.collections.create"], + 'collections.read' => $stats["database.collections.read"], + 'collections.update' => $stats["database.collections.update"], + 'collections.delete' => $stats["database.collections.delete"], ]); - } else { - $response->json([]); } + + $response->dynamic($usage, Response::MODEL_DATABASE_USAGE); }); App::get('/v1/database/:collectionId/usage') @@ -400,6 +345,9 @@ App::get('/v1/database/:collectionId/usage') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'database') ->label('sdk.method', 'getUsage') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_COLLECTION_USAGE) ->param('range', '30d', new WhiteList(['24h', '7d', '30d', '90d'], true), 'Date range.', true) ->param('collectionId', '', new UID(), 'Collection unique ID.') ->inject('response') @@ -417,11 +365,11 @@ App::get('/v1/database/:collectionId/usage') throw new Exception('Collection not found', 404); } - $stats = []; + $usage = []; if(App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') { $period = [ '24h' => [ - 'period' => '30m', + 'period' => '15m', 'limit' => 48, ], '7d' => [ @@ -441,12 +389,14 @@ App::get('/v1/database/:collectionId/usage') Authorization::disable(); $metrics = [ + "database.collections.$collectionId.documents.count", "database.collections.$collectionId.documents.create", "database.collections.$collectionId.documents.read", "database.collections.$collectionId.documents.update", "database.collections.$collectionId.documents.delete", ]; + $stats = []; foreach ($metrics as $metric) { $requestDocs = $dbForInternal->find('stats', [ new Query('period', Query::TYPE_EQUAL, [$period[$range]['period']]), @@ -460,54 +410,22 @@ App::get('/v1/database/:collectionId/usage') 'date' => $requestDoc->getAttribute('time'), ]; } - $stats[$metric] = array_reverse($stats[$metric]); } - - $documentsCount = $dbForInternal->findOne('stats', [new Query('metric', Query::TYPE_EQUAL, ["database.collections.$collectionId.documents.count"])], 0, ['time'], [Database::ORDER_DESC]); - $documentsTotal = $documentsCount ? $documentsCount->getAttribute('value', 0) : 0; Authorization::reset(); - - $create = $stats["database.collections.$collectionId.documents.create"] ?? []; - $read = $stats["database.collections.$collectionId.documents.read"] ?? []; - $update = $stats["database.collections.$collectionId.documents.update"] ?? []; - $delete = $stats["database.collections.$collectionId.documents.delete"] ?? []; - $response->json([ + $usage = new Document([ 'range' => $range, - 'create' => [ - 'data' => $create, - 'total' => \array_sum(\array_map(function ($item) { - return $item['value']; - }, $create)), - ], - 'read' => [ - 'data' => $read, - 'total' => \array_sum(\array_map(function ($item) { - return $item['value']; - }, $read)), - ], - 'update' => [ - 'data' => $update, - 'total' => \array_sum(\array_map(function ($item) { - return $item['value']; - }, $update)), - ], - 'delete' => [ - 'data' => $delete, - 'total' => \array_sum(\array_map(function ($item) { - return $item['value']; - }, $delete)), - ], - 'documentCount' => [ - 'data' => [], - 'total' => $documentsTotal, - ], + 'documents.count' => $stats["database.collections.$collectionId.documents.count"], + 'documents.create' => $stats["database.collections.$collectionId.documents.create"], + 'documents.read' => $stats["database.collections.$collectionId.documents.read"], + 'documents.update' => $stats["database.collections.$collectionId.documents.update"], + 'documents.delete' => $stats["database.collections.$collectionId.documents.delete"] ]); - } else { - $response->json([]); } + + $response->dynamic($usage, Response::MODEL_COLLECTION_USAGE); }); App::get('/v1/database/collections/:collectionId/logs') @@ -1458,6 +1376,7 @@ App::post('/v1/database/collections/:collectionId/documents') $data['$read'] = (is_null($read) && !$user->isEmpty()) ? ['user:'.$user->getId()] : $read ?? []; // By default set read permissions for user $data['$write'] = (is_null($write) && !$user->isEmpty()) ? ['user:'.$user->getId()] : $write ?? []; // By default set write permissions for user + var_dump($collectionId); try { $document = $dbForExternal->createDocument($collectionId, new Document($data)); } diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 3b433988e..5589dbe95 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -647,7 +647,7 @@ App::delete('/v1/storage/files/:fileId') App::get('/v1/storage/usage') ->desc('Get usage stats for storage') ->groups(['api', 'storage']) - ->label('scope', 'storage.read') + ->label('scope', 'files.read') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'getUsage') @@ -705,7 +705,7 @@ App::get('/v1/storage/usage') App::get('/v1/storage/:bucketId/usage') ->desc('Get usage stats for a storage bucket') ->groups(['api', 'storage']) - ->label('scope', 'storage.read') + ->label('scope', 'files.read') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'storage') ->label('sdk.method', 'getUsage') @@ -772,6 +772,29 @@ App::get('/v1/storage/:bucketId/usage') $update = $stats["storage.buckets.$bucketId.files.update"] ?? []; $delete = $stats["storage.buckets.$bucketId.files.delete"] ?? []; + + // 'name' => [ + // [ + // [ + // 'value' => '', + // 'date' => 'unix timestamp' + // ] + // ] + // ] + + // $res = [ + // 'range' => '', + // 'name' => [ + // [ + // 'value' => , + // 'date' => + // ] + // ], + // 'nameTotal' => [ + + // ] + // ]; + $response->json([ 'range' => $range, 'create' => [ diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index f7217a515..44799fdaa 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -13,9 +13,11 @@ use Appwrite\Utopia\Response\Model\Any; use Appwrite\Utopia\Response\Model\Attribute; use Appwrite\Utopia\Response\Model\BaseList; use Appwrite\Utopia\Response\Model\Collection; +use Appwrite\Utopia\Response\Model\CollectionUsage; use Appwrite\Utopia\Response\Model\Continent; use Appwrite\Utopia\Response\Model\Country; use Appwrite\Utopia\Response\Model\Currency; +use Appwrite\Utopia\Response\Model\DatabaseUsage; use Appwrite\Utopia\Response\Model\Document as ModelDocument; use Appwrite\Utopia\Response\Model\Domain; use Appwrite\Utopia\Response\Model\Error; @@ -57,6 +59,7 @@ class Response extends SwooleResponse const MODEL_LOG_LIST = 'logList'; const MODEL_ERROR = 'error'; const MODEL_METRIC = 'metric'; + const MODEL_METRIC_LIST = 'metricList'; const MODEL_ERROR_DEV = 'errorDev'; const MODEL_BASE_LIST = 'baseList'; @@ -69,6 +72,8 @@ class Response extends SwooleResponse const MODEL_INDEX_LIST = 'indexList'; const MODEL_DOCUMENT = 'document'; const MODEL_DOCUMENT_LIST = 'documentList'; + const MODEL_DATABASE_USAGE = 'databaseUsage'; + const MODEL_COLLECTION_USAGE = 'collectionUsage'; // Users const MODEL_USER = 'user'; @@ -183,6 +188,8 @@ class Response extends SwooleResponse ->setModel(new Attribute()) ->setModel(new Index()) ->setModel(new ModelDocument()) + ->setModel(new DatabaseUsage()) + ->setModel(new CollectionUsage()) ->setModel(new Log()) ->setModel(new User()) ->setModel(new Preferences()) diff --git a/src/Appwrite/Utopia/Response/Model/CollectionUsage.php b/src/Appwrite/Utopia/Response/Model/CollectionUsage.php new file mode 100644 index 000000000..2281b3d03 --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/CollectionUsage.php @@ -0,0 +1,77 @@ +addRule('range', [ + 'type' => self::TYPE_INTEGER, + 'description' => 'The value of this metric at a timestamp.', + 'default' => 0, + 'example' => 1, + ]) + ->addRule('documents.count', [ + 'type' => Response::MODEL_METRIC_LIST, + 'description' => 'Aggregated stats for total number of documents.', + 'default' => [], + 'example' => new stdClass, + 'array' => true + ]) + ->addRule('documents.create', [ + 'type' => Response::MODEL_METRIC_LIST, + 'description' => 'Aggregated stats for documents created.', + 'default' => [], + 'example' => new stdClass, + 'array' => true + ]) + ->addRule('documents.read', [ + 'type' => Response::MODEL_METRIC_LIST, + 'description' => 'Aggregated stats for documents read.', + 'default' => [], + 'example' => new stdClass, + 'array' => true + ]) + ->addRule('documents.update', [ + 'type' => Response::MODEL_METRIC_LIST, + 'description' => 'Aggregated stats for documents updated.', + 'default' => [], + 'example' => new stdClass, + 'array' => true + ]) + ->addRule('documents.delete', [ + 'type' => Response::MODEL_METRIC_LIST, + 'description' => 'Aggregated stats for documents deleted.', + 'default' => [], + 'example' => new stdClass, + 'array' => true + ]) + ; + } + + /** + * Get Name + * + * @return string + */ + public function getName():string + { + return 'CollectionUsage'; + } + + /** + * Get Collection + * + * @return string + */ + public function getType():string + { + return Response::MODEL_COLLECTION_USAGE; + } +} \ No newline at end of file diff --git a/src/Appwrite/Utopia/Response/Model/DatabaseUsage.php b/src/Appwrite/Utopia/Response/Model/DatabaseUsage.php new file mode 100644 index 000000000..58d9575d7 --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/DatabaseUsage.php @@ -0,0 +1,112 @@ +addRule('range', [ + 'type' => self::TYPE_INTEGER, + 'description' => 'The value of this metric at a timestamp.', + 'default' => 0, + 'example' => 1, + ]) + ->addRule('documents.count', [ + 'type' => Response::MODEL_METRIC_LIST, + 'description' => 'Aggregated stats for total number of documents.', + 'default' => [], + 'example' => new stdClass, + 'array' => true + ]) + ->addRule('collections.count', [ + 'type' => Response::MODEL_METRIC_LIST, + 'description' => 'Aggregated stats for total number of collections.', + 'default' => [], + 'example' => new stdClass, + 'array' => true + ]) + ->addRule('documents.create', [ + 'type' => Response::MODEL_METRIC_LIST, + 'description' => 'Aggregated stats for documents created.', + 'default' => [], + 'example' => new stdClass, + 'array' => true + ]) + ->addRule('documents.read', [ + 'type' => Response::MODEL_METRIC_LIST, + 'description' => 'Aggregated stats for documents read.', + 'default' => [], + 'example' => new stdClass, + 'array' => true + ]) + ->addRule('documents.update', [ + 'type' => Response::MODEL_METRIC_LIST, + 'description' => 'Aggregated stats for documents updated.', + 'default' => [], + 'example' => new stdClass, + 'array' => true + ]) + ->addRule('documents.delete', [ + 'type' => Response::MODEL_METRIC_LIST, + 'description' => 'Aggregated stats for documents deleted.', + 'default' => [], + 'example' => new stdClass, + 'array' => true + ]) + ->addRule('collections.create', [ + 'type' => Response::MODEL_METRIC_LIST, + 'description' => 'Aggregated stats for collections created.', + 'default' => [], + 'example' => new stdClass, + 'array' => true + ]) + ->addRule('collections.read', [ + 'type' => Response::MODEL_METRIC_LIST, + 'description' => 'Aggregated stats for collections read.', + 'default' => [], + 'example' => new stdClass, + 'array' => true + ]) + ->addRule('collections.update', [ + 'type' => Response::MODEL_METRIC_LIST, + 'description' => 'Aggregated stats for collections updated.', + 'default' => [], + 'example' => new stdClass, + 'array' => true + ]) + ->addRule('collections.delete', [ + 'type' => Response::MODEL_METRIC_LIST, + 'description' => 'Aggregated stats for collections delete.', + 'default' => [], + 'example' => new stdClass, + 'array' => true + ]) + ; + } + + /** + * Get Name + * + * @return string + */ + public function getName():string + { + return 'DatabaseUsage'; + } + + /** + * Get Collection + * + * @return string + */ + public function getType():string + { + return Response::MODEL_DATABASE_USAGE; + } +} \ No newline at end of file diff --git a/src/Appwrite/Utopia/Response/Model/Metric.php b/src/Appwrite/Utopia/Response/Model/Metric.php index 73625eb1f..26038af08 100644 --- a/src/Appwrite/Utopia/Response/Model/Metric.php +++ b/src/Appwrite/Utopia/Response/Model/Metric.php @@ -10,23 +10,17 @@ class Metric extends Model public function __construct() { $this - ->addRule('message', [ - 'type' => self::TYPE_STRING, - 'description' => 'Error message.', - 'default' => '', - 'example' => 'Not found', + ->addRule('value', [ + 'type' => self::TYPE_INTEGER, + 'description' => 'The value of this metric at the timestamp.', + 'default' => -1, + 'example' => 1, ]) - ->addRule('code', [ - 'type' => self::TYPE_STRING, - 'description' => 'Error code.', - 'default' => '', - 'example' => '404', - ]) - ->addRule('version', [ - 'type' => self::TYPE_STRING, - 'description' => 'Server version number.', - 'default' => '', - 'example' => '1.0', + ->addRule('timestamp', [ + 'type' => self::TYPE_INTEGER, + 'description' => 'The UNIX timestamp at which this metric was aggregated.', + 'default' => 0, + 'example' => 1592981250 ]) ; }